chia-blockchain 2.5.0rc2__py3-none-any.whl → 2.5.1rc2__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.
- chia/_tests/README.md +1 -1
- chia/_tests/blockchain/blockchain_test_utils.py +24 -26
- chia/_tests/blockchain/test_augmented_chain.py +6 -8
- chia/_tests/blockchain/test_blockchain.py +409 -307
- chia/_tests/blockchain/test_blockchain_transactions.py +56 -75
- chia/_tests/blockchain/test_build_chains.py +11 -13
- chia/_tests/blockchain/test_get_block_generator.py +8 -8
- chia/_tests/blockchain/test_lookup_fork_chain.py +3 -4
- chia/_tests/build-init-files.py +3 -4
- chia/_tests/build-job-matrix.py +9 -9
- chia/_tests/check_sql_statements.py +2 -3
- chia/_tests/clvm/benchmark_costs.py +1 -1
- chia/_tests/clvm/coin_store.py +7 -5
- chia/_tests/clvm/test_chialisp_deserialization.py +8 -8
- chia/_tests/clvm/test_condition_codes.py +2 -2
- chia/_tests/clvm/test_curry_and_treehash.py +2 -4
- chia/_tests/clvm/test_message_conditions.py +184 -0
- chia/_tests/clvm/test_puzzle_compression.py +1 -2
- chia/_tests/clvm/test_puzzle_drivers.py +3 -3
- chia/_tests/clvm/test_puzzles.py +13 -18
- chia/_tests/clvm/test_singletons.py +17 -17
- chia/_tests/clvm/test_spend_sim.py +7 -7
- chia/_tests/cmds/cmd_test_utils.py +42 -45
- chia/_tests/cmds/conftest.py +2 -2
- chia/_tests/cmds/test_click_types.py +21 -16
- chia/_tests/cmds/test_cmd_framework.py +255 -35
- chia/_tests/cmds/test_cmds_util.py +2 -2
- chia/_tests/cmds/test_daemon.py +3 -3
- chia/_tests/cmds/test_dev_gh.py +131 -0
- chia/_tests/cmds/test_farm_cmd.py +1 -2
- chia/_tests/cmds/test_show.py +6 -6
- chia/_tests/cmds/test_tx_config_args.py +2 -1
- chia/_tests/cmds/wallet/test_dao.py +23 -23
- chia/_tests/cmds/wallet/test_did.py +29 -29
- chia/_tests/cmds/wallet/test_nft.py +24 -23
- chia/_tests/cmds/wallet/test_notifications.py +8 -8
- chia/_tests/cmds/wallet/test_tx_decorators.py +3 -3
- chia/_tests/cmds/wallet/test_vcs.py +97 -73
- chia/_tests/cmds/wallet/test_wallet.py +74 -75
- chia/_tests/cmds/wallet/test_wallet_check.py +5 -7
- chia/_tests/conftest.py +153 -38
- chia/_tests/connection_utils.py +7 -6
- chia/_tests/core/cmds/test_beta.py +3 -3
- chia/_tests/core/cmds/test_keys.py +6 -6
- chia/_tests/core/cmds/test_wallet.py +3 -3
- chia/_tests/core/consensus/test_block_creation.py +3 -5
- chia/_tests/core/custom_types/test_coin.py +1 -3
- chia/_tests/core/custom_types/test_spend_bundle.py +3 -4
- chia/_tests/core/daemon/test_daemon.py +58 -58
- chia/_tests/core/daemon/test_keychain_proxy.py +2 -1
- chia/_tests/core/data_layer/conftest.py +4 -3
- chia/_tests/core/data_layer/test_data_cli.py +1 -2
- chia/_tests/core/data_layer/test_data_layer.py +5 -5
- chia/_tests/core/data_layer/test_data_layer_util.py +8 -9
- chia/_tests/core/data_layer/test_data_rpc.py +75 -93
- chia/_tests/core/data_layer/test_data_store.py +38 -37
- chia/_tests/core/data_layer/test_data_store_schema.py +11 -11
- chia/_tests/core/data_layer/util.py +11 -10
- chia/_tests/core/farmer/test_farmer_api.py +6 -4
- chia/_tests/core/full_node/full_sync/test_full_sync.py +5 -10
- chia/_tests/core/full_node/ram_db.py +2 -2
- chia/_tests/core/full_node/stores/test_block_store.py +113 -11
- chia/_tests/core/full_node/stores/test_coin_store.py +37 -28
- chia/_tests/core/full_node/stores/test_full_node_store.py +34 -30
- chia/_tests/core/full_node/stores/test_hint_store.py +3 -4
- chia/_tests/core/full_node/test_address_manager.py +2 -2
- chia/_tests/core/full_node/test_block_height_map.py +1 -1
- chia/_tests/core/full_node/test_conditions.py +10 -12
- chia/_tests/core/full_node/test_full_node.py +2077 -1822
- chia/_tests/core/full_node/test_generator_tools.py +4 -4
- chia/_tests/core/full_node/test_hint_management.py +2 -2
- chia/_tests/core/full_node/test_performance.py +2 -5
- chia/_tests/core/full_node/test_subscriptions.py +4 -4
- chia/_tests/core/full_node/test_tx_processing_queue.py +5 -4
- chia/_tests/core/make_block_generator.py +5 -7
- chia/_tests/core/mempool/test_mempool.py +205 -208
- chia/_tests/core/mempool/test_mempool_fee_protocol.py +5 -5
- chia/_tests/core/mempool/test_mempool_item_queries.py +2 -4
- chia/_tests/core/mempool/test_mempool_manager.py +109 -80
- chia/_tests/core/mempool/test_mempool_performance.py +3 -4
- chia/_tests/core/mempool/test_singleton_fast_forward.py +12 -12
- chia/_tests/core/server/flood.py +6 -4
- chia/_tests/core/server/serve.py +10 -7
- chia/_tests/core/server/test_api_protocol.py +21 -0
- chia/_tests/core/server/test_capabilities.py +3 -5
- chia/_tests/core/server/test_dos.py +15 -16
- chia/_tests/core/server/test_loop.py +14 -10
- chia/_tests/core/server/test_node_discovery.py +1 -2
- chia/_tests/core/server/test_rate_limits.py +156 -44
- chia/_tests/core/server/test_server.py +8 -7
- chia/_tests/core/services/test_services.py +59 -37
- chia/_tests/core/ssl/test_ssl.py +5 -3
- chia/_tests/core/test_cost_calculation.py +5 -6
- chia/_tests/core/test_crawler.py +2 -2
- chia/_tests/core/test_db_conversion.py +5 -4
- chia/_tests/core/test_db_validation.py +6 -5
- chia/_tests/core/test_farmer_harvester_rpc.py +8 -7
- chia/_tests/core/test_filter.py +3 -5
- chia/_tests/core/test_full_node_rpc.py +64 -90
- chia/_tests/core/test_merkle_set.py +10 -10
- chia/_tests/core/test_program.py +2 -4
- chia/_tests/core/test_rpc_util.py +1 -2
- chia/_tests/core/test_seeder.py +124 -12
- chia/_tests/core/util/test_block_cache.py +5 -5
- chia/_tests/core/util/test_cached_bls.py +3 -3
- chia/_tests/core/util/test_config.py +13 -13
- chia/_tests/core/util/test_files.py +2 -2
- chia/_tests/core/util/test_jsonify.py +9 -9
- chia/_tests/core/util/test_keychain.py +13 -5
- chia/_tests/core/util/test_keyring_wrapper.py +6 -5
- chia/_tests/core/util/test_log_exceptions.py +3 -3
- chia/_tests/core/util/test_streamable.py +38 -38
- chia/_tests/db/test_db_wrapper.py +13 -12
- chia/_tests/environments/common.py +2 -2
- chia/_tests/environments/full_node.py +2 -2
- chia/_tests/environments/wallet.py +109 -48
- chia/_tests/farmer_harvester/test_farmer.py +35 -35
- chia/_tests/farmer_harvester/test_farmer_harvester.py +17 -17
- chia/_tests/farmer_harvester/test_filter_prefix_bits.py +6 -5
- chia/_tests/farmer_harvester/test_third_party_harvesters.py +73 -46
- chia/_tests/fee_estimation/test_fee_estimation_integration.py +8 -8
- chia/_tests/fee_estimation/test_fee_estimation_rpc.py +47 -47
- chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +6 -7
- chia/_tests/fee_estimation/test_mempoolitem_height_added.py +11 -11
- chia/_tests/generator/test_compression.py +13 -30
- chia/_tests/generator/test_generator_types.py +3 -3
- chia/_tests/generator/test_rom.py +7 -9
- chia/_tests/plot_sync/test_delta.py +2 -3
- chia/_tests/plot_sync/test_plot_sync.py +25 -24
- chia/_tests/plot_sync/test_receiver.py +9 -9
- chia/_tests/plot_sync/test_sender.py +1 -1
- chia/_tests/plot_sync/test_sync_simulated.py +27 -26
- chia/_tests/plot_sync/util.py +2 -1
- chia/_tests/plotting/test_plot_manager.py +54 -11
- chia/_tests/plotting/util.py +2 -3
- chia/_tests/pools/test_pool_cli_parsing.py +128 -0
- chia/_tests/pools/test_pool_cmdline.py +993 -15
- chia/_tests/pools/test_pool_config.py +3 -5
- chia/_tests/pools/test_pool_puzzles_lifecycle.py +10 -11
- chia/_tests/pools/test_pool_rpc.py +203 -90
- chia/_tests/pools/test_pool_wallet.py +12 -8
- chia/_tests/pools/test_wallet_pool_store.py +3 -3
- chia/_tests/process_junit.py +16 -17
- chia/_tests/rpc/test_rpc_client.py +59 -2
- chia/_tests/rpc/test_rpc_server.py +183 -0
- chia/_tests/simulation/test_simulation.py +5 -5
- chia/_tests/simulation/test_simulator.py +8 -10
- chia/_tests/simulation/test_start_simulator.py +5 -4
- chia/_tests/timelord/test_new_peak.py +19 -19
- chia/_tests/tools/test_run_block.py +1 -2
- chia/_tests/tools/test_virtual_project.py +591 -0
- chia/_tests/util/benchmark_cost.py +9 -9
- chia/_tests/util/benchmarks.py +1 -2
- chia/_tests/util/blockchain.py +12 -11
- chia/_tests/util/blockchain_mock.py +15 -15
- chia/_tests/util/build_network_protocol_files.py +12 -12
- chia/_tests/util/db_connection.py +3 -2
- chia/_tests/util/full_sync.py +14 -6
- chia/_tests/util/gen_ssl_certs.py +4 -5
- chia/_tests/util/generator_tools_testing.py +5 -7
- chia/_tests/util/get_name_puzzle_conditions.py +52 -0
- chia/_tests/util/key_tool.py +2 -3
- chia/_tests/util/misc.py +59 -106
- chia/_tests/util/network_protocol_data.py +7 -9
- chia/_tests/util/protocol_messages_json.py +112 -111
- chia/_tests/util/rpc.py +3 -0
- chia/_tests/util/run_block.py +16 -16
- chia/_tests/util/setup_nodes.py +25 -23
- chia/{clvm → _tests/util}/spend_sim.py +59 -55
- chia/_tests/util/split_managers.py +12 -9
- chia/_tests/util/temp_file.py +1 -1
- chia/_tests/util/test_action_scope.py +2 -1
- chia/_tests/util/test_async_pool.py +8 -8
- chia/_tests/util/test_build_job_matrix.py +2 -3
- chia/_tests/util/test_condition_tools.py +4 -6
- chia/_tests/util/test_config.py +5 -5
- chia/_tests/util/test_dump_keyring.py +1 -1
- chia/_tests/util/test_full_block_utils.py +19 -11
- chia/_tests/util/test_limited_semaphore.py +4 -3
- chia/_tests/util/test_logging_filter.py +2 -3
- chia/_tests/util/test_misc.py +29 -28
- chia/_tests/util/test_network.py +32 -31
- chia/_tests/util/test_network_protocol_files.py +2 -3
- chia/_tests/util/test_network_protocol_json.py +1 -0
- chia/_tests/util/test_network_protocol_test.py +18 -19
- chia/_tests/util/test_paginator.py +3 -4
- chia/_tests/util/test_pprint.py +1 -1
- chia/_tests/util/test_priority_mutex.py +18 -17
- chia/_tests/util/test_recursive_replace.py +2 -2
- chia/_tests/util/test_testnet_overrides.py +3 -3
- chia/_tests/util/test_timing.py +1 -1
- chia/_tests/util/test_trusted_peer.py +2 -2
- chia/_tests/util/time_out_assert.py +43 -6
- chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +13 -13
- chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +1 -1
- chia/_tests/wallet/cat_wallet/test_cat_wallet.py +117 -29
- chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +15 -15
- chia/_tests/wallet/cat_wallet/test_trades.py +50 -28
- chia/_tests/wallet/clawback/test_clawback_decorator.py +3 -5
- chia/_tests/wallet/clawback/test_clawback_lifecycle.py +6 -6
- chia/_tests/wallet/clawback/test_clawback_metadata.py +1 -2
- chia/_tests/wallet/conftest.py +135 -74
- chia/_tests/wallet/dao_wallet/test_dao_clvm.py +25 -17
- chia/_tests/wallet/dao_wallet/test_dao_wallets.py +75 -75
- chia/_tests/wallet/db_wallet/test_db_graftroot.py +10 -12
- chia/_tests/wallet/db_wallet/test_dl_offers.py +6 -6
- chia/_tests/wallet/db_wallet/test_dl_wallet.py +18 -18
- chia/_tests/wallet/did_wallet/test_did.py +1277 -474
- chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +12 -11
- chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +115 -105
- chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +6 -7
- chia/_tests/wallet/nft_wallet/test_nft_offers.py +16 -16
- chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +3 -3
- chia/_tests/wallet/nft_wallet/test_nft_wallet.py +38 -12
- chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +1 -1
- chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +31 -33
- chia/_tests/wallet/rpc/test_wallet_rpc.py +218 -171
- chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +36 -37
- chia/_tests/wallet/sync/test_wallet_sync.py +241 -78
- chia/_tests/wallet/test_address_type.py +20 -20
- chia/_tests/wallet/test_clvm_streamable.py +5 -5
- chia/_tests/wallet/test_coin_management.py +354 -0
- chia/_tests/wallet/test_coin_selection.py +34 -35
- chia/_tests/wallet/test_conditions.py +28 -16
- chia/_tests/wallet/test_debug_spend_bundle.py +156 -14
- chia/_tests/wallet/test_new_wallet_protocol.py +29 -31
- chia/_tests/wallet/test_nft_store.py +1 -2
- chia/_tests/wallet/test_notifications.py +2 -2
- chia/_tests/wallet/test_offer_parsing_performance.py +1 -1
- chia/_tests/wallet/test_puzzle_store.py +2 -3
- chia/_tests/wallet/test_sign_coin_spends.py +3 -3
- chia/_tests/wallet/test_signer_protocol.py +33 -34
- chia/_tests/wallet/test_singleton_lifecycle_fast.py +29 -29
- chia/_tests/wallet/test_taproot.py +1 -1
- chia/_tests/wallet/test_transaction_store.py +23 -19
- chia/_tests/wallet/test_util.py +36 -32
- chia/_tests/wallet/test_wallet.py +37 -37
- chia/_tests/wallet/test_wallet_action_scope.py +8 -8
- chia/_tests/wallet/test_wallet_blockchain.py +4 -6
- chia/_tests/wallet/test_wallet_coin_store.py +34 -34
- chia/_tests/wallet/test_wallet_node.py +69 -72
- chia/_tests/wallet/test_wallet_retry.py +3 -3
- chia/_tests/wallet/test_wallet_state_manager.py +12 -5
- chia/_tests/wallet/test_wallet_trade_store.py +2 -2
- chia/_tests/wallet/test_wallet_utils.py +5 -4
- chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +3 -3
- chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +18 -18
- chia/_tests/wallet/vc_wallet/test_vc_wallet.py +69 -40
- chia/_tests/wallet/wallet_block_tools.py +27 -27
- chia/_tests/weight_proof/test_weight_proof.py +30 -30
- chia/apis.py +19 -0
- chia/cmds/beta.py +8 -7
- chia/cmds/beta_funcs.py +15 -11
- chia/cmds/check_wallet_db.py +29 -27
- chia/cmds/chia.py +17 -9
- chia/cmds/cmd_classes.py +87 -79
- chia/cmds/cmd_helpers.py +242 -0
- chia/cmds/cmds_util.py +56 -66
- chia/cmds/coin_funcs.py +168 -153
- chia/cmds/coins.py +156 -194
- chia/cmds/configure.py +4 -3
- chia/cmds/dao.py +89 -33
- chia/cmds/dao_funcs.py +55 -33
- chia/cmds/data.py +7 -6
- chia/cmds/data_funcs.py +26 -21
- chia/cmds/db.py +4 -3
- chia/cmds/db_backup_func.py +2 -2
- chia/cmds/db_upgrade_func.py +3 -3
- chia/cmds/db_validate_func.py +2 -2
- chia/cmds/dev.py +2 -0
- chia/cmds/farm.py +18 -5
- chia/cmds/farm_funcs.py +17 -24
- chia/cmds/gh.py +275 -0
- chia/cmds/init.py +4 -11
- chia/cmds/init_funcs.py +9 -9
- chia/cmds/installers.py +5 -3
- chia/cmds/keys.py +56 -39
- chia/cmds/keys_funcs.py +30 -31
- chia/cmds/netspace.py +6 -3
- chia/cmds/netspace_funcs.py +3 -2
- chia/cmds/param_types.py +16 -6
- chia/cmds/passphrase.py +8 -7
- chia/cmds/passphrase_funcs.py +7 -61
- chia/cmds/peer.py +2 -1
- chia/cmds/peer_funcs.py +5 -5
- chia/cmds/plotnft.py +207 -153
- chia/cmds/plotnft_funcs.py +205 -174
- chia/cmds/plots.py +14 -6
- chia/cmds/plotters.py +2 -1
- chia/cmds/rpc.py +48 -28
- chia/cmds/show.py +2 -1
- chia/cmds/show_funcs.py +7 -6
- chia/cmds/signer.py +50 -58
- chia/cmds/sim.py +22 -14
- chia/cmds/sim_funcs.py +11 -11
- chia/cmds/start.py +3 -3
- chia/cmds/start_funcs.py +9 -12
- chia/cmds/stop.py +4 -3
- chia/cmds/units.py +1 -3
- chia/cmds/wallet.py +252 -96
- chia/cmds/wallet_funcs.py +217 -143
- chia/consensus/block_body_validation.py +133 -86
- chia/consensus/block_creation.py +42 -21
- chia/consensus/block_header_validation.py +32 -37
- chia/consensus/block_record.py +1 -2
- chia/consensus/blockchain.py +167 -180
- chia/consensus/blockchain_interface.py +10 -10
- chia/consensus/constants.py +2 -2
- chia/consensus/default_constants.py +3 -4
- chia/consensus/difficulty_adjustment.py +5 -5
- chia/consensus/find_fork_point.py +5 -5
- chia/consensus/full_block_to_block_record.py +4 -4
- chia/consensus/get_block_challenge.py +2 -2
- chia/consensus/get_block_generator.py +4 -3
- chia/consensus/multiprocess_validation.py +207 -304
- chia/consensus/vdf_info_computation.py +3 -3
- chia/daemon/client.py +46 -27
- chia/daemon/keychain_proxy.py +10 -9
- chia/daemon/keychain_server.py +18 -18
- chia/daemon/server.py +103 -113
- chia/daemon/windows_signal.py +2 -2
- chia/data_layer/data_layer.py +64 -76
- chia/data_layer/data_layer_api.py +8 -0
- chia/data_layer/data_layer_errors.py +3 -3
- chia/data_layer/data_layer_server.py +2 -2
- chia/data_layer/data_layer_util.py +71 -71
- chia/data_layer/data_layer_wallet.py +63 -67
- chia/data_layer/data_store.py +72 -72
- chia/data_layer/dl_wallet_store.py +10 -10
- chia/data_layer/download_data.py +5 -5
- chia/data_layer/s3_plugin_service.py +9 -9
- chia/data_layer/util/benchmark.py +0 -1
- chia/data_layer/util/plugin.py +2 -3
- chia/farmer/farmer.py +46 -43
- chia/farmer/farmer_api.py +27 -21
- chia/full_node/block_height_map.py +6 -6
- chia/full_node/block_store.py +41 -35
- chia/full_node/coin_store.py +42 -41
- chia/full_node/fee_estimate.py +2 -2
- chia/full_node/fee_estimation.py +1 -2
- chia/full_node/fee_history.py +5 -6
- chia/full_node/fee_tracker.py +24 -24
- chia/full_node/full_node.py +574 -300
- chia/full_node/full_node_api.py +181 -130
- chia/full_node/full_node_store.py +43 -43
- chia/full_node/hint_management.py +4 -4
- chia/full_node/hint_store.py +9 -10
- chia/full_node/mempool.py +25 -19
- chia/full_node/mempool_check_conditions.py +11 -42
- chia/full_node/mempool_manager.py +48 -53
- chia/full_node/pending_tx_cache.py +9 -9
- chia/full_node/subscriptions.py +23 -24
- chia/full_node/sync_store.py +8 -7
- chia/full_node/tx_processing_queue.py +3 -3
- chia/full_node/util/__init__.py +0 -0
- chia/full_node/weight_proof.py +79 -78
- chia/harvester/harvester.py +9 -8
- chia/harvester/harvester_api.py +19 -13
- chia/introducer/introducer.py +7 -5
- chia/introducer/introducer_api.py +9 -3
- chia/legacy/keyring.py +6 -5
- chia/plot_sync/delta.py +8 -8
- chia/plot_sync/receiver.py +12 -11
- chia/plot_sync/sender.py +15 -12
- chia/plotters/bladebit.py +12 -12
- chia/plotters/chiapos.py +2 -2
- chia/plotters/madmax.py +8 -8
- chia/plotters/plotters.py +6 -6
- chia/plotters/plotters_util.py +6 -4
- chia/plotting/cache.py +8 -7
- chia/plotting/check_plots.py +8 -8
- chia/plotting/create_plots.py +6 -6
- chia/plotting/manager.py +22 -22
- chia/plotting/util.py +31 -19
- chia/pools/pool_config.py +7 -7
- chia/pools/pool_puzzles.py +16 -16
- chia/pools/pool_wallet.py +64 -57
- chia/pools/pool_wallet_info.py +3 -3
- chia/protocols/full_node_protocol.py +3 -3
- chia/protocols/harvester_protocol.py +12 -12
- chia/protocols/introducer_protocol.py +1 -2
- chia/protocols/protocol_message_types.py +4 -4
- chia/protocols/protocol_state_machine.py +2 -2
- chia/protocols/protocol_timing.py +1 -0
- chia/protocols/shared_protocol.py +3 -3
- chia/protocols/timelord_protocol.py +2 -2
- chia/protocols/wallet_protocol.py +33 -33
- chia/rpc/crawler_rpc_api.py +12 -7
- chia/rpc/data_layer_rpc_api.py +49 -44
- chia/rpc/data_layer_rpc_client.py +41 -41
- chia/rpc/data_layer_rpc_util.py +7 -11
- chia/rpc/farmer_rpc_api.py +32 -27
- chia/rpc/farmer_rpc_client.py +14 -14
- chia/rpc/full_node_rpc_api.py +53 -48
- chia/rpc/full_node_rpc_client.py +30 -30
- chia/rpc/harvester_rpc_api.py +16 -11
- chia/rpc/harvester_rpc_client.py +6 -6
- chia/rpc/rpc_client.py +34 -14
- chia/rpc/rpc_server.py +117 -43
- chia/rpc/timelord_rpc_api.py +9 -4
- chia/rpc/util.py +11 -211
- chia/rpc/wallet_request_types.py +276 -60
- chia/rpc/wallet_rpc_api.py +563 -399
- chia/rpc/wallet_rpc_client.py +220 -250
- chia/seeder/crawl_store.py +6 -8
- chia/seeder/crawler.py +23 -36
- chia/seeder/crawler_api.py +28 -22
- chia/seeder/dns_server.py +99 -50
- chia/seeder/start_crawler.py +13 -9
- chia/server/address_manager.py +19 -19
- chia/server/address_manager_store.py +17 -17
- chia/server/api_protocol.py +106 -1
- chia/server/capabilities.py +3 -3
- chia/server/chia_policy.py +17 -16
- chia/server/introducer_peers.py +3 -3
- chia/server/node_discovery.py +34 -38
- chia/server/rate_limit_numbers.py +26 -16
- chia/server/rate_limits.py +67 -27
- chia/server/server.py +52 -31
- chia/server/signal_handlers.py +6 -3
- chia/server/ssl_context.py +5 -5
- chia/server/start_data_layer.py +37 -23
- chia/server/start_farmer.py +28 -16
- chia/server/start_full_node.py +29 -23
- chia/server/start_harvester.py +28 -15
- chia/server/start_introducer.py +27 -15
- chia/server/start_service.py +17 -29
- chia/server/start_timelord.py +25 -18
- chia/server/start_wallet.py +22 -18
- chia/server/upnp.py +4 -3
- chia/server/ws_connection.py +68 -54
- chia/simulator/add_blocks_in_batches.py +54 -0
- chia/simulator/block_tools.py +65 -64
- chia/simulator/full_node_simulator.py +66 -74
- chia/simulator/setup_services.py +10 -9
- chia/simulator/simulator_full_node_rpc_api.py +12 -14
- chia/simulator/simulator_full_node_rpc_client.py +3 -5
- chia/simulator/simulator_test_tools.py +8 -7
- chia/simulator/socket.py +1 -4
- chia/simulator/ssl_certs.py +5 -5
- chia/simulator/ssl_certs_1.py +2 -4
- chia/simulator/ssl_certs_10.py +2 -4
- chia/simulator/ssl_certs_2.py +2 -4
- chia/simulator/ssl_certs_3.py +2 -4
- chia/simulator/ssl_certs_4.py +2 -4
- chia/simulator/ssl_certs_5.py +2 -4
- chia/simulator/ssl_certs_6.py +2 -4
- chia/simulator/ssl_certs_7.py +2 -4
- chia/simulator/ssl_certs_8.py +2 -4
- chia/simulator/ssl_certs_9.py +2 -4
- chia/simulator/start_simulator.py +14 -6
- chia/simulator/wallet_tools.py +21 -20
- chia/ssl/create_ssl.py +11 -11
- chia/timelord/iters_from_block.py +2 -2
- chia/timelord/timelord.py +57 -33
- chia/timelord/timelord_api.py +12 -6
- chia/timelord/timelord_launcher.py +10 -8
- chia/timelord/timelord_state.py +5 -5
- chia/types/block_protocol.py +2 -2
- chia/types/blockchain_format/coin.py +3 -3
- chia/types/blockchain_format/program.py +17 -18
- chia/types/blockchain_format/tree_hash.py +9 -9
- chia/types/coin_spend.py +8 -8
- chia/types/condition_with_args.py +1 -2
- chia/types/eligible_coin_spends.py +16 -15
- chia/types/generator_types.py +1 -2
- chia/types/internal_mempool_item.py +1 -2
- chia/types/mempool_item.py +7 -7
- chia/types/mempool_submission_status.py +2 -2
- chia/types/peer_info.py +1 -1
- chia/types/spend_bundle.py +1 -2
- chia/types/transaction_queue_entry.py +2 -2
- chia/types/unfinished_header_block.py +2 -2
- chia/types/validation_state.py +14 -0
- chia/types/weight_proof.py +5 -6
- chia/util/action_scope.py +8 -8
- chia/util/async_pool.py +6 -4
- chia/util/augmented_chain.py +13 -9
- chia/util/batches.py +5 -2
- chia/util/bech32m.py +14 -11
- chia/util/beta_metrics.py +5 -4
- chia/util/block_cache.py +5 -5
- chia/util/byte_types.py +2 -0
- chia/util/check_fork_next_block.py +3 -2
- chia/util/chia_logging.py +41 -21
- chia/util/collection.py +3 -3
- chia/util/condition_tools.py +18 -18
- chia/util/config.py +26 -25
- chia/util/cpu.py +2 -0
- chia/util/db_synchronous.py +2 -0
- chia/util/db_version.py +2 -0
- chia/util/db_wrapper.py +13 -10
- chia/util/default_root.py +17 -0
- chia/util/dump_keyring.py +6 -6
- chia/util/errors.py +5 -3
- chia/util/file_keyring.py +22 -33
- chia/util/files.py +2 -0
- chia/util/full_block_utils.py +31 -7
- chia/util/generator_tools.py +18 -8
- chia/util/hash.py +3 -1
- chia/util/initial-config.yaml +19 -0
- chia/util/inline_executor.py +2 -0
- chia/util/ip_address.py +39 -0
- chia/util/json_util.py +0 -4
- chia/util/keychain.py +27 -24
- chia/util/keyring_wrapper.py +65 -4
- chia/util/limited_semaphore.py +3 -1
- chia/util/lock.py +4 -2
- chia/util/log_exceptions.py +5 -2
- chia/util/logging.py +3 -1
- chia/util/lru_cache.py +2 -0
- chia/util/math.py +4 -4
- chia/util/network.py +15 -73
- chia/util/paginator.py +3 -1
- chia/util/path.py +2 -0
- chia/util/permissions.py +3 -2
- chia/util/prev_transaction_block.py +1 -3
- chia/util/priority_mutex.py +6 -3
- chia/util/profiler.py +7 -4
- chia/util/recursive_replace.py +2 -0
- chia/util/safe_cancel_task.py +2 -0
- chia/util/service_groups.py +2 -2
- chia/util/setproctitle.py +2 -0
- chia/util/significant_bits.py +2 -0
- chia/util/ssl_check.py +11 -11
- chia/util/streamable.py +44 -56
- chia/util/task_referencer.py +59 -0
- chia/util/task_timing.py +22 -18
- chia/util/timing.py +4 -1
- chia/util/vdf_prover.py +2 -3
- chia/util/virtual_project_analysis.py +540 -0
- chia/util/ws_message.py +6 -6
- chia/wallet/cat_wallet/cat_info.py +3 -3
- chia/wallet/cat_wallet/cat_outer_puzzle.py +3 -3
- chia/wallet/cat_wallet/cat_utils.py +5 -4
- chia/wallet/cat_wallet/cat_wallet.py +56 -70
- chia/wallet/cat_wallet/dao_cat_info.py +3 -3
- chia/wallet/cat_wallet/dao_cat_wallet.py +18 -18
- chia/wallet/cat_wallet/lineage_store.py +2 -2
- chia/wallet/coin_selection.py +15 -15
- chia/wallet/conditions.py +257 -71
- chia/wallet/dao_wallet/dao_info.py +4 -4
- chia/wallet/dao_wallet/dao_utils.py +43 -42
- chia/wallet/dao_wallet/dao_wallet.py +66 -68
- chia/wallet/db_wallet/db_wallet_puzzles.py +12 -8
- chia/wallet/derive_keys.py +11 -11
- chia/wallet/did_wallet/did_info.py +3 -3
- chia/wallet/did_wallet/did_wallet.py +56 -47
- chia/wallet/did_wallet/did_wallet_puzzles.py +7 -6
- chia/wallet/lineage_proof.py +4 -4
- chia/wallet/nft_wallet/metadata_outer_puzzle.py +2 -2
- chia/wallet/nft_wallet/nft_info.py +4 -4
- chia/wallet/nft_wallet/nft_puzzles.py +16 -16
- chia/wallet/nft_wallet/nft_wallet.py +90 -89
- chia/wallet/nft_wallet/ownership_outer_puzzle.py +2 -2
- chia/wallet/nft_wallet/singleton_outer_puzzle.py +2 -2
- chia/wallet/nft_wallet/transfer_program_puzzle.py +2 -2
- chia/wallet/nft_wallet/uncurry_nft.py +2 -2
- chia/wallet/notification_manager.py +5 -5
- chia/wallet/notification_store.py +6 -6
- chia/wallet/outer_puzzles.py +2 -2
- chia/wallet/payment.py +4 -5
- chia/wallet/puzzle_drivers.py +4 -4
- chia/wallet/puzzles/clawback/drivers.py +5 -5
- chia/wallet/puzzles/clawback/puzzle_decorator.py +7 -7
- chia/wallet/puzzles/load_clvm.py +2 -3
- chia/wallet/puzzles/p2_conditions.py +1 -2
- chia/wallet/puzzles/p2_delegated_conditions.py +1 -2
- chia/wallet/puzzles/p2_delegated_puzzle.py +2 -3
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +3 -4
- chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +1 -2
- chia/wallet/puzzles/p2_puzzle_hash.py +1 -2
- chia/wallet/puzzles/puzzle_utils.py +7 -7
- chia/wallet/puzzles/singleton_top_layer.py +6 -5
- chia/wallet/puzzles/singleton_top_layer_v1_1.py +6 -5
- chia/wallet/puzzles/tails.py +34 -30
- chia/wallet/signer_protocol.py +7 -8
- chia/wallet/singleton.py +4 -4
- chia/wallet/trade_manager.py +155 -141
- chia/wallet/trade_record.py +5 -5
- chia/wallet/trading/offer.py +100 -101
- chia/wallet/trading/trade_store.py +14 -14
- chia/wallet/transaction_record.py +31 -16
- chia/wallet/util/address_type.py +4 -4
- chia/wallet/util/blind_signer_tl.py +8 -12
- chia/wallet/util/clvm_streamable.py +15 -15
- chia/wallet/util/compute_hints.py +5 -5
- chia/wallet/util/compute_memos.py +4 -6
- chia/wallet/util/curry_and_treehash.py +3 -2
- chia/wallet/util/debug_spend_bundle.py +6 -8
- chia/wallet/util/merkle_tree.py +10 -10
- chia/wallet/util/merkle_utils.py +10 -10
- chia/wallet/util/new_peak_queue.py +3 -3
- chia/wallet/util/peer_request_cache.py +8 -8
- chia/{util → wallet/util}/pprint.py +2 -3
- chia/wallet/util/puzzle_compression.py +3 -4
- chia/wallet/util/puzzle_decorator.py +10 -10
- chia/wallet/util/query_filter.py +9 -10
- chia/wallet/util/tx_config.py +12 -12
- chia/wallet/util/wallet_sync_utils.py +24 -21
- chia/wallet/util/wallet_types.py +9 -2
- chia/wallet/vc_wallet/cr_cat_drivers.py +28 -27
- chia/wallet/vc_wallet/cr_cat_wallet.py +42 -40
- chia/wallet/vc_wallet/cr_outer_puzzle.py +4 -4
- chia/wallet/vc_wallet/vc_drivers.py +16 -16
- chia/wallet/vc_wallet/vc_store.py +9 -9
- chia/wallet/vc_wallet/vc_wallet.py +35 -35
- chia/wallet/wallet.py +54 -54
- chia/wallet/wallet_action_scope.py +14 -13
- chia/wallet/wallet_blockchain.py +10 -10
- chia/wallet/wallet_coin_record.py +2 -2
- chia/wallet/wallet_coin_store.py +10 -10
- chia/wallet/wallet_info.py +1 -2
- chia/wallet/wallet_interested_store.py +5 -5
- chia/wallet/wallet_nft_store.py +6 -6
- chia/wallet/wallet_node.py +72 -76
- chia/wallet/wallet_node_api.py +33 -27
- chia/wallet/wallet_pool_store.py +1 -2
- chia/wallet/wallet_protocol.py +15 -15
- chia/wallet/wallet_puzzle_store.py +35 -4
- chia/wallet/wallet_retry_store.py +2 -2
- chia/wallet/wallet_singleton_store.py +10 -9
- chia/wallet/wallet_spend_bundle.py +4 -20
- chia/wallet/wallet_state_manager.py +223 -224
- chia/wallet/wallet_transaction_store.py +44 -18
- chia/wallet/wallet_user_store.py +2 -2
- chia/wallet/wallet_weight_proof_handler.py +2 -2
- {chia_blockchain-2.5.0rc2.dist-info → chia_blockchain-2.5.1rc2.dist-info}/LICENSE +1 -1
- {chia_blockchain-2.5.0rc2.dist-info → chia_blockchain-2.5.1rc2.dist-info}/METADATA +67 -72
- chia_blockchain-2.5.1rc2.dist-info/RECORD +1042 -0
- {chia_blockchain-2.5.0rc2.dist-info → chia_blockchain-2.5.1rc2.dist-info}/WHEEL +1 -1
- mozilla-ca/cacert.pem +32 -87
- chia/_tests/cmds/wallet/test_coins.py +0 -195
- chia/consensus/block_root_validation.py +0 -46
- chia/util/api_decorators.py +0 -89
- chia_blockchain-2.5.0rc2.dist-info/RECORD +0 -1028
- {chia_blockchain-2.5.0rc2.dist-info → chia_blockchain-2.5.1rc2.dist-info}/entry_points.txt +0 -0
chia/rpc/wallet_rpc_api.py
CHANGED
|
@@ -5,9 +5,9 @@ import json
|
|
|
5
5
|
import logging
|
|
6
6
|
import zlib
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Optional, Union, cast
|
|
9
9
|
|
|
10
|
-
from chia_rs import AugSchemeMPL, G1Element, G2Element, PrivateKey
|
|
10
|
+
from chia_rs import AugSchemeMPL, Coin, G1Element, G2Element, PrivateKey
|
|
11
11
|
from clvm_tools.binutils import assemble
|
|
12
12
|
|
|
13
13
|
from chia.consensus.block_rewards import calculate_base_farmer_reward
|
|
@@ -18,7 +18,7 @@ from chia.pools.pool_wallet import PoolWallet
|
|
|
18
18
|
from chia.pools.pool_wallet_info import FARMING_TO_POOL, PoolState, PoolWalletInfo, create_pool_state
|
|
19
19
|
from chia.protocols.wallet_protocol import CoinState
|
|
20
20
|
from chia.rpc.rpc_server import Endpoint, EndpointResult, default_get_connections
|
|
21
|
-
from chia.rpc.util import
|
|
21
|
+
from chia.rpc.util import ALL_TRANSLATION_LAYERS, RpcEndpoint, marshal
|
|
22
22
|
from chia.rpc.wallet_request_types import (
|
|
23
23
|
AddKey,
|
|
24
24
|
AddKeyResponse,
|
|
@@ -35,6 +35,7 @@ from chia.rpc.wallet_request_types import (
|
|
|
35
35
|
GatherSigningInfo,
|
|
36
36
|
GatherSigningInfoResponse,
|
|
37
37
|
GenerateMnemonicResponse,
|
|
38
|
+
GetHeightInfoResponse,
|
|
38
39
|
GetLoggedInFingerprintResponse,
|
|
39
40
|
GetNotifications,
|
|
40
41
|
GetNotificationsResponse,
|
|
@@ -42,16 +43,39 @@ from chia.rpc.wallet_request_types import (
|
|
|
42
43
|
GetPrivateKeyFormat,
|
|
43
44
|
GetPrivateKeyResponse,
|
|
44
45
|
GetPublicKeysResponse,
|
|
46
|
+
GetSyncStatusResponse,
|
|
47
|
+
GetTimestampForHeight,
|
|
48
|
+
GetTimestampForHeightResponse,
|
|
45
49
|
LogIn,
|
|
46
50
|
LogInResponse,
|
|
51
|
+
PushTransactions,
|
|
52
|
+
PushTransactionsResponse,
|
|
53
|
+
PushTX,
|
|
54
|
+
SetWalletResyncOnStartup,
|
|
47
55
|
SplitCoins,
|
|
48
56
|
SplitCoinsResponse,
|
|
49
57
|
SubmitTransactions,
|
|
50
58
|
SubmitTransactionsResponse,
|
|
59
|
+
VCAddProofs,
|
|
60
|
+
VCGet,
|
|
61
|
+
VCGetList,
|
|
62
|
+
VCGetListResponse,
|
|
63
|
+
VCGetProofsForRoot,
|
|
64
|
+
VCGetProofsForRootResponse,
|
|
65
|
+
VCGetResponse,
|
|
66
|
+
VCMint,
|
|
67
|
+
VCMintResponse,
|
|
68
|
+
VCProofsRPC,
|
|
69
|
+
VCProofWithHash,
|
|
70
|
+
VCRecordWithCoinID,
|
|
71
|
+
VCRevoke,
|
|
72
|
+
VCRevokeResponse,
|
|
73
|
+
VCSpend,
|
|
74
|
+
VCSpendResponse,
|
|
51
75
|
)
|
|
52
76
|
from chia.server.outbound_message import NodeType
|
|
53
77
|
from chia.server.ws_connection import WSChiaConnection
|
|
54
|
-
from chia.types.blockchain_format.coin import
|
|
78
|
+
from chia.types.blockchain_format.coin import coin_as_list
|
|
55
79
|
from chia.types.blockchain_format.program import INFINITE_COST, Program
|
|
56
80
|
from chia.types.blockchain_format.sized_bytes import bytes32
|
|
57
81
|
from chia.types.coin_record import CoinRecord
|
|
@@ -76,9 +100,12 @@ from chia.wallet.conditions import (
|
|
|
76
100
|
AssertCoinAnnouncement,
|
|
77
101
|
AssertPuzzleAnnouncement,
|
|
78
102
|
Condition,
|
|
103
|
+
ConditionValidTimes,
|
|
79
104
|
CreateCoinAnnouncement,
|
|
80
105
|
CreatePuzzleAnnouncement,
|
|
106
|
+
conditions_from_json_dicts,
|
|
81
107
|
parse_conditions_non_consensus,
|
|
108
|
+
parse_timelock_info,
|
|
82
109
|
)
|
|
83
110
|
from chia.wallet.dao_wallet.dao_info import DAORules
|
|
84
111
|
from chia.wallet.dao_wallet.dao_utils import (
|
|
@@ -127,6 +154,7 @@ from chia.wallet.trading.offer import Offer
|
|
|
127
154
|
from chia.wallet.transaction_record import TransactionRecord
|
|
128
155
|
from chia.wallet.uncurried_puzzle import uncurry_puzzle
|
|
129
156
|
from chia.wallet.util.address_type import AddressType, is_valid_address
|
|
157
|
+
from chia.wallet.util.clvm_streamable import json_serialize_with_clvm_streamable
|
|
130
158
|
from chia.wallet.util.compute_hints import compute_spend_hints_and_additions
|
|
131
159
|
from chia.wallet.util.compute_memos import compute_memos
|
|
132
160
|
from chia.wallet.util.curry_and_treehash import NIL_TREEHASH
|
|
@@ -156,7 +184,200 @@ MAX_NFT_CHUNK_SIZE = 25
|
|
|
156
184
|
log = logging.getLogger(__name__)
|
|
157
185
|
|
|
158
186
|
|
|
187
|
+
def tx_endpoint(
|
|
188
|
+
push: bool = False,
|
|
189
|
+
merge_spends: bool = True,
|
|
190
|
+
) -> Callable[[RpcEndpoint], RpcEndpoint]:
|
|
191
|
+
def _inner(func: RpcEndpoint) -> RpcEndpoint:
|
|
192
|
+
async def rpc_endpoint(
|
|
193
|
+
self: WalletRpcApi, request: dict[str, Any], *args: object, **kwargs: object
|
|
194
|
+
) -> EndpointResult:
|
|
195
|
+
assert self.service.logged_in_fingerprint is not None
|
|
196
|
+
tx_config_loader: TXConfigLoader = TXConfigLoader.from_json_dict(request)
|
|
197
|
+
|
|
198
|
+
# Some backwards compat fill-ins
|
|
199
|
+
if tx_config_loader.excluded_coin_ids is None:
|
|
200
|
+
tx_config_loader = tx_config_loader.override(
|
|
201
|
+
excluded_coin_ids=request.get("exclude_coin_ids"),
|
|
202
|
+
)
|
|
203
|
+
if tx_config_loader.excluded_coin_amounts is None:
|
|
204
|
+
tx_config_loader = tx_config_loader.override(
|
|
205
|
+
excluded_coin_amounts=request.get("exclude_coin_amounts"),
|
|
206
|
+
)
|
|
207
|
+
if tx_config_loader.excluded_coin_ids is None:
|
|
208
|
+
excluded_coins: Optional[list[dict[str, Any]]] = request.get(
|
|
209
|
+
"exclude_coins", request.get("excluded_coins")
|
|
210
|
+
)
|
|
211
|
+
if excluded_coins is not None:
|
|
212
|
+
tx_config_loader = tx_config_loader.override(
|
|
213
|
+
excluded_coin_ids=[Coin.from_json_dict(c).name() for c in excluded_coins],
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
tx_config: TXConfig = tx_config_loader.autofill(
|
|
217
|
+
constants=self.service.wallet_state_manager.constants,
|
|
218
|
+
config=self.service.wallet_state_manager.config,
|
|
219
|
+
logged_in_fingerprint=self.service.logged_in_fingerprint,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
extra_conditions: tuple[Condition, ...] = tuple()
|
|
223
|
+
if "extra_conditions" in request:
|
|
224
|
+
extra_conditions = tuple(conditions_from_json_dicts(request["extra_conditions"]))
|
|
225
|
+
extra_conditions = (*extra_conditions, *ConditionValidTimes.from_json_dict(request).to_conditions())
|
|
226
|
+
|
|
227
|
+
valid_times: ConditionValidTimes = parse_timelock_info(extra_conditions)
|
|
228
|
+
if (
|
|
229
|
+
valid_times.max_secs_after_created is not None
|
|
230
|
+
or valid_times.min_secs_since_created is not None
|
|
231
|
+
or valid_times.max_blocks_after_created is not None
|
|
232
|
+
or valid_times.min_blocks_since_created is not None
|
|
233
|
+
):
|
|
234
|
+
raise ValueError("Relative timelocks are not currently supported in the RPC")
|
|
235
|
+
|
|
236
|
+
async with self.service.wallet_state_manager.new_action_scope(
|
|
237
|
+
tx_config,
|
|
238
|
+
push=request.get("push", push),
|
|
239
|
+
merge_spends=request.get("merge_spends", merge_spends),
|
|
240
|
+
sign=request.get("sign", self.service.config.get("auto_sign_txs", True)),
|
|
241
|
+
) as action_scope:
|
|
242
|
+
response: EndpointResult = await func(
|
|
243
|
+
self,
|
|
244
|
+
request,
|
|
245
|
+
*args,
|
|
246
|
+
action_scope,
|
|
247
|
+
extra_conditions=extra_conditions,
|
|
248
|
+
**kwargs,
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
if func.__name__ == "create_new_wallet" and "transactions" not in response:
|
|
252
|
+
# unfortunately, this API isn't solely a tx endpoint
|
|
253
|
+
return response
|
|
254
|
+
|
|
255
|
+
unsigned_txs = await self.service.wallet_state_manager.gather_signing_info_for_txs(
|
|
256
|
+
action_scope.side_effects.transactions
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
if request.get("CHIP-0029", False):
|
|
260
|
+
response["unsigned_transactions"] = [
|
|
261
|
+
json_serialize_with_clvm_streamable(
|
|
262
|
+
tx,
|
|
263
|
+
translation_layer=(
|
|
264
|
+
ALL_TRANSLATION_LAYERS[request["translation"]] if "translation" in request else None
|
|
265
|
+
),
|
|
266
|
+
)
|
|
267
|
+
for tx in unsigned_txs
|
|
268
|
+
]
|
|
269
|
+
else:
|
|
270
|
+
response["unsigned_transactions"] = [tx.to_json_dict() for tx in unsigned_txs]
|
|
271
|
+
|
|
272
|
+
response["transactions"] = [
|
|
273
|
+
TransactionRecord.to_json_dict_convenience(tx, self.service.config)
|
|
274
|
+
for tx in action_scope.side_effects.transactions
|
|
275
|
+
]
|
|
276
|
+
|
|
277
|
+
# Some backwards compatibility code here because transaction information being returned was not uniform
|
|
278
|
+
# until the "transactions" key was applied to all of them. Unfortunately, since .add_pending_transactions
|
|
279
|
+
# now applies transformations to the transactions, we have to special case edit all of the previous
|
|
280
|
+
# spots where the information was being surfaced outside of the knowledge of this wrapper.
|
|
281
|
+
new_txs = action_scope.side_effects.transactions
|
|
282
|
+
if "transaction" in response:
|
|
283
|
+
if (
|
|
284
|
+
func.__name__ == "create_new_wallet" and request["wallet_type"] == "pool_wallet"
|
|
285
|
+
) or func.__name__ in {"pw_join_pool", "pw_self_pool", "pw_absorb_rewards"}:
|
|
286
|
+
# Theses RPCs return not "convenience" for some reason
|
|
287
|
+
response["transaction"] = new_txs[-1].to_json_dict()
|
|
288
|
+
else:
|
|
289
|
+
response["transaction"] = response["transactions"][0]
|
|
290
|
+
if "tx_record" in response:
|
|
291
|
+
response["tx_record"] = response["transactions"][0]
|
|
292
|
+
if "fee_transaction" in response:
|
|
293
|
+
# Theses RPCs return not "convenience" for some reason
|
|
294
|
+
fee_transactions = [tx for tx in new_txs if tx.wallet_id == 1]
|
|
295
|
+
if len(fee_transactions) == 0:
|
|
296
|
+
response["fee_transaction"] = None
|
|
297
|
+
else:
|
|
298
|
+
response["fee_transaction"] = fee_transactions[0].to_json_dict()
|
|
299
|
+
if "transaction_id" in response:
|
|
300
|
+
response["transaction_id"] = new_txs[0].name
|
|
301
|
+
if "transaction_ids" in response:
|
|
302
|
+
response["transaction_ids"] = [
|
|
303
|
+
tx.name.hex() for tx in new_txs if tx.type == TransactionType.OUTGOING_CLAWBACK.value
|
|
304
|
+
]
|
|
305
|
+
if "spend_bundle" in response:
|
|
306
|
+
response["spend_bundle"] = WalletSpendBundle.aggregate(
|
|
307
|
+
[tx.spend_bundle for tx in new_txs if tx.spend_bundle is not None]
|
|
308
|
+
)
|
|
309
|
+
if "signed_txs" in response:
|
|
310
|
+
response["signed_txs"] = response["transactions"]
|
|
311
|
+
if "signed_tx" in response:
|
|
312
|
+
response["signed_tx"] = response["transactions"][0]
|
|
313
|
+
if "tx" in response:
|
|
314
|
+
if func.__name__ == "send_notification":
|
|
315
|
+
response["tx"] = response["transactions"][0]
|
|
316
|
+
else:
|
|
317
|
+
response["tx"] = new_txs[0].to_json_dict()
|
|
318
|
+
if "txs" in response:
|
|
319
|
+
response["txs"] = [tx.to_json_dict() for tx in new_txs]
|
|
320
|
+
if "tx_id" in response:
|
|
321
|
+
response["tx_id"] = new_txs[0].name
|
|
322
|
+
if "trade_record" in response:
|
|
323
|
+
old_offer: Offer = Offer.from_bech32(response["offer"])
|
|
324
|
+
signed_coin_spends: list[CoinSpend] = [
|
|
325
|
+
coin_spend
|
|
326
|
+
for tx in new_txs
|
|
327
|
+
if tx.spend_bundle is not None
|
|
328
|
+
for coin_spend in tx.spend_bundle.coin_spends
|
|
329
|
+
]
|
|
330
|
+
involved_coins: list[Coin] = [spend.coin for spend in signed_coin_spends]
|
|
331
|
+
signed_coin_spends.extend(
|
|
332
|
+
[spend for spend in old_offer._bundle.coin_spends if spend.coin not in involved_coins]
|
|
333
|
+
)
|
|
334
|
+
new_offer_bundle = WalletSpendBundle(
|
|
335
|
+
signed_coin_spends,
|
|
336
|
+
AugSchemeMPL.aggregate(
|
|
337
|
+
[tx.spend_bundle.aggregated_signature for tx in new_txs if tx.spend_bundle is not None]
|
|
338
|
+
),
|
|
339
|
+
)
|
|
340
|
+
new_offer: Offer = Offer(old_offer.requested_payments, new_offer_bundle, old_offer.driver_dict)
|
|
341
|
+
response["offer"] = new_offer.to_bech32()
|
|
342
|
+
old_trade_record: TradeRecord = TradeRecord.from_json_dict_convenience(
|
|
343
|
+
response["trade_record"], bytes(old_offer).hex()
|
|
344
|
+
)
|
|
345
|
+
new_trade: TradeRecord = dataclasses.replace(
|
|
346
|
+
old_trade_record,
|
|
347
|
+
offer=bytes(new_offer),
|
|
348
|
+
trade_id=new_offer.name(),
|
|
349
|
+
)
|
|
350
|
+
response["trade_record"] = new_trade.to_json_dict_convenience()
|
|
351
|
+
if (
|
|
352
|
+
await self.service.wallet_state_manager.trade_manager.trade_store.get_trade_record(
|
|
353
|
+
old_trade_record.trade_id
|
|
354
|
+
)
|
|
355
|
+
is not None
|
|
356
|
+
):
|
|
357
|
+
await self.service.wallet_state_manager.trade_manager.trade_store.delete_trade_record(
|
|
358
|
+
old_trade_record.trade_id
|
|
359
|
+
)
|
|
360
|
+
await self.service.wallet_state_manager.trade_manager.save_trade(new_trade, new_offer)
|
|
361
|
+
for tx in await self.service.wallet_state_manager.tx_store.get_transactions_by_trade_id(
|
|
362
|
+
old_trade_record.trade_id
|
|
363
|
+
):
|
|
364
|
+
await self.service.wallet_state_manager.tx_store.add_transaction_record(
|
|
365
|
+
dataclasses.replace(tx, trade_id=new_trade.trade_id)
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
return response
|
|
369
|
+
|
|
370
|
+
return rpc_endpoint
|
|
371
|
+
|
|
372
|
+
return _inner
|
|
373
|
+
|
|
374
|
+
|
|
159
375
|
class WalletRpcApi:
|
|
376
|
+
if TYPE_CHECKING:
|
|
377
|
+
from chia.rpc.rpc_server import RpcApiProtocol
|
|
378
|
+
|
|
379
|
+
_protocol_check: ClassVar[RpcApiProtocol] = cast("WalletRpcApi", None)
|
|
380
|
+
|
|
160
381
|
max_get_coin_records_limit: ClassVar[uint32] = uint32(1000)
|
|
161
382
|
max_get_coin_records_filter_items: ClassVar[uint32] = uint32(1000)
|
|
162
383
|
|
|
@@ -165,7 +386,7 @@ class WalletRpcApi:
|
|
|
165
386
|
self.service = wallet_node
|
|
166
387
|
self.service_name = "chia_wallet"
|
|
167
388
|
|
|
168
|
-
def get_routes(self) ->
|
|
389
|
+
def get_routes(self) -> dict[str, Endpoint]:
|
|
169
390
|
return {
|
|
170
391
|
# Key management
|
|
171
392
|
"/log_in": self.log_in,
|
|
@@ -320,10 +541,10 @@ class WalletRpcApi:
|
|
|
320
541
|
"/execute_signing_instructions": self.execute_signing_instructions,
|
|
321
542
|
}
|
|
322
543
|
|
|
323
|
-
def get_connections(self, request_node_type: Optional[NodeType]) ->
|
|
544
|
+
def get_connections(self, request_node_type: Optional[NodeType]) -> list[dict[str, Any]]:
|
|
324
545
|
return default_get_connections(server=self.service.server, request_node_type=request_node_type)
|
|
325
546
|
|
|
326
|
-
async def _state_changed(self, change: str, change_data: Optional[
|
|
547
|
+
async def _state_changed(self, change: str, change_data: Optional[dict[str, Any]]) -> list[WsRpcMessage]:
|
|
327
548
|
"""
|
|
328
549
|
Called by the WalletNode or WalletStateManager when something has changed in the wallet. This
|
|
329
550
|
gives us an opportunity to send notifications to all connected clients via WebSocket.
|
|
@@ -356,8 +577,8 @@ class WalletRpcApi:
|
|
|
356
577
|
|
|
357
578
|
async def get_latest_singleton_coin_spend(
|
|
358
579
|
self, peer: WSChiaConnection, coin_id: bytes32, latest: bool = True
|
|
359
|
-
) ->
|
|
360
|
-
coin_state_list:
|
|
580
|
+
) -> tuple[CoinSpend, CoinState]:
|
|
581
|
+
coin_state_list: list[CoinState] = await self.service.wallet_state_manager.wallet_node.get_coin_state(
|
|
361
582
|
[coin_id], peer=peer
|
|
362
583
|
)
|
|
363
584
|
if coin_state_list is None or len(coin_state_list) < 1:
|
|
@@ -379,7 +600,7 @@ class WalletRpcApi:
|
|
|
379
600
|
raise ValueError("Cannot find child coin, please wait then retry.")
|
|
380
601
|
coin_state = odd_coin
|
|
381
602
|
# Get parent coin
|
|
382
|
-
parent_coin_state_list:
|
|
603
|
+
parent_coin_state_list: list[CoinState] = await self.service.wallet_state_manager.wallet_node.get_coin_state(
|
|
383
604
|
[coin_state.coin.parent_coin_info], peer=peer
|
|
384
605
|
)
|
|
385
606
|
if parent_coin_state_list is None or len(parent_coin_state_list) < 1:
|
|
@@ -429,7 +650,7 @@ class WalletRpcApi:
|
|
|
429
650
|
else:
|
|
430
651
|
return GetPublicKeysResponse(keyring_is_locked=False, public_key_fingerprints=fingerprints)
|
|
431
652
|
|
|
432
|
-
async def _get_private_key(self, fingerprint: int) ->
|
|
653
|
+
async def _get_private_key(self, fingerprint: int) -> tuple[Optional[PrivateKey], Optional[bytes]]:
|
|
433
654
|
try:
|
|
434
655
|
all_keys = await self.service.keychain_proxy.get_all_private_keys()
|
|
435
656
|
for sk, seed in all_keys:
|
|
@@ -501,7 +722,7 @@ class WalletRpcApi:
|
|
|
501
722
|
|
|
502
723
|
async def _check_key_used_for_rewards(
|
|
503
724
|
self, new_root: Path, sk: PrivateKey, max_ph_to_search: int
|
|
504
|
-
) ->
|
|
725
|
+
) -> tuple[bool, bool]:
|
|
505
726
|
"""Checks if the given key is used for either the farmer rewards or pool rewards
|
|
506
727
|
returns a tuple of two booleans
|
|
507
728
|
The first is true if the key is used as the Farmer rewards, otherwise false
|
|
@@ -511,10 +732,10 @@ class WalletRpcApi:
|
|
|
511
732
|
if sk is None:
|
|
512
733
|
return False, False
|
|
513
734
|
|
|
514
|
-
config:
|
|
735
|
+
config: dict[str, Any] = load_config(new_root, "config.yaml")
|
|
515
736
|
farmer_target = config["farmer"].get("xch_target_address", "")
|
|
516
737
|
pool_target = config["pool"].get("xch_target_address", "")
|
|
517
|
-
address_to_check:
|
|
738
|
+
address_to_check: list[bytes32] = []
|
|
518
739
|
|
|
519
740
|
try:
|
|
520
741
|
farmer_decoded = decode_puzzle_hash(farmer_target)
|
|
@@ -528,7 +749,7 @@ class WalletRpcApi:
|
|
|
528
749
|
except ValueError:
|
|
529
750
|
pool_decoded = None
|
|
530
751
|
|
|
531
|
-
found_addresses:
|
|
752
|
+
found_addresses: set[bytes32] = match_address_to_sk(sk, address_to_check, max_ph_to_search)
|
|
532
753
|
found_farmer = False
|
|
533
754
|
found_pool = False
|
|
534
755
|
|
|
@@ -560,7 +781,7 @@ class WalletRpcApi:
|
|
|
560
781
|
await self._stop_wallet()
|
|
561
782
|
await self.service._start_with_fingerprint(fingerprint=request.fingerprint)
|
|
562
783
|
|
|
563
|
-
wallets:
|
|
784
|
+
wallets: list[WalletInfo] = await self.service.wallet_state_manager.get_all_wallet_info_entries()
|
|
564
785
|
for w in wallets:
|
|
565
786
|
wallet = self.service.wallet_state_manager.wallets[w.id]
|
|
566
787
|
unspent = await self.service.wallet_state_manager.coin_store.get_unspent_coins_for_wallet(w.id)
|
|
@@ -594,64 +815,55 @@ class WalletRpcApi:
|
|
|
594
815
|
##########################################################################################
|
|
595
816
|
# Wallet Node
|
|
596
817
|
##########################################################################################
|
|
597
|
-
|
|
818
|
+
@marshal
|
|
819
|
+
async def set_wallet_resync_on_startup(self, request: SetWalletResyncOnStartup) -> Empty:
|
|
598
820
|
"""
|
|
599
821
|
Resync the current logged in wallet. The transaction and offer records will be kept.
|
|
600
822
|
:param request: optionally pass in `enable` as bool to enable/disable resync
|
|
601
823
|
:return:
|
|
602
824
|
"""
|
|
603
825
|
assert self.service.wallet_state_manager is not None
|
|
604
|
-
try:
|
|
605
|
-
enable = bool(request.get("enable", True))
|
|
606
|
-
except ValueError:
|
|
607
|
-
raise ValueError("Please provide a boolean value for `enable` parameter in request")
|
|
608
826
|
fingerprint = self.service.logged_in_fingerprint
|
|
609
827
|
if fingerprint is not None:
|
|
610
|
-
self.service.set_resync_on_startup(fingerprint, enable)
|
|
828
|
+
self.service.set_resync_on_startup(fingerprint, request.enable)
|
|
611
829
|
else:
|
|
612
830
|
raise ValueError("You need to login into wallet to use this RPC call")
|
|
613
|
-
return
|
|
831
|
+
return Empty()
|
|
614
832
|
|
|
615
|
-
|
|
833
|
+
@marshal
|
|
834
|
+
async def get_sync_status(self, request: Empty) -> GetSyncStatusResponse:
|
|
616
835
|
sync_mode = self.service.wallet_state_manager.sync_mode
|
|
617
836
|
has_pending_queue_items = self.service.new_peak_queue.has_pending_data_process_items()
|
|
618
837
|
syncing = sync_mode or has_pending_queue_items
|
|
619
838
|
synced = await self.service.wallet_state_manager.synced()
|
|
620
|
-
return
|
|
839
|
+
return GetSyncStatusResponse(synced=synced, syncing=syncing)
|
|
621
840
|
|
|
622
|
-
|
|
841
|
+
@marshal
|
|
842
|
+
async def get_height_info(self, request: Empty) -> GetHeightInfoResponse:
|
|
623
843
|
height = await self.service.wallet_state_manager.blockchain.get_finished_sync_up_to()
|
|
624
|
-
return
|
|
844
|
+
return GetHeightInfoResponse(height=height)
|
|
625
845
|
|
|
626
|
-
|
|
846
|
+
@marshal
|
|
847
|
+
async def push_tx(self, request: PushTX) -> Empty:
|
|
627
848
|
nodes = self.service.server.get_connections(NodeType.FULL_NODE)
|
|
628
849
|
if len(nodes) == 0:
|
|
629
850
|
raise ValueError("Wallet is not currently connected to any full node peers")
|
|
630
|
-
await self.service.push_tx(
|
|
631
|
-
return
|
|
851
|
+
await self.service.push_tx(request.spend_bundle)
|
|
852
|
+
return Empty()
|
|
632
853
|
|
|
633
854
|
@tx_endpoint(push=True)
|
|
855
|
+
@marshal
|
|
634
856
|
async def push_transactions(
|
|
635
857
|
self,
|
|
636
|
-
request:
|
|
858
|
+
request: PushTransactions,
|
|
637
859
|
action_scope: WalletActionScope,
|
|
638
|
-
extra_conditions:
|
|
639
|
-
) ->
|
|
860
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
861
|
+
) -> PushTransactionsResponse:
|
|
640
862
|
if not action_scope.config.push:
|
|
641
863
|
raise ValueError("Cannot push transactions if push is False")
|
|
642
864
|
async with action_scope.use() as interface:
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
tx = TransactionRecord.from_bytes(hexstr_to_bytes(transaction_hexstr_or_json))
|
|
646
|
-
interface.side_effects.transactions.append(tx)
|
|
647
|
-
else:
|
|
648
|
-
try:
|
|
649
|
-
tx = TransactionRecord.from_json_dict_convenience(transaction_hexstr_or_json)
|
|
650
|
-
except AttributeError:
|
|
651
|
-
tx = TransactionRecord.from_json_dict(transaction_hexstr_or_json)
|
|
652
|
-
interface.side_effects.transactions.append(tx)
|
|
653
|
-
|
|
654
|
-
if request.get("fee", 0) != 0:
|
|
865
|
+
interface.side_effects.transactions.extend(request.transactions)
|
|
866
|
+
if request.fee != 0:
|
|
655
867
|
all_conditions_and_origins = [
|
|
656
868
|
(condition, cs.coin.name())
|
|
657
869
|
for tx in interface.side_effects.transactions
|
|
@@ -682,7 +894,7 @@ class WalletRpcApi:
|
|
|
682
894
|
push=False,
|
|
683
895
|
) as inner_action_scope:
|
|
684
896
|
await self.service.wallet_state_manager.main_wallet.create_tandem_xch_tx(
|
|
685
|
-
|
|
897
|
+
request.fee,
|
|
686
898
|
inner_action_scope,
|
|
687
899
|
(
|
|
688
900
|
*extra_conditions,
|
|
@@ -694,20 +906,23 @@ class WalletRpcApi:
|
|
|
694
906
|
|
|
695
907
|
interface.side_effects.transactions.extend(inner_action_scope.side_effects.transactions)
|
|
696
908
|
|
|
697
|
-
return
|
|
909
|
+
return PushTransactionsResponse([], []) # tx_endpoint takes care of this
|
|
698
910
|
|
|
699
|
-
|
|
700
|
-
|
|
911
|
+
@marshal
|
|
912
|
+
async def get_timestamp_for_height(self, request: GetTimestampForHeight) -> GetTimestampForHeightResponse:
|
|
913
|
+
return GetTimestampForHeightResponse(await self.service.get_timestamp_for_height(request.height))
|
|
701
914
|
|
|
702
|
-
|
|
915
|
+
@marshal
|
|
916
|
+
async def set_auto_claim(self, request: AutoClaimSettings) -> AutoClaimSettings:
|
|
703
917
|
"""
|
|
704
918
|
Set auto claim merkle coins config
|
|
705
919
|
:param request: Example {"enable": true, "tx_fee": 100000, "min_amount": 0, "batch_size": 50}
|
|
706
920
|
:return:
|
|
707
921
|
"""
|
|
708
|
-
return self.service.set_auto_claim(
|
|
922
|
+
return AutoClaimSettings.from_json_dict(self.service.set_auto_claim(request))
|
|
709
923
|
|
|
710
|
-
|
|
924
|
+
@marshal
|
|
925
|
+
async def get_auto_claim(self, request: Empty) -> AutoClaimSettings:
|
|
711
926
|
"""
|
|
712
927
|
Get auto claim merkle coins config
|
|
713
928
|
:param request: None
|
|
@@ -716,21 +931,21 @@ class WalletRpcApi:
|
|
|
716
931
|
auto_claim_settings = AutoClaimSettings.from_json_dict(
|
|
717
932
|
self.service.wallet_state_manager.config.get("auto_claim", {})
|
|
718
933
|
)
|
|
719
|
-
return auto_claim_settings
|
|
934
|
+
return auto_claim_settings
|
|
720
935
|
|
|
721
936
|
##########################################################################################
|
|
722
937
|
# Wallet Management
|
|
723
938
|
##########################################################################################
|
|
724
939
|
|
|
725
|
-
async def get_wallets(self, request:
|
|
940
|
+
async def get_wallets(self, request: dict[str, Any]) -> EndpointResult:
|
|
726
941
|
include_data: bool = request.get("include_data", True)
|
|
727
942
|
wallet_type: Optional[WalletType] = None
|
|
728
943
|
if "type" in request:
|
|
729
944
|
wallet_type = WalletType(request["type"])
|
|
730
945
|
|
|
731
|
-
wallets:
|
|
946
|
+
wallets: list[WalletInfo] = await self.service.wallet_state_manager.get_all_wallet_info_entries(wallet_type)
|
|
732
947
|
if not include_data:
|
|
733
|
-
result:
|
|
948
|
+
result: list[WalletInfo] = []
|
|
734
949
|
for wallet in wallets:
|
|
735
950
|
result.append(WalletInfo(wallet.id, wallet.name, wallet.type, ""))
|
|
736
951
|
wallets = result
|
|
@@ -759,9 +974,9 @@ class WalletRpcApi:
|
|
|
759
974
|
@tx_endpoint(push=True)
|
|
760
975
|
async def create_new_wallet(
|
|
761
976
|
self,
|
|
762
|
-
request:
|
|
977
|
+
request: dict[str, Any],
|
|
763
978
|
action_scope: WalletActionScope,
|
|
764
|
-
extra_conditions:
|
|
979
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
765
980
|
) -> EndpointResult:
|
|
766
981
|
wallet_state_manager = self.service.wallet_state_manager
|
|
767
982
|
|
|
@@ -819,7 +1034,7 @@ class WalletRpcApi:
|
|
|
819
1034
|
backup_dids.append(decode_puzzle_hash(d))
|
|
820
1035
|
if len(backup_dids) > 0:
|
|
821
1036
|
num_needed = uint64(request["num_of_backup_ids_needed"])
|
|
822
|
-
metadata:
|
|
1037
|
+
metadata: dict[str, str] = {}
|
|
823
1038
|
if "metadata" in request:
|
|
824
1039
|
if type(request["metadata"]) is dict:
|
|
825
1040
|
metadata = request["metadata"]
|
|
@@ -959,7 +1174,9 @@ class WalletRpcApi:
|
|
|
959
1174
|
if "initial_target_state" not in request:
|
|
960
1175
|
raise AttributeError("Daemon didn't send `initial_target_state`. Try updating the daemon.")
|
|
961
1176
|
|
|
962
|
-
owner_puzzle_hash: bytes32 = await self.service.wallet_state_manager.main_wallet.get_puzzle_hash(
|
|
1177
|
+
owner_puzzle_hash: bytes32 = await self.service.wallet_state_manager.main_wallet.get_puzzle_hash(
|
|
1178
|
+
new=not action_scope.config.tx_config.reuse_puzhash
|
|
1179
|
+
)
|
|
963
1180
|
|
|
964
1181
|
from chia.pools.pool_wallet_info import initial_pool_state_from_dict
|
|
965
1182
|
|
|
@@ -1027,7 +1244,7 @@ class WalletRpcApi:
|
|
|
1027
1244
|
# Wallet
|
|
1028
1245
|
##########################################################################################
|
|
1029
1246
|
|
|
1030
|
-
async def _get_wallet_balance(self, wallet_id: uint32) ->
|
|
1247
|
+
async def _get_wallet_balance(self, wallet_id: uint32) -> dict[str, Any]:
|
|
1031
1248
|
wallet = self.service.wallet_state_manager.wallets[wallet_id]
|
|
1032
1249
|
balance = await self.service.get_balance(wallet_id)
|
|
1033
1250
|
wallet_balance = balance.to_json_dict()
|
|
@@ -1044,22 +1261,22 @@ class WalletRpcApi:
|
|
|
1044
1261
|
|
|
1045
1262
|
return wallet_balance
|
|
1046
1263
|
|
|
1047
|
-
async def get_wallet_balance(self, request:
|
|
1264
|
+
async def get_wallet_balance(self, request: dict[str, Any]) -> EndpointResult:
|
|
1048
1265
|
wallet_id = uint32(int(request["wallet_id"]))
|
|
1049
1266
|
wallet_balance = await self._get_wallet_balance(wallet_id)
|
|
1050
1267
|
return {"wallet_balance": wallet_balance}
|
|
1051
1268
|
|
|
1052
|
-
async def get_wallet_balances(self, request:
|
|
1269
|
+
async def get_wallet_balances(self, request: dict[str, Any]) -> EndpointResult:
|
|
1053
1270
|
try:
|
|
1054
|
-
wallet_ids:
|
|
1271
|
+
wallet_ids: list[uint32] = [uint32(int(wallet_id)) for wallet_id in request["wallet_ids"]]
|
|
1055
1272
|
except (TypeError, KeyError):
|
|
1056
1273
|
wallet_ids = list(self.service.wallet_state_manager.wallets.keys())
|
|
1057
|
-
wallet_balances:
|
|
1274
|
+
wallet_balances: dict[uint32, dict[str, Any]] = {}
|
|
1058
1275
|
for wallet_id in wallet_ids:
|
|
1059
1276
|
wallet_balances[wallet_id] = await self._get_wallet_balance(wallet_id)
|
|
1060
1277
|
return {"wallet_balances": wallet_balances}
|
|
1061
1278
|
|
|
1062
|
-
async def get_transaction(self, request:
|
|
1279
|
+
async def get_transaction(self, request: dict[str, Any]) -> EndpointResult:
|
|
1063
1280
|
transaction_id: bytes32 = bytes32.from_hexstr(request["transaction_id"])
|
|
1064
1281
|
tr: Optional[TransactionRecord] = await self.service.wallet_state_manager.get_transaction(transaction_id)
|
|
1065
1282
|
if tr is None:
|
|
@@ -1070,7 +1287,7 @@ class WalletRpcApi:
|
|
|
1070
1287
|
"transaction_id": tr.name,
|
|
1071
1288
|
}
|
|
1072
1289
|
|
|
1073
|
-
async def get_transaction_memo(self, request:
|
|
1290
|
+
async def get_transaction_memo(self, request: dict[str, Any]) -> EndpointResult:
|
|
1074
1291
|
transaction_id: bytes32 = bytes32.from_hexstr(request["transaction_id"])
|
|
1075
1292
|
tr: Optional[TransactionRecord] = await self.service.wallet_state_manager.get_transaction(transaction_id)
|
|
1076
1293
|
if tr is None:
|
|
@@ -1080,7 +1297,7 @@ class WalletRpcApi:
|
|
|
1080
1297
|
# Fetch incoming tx coin spend
|
|
1081
1298
|
peer = self.service.get_full_node_peer()
|
|
1082
1299
|
assert len(tr.additions) == 1
|
|
1083
|
-
coin_state_list:
|
|
1300
|
+
coin_state_list: list[CoinState] = await self.service.wallet_state_manager.wallet_node.get_coin_state(
|
|
1084
1301
|
[tr.additions[0].parent_coin_info], peer=peer
|
|
1085
1302
|
)
|
|
1086
1303
|
assert len(coin_state_list) == 1
|
|
@@ -1089,7 +1306,7 @@ class WalletRpcApi:
|
|
|
1089
1306
|
else:
|
|
1090
1307
|
raise ValueError(f"Transaction 0x{transaction_id.hex()} doesn't have any coin spend.")
|
|
1091
1308
|
assert tr.spend_bundle is not None
|
|
1092
|
-
memos:
|
|
1309
|
+
memos: dict[bytes32, list[bytes]] = compute_memos(tr.spend_bundle)
|
|
1093
1310
|
response = {}
|
|
1094
1311
|
# Convert to hex string
|
|
1095
1312
|
for coin_id, memo_list in memos.items():
|
|
@@ -1099,7 +1316,7 @@ class WalletRpcApi:
|
|
|
1099
1316
|
@tx_endpoint(push=False)
|
|
1100
1317
|
@marshal
|
|
1101
1318
|
async def split_coins(
|
|
1102
|
-
self, request: SplitCoins, action_scope: WalletActionScope, extra_conditions:
|
|
1319
|
+
self, request: SplitCoins, action_scope: WalletActionScope, extra_conditions: tuple[Condition, ...] = tuple()
|
|
1103
1320
|
) -> SplitCoinsResponse:
|
|
1104
1321
|
if request.number_of_coins > 500:
|
|
1105
1322
|
raise ValueError(f"{request.number_of_coins} coins is greater then the maximum limit of 500 coins.")
|
|
@@ -1124,7 +1341,12 @@ class WalletRpcApi:
|
|
|
1124
1341
|
raise ValueError("Cannot split coins from non-fungible wallet types")
|
|
1125
1342
|
|
|
1126
1343
|
outputs = [
|
|
1127
|
-
Payment(
|
|
1344
|
+
Payment(
|
|
1345
|
+
await wallet.get_puzzle_hash(new=True)
|
|
1346
|
+
if isinstance(wallet, Wallet)
|
|
1347
|
+
else await wallet.standard_wallet.get_puzzle_hash(new=True),
|
|
1348
|
+
request.amount_per_coin,
|
|
1349
|
+
)
|
|
1128
1350
|
for _ in range(request.number_of_coins)
|
|
1129
1351
|
]
|
|
1130
1352
|
if len(outputs) == 0:
|
|
@@ -1168,9 +1390,8 @@ class WalletRpcApi:
|
|
|
1168
1390
|
@tx_endpoint(push=False)
|
|
1169
1391
|
@marshal
|
|
1170
1392
|
async def combine_coins(
|
|
1171
|
-
self, request: CombineCoins, action_scope: WalletActionScope, extra_conditions:
|
|
1393
|
+
self, request: CombineCoins, action_scope: WalletActionScope, extra_conditions: tuple[Condition, ...] = tuple()
|
|
1172
1394
|
) -> CombineCoinsResponse:
|
|
1173
|
-
|
|
1174
1395
|
# Some "number of coins" validation
|
|
1175
1396
|
if request.number_of_coins > request.coin_num_limit:
|
|
1176
1397
|
raise ValueError(
|
|
@@ -1187,7 +1408,7 @@ class WalletRpcApi:
|
|
|
1187
1408
|
if not isinstance(wallet, (Wallet, CATWallet)):
|
|
1188
1409
|
raise ValueError("Cannot combine coins from non-fungible wallet types")
|
|
1189
1410
|
|
|
1190
|
-
coins:
|
|
1411
|
+
coins: list[Coin] = []
|
|
1191
1412
|
|
|
1192
1413
|
# First get the coin IDs specified
|
|
1193
1414
|
if request.target_coin_ids != []:
|
|
@@ -1250,7 +1471,7 @@ class WalletRpcApi:
|
|
|
1250
1471
|
primary_output_amount = uint64(primary_output_amount - request.fee)
|
|
1251
1472
|
await wallet.generate_signed_transaction(
|
|
1252
1473
|
primary_output_amount,
|
|
1253
|
-
await wallet.get_puzzle_hash(new=action_scope.config.tx_config.reuse_puzhash),
|
|
1474
|
+
await wallet.get_puzzle_hash(new=not action_scope.config.tx_config.reuse_puzhash),
|
|
1254
1475
|
action_scope,
|
|
1255
1476
|
request.fee,
|
|
1256
1477
|
set(coins),
|
|
@@ -1260,7 +1481,7 @@ class WalletRpcApi:
|
|
|
1260
1481
|
assert isinstance(wallet, CATWallet)
|
|
1261
1482
|
await wallet.generate_signed_transaction(
|
|
1262
1483
|
[primary_output_amount],
|
|
1263
|
-
[await wallet.get_puzzle_hash(new=action_scope.config.tx_config.reuse_puzhash)],
|
|
1484
|
+
[await wallet.standard_wallet.get_puzzle_hash(new=not action_scope.config.tx_config.reuse_puzhash)],
|
|
1264
1485
|
action_scope,
|
|
1265
1486
|
request.fee,
|
|
1266
1487
|
coins=set(coins),
|
|
@@ -1269,7 +1490,7 @@ class WalletRpcApi:
|
|
|
1269
1490
|
|
|
1270
1491
|
return CombineCoinsResponse([], []) # tx_endpoint will take care to fill this out
|
|
1271
1492
|
|
|
1272
|
-
async def get_transactions(self, request:
|
|
1493
|
+
async def get_transactions(self, request: dict[str, Any]) -> EndpointResult:
|
|
1273
1494
|
wallet_id = int(request["wallet_id"])
|
|
1274
1495
|
|
|
1275
1496
|
start = request.get("start", 0)
|
|
@@ -1321,7 +1542,7 @@ class WalletRpcApi:
|
|
|
1321
1542
|
"wallet_id": wallet_id,
|
|
1322
1543
|
}
|
|
1323
1544
|
|
|
1324
|
-
async def get_transaction_count(self, request:
|
|
1545
|
+
async def get_transaction_count(self, request: dict[str, Any]) -> EndpointResult:
|
|
1325
1546
|
wallet_id = int(request["wallet_id"])
|
|
1326
1547
|
type_filter = None
|
|
1327
1548
|
if "type_filter" in request:
|
|
@@ -1334,7 +1555,7 @@ class WalletRpcApi:
|
|
|
1334
1555
|
"wallet_id": wallet_id,
|
|
1335
1556
|
}
|
|
1336
1557
|
|
|
1337
|
-
async def get_next_address(self, request:
|
|
1558
|
+
async def get_next_address(self, request: dict[str, Any]) -> EndpointResult:
|
|
1338
1559
|
"""
|
|
1339
1560
|
Returns a new address
|
|
1340
1561
|
"""
|
|
@@ -1365,9 +1586,9 @@ class WalletRpcApi:
|
|
|
1365
1586
|
@tx_endpoint(push=True)
|
|
1366
1587
|
async def send_transaction(
|
|
1367
1588
|
self,
|
|
1368
|
-
request:
|
|
1589
|
+
request: dict[str, Any],
|
|
1369
1590
|
action_scope: WalletActionScope,
|
|
1370
|
-
extra_conditions:
|
|
1591
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
1371
1592
|
) -> EndpointResult:
|
|
1372
1593
|
if await self.service.wallet_state_manager.synced() is False:
|
|
1373
1594
|
raise ValueError("Wallet needs to be fully synced before sending transactions")
|
|
@@ -1385,7 +1606,7 @@ class WalletRpcApi:
|
|
|
1385
1606
|
raise ValueError("Unexpected Address Prefix")
|
|
1386
1607
|
puzzle_hash: bytes32 = decode_puzzle_hash(address)
|
|
1387
1608
|
|
|
1388
|
-
memos:
|
|
1609
|
+
memos: list[bytes] = []
|
|
1389
1610
|
if "memos" in request:
|
|
1390
1611
|
memos = [mem.encode("utf-8") for mem in request["memos"]]
|
|
1391
1612
|
|
|
@@ -1409,7 +1630,7 @@ class WalletRpcApi:
|
|
|
1409
1630
|
"transaction_id": None, # tx_endpoint wrapper will take care of this
|
|
1410
1631
|
}
|
|
1411
1632
|
|
|
1412
|
-
async def send_transaction_multi(self, request:
|
|
1633
|
+
async def send_transaction_multi(self, request: dict[str, Any]) -> EndpointResult:
|
|
1413
1634
|
if await self.service.wallet_state_manager.synced() is False:
|
|
1414
1635
|
raise ValueError("Wallet needs to be fully synced before sending transactions")
|
|
1415
1636
|
|
|
@@ -1442,9 +1663,9 @@ class WalletRpcApi:
|
|
|
1442
1663
|
@tx_endpoint(push=True, merge_spends=False)
|
|
1443
1664
|
async def spend_clawback_coins(
|
|
1444
1665
|
self,
|
|
1445
|
-
request:
|
|
1666
|
+
request: dict[str, Any],
|
|
1446
1667
|
action_scope: WalletActionScope,
|
|
1447
|
-
extra_conditions:
|
|
1668
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
1448
1669
|
) -> EndpointResult:
|
|
1449
1670
|
"""Spend clawback coins that were sent (to claw them back) or received (to claim them).
|
|
1450
1671
|
|
|
@@ -1455,7 +1676,7 @@ class WalletRpcApi:
|
|
|
1455
1676
|
"""
|
|
1456
1677
|
if "coin_ids" not in request:
|
|
1457
1678
|
raise ValueError("Coin IDs are required.")
|
|
1458
|
-
coin_ids:
|
|
1679
|
+
coin_ids: list[bytes32] = [bytes32.from_hexstr(coin) for coin in request["coin_ids"]]
|
|
1459
1680
|
tx_fee: uint64 = uint64(request.get("fee", 0))
|
|
1460
1681
|
# Get inner puzzle
|
|
1461
1682
|
coin_records = await self.service.wallet_state_manager.coin_store.get_coin_records(
|
|
@@ -1465,7 +1686,7 @@ class WalletRpcApi:
|
|
|
1465
1686
|
spent_range=UInt32Range(stop=uint32(0)),
|
|
1466
1687
|
)
|
|
1467
1688
|
|
|
1468
|
-
coins:
|
|
1689
|
+
coins: dict[Coin, ClawbackMetadata] = {}
|
|
1469
1690
|
batch_size = request.get(
|
|
1470
1691
|
"batch_size", self.service.wallet_state_manager.config.get("auto_claim", {}).get("batch_size", 50)
|
|
1471
1692
|
)
|
|
@@ -1482,18 +1703,6 @@ class WalletRpcApi:
|
|
|
1482
1703
|
request.get("force", False),
|
|
1483
1704
|
extra_conditions=extra_conditions,
|
|
1484
1705
|
)
|
|
1485
|
-
async with action_scope.use() as interface:
|
|
1486
|
-
# TODO: editing this is not ideal. Action scopes should know what coins have been spent.
|
|
1487
|
-
action_scope._config = dataclasses.replace(
|
|
1488
|
-
action_scope._config,
|
|
1489
|
-
tx_config=dataclasses.replace(
|
|
1490
|
-
action_scope._config.tx_config,
|
|
1491
|
-
excluded_coin_ids=[
|
|
1492
|
-
*action_scope._config.tx_config.excluded_coin_ids,
|
|
1493
|
-
*(c.name() for tx in interface.side_effects.transactions for c in tx.removals),
|
|
1494
|
-
],
|
|
1495
|
-
),
|
|
1496
|
-
)
|
|
1497
1706
|
coins = {}
|
|
1498
1707
|
except Exception as e:
|
|
1499
1708
|
log.error(f"Failed to spend clawback coin {coin_id.hex()}: %s", e)
|
|
@@ -1512,7 +1721,7 @@ class WalletRpcApi:
|
|
|
1512
1721
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
1513
1722
|
}
|
|
1514
1723
|
|
|
1515
|
-
async def delete_unconfirmed_transactions(self, request:
|
|
1724
|
+
async def delete_unconfirmed_transactions(self, request: dict[str, Any]) -> EndpointResult:
|
|
1516
1725
|
wallet_id = uint32(request["wallet_id"])
|
|
1517
1726
|
if wallet_id not in self.service.wallet_state_manager.wallets:
|
|
1518
1727
|
raise ValueError(f"Wallet id {wallet_id} does not exist")
|
|
@@ -1529,14 +1738,14 @@ class WalletRpcApi:
|
|
|
1529
1738
|
|
|
1530
1739
|
async def select_coins(
|
|
1531
1740
|
self,
|
|
1532
|
-
request:
|
|
1741
|
+
request: dict[str, Any],
|
|
1533
1742
|
) -> EndpointResult:
|
|
1534
1743
|
assert self.service.logged_in_fingerprint is not None
|
|
1535
1744
|
tx_config_loader: TXConfigLoader = TXConfigLoader.from_json_dict(request)
|
|
1536
1745
|
|
|
1537
1746
|
# Some backwards compat fill-ins
|
|
1538
1747
|
if tx_config_loader.excluded_coin_ids is None:
|
|
1539
|
-
excluded_coins: Optional[
|
|
1748
|
+
excluded_coins: Optional[list[dict[str, Any]]] = request.get("excluded_coins", request.get("exclude_coins"))
|
|
1540
1749
|
if excluded_coins is not None:
|
|
1541
1750
|
tx_config_loader = tx_config_loader.override(
|
|
1542
1751
|
excluded_coin_ids=[Coin.from_json_dict(c).name() for c in excluded_coins],
|
|
@@ -1558,7 +1767,7 @@ class WalletRpcApi:
|
|
|
1558
1767
|
|
|
1559
1768
|
return {"coins": [coin.to_json_dict() for coin in selected_coins]}
|
|
1560
1769
|
|
|
1561
|
-
async def get_spendable_coins(self, request:
|
|
1770
|
+
async def get_spendable_coins(self, request: dict[str, Any]) -> EndpointResult:
|
|
1562
1771
|
if await self.service.wallet_state_manager.synced() is False:
|
|
1563
1772
|
raise ValueError("Wallet needs to be fully synced before getting all coins")
|
|
1564
1773
|
|
|
@@ -1567,17 +1776,17 @@ class WalletRpcApi:
|
|
|
1567
1776
|
max_coin_amount: uint64 = uint64(request.get("max_coin_amount", 0))
|
|
1568
1777
|
if max_coin_amount == 0:
|
|
1569
1778
|
max_coin_amount = uint64(self.service.wallet_state_manager.constants.MAX_COIN_AMOUNT)
|
|
1570
|
-
excluded_coin_amounts: Optional[
|
|
1779
|
+
excluded_coin_amounts: Optional[list[uint64]] = request.get("excluded_coin_amounts")
|
|
1571
1780
|
if excluded_coin_amounts is not None:
|
|
1572
1781
|
excluded_coin_amounts = [uint64(a) for a in excluded_coin_amounts]
|
|
1573
1782
|
else:
|
|
1574
1783
|
excluded_coin_amounts = []
|
|
1575
|
-
excluded_coins_input: Optional[
|
|
1784
|
+
excluded_coins_input: Optional[dict[str, dict[str, Any]]] = request.get("excluded_coins")
|
|
1576
1785
|
if excluded_coins_input is not None:
|
|
1577
1786
|
excluded_coins = [Coin.from_json_dict(json_coin) for json_coin in excluded_coins_input.values()]
|
|
1578
1787
|
else:
|
|
1579
1788
|
excluded_coins = []
|
|
1580
|
-
excluded_coin_ids_input: Optional[
|
|
1789
|
+
excluded_coin_ids_input: Optional[list[str]] = request.get("excluded_coin_ids")
|
|
1581
1790
|
if excluded_coin_ids_input is not None:
|
|
1582
1791
|
excluded_coin_ids = [bytes32.from_hexstr(hex_id) for hex_id in excluded_coin_ids_input]
|
|
1583
1792
|
else:
|
|
@@ -1588,27 +1797,27 @@ class WalletRpcApi:
|
|
|
1588
1797
|
all_coin_records = await state_mgr.coin_store.get_unspent_coins_for_wallet(wallet_id)
|
|
1589
1798
|
if wallet.type() in {WalletType.CAT, WalletType.CRCAT}:
|
|
1590
1799
|
assert isinstance(wallet, CATWallet)
|
|
1591
|
-
spendable_coins:
|
|
1800
|
+
spendable_coins: list[WalletCoinRecord] = await wallet.get_cat_spendable_coins(all_coin_records)
|
|
1592
1801
|
else:
|
|
1593
1802
|
spendable_coins = list(await state_mgr.get_spendable_coins_for_wallet(wallet_id, all_coin_records))
|
|
1594
1803
|
|
|
1595
1804
|
# Now we get the unconfirmed transactions and manually derive the additions and removals.
|
|
1596
|
-
unconfirmed_transactions:
|
|
1805
|
+
unconfirmed_transactions: list[TransactionRecord] = await state_mgr.tx_store.get_unconfirmed_for_wallet(
|
|
1597
1806
|
wallet_id
|
|
1598
1807
|
)
|
|
1599
|
-
unconfirmed_removal_ids:
|
|
1808
|
+
unconfirmed_removal_ids: dict[bytes32, uint64] = {
|
|
1600
1809
|
coin.name(): transaction.created_at_time
|
|
1601
1810
|
for transaction in unconfirmed_transactions
|
|
1602
1811
|
for coin in transaction.removals
|
|
1603
1812
|
}
|
|
1604
|
-
unconfirmed_additions:
|
|
1813
|
+
unconfirmed_additions: list[Coin] = [
|
|
1605
1814
|
coin
|
|
1606
1815
|
for transaction in unconfirmed_transactions
|
|
1607
1816
|
for coin in transaction.additions
|
|
1608
1817
|
if await state_mgr.does_coin_belong_to_wallet(coin, wallet_id)
|
|
1609
1818
|
]
|
|
1610
|
-
valid_spendable_cr:
|
|
1611
|
-
unconfirmed_removals:
|
|
1819
|
+
valid_spendable_cr: list[CoinRecord] = []
|
|
1820
|
+
unconfirmed_removals: list[CoinRecord] = []
|
|
1612
1821
|
for coin_record in all_coin_records:
|
|
1613
1822
|
if coin_record.name() in unconfirmed_removal_ids:
|
|
1614
1823
|
unconfirmed_removals.append(coin_record.to_coin_record(unconfirmed_removal_ids[coin_record.name()]))
|
|
@@ -1633,14 +1842,14 @@ class WalletRpcApi:
|
|
|
1633
1842
|
"unconfirmed_additions": [coin.to_json_dict() for coin in unconfirmed_additions],
|
|
1634
1843
|
}
|
|
1635
1844
|
|
|
1636
|
-
async def get_coin_records_by_names(self, request:
|
|
1845
|
+
async def get_coin_records_by_names(self, request: dict[str, Any]) -> EndpointResult:
|
|
1637
1846
|
if await self.service.wallet_state_manager.synced() is False:
|
|
1638
1847
|
raise ValueError("Wallet needs to be fully synced before finding coin information")
|
|
1639
1848
|
|
|
1640
1849
|
if "names" not in request:
|
|
1641
1850
|
raise ValueError("Names not in request")
|
|
1642
1851
|
coin_ids = [bytes32.from_hexstr(name) for name in request["names"]]
|
|
1643
|
-
kwargs:
|
|
1852
|
+
kwargs: dict[str, Any] = {
|
|
1644
1853
|
"coin_id_filter": HashFilter.include(coin_ids),
|
|
1645
1854
|
}
|
|
1646
1855
|
|
|
@@ -1656,10 +1865,10 @@ class WalletRpcApi:
|
|
|
1656
1865
|
kwargs["spent_range"] = unspent_range
|
|
1657
1866
|
|
|
1658
1867
|
async with self.service.wallet_state_manager.lock:
|
|
1659
|
-
coin_records:
|
|
1868
|
+
coin_records: list[CoinRecord] = await self.service.wallet_state_manager.get_coin_records_by_coin_ids(
|
|
1660
1869
|
**kwargs
|
|
1661
1870
|
)
|
|
1662
|
-
missed_coins:
|
|
1871
|
+
missed_coins: list[str] = [
|
|
1663
1872
|
"0x" + c_id.hex() for c_id in coin_ids if c_id not in [cr.name for cr in coin_records]
|
|
1664
1873
|
]
|
|
1665
1874
|
if missed_coins:
|
|
@@ -1667,14 +1876,14 @@ class WalletRpcApi:
|
|
|
1667
1876
|
|
|
1668
1877
|
return {"coin_records": [cr.to_json_dict() for cr in coin_records]}
|
|
1669
1878
|
|
|
1670
|
-
async def get_current_derivation_index(self, request:
|
|
1879
|
+
async def get_current_derivation_index(self, request: dict[str, Any]) -> dict[str, Any]:
|
|
1671
1880
|
assert self.service.wallet_state_manager is not None
|
|
1672
1881
|
|
|
1673
1882
|
index: Optional[uint32] = await self.service.wallet_state_manager.puzzle_store.get_last_derivation_path()
|
|
1674
1883
|
|
|
1675
1884
|
return {"success": True, "index": index}
|
|
1676
1885
|
|
|
1677
|
-
async def extend_derivation_index(self, request:
|
|
1886
|
+
async def extend_derivation_index(self, request: dict[str, Any]) -> dict[str, Any]:
|
|
1678
1887
|
assert self.service.wallet_state_manager is not None
|
|
1679
1888
|
|
|
1680
1889
|
# Require a new max derivation index
|
|
@@ -1718,10 +1927,10 @@ class WalletRpcApi:
|
|
|
1718
1927
|
@marshal
|
|
1719
1928
|
async def get_notifications(self, request: GetNotifications) -> GetNotificationsResponse:
|
|
1720
1929
|
if request.ids is None:
|
|
1721
|
-
notifications:
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
)
|
|
1930
|
+
notifications: list[
|
|
1931
|
+
Notification
|
|
1932
|
+
] = await self.service.wallet_state_manager.notification_manager.notification_store.get_all_notifications(
|
|
1933
|
+
pagination=(request.start, request.end)
|
|
1725
1934
|
)
|
|
1726
1935
|
else:
|
|
1727
1936
|
notifications = (
|
|
@@ -1732,8 +1941,8 @@ class WalletRpcApi:
|
|
|
1732
1941
|
|
|
1733
1942
|
return GetNotificationsResponse(notifications)
|
|
1734
1943
|
|
|
1735
|
-
async def delete_notifications(self, request:
|
|
1736
|
-
ids: Optional[
|
|
1944
|
+
async def delete_notifications(self, request: dict[str, Any]) -> EndpointResult:
|
|
1945
|
+
ids: Optional[list[str]] = request.get("ids", None)
|
|
1737
1946
|
if ids is None:
|
|
1738
1947
|
await self.service.wallet_state_manager.notification_manager.notification_store.delete_all_notifications()
|
|
1739
1948
|
else:
|
|
@@ -1746,9 +1955,9 @@ class WalletRpcApi:
|
|
|
1746
1955
|
@tx_endpoint(push=True)
|
|
1747
1956
|
async def send_notification(
|
|
1748
1957
|
self,
|
|
1749
|
-
request:
|
|
1958
|
+
request: dict[str, Any],
|
|
1750
1959
|
action_scope: WalletActionScope,
|
|
1751
|
-
extra_conditions:
|
|
1960
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
1752
1961
|
) -> EndpointResult:
|
|
1753
1962
|
await self.service.wallet_state_manager.notification_manager.send_new_notification(
|
|
1754
1963
|
bytes32.from_hexstr(request["target"]),
|
|
@@ -1761,7 +1970,7 @@ class WalletRpcApi:
|
|
|
1761
1970
|
|
|
1762
1971
|
return {"tx": None, "transactions": None} # tx_endpoint wrapper will take care of this
|
|
1763
1972
|
|
|
1764
|
-
async def verify_signature(self, request:
|
|
1973
|
+
async def verify_signature(self, request: dict[str, Any]) -> EndpointResult:
|
|
1765
1974
|
"""
|
|
1766
1975
|
Given a public key, message and signature, verify if it is valid.
|
|
1767
1976
|
:param request:
|
|
@@ -1779,7 +1988,7 @@ class WalletRpcApi:
|
|
|
1779
1988
|
except ValueError:
|
|
1780
1989
|
raise ValueError(f"Invalid signing mode: {signing_mode_str!r}")
|
|
1781
1990
|
|
|
1782
|
-
if signing_mode
|
|
1991
|
+
if signing_mode in {SigningMode.CHIP_0002, SigningMode.CHIP_0002_P2_DELEGATED_CONDITIONS}:
|
|
1783
1992
|
# CHIP-0002 message signatures are made over the tree hash of:
|
|
1784
1993
|
# ("Chia Signed Message", message)
|
|
1785
1994
|
message_to_verify: bytes = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, input_message)).get_tree_hash()
|
|
@@ -1819,7 +2028,7 @@ class WalletRpcApi:
|
|
|
1819
2028
|
else:
|
|
1820
2029
|
return {"isValid": False, "error": "Signature is invalid."}
|
|
1821
2030
|
|
|
1822
|
-
async def sign_message_by_address(self, request:
|
|
2031
|
+
async def sign_message_by_address(self, request: dict[str, Any]) -> EndpointResult:
|
|
1823
2032
|
"""
|
|
1824
2033
|
Given a derived P2 address, sign the message by its private key.
|
|
1825
2034
|
:param request:
|
|
@@ -1849,7 +2058,7 @@ class WalletRpcApi:
|
|
|
1849
2058
|
"signing_mode": mode.value,
|
|
1850
2059
|
}
|
|
1851
2060
|
|
|
1852
|
-
async def sign_message_by_id(self, request:
|
|
2061
|
+
async def sign_message_by_id(self, request: dict[str, Any]) -> EndpointResult:
|
|
1853
2062
|
"""
|
|
1854
2063
|
Given a NFT/DID ID, sign the message by the P2 private key.
|
|
1855
2064
|
:param request:
|
|
@@ -1914,22 +2123,22 @@ class WalletRpcApi:
|
|
|
1914
2123
|
# CATs and Trading
|
|
1915
2124
|
##########################################################################################
|
|
1916
2125
|
|
|
1917
|
-
async def get_cat_list(self, request:
|
|
2126
|
+
async def get_cat_list(self, request: dict[str, Any]) -> EndpointResult:
|
|
1918
2127
|
return {"cat_list": list(DEFAULT_CATS.values())}
|
|
1919
2128
|
|
|
1920
|
-
async def cat_set_name(self, request:
|
|
2129
|
+
async def cat_set_name(self, request: dict[str, Any]) -> EndpointResult:
|
|
1921
2130
|
wallet_id = uint32(request["wallet_id"])
|
|
1922
2131
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=CATWallet)
|
|
1923
2132
|
await wallet.set_name(str(request["name"]))
|
|
1924
2133
|
return {"wallet_id": wallet_id}
|
|
1925
2134
|
|
|
1926
|
-
async def cat_get_name(self, request:
|
|
2135
|
+
async def cat_get_name(self, request: dict[str, Any]) -> EndpointResult:
|
|
1927
2136
|
wallet_id = uint32(request["wallet_id"])
|
|
1928
2137
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=CATWallet)
|
|
1929
2138
|
name: str = wallet.get_name()
|
|
1930
2139
|
return {"wallet_id": wallet_id, "name": name}
|
|
1931
2140
|
|
|
1932
|
-
async def get_stray_cats(self, request:
|
|
2141
|
+
async def get_stray_cats(self, request: dict[str, Any]) -> EndpointResult:
|
|
1933
2142
|
"""
|
|
1934
2143
|
Get a list of all unacknowledged CATs
|
|
1935
2144
|
:param request: RPC request
|
|
@@ -1941,9 +2150,9 @@ class WalletRpcApi:
|
|
|
1941
2150
|
@tx_endpoint(push=True)
|
|
1942
2151
|
async def cat_spend(
|
|
1943
2152
|
self,
|
|
1944
|
-
request:
|
|
2153
|
+
request: dict[str, Any],
|
|
1945
2154
|
action_scope: WalletActionScope,
|
|
1946
|
-
extra_conditions:
|
|
2155
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
1947
2156
|
hold_lock: bool = True,
|
|
1948
2157
|
) -> EndpointResult:
|
|
1949
2158
|
if await self.service.wallet_state_manager.synced() is False:
|
|
@@ -1951,10 +2160,10 @@ class WalletRpcApi:
|
|
|
1951
2160
|
wallet_id = uint32(request["wallet_id"])
|
|
1952
2161
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=CATWallet)
|
|
1953
2162
|
|
|
1954
|
-
amounts:
|
|
1955
|
-
puzzle_hashes:
|
|
1956
|
-
memos:
|
|
1957
|
-
additions: Optional[
|
|
2163
|
+
amounts: list[uint64] = []
|
|
2164
|
+
puzzle_hashes: list[bytes32] = []
|
|
2165
|
+
memos: list[list[bytes]] = []
|
|
2166
|
+
additions: Optional[list[dict[str, Any]]] = request.get("additions")
|
|
1958
2167
|
if not isinstance(request["fee"], int) or (additions is None and not isinstance(request["amount"], int)):
|
|
1959
2168
|
raise ValueError("An integer amount or fee is required (too many decimals)")
|
|
1960
2169
|
if additions is not None:
|
|
@@ -1974,17 +2183,17 @@ class WalletRpcApi:
|
|
|
1974
2183
|
puzzle_hashes.append(decode_puzzle_hash(request["inner_address"]))
|
|
1975
2184
|
if "memos" in request:
|
|
1976
2185
|
memos.append([mem.encode("utf-8") for mem in request["memos"]])
|
|
1977
|
-
coins: Optional[
|
|
2186
|
+
coins: Optional[set[Coin]] = None
|
|
1978
2187
|
if "coins" in request and len(request["coins"]) > 0:
|
|
1979
2188
|
coins = {Coin.from_json_dict(coin_json) for coin_json in request["coins"]}
|
|
1980
2189
|
fee: uint64 = uint64(request.get("fee", 0))
|
|
1981
2190
|
|
|
1982
|
-
cat_discrepancy_params:
|
|
2191
|
+
cat_discrepancy_params: tuple[Optional[int], Optional[str], Optional[str]] = (
|
|
1983
2192
|
request.get("extra_delta", None),
|
|
1984
2193
|
request.get("tail_reveal", None),
|
|
1985
2194
|
request.get("tail_solution", None),
|
|
1986
2195
|
)
|
|
1987
|
-
cat_discrepancy: Optional[
|
|
2196
|
+
cat_discrepancy: Optional[tuple[int, Program, Program]] = None
|
|
1988
2197
|
if cat_discrepancy_params != (None, None, None):
|
|
1989
2198
|
if None in cat_discrepancy_params:
|
|
1990
2199
|
raise ValueError("Specifying extra_delta, tail_reveal, or tail_solution requires specifying the others")
|
|
@@ -2027,13 +2236,13 @@ class WalletRpcApi:
|
|
|
2027
2236
|
"transaction_id": None, # tx_endpoint wrapper will take care of this
|
|
2028
2237
|
}
|
|
2029
2238
|
|
|
2030
|
-
async def cat_get_asset_id(self, request:
|
|
2239
|
+
async def cat_get_asset_id(self, request: dict[str, Any]) -> EndpointResult:
|
|
2031
2240
|
wallet_id = uint32(request["wallet_id"])
|
|
2032
2241
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=CATWallet)
|
|
2033
2242
|
asset_id: str = wallet.get_asset_id()
|
|
2034
2243
|
return {"asset_id": asset_id, "wallet_id": wallet_id}
|
|
2035
2244
|
|
|
2036
|
-
async def cat_asset_id_to_name(self, request:
|
|
2245
|
+
async def cat_asset_id_to_name(self, request: dict[str, Any]) -> EndpointResult:
|
|
2037
2246
|
wallet = await self.service.wallet_state_manager.get_wallet_for_asset_id(request["asset_id"])
|
|
2038
2247
|
if wallet is None:
|
|
2039
2248
|
if request["asset_id"] in DEFAULT_CATS:
|
|
@@ -2046,17 +2255,17 @@ class WalletRpcApi:
|
|
|
2046
2255
|
@tx_endpoint(push=False)
|
|
2047
2256
|
async def create_offer_for_ids(
|
|
2048
2257
|
self,
|
|
2049
|
-
request:
|
|
2258
|
+
request: dict[str, Any],
|
|
2050
2259
|
action_scope: WalletActionScope,
|
|
2051
|
-
extra_conditions:
|
|
2260
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2052
2261
|
) -> EndpointResult:
|
|
2053
2262
|
if action_scope.config.push:
|
|
2054
2263
|
raise ValueError("Cannot push an incomplete spend") # pragma: no cover
|
|
2055
2264
|
|
|
2056
|
-
offer:
|
|
2265
|
+
offer: dict[str, int] = request["offer"]
|
|
2057
2266
|
fee: uint64 = uint64(request.get("fee", 0))
|
|
2058
2267
|
validate_only: bool = request.get("validate_only", False)
|
|
2059
|
-
driver_dict_str: Optional[
|
|
2268
|
+
driver_dict_str: Optional[dict[str, Any]] = request.get("driver_dict", None)
|
|
2060
2269
|
marshalled_solver = request.get("solver")
|
|
2061
2270
|
solver: Optional[Solver]
|
|
2062
2271
|
if marshalled_solver is None:
|
|
@@ -2065,7 +2274,7 @@ class WalletRpcApi:
|
|
|
2065
2274
|
solver = Solver(info=marshalled_solver)
|
|
2066
2275
|
|
|
2067
2276
|
# This driver_dict construction is to maintain backward compatibility where everything is assumed to be a CAT
|
|
2068
|
-
driver_dict:
|
|
2277
|
+
driver_dict: dict[bytes32, PuzzleInfo] = {}
|
|
2069
2278
|
if driver_dict_str is None:
|
|
2070
2279
|
for key, amount in offer.items():
|
|
2071
2280
|
if amount > 0:
|
|
@@ -2079,12 +2288,12 @@ class WalletRpcApi:
|
|
|
2079
2288
|
for key, value in driver_dict_str.items():
|
|
2080
2289
|
driver_dict[bytes32.from_hexstr(key)] = PuzzleInfo(value)
|
|
2081
2290
|
|
|
2082
|
-
modified_offer:
|
|
2083
|
-
for
|
|
2291
|
+
modified_offer: dict[Union[int, bytes32], int] = {}
|
|
2292
|
+
for wallet_identifier, change in offer.items():
|
|
2084
2293
|
try:
|
|
2085
|
-
modified_offer[bytes32.from_hexstr(
|
|
2294
|
+
modified_offer[bytes32.from_hexstr(wallet_identifier)] = change
|
|
2086
2295
|
except ValueError:
|
|
2087
|
-
modified_offer[int(
|
|
2296
|
+
modified_offer[int(wallet_identifier)] = change
|
|
2088
2297
|
|
|
2089
2298
|
async with self.service.wallet_state_manager.lock:
|
|
2090
2299
|
result = await self.service.wallet_state_manager.trade_manager.create_offer_for_ids(
|
|
@@ -2097,7 +2306,7 @@ class WalletRpcApi:
|
|
|
2097
2306
|
extra_conditions=extra_conditions,
|
|
2098
2307
|
)
|
|
2099
2308
|
if result[0]:
|
|
2100
|
-
|
|
2309
|
+
_success, trade_record, _error = result
|
|
2101
2310
|
return {
|
|
2102
2311
|
"offer": Offer.from_bytes(trade_record.offer).to_bech32(),
|
|
2103
2312
|
"trade_record": trade_record.to_json_dict_convenience(),
|
|
@@ -2105,7 +2314,7 @@ class WalletRpcApi:
|
|
|
2105
2314
|
}
|
|
2106
2315
|
raise ValueError(result[2])
|
|
2107
2316
|
|
|
2108
|
-
async def get_offer_summary(self, request:
|
|
2317
|
+
async def get_offer_summary(self, request: dict[str, Any]) -> EndpointResult:
|
|
2109
2318
|
offer_hex: str = request["offer"]
|
|
2110
2319
|
|
|
2111
2320
|
###
|
|
@@ -2114,7 +2323,7 @@ class WalletRpcApi:
|
|
|
2114
2323
|
from chia.util.bech32m import bech32_decode, convertbits
|
|
2115
2324
|
from chia.wallet.util.puzzle_compression import OFFER_MOD_OLD, decompress_object_with_puzzles
|
|
2116
2325
|
|
|
2117
|
-
|
|
2326
|
+
_hrpgot, data = bech32_decode(offer_hex, max_length=len(offer_hex))
|
|
2118
2327
|
if data is None:
|
|
2119
2328
|
raise ValueError("Invalid Offer")
|
|
2120
2329
|
decoded = convertbits(list(data), 5, 8, False)
|
|
@@ -2143,12 +2352,12 @@ class WalletRpcApi:
|
|
|
2143
2352
|
k: v
|
|
2144
2353
|
for k, v in valid_times.to_json_dict().items()
|
|
2145
2354
|
if k
|
|
2146
|
-
not in
|
|
2355
|
+
not in {
|
|
2147
2356
|
"max_secs_after_created",
|
|
2148
2357
|
"min_secs_since_created",
|
|
2149
2358
|
"max_blocks_after_created",
|
|
2150
2359
|
"min_blocks_since_created",
|
|
2151
|
-
|
|
2360
|
+
}
|
|
2152
2361
|
},
|
|
2153
2362
|
},
|
|
2154
2363
|
"id": offer.name(),
|
|
@@ -2184,7 +2393,7 @@ class WalletRpcApi:
|
|
|
2184
2393
|
},
|
|
2185
2394
|
}
|
|
2186
2395
|
|
|
2187
|
-
async def check_offer_validity(self, request:
|
|
2396
|
+
async def check_offer_validity(self, request: dict[str, Any]) -> EndpointResult:
|
|
2188
2397
|
offer_hex: str = request["offer"]
|
|
2189
2398
|
|
|
2190
2399
|
###
|
|
@@ -2193,7 +2402,7 @@ class WalletRpcApi:
|
|
|
2193
2402
|
from chia.util.bech32m import bech32_decode, convertbits
|
|
2194
2403
|
from chia.wallet.util.puzzle_compression import OFFER_MOD_OLD, decompress_object_with_puzzles
|
|
2195
2404
|
|
|
2196
|
-
|
|
2405
|
+
_hrpgot, data = bech32_decode(offer_hex, max_length=len(offer_hex))
|
|
2197
2406
|
if data is None:
|
|
2198
2407
|
raise ValueError("Invalid Offer") # pragma: no cover
|
|
2199
2408
|
decoded = convertbits(list(data), 5, 8, False)
|
|
@@ -2216,9 +2425,9 @@ class WalletRpcApi:
|
|
|
2216
2425
|
@tx_endpoint(push=True)
|
|
2217
2426
|
async def take_offer(
|
|
2218
2427
|
self,
|
|
2219
|
-
request:
|
|
2428
|
+
request: dict[str, Any],
|
|
2220
2429
|
action_scope: WalletActionScope,
|
|
2221
|
-
extra_conditions:
|
|
2430
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2222
2431
|
) -> EndpointResult:
|
|
2223
2432
|
offer_hex: str = request["offer"]
|
|
2224
2433
|
|
|
@@ -2228,7 +2437,7 @@ class WalletRpcApi:
|
|
|
2228
2437
|
from chia.util.bech32m import bech32_decode, convertbits
|
|
2229
2438
|
from chia.wallet.util.puzzle_compression import OFFER_MOD_OLD, decompress_object_with_puzzles
|
|
2230
2439
|
|
|
2231
|
-
|
|
2440
|
+
_hrpgot, data = bech32_decode(offer_hex, max_length=len(offer_hex))
|
|
2232
2441
|
if data is None:
|
|
2233
2442
|
raise ValueError("Invalid Offer") # pragma: no cover
|
|
2234
2443
|
decoded = convertbits(list(data), 5, 8, False)
|
|
@@ -2243,7 +2452,7 @@ class WalletRpcApi:
|
|
|
2243
2452
|
|
|
2244
2453
|
offer = Offer.from_bech32(offer_hex)
|
|
2245
2454
|
fee: uint64 = uint64(request.get("fee", 0))
|
|
2246
|
-
maybe_marshalled_solver: Optional[
|
|
2455
|
+
maybe_marshalled_solver: Optional[dict[str, Any]] = request.get("solver")
|
|
2247
2456
|
solver: Optional[Solver]
|
|
2248
2457
|
if maybe_marshalled_solver is None:
|
|
2249
2458
|
solver = None
|
|
@@ -2272,7 +2481,7 @@ class WalletRpcApi:
|
|
|
2272
2481
|
"signing_responses": None, # tx_endpoint wrapper will take care of this
|
|
2273
2482
|
}
|
|
2274
2483
|
|
|
2275
|
-
async def get_offer(self, request:
|
|
2484
|
+
async def get_offer(self, request: dict[str, Any]) -> EndpointResult:
|
|
2276
2485
|
trade_mgr = self.service.wallet_state_manager.trade_manager
|
|
2277
2486
|
|
|
2278
2487
|
trade_id = bytes32.from_hexstr(request["trade_id"])
|
|
@@ -2285,7 +2494,7 @@ class WalletRpcApi:
|
|
|
2285
2494
|
offer_value: Optional[str] = Offer.from_bytes(offer_to_return).to_bech32() if file_contents else None
|
|
2286
2495
|
return {"trade_record": trade_record.to_json_dict_convenience(), "offer": offer_value}
|
|
2287
2496
|
|
|
2288
|
-
async def get_all_offers(self, request:
|
|
2497
|
+
async def get_all_offers(self, request: dict[str, Any]) -> EndpointResult:
|
|
2289
2498
|
trade_mgr = self.service.wallet_state_manager.trade_manager
|
|
2290
2499
|
|
|
2291
2500
|
start: int = request.get("start", 0)
|
|
@@ -2307,7 +2516,7 @@ class WalletRpcApi:
|
|
|
2307
2516
|
include_completed=include_completed,
|
|
2308
2517
|
)
|
|
2309
2518
|
result = []
|
|
2310
|
-
offer_values: Optional[
|
|
2519
|
+
offer_values: Optional[list[str]] = [] if file_contents else None
|
|
2311
2520
|
for trade in all_trades:
|
|
2312
2521
|
result.append(trade.to_json_dict_convenience())
|
|
2313
2522
|
if file_contents and offer_values is not None:
|
|
@@ -2316,7 +2525,7 @@ class WalletRpcApi:
|
|
|
2316
2525
|
|
|
2317
2526
|
return {"trade_records": result, "offers": offer_values}
|
|
2318
2527
|
|
|
2319
|
-
async def get_offers_count(self, request:
|
|
2528
|
+
async def get_offers_count(self, request: dict[str, Any]) -> EndpointResult:
|
|
2320
2529
|
trade_mgr = self.service.wallet_state_manager.trade_manager
|
|
2321
2530
|
|
|
2322
2531
|
(total, my_offers_count, taken_offers_count) = await trade_mgr.trade_store.get_trades_count()
|
|
@@ -2326,9 +2535,9 @@ class WalletRpcApi:
|
|
|
2326
2535
|
@tx_endpoint(push=True)
|
|
2327
2536
|
async def cancel_offer(
|
|
2328
2537
|
self,
|
|
2329
|
-
request:
|
|
2538
|
+
request: dict[str, Any],
|
|
2330
2539
|
action_scope: WalletActionScope,
|
|
2331
|
-
extra_conditions:
|
|
2540
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2332
2541
|
) -> EndpointResult:
|
|
2333
2542
|
wsm = self.service.wallet_state_manager
|
|
2334
2543
|
secure = request["secure"]
|
|
@@ -2336,7 +2545,7 @@ class WalletRpcApi:
|
|
|
2336
2545
|
fee: uint64 = uint64(request.get("fee", 0))
|
|
2337
2546
|
async with self.service.wallet_state_manager.lock:
|
|
2338
2547
|
await wsm.trade_manager.cancel_pending_offers(
|
|
2339
|
-
[
|
|
2548
|
+
[trade_id], action_scope, fee=fee, secure=secure, extra_conditions=extra_conditions
|
|
2340
2549
|
)
|
|
2341
2550
|
|
|
2342
2551
|
return {"transactions": None} # tx_endpoint wrapper will take care of this
|
|
@@ -2344,9 +2553,9 @@ class WalletRpcApi:
|
|
|
2344
2553
|
@tx_endpoint(push=True, merge_spends=False)
|
|
2345
2554
|
async def cancel_offers(
|
|
2346
2555
|
self,
|
|
2347
|
-
request:
|
|
2556
|
+
request: dict[str, Any],
|
|
2348
2557
|
action_scope: WalletActionScope,
|
|
2349
|
-
extra_conditions:
|
|
2558
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2350
2559
|
) -> EndpointResult:
|
|
2351
2560
|
secure = request["secure"]
|
|
2352
2561
|
batch_fee: uint64 = uint64(request.get("batch_fee", 0))
|
|
@@ -2366,7 +2575,7 @@ class WalletRpcApi:
|
|
|
2366
2575
|
if asset_id is not None and asset_id != "xch":
|
|
2367
2576
|
key = bytes32.from_hexstr(asset_id)
|
|
2368
2577
|
while True:
|
|
2369
|
-
records:
|
|
2578
|
+
records: dict[bytes32, TradeRecord] = {}
|
|
2370
2579
|
trades = await trade_mgr.trade_store.get_trades_between(
|
|
2371
2580
|
start,
|
|
2372
2581
|
end,
|
|
@@ -2411,13 +2620,13 @@ class WalletRpcApi:
|
|
|
2411
2620
|
# Distributed Identities
|
|
2412
2621
|
##########################################################################################
|
|
2413
2622
|
|
|
2414
|
-
async def did_set_wallet_name(self, request:
|
|
2623
|
+
async def did_set_wallet_name(self, request: dict[str, Any]) -> EndpointResult:
|
|
2415
2624
|
wallet_id = uint32(request["wallet_id"])
|
|
2416
2625
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2417
2626
|
await wallet.set_name(str(request["name"]))
|
|
2418
2627
|
return {"success": True, "wallet_id": wallet_id}
|
|
2419
2628
|
|
|
2420
|
-
async def did_get_wallet_name(self, request:
|
|
2629
|
+
async def did_get_wallet_name(self, request: dict[str, Any]) -> EndpointResult:
|
|
2421
2630
|
wallet_id = uint32(request["wallet_id"])
|
|
2422
2631
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2423
2632
|
name: str = wallet.get_name() # type: ignore[no-untyped-call] # Missing hint in `did_wallet.py`
|
|
@@ -2426,9 +2635,9 @@ class WalletRpcApi:
|
|
|
2426
2635
|
@tx_endpoint(push=True)
|
|
2427
2636
|
async def did_update_recovery_ids(
|
|
2428
2637
|
self,
|
|
2429
|
-
request:
|
|
2638
|
+
request: dict[str, Any],
|
|
2430
2639
|
action_scope: WalletActionScope,
|
|
2431
|
-
extra_conditions:
|
|
2640
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2432
2641
|
) -> EndpointResult:
|
|
2433
2642
|
wallet_id = uint32(request["wallet_id"])
|
|
2434
2643
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
@@ -2456,9 +2665,9 @@ class WalletRpcApi:
|
|
|
2456
2665
|
@tx_endpoint(push=False)
|
|
2457
2666
|
async def did_message_spend(
|
|
2458
2667
|
self,
|
|
2459
|
-
request:
|
|
2668
|
+
request: dict[str, Any],
|
|
2460
2669
|
action_scope: WalletActionScope,
|
|
2461
|
-
extra_conditions:
|
|
2670
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2462
2671
|
) -> EndpointResult:
|
|
2463
2672
|
wallet_id = uint32(request["wallet_id"])
|
|
2464
2673
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
@@ -2477,7 +2686,7 @@ class WalletRpcApi:
|
|
|
2477
2686
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
2478
2687
|
}
|
|
2479
2688
|
|
|
2480
|
-
async def did_get_info(self, request:
|
|
2689
|
+
async def did_get_info(self, request: dict[str, Any]) -> EndpointResult:
|
|
2481
2690
|
if "coin_id" not in request:
|
|
2482
2691
|
return {"success": False, "error": "Coin ID is required."}
|
|
2483
2692
|
coin_id = request["coin_id"]
|
|
@@ -2517,7 +2726,7 @@ class WalletRpcApi:
|
|
|
2517
2726
|
"hints": hints,
|
|
2518
2727
|
}
|
|
2519
2728
|
|
|
2520
|
-
async def did_find_lost_did(self, request:
|
|
2729
|
+
async def did_find_lost_did(self, request: dict[str, Any]) -> EndpointResult:
|
|
2521
2730
|
"""
|
|
2522
2731
|
Recover a missing or unspendable DID wallet by a coin id of the DID
|
|
2523
2732
|
:param coin_id: It can be DID ID, launcher coin ID or any coin ID of the DID you want to find.
|
|
@@ -2556,21 +2765,22 @@ class WalletRpcApi:
|
|
|
2556
2765
|
if hinted_coin.coin.amount % 2 == 1 and hinted_coin.hint is not None:
|
|
2557
2766
|
hint = hinted_coin.hint
|
|
2558
2767
|
break
|
|
2559
|
-
|
|
2768
|
+
derivation_record = None
|
|
2769
|
+
if hint is not None:
|
|
2770
|
+
derivation_record = (
|
|
2771
|
+
await self.service.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(hint)
|
|
2772
|
+
)
|
|
2773
|
+
if derivation_record is None:
|
|
2560
2774
|
# This is an invalid DID, check if we are owner
|
|
2561
2775
|
derivation_record = (
|
|
2562
2776
|
await self.service.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(
|
|
2563
2777
|
p2_puzzle.get_tree_hash()
|
|
2564
2778
|
)
|
|
2565
2779
|
)
|
|
2566
|
-
else:
|
|
2567
|
-
derivation_record = (
|
|
2568
|
-
await self.service.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(hint)
|
|
2569
|
-
)
|
|
2570
2780
|
|
|
2571
2781
|
launcher_id = bytes32(singleton_struct.rest().first().as_atom())
|
|
2572
2782
|
if derivation_record is None:
|
|
2573
|
-
return {"success": False, "error": f"This DID {launcher_id}
|
|
2783
|
+
return {"success": False, "error": f"This DID {launcher_id} does not belong to the connected wallet"}
|
|
2574
2784
|
else:
|
|
2575
2785
|
our_inner_puzzle: Program = self.service.wallet_state_manager.main_wallet.puzzle_for_pk(
|
|
2576
2786
|
derivation_record.pubkey
|
|
@@ -2650,7 +2860,7 @@ class WalletRpcApi:
|
|
|
2650
2860
|
|
|
2651
2861
|
if did_wallet is None:
|
|
2652
2862
|
# Create DID wallet
|
|
2653
|
-
response:
|
|
2863
|
+
response: list[CoinState] = await self.service.get_coin_state([launcher_id], peer=peer)
|
|
2654
2864
|
if len(response) == 0:
|
|
2655
2865
|
return {"success": False, "error": f"Could not find the launch coin with ID: {launcher_id}"}
|
|
2656
2866
|
launcher_coin: CoinState = response[0]
|
|
@@ -2668,7 +2878,7 @@ class WalletRpcApi:
|
|
|
2668
2878
|
# Inner DID puzzle doesn't match, we need to update the DID info
|
|
2669
2879
|
full_solution: Program = Program.from_bytes(bytes(coin_spend.solution))
|
|
2670
2880
|
inner_solution: Program = full_solution.rest().rest().first()
|
|
2671
|
-
recovery_list:
|
|
2881
|
+
recovery_list: list[bytes32] = []
|
|
2672
2882
|
backup_required: int = num_verification.as_int()
|
|
2673
2883
|
if recovery_list_hash != NIL_TREEHASH:
|
|
2674
2884
|
try:
|
|
@@ -2718,13 +2928,13 @@ class WalletRpcApi:
|
|
|
2718
2928
|
@tx_endpoint(push=True)
|
|
2719
2929
|
async def did_update_metadata(
|
|
2720
2930
|
self,
|
|
2721
|
-
request:
|
|
2931
|
+
request: dict[str, Any],
|
|
2722
2932
|
action_scope: WalletActionScope,
|
|
2723
|
-
extra_conditions:
|
|
2933
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2724
2934
|
) -> EndpointResult:
|
|
2725
2935
|
wallet_id = uint32(request["wallet_id"])
|
|
2726
2936
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2727
|
-
metadata:
|
|
2937
|
+
metadata: dict[str, str] = {}
|
|
2728
2938
|
if "metadata" in request and type(request["metadata"]) is dict:
|
|
2729
2939
|
metadata = request["metadata"]
|
|
2730
2940
|
async with self.service.wallet_state_manager.lock:
|
|
@@ -2743,7 +2953,7 @@ class WalletRpcApi:
|
|
|
2743
2953
|
else:
|
|
2744
2954
|
return {"success": False, "error": f"Couldn't update metadata with input: {metadata}"}
|
|
2745
2955
|
|
|
2746
|
-
async def did_get_did(self, request:
|
|
2956
|
+
async def did_get_did(self, request: dict[str, Any]) -> EndpointResult:
|
|
2747
2957
|
wallet_id = uint32(request["wallet_id"])
|
|
2748
2958
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2749
2959
|
my_did: str = encode_puzzle_hash(bytes32.fromhex(wallet.get_my_DID()), AddressType.DID.hrp(self.service.config))
|
|
@@ -2754,7 +2964,7 @@ class WalletRpcApi:
|
|
|
2754
2964
|
except RuntimeError:
|
|
2755
2965
|
return {"success": True, "wallet_id": wallet_id, "my_did": my_did}
|
|
2756
2966
|
|
|
2757
|
-
async def did_get_recovery_list(self, request:
|
|
2967
|
+
async def did_get_recovery_list(self, request: dict[str, Any]) -> EndpointResult:
|
|
2758
2968
|
wallet_id = uint32(request["wallet_id"])
|
|
2759
2969
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2760
2970
|
recovery_list = wallet.did_info.backup_ids
|
|
@@ -2768,7 +2978,7 @@ class WalletRpcApi:
|
|
|
2768
2978
|
"num_required": wallet.did_info.num_of_backup_ids_needed,
|
|
2769
2979
|
}
|
|
2770
2980
|
|
|
2771
|
-
async def did_get_metadata(self, request:
|
|
2981
|
+
async def did_get_metadata(self, request: dict[str, Any]) -> EndpointResult:
|
|
2772
2982
|
wallet_id = uint32(request["wallet_id"])
|
|
2773
2983
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2774
2984
|
metadata = json.loads(wallet.did_info.metadata)
|
|
@@ -2780,7 +2990,7 @@ class WalletRpcApi:
|
|
|
2780
2990
|
|
|
2781
2991
|
# TODO: this needs a test
|
|
2782
2992
|
# Don't need full @tx_endpoint decorator here, but "push" is still a valid option
|
|
2783
|
-
async def did_recovery_spend(self, request:
|
|
2993
|
+
async def did_recovery_spend(self, request: dict[str, Any]) -> EndpointResult: # pragma: no cover
|
|
2784
2994
|
wallet_id = uint32(request["wallet_id"])
|
|
2785
2995
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2786
2996
|
if len(request["attest_data"]) < wallet.did_info.num_of_backup_ids_needed:
|
|
@@ -2822,7 +3032,7 @@ class WalletRpcApi:
|
|
|
2822
3032
|
"transactions": [tx.to_json_dict_convenience(self.service.config)],
|
|
2823
3033
|
}
|
|
2824
3034
|
|
|
2825
|
-
async def did_get_pubkey(self, request:
|
|
3035
|
+
async def did_get_pubkey(self, request: dict[str, Any]) -> EndpointResult:
|
|
2826
3036
|
wallet_id = uint32(request["wallet_id"])
|
|
2827
3037
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2828
3038
|
pubkey = bytes((await wallet.wallet_state_manager.get_unused_derivation_record(wallet_id)).pubkey).hex()
|
|
@@ -2832,9 +3042,9 @@ class WalletRpcApi:
|
|
|
2832
3042
|
@tx_endpoint(push=True)
|
|
2833
3043
|
async def did_create_attest(
|
|
2834
3044
|
self,
|
|
2835
|
-
request:
|
|
3045
|
+
request: dict[str, Any],
|
|
2836
3046
|
action_scope: WalletActionScope,
|
|
2837
|
-
extra_conditions:
|
|
3047
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2838
3048
|
) -> EndpointResult: # pragma: no cover
|
|
2839
3049
|
wallet_id = uint32(request["wallet_id"])
|
|
2840
3050
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
@@ -2860,7 +3070,7 @@ class WalletRpcApi:
|
|
|
2860
3070
|
else:
|
|
2861
3071
|
return {"success": False}
|
|
2862
3072
|
|
|
2863
|
-
async def did_get_information_needed_for_recovery(self, request:
|
|
3073
|
+
async def did_get_information_needed_for_recovery(self, request: dict[str, Any]) -> EndpointResult:
|
|
2864
3074
|
wallet_id = uint32(request["wallet_id"])
|
|
2865
3075
|
did_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2866
3076
|
my_did = encode_puzzle_hash(
|
|
@@ -2878,7 +3088,7 @@ class WalletRpcApi:
|
|
|
2878
3088
|
"backup_dids": did_wallet.did_info.backup_ids,
|
|
2879
3089
|
}
|
|
2880
3090
|
|
|
2881
|
-
async def did_get_current_coin_info(self, request:
|
|
3091
|
+
async def did_get_current_coin_info(self, request: dict[str, Any]) -> EndpointResult:
|
|
2882
3092
|
wallet_id = uint32(request["wallet_id"])
|
|
2883
3093
|
did_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2884
3094
|
my_did = encode_puzzle_hash(
|
|
@@ -2897,7 +3107,7 @@ class WalletRpcApi:
|
|
|
2897
3107
|
"did_amount": did_coin_threeple[2],
|
|
2898
3108
|
}
|
|
2899
3109
|
|
|
2900
|
-
async def did_create_backup_file(self, request:
|
|
3110
|
+
async def did_create_backup_file(self, request: dict[str, Any]) -> EndpointResult:
|
|
2901
3111
|
wallet_id = uint32(request["wallet_id"])
|
|
2902
3112
|
did_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
|
2903
3113
|
return {"wallet_id": wallet_id, "success": True, "backup_data": did_wallet.create_backup()}
|
|
@@ -2905,9 +3115,9 @@ class WalletRpcApi:
|
|
|
2905
3115
|
@tx_endpoint(push=True)
|
|
2906
3116
|
async def did_transfer_did(
|
|
2907
3117
|
self,
|
|
2908
|
-
request:
|
|
3118
|
+
request: dict[str, Any],
|
|
2909
3119
|
action_scope: WalletActionScope,
|
|
2910
|
-
extra_conditions:
|
|
3120
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2911
3121
|
) -> EndpointResult:
|
|
2912
3122
|
if await self.service.wallet_state_manager.synced() is False:
|
|
2913
3123
|
raise ValueError("Wallet needs to be fully synced.")
|
|
@@ -2934,7 +3144,7 @@ class WalletRpcApi:
|
|
|
2934
3144
|
# DAO Wallet
|
|
2935
3145
|
##########################################################################################
|
|
2936
3146
|
|
|
2937
|
-
async def dao_adjust_filter_level(self, request:
|
|
3147
|
+
async def dao_adjust_filter_level(self, request: dict[str, Any]) -> EndpointResult:
|
|
2938
3148
|
wallet_id = uint32(request["wallet_id"])
|
|
2939
3149
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
2940
3150
|
await dao_wallet.adjust_filter_level(uint64(request["filter_level"]))
|
|
@@ -2946,9 +3156,9 @@ class WalletRpcApi:
|
|
|
2946
3156
|
@tx_endpoint(push=True)
|
|
2947
3157
|
async def dao_add_funds_to_treasury(
|
|
2948
3158
|
self,
|
|
2949
|
-
request:
|
|
3159
|
+
request: dict[str, Any],
|
|
2950
3160
|
action_scope: WalletActionScope,
|
|
2951
|
-
extra_conditions:
|
|
3161
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2952
3162
|
) -> EndpointResult:
|
|
2953
3163
|
wallet_id = uint32(request["wallet_id"])
|
|
2954
3164
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
@@ -2956,7 +3166,7 @@ class WalletRpcApi:
|
|
|
2956
3166
|
wallet_type = self.service.wallet_state_manager.wallets[funding_wallet_id].type()
|
|
2957
3167
|
amount = request.get("amount")
|
|
2958
3168
|
assert amount
|
|
2959
|
-
if wallet_type not in
|
|
3169
|
+
if wallet_type not in {WalletType.STANDARD_WALLET, WalletType.CAT}: # pragma: no cover
|
|
2960
3170
|
raise ValueError(f"Cannot fund a treasury with assets from a {wallet_type.name} wallet")
|
|
2961
3171
|
await dao_wallet.create_add_funds_to_treasury_spend(
|
|
2962
3172
|
uint64(amount),
|
|
@@ -2972,7 +3182,7 @@ class WalletRpcApi:
|
|
|
2972
3182
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
2973
3183
|
}
|
|
2974
3184
|
|
|
2975
|
-
async def dao_get_treasury_balance(self, request:
|
|
3185
|
+
async def dao_get_treasury_balance(self, request: dict[str, Any]) -> EndpointResult:
|
|
2976
3186
|
wallet_id = uint32(request["wallet_id"])
|
|
2977
3187
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
2978
3188
|
assert dao_wallet is not None
|
|
@@ -2986,14 +3196,14 @@ class WalletRpcApi:
|
|
|
2986
3196
|
balances[asset_id.hex()] = balance
|
|
2987
3197
|
return {"success": True, "balances": balances}
|
|
2988
3198
|
|
|
2989
|
-
async def dao_get_treasury_id(self, request:
|
|
3199
|
+
async def dao_get_treasury_id(self, request: dict[str, Any]) -> EndpointResult:
|
|
2990
3200
|
wallet_id = uint32(request["wallet_id"])
|
|
2991
3201
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
2992
3202
|
assert dao_wallet is not None
|
|
2993
3203
|
treasury_id = dao_wallet.dao_info.treasury_id
|
|
2994
3204
|
return {"treasury_id": treasury_id}
|
|
2995
3205
|
|
|
2996
|
-
async def dao_get_rules(self, request:
|
|
3206
|
+
async def dao_get_rules(self, request: dict[str, Any]) -> EndpointResult:
|
|
2997
3207
|
wallet_id = uint32(request["wallet_id"])
|
|
2998
3208
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
2999
3209
|
assert dao_wallet is not None
|
|
@@ -3003,9 +3213,9 @@ class WalletRpcApi:
|
|
|
3003
3213
|
@tx_endpoint(push=True)
|
|
3004
3214
|
async def dao_send_to_lockup(
|
|
3005
3215
|
self,
|
|
3006
|
-
request:
|
|
3216
|
+
request: dict[str, Any],
|
|
3007
3217
|
action_scope: WalletActionScope,
|
|
3008
|
-
extra_conditions:
|
|
3218
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3009
3219
|
) -> EndpointResult:
|
|
3010
3220
|
wallet_id = uint32(request["wallet_id"])
|
|
3011
3221
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
@@ -3027,7 +3237,7 @@ class WalletRpcApi:
|
|
|
3027
3237
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
3028
3238
|
}
|
|
3029
3239
|
|
|
3030
|
-
async def dao_get_proposals(self, request:
|
|
3240
|
+
async def dao_get_proposals(self, request: dict[str, Any]) -> EndpointResult:
|
|
3031
3241
|
wallet_id = uint32(request["wallet_id"])
|
|
3032
3242
|
include_closed = request.get("include_closed", True)
|
|
3033
3243
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
@@ -3043,7 +3253,7 @@ class WalletRpcApi:
|
|
|
3043
3253
|
"soft_close_length": dao_rules.soft_close_length,
|
|
3044
3254
|
}
|
|
3045
3255
|
|
|
3046
|
-
async def dao_get_proposal_state(self, request:
|
|
3256
|
+
async def dao_get_proposal_state(self, request: dict[str, Any]) -> EndpointResult:
|
|
3047
3257
|
wallet_id = uint32(request["wallet_id"])
|
|
3048
3258
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
3049
3259
|
assert dao_wallet is not None
|
|
@@ -3053,9 +3263,9 @@ class WalletRpcApi:
|
|
|
3053
3263
|
@tx_endpoint(push=True)
|
|
3054
3264
|
async def dao_exit_lockup(
|
|
3055
3265
|
self,
|
|
3056
|
-
request:
|
|
3266
|
+
request: dict[str, Any],
|
|
3057
3267
|
action_scope: WalletActionScope,
|
|
3058
|
-
extra_conditions:
|
|
3268
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3059
3269
|
) -> EndpointResult:
|
|
3060
3270
|
wallet_id = uint32(request["wallet_id"])
|
|
3061
3271
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
@@ -3066,7 +3276,7 @@ class WalletRpcApi:
|
|
|
3066
3276
|
assert dao_cat_wallet is not None
|
|
3067
3277
|
if request["coins"]: # pragma: no cover
|
|
3068
3278
|
coin_list = [Coin.from_json_dict(coin) for coin in request["coins"]]
|
|
3069
|
-
coins:
|
|
3279
|
+
coins: list[LockedCoinInfo] = []
|
|
3070
3280
|
for lci in dao_cat_wallet.dao_cat_info.locked_coins:
|
|
3071
3281
|
if lci.coin in coin_list:
|
|
3072
3282
|
coins.append(lci)
|
|
@@ -3094,19 +3304,19 @@ class WalletRpcApi:
|
|
|
3094
3304
|
@tx_endpoint(push=True)
|
|
3095
3305
|
async def dao_create_proposal(
|
|
3096
3306
|
self,
|
|
3097
|
-
request:
|
|
3307
|
+
request: dict[str, Any],
|
|
3098
3308
|
action_scope: WalletActionScope,
|
|
3099
|
-
extra_conditions:
|
|
3309
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3100
3310
|
) -> EndpointResult:
|
|
3101
3311
|
wallet_id = uint32(request["wallet_id"])
|
|
3102
3312
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
3103
3313
|
assert dao_wallet is not None
|
|
3104
3314
|
|
|
3105
3315
|
if request["proposal_type"] == "spend":
|
|
3106
|
-
amounts:
|
|
3107
|
-
puzzle_hashes:
|
|
3108
|
-
asset_types:
|
|
3109
|
-
additions: Optional[
|
|
3316
|
+
amounts: list[uint64] = []
|
|
3317
|
+
puzzle_hashes: list[bytes32] = []
|
|
3318
|
+
asset_types: list[Optional[bytes32]] = []
|
|
3319
|
+
additions: Optional[list[dict[str, Any]]] = request.get("additions")
|
|
3110
3320
|
if additions is not None:
|
|
3111
3321
|
for addition in additions:
|
|
3112
3322
|
if "asset_id" in addition:
|
|
@@ -3183,7 +3393,7 @@ class WalletRpcApi:
|
|
|
3183
3393
|
return {
|
|
3184
3394
|
"success": True,
|
|
3185
3395
|
# Semantics guarantee proposal_id here
|
|
3186
|
-
"proposal_id": proposal_id,
|
|
3396
|
+
"proposal_id": proposal_id,
|
|
3187
3397
|
"tx_id": None, # tx_endpoint wrapper will take care of this
|
|
3188
3398
|
"tx": None, # tx_endpoint wrapper will take care of this
|
|
3189
3399
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
@@ -3192,9 +3402,9 @@ class WalletRpcApi:
|
|
|
3192
3402
|
@tx_endpoint(push=True)
|
|
3193
3403
|
async def dao_vote_on_proposal(
|
|
3194
3404
|
self,
|
|
3195
|
-
request:
|
|
3405
|
+
request: dict[str, Any],
|
|
3196
3406
|
action_scope: WalletActionScope,
|
|
3197
|
-
extra_conditions:
|
|
3407
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3198
3408
|
) -> EndpointResult:
|
|
3199
3409
|
wallet_id = uint32(request["wallet_id"])
|
|
3200
3410
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
@@ -3218,7 +3428,7 @@ class WalletRpcApi:
|
|
|
3218
3428
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
3219
3429
|
}
|
|
3220
3430
|
|
|
3221
|
-
async def dao_parse_proposal(self, request:
|
|
3431
|
+
async def dao_parse_proposal(self, request: dict[str, Any]) -> EndpointResult:
|
|
3222
3432
|
wallet_id = uint32(request["wallet_id"])
|
|
3223
3433
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
3224
3434
|
assert dao_wallet is not None
|
|
@@ -3230,9 +3440,9 @@ class WalletRpcApi:
|
|
|
3230
3440
|
@tx_endpoint(push=True)
|
|
3231
3441
|
async def dao_close_proposal(
|
|
3232
3442
|
self,
|
|
3233
|
-
request:
|
|
3443
|
+
request: dict[str, Any],
|
|
3234
3444
|
action_scope: WalletActionScope,
|
|
3235
|
-
extra_conditions:
|
|
3445
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3236
3446
|
) -> EndpointResult:
|
|
3237
3447
|
wallet_id = uint32(request["wallet_id"])
|
|
3238
3448
|
dao_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DAOWallet)
|
|
@@ -3261,9 +3471,9 @@ class WalletRpcApi:
|
|
|
3261
3471
|
@tx_endpoint(push=True)
|
|
3262
3472
|
async def dao_free_coins_from_finished_proposals(
|
|
3263
3473
|
self,
|
|
3264
|
-
request:
|
|
3474
|
+
request: dict[str, Any],
|
|
3265
3475
|
action_scope: WalletActionScope,
|
|
3266
|
-
extra_conditions:
|
|
3476
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3267
3477
|
) -> EndpointResult:
|
|
3268
3478
|
wallet_id = uint32(request["wallet_id"])
|
|
3269
3479
|
fee = uint64(request.get("fee", 0))
|
|
@@ -3288,9 +3498,9 @@ class WalletRpcApi:
|
|
|
3288
3498
|
@tx_endpoint(push=True)
|
|
3289
3499
|
async def nft_mint_nft(
|
|
3290
3500
|
self,
|
|
3291
|
-
request:
|
|
3501
|
+
request: dict[str, Any],
|
|
3292
3502
|
action_scope: WalletActionScope,
|
|
3293
|
-
extra_conditions:
|
|
3503
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3294
3504
|
) -> EndpointResult:
|
|
3295
3505
|
log.debug("Got minting RPC request: %s", request)
|
|
3296
3506
|
wallet_id = uint32(request["wallet_id"])
|
|
@@ -3303,14 +3513,18 @@ class WalletRpcApi:
|
|
|
3303
3513
|
if isinstance(royalty_address, str):
|
|
3304
3514
|
royalty_puzhash = decode_puzzle_hash(royalty_address)
|
|
3305
3515
|
elif royalty_address is None:
|
|
3306
|
-
royalty_puzhash = await nft_wallet.standard_wallet.
|
|
3516
|
+
royalty_puzhash = await nft_wallet.standard_wallet.get_puzzle_hash(
|
|
3517
|
+
new=not action_scope.config.tx_config.reuse_puzhash
|
|
3518
|
+
)
|
|
3307
3519
|
else:
|
|
3308
3520
|
royalty_puzhash = royalty_address
|
|
3309
3521
|
target_address = request.get("target_address")
|
|
3310
3522
|
if isinstance(target_address, str):
|
|
3311
3523
|
target_puzhash = decode_puzzle_hash(target_address)
|
|
3312
3524
|
elif target_address is None:
|
|
3313
|
-
target_puzhash = await nft_wallet.standard_wallet.
|
|
3525
|
+
target_puzhash = await nft_wallet.standard_wallet.get_puzzle_hash(
|
|
3526
|
+
new=not action_scope.config.tx_config.reuse_puzhash
|
|
3527
|
+
)
|
|
3314
3528
|
else:
|
|
3315
3529
|
target_puzhash = target_address
|
|
3316
3530
|
if "uris" not in request:
|
|
@@ -3361,7 +3575,7 @@ class WalletRpcApi:
|
|
|
3361
3575
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
3362
3576
|
}
|
|
3363
3577
|
|
|
3364
|
-
async def nft_count_nfts(self, request:
|
|
3578
|
+
async def nft_count_nfts(self, request: dict[str, Any]) -> EndpointResult:
|
|
3365
3579
|
wallet_id = request.get("wallet_id", None)
|
|
3366
3580
|
count = 0
|
|
3367
3581
|
if wallet_id is not None:
|
|
@@ -3375,9 +3589,9 @@ class WalletRpcApi:
|
|
|
3375
3589
|
count = await self.service.wallet_state_manager.nft_store.count()
|
|
3376
3590
|
return {"wallet_id": wallet_id, "success": True, "count": count}
|
|
3377
3591
|
|
|
3378
|
-
async def nft_get_nfts(self, request:
|
|
3592
|
+
async def nft_get_nfts(self, request: dict[str, Any]) -> EndpointResult:
|
|
3379
3593
|
wallet_id = request.get("wallet_id", None)
|
|
3380
|
-
nfts:
|
|
3594
|
+
nfts: list[NFTCoinInfo] = []
|
|
3381
3595
|
if wallet_id is not None:
|
|
3382
3596
|
nft_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=NFTWallet)
|
|
3383
3597
|
else:
|
|
@@ -3403,9 +3617,9 @@ class WalletRpcApi:
|
|
|
3403
3617
|
@tx_endpoint(push=True)
|
|
3404
3618
|
async def nft_set_nft_did(
|
|
3405
3619
|
self,
|
|
3406
|
-
request:
|
|
3620
|
+
request: dict[str, Any],
|
|
3407
3621
|
action_scope: WalletActionScope,
|
|
3408
|
-
extra_conditions:
|
|
3622
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3409
3623
|
) -> EndpointResult:
|
|
3410
3624
|
wallet_id = uint32(request["wallet_id"])
|
|
3411
3625
|
nft_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=NFTWallet)
|
|
@@ -3436,9 +3650,9 @@ class WalletRpcApi:
|
|
|
3436
3650
|
@tx_endpoint(push=True)
|
|
3437
3651
|
async def nft_set_did_bulk(
|
|
3438
3652
|
self,
|
|
3439
|
-
request:
|
|
3653
|
+
request: dict[str, Any],
|
|
3440
3654
|
action_scope: WalletActionScope,
|
|
3441
|
-
extra_conditions:
|
|
3655
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3442
3656
|
) -> EndpointResult:
|
|
3443
3657
|
"""
|
|
3444
3658
|
Bulk set DID for NFTs across different wallets.
|
|
@@ -3454,7 +3668,7 @@ class WalletRpcApi:
|
|
|
3454
3668
|
did_id = request.get("did_id", b"")
|
|
3455
3669
|
if did_id != b"":
|
|
3456
3670
|
did_id = decode_puzzle_hash(did_id)
|
|
3457
|
-
nft_dict:
|
|
3671
|
+
nft_dict: dict[uint32, list[NFTCoinInfo]] = {}
|
|
3458
3672
|
coin_ids = []
|
|
3459
3673
|
nft_ids = []
|
|
3460
3674
|
fee = uint64(request.get("fee", 0))
|
|
@@ -3514,9 +3728,9 @@ class WalletRpcApi:
|
|
|
3514
3728
|
@tx_endpoint(push=True)
|
|
3515
3729
|
async def nft_transfer_bulk(
|
|
3516
3730
|
self,
|
|
3517
|
-
request:
|
|
3731
|
+
request: dict[str, Any],
|
|
3518
3732
|
action_scope: WalletActionScope,
|
|
3519
|
-
extra_conditions:
|
|
3733
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3520
3734
|
) -> EndpointResult:
|
|
3521
3735
|
"""
|
|
3522
3736
|
Bulk transfer NFTs to an address.
|
|
@@ -3534,7 +3748,7 @@ class WalletRpcApi:
|
|
|
3534
3748
|
puzzle_hash = decode_puzzle_hash(address)
|
|
3535
3749
|
else:
|
|
3536
3750
|
return dict(success=False, error="target_address parameter missing")
|
|
3537
|
-
nft_dict:
|
|
3751
|
+
nft_dict: dict[uint32, list[NFTCoinInfo]] = {}
|
|
3538
3752
|
coin_ids = []
|
|
3539
3753
|
fee = uint64(request.get("fee", 0))
|
|
3540
3754
|
|
|
@@ -3585,7 +3799,7 @@ class WalletRpcApi:
|
|
|
3585
3799
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
3586
3800
|
}
|
|
3587
3801
|
|
|
3588
|
-
async def nft_get_by_did(self, request:
|
|
3802
|
+
async def nft_get_by_did(self, request: dict[str, Any]) -> EndpointResult:
|
|
3589
3803
|
did_id: Optional[bytes32] = None
|
|
3590
3804
|
if request.get("did_id", None) is not None:
|
|
3591
3805
|
did_id = decode_puzzle_hash(request["did_id"])
|
|
@@ -3594,7 +3808,7 @@ class WalletRpcApi:
|
|
|
3594
3808
|
return {"wallet_id": wallet.wallet_id, "success": True}
|
|
3595
3809
|
return {"error": f"Cannot find a NFT wallet DID = {did_id}", "success": False}
|
|
3596
3810
|
|
|
3597
|
-
async def nft_get_wallet_did(self, request:
|
|
3811
|
+
async def nft_get_wallet_did(self, request: dict[str, Any]) -> EndpointResult:
|
|
3598
3812
|
wallet_id = uint32(request["wallet_id"])
|
|
3599
3813
|
nft_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=NFTWallet)
|
|
3600
3814
|
did_bytes: Optional[bytes32] = nft_wallet.get_did()
|
|
@@ -3603,9 +3817,9 @@ class WalletRpcApi:
|
|
|
3603
3817
|
did_id = encode_puzzle_hash(did_bytes, AddressType.DID.hrp(self.service.config))
|
|
3604
3818
|
return {"success": True, "did_id": None if len(did_id) == 0 else did_id}
|
|
3605
3819
|
|
|
3606
|
-
async def nft_get_wallets_with_dids(self, request:
|
|
3820
|
+
async def nft_get_wallets_with_dids(self, request: dict[str, Any]) -> EndpointResult:
|
|
3607
3821
|
all_wallets = self.service.wallet_state_manager.wallets.values()
|
|
3608
|
-
did_wallets_by_did_id:
|
|
3822
|
+
did_wallets_by_did_id: dict[bytes32, uint32] = {}
|
|
3609
3823
|
|
|
3610
3824
|
for wallet in all_wallets:
|
|
3611
3825
|
if wallet.type() == WalletType.DECENTRALIZED_ID:
|
|
@@ -3613,7 +3827,7 @@ class WalletRpcApi:
|
|
|
3613
3827
|
if wallet.did_info.origin_coin is not None:
|
|
3614
3828
|
did_wallets_by_did_id[wallet.did_info.origin_coin.name()] = wallet.id()
|
|
3615
3829
|
|
|
3616
|
-
did_nft_wallets:
|
|
3830
|
+
did_nft_wallets: list[dict[str, Any]] = []
|
|
3617
3831
|
for wallet in all_wallets:
|
|
3618
3832
|
if isinstance(wallet, NFTWallet):
|
|
3619
3833
|
nft_wallet_did: Optional[bytes32] = wallet.get_did()
|
|
@@ -3631,7 +3845,7 @@ class WalletRpcApi:
|
|
|
3631
3845
|
)
|
|
3632
3846
|
return {"success": True, "nft_wallets": did_nft_wallets}
|
|
3633
3847
|
|
|
3634
|
-
async def nft_set_nft_status(self, request:
|
|
3848
|
+
async def nft_set_nft_status(self, request: dict[str, Any]) -> EndpointResult:
|
|
3635
3849
|
wallet_id: uint32 = uint32(request["wallet_id"])
|
|
3636
3850
|
coin_id: bytes32 = bytes32.from_hexstr(request["coin_id"])
|
|
3637
3851
|
status: bool = request["in_transaction"]
|
|
@@ -3643,9 +3857,9 @@ class WalletRpcApi:
|
|
|
3643
3857
|
@tx_endpoint(push=True)
|
|
3644
3858
|
async def nft_transfer_nft(
|
|
3645
3859
|
self,
|
|
3646
|
-
request:
|
|
3860
|
+
request: dict[str, Any],
|
|
3647
3861
|
action_scope: WalletActionScope,
|
|
3648
|
-
extra_conditions:
|
|
3862
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3649
3863
|
) -> EndpointResult:
|
|
3650
3864
|
wallet_id = uint32(request["wallet_id"])
|
|
3651
3865
|
address = request["target_address"]
|
|
@@ -3686,7 +3900,7 @@ class WalletRpcApi:
|
|
|
3686
3900
|
log.exception(f"Failed to transfer NFT: {e}")
|
|
3687
3901
|
return {"success": False, "error": str(e)}
|
|
3688
3902
|
|
|
3689
|
-
async def nft_get_info(self, request:
|
|
3903
|
+
async def nft_get_info(self, request: dict[str, Any]) -> EndpointResult:
|
|
3690
3904
|
if "coin_id" not in request:
|
|
3691
3905
|
return {"success": False, "error": "Coin ID is required."}
|
|
3692
3906
|
coin_id = request["coin_id"]
|
|
@@ -3726,7 +3940,7 @@ class WalletRpcApi:
|
|
|
3726
3940
|
)
|
|
3727
3941
|
|
|
3728
3942
|
# Get launcher coin
|
|
3729
|
-
launcher_coin:
|
|
3943
|
+
launcher_coin: list[CoinState] = await self.service.wallet_state_manager.wallet_node.get_coin_state(
|
|
3730
3944
|
[uncurried_nft.singleton_launcher_id], peer=peer
|
|
3731
3945
|
)
|
|
3732
3946
|
if launcher_coin is None or len(launcher_coin) < 1 or launcher_coin[0].spent_height is None:
|
|
@@ -3755,9 +3969,9 @@ class WalletRpcApi:
|
|
|
3755
3969
|
@tx_endpoint(push=True)
|
|
3756
3970
|
async def nft_add_uri(
|
|
3757
3971
|
self,
|
|
3758
|
-
request:
|
|
3972
|
+
request: dict[str, Any],
|
|
3759
3973
|
action_scope: WalletActionScope,
|
|
3760
|
-
extra_conditions:
|
|
3974
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3761
3975
|
) -> EndpointResult:
|
|
3762
3976
|
wallet_id = uint32(request["wallet_id"])
|
|
3763
3977
|
# Note metadata updater can only add one uri for one field per spend.
|
|
@@ -3783,7 +3997,7 @@ class WalletRpcApi:
|
|
|
3783
3997
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
3784
3998
|
}
|
|
3785
3999
|
|
|
3786
|
-
async def nft_calculate_royalties(self, request:
|
|
4000
|
+
async def nft_calculate_royalties(self, request: dict[str, Any]) -> EndpointResult:
|
|
3787
4001
|
return NFTWallet.royalty_calculation(
|
|
3788
4002
|
{
|
|
3789
4003
|
asset["asset"]: (asset["royalty_address"], uint16(asset["royalty_percentage"]))
|
|
@@ -3795,9 +4009,9 @@ class WalletRpcApi:
|
|
|
3795
4009
|
@tx_endpoint(push=False)
|
|
3796
4010
|
async def nft_mint_bulk(
|
|
3797
4011
|
self,
|
|
3798
|
-
request:
|
|
4012
|
+
request: dict[str, Any],
|
|
3799
4013
|
action_scope: WalletActionScope,
|
|
3800
|
-
extra_conditions:
|
|
4014
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3801
4015
|
) -> EndpointResult:
|
|
3802
4016
|
if action_scope.config.push:
|
|
3803
4017
|
raise ValueError("Automatic pushing of nft minting transactions not yet available") # pragma: no cover
|
|
@@ -3808,7 +4022,7 @@ class WalletRpcApi:
|
|
|
3808
4022
|
royalty_address = request.get("royalty_address", None)
|
|
3809
4023
|
if isinstance(royalty_address, str) and royalty_address != "":
|
|
3810
4024
|
royalty_puzhash = decode_puzzle_hash(royalty_address)
|
|
3811
|
-
elif royalty_address in
|
|
4025
|
+
elif royalty_address in {None, ""}:
|
|
3812
4026
|
royalty_puzhash = await nft_wallet.standard_wallet.get_new_puzzlehash()
|
|
3813
4027
|
else:
|
|
3814
4028
|
royalty_puzhash = bytes32.from_hexstr(royalty_address)
|
|
@@ -3924,7 +4138,7 @@ class WalletRpcApi:
|
|
|
3924
4138
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
3925
4139
|
}
|
|
3926
4140
|
|
|
3927
|
-
async def get_coin_records(self, request:
|
|
4141
|
+
async def get_coin_records(self, request: dict[str, Any]) -> EndpointResult:
|
|
3928
4142
|
parsed_request = GetCoinRecords.from_json_dict(request)
|
|
3929
4143
|
|
|
3930
4144
|
if parsed_request.limit != uint32.MAXIMUM and parsed_request.limit > self.max_get_coin_records_limit:
|
|
@@ -3966,8 +4180,8 @@ class WalletRpcApi:
|
|
|
3966
4180
|
"total_count": result.total_count,
|
|
3967
4181
|
}
|
|
3968
4182
|
|
|
3969
|
-
async def get_farmed_amount(self, request:
|
|
3970
|
-
tx_records:
|
|
4183
|
+
async def get_farmed_amount(self, request: dict[str, Any]) -> EndpointResult:
|
|
4184
|
+
tx_records: list[TransactionRecord] = await self.service.wallet_state_manager.tx_store.get_farming_rewards()
|
|
3971
4185
|
amount = 0
|
|
3972
4186
|
pool_reward_amount = 0
|
|
3973
4187
|
farmer_reward_amount = 0
|
|
@@ -4013,9 +4227,9 @@ class WalletRpcApi:
|
|
|
4013
4227
|
@tx_endpoint(push=False)
|
|
4014
4228
|
async def create_signed_transaction(
|
|
4015
4229
|
self,
|
|
4016
|
-
request:
|
|
4230
|
+
request: dict[str, Any],
|
|
4017
4231
|
action_scope: WalletActionScope,
|
|
4018
|
-
extra_conditions:
|
|
4232
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4019
4233
|
hold_lock: bool = True,
|
|
4020
4234
|
) -> EndpointResult:
|
|
4021
4235
|
if "wallet_id" in request:
|
|
@@ -4031,7 +4245,7 @@ class WalletRpcApi:
|
|
|
4031
4245
|
if "additions" not in request or len(request["additions"]) < 1:
|
|
4032
4246
|
raise ValueError("Specify additions list")
|
|
4033
4247
|
|
|
4034
|
-
additions:
|
|
4248
|
+
additions: list[dict[str, Any]] = request["additions"]
|
|
4035
4249
|
amount_0: uint64 = uint64(additions[0]["amount"])
|
|
4036
4250
|
assert amount_0 <= self.service.constants.MAX_COIN_AMOUNT
|
|
4037
4251
|
puzzle_hash_0 = bytes32.from_hexstr(additions[0]["puzzle_hash"])
|
|
@@ -4040,7 +4254,7 @@ class WalletRpcApi:
|
|
|
4040
4254
|
|
|
4041
4255
|
memos_0 = [] if "memos" not in additions[0] else [mem.encode("utf-8") for mem in additions[0]["memos"]]
|
|
4042
4256
|
|
|
4043
|
-
additional_outputs:
|
|
4257
|
+
additional_outputs: list[Payment] = []
|
|
4044
4258
|
for addition in additions[1:]:
|
|
4045
4259
|
receiver_ph = bytes32.from_hexstr(addition["puzzle_hash"])
|
|
4046
4260
|
if len(receiver_ph) != 32:
|
|
@@ -4147,9 +4361,9 @@ class WalletRpcApi:
|
|
|
4147
4361
|
@tx_endpoint(push=True)
|
|
4148
4362
|
async def pw_join_pool(
|
|
4149
4363
|
self,
|
|
4150
|
-
request:
|
|
4364
|
+
request: dict[str, Any],
|
|
4151
4365
|
action_scope: WalletActionScope,
|
|
4152
|
-
extra_conditions:
|
|
4366
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4153
4367
|
) -> EndpointResult:
|
|
4154
4368
|
fee = uint64(request.get("fee", 0))
|
|
4155
4369
|
wallet_id = uint32(request["wallet_id"])
|
|
@@ -4185,9 +4399,9 @@ class WalletRpcApi:
|
|
|
4185
4399
|
@tx_endpoint(push=True)
|
|
4186
4400
|
async def pw_self_pool(
|
|
4187
4401
|
self,
|
|
4188
|
-
request:
|
|
4402
|
+
request: dict[str, Any],
|
|
4189
4403
|
action_scope: WalletActionScope,
|
|
4190
|
-
extra_conditions:
|
|
4404
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4191
4405
|
) -> EndpointResult:
|
|
4192
4406
|
# Leaving a pool requires two state transitions.
|
|
4193
4407
|
# First we transition to PoolSingletonState.LEAVING_POOL
|
|
@@ -4211,9 +4425,9 @@ class WalletRpcApi:
|
|
|
4211
4425
|
@tx_endpoint(push=True)
|
|
4212
4426
|
async def pw_absorb_rewards(
|
|
4213
4427
|
self,
|
|
4214
|
-
request:
|
|
4428
|
+
request: dict[str, Any],
|
|
4215
4429
|
action_scope: WalletActionScope,
|
|
4216
|
-
extra_conditions:
|
|
4430
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4217
4431
|
) -> EndpointResult:
|
|
4218
4432
|
"""Perform a sweep of the p2_singleton rewards controlled by the pool wallet singleton"""
|
|
4219
4433
|
if await self.service.wallet_state_manager.synced() is False:
|
|
@@ -4234,14 +4448,14 @@ class WalletRpcApi:
|
|
|
4234
4448
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
4235
4449
|
}
|
|
4236
4450
|
|
|
4237
|
-
async def pw_status(self, request:
|
|
4451
|
+
async def pw_status(self, request: dict[str, Any]) -> EndpointResult:
|
|
4238
4452
|
"""Return the complete state of the Pool wallet with id `request["wallet_id"]`"""
|
|
4239
4453
|
wallet_id = uint32(request["wallet_id"])
|
|
4240
4454
|
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=PoolWallet)
|
|
4241
4455
|
|
|
4242
4456
|
assert isinstance(wallet, PoolWallet)
|
|
4243
4457
|
state: PoolWalletInfo = await wallet.get_current_state()
|
|
4244
|
-
unconfirmed_transactions:
|
|
4458
|
+
unconfirmed_transactions: list[TransactionRecord] = await wallet.get_unconfirmed_transactions()
|
|
4245
4459
|
return {
|
|
4246
4460
|
"state": state.to_json_dict(),
|
|
4247
4461
|
"unconfirmed_transactions": unconfirmed_transactions,
|
|
@@ -4253,9 +4467,9 @@ class WalletRpcApi:
|
|
|
4253
4467
|
@tx_endpoint(push=True)
|
|
4254
4468
|
async def create_new_dl(
|
|
4255
4469
|
self,
|
|
4256
|
-
request:
|
|
4470
|
+
request: dict[str, Any],
|
|
4257
4471
|
action_scope: WalletActionScope,
|
|
4258
|
-
extra_conditions:
|
|
4472
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4259
4473
|
) -> EndpointResult:
|
|
4260
4474
|
"""Initialize the DataLayer Wallet (only one can exist)"""
|
|
4261
4475
|
if self.service.wallet_state_manager is None:
|
|
@@ -4284,7 +4498,7 @@ class WalletRpcApi:
|
|
|
4284
4498
|
"launcher_id": launcher_id,
|
|
4285
4499
|
}
|
|
4286
4500
|
|
|
4287
|
-
async def dl_track_new(self, request:
|
|
4501
|
+
async def dl_track_new(self, request: dict[str, Any]) -> EndpointResult:
|
|
4288
4502
|
"""Initialize the DataLayer Wallet (only one can exist)"""
|
|
4289
4503
|
if self.service.wallet_state_manager is None:
|
|
4290
4504
|
raise ValueError("The wallet service is not currently initialized")
|
|
@@ -4309,7 +4523,7 @@ class WalletRpcApi:
|
|
|
4309
4523
|
continue # try some other peers, maybe someone has it
|
|
4310
4524
|
return {}
|
|
4311
4525
|
|
|
4312
|
-
async def dl_stop_tracking(self, request:
|
|
4526
|
+
async def dl_stop_tracking(self, request: dict[str, Any]) -> EndpointResult:
|
|
4313
4527
|
"""Initialize the DataLayer Wallet (only one can exist)"""
|
|
4314
4528
|
if self.service.wallet_state_manager is None:
|
|
4315
4529
|
raise ValueError("The wallet service is not currently initialized")
|
|
@@ -4318,7 +4532,7 @@ class WalletRpcApi:
|
|
|
4318
4532
|
await dl_wallet.stop_tracking_singleton(bytes32.from_hexstr(request["launcher_id"]))
|
|
4319
4533
|
return {}
|
|
4320
4534
|
|
|
4321
|
-
async def dl_latest_singleton(self, request:
|
|
4535
|
+
async def dl_latest_singleton(self, request: dict[str, Any]) -> EndpointResult:
|
|
4322
4536
|
"""Get the singleton record for the latest singleton of a launcher ID"""
|
|
4323
4537
|
if self.service.wallet_state_manager is None:
|
|
4324
4538
|
raise ValueError("The wallet service is not currently initialized")
|
|
@@ -4330,7 +4544,7 @@ class WalletRpcApi:
|
|
|
4330
4544
|
record = await wallet.get_latest_singleton(bytes32.from_hexstr(request["launcher_id"]), only_confirmed)
|
|
4331
4545
|
return {"singleton": None if record is None else record.to_json_dict()}
|
|
4332
4546
|
|
|
4333
|
-
async def dl_singletons_by_root(self, request:
|
|
4547
|
+
async def dl_singletons_by_root(self, request: dict[str, Any]) -> EndpointResult:
|
|
4334
4548
|
"""Get the singleton records that contain the specified root"""
|
|
4335
4549
|
if self.service.wallet_state_manager is None:
|
|
4336
4550
|
raise ValueError("The wallet service is not currently initialized")
|
|
@@ -4345,9 +4559,9 @@ class WalletRpcApi:
|
|
|
4345
4559
|
@tx_endpoint(push=True)
|
|
4346
4560
|
async def dl_update_root(
|
|
4347
4561
|
self,
|
|
4348
|
-
request:
|
|
4562
|
+
request: dict[str, Any],
|
|
4349
4563
|
action_scope: WalletActionScope,
|
|
4350
|
-
extra_conditions:
|
|
4564
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4351
4565
|
) -> EndpointResult:
|
|
4352
4566
|
"""Get the singleton record for the latest singleton of a launcher ID"""
|
|
4353
4567
|
if self.service.wallet_state_manager is None:
|
|
@@ -4371,9 +4585,9 @@ class WalletRpcApi:
|
|
|
4371
4585
|
@tx_endpoint(push=True)
|
|
4372
4586
|
async def dl_update_multiple(
|
|
4373
4587
|
self,
|
|
4374
|
-
request:
|
|
4588
|
+
request: dict[str, Any],
|
|
4375
4589
|
action_scope: WalletActionScope,
|
|
4376
|
-
extra_conditions:
|
|
4590
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4377
4591
|
) -> EndpointResult:
|
|
4378
4592
|
"""Update multiple singletons with new merkle roots"""
|
|
4379
4593
|
if self.service.wallet_state_manager is None:
|
|
@@ -4397,7 +4611,7 @@ class WalletRpcApi:
|
|
|
4397
4611
|
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
4398
4612
|
}
|
|
4399
4613
|
|
|
4400
|
-
async def dl_history(self, request:
|
|
4614
|
+
async def dl_history(self, request: dict[str, Any]) -> EndpointResult:
|
|
4401
4615
|
"""Get the singleton record for the latest singleton of a launcher ID"""
|
|
4402
4616
|
if self.service.wallet_state_manager is None:
|
|
4403
4617
|
raise ValueError("The wallet service is not currently initialized")
|
|
@@ -4416,7 +4630,7 @@ class WalletRpcApi:
|
|
|
4416
4630
|
history_json = [rec.to_json_dict() for rec in history]
|
|
4417
4631
|
return {"history": history_json, "count": len(history_json)}
|
|
4418
4632
|
|
|
4419
|
-
async def dl_owned_singletons(self, request:
|
|
4633
|
+
async def dl_owned_singletons(self, request: dict[str, Any]) -> EndpointResult:
|
|
4420
4634
|
"""Get all owned singleton records"""
|
|
4421
4635
|
if self.service.wallet_state_manager is None:
|
|
4422
4636
|
raise ValueError("The wallet service is not currently initialized")
|
|
@@ -4431,7 +4645,7 @@ class WalletRpcApi:
|
|
|
4431
4645
|
|
|
4432
4646
|
return {"singletons": singletons_json, "count": len(singletons_json)}
|
|
4433
4647
|
|
|
4434
|
-
async def dl_get_mirrors(self, request:
|
|
4648
|
+
async def dl_get_mirrors(self, request: dict[str, Any]) -> EndpointResult:
|
|
4435
4649
|
"""Get all of the mirrors for a specific singleton"""
|
|
4436
4650
|
if self.service.wallet_state_manager is None:
|
|
4437
4651
|
raise ValueError("The wallet service is not currently initialized")
|
|
@@ -4446,9 +4660,9 @@ class WalletRpcApi:
|
|
|
4446
4660
|
@tx_endpoint(push=True)
|
|
4447
4661
|
async def dl_new_mirror(
|
|
4448
4662
|
self,
|
|
4449
|
-
request:
|
|
4663
|
+
request: dict[str, Any],
|
|
4450
4664
|
action_scope: WalletActionScope,
|
|
4451
|
-
extra_conditions:
|
|
4665
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4452
4666
|
) -> EndpointResult:
|
|
4453
4667
|
"""Add a new on chain message for a specific singleton"""
|
|
4454
4668
|
if self.service.wallet_state_manager is None:
|
|
@@ -4472,9 +4686,9 @@ class WalletRpcApi:
|
|
|
4472
4686
|
@tx_endpoint(push=True)
|
|
4473
4687
|
async def dl_delete_mirror(
|
|
4474
4688
|
self,
|
|
4475
|
-
request:
|
|
4689
|
+
request: dict[str, Any],
|
|
4476
4690
|
action_scope: WalletActionScope,
|
|
4477
|
-
extra_conditions:
|
|
4691
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4478
4692
|
) -> EndpointResult:
|
|
4479
4693
|
"""Remove an existing mirror for a specific singleton"""
|
|
4480
4694
|
if self.service.wallet_state_manager is None:
|
|
@@ -4497,7 +4711,7 @@ class WalletRpcApi:
|
|
|
4497
4711
|
|
|
4498
4712
|
async def dl_verify_proof(
|
|
4499
4713
|
self,
|
|
4500
|
-
request:
|
|
4714
|
+
request: dict[str, Any],
|
|
4501
4715
|
) -> EndpointResult:
|
|
4502
4716
|
"""Verify a proof of inclusion for a DL singleton"""
|
|
4503
4717
|
res = await dl_verify_proof(
|
|
@@ -4512,12 +4726,13 @@ class WalletRpcApi:
|
|
|
4512
4726
|
# Verified Credential
|
|
4513
4727
|
##########################################################################################
|
|
4514
4728
|
@tx_endpoint(push=True)
|
|
4729
|
+
@marshal
|
|
4515
4730
|
async def vc_mint(
|
|
4516
4731
|
self,
|
|
4517
|
-
request:
|
|
4732
|
+
request: VCMint,
|
|
4518
4733
|
action_scope: WalletActionScope,
|
|
4519
|
-
extra_conditions:
|
|
4520
|
-
) ->
|
|
4734
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4735
|
+
) -> VCMintResponse:
|
|
4521
4736
|
"""
|
|
4522
4737
|
Mint a verified credential using the assigned DID
|
|
4523
4738
|
:param request: We require 'did_id' that will be minting the VC and options for a new 'target_address' as well
|
|
@@ -4525,84 +4740,58 @@ class WalletRpcApi:
|
|
|
4525
4740
|
:return: a 'vc_record' containing all the information of the soon-to-be-confirmed vc as well as any relevant
|
|
4526
4741
|
'transactions'
|
|
4527
4742
|
"""
|
|
4528
|
-
|
|
4529
|
-
@streamable
|
|
4530
|
-
@dataclasses.dataclass(frozen=True)
|
|
4531
|
-
class VCMint(Streamable):
|
|
4532
|
-
did_id: str
|
|
4533
|
-
target_address: Optional[str] = None
|
|
4534
|
-
fee: uint64 = uint64(0)
|
|
4535
|
-
|
|
4536
|
-
parsed_request = VCMint.from_json_dict(request)
|
|
4537
|
-
|
|
4538
|
-
did_id = decode_puzzle_hash(parsed_request.did_id)
|
|
4743
|
+
did_id = decode_puzzle_hash(request.did_id)
|
|
4539
4744
|
puzhash: Optional[bytes32] = None
|
|
4540
|
-
if
|
|
4541
|
-
puzhash = decode_puzzle_hash(
|
|
4745
|
+
if request.target_address is not None:
|
|
4746
|
+
puzhash = decode_puzzle_hash(request.target_address)
|
|
4542
4747
|
|
|
4543
4748
|
vc_wallet: VCWallet = await self.service.wallet_state_manager.get_or_create_vc_wallet()
|
|
4544
4749
|
vc_record = await vc_wallet.launch_new_vc(
|
|
4545
|
-
did_id, action_scope, puzhash,
|
|
4750
|
+
did_id, action_scope, puzhash, request.fee, extra_conditions=extra_conditions
|
|
4546
4751
|
)
|
|
4547
|
-
return
|
|
4548
|
-
"vc_record": vc_record.to_json_dict(),
|
|
4549
|
-
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
4550
|
-
}
|
|
4752
|
+
return VCMintResponse([], [], vc_record)
|
|
4551
4753
|
|
|
4552
|
-
|
|
4754
|
+
@marshal
|
|
4755
|
+
async def vc_get(self, request: VCGet) -> VCGetResponse:
|
|
4553
4756
|
"""
|
|
4554
4757
|
Given a launcher ID get the verified credential
|
|
4555
4758
|
:param request: the 'vc_id' launcher id of a verifiable credential
|
|
4556
4759
|
:return: the 'vc_record' representing the specified verifiable credential
|
|
4557
4760
|
"""
|
|
4761
|
+
vc_record = await self.service.wallet_state_manager.vc_store.get_vc_record(request.vc_id)
|
|
4762
|
+
return VCGetResponse(vc_record)
|
|
4558
4763
|
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
class VCGet(Streamable):
|
|
4562
|
-
vc_id: bytes32
|
|
4563
|
-
|
|
4564
|
-
parsed_request = VCGet.from_json_dict(request)
|
|
4565
|
-
|
|
4566
|
-
vc_record = await self.service.wallet_state_manager.vc_store.get_vc_record(parsed_request.vc_id)
|
|
4567
|
-
return {"vc_record": vc_record}
|
|
4568
|
-
|
|
4569
|
-
async def vc_get_list(self, request: Dict[str, Any]) -> EndpointResult:
|
|
4764
|
+
@marshal
|
|
4765
|
+
async def vc_get_list(self, request: VCGetList) -> VCGetListResponse:
|
|
4570
4766
|
"""
|
|
4571
4767
|
Get a list of verified credentials
|
|
4572
4768
|
:param request: optional parameters for pagination 'start' and 'count'
|
|
4573
4769
|
:return: all 'vc_records' in the specified range and any 'proofs' associated with the roots contained within
|
|
4574
4770
|
"""
|
|
4575
4771
|
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
vc_list = await self.service.wallet_state_manager.vc_store.get_vc_record_list(
|
|
4585
|
-
parsed_request.start, parsed_request.end
|
|
4586
|
-
)
|
|
4587
|
-
return {
|
|
4588
|
-
"vc_records": [{"coin_id": "0x" + vc.vc.coin.name().hex(), **vc.to_json_dict()} for vc in vc_list],
|
|
4589
|
-
"proofs": {
|
|
4590
|
-
rec.vc.proof_hash.hex(): None if fetched_proof is None else fetched_proof.key_value_pairs
|
|
4772
|
+
vc_list = await self.service.wallet_state_manager.vc_store.get_vc_record_list(request.start, request.end)
|
|
4773
|
+
return VCGetListResponse(
|
|
4774
|
+
[VCRecordWithCoinID.from_vc_record(vc) for vc in vc_list],
|
|
4775
|
+
[
|
|
4776
|
+
VCProofWithHash(
|
|
4777
|
+
rec.vc.proof_hash, None if fetched_proof is None else VCProofsRPC.from_vc_proofs(fetched_proof)
|
|
4778
|
+
)
|
|
4591
4779
|
for rec in vc_list
|
|
4592
4780
|
if rec.vc.proof_hash is not None
|
|
4593
4781
|
for fetched_proof in (
|
|
4594
4782
|
await self.service.wallet_state_manager.vc_store.get_proofs_for_root(rec.vc.proof_hash),
|
|
4595
4783
|
)
|
|
4596
|
-
|
|
4597
|
-
|
|
4784
|
+
],
|
|
4785
|
+
)
|
|
4598
4786
|
|
|
4599
4787
|
@tx_endpoint(push=True)
|
|
4788
|
+
@marshal
|
|
4600
4789
|
async def vc_spend(
|
|
4601
4790
|
self,
|
|
4602
|
-
request:
|
|
4791
|
+
request: VCSpend,
|
|
4603
4792
|
action_scope: WalletActionScope,
|
|
4604
|
-
extra_conditions:
|
|
4605
|
-
) ->
|
|
4793
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4794
|
+
) -> VCSpendResponse:
|
|
4606
4795
|
"""
|
|
4607
4796
|
Spend a verified credential
|
|
4608
4797
|
:param request: Required 'vc_id' launcher id of the vc we wish to spend. Optional parameters for a 'new_puzhash'
|
|
@@ -4611,34 +4800,22 @@ class WalletRpcApi:
|
|
|
4611
4800
|
:return: a list of all relevant 'transactions' (TransactionRecord) that this spend generates (VC TX + fee TX)
|
|
4612
4801
|
"""
|
|
4613
4802
|
|
|
4614
|
-
@streamable
|
|
4615
|
-
@dataclasses.dataclass(frozen=True)
|
|
4616
|
-
class VCSpend(Streamable):
|
|
4617
|
-
vc_id: bytes32
|
|
4618
|
-
new_puzhash: Optional[bytes32] = None
|
|
4619
|
-
new_proof_hash: Optional[bytes32] = None
|
|
4620
|
-
provider_inner_puzhash: Optional[bytes32] = None
|
|
4621
|
-
fee: uint64 = uint64(0)
|
|
4622
|
-
|
|
4623
|
-
parsed_request = VCSpend.from_json_dict(request)
|
|
4624
|
-
|
|
4625
4803
|
vc_wallet: VCWallet = await self.service.wallet_state_manager.get_or_create_vc_wallet()
|
|
4626
4804
|
|
|
4627
4805
|
await vc_wallet.generate_signed_transaction(
|
|
4628
|
-
|
|
4806
|
+
request.vc_id,
|
|
4629
4807
|
action_scope,
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
new_proof_hash=
|
|
4633
|
-
provider_inner_puzhash=
|
|
4808
|
+
request.fee,
|
|
4809
|
+
request.new_puzhash,
|
|
4810
|
+
new_proof_hash=request.new_proof_hash,
|
|
4811
|
+
provider_inner_puzhash=request.provider_inner_puzhash,
|
|
4634
4812
|
extra_conditions=extra_conditions,
|
|
4635
4813
|
)
|
|
4636
4814
|
|
|
4637
|
-
return
|
|
4638
|
-
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
4639
|
-
}
|
|
4815
|
+
return VCSpendResponse([], []) # tx_endpoint takes care of filling this out
|
|
4640
4816
|
|
|
4641
|
-
|
|
4817
|
+
@marshal
|
|
4818
|
+
async def vc_add_proofs(self, request: VCAddProofs) -> Empty:
|
|
4642
4819
|
"""
|
|
4643
4820
|
Add a set of proofs to the DB that can be used when spending a VC. VCs are near useless until their proofs have
|
|
4644
4821
|
been added.
|
|
@@ -4647,70 +4824,57 @@ class WalletRpcApi:
|
|
|
4647
4824
|
"""
|
|
4648
4825
|
vc_wallet: VCWallet = await self.service.wallet_state_manager.get_or_create_vc_wallet()
|
|
4649
4826
|
|
|
4650
|
-
await vc_wallet.store.add_vc_proofs(
|
|
4827
|
+
await vc_wallet.store.add_vc_proofs(request.to_vc_proofs())
|
|
4651
4828
|
|
|
4652
|
-
return
|
|
4829
|
+
return Empty()
|
|
4653
4830
|
|
|
4654
|
-
|
|
4831
|
+
@marshal
|
|
4832
|
+
async def vc_get_proofs_for_root(self, request: VCGetProofsForRoot) -> VCGetProofsForRootResponse:
|
|
4655
4833
|
"""
|
|
4656
4834
|
Given a specified vc root, get any proofs associated with that root.
|
|
4657
4835
|
:param request: must specify 'root' representing the tree hash of some set of proofs
|
|
4658
4836
|
:return: a dictionary of root hashes mapped to dictionaries of key value pairs of 'proofs'
|
|
4659
4837
|
"""
|
|
4660
4838
|
|
|
4661
|
-
@streamable
|
|
4662
|
-
@dataclasses.dataclass(frozen=True)
|
|
4663
|
-
class VCGetProofsForRoot(Streamable):
|
|
4664
|
-
root: bytes32
|
|
4665
|
-
|
|
4666
|
-
parsed_request = VCGetProofsForRoot.from_json_dict(request)
|
|
4667
4839
|
vc_wallet: VCWallet = await self.service.wallet_state_manager.get_or_create_vc_wallet()
|
|
4668
4840
|
|
|
4669
|
-
vc_proofs: Optional[VCProofs] = await vc_wallet.store.get_proofs_for_root(
|
|
4841
|
+
vc_proofs: Optional[VCProofs] = await vc_wallet.store.get_proofs_for_root(request.root)
|
|
4670
4842
|
if vc_proofs is None:
|
|
4671
4843
|
raise ValueError("no proofs found for specified root") # pragma: no cover
|
|
4672
|
-
return
|
|
4844
|
+
return VCGetProofsForRootResponse.from_vc_proofs(vc_proofs)
|
|
4673
4845
|
|
|
4674
4846
|
@tx_endpoint(push=True)
|
|
4847
|
+
@marshal
|
|
4675
4848
|
async def vc_revoke(
|
|
4676
4849
|
self,
|
|
4677
|
-
request:
|
|
4850
|
+
request: VCRevoke,
|
|
4678
4851
|
action_scope: WalletActionScope,
|
|
4679
|
-
extra_conditions:
|
|
4680
|
-
) ->
|
|
4852
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4853
|
+
) -> VCRevokeResponse:
|
|
4681
4854
|
"""
|
|
4682
4855
|
Revoke an on chain VC provided the correct DID is available
|
|
4683
4856
|
:param request: required 'vc_parent_id' for the VC coin. Standard transaction params 'fee' & 'reuse_puzhash'.
|
|
4684
4857
|
:return: a list of all relevant 'transactions' (TransactionRecord) that this spend generates (VC TX + fee TX)
|
|
4685
4858
|
"""
|
|
4686
4859
|
|
|
4687
|
-
@streamable
|
|
4688
|
-
@dataclasses.dataclass(frozen=True)
|
|
4689
|
-
class VCRevoke(Streamable):
|
|
4690
|
-
vc_parent_id: bytes32
|
|
4691
|
-
fee: uint64 = uint64(0)
|
|
4692
|
-
|
|
4693
|
-
parsed_request = VCRevoke.from_json_dict(request)
|
|
4694
4860
|
vc_wallet: VCWallet = await self.service.wallet_state_manager.get_or_create_vc_wallet()
|
|
4695
4861
|
|
|
4696
4862
|
await vc_wallet.revoke_vc(
|
|
4697
|
-
|
|
4863
|
+
request.vc_parent_id,
|
|
4698
4864
|
self.service.get_full_node_peer(),
|
|
4699
4865
|
action_scope,
|
|
4700
|
-
|
|
4866
|
+
request.fee,
|
|
4701
4867
|
extra_conditions=extra_conditions,
|
|
4702
4868
|
)
|
|
4703
4869
|
|
|
4704
|
-
return
|
|
4705
|
-
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
4706
|
-
}
|
|
4870
|
+
return VCRevokeResponse([], []) # tx_endpoint takes care of filling this out
|
|
4707
4871
|
|
|
4708
4872
|
@tx_endpoint(push=True)
|
|
4709
4873
|
async def crcat_approve_pending(
|
|
4710
4874
|
self,
|
|
4711
|
-
request:
|
|
4875
|
+
request: dict[str, Any],
|
|
4712
4876
|
action_scope: WalletActionScope,
|
|
4713
|
-
extra_conditions:
|
|
4877
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4714
4878
|
) -> EndpointResult:
|
|
4715
4879
|
"""
|
|
4716
4880
|
Moving any "pending approval" CR-CATs into the spendable balance of the wallet
|