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,3488 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import time
5
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
6
+
7
+ import pytest
8
+
9
+ from chia._tests.util.rpc import validate_get_routes
10
+ from chia._tests.util.setup_nodes import OldSimulatorsAndWallets, SimulatorsAndWalletsServices
11
+ from chia._tests.util.time_out_assert import time_out_assert, time_out_assert_not_none
12
+ from chia.consensus.block_rewards import calculate_base_farmer_reward, calculate_pool_reward
13
+ from chia.rpc.wallet_rpc_api import WalletRpcApi
14
+ from chia.rpc.wallet_rpc_client import WalletRpcClient
15
+ from chia.simulator.simulator_protocol import FarmNewBlockProtocol, ReorgProtocol
16
+ from chia.types.blockchain_format.program import Program
17
+ from chia.types.blockchain_format.sized_bytes import bytes32
18
+ from chia.types.peer_info import PeerInfo
19
+ from chia.util.bech32m import encode_puzzle_hash
20
+ from chia.util.ints import uint32, uint64, uint128
21
+ from chia.util.timing import adjusted_timeout
22
+ from chia.wallet.cat_wallet.cat_wallet import CATWallet
23
+ from chia.wallet.cat_wallet.dao_cat_wallet import DAOCATWallet
24
+ from chia.wallet.dao_wallet.dao_info import DAORules
25
+ from chia.wallet.dao_wallet.dao_utils import (
26
+ generate_mint_proposal_innerpuz,
27
+ generate_simple_proposal_innerpuz,
28
+ generate_update_proposal_innerpuz,
29
+ )
30
+ from chia.wallet.dao_wallet.dao_wallet import DAOWallet
31
+ from chia.wallet.transaction_record import TransactionRecord
32
+ from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
33
+
34
+
35
+ async def get_proposal_state(wallet: DAOWallet, index: int) -> Tuple[Optional[bool], Optional[bool]]:
36
+ return wallet.dao_info.proposals_list[index].passed, wallet.dao_info.proposals_list[index].closed
37
+
38
+
39
+ async def rpc_state(
40
+ timeout: float,
41
+ async_function: Callable[[Any], Any],
42
+ params: List[Union[int, Dict[str, Any]]],
43
+ condition_func: Callable[[Dict[str, Any]], Any],
44
+ result: Optional[Any] = None,
45
+ ) -> Union[bool, Dict[str, Any]]: # pragma: no cover
46
+ __tracebackhide__ = True
47
+
48
+ timeout = adjusted_timeout(timeout=timeout)
49
+
50
+ start = time.monotonic()
51
+
52
+ while True:
53
+ resp = await async_function(*params)
54
+ assert isinstance(resp, dict)
55
+ try:
56
+ if result:
57
+ if condition_func(resp) == result:
58
+ return True
59
+ else:
60
+ if condition_func(resp):
61
+ return resp
62
+ except IndexError:
63
+ continue
64
+
65
+ now = time.monotonic()
66
+ elapsed = now - start
67
+ if elapsed >= timeout:
68
+ raise asyncio.TimeoutError(
69
+ f"timed out while waiting for {async_function.__name__}(): {elapsed} >= {timeout}",
70
+ )
71
+
72
+ await asyncio.sleep(0.3)
73
+
74
+
75
+ puzzle_hash_0 = bytes32(32 * b"0")
76
+
77
+
78
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
79
+ @pytest.mark.parametrize(
80
+ "trusted",
81
+ [True, False],
82
+ )
83
+ @pytest.mark.anyio
84
+ async def test_dao_creation(self_hostname: str, two_wallet_nodes: OldSimulatorsAndWallets, trusted: bool) -> None:
85
+ full_nodes, wallets, _ = two_wallet_nodes
86
+ full_node_api = full_nodes[0]
87
+ full_node_server = full_node_api.server
88
+ wallet_node_0, server_0 = wallets[0]
89
+ wallet_node_1, server_1 = wallets[1]
90
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
91
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
92
+ ph = await wallet_0.get_new_puzzlehash()
93
+ ph_1 = await wallet_1.get_new_puzzlehash()
94
+
95
+ if trusted:
96
+ wallet_node_0.config["trusted_peers"] = {
97
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
98
+ }
99
+ wallet_node_1.config["trusted_peers"] = {
100
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
101
+ }
102
+ else:
103
+ wallet_node_0.config["trusted_peers"] = {}
104
+ wallet_node_1.config["trusted_peers"] = {}
105
+
106
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
107
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
108
+
109
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
110
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
111
+
112
+ funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
113
+
114
+ await time_out_assert(20, wallet_0.get_confirmed_balance, funds)
115
+ await time_out_assert(20, full_node_api.wallet_is_synced, True, wallet_node_0)
116
+
117
+ cat_amt = 2000
118
+ dao_rules = DAORules(
119
+ proposal_timelock=uint64(10),
120
+ soft_close_length=uint64(5),
121
+ attendance_required=uint64(1000), # 10%
122
+ pass_percentage=uint64(5100), # 51%
123
+ self_destruct_length=uint64(20),
124
+ oracle_spend_delay=uint64(10),
125
+ proposal_minimum_amount=uint64(1),
126
+ )
127
+
128
+ fee = uint64(10)
129
+ fee_for_cat = uint64(20)
130
+
131
+ # Try to create a DAO with more CATs than xch balance
132
+ with pytest.raises(ValueError) as e_info:
133
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
134
+ await DAOWallet.create_new_dao_and_wallet(
135
+ wallet_node_0.wallet_state_manager,
136
+ wallet_0,
137
+ uint64(funds + 1),
138
+ dao_rules,
139
+ action_scope,
140
+ fee=fee,
141
+ fee_for_cat=fee_for_cat,
142
+ )
143
+ assert e_info.value.args[0] == f"Your balance of {funds} mojos is not enough to create {funds + 1} CATs"
144
+
145
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
146
+ dao_wallet_0 = await DAOWallet.create_new_dao_and_wallet(
147
+ wallet_node_0.wallet_state_manager,
148
+ wallet_0,
149
+ uint64(cat_amt * 2),
150
+ dao_rules,
151
+ action_scope,
152
+ fee=fee,
153
+ fee_for_cat=fee_for_cat,
154
+ )
155
+
156
+ await full_node_api.wait_transaction_records_entered_mempool(
157
+ records=action_scope.side_effects.transactions, timeout=60
158
+ )
159
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
160
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
161
+
162
+ # Check the spend was successful
163
+ treasury_id = dao_wallet_0.dao_info.treasury_id
164
+
165
+ # check the dao wallet balances
166
+ await time_out_assert(20, dao_wallet_0.get_confirmed_balance, uint128(1))
167
+ await time_out_assert(20, dao_wallet_0.get_unconfirmed_balance, uint128(1))
168
+ await time_out_assert(20, dao_wallet_0.get_pending_change_balance, uint64(0))
169
+
170
+ # check select coins
171
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
172
+ no_coins = await dao_wallet_0.select_coins(uint64(2), action_scope)
173
+ assert no_coins == set()
174
+ selected_coins = await dao_wallet_0.select_coins(uint64(1), action_scope)
175
+ assert len(selected_coins) == 1
176
+
177
+ # get the cat wallets
178
+ cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.cat_wallet_id]
179
+ dao_cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.dao_cat_wallet_id]
180
+ # Some dao_cat_wallet checks for coverage
181
+ assert dao_cat_wallet_0.get_name() == f"CAT {cat_wallet_0.cat_info.limitations_program_hash.hex()[:16]}..."
182
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=False) as action_scope:
183
+ assert (await dao_cat_wallet_0.select_coins(uint64(1), action_scope)) == set()
184
+ dao_cat_puzhash = await dao_cat_wallet_0.get_new_puzzlehash()
185
+ assert dao_cat_puzhash == bytes32.from_hexstr("09f905ba3e9db3644ac4537495565bf268c6f030266aa412863c5efced6b1800")
186
+ await dao_cat_wallet_0.get_new_inner_puzzle(DEFAULT_TX_CONFIG)
187
+ dao_cat_inner_hash = await dao_cat_wallet_0.get_new_inner_hash(DEFAULT_TX_CONFIG)
188
+ assert dao_cat_inner_hash == bytes32.from_hexstr("8a66292fde9ef08198d996eae0ea21677eb478afeabed8030b1bf42c728f7dcc")
189
+
190
+ cat_wallet_0_bal = await cat_wallet_0.get_confirmed_balance()
191
+ assert cat_wallet_0_bal == cat_amt * 2
192
+
193
+ # Create the other user's wallet from the treasury id
194
+ dao_wallet_1 = await DAOWallet.create_new_dao_wallet_for_existing_dao(
195
+ wallet_node_1.wallet_state_manager, wallet_1, treasury_id
196
+ )
197
+ assert dao_wallet_0.dao_info.treasury_id == dao_wallet_1.dao_info.treasury_id
198
+
199
+ # Get the cat wallets for wallet_1
200
+ cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.cat_wallet_id]
201
+ assert cat_wallet_1
202
+
203
+ # Send some cats to the dao_cat lockup
204
+ dao_cat_amt = uint64(100)
205
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
206
+ await dao_wallet_0.enter_dao_cat_voting_mode(dao_cat_amt, action_scope)
207
+
208
+ await full_node_api.wait_transaction_records_entered_mempool(
209
+ records=action_scope.side_effects.transactions, timeout=60
210
+ )
211
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
212
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
213
+
214
+ # Test that we can get spendable coins from both cat and dao_cat wallet
215
+ fake_proposal_id = Program.to("proposal_id").get_tree_hash()
216
+ spendable_coins = await dao_cat_wallet_0.wallet_state_manager.get_spendable_coins_for_wallet(
217
+ dao_cat_wallet_0.id(), None
218
+ )
219
+
220
+ assert len(spendable_coins) > 0
221
+ coins = await dao_cat_wallet_0.advanced_select_coins(1, fake_proposal_id)
222
+ assert len(coins) > 0
223
+ # check that we have selected the coin from dao_cat_wallet
224
+ assert list(coins)[0].coin.amount == dao_cat_amt
225
+
226
+ # send some cats from wallet_0 to wallet_1 so we can test voting
227
+ async with cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
228
+ await cat_wallet_0.generate_signed_transaction([cat_amt], [ph_1], action_scope)
229
+
230
+ await full_node_api.wait_transaction_records_entered_mempool(
231
+ records=action_scope.side_effects.transactions, timeout=60
232
+ )
233
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
234
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
235
+
236
+ await time_out_assert(10, cat_wallet_1.get_confirmed_balance, cat_amt)
237
+
238
+ # Smaller tests of dao_wallet funcs for coverage
239
+ await dao_wallet_0.adjust_filter_level(uint64(10))
240
+ assert dao_wallet_0.dao_info.filter_below_vote_amount == uint64(10)
241
+
242
+ await dao_wallet_0.set_name("Renamed Wallet")
243
+ assert dao_wallet_0.get_name() == "Renamed Wallet"
244
+
245
+ new_inner_puzhash = await dao_wallet_0.get_new_p2_inner_hash()
246
+ assert isinstance(new_inner_puzhash, bytes32)
247
+
248
+ # run DAOCATwallet.create for coverage
249
+ create_dao_cat_from_info = await DAOCATWallet.create(
250
+ wallet_0.wallet_state_manager, wallet_0, dao_cat_wallet_0.wallet_info
251
+ )
252
+ assert create_dao_cat_from_info
253
+ create_dao_wallet_from_info = await DAOWallet.create(
254
+ wallet_0.wallet_state_manager, wallet_0, dao_wallet_0.wallet_info
255
+ )
256
+ assert create_dao_wallet_from_info
257
+
258
+
259
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
260
+ @pytest.mark.parametrize(
261
+ "trusted",
262
+ [True, False],
263
+ )
264
+ @pytest.mark.anyio
265
+ async def test_dao_funding(self_hostname: str, three_wallet_nodes: OldSimulatorsAndWallets, trusted: bool) -> None:
266
+ full_nodes, wallets, _ = three_wallet_nodes
267
+ full_node_api = full_nodes[0]
268
+ full_node_server = full_node_api.server
269
+ wallet_node_0, server_0 = wallets[0]
270
+ wallet_node_1, server_1 = wallets[1]
271
+ wallet_node_2, server_2 = wallets[2]
272
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
273
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
274
+ wallet_2 = wallet_node_1.wallet_state_manager.main_wallet
275
+ ph = await wallet_0.get_new_puzzlehash()
276
+ ph_1 = await wallet_1.get_new_puzzlehash()
277
+ ph_2 = await wallet_2.get_new_puzzlehash()
278
+
279
+ if trusted:
280
+ wallet_node_0.config["trusted_peers"] = {
281
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
282
+ }
283
+ wallet_node_1.config["trusted_peers"] = {
284
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
285
+ }
286
+ wallet_node_2.config["trusted_peers"] = {
287
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
288
+ }
289
+ else:
290
+ wallet_node_0.config["trusted_peers"] = {}
291
+ wallet_node_1.config["trusted_peers"] = {}
292
+ wallet_node_2.config["trusted_peers"] = {}
293
+
294
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
295
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
296
+ await server_2.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
297
+
298
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
299
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
300
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_2))
301
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
302
+
303
+ funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
304
+
305
+ await time_out_assert(20, wallet_0.get_confirmed_balance, funds)
306
+ await time_out_assert(20, full_node_api.wallet_is_synced, True, wallet_node_0)
307
+
308
+ cat_amt = 300000
309
+ dao_rules = DAORules(
310
+ proposal_timelock=uint64(5),
311
+ soft_close_length=uint64(5),
312
+ attendance_required=uint64(1000), # 10%
313
+ pass_percentage=uint64(5100), # 51%
314
+ self_destruct_length=uint64(20),
315
+ oracle_spend_delay=uint64(10),
316
+ proposal_minimum_amount=uint64(1),
317
+ )
318
+
319
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
320
+ dao_wallet_0 = await DAOWallet.create_new_dao_and_wallet(
321
+ wallet_node_0.wallet_state_manager, wallet_0, uint64(cat_amt), dao_rules, action_scope
322
+ )
323
+
324
+ treasury_id = dao_wallet_0.dao_info.treasury_id
325
+
326
+ # Get the full node sim to process the wallet creation spend
327
+ await full_node_api.wait_transaction_records_entered_mempool(
328
+ records=action_scope.side_effects.transactions, timeout=60
329
+ )
330
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
331
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
332
+
333
+ # get the cat wallets
334
+ cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.cat_wallet_id]
335
+ await time_out_assert(20, cat_wallet_0.get_confirmed_balance, cat_amt)
336
+
337
+ # Create funding spends for xch and cat
338
+ xch_funds = uint64(500000)
339
+ cat_funds = uint64(100000)
340
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
341
+ await dao_wallet_0.create_add_funds_to_treasury_spend(xch_funds, action_scope)
342
+ await full_node_api.wait_transaction_records_entered_mempool(
343
+ records=action_scope.side_effects.transactions, timeout=60
344
+ )
345
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
346
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
347
+
348
+ # Check that the funding spend is found
349
+ await time_out_assert(20, dao_wallet_0.get_balance_by_asset_type, xch_funds)
350
+
351
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
352
+ await dao_wallet_0.create_add_funds_to_treasury_spend(
353
+ cat_funds, action_scope, funding_wallet_id=cat_wallet_0.id()
354
+ )
355
+ await full_node_api.wait_transaction_records_entered_mempool(
356
+ records=action_scope.side_effects.transactions, timeout=60
357
+ )
358
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
359
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
360
+
361
+ await time_out_assert(20, cat_wallet_0.get_confirmed_balance, cat_amt - cat_funds)
362
+
363
+ # Check that the funding spend is found
364
+ cat_id = bytes32.from_hexstr(cat_wallet_0.get_asset_id())
365
+ await time_out_assert(20, dao_wallet_0.get_balance_by_asset_type, cat_funds, cat_id)
366
+
367
+ # Create and close a proposal
368
+ cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.cat_wallet_id]
369
+ dao_cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.dao_cat_wallet_id]
370
+ dao_cat_0_bal = await dao_cat_wallet_0.get_votable_balance()
371
+ async with dao_cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
372
+ await dao_cat_wallet_0.enter_dao_cat_voting_mode(dao_cat_0_bal, action_scope)
373
+ await full_node_api.wait_transaction_records_entered_mempool(
374
+ records=action_scope.side_effects.transactions, timeout=60
375
+ )
376
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
377
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
378
+
379
+ recipient_puzzle_hash = await wallet_2.get_new_puzzlehash()
380
+ proposal_amount_1 = uint64(10000)
381
+ xch_proposal_inner = generate_simple_proposal_innerpuz(
382
+ treasury_id,
383
+ [recipient_puzzle_hash],
384
+ [proposal_amount_1],
385
+ [None],
386
+ )
387
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
388
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, dao_cat_0_bal)
389
+ await full_node_api.wait_transaction_records_entered_mempool(
390
+ records=action_scope.side_effects.transactions, timeout=60
391
+ )
392
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
393
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
394
+
395
+ # farm blocks to pass proposal
396
+ for _ in range(5):
397
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
398
+
399
+ prop_0 = dao_wallet_0.dao_info.proposals_list[0]
400
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
401
+ await dao_wallet_0.create_proposal_close_spend(prop_0.proposal_id, action_scope)
402
+ await full_node_api.wait_transaction_records_entered_mempool(
403
+ records=action_scope.side_effects.transactions, timeout=60
404
+ )
405
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
406
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
407
+
408
+ # Create the other user's wallet from the treasury id
409
+ dao_wallet_1 = await DAOWallet.create_new_dao_wallet_for_existing_dao(
410
+ wallet_node_1.wallet_state_manager, wallet_1, treasury_id
411
+ )
412
+ assert dao_wallet_1.dao_info.treasury_id == dao_wallet_1.dao_info.treasury_id
413
+
414
+ # Get the cat wallets for wallet_1
415
+ cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.cat_wallet_id]
416
+ assert cat_wallet_1
417
+ assert cat_wallet_1.cat_info.limitations_program_hash == cat_id
418
+
419
+ await time_out_assert(30, dao_wallet_0.get_balance_by_asset_type, xch_funds - 10000)
420
+ await time_out_assert(30, dao_wallet_0.get_balance_by_asset_type, cat_funds, cat_id)
421
+ await time_out_assert(30, dao_wallet_1.get_balance_by_asset_type, xch_funds - 10000)
422
+ await time_out_assert(30, dao_wallet_1.get_balance_by_asset_type, cat_funds, cat_id)
423
+
424
+
425
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
426
+ @pytest.mark.parametrize(
427
+ "trusted",
428
+ [True, False],
429
+ )
430
+ @pytest.mark.anyio
431
+ async def test_dao_proposals(self_hostname: str, three_wallet_nodes: OldSimulatorsAndWallets, trusted: bool) -> None:
432
+ """
433
+ Test a set of proposals covering:
434
+ - the spend, update, and mint types.
435
+ - passing and failing
436
+ - force closing broken proposals
437
+
438
+ total cats issued: 300k
439
+ each wallet holds: 100k
440
+
441
+ The proposal types and amounts voted are:
442
+ P0 Spend => Pass
443
+ P1 Mint => Pass
444
+ P2 Update => Pass
445
+ P3 Spend => Fail
446
+ P4 Bad Spend => Force Close
447
+
448
+ """
449
+ full_nodes, wallets, _ = three_wallet_nodes
450
+ full_node_api = full_nodes[0]
451
+ full_node_server = full_node_api.server
452
+ wallet_node_0, server_0 = wallets[0]
453
+ wallet_node_1, server_1 = wallets[1]
454
+ wallet_node_2, server_2 = wallets[2]
455
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
456
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
457
+ wallet_2 = wallet_node_2.wallet_state_manager.main_wallet
458
+ ph_0 = await wallet_0.get_new_puzzlehash()
459
+ ph_1 = await wallet_1.get_new_puzzlehash()
460
+ ph_2 = await wallet_2.get_new_puzzlehash()
461
+
462
+ if trusted:
463
+ wallet_node_0.config["trusted_peers"] = {
464
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
465
+ }
466
+ wallet_node_1.config["trusted_peers"] = {
467
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
468
+ }
469
+ wallet_node_2.config["trusted_peers"] = {
470
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
471
+ }
472
+ else:
473
+ wallet_node_0.config["trusted_peers"] = {}
474
+ wallet_node_1.config["trusted_peers"] = {}
475
+ wallet_node_2.config["trusted_peers"] = {}
476
+
477
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
478
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
479
+ await server_2.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
480
+
481
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_0))
482
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
483
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_2))
484
+
485
+ funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
486
+
487
+ await time_out_assert(20, wallet_0.get_confirmed_balance, funds)
488
+ await time_out_assert(20, full_node_api.wallet_is_synced, True, wallet_node_0)
489
+
490
+ # set a standard fee amount to use in all txns
491
+ base_fee = uint64(100)
492
+
493
+ # set the cat issuance and DAO rules
494
+ cat_issuance = 300000
495
+ proposal_min_amt = uint64(101)
496
+ dao_rules = DAORules(
497
+ proposal_timelock=uint64(10),
498
+ soft_close_length=uint64(5),
499
+ attendance_required=uint64(190000),
500
+ pass_percentage=uint64(5100), # 51%
501
+ self_destruct_length=uint64(20),
502
+ oracle_spend_delay=uint64(10),
503
+ proposal_minimum_amount=proposal_min_amt,
504
+ )
505
+
506
+ # Create the DAO.
507
+ # This takes two steps: create the treasury singleton, wait for oracle_spend_delay and
508
+ # then complete the eve spend
509
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
510
+ dao_wallet_0 = await DAOWallet.create_new_dao_and_wallet(
511
+ wallet_node_0.wallet_state_manager,
512
+ wallet_0,
513
+ uint64(cat_issuance),
514
+ dao_rules,
515
+ action_scope,
516
+ )
517
+
518
+ await full_node_api.wait_transaction_records_entered_mempool(
519
+ records=action_scope.side_effects.transactions, timeout=60
520
+ )
521
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
522
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
523
+
524
+ cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.cat_wallet_id]
525
+ dao_cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.dao_cat_wallet_id]
526
+ await time_out_assert(10, cat_wallet_0.get_confirmed_balance, cat_issuance)
527
+ assert dao_cat_wallet_0
528
+
529
+ treasury_id = dao_wallet_0.dao_info.treasury_id
530
+
531
+ # Create dao_wallet_1 from the treasury id
532
+ dao_wallet_1 = await DAOWallet.create_new_dao_wallet_for_existing_dao(
533
+ wallet_node_1.wallet_state_manager, wallet_1, treasury_id
534
+ )
535
+ assert dao_wallet_1.dao_info.treasury_id == treasury_id
536
+ cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.cat_wallet_id]
537
+ dao_cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.dao_cat_wallet_id]
538
+ assert cat_wallet_1
539
+ assert dao_cat_wallet_1
540
+
541
+ # Create dao_wallet_2 from the treasury id
542
+ dao_wallet_2 = await DAOWallet.create_new_dao_wallet_for_existing_dao(
543
+ wallet_node_2.wallet_state_manager, wallet_2, treasury_id
544
+ )
545
+ assert dao_wallet_2.dao_info.treasury_id == treasury_id
546
+ cat_wallet_2 = dao_wallet_2.wallet_state_manager.wallets[dao_wallet_2.dao_info.cat_wallet_id]
547
+ dao_cat_wallet_2 = dao_wallet_2.wallet_state_manager.wallets[dao_wallet_2.dao_info.dao_cat_wallet_id]
548
+ assert cat_wallet_2
549
+ assert dao_cat_wallet_2
550
+
551
+ # Send 100k cats to wallet_1 and wallet_2
552
+ cat_amt = uint64(100000)
553
+ async with cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
554
+ await cat_wallet_0.generate_signed_transaction([cat_amt, cat_amt], [ph_1, ph_2], action_scope, fee=base_fee)
555
+ await full_node_api.wait_transaction_records_entered_mempool(
556
+ records=action_scope.side_effects.transactions, timeout=60
557
+ )
558
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
559
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
560
+
561
+ # Lockup voting cats for all wallets
562
+ dao_cat_0_bal = await dao_cat_wallet_0.get_votable_balance()
563
+ async with dao_cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
564
+ await dao_cat_wallet_0.enter_dao_cat_voting_mode(dao_cat_0_bal, action_scope, fee=base_fee)
565
+ await full_node_api.wait_transaction_records_entered_mempool(
566
+ records=action_scope.side_effects.transactions, timeout=60
567
+ )
568
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
569
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
570
+
571
+ dao_cat_1_bal = await dao_cat_wallet_1.get_votable_balance()
572
+ async with dao_cat_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
573
+ await dao_cat_wallet_1.enter_dao_cat_voting_mode(dao_cat_1_bal, action_scope)
574
+ await full_node_api.wait_transaction_records_entered_mempool(
575
+ records=action_scope.side_effects.transactions, timeout=60
576
+ )
577
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
578
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
579
+
580
+ dao_cat_2_bal = await dao_cat_wallet_2.get_votable_balance()
581
+ async with dao_cat_wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
582
+ await dao_cat_wallet_2.enter_dao_cat_voting_mode(dao_cat_2_bal, action_scope)
583
+ await full_node_api.wait_transaction_records_entered_mempool(
584
+ records=action_scope.side_effects.transactions, timeout=60
585
+ )
586
+ await full_node_api.process_all_wallet_transactions(wallet_2, timeout=60)
587
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
588
+
589
+ await time_out_assert(10, dao_cat_wallet_0.get_confirmed_balance, cat_amt)
590
+ await time_out_assert(10, dao_cat_wallet_1.get_confirmed_balance, cat_amt)
591
+ await time_out_assert(10, dao_cat_wallet_2.get_confirmed_balance, cat_amt)
592
+
593
+ # Create funding spend so the treasury holds some XCH
594
+ xch_funds = uint64(500000)
595
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
596
+ await dao_wallet_0.create_add_funds_to_treasury_spend(xch_funds, action_scope)
597
+ await full_node_api.wait_transaction_records_entered_mempool(
598
+ records=action_scope.side_effects.transactions, timeout=60
599
+ )
600
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
601
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
602
+
603
+ # Check that the funding spend is recognized by all wallets
604
+ await time_out_assert(10, dao_wallet_0.get_balance_by_asset_type, xch_funds)
605
+ await time_out_assert(10, dao_wallet_1.get_balance_by_asset_type, xch_funds)
606
+ await time_out_assert(10, dao_wallet_2.get_balance_by_asset_type, xch_funds)
607
+
608
+ # Create Proposals
609
+
610
+ # Proposal 0: Spend xch to wallet_2.
611
+ recipient_puzzle_hash = await wallet_2.get_new_puzzlehash()
612
+ proposal_amount_1 = uint64(9998)
613
+ xch_proposal_inner = generate_simple_proposal_innerpuz(
614
+ treasury_id,
615
+ [recipient_puzzle_hash],
616
+ [proposal_amount_1],
617
+ [None],
618
+ )
619
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
620
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, dao_cat_0_bal, fee=base_fee)
621
+ await full_node_api.wait_transaction_records_entered_mempool(
622
+ records=action_scope.side_effects.transactions, timeout=60
623
+ )
624
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
625
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
626
+
627
+ assert len(dao_wallet_0.dao_info.proposals_list) == 1
628
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == dao_cat_0_bal
629
+ assert dao_wallet_0.dao_info.proposals_list[0].timer_coin is not None
630
+ prop_0 = dao_wallet_0.dao_info.proposals_list[0]
631
+
632
+ # Proposal 1: Mint new CATs
633
+ new_mint_amount = uint64(1000)
634
+ mint_proposal_inner = await generate_mint_proposal_innerpuz(
635
+ treasury_id,
636
+ cat_wallet_0.cat_info.limitations_program_hash,
637
+ new_mint_amount,
638
+ recipient_puzzle_hash,
639
+ )
640
+
641
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
642
+ await dao_wallet_0.generate_new_proposal(
643
+ mint_proposal_inner, action_scope, vote_amount=dao_cat_0_bal, fee=base_fee
644
+ )
645
+ await full_node_api.wait_transaction_records_entered_mempool(
646
+ records=action_scope.side_effects.transactions, timeout=60
647
+ )
648
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
649
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
650
+
651
+ assert len(dao_wallet_0.dao_info.proposals_list) == 2
652
+ prop_1 = dao_wallet_0.dao_info.proposals_list[1]
653
+
654
+ # Proposal 2: Update DAO Rules.
655
+ new_dao_rules = DAORules(
656
+ proposal_timelock=uint64(8),
657
+ soft_close_length=uint64(4),
658
+ attendance_required=uint64(150000),
659
+ pass_percentage=uint64(7500),
660
+ self_destruct_length=uint64(12),
661
+ oracle_spend_delay=uint64(5),
662
+ proposal_minimum_amount=uint64(1),
663
+ )
664
+ current_innerpuz = dao_wallet_0.dao_info.current_treasury_innerpuz
665
+ assert current_innerpuz is not None
666
+ update_inner = await generate_update_proposal_innerpuz(current_innerpuz, new_dao_rules)
667
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
668
+ await dao_wallet_0.generate_new_proposal(update_inner, action_scope, dao_cat_0_bal, fee=base_fee)
669
+ await full_node_api.wait_transaction_records_entered_mempool(
670
+ records=action_scope.side_effects.transactions, timeout=60
671
+ )
672
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
673
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
674
+
675
+ assert len(dao_wallet_0.dao_info.proposals_list) == 3
676
+ prop_2 = dao_wallet_0.dao_info.proposals_list[2]
677
+
678
+ # Proposal 3: Spend xch to wallet_2 (this prop will close as failed)
679
+ proposal_amount_2 = uint64(500)
680
+ xch_proposal_inner = generate_simple_proposal_innerpuz(
681
+ treasury_id, [recipient_puzzle_hash], [proposal_amount_2], [None]
682
+ )
683
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
684
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, dao_cat_0_bal, fee=base_fee)
685
+ await full_node_api.wait_transaction_records_entered_mempool(
686
+ records=action_scope.side_effects.transactions, timeout=60
687
+ )
688
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
689
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
690
+
691
+ assert len(dao_wallet_0.dao_info.proposals_list) == 4
692
+ prop_3 = dao_wallet_0.dao_info.proposals_list[3]
693
+
694
+ # Proposal 4: Create a 'bad' proposal (can't be executed, must be force-closed)
695
+ xch_proposal_inner = Program.to(["x"])
696
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
697
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, dao_cat_0_bal, fee=base_fee)
698
+ await full_node_api.wait_transaction_records_entered_mempool(
699
+ records=action_scope.side_effects.transactions, timeout=60
700
+ )
701
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
702
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
703
+
704
+ assert len(dao_wallet_0.dao_info.proposals_list) == 5
705
+ assert len(dao_wallet_1.dao_info.proposals_list) == 5
706
+ assert len(dao_wallet_1.dao_info.proposals_list) == 5
707
+ prop_4 = dao_wallet_0.dao_info.proposals_list[4]
708
+
709
+ # Proposal 0 Voting: wallet 1 votes yes, wallet 2 votes no. Proposal Passes
710
+ async with dao_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
711
+ await dao_wallet_1.generate_proposal_vote_spend(prop_0.proposal_id, dao_cat_1_bal, True, action_scope)
712
+ await full_node_api.wait_transaction_records_entered_mempool(
713
+ records=action_scope.side_effects.transactions, timeout=60
714
+ )
715
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
716
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
717
+
718
+ async with dao_wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
719
+ await dao_wallet_2.generate_proposal_vote_spend(prop_0.proposal_id, dao_cat_2_bal, False, action_scope)
720
+ await full_node_api.wait_transaction_records_entered_mempool(
721
+ records=action_scope.side_effects.transactions, timeout=60
722
+ )
723
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
724
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
725
+
726
+ total_votes = dao_cat_0_bal + dao_cat_1_bal + dao_cat_2_bal
727
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == total_votes
728
+ assert dao_wallet_0.dao_info.proposals_list[0].yes_votes == total_votes - dao_cat_2_bal
729
+ assert dao_wallet_1.dao_info.proposals_list[0].amount_voted == total_votes
730
+ assert dao_wallet_1.dao_info.proposals_list[0].yes_votes == total_votes - dao_cat_2_bal
731
+ assert dao_wallet_2.dao_info.proposals_list[0].amount_voted == total_votes
732
+ assert dao_wallet_2.dao_info.proposals_list[0].yes_votes == total_votes - dao_cat_2_bal
733
+
734
+ prop_0_state = await dao_wallet_0.get_proposal_state(prop_0.proposal_id)
735
+ assert prop_0_state["passed"]
736
+ assert prop_0_state["closable"]
737
+
738
+ # Proposal 0 is closable, but soft_close_length has not passed.
739
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
740
+ await dao_wallet_0.create_proposal_close_spend(prop_0.proposal_id, action_scope)
741
+ with pytest.raises(AssertionError, match="Timed assertion timed out"):
742
+ assert action_scope.side_effects.transactions[0].spend_bundle is not None
743
+ await time_out_assert_not_none(
744
+ 5,
745
+ full_node_api.full_node.mempool_manager.get_spendbundle,
746
+ action_scope.side_effects.transactions[0].spend_bundle.name(),
747
+ )
748
+
749
+ for _ in range(5):
750
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
751
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
752
+
753
+ # Proposal 0: Close
754
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
755
+ await dao_wallet_0.create_proposal_close_spend(prop_0.proposal_id, action_scope)
756
+ close_sb_0 = action_scope.side_effects.transactions[0].spend_bundle
757
+ assert close_sb_0 is not None
758
+ await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, close_sb_0.name())
759
+ await full_node_api.process_spend_bundles(bundles=[close_sb_0])
760
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
761
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
762
+ await time_out_assert(20, wallet_2.get_confirmed_balance, funds + proposal_amount_1)
763
+ await time_out_assert(
764
+ 20, dao_wallet_0.get_balance_by_asset_type, xch_funds - proposal_amount_1 + proposal_min_amt - 1
765
+ )
766
+
767
+ await time_out_assert(20, get_proposal_state, (True, True), *[dao_wallet_0, 0])
768
+ await time_out_assert(20, get_proposal_state, (True, True), *[dao_wallet_1, 0])
769
+ await time_out_assert(20, get_proposal_state, (True, True), *[dao_wallet_2, 0])
770
+
771
+ # Proposal 1 vote and close
772
+ async with dao_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
773
+ await dao_wallet_1.generate_proposal_vote_spend(prop_1.proposal_id, dao_cat_1_bal, True, action_scope)
774
+ await full_node_api.wait_transaction_records_entered_mempool(
775
+ records=action_scope.side_effects.transactions, timeout=60
776
+ )
777
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
778
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
779
+
780
+ for _ in range(10):
781
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
782
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
783
+
784
+ prop_1_state = await dao_wallet_0.get_proposal_state(prop_1.proposal_id)
785
+ assert prop_1_state["passed"]
786
+ assert prop_1_state["closable"]
787
+
788
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
789
+ await dao_wallet_0.create_proposal_close_spend(prop_1.proposal_id, action_scope)
790
+ await full_node_api.wait_transaction_records_entered_mempool(
791
+ records=action_scope.side_effects.transactions, timeout=60
792
+ )
793
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
794
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
795
+
796
+ await time_out_assert(20, cat_wallet_2.get_confirmed_balance, new_mint_amount)
797
+
798
+ # Proposal 2 vote and close
799
+ async with dao_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
800
+ await dao_wallet_1.generate_proposal_vote_spend(prop_2.proposal_id, dao_cat_1_bal, True, action_scope)
801
+ await full_node_api.wait_transaction_records_entered_mempool(
802
+ records=action_scope.side_effects.transactions, timeout=60
803
+ )
804
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
805
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
806
+
807
+ for _ in range(10):
808
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
809
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
810
+
811
+ prop_2_state = await dao_wallet_0.get_proposal_state(prop_2.proposal_id)
812
+ assert prop_2_state["passed"]
813
+ assert prop_2_state["closable"]
814
+
815
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
816
+ await dao_wallet_0.create_proposal_close_spend(prop_2.proposal_id, action_scope)
817
+ await full_node_api.wait_transaction_records_entered_mempool(
818
+ records=action_scope.side_effects.transactions, timeout=60
819
+ )
820
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
821
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
822
+
823
+ assert dao_wallet_0.dao_rules == new_dao_rules
824
+ assert dao_wallet_1.dao_rules == new_dao_rules
825
+ assert dao_wallet_2.dao_rules == new_dao_rules
826
+
827
+ # Proposal 3 - Close as FAILED
828
+ async with dao_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
829
+ await dao_wallet_1.generate_proposal_vote_spend(prop_3.proposal_id, dao_cat_1_bal, False, action_scope)
830
+ await full_node_api.wait_transaction_records_entered_mempool(
831
+ records=action_scope.side_effects.transactions, timeout=60
832
+ )
833
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
834
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
835
+
836
+ for _ in range(10):
837
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
838
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
839
+
840
+ prop_3_state = await dao_wallet_1.get_proposal_state(prop_3.proposal_id)
841
+ assert not prop_3_state["passed"]
842
+ assert prop_3_state["closable"]
843
+
844
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
845
+ await dao_wallet_0.create_proposal_close_spend(prop_3.proposal_id, action_scope)
846
+ await full_node_api.wait_transaction_records_entered_mempool(
847
+ records=action_scope.side_effects.transactions, timeout=60
848
+ )
849
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
850
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
851
+
852
+ await time_out_assert(20, wallet_2.get_confirmed_balance, funds + proposal_amount_1)
853
+ expected_balance = xch_funds - proposal_amount_1 + (3 * proposal_min_amt) - 3 - new_mint_amount
854
+ await time_out_assert(20, dao_wallet_0.get_balance_by_asset_type, expected_balance)
855
+
856
+ await time_out_assert(20, get_proposal_state, (False, True), *[dao_wallet_0, 3])
857
+ await time_out_assert(20, get_proposal_state, (False, True), *[dao_wallet_1, 3])
858
+ await time_out_assert(20, get_proposal_state, (False, True), *[dao_wallet_2, 3])
859
+
860
+ # Proposal 4 - Self Destruct a broken proposal
861
+ async with dao_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
862
+ await dao_wallet_1.generate_proposal_vote_spend(prop_4.proposal_id, dao_cat_1_bal, True, action_scope)
863
+ await full_node_api.wait_transaction_records_entered_mempool(
864
+ records=action_scope.side_effects.transactions, timeout=60
865
+ )
866
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
867
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
868
+
869
+ for _ in range(10):
870
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
871
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
872
+
873
+ prop_4_state = await dao_wallet_1.get_proposal_state(prop_4.proposal_id)
874
+ assert prop_4_state["passed"]
875
+ assert prop_4_state["closable"]
876
+
877
+ with pytest.raises(Exception, match="Unrecognised proposal type"):
878
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
879
+ await dao_wallet_0.create_proposal_close_spend(prop_4.proposal_id, action_scope)
880
+
881
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
882
+ await dao_wallet_0.create_proposal_close_spend(prop_4.proposal_id, action_scope, self_destruct=True)
883
+ await full_node_api.wait_transaction_records_entered_mempool(
884
+ records=action_scope.side_effects.transactions, timeout=60
885
+ )
886
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
887
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
888
+
889
+ # expected balance is unchanged because broken props can't release their amount
890
+ await time_out_assert(20, dao_wallet_0.get_balance_by_asset_type, expected_balance)
891
+ await time_out_assert(20, get_proposal_state, (True, True), *[dao_wallet_0, 4])
892
+ await time_out_assert(20, get_proposal_state, (True, True), *[dao_wallet_1, 4])
893
+ await time_out_assert(20, get_proposal_state, (True, True), *[dao_wallet_2, 4])
894
+
895
+ # Remove Proposals from Memory and Free up locked coins
896
+ await time_out_assert(20, len, 5, dao_wallet_0.dao_info.proposals_list)
897
+ await dao_wallet_0.clear_finished_proposals_from_memory()
898
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
899
+ await dao_wallet_0.free_coins_from_finished_proposals(action_scope, fee=uint64(100))
900
+ await full_node_api.wait_transaction_records_entered_mempool(
901
+ records=action_scope.side_effects.transactions, timeout=60
902
+ )
903
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
904
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
905
+
906
+ await dao_wallet_0.clear_finished_proposals_from_memory()
907
+ await time_out_assert(20, len, 0, dao_wallet_0.dao_info.proposals_list)
908
+
909
+
910
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
911
+ @pytest.mark.parametrize(
912
+ "trusted",
913
+ [True, False],
914
+ )
915
+ @pytest.mark.anyio
916
+ async def test_dao_proposal_partial_vote(
917
+ self_hostname: str, two_wallet_nodes: OldSimulatorsAndWallets, trusted: bool
918
+ ) -> None:
919
+ full_nodes, wallets, _ = two_wallet_nodes
920
+ full_node_api = full_nodes[0]
921
+ full_node_server = full_node_api.server
922
+ wallet_node_0, server_0 = wallets[0]
923
+ wallet_node_1, server_1 = wallets[1]
924
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
925
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
926
+ ph = await wallet_0.get_new_puzzlehash()
927
+ ph_1 = await wallet_1.get_new_puzzlehash()
928
+
929
+ if trusted:
930
+ wallet_node_0.config["trusted_peers"] = {
931
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
932
+ }
933
+ wallet_node_1.config["trusted_peers"] = {
934
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
935
+ }
936
+ else:
937
+ wallet_node_0.config["trusted_peers"] = {}
938
+ wallet_node_1.config["trusted_peers"] = {}
939
+
940
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
941
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
942
+
943
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
944
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
945
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
946
+
947
+ funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
948
+
949
+ await time_out_assert(20, wallet_0.get_confirmed_balance, funds)
950
+ await time_out_assert(20, full_node_api.wallet_is_synced, True, wallet_node_0)
951
+
952
+ cat_amt = 300000
953
+ dao_rules = DAORules(
954
+ proposal_timelock=uint64(10),
955
+ soft_close_length=uint64(5),
956
+ attendance_required=uint64(1000), # 10%
957
+ pass_percentage=uint64(5100), # 51%
958
+ self_destruct_length=uint64(20),
959
+ oracle_spend_delay=uint64(10),
960
+ proposal_minimum_amount=uint64(1),
961
+ )
962
+
963
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
964
+ dao_wallet_0 = await DAOWallet.create_new_dao_and_wallet(
965
+ wallet_node_0.wallet_state_manager, wallet_0, uint64(cat_amt), dao_rules, action_scope
966
+ )
967
+
968
+ # Get the full node sim to process the wallet creation spend
969
+ await full_node_api.wait_transaction_records_entered_mempool(
970
+ records=action_scope.side_effects.transactions, timeout=60
971
+ )
972
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
973
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
974
+
975
+ # get the cat wallets
976
+ cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.cat_wallet_id]
977
+ await time_out_assert(10, cat_wallet_0.get_confirmed_balance, cat_amt)
978
+
979
+ # get the dao_cat wallet
980
+ dao_cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.dao_cat_wallet_id]
981
+
982
+ treasury_id = dao_wallet_0.dao_info.treasury_id
983
+
984
+ # make sure the next wallet node can find the treasury
985
+ assert dao_wallet_0.dao_info.current_treasury_coin is not None
986
+ treasury_parent = dao_wallet_0.dao_info.current_treasury_coin.parent_coin_info
987
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
988
+ await time_out_assert_not_none(
989
+ 60, wallet_node_1.fetch_children, treasury_parent, wallet_node_1.get_full_node_peer()
990
+ )
991
+ # Create the other user's wallet from the treasury id
992
+ dao_wallet_1 = await DAOWallet.create_new_dao_wallet_for_existing_dao(
993
+ wallet_node_1.wallet_state_manager, wallet_1, treasury_id
994
+ )
995
+ assert dao_wallet_1.dao_info.treasury_id == treasury_id
996
+
997
+ # Create funding spends for xch
998
+ xch_funds = uint64(500000)
999
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1000
+ await dao_wallet_0.create_add_funds_to_treasury_spend(
1001
+ xch_funds,
1002
+ action_scope,
1003
+ )
1004
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1005
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1006
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
1007
+
1008
+ # Check that the funding spend is recognized by both dao wallets
1009
+ await time_out_assert(10, dao_wallet_0.get_balance_by_asset_type, xch_funds)
1010
+
1011
+ # Send some dao_cats to wallet_1
1012
+ # Get the cat wallets for wallet_1
1013
+ cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.cat_wallet_id]
1014
+ dao_cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.dao_cat_wallet_id]
1015
+ assert cat_wallet_1
1016
+ assert dao_cat_wallet_1
1017
+
1018
+ async with cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1019
+ await cat_wallet_0.generate_signed_transaction([100000], [ph_1], action_scope)
1020
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1021
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1022
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
1023
+ await time_out_assert(10, cat_wallet_1.get_spendable_balance, 100000)
1024
+
1025
+ # Create dao cats for voting
1026
+ dao_cat_0_bal = await dao_cat_wallet_0.get_votable_balance()
1027
+ async with dao_cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1028
+ await dao_cat_wallet_0.enter_dao_cat_voting_mode(dao_cat_0_bal, action_scope)
1029
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1030
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1031
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1032
+
1033
+ # Create a mint proposal
1034
+ recipient_puzzle_hash = await cat_wallet_1.get_new_inner_hash()
1035
+ new_mint_amount = uint64(500)
1036
+ mint_proposal_inner = await generate_mint_proposal_innerpuz(
1037
+ treasury_id,
1038
+ cat_wallet_0.cat_info.limitations_program_hash,
1039
+ new_mint_amount,
1040
+ recipient_puzzle_hash,
1041
+ )
1042
+
1043
+ vote_amount = dao_cat_0_bal - 10
1044
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1045
+ await dao_wallet_0.generate_new_proposal(
1046
+ mint_proposal_inner, action_scope, vote_amount=vote_amount, fee=uint64(1000)
1047
+ )
1048
+ await full_node_api.wait_transaction_records_entered_mempool(records=action_scope.side_effects.transactions)
1049
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1050
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1051
+
1052
+ # Check the proposal is saved
1053
+ assert len(dao_wallet_0.dao_info.proposals_list) == 1
1054
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == vote_amount
1055
+ assert dao_wallet_0.dao_info.proposals_list[0].timer_coin is not None
1056
+
1057
+ # Check that wallet_1 also finds and saved the proposal
1058
+ assert len(dao_wallet_1.dao_info.proposals_list) == 1
1059
+ prop = dao_wallet_1.dao_info.proposals_list[0]
1060
+
1061
+ # Create votable dao cats and add a new vote
1062
+ dao_cat_1_bal = await dao_cat_wallet_1.get_votable_balance()
1063
+ async with dao_cat_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1064
+ await dao_cat_wallet_1.enter_dao_cat_voting_mode(dao_cat_1_bal, action_scope)
1065
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1066
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1067
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1068
+
1069
+ async with dao_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1070
+ await dao_wallet_1.generate_proposal_vote_spend(prop.proposal_id, dao_cat_1_bal // 2, True, action_scope)
1071
+ [vote_tx] = action_scope.side_effects.transactions
1072
+ vote_sb = vote_tx.spend_bundle
1073
+ assert vote_sb is not None
1074
+ await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, vote_sb.name())
1075
+ await full_node_api.process_spend_bundles(bundles=[vote_sb])
1076
+
1077
+ for i in range(1, dao_rules.proposal_timelock + 1):
1078
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1079
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1080
+
1081
+ total_votes = vote_amount + dao_cat_1_bal // 2
1082
+
1083
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == total_votes
1084
+ assert dao_wallet_0.dao_info.proposals_list[0].yes_votes == total_votes
1085
+ assert dao_wallet_1.dao_info.proposals_list[0].amount_voted == total_votes
1086
+ assert dao_wallet_1.dao_info.proposals_list[0].yes_votes == total_votes
1087
+
1088
+ try:
1089
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1090
+ await dao_wallet_0.create_proposal_close_spend(prop.proposal_id, action_scope, fee=uint64(100))
1091
+ except Exception as e: # pragma: no cover
1092
+ print(e)
1093
+
1094
+ await full_node_api.process_transaction_records(action_scope.side_effects.transactions)
1095
+ balance = await cat_wallet_1.get_spendable_balance()
1096
+
1097
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1098
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1099
+
1100
+ await time_out_assert(20, get_proposal_state, (True, True), dao_wallet_0, 0)
1101
+ await time_out_assert(20, get_proposal_state, (True, True), dao_wallet_1, 0)
1102
+
1103
+ await time_out_assert(20, cat_wallet_1.get_spendable_balance, balance + new_mint_amount)
1104
+ # Can we spend the newly minted CATs?
1105
+ old_balance = await cat_wallet_0.get_spendable_balance()
1106
+ ph_0 = await cat_wallet_0.get_new_inner_hash()
1107
+ async with cat_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1108
+ await cat_wallet_1.generate_signed_transaction([balance + new_mint_amount], [ph_0], action_scope)
1109
+ await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
1110
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1111
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1112
+
1113
+ await time_out_assert(20, cat_wallet_1.get_spendable_balance, 0)
1114
+ await time_out_assert(20, cat_wallet_0.get_spendable_balance, old_balance + balance + new_mint_amount)
1115
+ # release coins
1116
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1117
+ await dao_wallet_0.free_coins_from_finished_proposals(action_scope)
1118
+
1119
+
1120
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
1121
+ @pytest.mark.parametrize(
1122
+ "trusted",
1123
+ [True, False],
1124
+ )
1125
+ @pytest.mark.anyio
1126
+ async def test_dao_rpc_api(self_hostname: str, two_wallet_nodes: Any, trusted: Any) -> None:
1127
+ full_nodes, wallets, _ = two_wallet_nodes
1128
+ full_node_api = full_nodes[0]
1129
+ full_node_server = full_node_api.server
1130
+ wallet_node_0, server_0 = wallets[0]
1131
+ wallet_node_1, server_1 = wallets[1]
1132
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
1133
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
1134
+
1135
+ ph_0 = await wallet_0.get_new_puzzlehash()
1136
+ ph_1 = await wallet_1.get_new_puzzlehash()
1137
+
1138
+ if trusted:
1139
+ wallet_node_0.config["trusted_peers"] = {
1140
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
1141
+ }
1142
+ wallet_node_1.config["trusted_peers"] = {
1143
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
1144
+ }
1145
+ else:
1146
+ wallet_node_0.config["trusted_peers"] = {}
1147
+ wallet_node_1.config["trusted_peers"] = {}
1148
+
1149
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
1150
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
1151
+
1152
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_0))
1153
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1154
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
1155
+
1156
+ funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
1157
+
1158
+ await time_out_assert(30, wallet_0.get_unconfirmed_balance, funds)
1159
+ await time_out_assert(30, wallet_0.get_confirmed_balance, funds)
1160
+
1161
+ api_0 = WalletRpcApi(wallet_node_0)
1162
+ api_1 = WalletRpcApi(wallet_node_1)
1163
+
1164
+ cat_amt = 300000
1165
+ fee = 10000
1166
+ dao_rules = DAORules(
1167
+ proposal_timelock=uint64(10),
1168
+ soft_close_length=uint64(5),
1169
+ attendance_required=uint64(1000), # 10%
1170
+ pass_percentage=uint64(5100), # 51%
1171
+ self_destruct_length=uint64(20),
1172
+ oracle_spend_delay=uint64(10),
1173
+ proposal_minimum_amount=uint64(1),
1174
+ )
1175
+
1176
+ # Try to create a DAO without rules
1177
+ with pytest.raises(ValueError) as e_info:
1178
+ dao_wallet_0 = await api_0.create_new_wallet(
1179
+ dict(
1180
+ wallet_type="dao_wallet",
1181
+ name="DAO WALLET 1",
1182
+ mode="new",
1183
+ amount_of_cats=cat_amt,
1184
+ filter_amount=1,
1185
+ fee=fee,
1186
+ )
1187
+ )
1188
+ assert e_info.value.args[0] == "DAO rules must be specified for wallet creation"
1189
+
1190
+ dao_wallet_0 = await api_0.create_new_wallet(
1191
+ dict(
1192
+ wallet_type="dao_wallet",
1193
+ name="DAO WALLET 1",
1194
+ mode="new",
1195
+ dao_rules=dao_rules,
1196
+ amount_of_cats=cat_amt,
1197
+ filter_amount=1,
1198
+ fee=fee,
1199
+ )
1200
+ )
1201
+ assert isinstance(dao_wallet_0, dict)
1202
+ assert dao_wallet_0.get("success")
1203
+ dao_wallet_0_id = dao_wallet_0["wallet_id"]
1204
+ dao_cat_wallet_0_id = dao_wallet_0["cat_wallet_id"]
1205
+ treasury_id = bytes32(dao_wallet_0["treasury_id"])
1206
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
1207
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1208
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1209
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
1210
+
1211
+ await time_out_assert(30, wallet_0.get_pending_change_balance, 0)
1212
+ expected_xch = funds - 1 - cat_amt - fee
1213
+ await time_out_assert(30, wallet_0.get_confirmed_balance, expected_xch)
1214
+
1215
+ dao_wallet_1 = await api_1.create_new_wallet(
1216
+ dict(
1217
+ wallet_type="dao_wallet",
1218
+ name="DAO WALLET 2",
1219
+ mode="existing",
1220
+ treasury_id=treasury_id.hex(),
1221
+ filter_amount=1,
1222
+ )
1223
+ )
1224
+ assert isinstance(dao_wallet_1, dict)
1225
+ assert dao_wallet_1.get("success")
1226
+ dao_wallet_1_id = dao_wallet_1["wallet_id"]
1227
+ # Create a cat wallet and add funds to treasury
1228
+ new_cat_amt = 1000000000000
1229
+ cat_wallet_0 = await api_0.create_new_wallet(
1230
+ dict(
1231
+ wallet_type="cat_wallet",
1232
+ name="CAT WALLET 1",
1233
+ test=True,
1234
+ mode="new",
1235
+ amount=new_cat_amt,
1236
+ )
1237
+ )
1238
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
1239
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1240
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1241
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
1242
+
1243
+ cat_wallet_0_id = cat_wallet_0["wallet_id"]
1244
+ cat_id = bytes32.from_hexstr(cat_wallet_0["asset_id"])
1245
+
1246
+ await rpc_state(
1247
+ 20,
1248
+ api_0.get_wallet_balance,
1249
+ [{"wallet_id": cat_wallet_0_id}],
1250
+ lambda x: x["wallet_balance"]["confirmed_wallet_balance"],
1251
+ new_cat_amt,
1252
+ )
1253
+
1254
+ cat_funding_amt = 500000
1255
+ cat_tx = await api_0.dao_add_funds_to_treasury(
1256
+ dict(
1257
+ wallet_id=dao_wallet_0_id,
1258
+ amount=cat_funding_amt,
1259
+ funding_wallet_id=cat_wallet_0_id,
1260
+ )
1261
+ )
1262
+
1263
+ xch_funding_amt = 200000
1264
+ xch_tx = await api_0.dao_add_funds_to_treasury(
1265
+ dict(
1266
+ wallet_id=dao_wallet_0_id,
1267
+ amount=xch_funding_amt,
1268
+ funding_wallet_id=1,
1269
+ )
1270
+ )
1271
+ txs = [TransactionRecord.from_json_dict(cat_tx["tx"]), TransactionRecord.from_json_dict(xch_tx["tx"])]
1272
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1273
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1274
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
1275
+
1276
+ expected_xch -= xch_funding_amt + new_cat_amt
1277
+ await time_out_assert(30, wallet_0.get_confirmed_balance, expected_xch)
1278
+
1279
+ await rpc_state(
1280
+ 20,
1281
+ api_0.get_wallet_balance,
1282
+ [{"wallet_id": cat_wallet_0_id}],
1283
+ lambda x: x["wallet_balance"]["confirmed_wallet_balance"],
1284
+ new_cat_amt - cat_funding_amt,
1285
+ )
1286
+
1287
+ await rpc_state(
1288
+ 20, api_0.dao_get_treasury_balance, [{"wallet_id": dao_wallet_0_id}], lambda x: x["balances"]["xch"]
1289
+ )
1290
+ balances = await api_0.dao_get_treasury_balance({"wallet_id": dao_wallet_0_id})
1291
+ assert balances["balances"]["xch"] == xch_funding_amt
1292
+ assert balances["balances"][cat_id.hex()] == cat_funding_amt
1293
+
1294
+ # Send some cats to wallet_1
1295
+ await api_0.cat_spend(
1296
+ {
1297
+ "wallet_id": dao_cat_wallet_0_id,
1298
+ "amount": cat_amt // 2,
1299
+ "inner_address": encode_puzzle_hash(ph_1, "xch"),
1300
+ "fee": fee,
1301
+ }
1302
+ )
1303
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
1304
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1305
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1306
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
1307
+
1308
+ await rpc_state(
1309
+ 20,
1310
+ api_0.get_wallet_balance,
1311
+ [{"wallet_id": dao_cat_wallet_0_id}],
1312
+ lambda x: x["wallet_balance"]["confirmed_wallet_balance"],
1313
+ cat_amt // 2,
1314
+ )
1315
+
1316
+ # send cats to lockup
1317
+ await api_0.dao_send_to_lockup({"wallet_id": dao_wallet_0_id, "amount": cat_amt // 2})
1318
+ tx_queue = await wallet_node_0.wallet_state_manager.tx_store.get_not_sent()
1319
+ await full_node_api.process_transaction_records(records=[tx for tx in tx_queue])
1320
+ await api_1.dao_send_to_lockup({"wallet_id": dao_wallet_1_id, "amount": cat_amt // 2})
1321
+ tx_queue = await wallet_node_1.wallet_state_manager.tx_store.get_not_sent()
1322
+ await full_node_api.process_transaction_records(records=[tx for tx in tx_queue])
1323
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
1324
+
1325
+ # create a spend proposal
1326
+ additions = [
1327
+ {"puzzle_hash": ph_1.hex(), "amount": 1000},
1328
+ ]
1329
+ create_proposal = await api_0.dao_create_proposal(
1330
+ {
1331
+ "wallet_id": dao_wallet_0_id,
1332
+ "proposal_type": "spend",
1333
+ "additions": additions,
1334
+ "vote_amount": cat_amt // 2,
1335
+ "fee": fee,
1336
+ }
1337
+ )
1338
+ txs = [TransactionRecord.from_json_dict(create_proposal["tx"])]
1339
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1340
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1341
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1342
+
1343
+ await rpc_state(20, api_0.dao_get_proposals, [{"wallet_id": dao_wallet_0_id}], lambda x: len(x["proposals"]), 1)
1344
+
1345
+ await rpc_state(20, api_1.dao_get_proposals, [{"wallet_id": dao_wallet_1_id}], lambda x: len(x["proposals"]), 1)
1346
+
1347
+ props_0 = await api_0.dao_get_proposals({"wallet_id": dao_wallet_0_id})
1348
+ prop = props_0["proposals"][0]
1349
+ assert prop.amount_voted == cat_amt // 2
1350
+ assert prop.yes_votes == cat_amt // 2
1351
+
1352
+ # Add votes
1353
+ vote_tx = await api_1.dao_vote_on_proposal(
1354
+ {
1355
+ "wallet_id": dao_wallet_1_id,
1356
+ "vote_amount": cat_amt // 2,
1357
+ "proposal_id": prop.proposal_id.hex(),
1358
+ "is_yes_vote": True,
1359
+ }
1360
+ )
1361
+ txs = [TransactionRecord.from_json_dict(vote_tx["tx"])]
1362
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1363
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
1364
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1365
+
1366
+ await rpc_state(
1367
+ 20, api_0.dao_get_proposals, [{"wallet_id": dao_wallet_0_id}], lambda x: x["proposals"][0].amount_voted, cat_amt
1368
+ )
1369
+
1370
+ # farm blocks until we can close proposal
1371
+ state = await api_0.dao_get_proposal_state({"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()})
1372
+ for _ in range(state["state"]["blocks_needed"] + 1):
1373
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1374
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1375
+
1376
+ await rpc_state(
1377
+ 20,
1378
+ api_0.dao_get_proposal_state,
1379
+ [{"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()}],
1380
+ lambda x: x["state"]["closable"],
1381
+ True,
1382
+ )
1383
+
1384
+ proposal_tx = await api_0.dao_close_proposal({"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()})
1385
+ txs = [TransactionRecord.from_json_dict(proposal_tx["tx"])]
1386
+ try:
1387
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1388
+ except TimeoutError: # pragma: no cover
1389
+ # try again
1390
+ await api_0.push_tx({"spend_bundle": txs[0].spend_bundle.stream_to_bytes().hex()})
1391
+ await full_node_api.wait_transaction_records_marked_as_in_mempool([txs[0].name], wallet_node_0, 60)
1392
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1393
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1394
+
1395
+ await rpc_state(
1396
+ 20, api_0.dao_get_proposals, [{"wallet_id": dao_wallet_0_id}], lambda x: x["proposals"][0].closed, True
1397
+ )
1398
+
1399
+ # check that the proposal state has changed for everyone
1400
+ await rpc_state(
1401
+ 20,
1402
+ api_0.dao_get_proposal_state,
1403
+ [{"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()}],
1404
+ lambda x: x["state"]["closed"],
1405
+ True,
1406
+ )
1407
+
1408
+ await rpc_state(
1409
+ 20,
1410
+ api_1.dao_get_proposal_state,
1411
+ [{"wallet_id": dao_wallet_1_id, "proposal_id": prop.proposal_id.hex()}],
1412
+ lambda x: x["state"]["closed"],
1413
+ True,
1414
+ )
1415
+
1416
+ # create a mint proposal
1417
+ mint_proposal = await api_0.dao_create_proposal(
1418
+ {
1419
+ "wallet_id": dao_wallet_0_id,
1420
+ "proposal_type": "mint",
1421
+ "amount": uint64(10000),
1422
+ "cat_target_address": encode_puzzle_hash(ph_0, "xch"),
1423
+ "vote_amount": cat_amt // 2,
1424
+ "fee": fee,
1425
+ }
1426
+ )
1427
+ txs = [TransactionRecord.from_json_dict(mint_proposal["tx"])]
1428
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1429
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1430
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1431
+
1432
+ await rpc_state(20, api_0.dao_get_proposals, [{"wallet_id": dao_wallet_0_id}], lambda x: len(x["proposals"]), 2)
1433
+
1434
+ await rpc_state(20, api_1.dao_get_proposals, [{"wallet_id": dao_wallet_1_id}], lambda x: len(x["proposals"]), 2)
1435
+
1436
+ props = await api_0.dao_get_proposals({"wallet_id": dao_wallet_0_id})
1437
+ prop = props["proposals"][1]
1438
+ assert prop.amount_voted == cat_amt // 2
1439
+ assert prop.yes_votes == cat_amt // 2
1440
+
1441
+ # Add votes
1442
+ vote_tx = await api_1.dao_vote_on_proposal(
1443
+ {
1444
+ "wallet_id": dao_wallet_1_id,
1445
+ "vote_amount": cat_amt // 2,
1446
+ "proposal_id": prop.proposal_id.hex(),
1447
+ "is_yes_vote": True,
1448
+ }
1449
+ )
1450
+ txs = [TransactionRecord.from_json_dict(vote_tx["tx"])]
1451
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1452
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
1453
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1454
+
1455
+ await rpc_state(
1456
+ 20, api_0.dao_get_proposals, [{"wallet_id": dao_wallet_0_id}], lambda x: x["proposals"][1].amount_voted, cat_amt
1457
+ )
1458
+
1459
+ # farm blocks until we can close proposal
1460
+ state = await api_0.dao_get_proposal_state({"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()})
1461
+ for _ in range(state["state"]["blocks_needed"] + 1):
1462
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1463
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1464
+
1465
+ await rpc_state(
1466
+ 20,
1467
+ api_0.dao_get_proposal_state,
1468
+ [{"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()}],
1469
+ lambda x: x["state"]["closable"],
1470
+ True,
1471
+ )
1472
+
1473
+ proposal_tx = await api_0.dao_close_proposal({"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()})
1474
+ txs = [TransactionRecord.from_json_dict(proposal_tx["tx"])]
1475
+ try:
1476
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1477
+ except TimeoutError: # pragma: no cover
1478
+ # try again
1479
+ await api_0.push_tx({"spend_bundle": txs[0].spend_bundle.stream_to_bytes().hex()})
1480
+ await full_node_api.wait_transaction_records_marked_as_in_mempool([txs[0].name], wallet_node_0, 60)
1481
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1482
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1483
+
1484
+ await rpc_state(
1485
+ 20, api_0.dao_get_proposals, [{"wallet_id": dao_wallet_0_id}], lambda x: x["proposals"][1].closed, True
1486
+ )
1487
+
1488
+ # check that the proposal state has changed for everyone
1489
+ await rpc_state(
1490
+ 20,
1491
+ api_0.dao_get_proposal_state,
1492
+ [{"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()}],
1493
+ lambda x: x["state"]["closed"],
1494
+ True,
1495
+ )
1496
+
1497
+ await rpc_state(
1498
+ 20,
1499
+ api_1.dao_get_proposal_state,
1500
+ [{"wallet_id": dao_wallet_1_id, "proposal_id": prop.proposal_id.hex()}],
1501
+ lambda x: x["state"]["closed"],
1502
+ True,
1503
+ )
1504
+
1505
+ # Check the minted cats are received
1506
+ await rpc_state(
1507
+ 20,
1508
+ api_0.get_wallet_balance,
1509
+ [{"wallet_id": dao_cat_wallet_0_id}],
1510
+ lambda x: x["wallet_balance"]["confirmed_wallet_balance"],
1511
+ 10000,
1512
+ )
1513
+
1514
+ # create an update proposal
1515
+ new_dao_rules = {"pass_percentage": 10000}
1516
+ update_proposal = await api_0.dao_create_proposal(
1517
+ {
1518
+ "wallet_id": dao_wallet_0_id,
1519
+ "proposal_type": "update",
1520
+ "new_dao_rules": new_dao_rules,
1521
+ "vote_amount": cat_amt // 2,
1522
+ "fee": fee,
1523
+ }
1524
+ )
1525
+ txs = [TransactionRecord.from_json_dict(update_proposal["tx"])]
1526
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1527
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1528
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1529
+
1530
+ await rpc_state(20, api_0.dao_get_proposals, [{"wallet_id": dao_wallet_0_id}], lambda x: len(x["proposals"]), 3)
1531
+
1532
+ await rpc_state(20, api_1.dao_get_proposals, [{"wallet_id": dao_wallet_1_id}], lambda x: len(x["proposals"]), 3)
1533
+
1534
+ props = await api_0.dao_get_proposals({"wallet_id": dao_wallet_0_id})
1535
+ prop = props["proposals"][2]
1536
+ assert prop.amount_voted == cat_amt // 2
1537
+ assert prop.yes_votes == cat_amt // 2
1538
+
1539
+ # Add votes
1540
+ vote_tx = await api_1.dao_vote_on_proposal(
1541
+ {
1542
+ "wallet_id": dao_wallet_1_id,
1543
+ "vote_amount": cat_amt // 2,
1544
+ "proposal_id": prop.proposal_id.hex(),
1545
+ "is_yes_vote": True,
1546
+ }
1547
+ )
1548
+ txs = [TransactionRecord.from_json_dict(vote_tx["tx"])]
1549
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1550
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
1551
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1552
+
1553
+ await rpc_state(
1554
+ 20, api_0.dao_get_proposals, [{"wallet_id": dao_wallet_0_id}], lambda x: x["proposals"][2].amount_voted, cat_amt
1555
+ )
1556
+
1557
+ # farm blocks until we can close proposal
1558
+ state = await api_0.dao_get_proposal_state({"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()})
1559
+ for _ in range(state["state"]["blocks_needed"] + 1):
1560
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1561
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1562
+
1563
+ await rpc_state(
1564
+ 20,
1565
+ api_0.dao_get_proposal_state,
1566
+ [{"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()}],
1567
+ lambda x: x["state"]["closable"],
1568
+ True,
1569
+ )
1570
+
1571
+ open_props = await api_0.dao_get_proposals({"wallet_id": dao_wallet_0_id, "include_closed": False})
1572
+ assert len(open_props["proposals"]) == 1
1573
+
1574
+ close_tx = await api_0.dao_close_proposal({"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()})
1575
+ txs = [TransactionRecord.from_json_dict(close_tx["tx"])]
1576
+ try:
1577
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1578
+ except TimeoutError: # pragma: no cover
1579
+ # try again
1580
+ await api_0.push_tx({"spend_bundle": txs[0].spend_bundle.stream_to_bytes().hex()})
1581
+ await full_node_api.wait_transaction_records_marked_as_in_mempool([txs[0].name], wallet_node_0, 60)
1582
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1583
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1584
+
1585
+ await rpc_state(
1586
+ 20, api_0.dao_get_proposals, [{"wallet_id": dao_wallet_0_id}], lambda x: x["proposals"][1].closed, True
1587
+ )
1588
+
1589
+ # check that the proposal state has changed for everyone
1590
+ await rpc_state(
1591
+ 20,
1592
+ api_0.dao_get_proposal_state,
1593
+ [{"wallet_id": dao_wallet_0_id, "proposal_id": prop.proposal_id.hex()}],
1594
+ lambda x: x["state"]["closed"],
1595
+ True,
1596
+ )
1597
+
1598
+ await rpc_state(
1599
+ 20,
1600
+ api_1.dao_get_proposal_state,
1601
+ [{"wallet_id": dao_wallet_1_id, "proposal_id": prop.proposal_id.hex()}],
1602
+ lambda x: x["state"]["closed"],
1603
+ True,
1604
+ )
1605
+
1606
+ # Check the rules have updated
1607
+ dao_wallet = wallet_node_0.wallet_state_manager.wallets[dao_wallet_0_id]
1608
+ assert dao_wallet.dao_rules.pass_percentage == 10000
1609
+
1610
+ # Test adjust filter level
1611
+ resp = await api_0.dao_adjust_filter_level({"wallet_id": dao_wallet_1_id, "filter_level": 101})
1612
+ assert resp["success"]
1613
+ assert resp["dao_info"].filter_below_vote_amount == 101
1614
+
1615
+ # Test get_treasury_id
1616
+ resp = await api_0.dao_get_treasury_id({"wallet_id": dao_wallet_0_id})
1617
+ assert resp["treasury_id"] == treasury_id
1618
+
1619
+
1620
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
1621
+ @pytest.mark.parametrize(
1622
+ "trusted",
1623
+ [True, False],
1624
+ )
1625
+ @pytest.mark.anyio
1626
+ async def test_dao_rpc_client(
1627
+ two_wallet_nodes_services: SimulatorsAndWalletsServices, trusted: bool, self_hostname: str
1628
+ ) -> None:
1629
+ [full_node_service], wallet_services, bt = two_wallet_nodes_services
1630
+ full_node_api = full_node_service._api
1631
+ full_node_server = full_node_api.full_node.server
1632
+ wallet_node_0 = wallet_services[0]._node
1633
+ server_0 = wallet_node_0.server
1634
+ wallet_node_1 = wallet_services[1]._node
1635
+ server_1 = wallet_node_1.server
1636
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
1637
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
1638
+ ph_0 = await wallet_0.get_new_puzzlehash()
1639
+ ph_1 = await wallet_1.get_new_puzzlehash()
1640
+
1641
+ if trusted:
1642
+ wallet_node_0.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
1643
+ wallet_node_1.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
1644
+ else:
1645
+ wallet_node_0.config["trusted_peers"] = {}
1646
+ wallet_node_1.config["trusted_peers"] = {}
1647
+
1648
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
1649
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
1650
+
1651
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_0))
1652
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
1653
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1654
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1655
+
1656
+ initial_funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
1657
+
1658
+ await time_out_assert(15, wallet_0.get_confirmed_balance, initial_funds)
1659
+ await time_out_assert(15, wallet_0.get_unconfirmed_balance, initial_funds)
1660
+
1661
+ assert wallet_services[0].rpc_server is not None
1662
+ assert wallet_services[1].rpc_server is not None
1663
+
1664
+ client_0 = await WalletRpcClient.create(
1665
+ self_hostname,
1666
+ wallet_services[0].rpc_server.listen_port,
1667
+ wallet_services[0].root_path,
1668
+ wallet_services[0].config,
1669
+ )
1670
+ await validate_get_routes(client_0, wallet_services[0].rpc_server.rpc_api)
1671
+ client_1 = await WalletRpcClient.create(
1672
+ self_hostname,
1673
+ wallet_services[1].rpc_server.listen_port,
1674
+ wallet_services[1].root_path,
1675
+ wallet_services[1].config,
1676
+ )
1677
+ await validate_get_routes(client_1, wallet_services[1].rpc_server.rpc_api)
1678
+
1679
+ try:
1680
+ cat_amt = uint64(150000)
1681
+ amount_of_cats = uint64(cat_amt * 2)
1682
+ dao_rules = DAORules(
1683
+ proposal_timelock=uint64(8),
1684
+ soft_close_length=uint64(4),
1685
+ attendance_required=uint64(1000), # 10%
1686
+ pass_percentage=uint64(4900), # 49%
1687
+ self_destruct_length=uint64(20),
1688
+ oracle_spend_delay=uint64(10),
1689
+ proposal_minimum_amount=uint64(1),
1690
+ )
1691
+ filter_amount = uint64(1)
1692
+ fee = uint64(10000)
1693
+
1694
+ # create new dao
1695
+ dao_wallet_res_0 = await client_0.create_new_dao_wallet(
1696
+ mode="new",
1697
+ tx_config=DEFAULT_TX_CONFIG,
1698
+ dao_rules=dao_rules.to_json_dict(),
1699
+ amount_of_cats=amount_of_cats,
1700
+ filter_amount=filter_amount,
1701
+ name="DAO WALLET 0",
1702
+ )
1703
+ dao_id_0 = dao_wallet_res_0.wallet_id
1704
+ cat_wallet_0 = wallet_node_0.wallet_state_manager.wallets[dao_wallet_res_0.cat_wallet_id]
1705
+
1706
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
1707
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1708
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1709
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1710
+
1711
+ await time_out_assert(20, cat_wallet_0.get_confirmed_balance, amount_of_cats)
1712
+
1713
+ # Create a new standard cat for treasury funds
1714
+ new_cat_amt = uint64(100000)
1715
+ new_cat_res = await client_0.create_new_cat_and_wallet(new_cat_amt, test=True)
1716
+ new_cat_wallet_id = new_cat_res["wallet_id"]
1717
+ new_cat_wallet = wallet_node_0.wallet_state_manager.wallets[new_cat_wallet_id]
1718
+
1719
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
1720
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1721
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1722
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1723
+
1724
+ # join dao
1725
+ dao_wallet_res_1 = await client_1.create_new_dao_wallet(
1726
+ mode="existing",
1727
+ tx_config=DEFAULT_TX_CONFIG,
1728
+ treasury_id=dao_wallet_res_0.treasury_id,
1729
+ filter_amount=filter_amount,
1730
+ name="DAO WALLET 1",
1731
+ )
1732
+ dao_id_1 = dao_wallet_res_1.wallet_id
1733
+ cat_wallet_1 = wallet_node_1.wallet_state_manager.wallets[dao_wallet_res_1.cat_wallet_id]
1734
+
1735
+ # fund treasury
1736
+ xch_funds = uint64(10000000000)
1737
+ await client_0.dao_add_funds_to_treasury(dao_id_0, 1, xch_funds, DEFAULT_TX_CONFIG)
1738
+ await client_0.dao_add_funds_to_treasury(dao_id_0, new_cat_wallet_id, new_cat_amt, DEFAULT_TX_CONFIG)
1739
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
1740
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1741
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1742
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1743
+
1744
+ await rpc_state(20, client_0.dao_get_treasury_balance, [dao_id_0], lambda x: x["balances"]["xch"], xch_funds)
1745
+ assert isinstance(new_cat_wallet, CATWallet)
1746
+ new_cat_asset_id = new_cat_wallet.cat_info.limitations_program_hash
1747
+ await rpc_state(
1748
+ 20,
1749
+ client_0.dao_get_treasury_balance,
1750
+ [dao_id_0],
1751
+ lambda x: x["balances"][new_cat_asset_id.hex()],
1752
+ new_cat_amt,
1753
+ )
1754
+ await rpc_state(
1755
+ 20,
1756
+ client_0.dao_get_treasury_balance,
1757
+ [dao_id_0],
1758
+ lambda x: x["balances"]["xch"],
1759
+ xch_funds,
1760
+ )
1761
+
1762
+ # send cats to wallet 1
1763
+ await client_0.cat_spend(
1764
+ wallet_id=dao_wallet_res_0.cat_wallet_id,
1765
+ tx_config=DEFAULT_TX_CONFIG,
1766
+ amount=cat_amt,
1767
+ inner_address=encode_puzzle_hash(ph_1, "xch"),
1768
+ fee=fee,
1769
+ )
1770
+
1771
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
1772
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1773
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1774
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1775
+
1776
+ await time_out_assert(20, cat_wallet_0.get_confirmed_balance, cat_amt)
1777
+ await time_out_assert(20, cat_wallet_1.get_confirmed_balance, cat_amt)
1778
+
1779
+ # send cats to lockup
1780
+ await client_0.dao_send_to_lockup(dao_id_0, cat_amt, DEFAULT_TX_CONFIG)
1781
+ await client_1.dao_send_to_lockup(dao_id_1, cat_amt, DEFAULT_TX_CONFIG)
1782
+
1783
+ txs_0 = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
1784
+ txs_1 = await wallet_1.wallet_state_manager.tx_store.get_all_unconfirmed()
1785
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs_0 + txs_1, timeout=60)
1786
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1787
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
1788
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1789
+
1790
+ # create a spend proposal
1791
+ additions = [
1792
+ {"puzzle_hash": ph_0.hex(), "amount": 1000},
1793
+ {"puzzle_hash": ph_0.hex(), "amount": 10000, "asset_id": new_cat_asset_id.hex()},
1794
+ ]
1795
+ await client_0.dao_create_proposal(
1796
+ wallet_id=dao_id_0,
1797
+ proposal_type="spend",
1798
+ tx_config=DEFAULT_TX_CONFIG,
1799
+ additions=additions,
1800
+ vote_amount=cat_amt,
1801
+ fee=fee,
1802
+ )
1803
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
1804
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1805
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1806
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1807
+
1808
+ # check proposal is found by wallet 1
1809
+ await rpc_state(20, client_1.dao_get_proposals, [dao_id_1], lambda x: x["proposals"][0]["yes_votes"], cat_amt)
1810
+ props = await client_1.dao_get_proposals(dao_id_1)
1811
+ proposal_id_hex = props["proposals"][0]["proposal_id"]
1812
+
1813
+ # create an update proposal
1814
+ await client_1.dao_create_proposal(
1815
+ wallet_id=dao_id_1,
1816
+ proposal_type="update",
1817
+ tx_config=DEFAULT_TX_CONFIG,
1818
+ vote_amount=cat_amt,
1819
+ new_dao_rules={"proposal_timelock": uint64(10)},
1820
+ fee=fee,
1821
+ )
1822
+ txs = await wallet_1.wallet_state_manager.tx_store.get_all_unconfirmed()
1823
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1824
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
1825
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1826
+
1827
+ # create a mint proposal
1828
+ mint_addr = await client_1.get_next_address(wallet_id=wallet_1.id(), new_address=False)
1829
+ await client_1.dao_create_proposal(
1830
+ wallet_id=dao_id_1,
1831
+ proposal_type="mint",
1832
+ tx_config=DEFAULT_TX_CONFIG,
1833
+ vote_amount=cat_amt,
1834
+ amount=uint64(100),
1835
+ cat_target_address=mint_addr,
1836
+ fee=fee,
1837
+ )
1838
+ txs = await wallet_1.wallet_state_manager.tx_store.get_all_unconfirmed()
1839
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1840
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
1841
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1842
+
1843
+ # vote spend
1844
+ await client_1.dao_vote_on_proposal(
1845
+ wallet_id=dao_id_1,
1846
+ proposal_id=proposal_id_hex,
1847
+ vote_amount=cat_amt,
1848
+ tx_config=DEFAULT_TX_CONFIG,
1849
+ is_yes_vote=True,
1850
+ fee=fee,
1851
+ )
1852
+ txs = await wallet_1.wallet_state_manager.tx_store.get_all_unconfirmed()
1853
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
1854
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
1855
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1856
+
1857
+ # check updated proposal is found by wallet 0
1858
+ await rpc_state(
1859
+ 20, client_0.dao_get_proposals, [dao_id_0], lambda x: x["proposals"][0]["yes_votes"], cat_amt * 2
1860
+ )
1861
+
1862
+ # check proposal state and farm enough blocks to pass
1863
+ state = await client_0.dao_get_proposal_state(wallet_id=dao_id_0, proposal_id=proposal_id_hex)
1864
+ assert state["success"]
1865
+ assert state["state"]["passed"]
1866
+
1867
+ for _ in range(0, state["state"]["blocks_needed"]):
1868
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1869
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1870
+
1871
+ state = await client_0.dao_get_proposal_state(wallet_id=dao_id_0, proposal_id=proposal_id_hex)
1872
+ assert state["success"]
1873
+ assert state["state"]["closable"]
1874
+
1875
+ # check proposal parsing
1876
+ props = await client_0.dao_get_proposals(dao_id_0)
1877
+ proposal_2_hex = props["proposals"][1]["proposal_id"]
1878
+ proposal_3_hex = props["proposals"][2]["proposal_id"]
1879
+ parsed_1 = await client_0.dao_parse_proposal(wallet_id=dao_id_0, proposal_id=proposal_id_hex)
1880
+ assert parsed_1["success"]
1881
+ parsed_2 = await client_0.dao_parse_proposal(wallet_id=dao_id_0, proposal_id=proposal_2_hex)
1882
+ assert parsed_2["success"]
1883
+ parsed_3 = await client_0.dao_parse_proposal(wallet_id=dao_id_0, proposal_id=proposal_3_hex)
1884
+ assert parsed_3["success"]
1885
+
1886
+ # farm blocks so proposal can close
1887
+ for i in range(1, 10):
1888
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
1889
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1890
+
1891
+ # close the proposal
1892
+ close = await client_0.dao_close_proposal(
1893
+ wallet_id=dao_id_0, proposal_id=proposal_id_hex, tx_config=DEFAULT_TX_CONFIG, self_destruct=False, fee=fee
1894
+ )
1895
+ tx = close.tx
1896
+ await full_node_api.wait_transaction_records_entered_mempool(records=[tx], timeout=60)
1897
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1898
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1899
+
1900
+ # check proposal is closed
1901
+ await rpc_state(20, client_0.dao_get_proposals, [dao_id_0], lambda x: x["proposals"][0]["closed"], True)
1902
+ await rpc_state(20, client_1.dao_get_proposals, [dao_id_1], lambda x: x["proposals"][0]["closed"], True)
1903
+ # check treasury balances
1904
+ await rpc_state(
1905
+ 20,
1906
+ client_0.dao_get_treasury_balance,
1907
+ [dao_id_0],
1908
+ lambda x: x["balances"][new_cat_asset_id.hex()],
1909
+ new_cat_amt - 10000,
1910
+ )
1911
+ await rpc_state(
1912
+ 20, client_0.dao_get_treasury_balance, [dao_id_0], lambda x: x["balances"]["xch"], xch_funds - 1000
1913
+ )
1914
+
1915
+ # check wallet balances
1916
+ await rpc_state(
1917
+ 20, client_0.get_wallet_balance, [new_cat_wallet_id], lambda x: x["confirmed_wallet_balance"], 10000
1918
+ )
1919
+ expected_xch = initial_funds - amount_of_cats - new_cat_amt - xch_funds - (2 * fee) - 2 - 9000
1920
+ await rpc_state(
1921
+ 20, client_0.get_wallet_balance, [wallet_0.id()], lambda x: x["confirmed_wallet_balance"], expected_xch
1922
+ )
1923
+
1924
+ # close the mint proposal
1925
+ props = await client_0.dao_get_proposals(dao_id_0)
1926
+ proposal_id_hex = props["proposals"][2]["proposal_id"]
1927
+ close = await client_0.dao_close_proposal(
1928
+ wallet_id=dao_id_0, proposal_id=proposal_id_hex, tx_config=DEFAULT_TX_CONFIG, self_destruct=False, fee=fee
1929
+ )
1930
+ tx = close.tx
1931
+ await full_node_api.wait_transaction_records_entered_mempool(records=[tx], timeout=60)
1932
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1933
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1934
+
1935
+ # check proposal is closed
1936
+ await rpc_state(20, client_0.dao_get_proposals, [dao_id_0], lambda x: x["proposals"][2]["closed"], True)
1937
+ await rpc_state(20, client_1.dao_get_proposals, [dao_id_1], lambda x: x["proposals"][2]["closed"], True)
1938
+
1939
+ # check minted cats are received
1940
+ await rpc_state(
1941
+ 20,
1942
+ client_1.get_wallet_balance,
1943
+ [dao_wallet_res_1.cat_wallet_id],
1944
+ lambda x: x["confirmed_wallet_balance"],
1945
+ 100,
1946
+ )
1947
+
1948
+ open_props = await client_0.dao_get_proposals(dao_id_0, False)
1949
+ assert len(open_props["proposals"]) == 1
1950
+
1951
+ # close the update proposal
1952
+ proposal_id_hex = props["proposals"][1]["proposal_id"]
1953
+ close = await client_0.dao_close_proposal(
1954
+ wallet_id=dao_id_0, proposal_id=proposal_id_hex, tx_config=DEFAULT_TX_CONFIG, self_destruct=False, fee=fee
1955
+ )
1956
+ tx = close.tx
1957
+ await full_node_api.wait_transaction_records_entered_mempool(records=[tx], timeout=60)
1958
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1959
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1960
+
1961
+ # check proposal is closed
1962
+ await rpc_state(20, client_0.dao_get_proposals, [dao_id_0], lambda x: x["proposals"][1]["closed"], True)
1963
+ await rpc_state(20, client_1.dao_get_proposals, [dao_id_1], lambda x: x["proposals"][1]["closed"], True)
1964
+
1965
+ # check dao rules are updated
1966
+ new_rules = await client_0.dao_get_rules(dao_id_0)
1967
+ assert new_rules["rules"]["proposal_timelock"] == 10
1968
+ new_rules_1 = await client_0.dao_get_rules(dao_id_1)
1969
+ assert new_rules_1["rules"]["proposal_timelock"] == 10
1970
+
1971
+ # free locked cats from finished proposal
1972
+ free_coins_res = await client_0.dao_free_coins_from_finished_proposals(
1973
+ wallet_id=dao_id_0, tx_config=DEFAULT_TX_CONFIG
1974
+ )
1975
+ free_coins_tx = free_coins_res.tx
1976
+ await full_node_api.wait_transaction_records_entered_mempool(records=[free_coins_tx], timeout=60)
1977
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1978
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1979
+
1980
+ bal = await client_0.get_wallet_balance(dao_wallet_res_0.dao_cat_wallet_id)
1981
+ assert bal["confirmed_wallet_balance"] == cat_amt
1982
+
1983
+ exit = await client_0.dao_exit_lockup(dao_id_0, tx_config=DEFAULT_TX_CONFIG)
1984
+ exit_tx = exit.tx
1985
+ await full_node_api.wait_transaction_records_entered_mempool(records=[exit_tx], timeout=60)
1986
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
1987
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
1988
+
1989
+ await rpc_state(
1990
+ 20,
1991
+ client_0.get_wallet_balance,
1992
+ [dao_wallet_res_0.cat_wallet_id],
1993
+ lambda x: x["confirmed_wallet_balance"],
1994
+ cat_amt,
1995
+ )
1996
+
1997
+ # coverage tests for filter amount and get treasury id
1998
+ treasury_id_resp = await client_0.dao_get_treasury_id(wallet_id=dao_id_0)
1999
+ assert treasury_id_resp["treasury_id"] == "0x" + dao_wallet_res_0.treasury_id.hex()
2000
+ filter_amount_resp = await client_0.dao_adjust_filter_level(wallet_id=dao_id_0, filter_level=30)
2001
+ assert filter_amount_resp["dao_info"]["filter_below_vote_amount"] == 30
2002
+
2003
+ finally:
2004
+ client_0.close()
2005
+ client_1.close()
2006
+ await client_0.await_closed()
2007
+ await client_1.await_closed()
2008
+
2009
+
2010
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
2011
+ @pytest.mark.parametrize(
2012
+ "trusted",
2013
+ [True, False],
2014
+ )
2015
+ @pytest.mark.anyio
2016
+ async def test_dao_complex_spends(
2017
+ two_wallet_nodes_services: SimulatorsAndWalletsServices, trusted: bool, self_hostname: str
2018
+ ) -> None:
2019
+ [full_node_service], wallet_services, bt = two_wallet_nodes_services
2020
+ full_node_api = full_node_service._api
2021
+ full_node_server = full_node_api.full_node.server
2022
+ wallet_node_0 = wallet_services[0]._node
2023
+ server_0 = wallet_node_0.server
2024
+ wallet_node_1 = wallet_services[1]._node
2025
+ server_1 = wallet_node_1.server
2026
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
2027
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
2028
+ ph_0 = await wallet_0.get_new_puzzlehash()
2029
+ ph_1 = await wallet_1.get_new_puzzlehash()
2030
+
2031
+ if trusted:
2032
+ wallet_node_0.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
2033
+ wallet_node_1.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
2034
+ else:
2035
+ wallet_node_0.config["trusted_peers"] = {}
2036
+ wallet_node_1.config["trusted_peers"] = {}
2037
+
2038
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2039
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2040
+
2041
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_0))
2042
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
2043
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
2044
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2045
+
2046
+ initial_funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
2047
+
2048
+ await time_out_assert(15, wallet_0.get_confirmed_balance, initial_funds)
2049
+ await time_out_assert(15, wallet_0.get_unconfirmed_balance, initial_funds)
2050
+
2051
+ assert wallet_services[0].rpc_server is not None
2052
+ assert wallet_services[1].rpc_server is not None
2053
+
2054
+ client_0 = await WalletRpcClient.create(
2055
+ self_hostname,
2056
+ wallet_services[0].rpc_server.listen_port,
2057
+ wallet_services[0].root_path,
2058
+ wallet_services[0].config,
2059
+ )
2060
+ await validate_get_routes(client_0, wallet_services[0].rpc_server.rpc_api)
2061
+ client_1 = await WalletRpcClient.create(
2062
+ self_hostname,
2063
+ wallet_services[1].rpc_server.listen_port,
2064
+ wallet_services[1].root_path,
2065
+ wallet_services[1].config,
2066
+ )
2067
+ await validate_get_routes(client_1, wallet_services[1].rpc_server.rpc_api)
2068
+
2069
+ try:
2070
+ cat_amt = uint64(300000)
2071
+ dao_rules = DAORules(
2072
+ proposal_timelock=uint64(2),
2073
+ soft_close_length=uint64(2),
2074
+ attendance_required=uint64(1000), # 10%
2075
+ pass_percentage=uint64(5100), # 51%
2076
+ self_destruct_length=uint64(5),
2077
+ oracle_spend_delay=uint64(2),
2078
+ proposal_minimum_amount=uint64(1),
2079
+ )
2080
+ filter_amount = uint64(1)
2081
+
2082
+ # create new dao
2083
+ dao_wallet_res_0 = await client_0.create_new_dao_wallet(
2084
+ mode="new",
2085
+ tx_config=DEFAULT_TX_CONFIG,
2086
+ dao_rules=dao_rules.to_json_dict(),
2087
+ amount_of_cats=cat_amt,
2088
+ filter_amount=filter_amount,
2089
+ name="DAO WALLET 0",
2090
+ )
2091
+ dao_id_0 = dao_wallet_res_0.wallet_id
2092
+ treasury_id = dao_wallet_res_0.treasury_id
2093
+ cat_wallet_0 = wallet_node_0.wallet_state_manager.wallets[dao_wallet_res_0.cat_wallet_id]
2094
+
2095
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2096
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2097
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2098
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2099
+
2100
+ await time_out_assert(20, cat_wallet_0.get_confirmed_balance, cat_amt)
2101
+
2102
+ # Create a new standard cat for treasury funds
2103
+ new_cat_amt = uint64(1000000)
2104
+ new_cat_wallet_dict = await client_0.create_new_cat_and_wallet(new_cat_amt, test=True)
2105
+ new_cat_wallet_id = new_cat_wallet_dict["wallet_id"]
2106
+ new_cat_wallet = wallet_node_0.wallet_state_manager.wallets[new_cat_wallet_id]
2107
+
2108
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2109
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2110
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2111
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2112
+
2113
+ # Create a new standard cat for treasury funds
2114
+ new_cat_wallet_dict_2 = await client_0.create_new_cat_and_wallet(new_cat_amt, test=True)
2115
+ new_cat_wallet_id_2 = new_cat_wallet_dict_2["wallet_id"]
2116
+ new_cat_wallet_2 = wallet_node_0.wallet_state_manager.wallets[new_cat_wallet_id_2]
2117
+
2118
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2119
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2120
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2121
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2122
+
2123
+ # join dao
2124
+ dao_wallet_res_1 = await client_1.create_new_dao_wallet(
2125
+ mode="existing",
2126
+ tx_config=DEFAULT_TX_CONFIG,
2127
+ treasury_id=treasury_id,
2128
+ filter_amount=filter_amount,
2129
+ name="DAO WALLET 1",
2130
+ )
2131
+ dao_id_1 = dao_wallet_res_1.wallet_id
2132
+
2133
+ # fund treasury so there are multiple coins for each asset
2134
+ xch_funds = uint64(10000000000)
2135
+ for _ in range(4):
2136
+ await client_0.dao_add_funds_to_treasury(dao_id_0, 1, uint64(xch_funds / 4), DEFAULT_TX_CONFIG)
2137
+ await client_0.dao_add_funds_to_treasury(
2138
+ dao_id_0, new_cat_wallet_id, uint64(new_cat_amt / 4), DEFAULT_TX_CONFIG
2139
+ )
2140
+ await client_0.dao_add_funds_to_treasury(
2141
+ dao_id_0, new_cat_wallet_id_2, uint64(new_cat_amt / 4), DEFAULT_TX_CONFIG
2142
+ )
2143
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2144
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2145
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2146
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2147
+
2148
+ await rpc_state(20, client_0.dao_get_treasury_balance, [dao_id_0], lambda x: x["balances"]["xch"], xch_funds)
2149
+ assert isinstance(new_cat_wallet, CATWallet)
2150
+ new_cat_asset_id = new_cat_wallet.cat_info.limitations_program_hash
2151
+ assert isinstance(new_cat_wallet_2, CATWallet)
2152
+ new_cat_asset_id_2 = new_cat_wallet_2.cat_info.limitations_program_hash
2153
+ await rpc_state(
2154
+ 20,
2155
+ client_0.dao_get_treasury_balance,
2156
+ [dao_id_0],
2157
+ lambda x: x["balances"][new_cat_asset_id.hex()],
2158
+ new_cat_amt,
2159
+ )
2160
+ await rpc_state(
2161
+ 20,
2162
+ client_0.dao_get_treasury_balance,
2163
+ [dao_id_0],
2164
+ lambda x: x["balances"][new_cat_asset_id_2.hex()],
2165
+ new_cat_amt,
2166
+ )
2167
+
2168
+ # add the new cat wallets to wallet_1
2169
+ await client_1.create_wallet_for_existing_cat(new_cat_asset_id)
2170
+ await client_1.create_wallet_for_existing_cat(new_cat_asset_id_2)
2171
+
2172
+ # send cats to lockup
2173
+ await client_0.dao_send_to_lockup(dao_id_0, cat_amt, DEFAULT_TX_CONFIG)
2174
+
2175
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2176
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2177
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2178
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2179
+
2180
+ # Test spend proposal types
2181
+
2182
+ # Test proposal with multiple conditions and xch coins
2183
+ additions = [
2184
+ {"puzzle_hash": ph_0.hex(), "amount": xch_funds / 4},
2185
+ {"puzzle_hash": ph_1.hex(), "amount": xch_funds / 4},
2186
+ ]
2187
+ await client_0.dao_create_proposal(
2188
+ wallet_id=dao_id_0,
2189
+ proposal_type="spend",
2190
+ tx_config=DEFAULT_TX_CONFIG,
2191
+ additions=additions,
2192
+ vote_amount=cat_amt,
2193
+ )
2194
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2195
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2196
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2197
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2198
+
2199
+ props = await client_1.dao_get_proposals(dao_id_1)
2200
+ proposal_id_hex = props["proposals"][-1]["proposal_id"]
2201
+
2202
+ await client_0.dao_close_proposal(
2203
+ wallet_id=dao_id_0, proposal_id=proposal_id_hex, tx_config=DEFAULT_TX_CONFIG, self_destruct=False
2204
+ )
2205
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2206
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2207
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2208
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2209
+
2210
+ # check proposal is closed
2211
+ await rpc_state(20, client_0.dao_get_proposals, [dao_id_0], lambda x: x["proposals"][-1]["closed"], True)
2212
+ await rpc_state(20, client_1.dao_get_proposals, [dao_id_1], lambda x: x["proposals"][-1]["closed"], True)
2213
+ # check the xch is received and removed from treasury
2214
+ await rpc_state(
2215
+ 20,
2216
+ client_1.get_wallet_balance,
2217
+ [wallet_1.id()],
2218
+ lambda x: x["confirmed_wallet_balance"],
2219
+ initial_funds + (xch_funds / 4),
2220
+ )
2221
+ await rpc_state(
2222
+ 20,
2223
+ client_0.dao_get_treasury_balance,
2224
+ [dao_id_0],
2225
+ lambda x: x["balances"]["xch"],
2226
+ xch_funds / 2,
2227
+ )
2228
+
2229
+ # Test proposal with multiple cats and multiple coins
2230
+ cat_spend_amt = 510000
2231
+ additions = [
2232
+ {"puzzle_hash": ph_0.hex(), "amount": cat_spend_amt, "asset_id": new_cat_asset_id.hex()},
2233
+ {"puzzle_hash": ph_0.hex(), "amount": cat_spend_amt, "asset_id": new_cat_asset_id_2.hex()},
2234
+ ]
2235
+ await client_0.dao_create_proposal(
2236
+ wallet_id=dao_id_0,
2237
+ proposal_type="spend",
2238
+ tx_config=DEFAULT_TX_CONFIG,
2239
+ additions=additions,
2240
+ vote_amount=cat_amt,
2241
+ )
2242
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2243
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2244
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2245
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2246
+
2247
+ props = await client_1.dao_get_proposals(dao_id_1)
2248
+ proposal_id_hex = props["proposals"][-1]["proposal_id"]
2249
+
2250
+ await client_0.dao_close_proposal(
2251
+ wallet_id=dao_id_0, proposal_id=proposal_id_hex, tx_config=DEFAULT_TX_CONFIG, self_destruct=False
2252
+ )
2253
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2254
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2255
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2256
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2257
+
2258
+ # check proposal is closed
2259
+ await rpc_state(20, client_0.dao_get_proposals, [dao_id_0], lambda x: x["proposals"][-1]["closed"], True)
2260
+ await rpc_state(20, client_1.dao_get_proposals, [dao_id_1], lambda x: x["proposals"][-1]["closed"], True)
2261
+
2262
+ # check cat balances
2263
+ await rpc_state(
2264
+ 20,
2265
+ client_0.dao_get_treasury_balance,
2266
+ [dao_id_0],
2267
+ lambda x: x["balances"][new_cat_asset_id.hex()],
2268
+ new_cat_amt - cat_spend_amt,
2269
+ )
2270
+ await rpc_state(
2271
+ 20,
2272
+ client_0.dao_get_treasury_balance,
2273
+ [dao_id_0],
2274
+ lambda x: x["balances"][new_cat_asset_id_2.hex()],
2275
+ new_cat_amt - cat_spend_amt,
2276
+ )
2277
+
2278
+ await rpc_state(
2279
+ 20, client_0.get_wallet_balance, [new_cat_wallet_id], lambda x: x["confirmed_wallet_balance"], cat_spend_amt
2280
+ )
2281
+ await rpc_state(
2282
+ 20,
2283
+ client_0.get_wallet_balance,
2284
+ [new_cat_wallet_id_2],
2285
+ lambda x: x["confirmed_wallet_balance"],
2286
+ cat_spend_amt,
2287
+ )
2288
+
2289
+ # Spend remaining balances with multiple outputs
2290
+
2291
+ additions = [
2292
+ {"puzzle_hash": ph_0.hex(), "amount": 400000, "asset_id": new_cat_asset_id.hex()},
2293
+ {"puzzle_hash": ph_1.hex(), "amount": 90000, "asset_id": new_cat_asset_id.hex()},
2294
+ {"puzzle_hash": ph_0.hex(), "amount": 400000, "asset_id": new_cat_asset_id_2.hex()},
2295
+ {"puzzle_hash": ph_1.hex(), "amount": 90000, "asset_id": new_cat_asset_id_2.hex()},
2296
+ {"puzzle_hash": ph_0.hex(), "amount": xch_funds / 4},
2297
+ {"puzzle_hash": ph_1.hex(), "amount": xch_funds / 4},
2298
+ ]
2299
+ await client_0.dao_create_proposal(
2300
+ wallet_id=dao_id_0,
2301
+ proposal_type="spend",
2302
+ tx_config=DEFAULT_TX_CONFIG,
2303
+ additions=additions,
2304
+ vote_amount=cat_amt,
2305
+ )
2306
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2307
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2308
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2309
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2310
+
2311
+ props = await client_0.dao_get_proposals(dao_id_0)
2312
+ proposal_id_hex = props["proposals"][-1]["proposal_id"]
2313
+
2314
+ await client_0.dao_close_proposal(
2315
+ wallet_id=dao_id_0,
2316
+ proposal_id=proposal_id_hex,
2317
+ tx_config=DEFAULT_TX_CONFIG,
2318
+ self_destruct=False,
2319
+ )
2320
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2321
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2322
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2323
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2324
+
2325
+ # check proposal is closed
2326
+ await rpc_state(20, client_0.dao_get_proposals, [dao_id_0], lambda x: x["proposals"][-1]["closed"], True)
2327
+ await rpc_state(20, client_1.dao_get_proposals, [dao_id_1], lambda x: x["proposals"][-1]["closed"], True)
2328
+
2329
+ # check cat balances
2330
+ await rpc_state(
2331
+ 20,
2332
+ client_0.get_wallet_balance,
2333
+ [new_cat_wallet_id],
2334
+ lambda x: x["confirmed_wallet_balance"],
2335
+ cat_spend_amt + 400000,
2336
+ )
2337
+ await rpc_state(
2338
+ 20,
2339
+ client_0.get_wallet_balance,
2340
+ [new_cat_wallet_id_2],
2341
+ lambda x: x["confirmed_wallet_balance"],
2342
+ cat_spend_amt + 400000,
2343
+ )
2344
+ await rpc_state(
2345
+ 20, client_1.get_wallet_balance, [new_cat_wallet_id], lambda x: x["confirmed_wallet_balance"], 90000
2346
+ )
2347
+ await rpc_state(
2348
+ 20, client_1.get_wallet_balance, [new_cat_wallet_id_2], lambda x: x["confirmed_wallet_balance"], 90000
2349
+ )
2350
+
2351
+ # check xch
2352
+ await rpc_state(
2353
+ 20,
2354
+ client_1.get_wallet_balance,
2355
+ [wallet_1.id()],
2356
+ lambda x: x["confirmed_wallet_balance"],
2357
+ initial_funds + (xch_funds / 2),
2358
+ )
2359
+
2360
+ # check treasury balances are 0
2361
+ await rpc_state(
2362
+ 20,
2363
+ client_1.dao_get_treasury_balance,
2364
+ [dao_id_0],
2365
+ lambda x: x["balances"]["xch"] + 1, # add 1 so result isn't 0
2366
+ 1,
2367
+ )
2368
+ await rpc_state(
2369
+ 20,
2370
+ client_1.dao_get_treasury_balance,
2371
+ [dao_id_0],
2372
+ lambda x: x["balances"][new_cat_asset_id.hex()] + 1, # add 1 so result isn't 0
2373
+ 1,
2374
+ )
2375
+ await rpc_state(
2376
+ 20,
2377
+ client_0.dao_get_treasury_balance,
2378
+ [dao_id_0],
2379
+ lambda x: x["balances"][new_cat_asset_id_2.hex()] + 1, # add 1 so result isn't 0
2380
+ 1,
2381
+ )
2382
+
2383
+ finally:
2384
+ client_0.close()
2385
+ client_1.close()
2386
+ await client_0.await_closed()
2387
+ await client_1.await_closed()
2388
+
2389
+
2390
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
2391
+ @pytest.mark.parametrize(
2392
+ "trusted",
2393
+ [True, False],
2394
+ )
2395
+ @pytest.mark.anyio
2396
+ async def test_dao_concurrency(self_hostname: str, three_wallet_nodes: OldSimulatorsAndWallets, trusted: bool) -> None:
2397
+ full_nodes, wallets, _ = three_wallet_nodes
2398
+ full_node_api = full_nodes[0]
2399
+ full_node_server = full_node_api.server
2400
+ wallet_node_0, server_0 = wallets[0]
2401
+ wallet_node_1, server_1 = wallets[1]
2402
+ wallet_node_2, server_2 = wallets[2]
2403
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
2404
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
2405
+ wallet_2 = wallet_node_2.wallet_state_manager.main_wallet
2406
+ ph = await wallet_0.get_new_puzzlehash()
2407
+ ph_1 = await wallet_1.get_new_puzzlehash()
2408
+ ph_2 = await wallet_2.get_new_puzzlehash()
2409
+
2410
+ if trusted:
2411
+ wallet_node_0.config["trusted_peers"] = {
2412
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
2413
+ }
2414
+ wallet_node_1.config["trusted_peers"] = {
2415
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
2416
+ }
2417
+ wallet_node_2.config["trusted_peers"] = {
2418
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
2419
+ }
2420
+ else:
2421
+ wallet_node_0.config["trusted_peers"] = {}
2422
+ wallet_node_1.config["trusted_peers"] = {}
2423
+ wallet_node_2.config["trusted_peers"] = {}
2424
+
2425
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2426
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2427
+ await server_2.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2428
+
2429
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
2430
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
2431
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_2))
2432
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
2433
+
2434
+ funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
2435
+
2436
+ await time_out_assert(20, wallet_0.get_confirmed_balance, funds)
2437
+ await time_out_assert(20, full_node_api.wallet_is_synced, True, wallet_node_0)
2438
+
2439
+ cat_amt = 300000
2440
+ dao_rules = DAORules(
2441
+ proposal_timelock=uint64(10),
2442
+ soft_close_length=uint64(5),
2443
+ attendance_required=uint64(1000), # 10%
2444
+ pass_percentage=uint64(5100), # 51%
2445
+ self_destruct_length=uint64(20),
2446
+ oracle_spend_delay=uint64(10),
2447
+ proposal_minimum_amount=uint64(101),
2448
+ )
2449
+
2450
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2451
+ dao_wallet_0 = await DAOWallet.create_new_dao_and_wallet(
2452
+ wallet_node_0.wallet_state_manager, wallet_0, uint64(cat_amt), dao_rules, action_scope
2453
+ )
2454
+
2455
+ # Get the full node sim to process the wallet creation spend
2456
+ await full_node_api.wait_transaction_records_entered_mempool(
2457
+ records=action_scope.side_effects.transactions, timeout=60
2458
+ )
2459
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2460
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2461
+
2462
+ # get the cat wallets
2463
+ cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.cat_wallet_id]
2464
+ await time_out_assert(10, cat_wallet_0.get_confirmed_balance, cat_amt)
2465
+
2466
+ # get the dao_cat wallet
2467
+ dao_cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.dao_cat_wallet_id]
2468
+
2469
+ treasury_id = dao_wallet_0.dao_info.treasury_id
2470
+
2471
+ # Create the other user's wallet from the treasury id
2472
+ dao_wallet_1 = await DAOWallet.create_new_dao_wallet_for_existing_dao(
2473
+ wallet_node_1.wallet_state_manager, wallet_1, treasury_id
2474
+ )
2475
+ assert dao_wallet_1.dao_info.treasury_id == treasury_id
2476
+
2477
+ # Create funding spends for xch
2478
+ xch_funds = uint64(500000)
2479
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2480
+ await dao_wallet_0.create_add_funds_to_treasury_spend(xch_funds, action_scope)
2481
+ await full_node_api.wait_transaction_records_entered_mempool(
2482
+ records=action_scope.side_effects.transactions, timeout=60
2483
+ )
2484
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2485
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2486
+
2487
+ # Check that the funding spend is recognized by both dao wallets
2488
+ await time_out_assert(10, dao_wallet_0.get_balance_by_asset_type, xch_funds)
2489
+
2490
+ # Send some dao_cats to wallet_1
2491
+ # Get the cat wallets for wallet_1
2492
+ cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.cat_wallet_id]
2493
+ dao_cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.dao_cat_wallet_id]
2494
+ assert cat_wallet_1
2495
+ assert dao_cat_wallet_1
2496
+
2497
+ # Add a third wallet and check they can find proposal with accurate vote counts
2498
+ dao_wallet_2 = await DAOWallet.create_new_dao_wallet_for_existing_dao(
2499
+ wallet_node_2.wallet_state_manager, wallet_2, treasury_id
2500
+ )
2501
+ assert dao_wallet_2.dao_info.treasury_id == treasury_id
2502
+
2503
+ dao_cat_wallet_2 = dao_wallet_2.wallet_state_manager.wallets[dao_wallet_2.dao_info.dao_cat_wallet_id]
2504
+ assert dao_cat_wallet_2
2505
+
2506
+ async with cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2507
+ await cat_wallet_0.generate_signed_transaction([100000, 100000], [ph_1, ph_2], action_scope)
2508
+ await full_node_api.wait_transaction_records_entered_mempool(
2509
+ records=action_scope.side_effects.transactions, timeout=60
2510
+ )
2511
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2512
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2513
+
2514
+ cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.cat_wallet_id]
2515
+ await time_out_assert(10, cat_wallet_1.get_confirmed_balance, 100000)
2516
+ cat_wallet_2 = dao_wallet_2.wallet_state_manager.wallets[dao_wallet_2.dao_info.cat_wallet_id]
2517
+ await time_out_assert(10, cat_wallet_2.get_confirmed_balance, 100000)
2518
+ await time_out_assert(10, cat_wallet_0.get_confirmed_balance, 100000)
2519
+
2520
+ # Create dao cats for voting
2521
+ dao_cat_0_bal = await dao_cat_wallet_0.get_votable_balance()
2522
+ assert dao_cat_0_bal == 100000
2523
+ async with dao_cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2524
+ await dao_cat_wallet_0.enter_dao_cat_voting_mode(dao_cat_0_bal, action_scope)
2525
+ await full_node_api.wait_transaction_records_entered_mempool(
2526
+ records=action_scope.side_effects.transactions, timeout=60
2527
+ )
2528
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2529
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2530
+
2531
+ # Create a proposal for xch spend
2532
+ recipient_puzzle_hash = await wallet_2.get_new_puzzlehash()
2533
+ proposal_amount = uint64(10000)
2534
+ xch_proposal_inner = generate_simple_proposal_innerpuz(
2535
+ treasury_id,
2536
+ [recipient_puzzle_hash],
2537
+ [proposal_amount],
2538
+ [None],
2539
+ )
2540
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2541
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, dao_cat_0_bal, uint64(1000))
2542
+ await full_node_api.wait_transaction_records_entered_mempool(
2543
+ records=action_scope.side_effects.transactions, timeout=60
2544
+ )
2545
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2546
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2547
+
2548
+ # Check the proposal is saved
2549
+ assert len(dao_wallet_0.dao_info.proposals_list) == 1
2550
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == dao_cat_0_bal
2551
+ assert dao_wallet_0.dao_info.proposals_list[0].timer_coin is not None
2552
+
2553
+ # Check that wallet_1 also finds and saved the proposal
2554
+ assert len(dao_wallet_1.dao_info.proposals_list) == 1
2555
+ prop = dao_wallet_1.dao_info.proposals_list[0]
2556
+
2557
+ total_votes = dao_cat_0_bal
2558
+
2559
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == total_votes
2560
+ assert dao_wallet_0.dao_info.proposals_list[0].yes_votes == total_votes
2561
+ assert dao_wallet_1.dao_info.proposals_list[0].amount_voted == total_votes
2562
+ assert dao_wallet_1.dao_info.proposals_list[0].yes_votes == total_votes
2563
+
2564
+ # Create votable dao cats and add a new vote
2565
+ dao_cat_1_bal = await dao_cat_wallet_1.get_votable_balance()
2566
+ async with dao_cat_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2567
+ await dao_cat_wallet_1.enter_dao_cat_voting_mode(dao_cat_1_bal, action_scope)
2568
+ await full_node_api.wait_transaction_records_entered_mempool(
2569
+ records=action_scope.side_effects.transactions, timeout=60
2570
+ )
2571
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
2572
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
2573
+
2574
+ async with dao_cat_wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2575
+ await dao_cat_wallet_2.enter_dao_cat_voting_mode(dao_cat_1_bal, action_scope)
2576
+ await full_node_api.wait_transaction_records_entered_mempool(
2577
+ records=action_scope.side_effects.transactions, timeout=60
2578
+ )
2579
+ await full_node_api.process_all_wallet_transactions(wallet_2, timeout=60)
2580
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
2581
+
2582
+ async with dao_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2583
+ await dao_wallet_1.generate_proposal_vote_spend(prop.proposal_id, dao_cat_1_bal, True, action_scope)
2584
+ [vote_tx] = action_scope.side_effects.transactions
2585
+ vote_sb = vote_tx.spend_bundle
2586
+ assert vote_sb is not None
2587
+ async with dao_wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2588
+ await dao_wallet_2.generate_proposal_vote_spend(prop.proposal_id, dao_cat_1_bal, True, action_scope)
2589
+ [vote_tx_2] = action_scope.side_effects.transactions
2590
+ vote_2 = vote_tx_2.spend_bundle
2591
+ assert vote_2 is not None
2592
+ await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, vote_sb.name())
2593
+ await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, vote_2.name())
2594
+
2595
+ await time_out_assert(20, len, 1, dao_wallet_2.dao_info.proposals_list)
2596
+ await time_out_assert(20, int, total_votes, dao_wallet_1.dao_info.proposals_list[0].amount_voted)
2597
+ await time_out_assert(20, int, total_votes, dao_wallet_2.dao_info.proposals_list[0].amount_voted)
2598
+
2599
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
2600
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1, wallet_node_2], timeout=30)
2601
+
2602
+ await time_out_assert(20, int, total_votes * 2, dao_wallet_1.dao_info.proposals_list[0].amount_voted)
2603
+ await time_out_assert(20, int, total_votes * 2, dao_wallet_2.dao_info.proposals_list[0].amount_voted)
2604
+ dao_cat_1_bal = await dao_cat_wallet_1.get_votable_balance(prop.proposal_id)
2605
+ dao_cat_2_bal = await dao_cat_wallet_2.get_votable_balance(prop.proposal_id)
2606
+
2607
+ assert (dao_cat_1_bal == 100000 and dao_cat_2_bal == 0) or (dao_cat_1_bal == 0 and dao_cat_2_bal == 100000)
2608
+
2609
+
2610
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
2611
+ @pytest.mark.parametrize(
2612
+ "trusted",
2613
+ [True, False],
2614
+ )
2615
+ @pytest.mark.anyio
2616
+ @pytest.mark.standard_block_tools
2617
+ async def test_dao_cat_exits(
2618
+ two_wallet_nodes_services: SimulatorsAndWalletsServices, trusted: bool, self_hostname: str
2619
+ ) -> None:
2620
+ [full_node_service], wallet_services, bt = two_wallet_nodes_services
2621
+ full_node_api = full_node_service._api
2622
+ full_node_server = full_node_api.full_node.server
2623
+ wallet_node_0 = wallet_services[0]._node
2624
+ server_0 = wallet_node_0.server
2625
+ wallet_node_1 = wallet_services[1]._node
2626
+ server_1 = wallet_node_1.server
2627
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
2628
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
2629
+ ph_0 = await wallet_0.get_new_puzzlehash()
2630
+ ph_1 = await wallet_1.get_new_puzzlehash()
2631
+
2632
+ if trusted:
2633
+ wallet_node_0.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
2634
+ wallet_node_1.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
2635
+ else:
2636
+ wallet_node_0.config["trusted_peers"] = {}
2637
+ wallet_node_1.config["trusted_peers"] = {}
2638
+
2639
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2640
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2641
+
2642
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_0))
2643
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
2644
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
2645
+
2646
+ initial_funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
2647
+
2648
+ await time_out_assert(15, wallet_0.get_confirmed_balance, initial_funds)
2649
+ await time_out_assert(15, wallet_0.get_unconfirmed_balance, initial_funds)
2650
+
2651
+ assert wallet_services[0].rpc_server is not None
2652
+ assert wallet_services[1].rpc_server is not None
2653
+
2654
+ client_0 = await WalletRpcClient.create(
2655
+ self_hostname,
2656
+ wallet_services[0].rpc_server.listen_port,
2657
+ wallet_services[0].root_path,
2658
+ wallet_services[0].config,
2659
+ )
2660
+ await validate_get_routes(client_0, wallet_services[0].rpc_server.rpc_api)
2661
+ client_1 = await WalletRpcClient.create(
2662
+ self_hostname,
2663
+ wallet_services[1].rpc_server.listen_port,
2664
+ wallet_services[1].root_path,
2665
+ wallet_services[1].config,
2666
+ )
2667
+ await validate_get_routes(client_1, wallet_services[1].rpc_server.rpc_api)
2668
+
2669
+ try:
2670
+ cat_amt = uint64(150000)
2671
+ dao_rules = DAORules(
2672
+ proposal_timelock=uint64(8),
2673
+ soft_close_length=uint64(4),
2674
+ attendance_required=uint64(1000), # 10%
2675
+ pass_percentage=uint64(5100), # 51%
2676
+ self_destruct_length=uint64(20),
2677
+ oracle_spend_delay=uint64(10),
2678
+ proposal_minimum_amount=uint64(1),
2679
+ )
2680
+ filter_amount = uint64(1)
2681
+ fee = uint64(10000)
2682
+
2683
+ # create new dao
2684
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2685
+ dao_wallet_res_0 = await client_0.create_new_dao_wallet(
2686
+ mode="new",
2687
+ tx_config=DEFAULT_TX_CONFIG,
2688
+ dao_rules=dao_rules.to_json_dict(),
2689
+ amount_of_cats=cat_amt,
2690
+ filter_amount=filter_amount,
2691
+ name="DAO WALLET 0",
2692
+ )
2693
+ dao_id_0 = dao_wallet_res_0.wallet_id
2694
+ cat_wallet_0 = wallet_node_0.wallet_state_manager.wallets[dao_wallet_res_0.cat_wallet_id]
2695
+ dao_cat_wallet_0 = wallet_node_0.wallet_state_manager.wallets[dao_wallet_res_0.dao_cat_wallet_id]
2696
+ txs = await wallet_0.wallet_state_manager.tx_store.get_all_unconfirmed()
2697
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2698
+ await full_node_api.process_transaction_records(records=txs, timeout=60)
2699
+ await full_node_api.process_all_wallet_transactions(wallet_0, 60)
2700
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2701
+ await full_node_api.check_transactions_confirmed(wallet_node_0.wallet_state_manager, txs, 60)
2702
+ await time_out_assert(60, cat_wallet_0.get_confirmed_balance, cat_amt)
2703
+
2704
+ # fund treasury
2705
+ xch_funds = uint64(10000000000)
2706
+ funding_tx = await client_0.dao_add_funds_to_treasury(dao_id_0, 1, xch_funds, DEFAULT_TX_CONFIG)
2707
+ tx = funding_tx.tx
2708
+ await full_node_api.wait_transaction_records_entered_mempool(records=[tx], timeout=60)
2709
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2710
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2711
+
2712
+ await rpc_state(20, client_0.dao_get_treasury_balance, [dao_id_0], lambda x: x["balances"]["xch"], xch_funds)
2713
+
2714
+ # send cats to lockup
2715
+ lockup_0 = await client_0.dao_send_to_lockup(dao_id_0, cat_amt, DEFAULT_TX_CONFIG)
2716
+ txs = lockup_0.txs
2717
+ await full_node_api.wait_transaction_records_entered_mempool(records=txs, timeout=60)
2718
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2719
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2720
+
2721
+ assert isinstance(dao_cat_wallet_0, DAOCATWallet)
2722
+ await time_out_assert(60, dao_cat_wallet_0.get_confirmed_balance, cat_amt)
2723
+
2724
+ # create a spend proposal
2725
+ additions = [
2726
+ {"puzzle_hash": ph_1.hex(), "amount": 1000},
2727
+ ]
2728
+ proposal = await client_0.dao_create_proposal(
2729
+ wallet_id=dao_id_0,
2730
+ proposal_type="spend",
2731
+ tx_config=DEFAULT_TX_CONFIG,
2732
+ additions=additions,
2733
+ vote_amount=cat_amt,
2734
+ fee=fee,
2735
+ )
2736
+ tx = proposal.tx
2737
+ await full_node_api.wait_transaction_records_entered_mempool(records=[tx], timeout=60)
2738
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2739
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2740
+
2741
+ await time_out_assert_not_none(20, client_0.dao_get_proposals, dao_id_0)
2742
+ props = await client_0.dao_get_proposals(dao_id_0)
2743
+ proposal_id_hex = props["proposals"][0]["proposal_id"]
2744
+
2745
+ # check proposal state and farm enough blocks to pass
2746
+ state = await client_0.dao_get_proposal_state(wallet_id=dao_id_0, proposal_id=proposal_id_hex)
2747
+ assert state["success"]
2748
+ assert state["state"]["passed"]
2749
+
2750
+ for _ in range(state["state"]["blocks_needed"] + 1):
2751
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
2752
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2753
+
2754
+ state = await client_0.dao_get_proposal_state(wallet_id=dao_id_0, proposal_id=proposal_id_hex)
2755
+ assert state["success"]
2756
+ assert state["state"]["closable"]
2757
+
2758
+ # close the proposal
2759
+ close = await client_0.dao_close_proposal(
2760
+ wallet_id=dao_id_0, proposal_id=proposal_id_hex, tx_config=DEFAULT_TX_CONFIG, self_destruct=False, fee=fee
2761
+ )
2762
+ tx = close.tx
2763
+ await full_node_api.wait_transaction_records_entered_mempool(records=[tx], timeout=60)
2764
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2765
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2766
+
2767
+ # check proposal is closed
2768
+ await rpc_state(20, client_0.dao_get_proposals, [dao_id_0], lambda x: x["proposals"][0]["closed"], True)
2769
+
2770
+ # free locked cats from finished proposal
2771
+ res = await client_0.dao_free_coins_from_finished_proposals(wallet_id=dao_id_0, tx_config=DEFAULT_TX_CONFIG)
2772
+ tx = res.tx
2773
+ await full_node_api.wait_transaction_records_entered_mempool(records=[tx], timeout=60)
2774
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2775
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2776
+
2777
+ assert isinstance(dao_cat_wallet_0, DAOCATWallet)
2778
+ assert dao_cat_wallet_0.dao_cat_info.locked_coins[0].active_votes == []
2779
+
2780
+ exit = await client_0.dao_exit_lockup(dao_id_0, DEFAULT_TX_CONFIG)
2781
+ exit_tx = exit.tx
2782
+ await full_node_api.wait_transaction_records_entered_mempool(records=[exit_tx], timeout=60)
2783
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2784
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2785
+
2786
+ await time_out_assert(20, dao_cat_wallet_0.get_confirmed_balance, 0)
2787
+ await time_out_assert(20, cat_wallet_0.get_confirmed_balance, cat_amt)
2788
+
2789
+ finally:
2790
+ client_0.close()
2791
+ client_1.close()
2792
+ await client_0.await_closed()
2793
+ await client_1.await_closed()
2794
+
2795
+
2796
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
2797
+ @pytest.mark.parametrize(
2798
+ "trusted",
2799
+ [True, False],
2800
+ )
2801
+ @pytest.mark.anyio
2802
+ async def test_dao_reorgs(self_hostname: str, two_wallet_nodes: OldSimulatorsAndWallets, trusted: bool) -> None:
2803
+ full_nodes, wallets, _ = two_wallet_nodes
2804
+ full_node_api = full_nodes[0]
2805
+ full_node_server = full_node_api.server
2806
+ wallet_node_0, server_0 = wallets[0]
2807
+ wallet_node_1, server_1 = wallets[1]
2808
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
2809
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
2810
+ ph = await wallet_0.get_new_puzzlehash()
2811
+ ph_1 = await wallet_1.get_new_puzzlehash()
2812
+
2813
+ if trusted:
2814
+ wallet_node_0.config["trusted_peers"] = {
2815
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
2816
+ }
2817
+ wallet_node_1.config["trusted_peers"] = {
2818
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
2819
+ }
2820
+ else:
2821
+ wallet_node_0.config["trusted_peers"] = {}
2822
+ wallet_node_1.config["trusted_peers"] = {}
2823
+
2824
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2825
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
2826
+
2827
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
2828
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
2829
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
2830
+
2831
+ funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
2832
+
2833
+ await time_out_assert(20, wallet_0.get_confirmed_balance, funds)
2834
+ await time_out_assert(20, full_node_api.wallet_is_synced, True, wallet_node_0)
2835
+
2836
+ cat_amt = 300000
2837
+ dao_rules = DAORules(
2838
+ proposal_timelock=uint64(5),
2839
+ soft_close_length=uint64(2),
2840
+ attendance_required=uint64(1000), # 10%
2841
+ pass_percentage=uint64(5100), # 51%
2842
+ self_destruct_length=uint64(5),
2843
+ oracle_spend_delay=uint64(2),
2844
+ proposal_minimum_amount=uint64(101),
2845
+ )
2846
+
2847
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2848
+ dao_wallet_0 = await DAOWallet.create_new_dao_and_wallet(
2849
+ wallet_node_0.wallet_state_manager, wallet_0, uint64(cat_amt), dao_rules, action_scope
2850
+ )
2851
+
2852
+ # Get the full node sim to process the wallet creation spend
2853
+ await full_node_api.wait_transaction_records_entered_mempool(
2854
+ records=action_scope.side_effects.transactions, timeout=60
2855
+ )
2856
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2857
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2858
+
2859
+ await time_out_assert(60, dao_wallet_0.get_confirmed_balance, uint128(1))
2860
+
2861
+ # Test Reorg on creation
2862
+ height = full_node_api.full_node.blockchain.get_peak_height()
2863
+ assert height is not None
2864
+ await full_node_api.reorg_from_index_to_new_index(
2865
+ ReorgProtocol(uint32(height - 2), uint32(height + 1), puzzle_hash_0, None)
2866
+ )
2867
+
2868
+ assert dao_wallet_0.dao_info.current_treasury_coin
2869
+ await time_out_assert(60, dao_wallet_0.get_confirmed_balance, uint128(1))
2870
+
2871
+ # get the cat wallets
2872
+ cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.cat_wallet_id]
2873
+ await time_out_assert(10, cat_wallet_0.get_confirmed_balance, cat_amt)
2874
+
2875
+ # get the dao_cat wallet
2876
+ dao_cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.dao_cat_wallet_id]
2877
+
2878
+ treasury_id = dao_wallet_0.dao_info.treasury_id
2879
+
2880
+ # Create the other user's wallet from the treasury id
2881
+ dao_wallet_1 = await DAOWallet.create_new_dao_wallet_for_existing_dao(
2882
+ wallet_node_1.wallet_state_manager, wallet_1, treasury_id
2883
+ )
2884
+ assert dao_wallet_1.dao_info.treasury_id == treasury_id
2885
+
2886
+ # Create funding spends for xch
2887
+ xch_funds = uint64(500000)
2888
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2889
+ await dao_wallet_0.create_add_funds_to_treasury_spend(
2890
+ xch_funds,
2891
+ action_scope,
2892
+ )
2893
+ await full_node_api.wait_transaction_records_entered_mempool(
2894
+ records=action_scope.side_effects.transactions, timeout=60
2895
+ )
2896
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2897
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2898
+
2899
+ # Check that the funding spend is recognized by both dao wallets
2900
+ await time_out_assert(20, dao_wallet_0.get_balance_by_asset_type, xch_funds)
2901
+ await time_out_assert(20, dao_wallet_1.get_balance_by_asset_type, xch_funds)
2902
+
2903
+ # Reorg funding spend
2904
+ height = full_node_api.full_node.blockchain.get_peak_height()
2905
+ assert height is not None
2906
+ await full_node_api.reorg_from_index_to_new_index(
2907
+ ReorgProtocol(uint32(height - 1), uint32(height + 1), puzzle_hash_0, None)
2908
+ )
2909
+ await time_out_assert(20, dao_wallet_0.get_balance_by_asset_type, xch_funds)
2910
+ await time_out_assert(20, dao_wallet_1.get_balance_by_asset_type, xch_funds)
2911
+
2912
+ # Send some dao_cats to wallet_1
2913
+ # Get the cat wallets for wallet_1
2914
+ cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.cat_wallet_id]
2915
+ dao_cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.dao_cat_wallet_id]
2916
+ assert cat_wallet_1
2917
+ assert dao_cat_wallet_1
2918
+
2919
+ async with cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2920
+ await cat_wallet_0.generate_signed_transaction(
2921
+ [100000],
2922
+ [ph_1],
2923
+ action_scope,
2924
+ )
2925
+ await full_node_api.wait_transaction_records_entered_mempool(
2926
+ records=action_scope.side_effects.transactions, timeout=60
2927
+ )
2928
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2929
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2930
+
2931
+ cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.cat_wallet_id]
2932
+ await time_out_assert(20, cat_wallet_1.get_confirmed_balance, 100000)
2933
+
2934
+ # Create dao cats for voting
2935
+ dao_cat_0_bal = await dao_cat_wallet_0.get_votable_balance()
2936
+ assert dao_cat_0_bal == 200000
2937
+ async with dao_cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2938
+ await dao_cat_wallet_0.enter_dao_cat_voting_mode(dao_cat_0_bal, action_scope)
2939
+ await full_node_api.wait_transaction_records_entered_mempool(
2940
+ records=action_scope.side_effects.transactions, timeout=60
2941
+ )
2942
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2943
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2944
+
2945
+ # Create a proposal for xch spend
2946
+ recipient_puzzle_hash = await wallet_0.get_new_puzzlehash()
2947
+ proposal_amount = uint64(10000)
2948
+ xch_proposal_inner = generate_simple_proposal_innerpuz(
2949
+ treasury_id,
2950
+ [recipient_puzzle_hash],
2951
+ [proposal_amount],
2952
+ [None],
2953
+ )
2954
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2955
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, dao_cat_0_bal, uint64(1000))
2956
+ await full_node_api.wait_transaction_records_entered_mempool(
2957
+ records=action_scope.side_effects.transactions, timeout=60
2958
+ )
2959
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
2960
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2961
+
2962
+ # Check the proposal is saved
2963
+ assert len(dao_wallet_0.dao_info.proposals_list) == 1
2964
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == dao_cat_0_bal
2965
+ assert dao_wallet_0.dao_info.proposals_list[0].timer_coin is not None
2966
+
2967
+ # Reorg proposal creation
2968
+ height = full_node_api.full_node.blockchain.get_peak_height()
2969
+ assert height is not None
2970
+ await full_node_api.reorg_from_index_to_new_index(
2971
+ ReorgProtocol(uint32(height - 1), uint32(height + 1), puzzle_hash_0, None)
2972
+ )
2973
+ assert len(dao_wallet_0.dao_info.proposals_list) == 1
2974
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == dao_cat_0_bal
2975
+ assert dao_wallet_0.dao_info.proposals_list[0].timer_coin is not None
2976
+
2977
+ # Check that wallet_1 also finds and saved the proposal
2978
+ assert len(dao_wallet_1.dao_info.proposals_list) == 1
2979
+ prop = dao_wallet_1.dao_info.proposals_list[0]
2980
+
2981
+ total_votes = dao_cat_0_bal
2982
+
2983
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == total_votes
2984
+ assert dao_wallet_0.dao_info.proposals_list[0].yes_votes == total_votes
2985
+ assert dao_wallet_1.dao_info.proposals_list[0].amount_voted == total_votes
2986
+ assert dao_wallet_1.dao_info.proposals_list[0].yes_votes == total_votes
2987
+
2988
+ # Create votable dao cats and add a new vote
2989
+ dao_cat_1_bal = await dao_cat_wallet_1.get_votable_balance()
2990
+ async with dao_cat_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2991
+ await dao_cat_wallet_1.enter_dao_cat_voting_mode(dao_cat_1_bal, action_scope)
2992
+ await full_node_api.wait_transaction_records_entered_mempool(
2993
+ records=action_scope.side_effects.transactions, timeout=60
2994
+ )
2995
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
2996
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
2997
+
2998
+ async with dao_cat_wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2999
+ await dao_wallet_1.generate_proposal_vote_spend(prop.proposal_id, dao_cat_1_bal, True, action_scope)
3000
+ await full_node_api.wait_transaction_records_entered_mempool(
3001
+ records=action_scope.side_effects.transactions, timeout=60
3002
+ )
3003
+ await full_node_api.process_all_wallet_transactions(wallet_1, timeout=60)
3004
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
3005
+
3006
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == dao_cat_0_bal + dao_cat_1_bal
3007
+ assert dao_wallet_0.dao_info.proposals_list[0].yes_votes == dao_cat_0_bal + dao_cat_1_bal
3008
+ assert dao_wallet_1.dao_info.proposals_list[0].amount_voted == dao_cat_0_bal + dao_cat_1_bal
3009
+ assert dao_wallet_1.dao_info.proposals_list[0].yes_votes == dao_cat_0_bal + dao_cat_1_bal
3010
+
3011
+ # Reorg on vote spend
3012
+ height = full_node_api.full_node.blockchain.get_peak_height()
3013
+ assert height is not None
3014
+ await full_node_api.reorg_from_index_to_new_index(
3015
+ ReorgProtocol(uint32(height - 1), uint32(height + 1), puzzle_hash_0, None)
3016
+ )
3017
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == dao_cat_0_bal + dao_cat_1_bal
3018
+ assert dao_wallet_0.dao_info.proposals_list[0].yes_votes == dao_cat_0_bal + dao_cat_1_bal
3019
+ assert dao_wallet_1.dao_info.proposals_list[0].amount_voted == dao_cat_0_bal + dao_cat_1_bal
3020
+ assert dao_wallet_1.dao_info.proposals_list[0].yes_votes == dao_cat_0_bal + dao_cat_1_bal
3021
+
3022
+ # Close proposal
3023
+ for i in range(5):
3024
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
3025
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
3026
+
3027
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3028
+ await dao_wallet_0.create_proposal_close_spend(prop.proposal_id, action_scope, fee=uint64(100))
3029
+ await full_node_api.wait_transaction_records_entered_mempool(
3030
+ records=action_scope.side_effects.transactions, timeout=60
3031
+ )
3032
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3033
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
3034
+
3035
+ await time_out_assert(20, get_proposal_state, (True, True), *[dao_wallet_0, 0])
3036
+ await time_out_assert(20, get_proposal_state, (True, True), *[dao_wallet_1, 0])
3037
+
3038
+ # Reorg closed proposal
3039
+ height = full_node_api.full_node.blockchain.get_peak_height()
3040
+ assert height is not None
3041
+ await full_node_api.reorg_from_index_to_new_index(
3042
+ ReorgProtocol(uint32(height - 1), uint32(height + 1), puzzle_hash_0, None)
3043
+ )
3044
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
3045
+ await time_out_assert(20, get_proposal_state, (True, True), *[dao_wallet_0, 0])
3046
+ await time_out_assert(20, get_proposal_state, (True, True), *[dao_wallet_1, 0])
3047
+
3048
+
3049
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
3050
+ @pytest.mark.parametrize(
3051
+ "trusted",
3052
+ [True, False],
3053
+ )
3054
+ @pytest.mark.anyio
3055
+ async def test_dao_votes(self_hostname: str, three_wallet_nodes: OldSimulatorsAndWallets, trusted: bool) -> None:
3056
+ full_nodes, wallets, _ = three_wallet_nodes
3057
+ full_node_api = full_nodes[0]
3058
+ full_node_server = full_node_api.server
3059
+ wallet_node_0, server_0 = wallets[0]
3060
+ wallet_node_1, server_1 = wallets[1]
3061
+ wallet_node_2, server_2 = wallets[2]
3062
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
3063
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
3064
+ wallet_2 = wallet_node_2.wallet_state_manager.main_wallet
3065
+ ph_0 = await wallet_0.get_new_puzzlehash()
3066
+ ph_1 = await wallet_1.get_new_puzzlehash()
3067
+ ph_2 = await wallet_2.get_new_puzzlehash()
3068
+
3069
+ if trusted:
3070
+ wallet_node_0.config["trusted_peers"] = {
3071
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
3072
+ }
3073
+ wallet_node_1.config["trusted_peers"] = {
3074
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
3075
+ }
3076
+ wallet_node_2.config["trusted_peers"] = {
3077
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
3078
+ }
3079
+ else:
3080
+ wallet_node_0.config["trusted_peers"] = {}
3081
+ wallet_node_1.config["trusted_peers"] = {}
3082
+ wallet_node_2.config["trusted_peers"] = {}
3083
+
3084
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
3085
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
3086
+ await server_2.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
3087
+
3088
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_0))
3089
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
3090
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_2))
3091
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
3092
+
3093
+ funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
3094
+
3095
+ await time_out_assert(20, wallet_0.get_confirmed_balance, funds)
3096
+ await time_out_assert(20, full_node_api.wallet_is_synced, True, wallet_node_0)
3097
+
3098
+ # set a standard fee amount to use in all txns
3099
+ base_fee = uint64(100)
3100
+
3101
+ # set the cat issuance and DAO rules
3102
+ cat_issuance = 300000
3103
+ proposal_min_amt = uint64(101)
3104
+ dao_rules = DAORules(
3105
+ proposal_timelock=uint64(10),
3106
+ soft_close_length=uint64(5),
3107
+ attendance_required=uint64(190000),
3108
+ pass_percentage=uint64(5100), # 51%
3109
+ self_destruct_length=uint64(20),
3110
+ oracle_spend_delay=uint64(10),
3111
+ proposal_minimum_amount=proposal_min_amt,
3112
+ )
3113
+
3114
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3115
+ dao_wallet_0 = await DAOWallet.create_new_dao_and_wallet(
3116
+ wallet_node_0.wallet_state_manager,
3117
+ wallet_0,
3118
+ uint64(cat_issuance),
3119
+ dao_rules,
3120
+ action_scope,
3121
+ )
3122
+
3123
+ await full_node_api.wait_transaction_records_entered_mempool(
3124
+ records=action_scope.side_effects.transactions, timeout=60
3125
+ )
3126
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3127
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
3128
+
3129
+ cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.cat_wallet_id]
3130
+ dao_cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.dao_cat_wallet_id]
3131
+ await time_out_assert(10, cat_wallet_0.get_confirmed_balance, cat_issuance)
3132
+ assert dao_cat_wallet_0
3133
+
3134
+ treasury_id = dao_wallet_0.dao_info.treasury_id
3135
+
3136
+ dc_1 = uint64(100000)
3137
+ dc_2 = uint64(50000)
3138
+ dc_3 = uint64(30000)
3139
+ dc_4 = uint64(20000)
3140
+ dc_5 = uint64(10000)
3141
+
3142
+ # Lockup voting cats for all wallets
3143
+ async with dao_cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3144
+ await dao_cat_wallet_0.enter_dao_cat_voting_mode(dc_1, action_scope, fee=base_fee)
3145
+ await full_node_api.wait_transaction_records_entered_mempool(
3146
+ records=action_scope.side_effects.transactions, timeout=60
3147
+ )
3148
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3149
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3150
+
3151
+ async with dao_cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3152
+ await dao_cat_wallet_0.enter_dao_cat_voting_mode(dc_2, action_scope, fee=base_fee)
3153
+ await full_node_api.wait_transaction_records_entered_mempool(
3154
+ records=action_scope.side_effects.transactions, timeout=60
3155
+ )
3156
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3157
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3158
+
3159
+ async with dao_cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3160
+ await dao_cat_wallet_0.enter_dao_cat_voting_mode(dc_3, action_scope, fee=base_fee)
3161
+ await full_node_api.wait_transaction_records_entered_mempool(
3162
+ records=action_scope.side_effects.transactions, timeout=60
3163
+ )
3164
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3165
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3166
+
3167
+ async with dao_cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3168
+ await dao_cat_wallet_0.enter_dao_cat_voting_mode(dc_4, action_scope, fee=base_fee)
3169
+ await full_node_api.wait_transaction_records_entered_mempool(
3170
+ records=action_scope.side_effects.transactions, timeout=60
3171
+ )
3172
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3173
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3174
+
3175
+ async with dao_cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3176
+ await dao_cat_wallet_0.enter_dao_cat_voting_mode(dc_5, action_scope, fee=base_fee)
3177
+ await full_node_api.wait_transaction_records_entered_mempool(
3178
+ records=action_scope.side_effects.transactions, timeout=60
3179
+ )
3180
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3181
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3182
+
3183
+ await time_out_assert(10, dao_cat_wallet_0.get_confirmed_balance, dc_1 + dc_2 + dc_3 + dc_4 + dc_5)
3184
+
3185
+ # Create funding spend so the treasury holds some XCH
3186
+ xch_funds = uint64(500000)
3187
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3188
+ await dao_wallet_0.create_add_funds_to_treasury_spend(xch_funds, action_scope)
3189
+ await full_node_api.wait_transaction_records_entered_mempool(
3190
+ records=action_scope.side_effects.transactions, timeout=60
3191
+ )
3192
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3193
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3194
+
3195
+ # Check that the funding spend is recognized by all wallets
3196
+ await time_out_assert(10, dao_wallet_0.get_balance_by_asset_type, xch_funds)
3197
+
3198
+ # Create Proposals
3199
+ recipient_puzzle_hash = await wallet_2.get_new_puzzlehash()
3200
+ proposal_amount_1 = uint64(9998)
3201
+ xch_proposal_inner = generate_simple_proposal_innerpuz(
3202
+ treasury_id,
3203
+ [recipient_puzzle_hash],
3204
+ [proposal_amount_1],
3205
+ [None],
3206
+ )
3207
+
3208
+ vote_1 = uint64(120000)
3209
+ vote_2 = uint64(150000)
3210
+
3211
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3212
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, vote_1, fee=base_fee)
3213
+ await full_node_api.wait_transaction_records_entered_mempool(
3214
+ records=action_scope.side_effects.transactions, timeout=60
3215
+ )
3216
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3217
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3218
+
3219
+ assert len(dao_wallet_0.dao_info.proposals_list) == 1
3220
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == vote_1
3221
+ assert dao_wallet_0.dao_info.proposals_list[0].timer_coin is not None
3222
+ prop_0 = dao_wallet_0.dao_info.proposals_list[0]
3223
+
3224
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3225
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, vote_2, fee=base_fee)
3226
+ await full_node_api.wait_transaction_records_entered_mempool(
3227
+ records=action_scope.side_effects.transactions, timeout=60
3228
+ )
3229
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3230
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3231
+
3232
+ assert len(dao_wallet_0.dao_info.proposals_list) == 2
3233
+ assert dao_wallet_0.dao_info.proposals_list[1].amount_voted == vote_2
3234
+
3235
+ vote_3 = uint64(30000)
3236
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3237
+ await dao_wallet_0.generate_proposal_vote_spend(prop_0.proposal_id, vote_3, True, action_scope)
3238
+ await full_node_api.wait_transaction_records_entered_mempool(
3239
+ records=action_scope.side_effects.transactions, timeout=60
3240
+ )
3241
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3242
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3243
+
3244
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == vote_1 + vote_3
3245
+
3246
+ vote_4 = uint64(60000)
3247
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3248
+ await dao_wallet_0.generate_proposal_vote_spend(prop_0.proposal_id, vote_4, True, action_scope)
3249
+ await full_node_api.wait_transaction_records_entered_mempool(
3250
+ records=action_scope.side_effects.transactions, timeout=60
3251
+ )
3252
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3253
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3254
+
3255
+ assert dao_wallet_0.dao_info.proposals_list[0].amount_voted == vote_1 + vote_3 + vote_4
3256
+
3257
+ vote_5 = uint64(1)
3258
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3259
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, vote_5, fee=base_fee)
3260
+ await full_node_api.wait_transaction_records_entered_mempool(
3261
+ records=action_scope.side_effects.transactions, timeout=60
3262
+ )
3263
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3264
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3265
+
3266
+ assert len(dao_wallet_0.dao_info.proposals_list) == 3
3267
+ assert dao_wallet_0.dao_info.proposals_list[2].amount_voted == vote_5
3268
+ prop_2 = dao_wallet_0.dao_info.proposals_list[2]
3269
+
3270
+ vote_6 = uint64(20000)
3271
+ for i in range(10):
3272
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3273
+ await dao_wallet_0.generate_proposal_vote_spend(prop_2.proposal_id, vote_6, True, action_scope)
3274
+ await full_node_api.wait_transaction_records_entered_mempool(
3275
+ records=action_scope.side_effects.transactions, timeout=60
3276
+ )
3277
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3278
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3279
+
3280
+ assert dao_wallet_0.dao_info.proposals_list[2].amount_voted == 200001
3281
+
3282
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3283
+ await dao_wallet_0.create_proposal_close_spend(prop_0.proposal_id, action_scope)
3284
+ await full_node_api.wait_transaction_records_entered_mempool(
3285
+ records=action_scope.side_effects.transactions, timeout=60
3286
+ )
3287
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3288
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3289
+
3290
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3291
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, fee=base_fee)
3292
+ await full_node_api.wait_transaction_records_entered_mempool(
3293
+ records=action_scope.side_effects.transactions, timeout=60
3294
+ )
3295
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3296
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3297
+
3298
+ assert dao_wallet_0.dao_info.proposals_list[3].amount_voted == 210000
3299
+
3300
+
3301
+ @pytest.mark.limit_consensus_modes(reason="does not depend on consensus rules")
3302
+ @pytest.mark.parametrize(
3303
+ "trusted",
3304
+ [True, False],
3305
+ )
3306
+ @pytest.mark.anyio
3307
+ async def test_dao_resync(self_hostname: str, two_wallet_nodes: OldSimulatorsAndWallets, trusted: bool) -> None:
3308
+ full_nodes, wallets, _ = two_wallet_nodes
3309
+ full_node_api = full_nodes[0]
3310
+ full_node_server = full_node_api.server
3311
+ wallet_node_0, server_0 = wallets[0]
3312
+ wallet_node_1, server_1 = wallets[1]
3313
+ wallet_api_0 = WalletRpcApi(wallet_node_0)
3314
+ wallet_api_1 = WalletRpcApi(wallet_node_1)
3315
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
3316
+ wallet_1 = wallet_node_1.wallet_state_manager.main_wallet
3317
+ ph = await wallet_0.get_new_puzzlehash()
3318
+ ph_1 = await wallet_1.get_new_puzzlehash()
3319
+
3320
+ if trusted:
3321
+ wallet_node_0.config["trusted_peers"] = {
3322
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
3323
+ }
3324
+ wallet_node_1.config["trusted_peers"] = {
3325
+ full_node_api.full_node.server.node_id.hex(): full_node_api.full_node.server.node_id.hex()
3326
+ }
3327
+ else:
3328
+ wallet_node_0.config["trusted_peers"] = {}
3329
+ wallet_node_1.config["trusted_peers"] = {}
3330
+
3331
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
3332
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
3333
+
3334
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
3335
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_1))
3336
+
3337
+ funds = calculate_pool_reward(uint32(1)) + calculate_base_farmer_reward(uint32(1))
3338
+
3339
+ await time_out_assert(20, wallet_0.get_confirmed_balance, funds)
3340
+ await time_out_assert(20, full_node_api.wallet_is_synced, True, wallet_node_0)
3341
+
3342
+ cat_amt = 2000
3343
+ dao_rules = DAORules(
3344
+ proposal_timelock=uint64(10),
3345
+ soft_close_length=uint64(5),
3346
+ attendance_required=uint64(1000), # 10%
3347
+ pass_percentage=uint64(5100), # 51%
3348
+ self_destruct_length=uint64(20),
3349
+ oracle_spend_delay=uint64(10),
3350
+ proposal_minimum_amount=uint64(1),
3351
+ )
3352
+
3353
+ fee = uint64(10)
3354
+ fee_for_cat = uint64(20)
3355
+ async with wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3356
+ dao_wallet_0 = await DAOWallet.create_new_dao_and_wallet(
3357
+ wallet_node_0.wallet_state_manager,
3358
+ wallet_0,
3359
+ uint64(cat_amt * 2),
3360
+ dao_rules,
3361
+ action_scope=action_scope,
3362
+ fee=fee,
3363
+ fee_for_cat=fee_for_cat,
3364
+ )
3365
+
3366
+ await full_node_api.wait_transaction_records_entered_mempool(
3367
+ records=action_scope.side_effects.transactions, timeout=60
3368
+ )
3369
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3370
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
3371
+
3372
+ treasury_id = dao_wallet_0.dao_info.treasury_id
3373
+
3374
+ # get the cat wallets
3375
+ cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.cat_wallet_id]
3376
+ # dao_cat_wallet_0 = dao_wallet_0.wallet_state_manager.wallets[dao_wallet_0.dao_info.dao_cat_wallet_id]
3377
+
3378
+ # Create the other user's wallet from the treasury id
3379
+ dao_wallet_1 = await DAOWallet.create_new_dao_wallet_for_existing_dao(
3380
+ wallet_node_1.wallet_state_manager, wallet_1, treasury_id
3381
+ )
3382
+ assert dao_wallet_0.dao_info.treasury_id == dao_wallet_1.dao_info.treasury_id
3383
+
3384
+ # Get the cat wallets for wallet_1
3385
+ cat_wallet_1 = dao_wallet_1.wallet_state_manager.wallets[dao_wallet_1.dao_info.cat_wallet_id]
3386
+
3387
+ # Send some cats to the dao_cat lockup
3388
+ dao_cat_amt = uint64(100)
3389
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3390
+ await dao_wallet_0.enter_dao_cat_voting_mode(dao_cat_amt, action_scope)
3391
+
3392
+ await full_node_api.wait_transaction_records_entered_mempool(
3393
+ records=action_scope.side_effects.transactions, timeout=60
3394
+ )
3395
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3396
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3397
+
3398
+ # send some cats from wallet_0 to wallet_1 so we can test voting
3399
+ async with cat_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3400
+ await cat_wallet_0.generate_signed_transaction([cat_amt], [ph_1], action_scope)
3401
+
3402
+ await full_node_api.wait_transaction_records_entered_mempool(
3403
+ records=action_scope.side_effects.transactions, timeout=60
3404
+ )
3405
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3406
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=30)
3407
+
3408
+ await time_out_assert(10, cat_wallet_1.get_confirmed_balance, cat_amt)
3409
+
3410
+ recipient_puzzle_hash = await wallet_1.get_new_puzzlehash()
3411
+ proposal_amount_1 = uint64(9998)
3412
+ xch_proposal_inner = generate_simple_proposal_innerpuz(
3413
+ treasury_id,
3414
+ [recipient_puzzle_hash],
3415
+ [proposal_amount_1],
3416
+ [None],
3417
+ )
3418
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3419
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope, uint64(10))
3420
+ await full_node_api.wait_transaction_records_entered_mempool(
3421
+ records=action_scope.side_effects.transactions, timeout=60
3422
+ )
3423
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3424
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
3425
+
3426
+ # make another proposal spending all the dao_cats
3427
+ xch_proposal_inner = generate_simple_proposal_innerpuz(
3428
+ treasury_id,
3429
+ [recipient_puzzle_hash],
3430
+ [proposal_amount_1],
3431
+ [None],
3432
+ )
3433
+ async with dao_wallet_0.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3434
+ await dao_wallet_0.generate_new_proposal(xch_proposal_inner, action_scope)
3435
+ await full_node_api.wait_transaction_records_entered_mempool(
3436
+ records=action_scope.side_effects.transactions, timeout=60
3437
+ )
3438
+ await full_node_api.process_all_wallet_transactions(wallet_0, timeout=60)
3439
+ await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=30)
3440
+
3441
+ # set flag to reset wallet sync data on start
3442
+ await wallet_api_0.set_wallet_resync_on_startup({"enable": True})
3443
+ fingerprint_0 = wallet_node_0.logged_in_fingerprint
3444
+ await wallet_api_1.set_wallet_resync_on_startup({"enable": True})
3445
+ fingerprint_1 = wallet_node_1.logged_in_fingerprint
3446
+ # Delete tx records
3447
+ await wallet_node_0.wallet_state_manager.tx_store.rollback_to_block(0)
3448
+ wallet_node_0._close()
3449
+ await wallet_node_0._await_closed()
3450
+ wallet_node_1._close()
3451
+ await wallet_node_1._await_closed()
3452
+ wallet_node_0.config["database_path"] = "wallet/db/blockchain_wallet_v2_test_1_CHALLENGE_KEY.sqlite"
3453
+ wallet_node_1.config["database_path"] = "wallet/db/blockchain_wallet_v2_test_2_CHALLENGE_KEY.sqlite"
3454
+ # Start resync
3455
+ await wallet_node_0._start_with_fingerprint(fingerprint_0)
3456
+ await wallet_node_1._start_with_fingerprint(fingerprint_1)
3457
+ await server_0.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
3458
+ await server_1.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
3459
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
3460
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=20)
3461
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=20)
3462
+ wallet_0 = wallet_node_0.wallet_state_manager.main_wallet
3463
+
3464
+ assert len(await wallet_node_0.wallet_state_manager.get_all_wallet_info_entries()) == 1
3465
+
3466
+ new_dao_wallet = await DAOWallet.create_new_dao_wallet_for_existing_dao(
3467
+ wallet_node_0.wallet_state_manager,
3468
+ wallet_0,
3469
+ treasury_id,
3470
+ )
3471
+
3472
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
3473
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=20)
3474
+ assert len(await wallet_node_0.wallet_state_manager.get_all_wallet_info_entries()) == 4
3475
+ new_cat_wallet = new_dao_wallet.wallet_state_manager.wallets[new_dao_wallet.dao_info.cat_wallet_id]
3476
+ new_dao_cat_wallet = new_dao_wallet.wallet_state_manager.wallets[new_dao_wallet.dao_info.dao_cat_wallet_id]
3477
+
3478
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(puzzle_hash_0))
3479
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, timeout=20)
3480
+
3481
+ # Check the new wallets have the right balances
3482
+ await time_out_assert(20, new_cat_wallet.get_confirmed_balance, cat_amt - dao_cat_amt)
3483
+ await time_out_assert(20, new_dao_cat_wallet.get_confirmed_balance, dao_cat_amt)
3484
+
3485
+ # Check the proposals are found and accurate
3486
+ assert len(new_dao_wallet.dao_info.proposals_list) == 2
3487
+ assert new_dao_wallet.dao_info.proposals_list[0].yes_votes == 10
3488
+ assert new_dao_wallet.dao_info.proposals_list[1].yes_votes == 100