chia-blockchain 2.5.7rc4__py3-none-any.whl → 2.5.8rc1__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/__init__.py +8 -4
- chia/_tests/blockchain/blockchain_test_utils.py +6 -8
- chia/_tests/blockchain/test_augmented_chain.py +4 -4
- chia/_tests/blockchain/test_blockchain.py +165 -190
- chia/_tests/blockchain/test_build_chains.py +2 -4
- chia/_tests/blockchain/test_get_block_generator.py +2 -3
- chia/_tests/clvm/coin_store.py +4 -7
- chia/_tests/clvm/test_clvm_step.py +4 -4
- chia/_tests/clvm/test_puzzle_compression.py +2 -1
- chia/_tests/clvm/test_puzzle_drivers.py +2 -2
- chia/_tests/clvm/test_singletons.py +2 -4
- chia/_tests/clvm/test_spend_sim.py +2 -2
- chia/_tests/cmds/cmd_test_utils.py +27 -45
- chia/_tests/cmds/test_cmd_framework.py +6 -6
- chia/_tests/cmds/test_daemon.py +3 -3
- chia/_tests/cmds/test_show.py +4 -4
- chia/_tests/cmds/test_tx_config_args.py +1 -2
- chia/_tests/cmds/testing_classes.py +4 -5
- chia/_tests/cmds/wallet/test_did.py +24 -27
- chia/_tests/cmds/wallet/test_nft.py +12 -10
- chia/_tests/cmds/wallet/test_vcs.py +11 -12
- chia/_tests/cmds/wallet/test_wallet.py +134 -89
- chia/_tests/conftest.py +59 -30
- chia/_tests/connection_utils.py +2 -2
- chia/_tests/core/cmds/test_beta.py +4 -4
- chia/_tests/core/cmds/test_keys.py +2 -3
- chia/_tests/core/cmds/test_wallet.py +15 -15
- chia/_tests/core/consensus/test_pot_iterations.py +19 -73
- chia/_tests/core/custom_types/test_proof_of_space.py +124 -98
- chia/_tests/core/daemon/test_daemon.py +11 -11
- chia/_tests/core/data_layer/conftest.py +2 -2
- chia/_tests/core/data_layer/test_data_rpc.py +28 -14
- chia/_tests/core/data_layer/test_data_store.py +10 -10
- chia/_tests/core/data_layer/util.py +11 -11
- chia/_tests/core/farmer/test_farmer_api.py +2 -4
- chia/_tests/core/full_node/full_sync/test_full_sync.py +8 -7
- chia/_tests/core/full_node/stores/test_block_store.py +5 -4
- chia/_tests/core/full_node/stores/test_coin_store.py +5 -11
- chia/_tests/core/full_node/stores/test_full_node_store.py +8 -8
- chia/_tests/core/full_node/stores/test_hint_store.py +2 -2
- chia/_tests/core/full_node/test_block_height_map.py +3 -4
- chia/_tests/core/full_node/test_conditions.py +21 -23
- chia/_tests/core/full_node/test_full_node.py +225 -62
- chia/_tests/core/full_node/test_hint_management.py +2 -4
- chia/_tests/core/full_node/test_performance.py +0 -1
- chia/_tests/core/full_node/test_prev_tx_block.py +88 -11
- chia/_tests/core/full_node/test_transactions.py +1 -2
- chia/_tests/core/full_node/test_tx_processing_queue.py +109 -25
- chia/_tests/core/mempool/test_mempool.py +29 -37
- chia/_tests/core/mempool/test_mempool_fee_estimator.py +39 -39
- chia/_tests/core/mempool/test_mempool_fee_protocol.py +2 -6
- chia/_tests/core/mempool/test_mempool_manager.py +963 -839
- chia/_tests/core/mempool/test_singleton_fast_forward.py +6 -6
- chia/_tests/core/server/serve.py +7 -7
- chia/_tests/core/server/test_dos.py +1 -2
- chia/_tests/core/server/test_event_loop.py +12 -4
- chia/_tests/core/server/test_loop.py +7 -8
- chia/_tests/core/server/test_rate_limits.py +9 -8
- chia/_tests/core/server/test_server.py +61 -1
- chia/_tests/core/services/test_services.py +2 -2
- chia/_tests/core/ssl/test_ssl.py +2 -2
- chia/_tests/core/test_cost_calculation.py +2 -6
- chia/_tests/core/test_farmer_harvester_rpc.py +3 -5
- chia/_tests/core/test_filter.py +0 -1
- chia/_tests/core/test_full_node_rpc.py +2 -2
- chia/_tests/core/test_merkle_set.py +1 -2
- chia/_tests/core/test_seeder.py +4 -4
- chia/_tests/core/util/test_config.py +4 -4
- chia/_tests/core/util/test_jsonify.py +2 -2
- chia/_tests/core/util/test_keychain.py +3 -3
- chia/_tests/core/util/test_lockfile.py +2 -1
- chia/_tests/core/util/test_log_exceptions.py +1 -2
- chia/_tests/core/util/test_streamable.py +17 -17
- chia/_tests/db/test_db_wrapper.py +3 -2
- chia/_tests/environments/wallet.py +14 -14
- chia/_tests/ether.py +4 -3
- chia/_tests/farmer_harvester/test_farmer.py +41 -24
- chia/_tests/farmer_harvester/test_farmer_harvester.py +50 -17
- chia/_tests/farmer_harvester/test_filter_prefix_bits.py +27 -27
- chia/_tests/farmer_harvester/test_third_party_harvesters.py +21 -22
- chia/_tests/fee_estimation/test_fee_estimation_integration.py +18 -18
- chia/_tests/fee_estimation/test_fee_estimation_rpc.py +11 -9
- chia/_tests/harvester/test_harvester_api.py +11 -4
- chia/_tests/plot_sync/test_plot_sync.py +13 -11
- chia/_tests/plot_sync/test_receiver.py +11 -10
- chia/_tests/plot_sync/test_sync_simulated.py +2 -2
- chia/_tests/plot_sync/util.py +1 -2
- chia/_tests/plotting/test_plot_manager.py +7 -6
- chia/_tests/plotting/test_prover.py +30 -38
- chia/_tests/pools/test_pool_cmdline.py +4 -6
- chia/_tests/pools/test_pool_rpc.py +203 -61
- chia/_tests/pools/test_pool_wallet.py +3 -3
- chia/_tests/pools/test_wallet_pool_store.py +1 -4
- chia/_tests/process_junit.py +2 -2
- chia/_tests/rpc/test_rpc_client.py +4 -4
- chia/_tests/rpc/test_rpc_server.py +3 -3
- chia/_tests/simulation/test_simulation.py +12 -25
- chia/_tests/solver/test_solver_service.py +13 -4
- chia/_tests/testconfig.py +2 -2
- chia/_tests/timelord/test_new_peak.py +22 -11
- chia/_tests/tools/test_run_block.py +0 -2
- chia/_tests/tools/test_virtual_project.py +2 -1
- chia/_tests/util/benchmarks.py +1 -0
- chia/_tests/util/blockchain.py +38 -36
- chia/_tests/util/blockchain_mock.py +11 -11
- chia/_tests/util/build_network_protocol_files.py +2 -1
- chia/_tests/util/coin_store.py +2 -1
- chia/_tests/util/config.py +1 -1
- chia/_tests/util/db_connection.py +2 -3
- chia/_tests/util/full_sync.py +9 -11
- chia/_tests/util/gen_ssl_certs.py +4 -5
- chia/_tests/util/get_name_puzzle_conditions.py +2 -0
- chia/_tests/util/misc.py +24 -24
- chia/_tests/util/network_protocol_data.py +20 -3
- chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
- chia/_tests/util/protocol_messages_json.py +292 -3
- chia/_tests/util/setup_nodes.py +62 -47
- chia/_tests/util/spend_sim.py +57 -57
- chia/_tests/util/test_async_pool.py +2 -3
- chia/_tests/util/test_chia_version.py +1 -3
- chia/_tests/util/test_config.py +3 -3
- chia/_tests/util/test_full_block_utils.py +6 -3
- chia/_tests/util/test_limited_semaphore.py +1 -2
- chia/_tests/util/test_misc.py +2 -2
- chia/_tests/util/test_network.py +1 -2
- chia/_tests/util/test_priority_mutex.py +3 -3
- chia/_tests/util/test_recursive_replace.py +5 -6
- chia/_tests/util/test_replace_str_to_bytes.py +8 -10
- chia/_tests/util/test_testnet_overrides.py +3 -3
- chia/_tests/util/time_out_assert.py +2 -2
- chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +4 -6
- chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +2 -4
- chia/_tests/wallet/cat_wallet/test_cat_wallet.py +19 -13
- chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +13 -13
- chia/_tests/wallet/cat_wallet/test_trades.py +40 -38
- chia/_tests/wallet/clawback/test_clawback_lifecycle.py +2 -4
- chia/_tests/wallet/conftest.py +6 -6
- chia/_tests/wallet/db_wallet/test_db_graftroot.py +1 -1
- chia/_tests/wallet/db_wallet/test_dl_offers.py +34 -34
- chia/_tests/wallet/did_wallet/test_did.py +16 -6
- chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +21 -21
- chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +20 -6
- chia/_tests/wallet/nft_wallet/test_nft_offers.py +19 -21
- chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +1 -2
- chia/_tests/wallet/nft_wallet/test_nft_wallet.py +121 -2
- chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +6 -9
- chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +44 -1
- chia/_tests/wallet/rpc/test_wallet_rpc.py +1672 -896
- chia/_tests/wallet/sync/test_wallet_sync.py +43 -47
- chia/_tests/wallet/test_clvm_streamable.py +2 -3
- chia/_tests/wallet/test_coin_management.py +2 -2
- chia/_tests/wallet/test_conditions.py +45 -51
- chia/_tests/wallet/test_debug_spend_bundle.py +2 -2
- chia/_tests/wallet/test_new_wallet_protocol.py +4 -6
- chia/_tests/wallet/test_notifications.py +14 -14
- chia/_tests/wallet/test_signer_protocol.py +5 -5
- chia/_tests/wallet/test_singleton_lifecycle_fast.py +4 -3
- chia/_tests/wallet/test_transaction_store.py +20 -20
- chia/_tests/wallet/test_util.py +2 -2
- chia/_tests/wallet/test_wallet.py +380 -228
- chia/_tests/wallet/test_wallet_action_scope.py +4 -4
- chia/_tests/wallet/test_wallet_blockchain.py +12 -12
- chia/_tests/wallet/test_wallet_coin_store.py +3 -4
- chia/_tests/wallet/test_wallet_node.py +14 -14
- chia/_tests/wallet/test_wallet_test_framework.py +2 -1
- chia/_tests/wallet/test_wallet_utils.py +2 -3
- chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +3 -5
- chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +14 -15
- chia/_tests/wallet/vc_wallet/test_vc_wallet.py +29 -24
- chia/_tests/wallet/wallet_block_tools.py +12 -11
- chia/_tests/weight_proof/config.py +1 -0
- chia/_tests/weight_proof/test_weight_proof.py +5 -4
- chia/apis/__init__.py +21 -0
- chia/apis/farmer_stub.py +102 -0
- chia/apis/full_node_stub.py +372 -0
- chia/apis/harvester_stub.py +57 -0
- chia/apis/introducer_stub.py +35 -0
- chia/apis/solver_stub.py +30 -0
- chia/apis/stub_protocol_registry.py +21 -0
- chia/apis/timelord_stub.py +39 -0
- chia/apis/wallet_stub.py +161 -0
- chia/cmds/beta.py +3 -4
- chia/cmds/beta_funcs.py +4 -3
- chia/cmds/check_wallet_db.py +4 -4
- chia/cmds/chia.py +1 -2
- chia/cmds/cmd_classes.py +11 -13
- chia/cmds/cmd_helpers.py +11 -11
- chia/cmds/cmds_util.py +15 -15
- chia/cmds/coin_funcs.py +6 -7
- chia/cmds/coins.py +2 -3
- chia/cmds/configure.py +1 -2
- chia/cmds/data.py +42 -42
- chia/cmds/data_funcs.py +81 -81
- chia/cmds/db.py +4 -5
- 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/data.py +4 -4
- chia/cmds/dev/gh.py +5 -5
- chia/cmds/dev/installers.py +2 -3
- chia/cmds/dev/mempool.py +3 -4
- chia/cmds/dev/mempool_funcs.py +4 -4
- chia/cmds/dev/sim.py +8 -8
- chia/cmds/dump_keyring.py +3 -3
- chia/cmds/farm.py +6 -8
- chia/cmds/farm_funcs.py +25 -24
- chia/cmds/init_funcs.py +4 -4
- chia/cmds/keys.py +16 -18
- chia/cmds/keys_funcs.py +36 -36
- chia/cmds/netspace.py +1 -3
- chia/cmds/netspace_funcs.py +1 -2
- chia/cmds/options.py +3 -2
- chia/cmds/param_types.py +17 -16
- chia/cmds/passphrase.py +6 -7
- chia/cmds/passphrase_funcs.py +11 -13
- chia/cmds/peer.py +1 -3
- chia/cmds/peer_funcs.py +3 -3
- chia/cmds/plotnft.py +6 -7
- chia/cmds/plotnft_funcs.py +37 -26
- chia/cmds/rpc.py +3 -3
- chia/cmds/show.py +3 -5
- chia/cmds/show_funcs.py +9 -9
- chia/cmds/sim_funcs.py +25 -26
- chia/cmds/solver.py +1 -3
- chia/cmds/solver_funcs.py +1 -2
- chia/cmds/start_funcs.py +2 -2
- chia/cmds/wallet.py +76 -81
- chia/cmds/wallet_funcs.py +206 -177
- chia/consensus/augmented_chain.py +6 -6
- chia/consensus/block_body_validation.py +19 -15
- chia/consensus/block_creation.py +25 -21
- chia/consensus/block_header_validation.py +27 -13
- chia/consensus/block_height_map.py +3 -6
- chia/consensus/block_height_map_protocol.py +2 -2
- chia/consensus/block_record.py +2 -4
- chia/consensus/blockchain.py +58 -40
- chia/consensus/blockchain_interface.py +7 -7
- chia/consensus/coin_store_protocol.py +5 -6
- chia/consensus/condition_tools.py +4 -4
- chia/consensus/cost_calculator.py +2 -3
- chia/consensus/default_constants.py +16 -13
- chia/consensus/deficit.py +1 -3
- chia/consensus/difficulty_adjustment.py +3 -5
- chia/consensus/find_fork_point.py +2 -4
- chia/consensus/full_block_to_block_record.py +11 -13
- chia/consensus/generator_tools.py +2 -3
- chia/consensus/get_block_challenge.py +42 -26
- chia/consensus/get_block_generator.py +2 -3
- chia/consensus/make_sub_epoch_summary.py +8 -7
- chia/consensus/multiprocess_validation.py +31 -20
- chia/consensus/pos_quality.py +6 -23
- chia/consensus/pot_iterations.py +17 -44
- chia/consensus/signage_point.py +4 -5
- chia/consensus/vdf_info_computation.py +2 -4
- chia/daemon/client.py +8 -8
- chia/daemon/keychain_proxy.py +31 -37
- chia/daemon/server.py +32 -33
- chia/daemon/windows_signal.py +4 -3
- chia/data_layer/data_layer.py +86 -77
- chia/data_layer/data_layer_rpc_api.py +9 -9
- chia/data_layer/data_layer_rpc_client.py +13 -15
- chia/data_layer/data_layer_server.py +3 -3
- chia/data_layer/data_layer_util.py +14 -14
- chia/data_layer/data_layer_wallet.py +94 -101
- chia/data_layer/data_store.py +50 -50
- chia/data_layer/dl_wallet_store.py +9 -12
- chia/data_layer/download_data.py +8 -9
- chia/data_layer/s3_plugin_service.py +5 -9
- chia/data_layer/start_data_layer.py +5 -5
- chia/farmer/farmer.py +31 -31
- chia/farmer/farmer_api.py +45 -33
- chia/farmer/farmer_rpc_api.py +5 -4
- chia/farmer/farmer_rpc_client.py +6 -6
- chia/farmer/start_farmer.py +6 -6
- chia/full_node/block_store.py +13 -16
- chia/full_node/check_fork_next_block.py +1 -2
- chia/full_node/coin_store.py +15 -16
- chia/full_node/eligible_coin_spends.py +3 -3
- chia/full_node/fee_estimate_store.py +2 -3
- chia/full_node/fee_tracker.py +1 -2
- chia/full_node/full_block_utils.py +4 -4
- chia/full_node/full_node.py +238 -224
- chia/full_node/full_node_api.py +193 -150
- chia/full_node/full_node_rpc_api.py +53 -31
- chia/full_node/full_node_rpc_client.py +18 -19
- chia/full_node/full_node_store.py +45 -43
- chia/full_node/hint_management.py +2 -2
- chia/full_node/mempool.py +17 -19
- chia/full_node/mempool_manager.py +89 -42
- chia/full_node/pending_tx_cache.py +2 -3
- chia/full_node/start_full_node.py +5 -5
- chia/full_node/sync_store.py +3 -4
- chia/full_node/tx_processing_queue.py +34 -13
- chia/full_node/weight_proof.py +61 -48
- chia/harvester/harvester.py +25 -24
- chia/harvester/harvester_api.py +61 -38
- chia/harvester/harvester_rpc_api.py +10 -10
- chia/harvester/start_harvester.py +4 -4
- chia/introducer/introducer.py +3 -3
- chia/introducer/introducer_api.py +6 -4
- chia/introducer/start_introducer.py +4 -4
- chia/legacy/keyring.py +3 -3
- chia/plot_sync/delta.py +1 -2
- chia/plot_sync/receiver.py +20 -17
- chia/plot_sync/sender.py +15 -10
- chia/plotters/bladebit.py +7 -7
- chia/plotters/chiapos.py +2 -2
- chia/plotters/madmax.py +4 -4
- chia/plotters/plotters.py +4 -4
- chia/plotters/plotters_util.py +3 -3
- chia/plotting/cache.py +20 -14
- chia/plotting/check_plots.py +26 -35
- chia/plotting/create_plots.py +22 -23
- chia/plotting/manager.py +21 -14
- chia/plotting/prover.py +59 -42
- chia/plotting/util.py +16 -16
- chia/pools/pool_config.py +2 -1
- chia/pools/pool_puzzles.py +11 -12
- chia/pools/pool_wallet.py +34 -57
- chia/pools/pool_wallet_info.py +39 -10
- chia/protocols/farmer_protocol.py +8 -9
- chia/protocols/fee_estimate.py +3 -4
- chia/protocols/full_node_protocol.py +3 -4
- chia/protocols/harvester_protocol.py +27 -15
- chia/protocols/outbound_message.py +3 -3
- chia/protocols/pool_protocol.py +8 -9
- chia/protocols/shared_protocol.py +1 -2
- chia/protocols/solver_protocol.py +9 -2
- chia/protocols/timelord_protocol.py +4 -7
- chia/protocols/wallet_protocol.py +11 -12
- chia/rpc/rpc_client.py +9 -9
- chia/rpc/rpc_server.py +17 -17
- chia/rpc/util.py +2 -2
- chia/seeder/crawler.py +8 -8
- chia/seeder/crawler_api.py +21 -27
- chia/seeder/crawler_rpc_api.py +2 -2
- chia/seeder/dns_server.py +21 -21
- chia/seeder/start_crawler.py +4 -4
- chia/server/address_manager.py +15 -16
- chia/server/api_protocol.py +11 -11
- chia/server/chia_policy.py +46 -26
- chia/server/introducer_peers.py +2 -3
- chia/server/node_discovery.py +19 -19
- chia/server/rate_limit_numbers.py +4 -5
- chia/server/rate_limits.py +4 -4
- chia/server/resolve_peer_info.py +4 -4
- chia/server/server.py +49 -52
- chia/server/signal_handlers.py +6 -6
- chia/server/start_service.py +17 -17
- chia/server/upnp.py +4 -6
- chia/server/ws_connection.py +52 -37
- chia/simulator/add_blocks_in_batches.py +1 -3
- chia/simulator/block_tools.py +312 -200
- chia/simulator/full_node_simulator.py +56 -35
- chia/simulator/keyring.py +2 -3
- chia/simulator/setup_services.py +15 -15
- chia/simulator/simulator_full_node_rpc_api.py +1 -2
- chia/simulator/simulator_full_node_rpc_client.py +1 -2
- chia/simulator/simulator_protocol.py +1 -2
- chia/simulator/simulator_test_tools.py +3 -3
- chia/simulator/start_simulator.py +7 -7
- chia/simulator/wallet_tools.py +10 -10
- chia/solver/solver.py +10 -10
- chia/solver/solver_api.py +10 -8
- chia/solver/solver_rpc_api.py +2 -2
- chia/solver/start_solver.py +4 -4
- chia/ssl/cacert.pem +148 -90
- chia/ssl/chia_ca.crt +14 -10
- chia/ssl/chia_ca_old.crt +19 -0
- chia/ssl/create_ssl.py +4 -4
- chia/ssl/renewedselfsignedca.conf +4 -0
- chia/ssl/ssl_check.py +1 -2
- chia/timelord/iters_from_block.py +1 -4
- chia/timelord/start_timelord.py +4 -4
- chia/timelord/timelord.py +44 -40
- chia/timelord/timelord_api.py +6 -4
- chia/timelord/timelord_launcher.py +2 -2
- chia/timelord/timelord_rpc_api.py +2 -2
- chia/timelord/timelord_state.py +11 -12
- chia/types/block_protocol.py +1 -3
- chia/types/blockchain_format/coin.py +1 -3
- chia/types/blockchain_format/program.py +11 -8
- chia/types/blockchain_format/proof_of_space.py +123 -76
- chia/types/blockchain_format/tree_hash.py +3 -3
- chia/types/blockchain_format/vdf.py +1 -2
- chia/types/coin_spend.py +3 -3
- chia/types/mempool_item.py +5 -5
- chia/types/mempool_submission_status.py +2 -3
- chia/types/peer_info.py +1 -2
- chia/types/unfinished_header_block.py +3 -4
- chia/types/validation_state.py +1 -2
- chia/util/action_scope.py +8 -8
- chia/util/async_pool.py +5 -5
- chia/util/bech32m.py +1 -2
- chia/util/beta_metrics.py +2 -2
- chia/util/block_cache.py +4 -4
- chia/util/chia_logging.py +2 -2
- chia/util/chia_version.py +1 -2
- chia/util/config.py +15 -16
- chia/util/db_wrapper.py +26 -27
- chia/util/default_root.py +1 -2
- chia/util/errors.py +3 -3
- chia/util/file_keyring.py +14 -14
- chia/util/files.py +2 -3
- chia/util/hash.py +4 -4
- chia/util/initial-config.yaml +3 -5
- chia/util/inline_executor.py +2 -1
- chia/util/ip_address.py +1 -2
- chia/util/keychain.py +25 -27
- chia/util/keyring_wrapper.py +18 -19
- chia/util/lock.py +3 -4
- chia/util/log_exceptions.py +1 -2
- chia/util/lru_cache.py +2 -2
- chia/util/network.py +6 -6
- chia/util/path.py +2 -3
- chia/util/priority_mutex.py +2 -2
- chia/util/profiler.py +1 -2
- chia/util/safe_cancel_task.py +1 -2
- chia/util/streamable.py +22 -8
- chia/util/task_referencer.py +1 -1
- chia/util/timing.py +3 -3
- chia/util/virtual_project_analysis.py +6 -5
- chia/util/ws_message.py +2 -2
- chia/wallet/cat_wallet/cat_info.py +3 -4
- chia/wallet/cat_wallet/cat_outer_puzzle.py +12 -11
- chia/wallet/cat_wallet/cat_utils.py +3 -4
- chia/wallet/cat_wallet/cat_wallet.py +61 -83
- chia/wallet/cat_wallet/lineage_store.py +3 -4
- chia/wallet/cat_wallet/r_cat_wallet.py +19 -22
- chia/wallet/coin_selection.py +9 -10
- chia/wallet/conditions.py +120 -105
- chia/wallet/db_wallet/db_wallet_puzzles.py +4 -5
- chia/wallet/derivation_record.py +1 -2
- chia/wallet/derive_keys.py +2 -4
- chia/wallet/did_wallet/did_info.py +10 -11
- chia/wallet/did_wallet/did_wallet.py +36 -82
- chia/wallet/did_wallet/did_wallet_puzzles.py +7 -8
- chia/wallet/driver_protocol.py +5 -7
- chia/wallet/lineage_proof.py +4 -4
- chia/wallet/nft_wallet/metadata_outer_puzzle.py +11 -11
- chia/wallet/nft_wallet/nft_info.py +8 -9
- chia/wallet/nft_wallet/nft_puzzle_utils.py +8 -8
- chia/wallet/nft_wallet/nft_wallet.py +79 -116
- chia/wallet/nft_wallet/ownership_outer_puzzle.py +14 -14
- chia/wallet/nft_wallet/singleton_outer_puzzle.py +12 -11
- chia/wallet/nft_wallet/transfer_program_puzzle.py +11 -11
- chia/wallet/nft_wallet/uncurry_nft.py +10 -11
- chia/wallet/notification_manager.py +3 -3
- chia/wallet/notification_store.py +44 -61
- chia/wallet/outer_puzzles.py +6 -7
- chia/wallet/puzzle_drivers.py +34 -6
- chia/wallet/puzzles/clawback/drivers.py +6 -6
- chia/wallet/puzzles/deployed_puzzle_hashes.json +1 -54
- chia/wallet/puzzles/load_clvm.py +1 -1
- chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +1 -2
- chia/wallet/puzzles/singleton_top_layer.py +2 -3
- chia/wallet/puzzles/singleton_top_layer_v1_1.py +3 -4
- chia/wallet/puzzles/tails.py +3 -3
- chia/wallet/singleton.py +5 -7
- chia/wallet/singleton_record.py +3 -3
- chia/wallet/start_wallet.py +5 -5
- chia/wallet/trade_manager.py +37 -58
- chia/wallet/trade_record.py +4 -4
- chia/wallet/trading/offer.py +59 -46
- chia/wallet/trading/trade_store.py +8 -9
- chia/wallet/transaction_record.py +8 -8
- chia/wallet/uncurried_puzzle.py +1 -2
- chia/wallet/util/clvm_streamable.py +12 -12
- chia/wallet/util/compute_hints.py +4 -5
- chia/wallet/util/curry_and_treehash.py +1 -2
- chia/wallet/util/merkle_tree.py +2 -3
- chia/wallet/util/peer_request_cache.py +8 -8
- chia/wallet/util/signing.py +85 -0
- chia/wallet/util/tx_config.py +15 -6
- chia/wallet/util/wallet_sync_utils.py +14 -16
- chia/wallet/util/wallet_types.py +2 -2
- chia/wallet/vc_wallet/cr_cat_drivers.py +10 -11
- chia/wallet/vc_wallet/cr_cat_wallet.py +50 -68
- chia/wallet/vc_wallet/cr_outer_puzzle.py +14 -13
- chia/wallet/vc_wallet/vc_drivers.py +27 -27
- chia/wallet/vc_wallet/vc_store.py +5 -6
- chia/wallet/vc_wallet/vc_wallet.py +33 -61
- chia/wallet/wallet.py +50 -78
- chia/wallet/wallet_action_scope.py +11 -11
- chia/wallet/wallet_blockchain.py +12 -12
- chia/wallet/wallet_coin_record.py +12 -6
- chia/wallet/wallet_coin_store.py +24 -25
- chia/wallet/wallet_interested_store.py +3 -5
- chia/wallet/wallet_nft_store.py +10 -11
- chia/wallet/wallet_node.py +53 -61
- chia/wallet/wallet_node_api.py +5 -3
- chia/wallet/wallet_protocol.py +23 -23
- chia/wallet/wallet_puzzle_store.py +15 -18
- chia/wallet/wallet_request_types.py +778 -114
- chia/wallet/wallet_retry_store.py +1 -3
- chia/wallet/wallet_rpc_api.py +572 -909
- chia/wallet/wallet_rpc_client.py +87 -279
- chia/wallet/wallet_singleton_store.py +3 -4
- chia/wallet/wallet_state_manager.py +332 -106
- chia/wallet/wallet_transaction_store.py +11 -14
- chia/wallet/wallet_user_store.py +4 -6
- chia/wallet/wallet_weight_proof_handler.py +4 -4
- {chia_blockchain-2.5.7rc4.dist-info → chia_blockchain-2.5.8rc1.dist-info}/METADATA +6 -5
- {chia_blockchain-2.5.7rc4.dist-info → chia_blockchain-2.5.8rc1.dist-info}/RECORD +507 -516
- chia/apis.py +0 -21
- chia/consensus/check_time_locks.py +0 -57
- chia/data_layer/puzzles/__init__.py +0 -0
- chia/data_layer/puzzles/graftroot_dl_offers.clsp +0 -100
- chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +0 -1
- chia/types/coin_record.py +0 -44
- chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
- chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +0 -6
- chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +0 -1
- chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +0 -6
- chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +0 -1
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +0 -30
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +0 -1
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +0 -28
- chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +0 -1
- chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +0 -100
- chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +0 -1
- chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +0 -78
- chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +0 -1
- chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +0 -74
- chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +0 -1
- {chia_blockchain-2.5.7rc4.dist-info → chia_blockchain-2.5.8rc1.dist-info}/WHEEL +0 -0
- {chia_blockchain-2.5.7rc4.dist-info → chia_blockchain-2.5.8rc1.dist-info}/entry_points.txt +0 -0
- {chia_blockchain-2.5.7rc4.dist-info → chia_blockchain-2.5.8rc1.dist-info}/licenses/LICENSE +0 -0
chia/wallet/wallet_rpc_api.py
CHANGED
|
@@ -3,12 +3,14 @@ from __future__ import annotations
|
|
|
3
3
|
import dataclasses
|
|
4
4
|
import json
|
|
5
5
|
import logging
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from itertools import count
|
|
6
8
|
from pathlib import Path
|
|
7
|
-
from typing import TYPE_CHECKING, Any,
|
|
9
|
+
from typing import TYPE_CHECKING, Any, ClassVar, cast
|
|
8
10
|
|
|
9
|
-
from chia_rs import AugSchemeMPL, Coin, CoinSpend, CoinState, G1Element, G2Element, PrivateKey
|
|
11
|
+
from chia_rs import AugSchemeMPL, Coin, CoinRecord, CoinSpend, CoinState, G1Element, G2Element, PrivateKey
|
|
10
12
|
from chia_rs.sized_bytes import bytes32
|
|
11
|
-
from chia_rs.sized_ints import
|
|
13
|
+
from chia_rs.sized_ints import uint16, uint32, uint64
|
|
12
14
|
from clvm_tools.binutils import assemble
|
|
13
15
|
|
|
14
16
|
from chia.consensus.block_rewards import calculate_base_farmer_reward
|
|
@@ -16,41 +18,39 @@ from chia.data_layer.data_layer_errors import LauncherCoinNotFoundError
|
|
|
16
18
|
from chia.data_layer.data_layer_util import DLProof, VerifyProofResponse, dl_verify_proof
|
|
17
19
|
from chia.data_layer.data_layer_wallet import DataLayerWallet, Mirror
|
|
18
20
|
from chia.pools.pool_wallet import PoolWallet
|
|
19
|
-
from chia.pools.pool_wallet_info import
|
|
21
|
+
from chia.pools.pool_wallet_info import (
|
|
22
|
+
FARMING_TO_POOL,
|
|
23
|
+
PoolState,
|
|
24
|
+
PoolWalletInfo,
|
|
25
|
+
create_pool_state,
|
|
26
|
+
initial_pool_state_from_dict,
|
|
27
|
+
)
|
|
20
28
|
from chia.protocols.outbound_message import NodeType
|
|
21
29
|
from chia.rpc.rpc_server import Endpoint, EndpointResult, default_get_connections
|
|
22
30
|
from chia.rpc.util import ALL_TRANSLATION_LAYERS, RpcEndpoint, marshal
|
|
23
31
|
from chia.server.ws_connection import WSChiaConnection
|
|
24
|
-
from chia.types.blockchain_format.
|
|
25
|
-
from chia.types.blockchain_format.program import INFINITE_COST, Program, run_with_cost
|
|
26
|
-
from chia.types.coin_record import CoinRecord
|
|
27
|
-
from chia.types.signing_mode import CHIP_0002_SIGN_MESSAGE_PREFIX, SigningMode
|
|
32
|
+
from chia.types.blockchain_format.program import Program
|
|
28
33
|
from chia.util.bech32m import decode_puzzle_hash, encode_puzzle_hash
|
|
29
|
-
from chia.util.byte_types import hexstr_to_bytes
|
|
30
34
|
from chia.util.config import load_config
|
|
31
35
|
from chia.util.errors import KeychainIsLocked
|
|
32
|
-
from chia.util.hash import std_hash
|
|
33
36
|
from chia.util.keychain import bytes_to_mnemonic, generate_mnemonic
|
|
34
|
-
from chia.util.
|
|
35
|
-
from chia.util.streamable import Streamable, UInt32Range, streamable
|
|
37
|
+
from chia.util.streamable import UInt32Range
|
|
36
38
|
from chia.util.ws_message import WsRpcMessage, create_payload_dict
|
|
37
39
|
from chia.wallet.cat_wallet.cat_constants import DEFAULT_CATS
|
|
38
40
|
from chia.wallet.cat_wallet.cat_info import CRCATInfo
|
|
39
41
|
from chia.wallet.cat_wallet.cat_wallet import CATWallet
|
|
42
|
+
from chia.wallet.cat_wallet.r_cat_wallet import RCATWallet
|
|
40
43
|
from chia.wallet.conditions import (
|
|
41
|
-
|
|
42
|
-
AssertPuzzleAnnouncement,
|
|
44
|
+
AssertConcurrentSpend,
|
|
43
45
|
Condition,
|
|
44
46
|
ConditionValidTimes,
|
|
45
47
|
CreateCoin,
|
|
46
48
|
CreateCoinAnnouncement,
|
|
47
49
|
CreatePuzzleAnnouncement,
|
|
48
50
|
conditions_from_json_dicts,
|
|
49
|
-
parse_conditions_non_consensus,
|
|
50
51
|
parse_timelock_info,
|
|
51
52
|
)
|
|
52
53
|
from chia.wallet.derive_keys import (
|
|
53
|
-
MAX_POOL_WALLETS,
|
|
54
54
|
master_sk_to_farmer_sk,
|
|
55
55
|
master_sk_to_pool_sk,
|
|
56
56
|
match_address_to_sk,
|
|
@@ -69,12 +69,9 @@ from chia.wallet.nft_wallet.nft_info import NFTCoinInfo, NFTInfo
|
|
|
69
69
|
from chia.wallet.nft_wallet.nft_puzzle_utils import get_metadata_and_phs
|
|
70
70
|
from chia.wallet.nft_wallet.nft_wallet import NFTWallet
|
|
71
71
|
from chia.wallet.nft_wallet.uncurry_nft import UncurriedNFT
|
|
72
|
-
from chia.wallet.notification_store import Notification
|
|
73
72
|
from chia.wallet.outer_puzzles import AssetType
|
|
74
|
-
from chia.wallet.puzzle_drivers import PuzzleInfo
|
|
75
|
-
from chia.wallet.puzzles import
|
|
76
|
-
from chia.wallet.puzzles.clawback.metadata import AutoClaimSettings, ClawbackMetadata
|
|
77
|
-
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import puzzle_hash_for_synthetic_public_key
|
|
73
|
+
from chia.wallet.puzzle_drivers import PuzzleInfo
|
|
74
|
+
from chia.wallet.puzzles.clawback.metadata import AutoClaimSettings
|
|
78
75
|
from chia.wallet.signer_protocol import SigningResponse
|
|
79
76
|
from chia.wallet.singleton import (
|
|
80
77
|
SINGLETON_LAUNCHER_PUZZLE_HASH,
|
|
@@ -82,7 +79,7 @@ from chia.wallet.singleton import (
|
|
|
82
79
|
get_inner_puzzle_from_singleton,
|
|
83
80
|
)
|
|
84
81
|
from chia.wallet.trade_record import TradeRecord
|
|
85
|
-
from chia.wallet.trading.offer import Offer
|
|
82
|
+
from chia.wallet.trading.offer import Offer, OfferSummary
|
|
86
83
|
from chia.wallet.transaction_record import TransactionRecord
|
|
87
84
|
from chia.wallet.uncurried_puzzle import uncurry_puzzle
|
|
88
85
|
from chia.wallet.util.address_type import AddressType, is_valid_address
|
|
@@ -90,7 +87,8 @@ from chia.wallet.util.clvm_streamable import json_serialize_with_clvm_streamable
|
|
|
90
87
|
from chia.wallet.util.compute_hints import compute_spend_hints_and_additions
|
|
91
88
|
from chia.wallet.util.compute_memos import compute_memos
|
|
92
89
|
from chia.wallet.util.curry_and_treehash import NIL_TREEHASH
|
|
93
|
-
from chia.wallet.util.query_filter import
|
|
90
|
+
from chia.wallet.util.query_filter import HashFilter
|
|
91
|
+
from chia.wallet.util.signing import sign_message, verify_signature
|
|
94
92
|
from chia.wallet.util.transaction_type import CLAWBACK_INCOMING_TRANSACTION_TYPES, TransactionType
|
|
95
93
|
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG, TXConfig, TXConfigLoader
|
|
96
94
|
from chia.wallet.util.wallet_sync_utils import fetch_coin_spend_for_coin_state
|
|
@@ -101,17 +99,20 @@ from chia.wallet.vc_wallet.vc_store import VCProofs
|
|
|
101
99
|
from chia.wallet.vc_wallet.vc_wallet import VCWallet
|
|
102
100
|
from chia.wallet.wallet import Wallet
|
|
103
101
|
from chia.wallet.wallet_action_scope import WalletActionScope
|
|
104
|
-
from chia.wallet.wallet_coin_record import WalletCoinRecord
|
|
102
|
+
from chia.wallet.wallet_coin_record import WalletCoinRecord, WalletCoinRecordMetadataParsingError
|
|
105
103
|
from chia.wallet.wallet_coin_store import CoinRecordOrder, GetCoinRecords, unspent_range
|
|
106
104
|
from chia.wallet.wallet_info import WalletInfo
|
|
107
|
-
from chia.wallet.wallet_node import WalletNode
|
|
108
|
-
from chia.wallet.wallet_protocol import WalletProtocol
|
|
105
|
+
from chia.wallet.wallet_node import WalletNode, get_wallet_db_path
|
|
109
106
|
from chia.wallet.wallet_request_types import (
|
|
110
107
|
AddKey,
|
|
111
108
|
AddKeyResponse,
|
|
112
109
|
ApplySignatures,
|
|
113
110
|
ApplySignaturesResponse,
|
|
114
111
|
BalanceResponse,
|
|
112
|
+
CancelOffer,
|
|
113
|
+
CancelOfferResponse,
|
|
114
|
+
CancelOffers,
|
|
115
|
+
CancelOffersResponse,
|
|
115
116
|
CATAssetIDToName,
|
|
116
117
|
CATAssetIDToNameResponse,
|
|
117
118
|
CATGetAssetID,
|
|
@@ -128,8 +129,17 @@ from chia.wallet.wallet_request_types import (
|
|
|
128
129
|
CheckOfferValidityResponse,
|
|
129
130
|
CombineCoins,
|
|
130
131
|
CombineCoinsResponse,
|
|
132
|
+
CRCATApprovePending,
|
|
133
|
+
CRCATApprovePendingResponse,
|
|
131
134
|
CreateNewDL,
|
|
132
135
|
CreateNewDLResponse,
|
|
136
|
+
CreateNewWallet,
|
|
137
|
+
CreateNewWalletResponse,
|
|
138
|
+
CreateNewWalletType,
|
|
139
|
+
CreateOfferForIDs,
|
|
140
|
+
CreateOfferForIDsResponse,
|
|
141
|
+
CreateSignedTransaction,
|
|
142
|
+
CreateSignedTransactionsResponse,
|
|
133
143
|
DefaultCAT,
|
|
134
144
|
DeleteKey,
|
|
135
145
|
DeleteNotifications,
|
|
@@ -156,6 +166,7 @@ from chia.wallet.wallet_request_types import (
|
|
|
156
166
|
DIDSetWalletNameResponse,
|
|
157
167
|
DIDTransferDID,
|
|
158
168
|
DIDTransferDIDResponse,
|
|
169
|
+
DIDType,
|
|
159
170
|
DIDUpdateMetadata,
|
|
160
171
|
DIDUpdateMetadataResponse,
|
|
161
172
|
DLDeleteMirror,
|
|
@@ -185,17 +196,25 @@ from chia.wallet.wallet_request_types import (
|
|
|
185
196
|
GatherSigningInfo,
|
|
186
197
|
GatherSigningInfoResponse,
|
|
187
198
|
GenerateMnemonicResponse,
|
|
199
|
+
GetAllOffers,
|
|
200
|
+
GetAllOffersResponse,
|
|
188
201
|
GetCATListResponse,
|
|
189
202
|
GetCoinRecordsByNames,
|
|
190
203
|
GetCoinRecordsByNamesResponse,
|
|
191
204
|
GetCurrentDerivationIndexResponse,
|
|
205
|
+
GetFarmedAmount,
|
|
206
|
+
GetFarmedAmountResponse,
|
|
192
207
|
GetHeightInfoResponse,
|
|
193
208
|
GetLoggedInFingerprintResponse,
|
|
194
209
|
GetNextAddress,
|
|
195
210
|
GetNextAddressResponse,
|
|
196
211
|
GetNotifications,
|
|
197
212
|
GetNotificationsResponse,
|
|
213
|
+
GetOffer,
|
|
214
|
+
GetOfferResponse,
|
|
198
215
|
GetOffersCountResponse,
|
|
216
|
+
GetOfferSummary,
|
|
217
|
+
GetOfferSummaryResponse,
|
|
199
218
|
GetPrivateKey,
|
|
200
219
|
GetPrivateKeyFormat,
|
|
201
220
|
GetPrivateKeyResponse,
|
|
@@ -267,6 +286,8 @@ from chia.wallet.wallet_request_types import (
|
|
|
267
286
|
SendNotification,
|
|
268
287
|
SendNotificationResponse,
|
|
269
288
|
SendTransaction,
|
|
289
|
+
SendTransactionMulti,
|
|
290
|
+
SendTransactionMultiResponse,
|
|
270
291
|
SendTransactionResponse,
|
|
271
292
|
SetWalletResyncOnStartup,
|
|
272
293
|
SignMessageByAddress,
|
|
@@ -280,6 +301,8 @@ from chia.wallet.wallet_request_types import (
|
|
|
280
301
|
StrayCAT,
|
|
281
302
|
SubmitTransactions,
|
|
282
303
|
SubmitTransactionsResponse,
|
|
304
|
+
TakeOffer,
|
|
305
|
+
TakeOfferResponse,
|
|
283
306
|
TransactionRecordWithMetadata,
|
|
284
307
|
VCAddProofs,
|
|
285
308
|
VCGet,
|
|
@@ -299,6 +322,7 @@ from chia.wallet.wallet_request_types import (
|
|
|
299
322
|
VCSpendResponse,
|
|
300
323
|
VerifySignature,
|
|
301
324
|
VerifySignatureResponse,
|
|
325
|
+
WalletCreationMode,
|
|
302
326
|
WalletInfoResponse,
|
|
303
327
|
)
|
|
304
328
|
from chia.wallet.wallet_spend_bundle import WalletSpendBundle
|
|
@@ -319,6 +343,9 @@ def tx_endpoint(
|
|
|
319
343
|
async def rpc_endpoint(
|
|
320
344
|
self: WalletRpcApi, request: dict[str, Any], *args: object, **kwargs: object
|
|
321
345
|
) -> EndpointResult:
|
|
346
|
+
if await self.service.wallet_state_manager.synced() is False:
|
|
347
|
+
raise ValueError("Wallet needs to be fully synced before making transactions.")
|
|
348
|
+
|
|
322
349
|
assert self.service.logged_in_fingerprint is not None
|
|
323
350
|
tx_config_loader: TXConfigLoader = TXConfigLoader.from_json_dict(request)
|
|
324
351
|
|
|
@@ -332,7 +359,7 @@ def tx_endpoint(
|
|
|
332
359
|
excluded_coin_amounts=request.get("exclude_coin_amounts"),
|
|
333
360
|
)
|
|
334
361
|
if tx_config_loader.excluded_coin_ids is None:
|
|
335
|
-
excluded_coins:
|
|
362
|
+
excluded_coins: list[dict[str, Any]] | None = request.get(
|
|
336
363
|
"exclude_coins", request.get("excluded_coins")
|
|
337
364
|
)
|
|
338
365
|
if excluded_coins is not None:
|
|
@@ -360,25 +387,40 @@ def tx_endpoint(
|
|
|
360
387
|
):
|
|
361
388
|
raise ValueError("Relative timelocks are not currently supported in the RPC")
|
|
362
389
|
|
|
363
|
-
|
|
364
|
-
tx_config,
|
|
365
|
-
push=request.get("push", push),
|
|
366
|
-
merge_spends=request.get("merge_spends", merge_spends),
|
|
367
|
-
sign=request.get("sign", self.service.config.get("auto_sign_txs", True)),
|
|
368
|
-
) as action_scope:
|
|
390
|
+
if "action_scope_override" in kwargs:
|
|
369
391
|
response: EndpointResult = await func(
|
|
370
392
|
self,
|
|
371
393
|
request,
|
|
372
394
|
*args,
|
|
373
|
-
|
|
395
|
+
kwargs["action_scope_override"],
|
|
374
396
|
extra_conditions=extra_conditions,
|
|
375
|
-
**kwargs,
|
|
397
|
+
**{k: v for k, v in kwargs.items() if k != "action_scope_override"},
|
|
376
398
|
)
|
|
399
|
+
action_scope = cast(WalletActionScope, kwargs["action_scope_override"])
|
|
400
|
+
else:
|
|
401
|
+
async with self.service.wallet_state_manager.new_action_scope(
|
|
402
|
+
tx_config,
|
|
403
|
+
push=request.get("push", push),
|
|
404
|
+
merge_spends=request.get("merge_spends", merge_spends),
|
|
405
|
+
sign=request.get("sign", self.service.config.get("auto_sign_txs", True)),
|
|
406
|
+
) as action_scope:
|
|
407
|
+
response = await func(
|
|
408
|
+
self,
|
|
409
|
+
request,
|
|
410
|
+
*args,
|
|
411
|
+
action_scope,
|
|
412
|
+
extra_conditions=extra_conditions,
|
|
413
|
+
**kwargs,
|
|
414
|
+
)
|
|
377
415
|
|
|
378
416
|
if func.__name__ == "create_new_wallet" and "transactions" not in response:
|
|
379
417
|
# unfortunately, this API isn't solely a tx endpoint
|
|
380
418
|
return response
|
|
381
419
|
|
|
420
|
+
if "action_scope_override" in kwargs:
|
|
421
|
+
# deferring to parent action scope
|
|
422
|
+
return response
|
|
423
|
+
|
|
382
424
|
unsigned_txs = await self.service.wallet_state_manager.gather_signing_info_for_txs(
|
|
383
425
|
action_scope.side_effects.transactions
|
|
384
426
|
)
|
|
@@ -667,10 +709,10 @@ class WalletRpcApi:
|
|
|
667
709
|
"/execute_signing_instructions": self.execute_signing_instructions,
|
|
668
710
|
}
|
|
669
711
|
|
|
670
|
-
def get_connections(self, request_node_type:
|
|
712
|
+
def get_connections(self, request_node_type: NodeType | None) -> list[dict[str, Any]]:
|
|
671
713
|
return default_get_connections(server=self.service.server, request_node_type=request_node_type)
|
|
672
714
|
|
|
673
|
-
async def _state_changed(self, change: str, change_data:
|
|
715
|
+
async def _state_changed(self, change: str, change_data: dict[str, Any] | None) -> list[WsRpcMessage]:
|
|
674
716
|
"""
|
|
675
717
|
Called by the WalletNode or WalletStateManager when something has changed in the wallet. This
|
|
676
718
|
gives us an opportunity to send notifications to all connected clients via WebSocket.
|
|
@@ -762,10 +804,7 @@ class WalletRpcApi:
|
|
|
762
804
|
@marshal
|
|
763
805
|
async def get_public_keys(self, request: Empty) -> GetPublicKeysResponse:
|
|
764
806
|
try:
|
|
765
|
-
fingerprints = [
|
|
766
|
-
uint32(sk.get_g1().get_fingerprint())
|
|
767
|
-
for (sk, seed) in await self.service.keychain_proxy.get_all_private_keys()
|
|
768
|
-
]
|
|
807
|
+
fingerprints = [key_data.fingerprint for key_data in await self.service.keychain_proxy.get_keys()]
|
|
769
808
|
except KeychainIsLocked:
|
|
770
809
|
return GetPublicKeysResponse(keyring_is_locked=True)
|
|
771
810
|
except Exception as e:
|
|
@@ -776,7 +815,7 @@ class WalletRpcApi:
|
|
|
776
815
|
else:
|
|
777
816
|
return GetPublicKeysResponse(keyring_is_locked=False, public_key_fingerprints=fingerprints)
|
|
778
817
|
|
|
779
|
-
async def _get_private_key(self, fingerprint: int) -> tuple[
|
|
818
|
+
async def _get_private_key(self, fingerprint: int) -> tuple[PrivateKey | None, bytes | None]:
|
|
780
819
|
try:
|
|
781
820
|
all_keys = await self.service.keychain_proxy.get_all_private_keys()
|
|
782
821
|
for sk, seed in all_keys:
|
|
@@ -838,9 +877,10 @@ class WalletRpcApi:
|
|
|
838
877
|
except Exception as e:
|
|
839
878
|
log.error(f"Failed to delete key by fingerprint: {e}")
|
|
840
879
|
raise e
|
|
841
|
-
path =
|
|
880
|
+
path = get_wallet_db_path(
|
|
842
881
|
self.service.root_path,
|
|
843
|
-
|
|
882
|
+
self.service.config,
|
|
883
|
+
str(request.fingerprint),
|
|
844
884
|
)
|
|
845
885
|
if path.exists():
|
|
846
886
|
path.unlink()
|
|
@@ -928,14 +968,20 @@ class WalletRpcApi:
|
|
|
928
968
|
@marshal
|
|
929
969
|
async def delete_all_keys(self, request: Empty) -> Empty:
|
|
930
970
|
await self._stop_wallet()
|
|
971
|
+
all_key_datas = await self.service.keychain_proxy.get_keys()
|
|
931
972
|
try:
|
|
932
973
|
await self.service.keychain_proxy.delete_all_keys()
|
|
933
974
|
except Exception as e:
|
|
934
975
|
log.error(f"Failed to delete all keys: {e}")
|
|
935
976
|
raise e
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
977
|
+
for key_data in all_key_datas:
|
|
978
|
+
path = get_wallet_db_path(
|
|
979
|
+
self.service.root_path,
|
|
980
|
+
self.service.config,
|
|
981
|
+
str(key_data.fingerprint),
|
|
982
|
+
)
|
|
983
|
+
if path.exists():
|
|
984
|
+
path.unlink()
|
|
939
985
|
return Empty()
|
|
940
986
|
|
|
941
987
|
##########################################################################################
|
|
@@ -987,50 +1033,21 @@ class WalletRpcApi:
|
|
|
987
1033
|
) -> PushTransactionsResponse:
|
|
988
1034
|
if not action_scope.config.push:
|
|
989
1035
|
raise ValueError("Cannot push transactions if push is False")
|
|
1036
|
+
tx_removals = [c for tx in request.transactions for c in tx.removals]
|
|
990
1037
|
async with action_scope.use() as interface:
|
|
991
1038
|
interface.side_effects.transactions.extend(request.transactions)
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
)
|
|
1005
|
-
if isinstance(condition, CreateCoinAnnouncement)
|
|
1006
|
-
)
|
|
1007
|
-
announcement_origin = next(
|
|
1008
|
-
coin
|
|
1009
|
-
for condition, coin in all_conditions_and_origins
|
|
1010
|
-
if condition == create_coin_announcement.to_program()
|
|
1011
|
-
)
|
|
1012
|
-
async with self.service.wallet_state_manager.new_action_scope(
|
|
1013
|
-
dataclasses.replace(
|
|
1014
|
-
action_scope.config.tx_config,
|
|
1015
|
-
excluded_coin_ids=[
|
|
1016
|
-
*action_scope.config.tx_config.excluded_coin_ids,
|
|
1017
|
-
*(c.name() for tx in interface.side_effects.transactions for c in tx.removals),
|
|
1018
|
-
],
|
|
1019
|
-
),
|
|
1020
|
-
push=False,
|
|
1021
|
-
) as inner_action_scope:
|
|
1022
|
-
await self.service.wallet_state_manager.main_wallet.create_tandem_xch_tx(
|
|
1023
|
-
request.fee,
|
|
1024
|
-
inner_action_scope,
|
|
1025
|
-
extra_conditions=(
|
|
1026
|
-
*extra_conditions,
|
|
1027
|
-
CreateCoinAnnouncement(
|
|
1028
|
-
create_coin_announcement.msg, announcement_origin
|
|
1029
|
-
).corresponding_assertion(),
|
|
1030
|
-
),
|
|
1031
|
-
)
|
|
1032
|
-
|
|
1033
|
-
interface.side_effects.transactions.extend(inner_action_scope.side_effects.transactions)
|
|
1039
|
+
interface.side_effects.selected_coins.extend(tx_removals)
|
|
1040
|
+
if request.fee != 0:
|
|
1041
|
+
await self.service.wallet_state_manager.main_wallet.create_tandem_xch_tx(
|
|
1042
|
+
request.fee,
|
|
1043
|
+
action_scope,
|
|
1044
|
+
extra_conditions=(
|
|
1045
|
+
*extra_conditions,
|
|
1046
|
+
AssertConcurrentSpend(tx_removals[0].name()),
|
|
1047
|
+
),
|
|
1048
|
+
)
|
|
1049
|
+
elif extra_conditions != tuple():
|
|
1050
|
+
raise ValueError("Cannot add conditions to a transaction if no new fee spend is being added")
|
|
1034
1051
|
|
|
1035
1052
|
return PushTransactionsResponse([], []) # tx_endpoint takes care of this
|
|
1036
1053
|
|
|
@@ -1065,7 +1082,7 @@ class WalletRpcApi:
|
|
|
1065
1082
|
|
|
1066
1083
|
@marshal
|
|
1067
1084
|
async def get_wallets(self, request: GetWallets) -> GetWalletsResponse:
|
|
1068
|
-
wallet_type:
|
|
1085
|
+
wallet_type: WalletType | None = None
|
|
1069
1086
|
if request.type is not None:
|
|
1070
1087
|
wallet_type = WalletType(request.type)
|
|
1071
1088
|
|
|
@@ -1099,81 +1116,67 @@ class WalletRpcApi:
|
|
|
1099
1116
|
return GetWalletsResponse(wallet_infos, uint32.construct_optional(self.service.logged_in_fingerprint))
|
|
1100
1117
|
|
|
1101
1118
|
@tx_endpoint(push=True)
|
|
1102
|
-
|
|
1119
|
+
@marshal
|
|
1120
|
+
# Semantics guarantee returning on all paths, or else an error.
|
|
1121
|
+
# It's probably not great to add a bunch of unreachable code for the sake of mypy.
|
|
1122
|
+
async def create_new_wallet( # type: ignore[return]
|
|
1103
1123
|
self,
|
|
1104
|
-
request:
|
|
1124
|
+
request: CreateNewWallet,
|
|
1105
1125
|
action_scope: WalletActionScope,
|
|
1106
1126
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
1107
|
-
) ->
|
|
1127
|
+
) -> CreateNewWalletResponse:
|
|
1108
1128
|
wallet_state_manager = self.service.wallet_state_manager
|
|
1109
|
-
|
|
1110
|
-
if await self.service.wallet_state_manager.synced() is False:
|
|
1111
|
-
raise ValueError("Wallet needs to be fully synced.")
|
|
1112
1129
|
main_wallet = wallet_state_manager.main_wallet
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
action_scope,
|
|
1129
|
-
fee,
|
|
1130
|
-
name,
|
|
1131
|
-
)
|
|
1132
|
-
asset_id = cat_wallet.get_asset_id()
|
|
1133
|
-
self.service.wallet_state_manager.state_changed("wallet_created")
|
|
1134
|
-
return {
|
|
1135
|
-
"type": cat_wallet.type(),
|
|
1136
|
-
"asset_id": asset_id,
|
|
1137
|
-
"wallet_id": cat_wallet.id(),
|
|
1138
|
-
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
1139
|
-
}
|
|
1140
|
-
else:
|
|
1141
|
-
raise ValueError(
|
|
1142
|
-
"Support for this RPC mode has been dropped."
|
|
1143
|
-
" Please use the CAT Admin Tool @ https://github.com/Chia-Network/CAT-admin-tool instead."
|
|
1130
|
+
|
|
1131
|
+
if request.wallet_type == CreateNewWalletType.CAT_WALLET:
|
|
1132
|
+
if request.mode == WalletCreationMode.NEW:
|
|
1133
|
+
if not action_scope.config.push:
|
|
1134
|
+
raise ValueError("Test CAT minting must be pushed automatically") # pragma: no cover
|
|
1135
|
+
async with self.service.wallet_state_manager.lock:
|
|
1136
|
+
cat_wallet = await CATWallet.create_new_cat_wallet(
|
|
1137
|
+
wallet_state_manager,
|
|
1138
|
+
main_wallet,
|
|
1139
|
+
{"identifier": "genesis_by_id"},
|
|
1140
|
+
# mypy doesn't know about our __post_init__
|
|
1141
|
+
request.amount, # type: ignore[arg-type]
|
|
1142
|
+
action_scope,
|
|
1143
|
+
request.fee,
|
|
1144
|
+
request.name,
|
|
1144
1145
|
)
|
|
1146
|
+
asset_id = cat_wallet.get_asset_id()
|
|
1147
|
+
self.service.wallet_state_manager.state_changed("wallet_created")
|
|
1148
|
+
return CreateNewWalletResponse(
|
|
1149
|
+
[], [], type=cat_wallet.type().name, asset_id=asset_id, wallet_id=cat_wallet.id()
|
|
1150
|
+
)
|
|
1145
1151
|
|
|
1146
|
-
elif request
|
|
1152
|
+
elif request.mode == WalletCreationMode.EXISTING:
|
|
1147
1153
|
async with self.service.wallet_state_manager.lock:
|
|
1154
|
+
assert request.asset_id is not None # mypy doesn't know about our __post_init__
|
|
1148
1155
|
cat_wallet = await CATWallet.get_or_create_wallet_for_cat(
|
|
1149
|
-
wallet_state_manager, main_wallet, request
|
|
1156
|
+
wallet_state_manager, main_wallet, request.asset_id, request.name
|
|
1150
1157
|
)
|
|
1151
|
-
return
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
metadata: dict[str, str] = {}
|
|
1161
|
-
if "metadata" in request:
|
|
1162
|
-
if type(request["metadata"]) is dict:
|
|
1163
|
-
metadata = request["metadata"]
|
|
1164
|
-
|
|
1158
|
+
return CreateNewWalletResponse(
|
|
1159
|
+
[],
|
|
1160
|
+
[],
|
|
1161
|
+
type=cat_wallet.type().name,
|
|
1162
|
+
asset_id=request.asset_id,
|
|
1163
|
+
wallet_id=cat_wallet.id(),
|
|
1164
|
+
)
|
|
1165
|
+
elif request.wallet_type == CreateNewWalletType.DID_WALLET:
|
|
1166
|
+
if request.did_type == DIDType.NEW:
|
|
1165
1167
|
async with self.service.wallet_state_manager.lock:
|
|
1166
|
-
did_wallet_name
|
|
1167
|
-
if
|
|
1168
|
-
did_wallet_name =
|
|
1168
|
+
did_wallet_name = None
|
|
1169
|
+
if request.wallet_name is not None:
|
|
1170
|
+
did_wallet_name = request.wallet_name.strip()
|
|
1171
|
+
assert request.amount is not None # mypy doesn't know about our __post_init__
|
|
1169
1172
|
did_wallet: DIDWallet = await DIDWallet.create_new_did_wallet(
|
|
1170
1173
|
wallet_state_manager,
|
|
1171
1174
|
main_wallet,
|
|
1172
|
-
|
|
1175
|
+
request.amount,
|
|
1173
1176
|
action_scope,
|
|
1174
|
-
metadata,
|
|
1177
|
+
request.metadata,
|
|
1175
1178
|
did_wallet_name,
|
|
1176
|
-
|
|
1179
|
+
request.fee,
|
|
1177
1180
|
extra_conditions=extra_conditions,
|
|
1178
1181
|
)
|
|
1179
1182
|
|
|
@@ -1189,131 +1192,95 @@ class WalletRpcApi:
|
|
|
1189
1192
|
bytes32.fromhex(did_wallet.get_my_DID()),
|
|
1190
1193
|
nft_wallet_name,
|
|
1191
1194
|
)
|
|
1192
|
-
return
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
"my_did": my_did_id,
|
|
1196
|
-
"wallet_id": did_wallet.id(),
|
|
1197
|
-
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
1198
|
-
}
|
|
1195
|
+
return CreateNewWalletResponse(
|
|
1196
|
+
[], [], type=did_wallet.type().name, my_did=my_did_id, wallet_id=did_wallet.id()
|
|
1197
|
+
)
|
|
1199
1198
|
|
|
1200
|
-
elif request
|
|
1199
|
+
elif request.did_type == DIDType.RECOVERY:
|
|
1201
1200
|
async with self.service.wallet_state_manager.lock:
|
|
1201
|
+
assert request.backup_data is not None # mypy doesn't know about our __post_init__
|
|
1202
1202
|
did_wallet = await DIDWallet.create_new_did_wallet_from_recovery(
|
|
1203
|
-
wallet_state_manager, main_wallet, request
|
|
1203
|
+
wallet_state_manager, main_wallet, request.backup_data
|
|
1204
1204
|
)
|
|
1205
1205
|
assert did_wallet.did_info.temp_coin is not None
|
|
1206
1206
|
assert did_wallet.did_info.temp_puzhash is not None
|
|
1207
1207
|
assert did_wallet.did_info.temp_pubkey is not None
|
|
1208
1208
|
my_did = did_wallet.get_my_DID()
|
|
1209
|
-
coin_name = did_wallet.did_info.temp_coin.name()
|
|
1210
|
-
coin_list = coin_as_list(did_wallet.did_info.temp_coin)
|
|
1209
|
+
coin_name = did_wallet.did_info.temp_coin.name()
|
|
1211
1210
|
newpuzhash = did_wallet.did_info.temp_puzhash
|
|
1212
1211
|
pubkey = did_wallet.did_info.temp_pubkey
|
|
1213
|
-
return
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1212
|
+
return CreateNewWalletResponse(
|
|
1213
|
+
[],
|
|
1214
|
+
[],
|
|
1215
|
+
type=did_wallet.type().name,
|
|
1216
|
+
my_did=my_did,
|
|
1217
|
+
wallet_id=did_wallet.id(),
|
|
1218
|
+
coin_name=coin_name,
|
|
1219
|
+
coin_list=did_wallet.did_info.temp_coin,
|
|
1220
|
+
newpuzhash=newpuzhash,
|
|
1221
|
+
pubkey=G1Element.from_bytes(pubkey),
|
|
1222
|
+
backup_dids=did_wallet.did_info.backup_ids,
|
|
1223
|
+
num_verifications_required=did_wallet.did_info.num_of_backup_ids_needed,
|
|
1224
|
+
)
|
|
1225
|
+
elif request.wallet_type == CreateNewWalletType.NFT_WALLET:
|
|
1226
|
+
did_id: bytes32 | None = None
|
|
1227
|
+
if request.did_id is not None:
|
|
1228
|
+
did_id = decode_puzzle_hash(request.did_id)
|
|
1228
1229
|
for wallet in self.service.wallet_state_manager.wallets.values():
|
|
1229
|
-
did_id: Optional[bytes32] = None
|
|
1230
|
-
if "did_id" in request and request["did_id"] is not None:
|
|
1231
|
-
did_id = decode_puzzle_hash(request["did_id"])
|
|
1232
1230
|
if wallet.type() == WalletType.NFT:
|
|
1233
1231
|
assert isinstance(wallet, NFTWallet)
|
|
1234
1232
|
if wallet.get_did() == did_id:
|
|
1235
1233
|
log.info("NFT wallet already existed, skipping.")
|
|
1236
|
-
return
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1234
|
+
return CreateNewWalletResponse(
|
|
1235
|
+
[],
|
|
1236
|
+
[],
|
|
1237
|
+
type=wallet.type().name,
|
|
1238
|
+
wallet_id=wallet.id(),
|
|
1239
|
+
)
|
|
1241
1240
|
|
|
1242
1241
|
async with self.service.wallet_state_manager.lock:
|
|
1243
1242
|
nft_wallet: NFTWallet = await NFTWallet.create_new_nft_wallet(
|
|
1244
|
-
wallet_state_manager, main_wallet, did_id, request.
|
|
1243
|
+
wallet_state_manager, main_wallet, did_id, request.name
|
|
1245
1244
|
)
|
|
1246
|
-
return
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
raise AttributeError("Daemon didn't send `initial_target_state`. Try updating the daemon.")
|
|
1255
|
-
|
|
1256
|
-
owner_puzzle_hash: bytes32 = await action_scope.get_puzzle_hash(self.service.wallet_state_manager)
|
|
1257
|
-
|
|
1258
|
-
from chia.pools.pool_wallet_info import initial_pool_state_from_dict
|
|
1259
|
-
|
|
1245
|
+
return CreateNewWalletResponse(
|
|
1246
|
+
[],
|
|
1247
|
+
[],
|
|
1248
|
+
type=nft_wallet.type().name,
|
|
1249
|
+
wallet_id=nft_wallet.id(),
|
|
1250
|
+
)
|
|
1251
|
+
elif request.wallet_type == CreateNewWalletType.POOL_WALLET:
|
|
1252
|
+
if request.mode == WalletCreationMode.NEW:
|
|
1260
1253
|
async with self.service.wallet_state_manager.lock:
|
|
1261
|
-
|
|
1262
|
-
# owner and auth keys. The public keys will go on the blockchain, and the private keys can be found
|
|
1263
|
-
# using the root SK and trying each index from zero. The indexes are not fully unique though,
|
|
1264
|
-
# because the PoolWallet is not created until the tx gets confirmed on chain. Therefore if we
|
|
1265
|
-
# make multiple pool wallets at the same time, they will have the same ID.
|
|
1266
|
-
max_pwi = 1
|
|
1267
|
-
for _, wallet in self.service.wallet_state_manager.wallets.items():
|
|
1268
|
-
if wallet.type() == WalletType.POOLING_WALLET:
|
|
1269
|
-
max_pwi += 1
|
|
1270
|
-
|
|
1271
|
-
if max_pwi + 1 >= (MAX_POOL_WALLETS - 1):
|
|
1272
|
-
raise ValueError(f"Too many pool wallets ({max_pwi}), cannot create any more on this key.")
|
|
1273
|
-
|
|
1274
|
-
owner_pk: G1Element = self.service.wallet_state_manager.main_wallet.hardened_pubkey_for_path(
|
|
1275
|
-
# copied from chia.wallet.derive_keys. Could maybe be an exported constant in the future.
|
|
1276
|
-
[12381, 8444, 5, max_pwi]
|
|
1277
|
-
)
|
|
1278
|
-
|
|
1254
|
+
assert request.initial_target_state is not None # mypy doesn't know about our __post_init__
|
|
1279
1255
|
initial_target_state = initial_pool_state_from_dict(
|
|
1280
|
-
request
|
|
1256
|
+
request.initial_target_state,
|
|
1257
|
+
self.service.wallet_state_manager.new_pool_wallet_pubkey(),
|
|
1258
|
+
await action_scope.get_puzzle_hash(self.service.wallet_state_manager),
|
|
1281
1259
|
)
|
|
1282
1260
|
assert initial_target_state is not None
|
|
1283
1261
|
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
fee,
|
|
1295
|
-
request.get("p2_singleton_delay_time", None),
|
|
1296
|
-
delayed_address,
|
|
1297
|
-
extra_conditions=extra_conditions,
|
|
1298
|
-
)
|
|
1299
|
-
|
|
1300
|
-
except Exception as e:
|
|
1301
|
-
raise ValueError(str(e))
|
|
1302
|
-
return {
|
|
1303
|
-
"total_fee": fee * 2,
|
|
1304
|
-
"transaction": None, # tx_endpoint wrapper will take care of this
|
|
1305
|
-
"transactions": None, # tx_endpoint wrapper will take care of this
|
|
1306
|
-
"launcher_id": launcher_id.hex(),
|
|
1307
|
-
"p2_singleton_puzzle_hash": p2_singleton_puzzle_hash.hex(),
|
|
1308
|
-
}
|
|
1309
|
-
elif request["mode"] == "recovery":
|
|
1310
|
-
raise ValueError("Need upgraded singleton for on-chain recovery")
|
|
1311
|
-
|
|
1312
|
-
else: # undefined wallet_type
|
|
1313
|
-
pass
|
|
1262
|
+
p2_singleton_puzzle_hash, launcher_id = await PoolWallet.create_new_pool_wallet_transaction(
|
|
1263
|
+
wallet_state_manager,
|
|
1264
|
+
main_wallet,
|
|
1265
|
+
initial_target_state,
|
|
1266
|
+
action_scope,
|
|
1267
|
+
request.fee,
|
|
1268
|
+
request.p2_singleton_delay_time,
|
|
1269
|
+
request.p2_singleton_delayed_ph,
|
|
1270
|
+
extra_conditions=extra_conditions,
|
|
1271
|
+
)
|
|
1314
1272
|
|
|
1315
|
-
|
|
1316
|
-
|
|
1273
|
+
return CreateNewWalletResponse(
|
|
1274
|
+
[],
|
|
1275
|
+
[],
|
|
1276
|
+
transaction=REPLACEABLE_TRANSACTION_RECORD,
|
|
1277
|
+
total_fee=uint64(request.fee * 2),
|
|
1278
|
+
launcher_id=launcher_id,
|
|
1279
|
+
p2_singleton_puzzle_hash=p2_singleton_puzzle_hash,
|
|
1280
|
+
# irrelevant, will be replaced in serialization
|
|
1281
|
+
type=WalletType.POOLING_WALLET.name,
|
|
1282
|
+
wallet_id=uint32(0),
|
|
1283
|
+
)
|
|
1317
1284
|
|
|
1318
1285
|
##########################################################################################
|
|
1319
1286
|
# Wallet
|
|
@@ -1329,7 +1296,7 @@ class WalletRpcApi:
|
|
|
1329
1296
|
wallet_balance["fingerprint"] = self.service.logged_in_fingerprint
|
|
1330
1297
|
if wallet.type() in {WalletType.CAT, WalletType.CRCAT, WalletType.RCAT}:
|
|
1331
1298
|
assert isinstance(wallet, CATWallet)
|
|
1332
|
-
wallet_balance["asset_id"] = wallet.get_asset_id()
|
|
1299
|
+
wallet_balance["asset_id"] = wallet.get_asset_id().hex()
|
|
1333
1300
|
if wallet.type() == WalletType.CRCAT:
|
|
1334
1301
|
assert isinstance(wallet, CRCATWallet)
|
|
1335
1302
|
wallet_balance["pending_approval_balance"] = await wallet.get_pending_approval_balance()
|
|
@@ -1352,9 +1319,7 @@ class WalletRpcApi:
|
|
|
1352
1319
|
|
|
1353
1320
|
@marshal
|
|
1354
1321
|
async def get_transaction(self, request: GetTransaction) -> GetTransactionResponse:
|
|
1355
|
-
tr:
|
|
1356
|
-
request.transaction_id
|
|
1357
|
-
)
|
|
1322
|
+
tr: TransactionRecord | None = await self.service.wallet_state_manager.get_transaction(request.transaction_id)
|
|
1358
1323
|
if tr is None:
|
|
1359
1324
|
raise ValueError(f"Transaction 0x{request.transaction_id.hex()} not found")
|
|
1360
1325
|
|
|
@@ -1366,7 +1331,7 @@ class WalletRpcApi:
|
|
|
1366
1331
|
@marshal
|
|
1367
1332
|
async def get_transaction_memo(self, request: GetTransactionMemo) -> GetTransactionMemoResponse:
|
|
1368
1333
|
transaction_id: bytes32 = request.transaction_id
|
|
1369
|
-
tr:
|
|
1334
|
+
tr: TransactionRecord | None = await self.service.wallet_state_manager.get_transaction(transaction_id)
|
|
1370
1335
|
if tr is None:
|
|
1371
1336
|
raise ValueError(f"Transaction 0x{transaction_id.hex()} not found")
|
|
1372
1337
|
if tr.spend_bundle is None or len(tr.spend_bundle.coin_spends) == 0:
|
|
@@ -1390,57 +1355,13 @@ class WalletRpcApi:
|
|
|
1390
1355
|
async def split_coins(
|
|
1391
1356
|
self, request: SplitCoins, action_scope: WalletActionScope, extra_conditions: tuple[Condition, ...] = tuple()
|
|
1392
1357
|
) -> SplitCoinsResponse:
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
coin = optional_coin.coin
|
|
1401
|
-
|
|
1402
|
-
total_amount = request.amount_per_coin * request.number_of_coins
|
|
1403
|
-
|
|
1404
|
-
if coin.amount < total_amount:
|
|
1405
|
-
raise ValueError(
|
|
1406
|
-
f"Coin amount: {coin.amount} is less than the total amount of the split: {total_amount}, exiting."
|
|
1407
|
-
)
|
|
1408
|
-
|
|
1409
|
-
if request.wallet_id not in self.service.wallet_state_manager.wallets:
|
|
1410
|
-
raise ValueError(f"Wallet with ID {request.wallet_id} does not exist")
|
|
1411
|
-
wallet = self.service.wallet_state_manager.wallets[request.wallet_id]
|
|
1412
|
-
if not isinstance(wallet, (Wallet, CATWallet)):
|
|
1413
|
-
raise ValueError("Cannot split coins from non-fungible wallet types")
|
|
1414
|
-
|
|
1415
|
-
outputs = [
|
|
1416
|
-
CreateCoin(
|
|
1417
|
-
await action_scope.get_puzzle_hash(
|
|
1418
|
-
self.service.wallet_state_manager, override_reuse_puzhash_with=False
|
|
1419
|
-
),
|
|
1420
|
-
request.amount_per_coin,
|
|
1421
|
-
)
|
|
1422
|
-
for _ in range(request.number_of_coins)
|
|
1423
|
-
]
|
|
1424
|
-
if len(outputs) == 0:
|
|
1425
|
-
return SplitCoinsResponse([], [])
|
|
1426
|
-
|
|
1427
|
-
if wallet.type() == WalletType.STANDARD_WALLET and coin.amount < total_amount + request.fee:
|
|
1428
|
-
async with action_scope.use() as interface:
|
|
1429
|
-
interface.side_effects.selected_coins.append(coin)
|
|
1430
|
-
coins = await wallet.select_coins(
|
|
1431
|
-
uint64(total_amount + request.fee - coin.amount),
|
|
1432
|
-
action_scope,
|
|
1433
|
-
)
|
|
1434
|
-
coins.add(coin)
|
|
1435
|
-
else:
|
|
1436
|
-
coins = {coin}
|
|
1437
|
-
|
|
1438
|
-
await wallet.generate_signed_transaction(
|
|
1439
|
-
[output.amount for output in outputs],
|
|
1440
|
-
[output.puzzle_hash for output in outputs],
|
|
1441
|
-
action_scope,
|
|
1442
|
-
request.fee,
|
|
1443
|
-
coins=coins,
|
|
1358
|
+
await self.service.wallet_state_manager.split_coins(
|
|
1359
|
+
action_scope=action_scope,
|
|
1360
|
+
wallet_id=request.wallet_id,
|
|
1361
|
+
target_coin_id=request.target_coin_id,
|
|
1362
|
+
amount_per_coin=request.amount_per_coin,
|
|
1363
|
+
number_of_coins=request.number_of_coins,
|
|
1364
|
+
fee=request.fee,
|
|
1444
1365
|
extra_conditions=extra_conditions,
|
|
1445
1366
|
)
|
|
1446
1367
|
|
|
@@ -1451,98 +1372,22 @@ class WalletRpcApi:
|
|
|
1451
1372
|
async def combine_coins(
|
|
1452
1373
|
self, request: CombineCoins, action_scope: WalletActionScope, extra_conditions: tuple[Condition, ...] = tuple()
|
|
1453
1374
|
) -> CombineCoinsResponse:
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
if request.wallet_id not in self.service.wallet_state_manager.wallets:
|
|
1465
|
-
raise ValueError(f"Wallet with ID {request.wallet_id} does not exist")
|
|
1466
|
-
wallet = self.service.wallet_state_manager.wallets[request.wallet_id]
|
|
1467
|
-
if not isinstance(wallet, (Wallet, CATWallet)):
|
|
1468
|
-
raise ValueError("Cannot combine coins from non-fungible wallet types")
|
|
1469
|
-
|
|
1470
|
-
coins: list[Coin] = []
|
|
1471
|
-
|
|
1472
|
-
# First get the coin IDs specified
|
|
1473
|
-
if request.target_coin_ids != []:
|
|
1474
|
-
coins.extend(
|
|
1475
|
-
cr.coin
|
|
1476
|
-
for cr in (
|
|
1477
|
-
await self.service.wallet_state_manager.coin_store.get_coin_records(
|
|
1478
|
-
wallet_id=request.wallet_id,
|
|
1479
|
-
coin_id_filter=HashFilter(request.target_coin_ids, mode=uint8(FilterMode.include.value)),
|
|
1480
|
-
)
|
|
1481
|
-
).records
|
|
1482
|
-
)
|
|
1483
|
-
|
|
1484
|
-
async with action_scope.use() as interface:
|
|
1485
|
-
interface.side_effects.selected_coins.extend(coins)
|
|
1486
|
-
|
|
1487
|
-
# Next let's select enough coins to meet the target + fee if there is one
|
|
1488
|
-
fungible_amount_needed = uint64(0) if request.target_coin_amount is None else request.target_coin_amount
|
|
1489
|
-
if isinstance(wallet, Wallet):
|
|
1490
|
-
fungible_amount_needed = uint64(fungible_amount_needed + request.fee)
|
|
1491
|
-
amount_selected = sum(c.amount for c in coins)
|
|
1492
|
-
if amount_selected < fungible_amount_needed: # implicit fungible_amount_needed > 0 here
|
|
1493
|
-
coins.extend(
|
|
1494
|
-
await wallet.select_coins(
|
|
1495
|
-
amount=uint64(fungible_amount_needed - amount_selected), action_scope=action_scope
|
|
1496
|
-
)
|
|
1497
|
-
)
|
|
1498
|
-
|
|
1499
|
-
if len(coins) > request.number_of_coins:
|
|
1500
|
-
raise ValueError(
|
|
1501
|
-
f"Options specified cannot be met without selecting more coins than specified: {len(coins)}"
|
|
1502
|
-
)
|
|
1503
|
-
|
|
1504
|
-
# Now let's select enough coins to get to the target number to combine
|
|
1505
|
-
if len(coins) < request.number_of_coins:
|
|
1506
|
-
async with action_scope.use() as interface:
|
|
1507
|
-
coins.extend(
|
|
1508
|
-
cr.coin
|
|
1509
|
-
for cr in (
|
|
1510
|
-
await self.service.wallet_state_manager.coin_store.get_coin_records(
|
|
1511
|
-
wallet_id=request.wallet_id,
|
|
1512
|
-
limit=uint32(request.number_of_coins - len(coins)),
|
|
1513
|
-
order=CoinRecordOrder.amount,
|
|
1514
|
-
coin_id_filter=HashFilter(
|
|
1515
|
-
[c.name() for c in interface.side_effects.selected_coins],
|
|
1516
|
-
mode=uint8(FilterMode.exclude.value),
|
|
1517
|
-
),
|
|
1518
|
-
reverse=request.largest_first,
|
|
1519
|
-
)
|
|
1520
|
-
).records
|
|
1521
|
-
)
|
|
1522
|
-
|
|
1523
|
-
async with action_scope.use() as interface:
|
|
1524
|
-
interface.side_effects.selected_coins.extend(coins)
|
|
1525
|
-
|
|
1526
|
-
primary_output_amount = (
|
|
1527
|
-
uint64(sum(c.amount for c in coins)) if request.target_coin_amount is None else request.target_coin_amount
|
|
1528
|
-
)
|
|
1529
|
-
if isinstance(wallet, Wallet):
|
|
1530
|
-
primary_output_amount = uint64(primary_output_amount - request.fee)
|
|
1531
|
-
|
|
1532
|
-
await wallet.generate_signed_transaction(
|
|
1533
|
-
[primary_output_amount],
|
|
1534
|
-
[await action_scope.get_puzzle_hash(self.service.wallet_state_manager)],
|
|
1535
|
-
action_scope,
|
|
1536
|
-
request.fee,
|
|
1537
|
-
coins=set(coins),
|
|
1375
|
+
await self.service.wallet_state_manager.combine_coins(
|
|
1376
|
+
action_scope=action_scope,
|
|
1377
|
+
wallet_id=request.wallet_id,
|
|
1378
|
+
number_of_coins=request.number_of_coins,
|
|
1379
|
+
largest_first=request.largest_first,
|
|
1380
|
+
coin_num_limit=request.coin_num_limit,
|
|
1381
|
+
fee=request.fee,
|
|
1382
|
+
target_coin_amount=request.target_coin_amount,
|
|
1383
|
+
target_coin_ids=request.target_coin_ids if request.target_coin_ids != [] else None,
|
|
1538
1384
|
extra_conditions=extra_conditions,
|
|
1539
1385
|
)
|
|
1540
|
-
|
|
1541
1386
|
return CombineCoinsResponse([], []) # tx_endpoint will take care to fill this out
|
|
1542
1387
|
|
|
1543
1388
|
@marshal
|
|
1544
1389
|
async def get_transactions(self, request: GetTransactions) -> GetTransactionsResponse:
|
|
1545
|
-
to_puzzle_hash:
|
|
1390
|
+
to_puzzle_hash: bytes32 | None = None
|
|
1546
1391
|
if request.to_address is not None:
|
|
1547
1392
|
to_puzzle_hash = decode_puzzle_hash(request.to_address)
|
|
1548
1393
|
|
|
@@ -1564,7 +1409,7 @@ class WalletRpcApi:
|
|
|
1564
1409
|
if tx["type"] not in CLAWBACK_INCOMING_TRANSACTION_TYPES:
|
|
1565
1410
|
continue
|
|
1566
1411
|
coin: Coin = tr.additions[0]
|
|
1567
|
-
record:
|
|
1412
|
+
record: WalletCoinRecord | None = await self.service.wallet_state_manager.coin_store.get_coin_record(
|
|
1568
1413
|
coin.name()
|
|
1569
1414
|
)
|
|
1570
1415
|
if record is None:
|
|
@@ -1624,9 +1469,6 @@ class WalletRpcApi:
|
|
|
1624
1469
|
action_scope: WalletActionScope,
|
|
1625
1470
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
1626
1471
|
) -> SendTransactionResponse:
|
|
1627
|
-
if await self.service.wallet_state_manager.synced() is False:
|
|
1628
|
-
raise ValueError("Wallet needs to be fully synced before sending transactions")
|
|
1629
|
-
|
|
1630
1472
|
wallet = self.service.wallet_state_manager.get_wallet(id=request.wallet_id, required_type=Wallet)
|
|
1631
1473
|
|
|
1632
1474
|
# TODO: Add support for multiple puzhash/amount/memo sets
|
|
@@ -1651,35 +1493,41 @@ class WalletRpcApi:
|
|
|
1651
1493
|
# tx_endpoint will take care of the default values here
|
|
1652
1494
|
return SendTransactionResponse([], [], transaction=REPLACEABLE_TRANSACTION_RECORD, transaction_id=bytes32.zeros)
|
|
1653
1495
|
|
|
1654
|
-
|
|
1496
|
+
@tx_endpoint(push=True)
|
|
1497
|
+
@marshal
|
|
1498
|
+
async def send_transaction_multi(
|
|
1499
|
+
self,
|
|
1500
|
+
request: SendTransactionMulti,
|
|
1501
|
+
action_scope: WalletActionScope,
|
|
1502
|
+
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
1503
|
+
) -> SendTransactionMultiResponse:
|
|
1655
1504
|
if await self.service.wallet_state_manager.synced() is False:
|
|
1656
1505
|
raise ValueError("Wallet needs to be fully synced before sending transactions")
|
|
1657
1506
|
|
|
1658
|
-
|
|
1659
|
-
request.setdefault("push", True)
|
|
1660
|
-
request.setdefault("merge_spends", True)
|
|
1661
|
-
|
|
1662
|
-
wallet_id = uint32(request["wallet_id"])
|
|
1663
|
-
wallet = self.service.wallet_state_manager.wallets[wallet_id]
|
|
1507
|
+
wallet = self.service.wallet_state_manager.wallets[request.wallet_id]
|
|
1664
1508
|
|
|
1665
1509
|
async with self.service.wallet_state_manager.lock:
|
|
1666
|
-
if
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1510
|
+
if issubclass(type(wallet), CATWallet):
|
|
1511
|
+
await self.cat_spend(
|
|
1512
|
+
request.convert_to_proxy(CATSpend).json_serialize_for_transport(
|
|
1513
|
+
action_scope.config.tx_config, extra_conditions, ConditionValidTimes()
|
|
1514
|
+
),
|
|
1515
|
+
hold_lock=False,
|
|
1516
|
+
action_scope_override=action_scope,
|
|
1517
|
+
)
|
|
1671
1518
|
else:
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1519
|
+
await self.create_signed_transaction(
|
|
1520
|
+
request.convert_to_proxy(CreateSignedTransaction).json_serialize_for_transport(
|
|
1521
|
+
action_scope.config.tx_config, extra_conditions, ConditionValidTimes()
|
|
1522
|
+
),
|
|
1523
|
+
hold_lock=False,
|
|
1524
|
+
action_scope_override=action_scope,
|
|
1525
|
+
)
|
|
1675
1526
|
|
|
1676
|
-
#
|
|
1677
|
-
return
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
"transactions": transactions,
|
|
1681
|
-
"unsigned_transactions": response["unsigned_transactions"],
|
|
1682
|
-
}
|
|
1527
|
+
# tx_endpoint will take care of these values
|
|
1528
|
+
return SendTransactionMultiResponse(
|
|
1529
|
+
[], [], transaction=REPLACEABLE_TRANSACTION_RECORD, transaction_id=bytes32.zeros
|
|
1530
|
+
)
|
|
1683
1531
|
|
|
1684
1532
|
@tx_endpoint(push=True, merge_spends=False)
|
|
1685
1533
|
@marshal
|
|
@@ -1696,7 +1544,6 @@ class WalletRpcApi:
|
|
|
1696
1544
|
:param fee: transaction fee in mojos
|
|
1697
1545
|
:return:
|
|
1698
1546
|
"""
|
|
1699
|
-
# Get inner puzzle
|
|
1700
1547
|
coin_records = await self.service.wallet_state_manager.coin_store.get_coin_records(
|
|
1701
1548
|
coin_id_filter=HashFilter.include(request.coin_ids),
|
|
1702
1549
|
coin_type=CoinType.CLAWBACK,
|
|
@@ -1704,31 +1551,23 @@ class WalletRpcApi:
|
|
|
1704
1551
|
spent_range=UInt32Range(stop=uint32(0)),
|
|
1705
1552
|
)
|
|
1706
1553
|
|
|
1707
|
-
coins: dict[Coin, ClawbackMetadata] = {}
|
|
1708
1554
|
batch_size = (
|
|
1709
1555
|
request.batch_size
|
|
1710
1556
|
if request.batch_size is not None
|
|
1711
1557
|
else self.service.wallet_state_manager.config.get("auto_claim", {}).get("batch_size", 50)
|
|
1712
1558
|
)
|
|
1713
|
-
|
|
1559
|
+
records_list = list(coin_records.coin_id_to_record.values())
|
|
1560
|
+
for i in range(0, len(records_list), batch_size):
|
|
1714
1561
|
try:
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
request.fee,
|
|
1722
|
-
action_scope,
|
|
1723
|
-
request.force,
|
|
1724
|
-
extra_conditions=extra_conditions,
|
|
1725
|
-
)
|
|
1726
|
-
coins = {}
|
|
1727
|
-
except Exception as e:
|
|
1728
|
-
log.error(f"Failed to spend clawback coin {coin_id.hex()}: %s", e)
|
|
1729
|
-
if len(coins) > 0:
|
|
1562
|
+
coin_batch = {
|
|
1563
|
+
coin_record.coin: coin_record.parsed_metadata() for coin_record in records_list[i : i + batch_size]
|
|
1564
|
+
}
|
|
1565
|
+
except WalletCoinRecordMetadataParsingError as e:
|
|
1566
|
+
log.error("Failed to spend clawback coin: %s", e)
|
|
1567
|
+
continue
|
|
1730
1568
|
await self.service.wallet_state_manager.spend_clawback_coins(
|
|
1731
|
-
|
|
1569
|
+
# Semantically, we're guaranteed the right type here, but the typing isn't there
|
|
1570
|
+
coin_batch, # type: ignore[arg-type]
|
|
1732
1571
|
request.fee,
|
|
1733
1572
|
action_scope,
|
|
1734
1573
|
request.force,
|
|
@@ -1796,58 +1635,43 @@ class WalletRpcApi:
|
|
|
1796
1635
|
raise ValueError("Wallet needs to be fully synced before getting all coins")
|
|
1797
1636
|
|
|
1798
1637
|
state_mgr = self.service.wallet_state_manager
|
|
1799
|
-
wallet = state_mgr.wallets[request.wallet_id]
|
|
1800
1638
|
async with state_mgr.lock:
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1639
|
+
# Removals
|
|
1640
|
+
unconfirmed_removals = await state_mgr.unconfirmed_additions_or_removals_for_wallet(
|
|
1641
|
+
wallet_id=request.wallet_id, get="removals"
|
|
1642
|
+
)
|
|
1643
|
+
unconfirmed_removal_ids = {coin.name() for coin in unconfirmed_removals}
|
|
1644
|
+
removal_records: list[CoinRecord] = []
|
|
1645
|
+
for coin_record in (
|
|
1646
|
+
await state_mgr.coin_store.get_coin_records(
|
|
1647
|
+
coin_id_filter=HashFilter.include(list(unconfirmed_removal_ids))
|
|
1808
1648
|
)
|
|
1649
|
+
).records:
|
|
1650
|
+
removal_records.append(await state_mgr.get_coin_record_by_wallet_record(coin_record))
|
|
1809
1651
|
|
|
1810
|
-
#
|
|
1811
|
-
|
|
1812
|
-
request.wallet_id
|
|
1652
|
+
# Additions
|
|
1653
|
+
unconfirmed_additions = await state_mgr.unconfirmed_additions_or_removals_for_wallet(
|
|
1654
|
+
wallet_id=request.wallet_id, get="additions"
|
|
1655
|
+
)
|
|
1656
|
+
|
|
1657
|
+
# Spendable coins
|
|
1658
|
+
unfiltered_spendable_coin_records = await state_mgr.get_spendable_coins_for_wallet(
|
|
1659
|
+
request.wallet_id, pending_removals=unconfirmed_removal_ids
|
|
1660
|
+
)
|
|
1661
|
+
filtered_spendable_coins = request.autofill(
|
|
1662
|
+
constants=self.service.wallet_state_manager.constants
|
|
1663
|
+
).filter_coins({cr.coin for cr in unfiltered_spendable_coin_records})
|
|
1664
|
+
filtered_spendable_coin_records = list(
|
|
1665
|
+
cr for cr in unfiltered_spendable_coin_records if cr.coin in filtered_spendable_coins
|
|
1813
1666
|
)
|
|
1814
|
-
unconfirmed_removal_ids: dict[bytes32, uint64] = {
|
|
1815
|
-
coin.name(): transaction.created_at_time
|
|
1816
|
-
for transaction in unconfirmed_transactions
|
|
1817
|
-
for coin in transaction.removals
|
|
1818
|
-
}
|
|
1819
|
-
unconfirmed_additions: list[Coin] = [
|
|
1820
|
-
coin
|
|
1821
|
-
for transaction in unconfirmed_transactions
|
|
1822
|
-
for coin in transaction.additions
|
|
1823
|
-
if await state_mgr.does_coin_belong_to_wallet(coin, request.wallet_id)
|
|
1824
|
-
]
|
|
1825
1667
|
valid_spendable_cr: list[CoinRecord] = []
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
if coin_record.name() in unconfirmed_removal_ids:
|
|
1829
|
-
unconfirmed_removals.append(coin_record.to_coin_record(unconfirmed_removal_ids[coin_record.name()]))
|
|
1830
|
-
|
|
1831
|
-
cs_config = request.autofill(constants=self.service.wallet_state_manager.constants)
|
|
1832
|
-
for coin_record in spendable_coins: # remove all the unconfirmed coins, exclude coins and dust.
|
|
1833
|
-
if coin_record.name() in unconfirmed_removal_ids:
|
|
1834
|
-
continue
|
|
1835
|
-
if coin_record.coin.name() in cs_config.excluded_coin_ids:
|
|
1836
|
-
continue
|
|
1837
|
-
if (coin_record.coin.amount < cs_config.min_coin_amount) or (
|
|
1838
|
-
coin_record.coin.amount > cs_config.max_coin_amount
|
|
1839
|
-
):
|
|
1840
|
-
continue
|
|
1841
|
-
if coin_record.coin.amount in cs_config.excluded_coin_amounts:
|
|
1842
|
-
continue
|
|
1843
|
-
c_r = await state_mgr.get_coin_record_by_wallet_record(coin_record)
|
|
1844
|
-
assert c_r is not None and c_r.coin == coin_record.coin # this should never happen
|
|
1845
|
-
valid_spendable_cr.append(c_r)
|
|
1668
|
+
for coin_record in filtered_spendable_coin_records:
|
|
1669
|
+
valid_spendable_cr.append(await state_mgr.get_coin_record_by_wallet_record(coin_record))
|
|
1846
1670
|
|
|
1847
1671
|
return GetSpendableCoinsResponse(
|
|
1848
1672
|
confirmed_records=valid_spendable_cr,
|
|
1849
|
-
unconfirmed_removals=
|
|
1850
|
-
unconfirmed_additions=unconfirmed_additions,
|
|
1673
|
+
unconfirmed_removals=removal_records,
|
|
1674
|
+
unconfirmed_additions=list(unconfirmed_additions),
|
|
1851
1675
|
)
|
|
1852
1676
|
|
|
1853
1677
|
@marshal
|
|
@@ -1886,7 +1710,7 @@ class WalletRpcApi:
|
|
|
1886
1710
|
async def get_current_derivation_index(self, request: Empty) -> GetCurrentDerivationIndexResponse:
|
|
1887
1711
|
assert self.service.wallet_state_manager is not None
|
|
1888
1712
|
|
|
1889
|
-
index:
|
|
1713
|
+
index: uint32 | None = await self.service.wallet_state_manager.puzzle_store.get_last_derivation_path()
|
|
1890
1714
|
|
|
1891
1715
|
return GetCurrentDerivationIndexResponse(index)
|
|
1892
1716
|
|
|
@@ -1899,7 +1723,7 @@ class WalletRpcApi:
|
|
|
1899
1723
|
if synced is False:
|
|
1900
1724
|
raise ValueError("Wallet needs to be fully synced before extending derivation index")
|
|
1901
1725
|
|
|
1902
|
-
current:
|
|
1726
|
+
current: uint32 | None = await self.service.wallet_state_manager.puzzle_store.get_last_derivation_path()
|
|
1903
1727
|
|
|
1904
1728
|
# Additional sanity check that the wallet is synced
|
|
1905
1729
|
if current is None:
|
|
@@ -1929,29 +1753,17 @@ class WalletRpcApi:
|
|
|
1929
1753
|
|
|
1930
1754
|
@marshal
|
|
1931
1755
|
async def get_notifications(self, request: GetNotifications) -> GetNotificationsResponse:
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
] = await self.service.wallet_state_manager.notification_manager.notification_store.get_all_notifications(
|
|
1936
|
-
pagination=(request.start, request.end)
|
|
1756
|
+
return GetNotificationsResponse(
|
|
1757
|
+
await self.service.wallet_state_manager.notification_manager.notification_store.get_notifications(
|
|
1758
|
+
coin_ids=request.ids, pagination=(request.start, request.end)
|
|
1937
1759
|
)
|
|
1938
|
-
|
|
1939
|
-
notifications = (
|
|
1940
|
-
await self.service.wallet_state_manager.notification_manager.notification_store.get_notifications(
|
|
1941
|
-
request.ids
|
|
1942
|
-
)
|
|
1943
|
-
)
|
|
1944
|
-
|
|
1945
|
-
return GetNotificationsResponse(notifications)
|
|
1760
|
+
)
|
|
1946
1761
|
|
|
1947
1762
|
@marshal
|
|
1948
1763
|
async def delete_notifications(self, request: DeleteNotifications) -> Empty:
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
await self.service.wallet_state_manager.notification_manager.notification_store.delete_notifications(
|
|
1953
|
-
request.ids
|
|
1954
|
-
)
|
|
1764
|
+
await self.service.wallet_state_manager.notification_manager.notification_store.delete_notifications(
|
|
1765
|
+
coin_ids=request.ids
|
|
1766
|
+
)
|
|
1955
1767
|
|
|
1956
1768
|
return Empty()
|
|
1957
1769
|
|
|
@@ -1977,57 +1789,13 @@ class WalletRpcApi:
|
|
|
1977
1789
|
|
|
1978
1790
|
@marshal
|
|
1979
1791
|
async def verify_signature(self, request: VerifySignature) -> VerifySignatureResponse:
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
# signatures made by `chia keys sign`, which uses BLS_MESSAGE_AUGMENTATION_HEX_INPUT
|
|
1987
|
-
if request.signing_mode is None:
|
|
1988
|
-
signing_mode = SigningMode.BLS_MESSAGE_AUGMENTATION_HEX_INPUT
|
|
1989
|
-
else:
|
|
1990
|
-
try:
|
|
1991
|
-
signing_mode = SigningMode(request.signing_mode)
|
|
1992
|
-
except ValueError:
|
|
1993
|
-
raise ValueError(f"Invalid signing mode: {request.signing_mode!r}")
|
|
1994
|
-
|
|
1995
|
-
if signing_mode in {SigningMode.CHIP_0002, SigningMode.CHIP_0002_P2_DELEGATED_CONDITIONS}:
|
|
1996
|
-
# CHIP-0002 message signatures are made over the tree hash of:
|
|
1997
|
-
# ("Chia Signed Message", message)
|
|
1998
|
-
message_to_verify: bytes = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, request.message)).get_tree_hash()
|
|
1999
|
-
elif signing_mode == SigningMode.BLS_MESSAGE_AUGMENTATION_HEX_INPUT:
|
|
2000
|
-
# Message is expected to be a hex string
|
|
2001
|
-
message_to_verify = hexstr_to_bytes(request.message)
|
|
2002
|
-
elif signing_mode == SigningMode.BLS_MESSAGE_AUGMENTATION_UTF8_INPUT:
|
|
2003
|
-
# Message is expected to be a UTF-8 string
|
|
2004
|
-
message_to_verify = bytes(request.message, "utf-8")
|
|
2005
|
-
else:
|
|
2006
|
-
raise ValueError(f"Unsupported signing mode: {request.signing_mode!r}")
|
|
2007
|
-
|
|
2008
|
-
# Verify using the BLS message augmentation scheme
|
|
2009
|
-
is_valid = AugSchemeMPL.verify(
|
|
2010
|
-
request.pubkey,
|
|
2011
|
-
message_to_verify,
|
|
2012
|
-
request.signature,
|
|
1792
|
+
return verify_signature(
|
|
1793
|
+
signing_mode=request.signing_mode_enum,
|
|
1794
|
+
public_key=request.pubkey,
|
|
1795
|
+
message=request.message,
|
|
1796
|
+
signature=request.signature,
|
|
1797
|
+
address=request.address,
|
|
2013
1798
|
)
|
|
2014
|
-
if request.address is not None:
|
|
2015
|
-
# For signatures made by the sign_message_by_address/sign_message_by_id
|
|
2016
|
-
# endpoints, the "address" field should contain the p2_address of the NFT/DID
|
|
2017
|
-
# that was used to sign the message.
|
|
2018
|
-
puzzle_hash: bytes32 = decode_puzzle_hash(request.address)
|
|
2019
|
-
expected_puzzle_hash: Optional[bytes32] = None
|
|
2020
|
-
if signing_mode == SigningMode.CHIP_0002_P2_DELEGATED_CONDITIONS:
|
|
2021
|
-
puzzle = p2_delegated_conditions.puzzle_for_pk(Program.to(request.pubkey))
|
|
2022
|
-
expected_puzzle_hash = bytes32(puzzle.get_tree_hash())
|
|
2023
|
-
else:
|
|
2024
|
-
expected_puzzle_hash = puzzle_hash_for_synthetic_public_key(request.pubkey)
|
|
2025
|
-
if puzzle_hash != expected_puzzle_hash:
|
|
2026
|
-
return VerifySignatureResponse(isValid=False, error="Public key doesn't match the address")
|
|
2027
|
-
if is_valid:
|
|
2028
|
-
return VerifySignatureResponse(isValid=is_valid)
|
|
2029
|
-
else:
|
|
2030
|
-
return VerifySignatureResponse(isValid=False, error="Signature is invalid.")
|
|
2031
1799
|
|
|
2032
1800
|
@marshal
|
|
2033
1801
|
async def sign_message_by_address(self, request: SignMessageByAddress) -> SignMessageByAddressResponse:
|
|
@@ -2036,21 +1804,18 @@ class WalletRpcApi:
|
|
|
2036
1804
|
:param request:
|
|
2037
1805
|
:return:
|
|
2038
1806
|
"""
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
mode = SigningMode.BLS_MESSAGE_AUGMENTATION_HEX_INPUT
|
|
2047
|
-
pubkey, signature = await self.service.wallet_state_manager.main_wallet.sign_message(
|
|
2048
|
-
request.message, puzzle_hash, mode
|
|
1807
|
+
synthetic_secret_key = self.service.wallet_state_manager.main_wallet.convert_secret_key_to_synthetic(
|
|
1808
|
+
await self.service.wallet_state_manager.get_private_key(decode_puzzle_hash(request.address))
|
|
1809
|
+
)
|
|
1810
|
+
signing_response = sign_message(
|
|
1811
|
+
secret_key=synthetic_secret_key,
|
|
1812
|
+
message=request.message,
|
|
1813
|
+
mode=request.signing_mode_enum,
|
|
2049
1814
|
)
|
|
2050
1815
|
return SignMessageByAddressResponse(
|
|
2051
|
-
pubkey=pubkey,
|
|
2052
|
-
signature=signature,
|
|
2053
|
-
signing_mode=
|
|
1816
|
+
pubkey=signing_response.pubkey,
|
|
1817
|
+
signature=signing_response.signature,
|
|
1818
|
+
signing_mode=request.signing_mode_enum.value,
|
|
2054
1819
|
)
|
|
2055
1820
|
|
|
2056
1821
|
@marshal
|
|
@@ -2061,53 +1826,67 @@ class WalletRpcApi:
|
|
|
2061
1826
|
:return:
|
|
2062
1827
|
"""
|
|
2063
1828
|
entity_id: bytes32 = decode_puzzle_hash(request.id)
|
|
2064
|
-
selected_wallet: Optional[WalletProtocol[Any]] = None
|
|
2065
|
-
mode: SigningMode = SigningMode.CHIP_0002
|
|
2066
|
-
if request.is_hex and request.safe_mode:
|
|
2067
|
-
mode = SigningMode.CHIP_0002_HEX_INPUT
|
|
2068
|
-
elif not request.is_hex and not request.safe_mode:
|
|
2069
|
-
mode = SigningMode.BLS_MESSAGE_AUGMENTATION_UTF8_INPUT
|
|
2070
|
-
elif request.is_hex and not request.safe_mode:
|
|
2071
|
-
mode = SigningMode.BLS_MESSAGE_AUGMENTATION_HEX_INPUT
|
|
2072
1829
|
if is_valid_address(request.id, {AddressType.DID}, self.service.config):
|
|
1830
|
+
did_wallet: DIDWallet | None = None
|
|
2073
1831
|
for wallet in self.service.wallet_state_manager.wallets.values():
|
|
2074
1832
|
if wallet.type() == WalletType.DECENTRALIZED_ID.value:
|
|
2075
1833
|
assert isinstance(wallet, DIDWallet)
|
|
2076
1834
|
assert wallet.did_info.origin_coin is not None
|
|
2077
1835
|
if wallet.did_info.origin_coin.name() == entity_id:
|
|
2078
|
-
|
|
1836
|
+
did_wallet = wallet
|
|
2079
1837
|
break
|
|
2080
|
-
if
|
|
1838
|
+
if did_wallet is None:
|
|
2081
1839
|
raise ValueError(f"DID for {entity_id.hex()} doesn't exist.")
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
1840
|
+
synthetic_secret_key = self.service.wallet_state_manager.main_wallet.convert_secret_key_to_synthetic(
|
|
1841
|
+
await self.service.wallet_state_manager.get_private_key(await did_wallet.current_p2_puzzle_hash())
|
|
1842
|
+
)
|
|
1843
|
+
latest_coin_id = (await did_wallet.get_coin()).name()
|
|
1844
|
+
signing_response = sign_message(
|
|
1845
|
+
secret_key=synthetic_secret_key,
|
|
1846
|
+
message=request.message,
|
|
1847
|
+
mode=request.signing_mode_enum,
|
|
1848
|
+
)
|
|
1849
|
+
return SignMessageByIDResponse(
|
|
1850
|
+
pubkey=signing_response.pubkey,
|
|
1851
|
+
signature=signing_response.signature,
|
|
1852
|
+
signing_mode=request.signing_mode_enum.value,
|
|
1853
|
+
latest_coin_id=latest_coin_id,
|
|
1854
|
+
)
|
|
2085
1855
|
elif is_valid_address(request.id, {AddressType.NFT}, self.service.config):
|
|
2086
|
-
|
|
1856
|
+
nft_wallet: NFTWallet | None = None
|
|
1857
|
+
target_nft: NFTCoinInfo | None = None
|
|
2087
1858
|
for wallet in self.service.wallet_state_manager.wallets.values():
|
|
2088
1859
|
if wallet.type() == WalletType.NFT.value:
|
|
2089
1860
|
assert isinstance(wallet, NFTWallet)
|
|
2090
|
-
nft:
|
|
1861
|
+
nft: NFTCoinInfo | None = await wallet.get_nft(entity_id)
|
|
2091
1862
|
if nft is not None:
|
|
2092
|
-
|
|
1863
|
+
nft_wallet = wallet
|
|
2093
1864
|
target_nft = nft
|
|
2094
1865
|
break
|
|
2095
|
-
if
|
|
1866
|
+
if nft_wallet is None or target_nft is None:
|
|
2096
1867
|
raise ValueError(f"NFT for {entity_id.hex()} doesn't exist.")
|
|
2097
1868
|
|
|
2098
|
-
assert isinstance(
|
|
2099
|
-
|
|
1869
|
+
assert isinstance(nft_wallet, NFTWallet)
|
|
1870
|
+
synthetic_secret_key = self.service.wallet_state_manager.main_wallet.convert_secret_key_to_synthetic(
|
|
1871
|
+
await self.service.wallet_state_manager.get_private_key(
|
|
1872
|
+
await nft_wallet.current_p2_puzzle_hash(target_nft)
|
|
1873
|
+
)
|
|
1874
|
+
)
|
|
2100
1875
|
latest_coin_id = target_nft.coin.name()
|
|
1876
|
+
signing_response = sign_message(
|
|
1877
|
+
secret_key=synthetic_secret_key,
|
|
1878
|
+
message=request.message,
|
|
1879
|
+
mode=request.signing_mode_enum,
|
|
1880
|
+
)
|
|
1881
|
+
return SignMessageByIDResponse(
|
|
1882
|
+
pubkey=signing_response.pubkey,
|
|
1883
|
+
signature=signing_response.signature,
|
|
1884
|
+
signing_mode=request.signing_mode_enum.value,
|
|
1885
|
+
latest_coin_id=latest_coin_id,
|
|
1886
|
+
)
|
|
2101
1887
|
else:
|
|
2102
1888
|
raise ValueError(f"Unknown ID type, {request.id}")
|
|
2103
1889
|
|
|
2104
|
-
return SignMessageByIDResponse(
|
|
2105
|
-
pubkey=pubkey,
|
|
2106
|
-
signature=signature,
|
|
2107
|
-
latest_coin_id=latest_coin_id,
|
|
2108
|
-
signing_mode=mode.value,
|
|
2109
|
-
)
|
|
2110
|
-
|
|
2111
1890
|
##########################################################################################
|
|
2112
1891
|
# CATs and Trading
|
|
2113
1892
|
##########################################################################################
|
|
@@ -2147,8 +1926,6 @@ class WalletRpcApi:
|
|
|
2147
1926
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2148
1927
|
hold_lock: bool = True,
|
|
2149
1928
|
) -> CATSpendResponse:
|
|
2150
|
-
if await self.service.wallet_state_manager.synced() is False:
|
|
2151
|
-
raise ValueError("Wallet needs to be fully synced.")
|
|
2152
1929
|
wallet = self.service.wallet_state_manager.get_wallet(id=request.wallet_id, required_type=CATWallet)
|
|
2153
1930
|
|
|
2154
1931
|
amounts: list[uint64] = []
|
|
@@ -2168,7 +1945,7 @@ class WalletRpcApi:
|
|
|
2168
1945
|
puzzle_hashes.append(decode_puzzle_hash(request.inner_address)) # type: ignore[arg-type]
|
|
2169
1946
|
if request.memos is not None:
|
|
2170
1947
|
memos.append([mem.encode("utf-8") for mem in request.memos])
|
|
2171
|
-
coins:
|
|
1948
|
+
coins: set[Coin] | None = None
|
|
2172
1949
|
if request.coins is not None and len(request.coins) > 0:
|
|
2173
1950
|
coins = set(request.coins)
|
|
2174
1951
|
|
|
@@ -2202,12 +1979,12 @@ class WalletRpcApi:
|
|
|
2202
1979
|
@marshal
|
|
2203
1980
|
async def cat_get_asset_id(self, request: CATGetAssetID) -> CATGetAssetIDResponse:
|
|
2204
1981
|
wallet = self.service.wallet_state_manager.get_wallet(id=request.wallet_id, required_type=CATWallet)
|
|
2205
|
-
asset_id
|
|
2206
|
-
return CATGetAssetIDResponse(asset_id=
|
|
1982
|
+
asset_id = wallet.get_asset_id()
|
|
1983
|
+
return CATGetAssetIDResponse(asset_id=asset_id, wallet_id=request.wallet_id)
|
|
2207
1984
|
|
|
2208
1985
|
@marshal
|
|
2209
1986
|
async def cat_asset_id_to_name(self, request: CATAssetIDToName) -> CATAssetIDToNameResponse:
|
|
2210
|
-
wallet = await self.service.wallet_state_manager.get_wallet_for_asset_id(request.asset_id
|
|
1987
|
+
wallet = await self.service.wallet_state_manager.get_wallet_for_asset_id(request.asset_id)
|
|
2211
1988
|
if wallet is None:
|
|
2212
1989
|
if request.asset_id.hex() in DEFAULT_CATS:
|
|
2213
1990
|
return CATAssetIDToNameResponse(wallet_id=None, name=DEFAULT_CATS[request.asset_id.hex()]["name"])
|
|
@@ -2217,126 +1994,98 @@ class WalletRpcApi:
|
|
|
2217
1994
|
return CATAssetIDToNameResponse(wallet_id=wallet.id(), name=wallet.get_name())
|
|
2218
1995
|
|
|
2219
1996
|
@tx_endpoint(push=False)
|
|
1997
|
+
@marshal
|
|
2220
1998
|
async def create_offer_for_ids(
|
|
2221
1999
|
self,
|
|
2222
|
-
request:
|
|
2000
|
+
request: CreateOfferForIDs,
|
|
2223
2001
|
action_scope: WalletActionScope,
|
|
2224
2002
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2225
|
-
) ->
|
|
2003
|
+
) -> CreateOfferForIDsResponse:
|
|
2226
2004
|
if action_scope.config.push:
|
|
2227
|
-
raise ValueError("Cannot push an incomplete spend")
|
|
2228
|
-
|
|
2229
|
-
offer: dict[str, int] = request["offer"]
|
|
2230
|
-
fee: uint64 = uint64(request.get("fee", 0))
|
|
2231
|
-
validate_only: bool = request.get("validate_only", False)
|
|
2232
|
-
driver_dict_str: Optional[dict[str, Any]] = request.get("driver_dict", None)
|
|
2233
|
-
marshalled_solver = request.get("solver")
|
|
2234
|
-
solver: Optional[Solver]
|
|
2235
|
-
if marshalled_solver is None:
|
|
2236
|
-
solver = None
|
|
2237
|
-
else:
|
|
2238
|
-
solver = Solver(info=marshalled_solver)
|
|
2005
|
+
raise ValueError("Cannot push an incomplete spend")
|
|
2239
2006
|
|
|
2240
2007
|
# This driver_dict construction is to maintain backward compatibility where everything is assumed to be a CAT
|
|
2241
2008
|
driver_dict: dict[bytes32, PuzzleInfo] = {}
|
|
2242
|
-
if
|
|
2243
|
-
for key, amount in
|
|
2244
|
-
if amount > 0:
|
|
2245
|
-
|
|
2246
|
-
driver_dict[bytes32.from_hexstr(key)] = PuzzleInfo(
|
|
2247
|
-
{"type": AssetType.CAT.value, "tail": "0x" + key}
|
|
2248
|
-
)
|
|
2249
|
-
except ValueError:
|
|
2250
|
-
pass
|
|
2009
|
+
if request.driver_dict is None:
|
|
2010
|
+
for key, amount in request.offer_spec.items():
|
|
2011
|
+
if amount > 0 and isinstance(key, bytes32):
|
|
2012
|
+
driver_dict[key] = PuzzleInfo({"type": AssetType.CAT.value, "tail": "0x" + key.hex()})
|
|
2251
2013
|
else:
|
|
2252
|
-
|
|
2253
|
-
driver_dict[bytes32.from_hexstr(key)] = PuzzleInfo(value)
|
|
2254
|
-
|
|
2255
|
-
modified_offer: dict[Union[int, bytes32], int] = {}
|
|
2256
|
-
for wallet_identifier, change in offer.items():
|
|
2257
|
-
try:
|
|
2258
|
-
modified_offer[bytes32.from_hexstr(wallet_identifier)] = change
|
|
2259
|
-
except ValueError:
|
|
2260
|
-
modified_offer[int(wallet_identifier)] = change
|
|
2014
|
+
driver_dict = request.driver_dict
|
|
2261
2015
|
|
|
2262
2016
|
async with self.service.wallet_state_manager.lock:
|
|
2263
2017
|
result = await self.service.wallet_state_manager.trade_manager.create_offer_for_ids(
|
|
2264
|
-
|
|
2018
|
+
request.offer_spec,
|
|
2265
2019
|
action_scope,
|
|
2266
2020
|
driver_dict,
|
|
2267
|
-
solver=solver,
|
|
2268
|
-
fee=fee,
|
|
2269
|
-
validate_only=validate_only,
|
|
2021
|
+
solver=request.solver,
|
|
2022
|
+
fee=request.fee,
|
|
2023
|
+
validate_only=request.validate_only,
|
|
2270
2024
|
extra_conditions=extra_conditions,
|
|
2271
2025
|
)
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
async def get_offer_summary(self, request:
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
if
|
|
2288
|
-
response =
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
"fees": offer.fees(),
|
|
2293
|
-
"infos": infos,
|
|
2294
|
-
"additions": [c.name().hex() for c in offer.additions()],
|
|
2295
|
-
"removals": [c.name().hex() for c in offer.removals()],
|
|
2296
|
-
"valid_times": {
|
|
2297
|
-
k: v
|
|
2298
|
-
for k, v in valid_times.to_json_dict().items()
|
|
2299
|
-
if k
|
|
2300
|
-
not in {
|
|
2301
|
-
"max_secs_after_created",
|
|
2302
|
-
"min_secs_since_created",
|
|
2303
|
-
"max_blocks_after_created",
|
|
2304
|
-
"min_blocks_since_created",
|
|
2305
|
-
}
|
|
2306
|
-
},
|
|
2307
|
-
},
|
|
2308
|
-
"id": offer.name(),
|
|
2309
|
-
}
|
|
2026
|
+
|
|
2027
|
+
return CreateOfferForIDsResponse(
|
|
2028
|
+
[],
|
|
2029
|
+
[],
|
|
2030
|
+
offer=Offer.from_bytes(result[1].offer),
|
|
2031
|
+
trade_record=result[1],
|
|
2032
|
+
)
|
|
2033
|
+
|
|
2034
|
+
@marshal
|
|
2035
|
+
async def get_offer_summary(self, request: GetOfferSummary) -> GetOfferSummaryResponse:
|
|
2036
|
+
dl_summary = None
|
|
2037
|
+
if not request.advanced:
|
|
2038
|
+
dl_summary = await self.service.wallet_state_manager.trade_manager.get_dl_offer_summary(
|
|
2039
|
+
request.parsed_offer
|
|
2040
|
+
)
|
|
2041
|
+
if dl_summary is not None:
|
|
2042
|
+
response = GetOfferSummaryResponse(
|
|
2043
|
+
data_layer_summary=dl_summary,
|
|
2044
|
+
id=request.parsed_offer.name(),
|
|
2045
|
+
)
|
|
2310
2046
|
else:
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2047
|
+
offered, requested, infos, valid_times = request.parsed_offer.summary()
|
|
2048
|
+
response = GetOfferSummaryResponse(
|
|
2049
|
+
summary=OfferSummary(
|
|
2050
|
+
offered=offered,
|
|
2051
|
+
requested=requested,
|
|
2052
|
+
fees=uint64(request.parsed_offer.fees()),
|
|
2053
|
+
infos=infos,
|
|
2054
|
+
additions=[c.name() for c in request.parsed_offer.additions()],
|
|
2055
|
+
removals=[c.name() for c in request.parsed_offer.removals()],
|
|
2056
|
+
valid_times=valid_times.only_absolutes(),
|
|
2057
|
+
),
|
|
2058
|
+
id=request.parsed_offer.name(),
|
|
2059
|
+
)
|
|
2315
2060
|
|
|
2316
2061
|
# This is a bit of a hack in favor of returning some more manageable information about CR-CATs
|
|
2317
2062
|
# A more general solution surely exists, but I'm not sure what it is right now
|
|
2318
|
-
return
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2063
|
+
return dataclasses.replace(
|
|
2064
|
+
response,
|
|
2065
|
+
summary=dataclasses.replace(
|
|
2066
|
+
response.summary,
|
|
2067
|
+
infos={
|
|
2323
2068
|
key: (
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2069
|
+
PuzzleInfo(
|
|
2070
|
+
{
|
|
2071
|
+
**info.info,
|
|
2072
|
+
"also": {
|
|
2073
|
+
**info.info["also"],
|
|
2074
|
+
"flags": ProofsChecker.from_program(
|
|
2075
|
+
uncurry_puzzle(Program(assemble(info.info["also"]["proofs_checker"])))
|
|
2076
|
+
).flags,
|
|
2077
|
+
},
|
|
2078
|
+
}
|
|
2079
|
+
)
|
|
2080
|
+
if "also" in info.info and "proofs_checker" in info.info["also"]
|
|
2334
2081
|
else info
|
|
2335
2082
|
)
|
|
2336
|
-
for key, info in response
|
|
2083
|
+
for key, info in response.summary.infos.items()
|
|
2337
2084
|
},
|
|
2338
|
-
|
|
2339
|
-
|
|
2085
|
+
)
|
|
2086
|
+
if response.summary is not None
|
|
2087
|
+
else None,
|
|
2088
|
+
)
|
|
2340
2089
|
|
|
2341
2090
|
@marshal
|
|
2342
2091
|
async def check_offer_validity(self, request: CheckOfferValidity) -> CheckOfferValidityResponse:
|
|
@@ -2348,88 +2097,76 @@ class WalletRpcApi:
|
|
|
2348
2097
|
)
|
|
2349
2098
|
|
|
2350
2099
|
@tx_endpoint(push=True)
|
|
2100
|
+
@marshal
|
|
2351
2101
|
async def take_offer(
|
|
2352
2102
|
self,
|
|
2353
|
-
request:
|
|
2103
|
+
request: TakeOffer,
|
|
2354
2104
|
action_scope: WalletActionScope,
|
|
2355
2105
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2356
|
-
) ->
|
|
2357
|
-
offer_hex: str = request["offer"]
|
|
2358
|
-
|
|
2359
|
-
offer = Offer.from_bech32(offer_hex)
|
|
2360
|
-
fee: uint64 = uint64(request.get("fee", 0))
|
|
2361
|
-
maybe_marshalled_solver: Optional[dict[str, Any]] = request.get("solver")
|
|
2362
|
-
solver: Optional[Solver]
|
|
2363
|
-
if maybe_marshalled_solver is None:
|
|
2364
|
-
solver = None
|
|
2365
|
-
else:
|
|
2366
|
-
solver = Solver(info=maybe_marshalled_solver)
|
|
2367
|
-
|
|
2106
|
+
) -> TakeOfferResponse:
|
|
2368
2107
|
peer = self.service.get_full_node_peer()
|
|
2369
2108
|
trade_record = await self.service.wallet_state_manager.trade_manager.respond_to_offer(
|
|
2370
|
-
|
|
2109
|
+
request.parsed_offer,
|
|
2371
2110
|
peer,
|
|
2372
2111
|
action_scope,
|
|
2373
|
-
fee=fee,
|
|
2374
|
-
solver=solver,
|
|
2112
|
+
fee=request.fee,
|
|
2113
|
+
solver=request.solver,
|
|
2375
2114
|
extra_conditions=extra_conditions,
|
|
2376
2115
|
)
|
|
2377
2116
|
|
|
2378
2117
|
async with action_scope.use() as interface:
|
|
2379
2118
|
interface.side_effects.signing_responses.append(
|
|
2380
|
-
SigningResponse(bytes(
|
|
2119
|
+
SigningResponse(bytes(request.parsed_offer._bundle.aggregated_signature), trade_record.trade_id)
|
|
2381
2120
|
)
|
|
2382
2121
|
|
|
2383
|
-
return
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2122
|
+
return TakeOfferResponse(
|
|
2123
|
+
[], # tx_endpoint will fill in this default value
|
|
2124
|
+
[], # tx_endpoint will fill in this default value
|
|
2125
|
+
Offer.from_bytes(trade_record.offer),
|
|
2126
|
+
trade_record,
|
|
2127
|
+
)
|
|
2389
2128
|
|
|
2390
|
-
|
|
2129
|
+
@marshal
|
|
2130
|
+
async def get_offer(self, request: GetOffer) -> GetOfferResponse:
|
|
2391
2131
|
trade_mgr = self.service.wallet_state_manager.trade_manager
|
|
2392
2132
|
|
|
2393
|
-
|
|
2394
|
-
file_contents: bool = request.get("file_contents", False)
|
|
2395
|
-
trade_record: Optional[TradeRecord] = await trade_mgr.get_trade_by_id(bytes32(trade_id))
|
|
2133
|
+
trade_record: TradeRecord | None = await trade_mgr.get_trade_by_id(request.trade_id)
|
|
2396
2134
|
if trade_record is None:
|
|
2397
|
-
raise ValueError(f"No trade with trade id: {trade_id.hex()}")
|
|
2135
|
+
raise ValueError(f"No trade with trade id: {request.trade_id.hex()}")
|
|
2398
2136
|
|
|
2399
2137
|
offer_to_return: bytes = trade_record.offer if trade_record.taken_offer is None else trade_record.taken_offer
|
|
2400
|
-
|
|
2401
|
-
return
|
|
2138
|
+
offer: str | None = Offer.from_bytes(offer_to_return).to_bech32() if request.file_contents else None
|
|
2139
|
+
return GetOfferResponse(
|
|
2140
|
+
offer,
|
|
2141
|
+
trade_record,
|
|
2142
|
+
)
|
|
2402
2143
|
|
|
2403
|
-
|
|
2144
|
+
@marshal
|
|
2145
|
+
async def get_all_offers(self, request: GetAllOffers) -> GetAllOffersResponse:
|
|
2404
2146
|
trade_mgr = self.service.wallet_state_manager.trade_manager
|
|
2405
2147
|
|
|
2406
|
-
start: int = request.get("start", 0)
|
|
2407
|
-
end: int = request.get("end", 10)
|
|
2408
|
-
exclude_my_offers: bool = request.get("exclude_my_offers", False)
|
|
2409
|
-
exclude_taken_offers: bool = request.get("exclude_taken_offers", False)
|
|
2410
|
-
include_completed: bool = request.get("include_completed", False)
|
|
2411
|
-
sort_key: Optional[str] = request.get("sort_key", None)
|
|
2412
|
-
reverse: bool = request.get("reverse", False)
|
|
2413
|
-
file_contents: bool = request.get("file_contents", False)
|
|
2414
|
-
|
|
2415
2148
|
all_trades = await trade_mgr.trade_store.get_trades_between(
|
|
2416
|
-
start,
|
|
2417
|
-
end,
|
|
2418
|
-
sort_key=sort_key,
|
|
2419
|
-
reverse=reverse,
|
|
2420
|
-
exclude_my_offers=exclude_my_offers,
|
|
2421
|
-
exclude_taken_offers=exclude_taken_offers,
|
|
2422
|
-
include_completed=include_completed,
|
|
2149
|
+
request.start,
|
|
2150
|
+
request.end,
|
|
2151
|
+
sort_key=request.sort_key,
|
|
2152
|
+
reverse=request.reverse,
|
|
2153
|
+
exclude_my_offers=request.exclude_my_offers,
|
|
2154
|
+
exclude_taken_offers=request.exclude_taken_offers,
|
|
2155
|
+
include_completed=request.include_completed,
|
|
2423
2156
|
)
|
|
2424
2157
|
result = []
|
|
2425
|
-
offer_values:
|
|
2158
|
+
offer_values: list[str] | None = [] if request.file_contents else None
|
|
2426
2159
|
for trade in all_trades:
|
|
2427
|
-
result.append(trade
|
|
2428
|
-
if file_contents
|
|
2160
|
+
result.append(trade)
|
|
2161
|
+
if request.file_contents:
|
|
2429
2162
|
offer_to_return: bytes = trade.offer if trade.taken_offer is None else trade.taken_offer
|
|
2430
|
-
|
|
2163
|
+
# semantics guarantee this to be not None
|
|
2164
|
+
offer_values.append(Offer.from_bytes(offer_to_return).to_bech32()) # type: ignore[union-attr]
|
|
2431
2165
|
|
|
2432
|
-
return
|
|
2166
|
+
return GetAllOffersResponse(
|
|
2167
|
+
trade_records=result,
|
|
2168
|
+
offers=offer_values,
|
|
2169
|
+
)
|
|
2433
2170
|
|
|
2434
2171
|
@marshal
|
|
2435
2172
|
async def get_offers_count(self, request: Empty) -> GetOffersCountResponse:
|
|
@@ -2442,88 +2179,67 @@ class WalletRpcApi:
|
|
|
2442
2179
|
)
|
|
2443
2180
|
|
|
2444
2181
|
@tx_endpoint(push=True)
|
|
2182
|
+
@marshal
|
|
2445
2183
|
async def cancel_offer(
|
|
2446
2184
|
self,
|
|
2447
|
-
request:
|
|
2185
|
+
request: CancelOffer,
|
|
2448
2186
|
action_scope: WalletActionScope,
|
|
2449
2187
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2450
|
-
) ->
|
|
2188
|
+
) -> CancelOfferResponse:
|
|
2451
2189
|
wsm = self.service.wallet_state_manager
|
|
2452
|
-
secure = request["secure"]
|
|
2453
|
-
trade_id = bytes32.from_hexstr(request["trade_id"])
|
|
2454
|
-
fee: uint64 = uint64(request.get("fee", 0))
|
|
2455
2190
|
async with self.service.wallet_state_manager.lock:
|
|
2456
2191
|
await wsm.trade_manager.cancel_pending_offers(
|
|
2457
|
-
[trade_id],
|
|
2192
|
+
[request.trade_id],
|
|
2193
|
+
action_scope,
|
|
2194
|
+
fee=request.fee,
|
|
2195
|
+
secure=request.secure,
|
|
2196
|
+
extra_conditions=extra_conditions,
|
|
2458
2197
|
)
|
|
2459
2198
|
|
|
2460
|
-
return
|
|
2199
|
+
return CancelOfferResponse([], []) # tx_endpoint will fill in default values here
|
|
2461
2200
|
|
|
2462
2201
|
@tx_endpoint(push=True, merge_spends=False)
|
|
2202
|
+
@marshal
|
|
2463
2203
|
async def cancel_offers(
|
|
2464
2204
|
self,
|
|
2465
|
-
request:
|
|
2205
|
+
request: CancelOffers,
|
|
2466
2206
|
action_scope: WalletActionScope,
|
|
2467
2207
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2468
|
-
) ->
|
|
2469
|
-
secure = request["secure"]
|
|
2470
|
-
batch_fee: uint64 = uint64(request.get("batch_fee", 0))
|
|
2471
|
-
batch_size = request.get("batch_size", 5)
|
|
2472
|
-
cancel_all = request.get("cancel_all", False)
|
|
2473
|
-
if cancel_all:
|
|
2474
|
-
asset_id = None
|
|
2475
|
-
else:
|
|
2476
|
-
asset_id = request.get("asset_id", "xch")
|
|
2477
|
-
|
|
2478
|
-
start: int = 0
|
|
2479
|
-
end: int = start + batch_size
|
|
2208
|
+
) -> CancelOffersResponse:
|
|
2480
2209
|
trade_mgr = self.service.wallet_state_manager.trade_manager
|
|
2481
|
-
log.info(f"Start cancelling offers for {'
|
|
2210
|
+
log.info(f"Start cancelling offers for {'all' if request.cancel_all else 'asset_id: ' + request.asset_id} ...")
|
|
2482
2211
|
# Traverse offers page by page
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
if cancel_all:
|
|
2498
|
-
records[trade.trade_id] = trade
|
|
2499
|
-
continue
|
|
2500
|
-
if trade.offer and trade.offer != b"":
|
|
2501
|
-
offer = Offer.from_bytes(trade.offer)
|
|
2502
|
-
if key in offer.arbitrage():
|
|
2503
|
-
records[trade.trade_id] = trade
|
|
2504
|
-
continue
|
|
2212
|
+
for start in count(0, request.batch_size):
|
|
2213
|
+
records = {
|
|
2214
|
+
record.trade_id: record
|
|
2215
|
+
for record in await trade_mgr.trade_store.get_trades_between(
|
|
2216
|
+
start,
|
|
2217
|
+
start + request.batch_size,
|
|
2218
|
+
reverse=True,
|
|
2219
|
+
exclude_my_offers=False,
|
|
2220
|
+
exclude_taken_offers=True,
|
|
2221
|
+
include_completed=False,
|
|
2222
|
+
)
|
|
2223
|
+
if request.cancel_all
|
|
2224
|
+
or (record.offer != b"" and request.query_key in Offer.from_bytes(record.offer).arbitrage())
|
|
2225
|
+
}
|
|
2505
2226
|
|
|
2506
|
-
if
|
|
2227
|
+
if records == {}:
|
|
2507
2228
|
break
|
|
2508
2229
|
|
|
2509
2230
|
async with self.service.wallet_state_manager.lock:
|
|
2510
2231
|
await trade_mgr.cancel_pending_offers(
|
|
2511
2232
|
list(records.keys()),
|
|
2512
2233
|
action_scope,
|
|
2513
|
-
batch_fee,
|
|
2514
|
-
secure,
|
|
2234
|
+
request.batch_fee,
|
|
2235
|
+
request.secure,
|
|
2515
2236
|
records,
|
|
2516
2237
|
extra_conditions=extra_conditions,
|
|
2517
2238
|
)
|
|
2518
2239
|
|
|
2519
|
-
log.info(f"
|
|
2520
|
-
# If fewer records were returned than requested, we're done
|
|
2521
|
-
if len(trades) < batch_size:
|
|
2522
|
-
break
|
|
2523
|
-
start = end
|
|
2524
|
-
end += batch_size
|
|
2240
|
+
log.info(f"Created offer cancellations for {start} to {start + request.batch_size} ...")
|
|
2525
2241
|
|
|
2526
|
-
return
|
|
2242
|
+
return CancelOffersResponse([], []) # tx_endpoint wrapper will take care of this
|
|
2527
2243
|
|
|
2528
2244
|
##########################################################################################
|
|
2529
2245
|
# Distributed Identities
|
|
@@ -2621,11 +2337,11 @@ class WalletRpcApi:
|
|
|
2621
2337
|
if curried_args is None:
|
|
2622
2338
|
raise ValueError("The coin is not a DID.")
|
|
2623
2339
|
p2_puzzle, recovery_list_hash, num_verification, singleton_struct, metadata = curried_args
|
|
2624
|
-
num_verification_int:
|
|
2340
|
+
num_verification_int: uint16 | None = uint16(num_verification.as_int())
|
|
2625
2341
|
assert num_verification_int is not None
|
|
2626
2342
|
did_data: DIDCoinData = DIDCoinData(
|
|
2627
2343
|
p2_puzzle,
|
|
2628
|
-
bytes32(recovery_list_hash.as_atom()) if recovery_list_hash != Program.
|
|
2344
|
+
bytes32(recovery_list_hash.as_atom()) if recovery_list_hash != Program.NIL else None,
|
|
2629
2345
|
num_verification_int,
|
|
2630
2346
|
singleton_struct,
|
|
2631
2347
|
metadata,
|
|
@@ -2634,7 +2350,7 @@ class WalletRpcApi:
|
|
|
2634
2350
|
)
|
|
2635
2351
|
hinted_coins, _ = compute_spend_hints_and_additions(coin_spend)
|
|
2636
2352
|
# Hint is required, if it doesn't have any hint then it should be invalid
|
|
2637
|
-
hint:
|
|
2353
|
+
hint: bytes32 | None = None
|
|
2638
2354
|
for hinted_coin in hinted_coins.values():
|
|
2639
2355
|
if hinted_coin.coin.amount % 2 == 1 and hinted_coin.hint is not None:
|
|
2640
2356
|
hint = hinted_coin.hint
|
|
@@ -2667,7 +2383,7 @@ class WalletRpcApi:
|
|
|
2667
2383
|
our_inner_puzzle, NIL_TREEHASH, uint64(0), singleton_struct, metadata
|
|
2668
2384
|
)
|
|
2669
2385
|
# Check if we have the DID wallet
|
|
2670
|
-
did_wallet:
|
|
2386
|
+
did_wallet: DIDWallet | None = None
|
|
2671
2387
|
for wallet in self.service.wallet_state_manager.wallets.values():
|
|
2672
2388
|
if isinstance(wallet, DIDWallet):
|
|
2673
2389
|
assert wallet.did_info.origin_coin is not None
|
|
@@ -2881,8 +2597,6 @@ class WalletRpcApi:
|
|
|
2881
2597
|
action_scope: WalletActionScope,
|
|
2882
2598
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
2883
2599
|
) -> DIDTransferDIDResponse:
|
|
2884
|
-
if await self.service.wallet_state_manager.synced() is False:
|
|
2885
|
-
raise ValueError("Wallet needs to be fully synced.")
|
|
2886
2600
|
did_wallet = self.service.wallet_state_manager.get_wallet(id=request.wallet_id, required_type=DIDWallet)
|
|
2887
2601
|
puzzle_hash: bytes32 = decode_puzzle_hash(request.inner_address)
|
|
2888
2602
|
async with self.service.wallet_state_manager.lock:
|
|
@@ -2935,7 +2649,7 @@ class WalletRpcApi:
|
|
|
2935
2649
|
metadata = Program.to(metadata_list)
|
|
2936
2650
|
if request.did_id is not None:
|
|
2937
2651
|
if request.did_id == "":
|
|
2938
|
-
did_id:
|
|
2652
|
+
did_id: bytes | None = b""
|
|
2939
2653
|
else:
|
|
2940
2654
|
did_id = decode_puzzle_hash(request.did_id)
|
|
2941
2655
|
else:
|
|
@@ -2964,12 +2678,9 @@ class WalletRpcApi:
|
|
|
2964
2678
|
async def nft_count_nfts(self, request: NFTCountNFTs) -> NFTCountNFTsResponse:
|
|
2965
2679
|
count = 0
|
|
2966
2680
|
if request.wallet_id is not None:
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
# wallet not found
|
|
2971
|
-
raise ValueError(f"Wallet {request.wallet_id} not found.")
|
|
2972
|
-
count = await nft_wallet.get_nft_count()
|
|
2681
|
+
count = await self.service.wallet_state_manager.get_wallet(
|
|
2682
|
+
id=request.wallet_id, required_type=NFTWallet
|
|
2683
|
+
).get_nft_count()
|
|
2973
2684
|
else:
|
|
2974
2685
|
count = await self.service.wallet_state_manager.nft_store.count()
|
|
2975
2686
|
return NFTCountNFTsResponse(request.wallet_id, uint64(count))
|
|
@@ -3162,7 +2873,7 @@ class WalletRpcApi:
|
|
|
3162
2873
|
|
|
3163
2874
|
@marshal
|
|
3164
2875
|
async def nft_get_by_did(self, request: NFTGetByDID) -> NFTGetByDIDResponse:
|
|
3165
|
-
did_id:
|
|
2876
|
+
did_id: bytes32 | None = None
|
|
3166
2877
|
if request.did_id is not None:
|
|
3167
2878
|
did_id = decode_puzzle_hash(request.did_id)
|
|
3168
2879
|
for wallet in self.service.wallet_state_manager.wallets.values():
|
|
@@ -3173,7 +2884,7 @@ class WalletRpcApi:
|
|
|
3173
2884
|
@marshal
|
|
3174
2885
|
async def nft_get_wallet_did(self, request: NFTGetWalletDID) -> NFTGetWalletDIDResponse:
|
|
3175
2886
|
nft_wallet = self.service.wallet_state_manager.get_wallet(id=request.wallet_id, required_type=NFTWallet)
|
|
3176
|
-
did_bytes:
|
|
2887
|
+
did_bytes: bytes32 | None = nft_wallet.get_did()
|
|
3177
2888
|
did_id = ""
|
|
3178
2889
|
if did_bytes is not None:
|
|
3179
2890
|
did_id = encode_puzzle_hash(did_bytes, AddressType.DID.hrp(self.service.config))
|
|
@@ -3193,7 +2904,7 @@ class WalletRpcApi:
|
|
|
3193
2904
|
did_nft_wallets: list[NFTWalletWithDID] = []
|
|
3194
2905
|
for wallet in all_wallets:
|
|
3195
2906
|
if isinstance(wallet, NFTWallet):
|
|
3196
|
-
nft_wallet_did:
|
|
2907
|
+
nft_wallet_did: bytes32 | None = wallet.get_did()
|
|
3197
2908
|
if nft_wallet_did is not None:
|
|
3198
2909
|
did_wallet_id: uint32 = did_wallets_by_did_id.get(nft_wallet_did, uint32(0))
|
|
3199
2910
|
if did_wallet_id == 0:
|
|
@@ -3262,7 +2973,7 @@ class WalletRpcApi:
|
|
|
3262
2973
|
# Check if the metadata is updated
|
|
3263
2974
|
full_puzzle: Program = Program.from_bytes(bytes(coin_spend.puzzle_reveal))
|
|
3264
2975
|
|
|
3265
|
-
uncurried_nft:
|
|
2976
|
+
uncurried_nft: UncurriedNFT | None = UncurriedNFT.uncurry(*full_puzzle.uncurry())
|
|
3266
2977
|
if uncurried_nft is None:
|
|
3267
2978
|
raise ValueError("The coin is not a NFT.")
|
|
3268
2979
|
metadata, p2_puzzle_hash = get_metadata_and_phs(uncurried_nft, coin_spend.solution)
|
|
@@ -3352,8 +3063,6 @@ class WalletRpcApi:
|
|
|
3352
3063
|
) -> NFTMintBulkResponse:
|
|
3353
3064
|
if action_scope.config.push:
|
|
3354
3065
|
raise ValueError("Automatic pushing of nft minting transactions not yet available") # pragma: no cover
|
|
3355
|
-
if await self.service.wallet_state_manager.synced() is False:
|
|
3356
|
-
raise ValueError("Wallet needs to be fully synced.")
|
|
3357
3066
|
nft_wallet = self.service.wallet_state_manager.get_wallet(id=request.wallet_id, required_type=NFTWallet)
|
|
3358
3067
|
if request.royalty_address in {None, ""}:
|
|
3359
3068
|
royalty_puzhash = await action_scope.get_puzzle_hash(self.service.wallet_state_manager)
|
|
@@ -3383,7 +3092,7 @@ class WalletRpcApi:
|
|
|
3383
3092
|
metadata_list.append(metadata_dict)
|
|
3384
3093
|
target_list = [decode_puzzle_hash(target) for target in request.target_list]
|
|
3385
3094
|
if request.xch_change_target is not None:
|
|
3386
|
-
if request.xch_change_target.startswith(
|
|
3095
|
+
if request.xch_change_target.startswith(AddressType.XCH.hrp(self.service.config)):
|
|
3387
3096
|
xch_change_ph = decode_puzzle_hash(request.xch_change_target)
|
|
3388
3097
|
else:
|
|
3389
3098
|
xch_change_ph = bytes32.from_hexstr(request.xch_change_target)
|
|
@@ -3478,7 +3187,8 @@ class WalletRpcApi:
|
|
|
3478
3187
|
"total_count": result.total_count,
|
|
3479
3188
|
}
|
|
3480
3189
|
|
|
3481
|
-
|
|
3190
|
+
@marshal
|
|
3191
|
+
async def get_farmed_amount(self, request: GetFarmedAmount) -> GetFarmedAmountResponse:
|
|
3482
3192
|
tx_records: list[TransactionRecord] = await self.service.wallet_state_manager.tx_store.get_farming_rewards()
|
|
3483
3193
|
amount = 0
|
|
3484
3194
|
pool_reward_amount = 0
|
|
@@ -3487,14 +3197,12 @@ class WalletRpcApi:
|
|
|
3487
3197
|
blocks_won = 0
|
|
3488
3198
|
last_height_farmed = uint32(0)
|
|
3489
3199
|
|
|
3490
|
-
include_pool_rewards = request.get("include_pool_rewards", False)
|
|
3491
|
-
|
|
3492
3200
|
for record in tx_records:
|
|
3493
3201
|
if record.wallet_id not in self.service.wallet_state_manager.wallets:
|
|
3494
3202
|
continue
|
|
3495
3203
|
if record.type == TransactionType.COINBASE_REWARD.value:
|
|
3496
3204
|
if (
|
|
3497
|
-
not include_pool_rewards
|
|
3205
|
+
not request.include_pool_rewards
|
|
3498
3206
|
and self.service.wallet_state_manager.wallets[record.wallet_id].type() == WalletType.POOLING_WALLET
|
|
3499
3207
|
):
|
|
3500
3208
|
# Don't add pool rewards for pool wallets unless explicitly requested
|
|
@@ -3514,103 +3222,74 @@ class WalletRpcApi:
|
|
|
3514
3222
|
last_height_farmed = max(last_height_farmed, height)
|
|
3515
3223
|
amount += record.amount
|
|
3516
3224
|
|
|
3517
|
-
last_time_farmed =
|
|
3225
|
+
last_time_farmed = (
|
|
3518
3226
|
await self.service.get_timestamp_for_height(last_height_farmed) if last_height_farmed > 0 else 0
|
|
3519
3227
|
)
|
|
3520
3228
|
assert amount == pool_reward_amount + farmer_reward_amount + fee_amount
|
|
3521
|
-
return
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3229
|
+
return GetFarmedAmountResponse(
|
|
3230
|
+
farmed_amount=uint64(amount),
|
|
3231
|
+
pool_reward_amount=uint64(pool_reward_amount),
|
|
3232
|
+
farmer_reward_amount=uint64(farmer_reward_amount),
|
|
3233
|
+
fee_amount=uint64(fee_amount),
|
|
3234
|
+
last_height_farmed=uint32(last_height_farmed),
|
|
3235
|
+
last_time_farmed=uint64(last_time_farmed),
|
|
3236
|
+
blocks_won=uint32(blocks_won),
|
|
3237
|
+
)
|
|
3530
3238
|
|
|
3531
3239
|
@tx_endpoint(push=False)
|
|
3240
|
+
@marshal
|
|
3532
3241
|
async def create_signed_transaction(
|
|
3533
3242
|
self,
|
|
3534
|
-
request:
|
|
3243
|
+
request: CreateSignedTransaction,
|
|
3535
3244
|
action_scope: WalletActionScope,
|
|
3536
3245
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3537
3246
|
hold_lock: bool = True,
|
|
3538
|
-
) ->
|
|
3539
|
-
if
|
|
3540
|
-
|
|
3541
|
-
wallet = self.service.wallet_state_manager.wallets[wallet_id]
|
|
3247
|
+
) -> CreateSignedTransactionsResponse:
|
|
3248
|
+
if request.wallet_id is not None:
|
|
3249
|
+
wallet = self.service.wallet_state_manager.wallets[request.wallet_id]
|
|
3542
3250
|
else:
|
|
3543
3251
|
wallet = self.service.wallet_state_manager.main_wallet
|
|
3544
3252
|
|
|
3545
|
-
assert isinstance(wallet, (Wallet, CATWallet, CRCATWallet)), (
|
|
3253
|
+
assert isinstance(wallet, (Wallet, CATWallet, CRCATWallet, RCATWallet)), (
|
|
3546
3254
|
"create_signed_transaction only works for standard and CAT wallets"
|
|
3547
3255
|
)
|
|
3548
3256
|
|
|
3549
|
-
if
|
|
3257
|
+
if len(request.additions) < 1:
|
|
3550
3258
|
raise ValueError("Specify additions list")
|
|
3551
3259
|
|
|
3552
|
-
|
|
3553
|
-
amount_0: uint64 = uint64(additions[0]["amount"])
|
|
3260
|
+
amount_0: uint64 = uint64(request.additions[0].amount)
|
|
3554
3261
|
assert amount_0 <= self.service.constants.MAX_COIN_AMOUNT
|
|
3555
|
-
puzzle_hash_0 =
|
|
3262
|
+
puzzle_hash_0 = request.additions[0].puzzle_hash
|
|
3556
3263
|
if len(puzzle_hash_0) != 32:
|
|
3557
3264
|
raise ValueError(f"Address must be 32 bytes. {puzzle_hash_0.hex()}")
|
|
3558
3265
|
|
|
3559
|
-
memos_0 =
|
|
3266
|
+
memos_0 = (
|
|
3267
|
+
[] if request.additions[0].memos is None else [mem.encode("utf-8") for mem in request.additions[0].memos]
|
|
3268
|
+
)
|
|
3560
3269
|
|
|
3561
3270
|
additional_outputs: list[CreateCoin] = []
|
|
3562
|
-
for addition in additions[1:]:
|
|
3563
|
-
|
|
3564
|
-
if len(receiver_ph) != 32:
|
|
3565
|
-
raise ValueError(f"Address must be 32 bytes. {receiver_ph.hex()}")
|
|
3566
|
-
amount = uint64(addition["amount"])
|
|
3567
|
-
if amount > self.service.constants.MAX_COIN_AMOUNT:
|
|
3271
|
+
for addition in request.additions[1:]:
|
|
3272
|
+
if addition.amount > self.service.constants.MAX_COIN_AMOUNT:
|
|
3568
3273
|
raise ValueError(f"Coin amount cannot exceed {self.service.constants.MAX_COIN_AMOUNT}")
|
|
3569
|
-
memos = [] if
|
|
3570
|
-
additional_outputs.append(CreateCoin(
|
|
3571
|
-
|
|
3572
|
-
fee: uint64 = uint64(request.get("fee", 0))
|
|
3274
|
+
memos = [] if addition.memos is None else [mem.encode("utf-8") for mem in addition.memos]
|
|
3275
|
+
additional_outputs.append(CreateCoin(addition.puzzle_hash, addition.amount, memos))
|
|
3573
3276
|
|
|
3574
|
-
|
|
3575
|
-
if "coins" in request and len(request["coins"]) > 0:
|
|
3576
|
-
coins = {Coin.from_json_dict(coin_json) for coin_json in request["coins"]}
|
|
3577
|
-
|
|
3578
|
-
async def _generate_signed_transaction() -> EndpointResult:
|
|
3277
|
+
async def _generate_signed_transaction() -> CreateSignedTransactionsResponse:
|
|
3579
3278
|
await wallet.generate_signed_transaction(
|
|
3580
3279
|
[amount_0] + [output.amount for output in additional_outputs],
|
|
3581
3280
|
[bytes32(puzzle_hash_0)] + [output.puzzle_hash for output in additional_outputs],
|
|
3582
3281
|
action_scope,
|
|
3583
|
-
fee,
|
|
3584
|
-
coins=
|
|
3282
|
+
request.fee,
|
|
3283
|
+
coins=request.coin_set,
|
|
3585
3284
|
memos=[memos_0] + [output.memos if output.memos is not None else [] for output in additional_outputs],
|
|
3586
3285
|
extra_conditions=(
|
|
3587
3286
|
*extra_conditions,
|
|
3588
|
-
*
|
|
3589
|
-
|
|
3590
|
-
asserted_id=bytes32.from_hexstr(ca["coin_id"]),
|
|
3591
|
-
asserted_msg=(
|
|
3592
|
-
hexstr_to_bytes(ca["message"])
|
|
3593
|
-
if request.get("morph_bytes") is None
|
|
3594
|
-
else std_hash(hexstr_to_bytes(ca["morph_bytes"]) + hexstr_to_bytes(ca["message"]))
|
|
3595
|
-
),
|
|
3596
|
-
)
|
|
3597
|
-
for ca in request.get("coin_announcements", [])
|
|
3598
|
-
),
|
|
3599
|
-
*(
|
|
3600
|
-
AssertPuzzleAnnouncement(
|
|
3601
|
-
asserted_ph=bytes32.from_hexstr(pa["puzzle_hash"]),
|
|
3602
|
-
asserted_msg=(
|
|
3603
|
-
hexstr_to_bytes(pa["message"])
|
|
3604
|
-
if request.get("morph_bytes") is None
|
|
3605
|
-
else std_hash(hexstr_to_bytes(pa["morph_bytes"]) + hexstr_to_bytes(pa["message"]))
|
|
3606
|
-
),
|
|
3607
|
-
)
|
|
3608
|
-
for pa in request.get("puzzle_announcements", [])
|
|
3609
|
-
),
|
|
3287
|
+
*request.asserted_coin_announcements,
|
|
3288
|
+
*request.asserted_puzzle_announcements,
|
|
3610
3289
|
),
|
|
3611
3290
|
)
|
|
3612
|
-
# tx_endpoint wrapper will take care of
|
|
3613
|
-
return
|
|
3291
|
+
# tx_endpoint wrapper will take care of these default values
|
|
3292
|
+
return CreateSignedTransactionsResponse([], [], [], REPLACEABLE_TRANSACTION_RECORD)
|
|
3614
3293
|
|
|
3615
3294
|
if hold_lock:
|
|
3616
3295
|
async with self.service.wallet_state_manager.lock:
|
|
@@ -3631,9 +3310,6 @@ class WalletRpcApi:
|
|
|
3631
3310
|
) -> PWJoinPoolResponse:
|
|
3632
3311
|
wallet = self.service.wallet_state_manager.get_wallet(id=request.wallet_id, required_type=PoolWallet)
|
|
3633
3312
|
|
|
3634
|
-
if await self.service.wallet_state_manager.synced() is False:
|
|
3635
|
-
raise ValueError("Wallet needs to be fully synced.")
|
|
3636
|
-
|
|
3637
3313
|
pool_wallet_info: PoolWalletInfo = await wallet.get_current_state()
|
|
3638
3314
|
if (
|
|
3639
3315
|
pool_wallet_info.current.state == FARMING_TO_POOL.value
|
|
@@ -3673,9 +3349,6 @@ class WalletRpcApi:
|
|
|
3673
3349
|
# Then we transition to FARMING_TO_POOL or SELF_POOLING
|
|
3674
3350
|
wallet = self.service.wallet_state_manager.get_wallet(id=request.wallet_id, required_type=PoolWallet)
|
|
3675
3351
|
|
|
3676
|
-
if await self.service.wallet_state_manager.synced() is False:
|
|
3677
|
-
raise ValueError("Wallet needs to be fully synced.")
|
|
3678
|
-
|
|
3679
3352
|
total_fee = await wallet.self_pool(request.fee, action_scope)
|
|
3680
3353
|
# tx_endpoint will take care of filling in these default values
|
|
3681
3354
|
return PWSelfPoolResponse(
|
|
@@ -3695,8 +3368,6 @@ class WalletRpcApi:
|
|
|
3695
3368
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
3696
3369
|
) -> PWAbsorbRewardsResponse:
|
|
3697
3370
|
"""Perform a sweep of the p2_singleton rewards controlled by the pool wallet singleton"""
|
|
3698
|
-
if await self.service.wallet_state_manager.synced() is False:
|
|
3699
|
-
raise ValueError("Wallet needs to be fully synced before collecting rewards")
|
|
3700
3371
|
wallet = self.service.wallet_state_manager.get_wallet(id=request.wallet_id, required_type=PoolWallet)
|
|
3701
3372
|
|
|
3702
3373
|
assert isinstance(wallet, PoolWallet)
|
|
@@ -4003,7 +3674,7 @@ class WalletRpcApi:
|
|
|
4003
3674
|
'transactions'
|
|
4004
3675
|
"""
|
|
4005
3676
|
did_id = decode_puzzle_hash(request.did_id)
|
|
4006
|
-
puzhash:
|
|
3677
|
+
puzhash: bytes32 | None = None
|
|
4007
3678
|
if request.target_address is not None:
|
|
4008
3679
|
puzhash = decode_puzzle_hash(request.target_address)
|
|
4009
3680
|
|
|
@@ -4105,7 +3776,7 @@ class WalletRpcApi:
|
|
|
4105
3776
|
|
|
4106
3777
|
vc_wallet: VCWallet = await self.service.wallet_state_manager.get_or_create_vc_wallet()
|
|
4107
3778
|
|
|
4108
|
-
vc_proofs:
|
|
3779
|
+
vc_proofs: VCProofs | None = await vc_wallet.store.get_proofs_for_root(request.root)
|
|
4109
3780
|
if vc_proofs is None:
|
|
4110
3781
|
raise ValueError("no proofs found for specified root") # pragma: no cover
|
|
4111
3782
|
return VCGetProofsForRootResponse.from_vc_proofs(vc_proofs)
|
|
@@ -4137,12 +3808,13 @@ class WalletRpcApi:
|
|
|
4137
3808
|
return VCRevokeResponse([], []) # tx_endpoint takes care of filling this out
|
|
4138
3809
|
|
|
4139
3810
|
@tx_endpoint(push=True)
|
|
3811
|
+
@marshal
|
|
4140
3812
|
async def crcat_approve_pending(
|
|
4141
3813
|
self,
|
|
4142
|
-
request:
|
|
3814
|
+
request: CRCATApprovePending,
|
|
4143
3815
|
action_scope: WalletActionScope,
|
|
4144
3816
|
extra_conditions: tuple[Condition, ...] = tuple(),
|
|
4145
|
-
) ->
|
|
3817
|
+
) -> CRCATApprovePendingResponse:
|
|
4146
3818
|
"""
|
|
4147
3819
|
Moving any "pending approval" CR-CATs into the spendable balance of the wallet
|
|
4148
3820
|
:param request: Required 'wallet_id'. Optional 'min_amount_to_claim' (default: full balance).
|
|
@@ -4151,27 +3823,18 @@ class WalletRpcApi:
|
|
|
4151
3823
|
(CRCAT TX + fee TX)
|
|
4152
3824
|
"""
|
|
4153
3825
|
|
|
4154
|
-
|
|
4155
|
-
@dataclasses.dataclass(frozen=True)
|
|
4156
|
-
class CRCATApprovePending(Streamable):
|
|
4157
|
-
wallet_id: uint32
|
|
4158
|
-
min_amount_to_claim: uint64
|
|
4159
|
-
fee: uint64 = uint64(0)
|
|
4160
|
-
|
|
4161
|
-
parsed_request = CRCATApprovePending.from_json_dict(request)
|
|
4162
|
-
cr_cat_wallet = self.service.wallet_state_manager.wallets[parsed_request.wallet_id]
|
|
3826
|
+
cr_cat_wallet = self.service.wallet_state_manager.wallets[request.wallet_id]
|
|
4163
3827
|
assert isinstance(cr_cat_wallet, CRCATWallet)
|
|
4164
3828
|
|
|
4165
3829
|
await cr_cat_wallet.claim_pending_approval_balance(
|
|
4166
|
-
|
|
3830
|
+
request.min_amount_to_claim,
|
|
4167
3831
|
action_scope,
|
|
4168
|
-
fee=
|
|
3832
|
+
fee=request.fee,
|
|
4169
3833
|
extra_conditions=extra_conditions,
|
|
4170
3834
|
)
|
|
4171
3835
|
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
}
|
|
3836
|
+
# tx_endpoint will take care of default values here
|
|
3837
|
+
return CRCATApprovePendingResponse([], [])
|
|
4175
3838
|
|
|
4176
3839
|
@marshal
|
|
4177
3840
|
async def gather_signing_info(
|