Compare commits

...

5 Commits

Author SHA1 Message Date
Matt Hauff b71466f427
more test fixs 2023-06-30 13:43:14 -07:00
Matt Hauff 2d94ae765d
more test fixs 2023-06-30 10:58:09 -07:00
Matt Hauff f13eb468b3
test fixes 2023-06-30 09:58:28 -07:00
Matt Hauff b849d4bf09
pre-commit? 2023-06-29 12:10:33 -07:00
Matt Hauff dbcc201cf8
Explore TXConfig 2023-06-29 12:00:30 -07:00
46 changed files with 1891 additions and 1054 deletions

View File

@ -1,13 +1,17 @@
from __future__ import annotations
import dataclasses
import logging
import traceback
from contextlib import asynccontextmanager
from decimal import Decimal
from pathlib import Path
from typing import Any, AsyncIterator, Awaitable, Callable, Dict, List, Optional, Tuple, Type, TypeVar
import click
from aiohttp import ClientConnectorError
from chia.consensus.default_constants import DEFAULT_CONSTANTS
from chia.daemon.keychain_proxy import KeychainProxy, connect_to_keychain_and_validate
from chia.rpc.data_layer_rpc_client import DataLayerRpcClient
from chia.rpc.farmer_rpc_client import FarmerRpcClient
@ -20,9 +24,11 @@ from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.mempool_submission_status import MempoolSubmissionStatus
from chia.util.config import load_config
from chia.util.default_root import DEFAULT_ROOT_PATH
from chia.util.ints import uint16
from chia.util.ints import uint16, uint64
from chia.util.keychain import KeyData
from chia.util.streamable import Streamable, streamable
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.tx_config import CoinSelectionConfig, CoinSelectionConfigLoader, TXConfig, TXConfigLoader
NODE_TYPES: Dict[str, Type[RpcClient]] = {
"farmer": FarmerRpcClient,
@ -222,3 +228,93 @@ async def execute_with_wallet(
return
await function(extra_params, wallet_client, new_fp)
def coin_selection_args(func: Callable[..., None]) -> Callable[..., None]:
return click.option(
"-ma",
"--min-coin-amount",
"--min-amount",
help="Ignore coins worth less then this much XCH or CAT units",
type=str,
required=False,
default=None,
)(
click.option(
"-l",
"--max-coin-amount",
"--max-amount",
help="Ignore coins worth more then this much XCH or CAT units",
type=str,
required=False,
default=None,
)(
click.option(
"--exclude-coin",
"coins_to_exclude",
multiple=True,
help="Exclude this coin from being spent.",
)(
click.option(
"--exclude-amount",
"amounts_to_exclude",
multiple=True,
help="Exclude any coins with this XCH or CAT amount from being included.",
)(func)
)
)
)
def tx_config_args(func: Callable[..., None]) -> Callable[..., None]:
return click.option(
"--reuse/--new-address",
"--reuse-puzhash/--generate-new-puzhash",
help="Reuse existing address for the change.",
is_flag=True,
default=False,
)(coin_selection_args(func))
@streamable
@dataclasses.dataclass(frozen=True)
class CMDCoinSelectionConfigLoader(Streamable):
min_coin_amount: Optional[str] = None
max_coin_amount: Optional[str] = None
excluded_coin_amounts: Optional[List[str]] = None
excluded_coin_ids: Optional[List[bytes32]] = None
def to_coin_selection_config(self, mojo_per_unit: int) -> CoinSelectionConfig:
return CoinSelectionConfigLoader(
uint64(int(Decimal(self.min_coin_amount) * mojo_per_unit)) if self.min_coin_amount is not None else None,
uint64(int(Decimal(self.max_coin_amount) * mojo_per_unit)) if self.max_coin_amount is not None else None,
[uint64(int(Decimal(amount) * mojo_per_unit)) for amount in self.excluded_coin_amounts]
if self.excluded_coin_amounts is not None
else None,
self.excluded_coin_ids,
).autofill(DEFAULT_CONSTANTS)
@streamable
@dataclasses.dataclass(frozen=True)
class CMDTXConfigLoader(Streamable):
min_coin_amount: Optional[str] = None
max_coin_amount: Optional[str] = None
excluded_coin_amounts: Optional[List[str]] = None
excluded_coin_ids: Optional[List[bytes32]] = None
reuse_puzhash: Optional[bool] = None
def to_tx_config(self, mojo_per_unit: int, config: Dict[str, Any], fingerprint: int) -> TXConfig:
return TXConfigLoader.from_json_dict(
{
"reuse_puzhash": self.reuse_puzhash,
**CMDCoinSelectionConfigLoader(
self.min_coin_amount,
self.max_coin_amount,
self.excluded_coin_amounts,
self.excluded_coin_ids,
)
.to_coin_selection_config(mojo_per_unit)
.to_json_dict(),
}
).autofill(config, fingerprint, DEFAULT_CONSTANTS)

View File

@ -1,16 +1,21 @@
from __future__ import annotations
import dataclasses
import sys
from decimal import Decimal
from typing import Any, Dict, List, Tuple, Union
from chia.cmds.cmd_utils import CMDCoinSelectionConfigLoader, CMDTXConfigLoader
from chia.cmds.units import units
from chia.cmds.wallet_funcs import get_mojo_per_unit, get_wallet_type, print_balance
from chia.rpc.wallet_rpc_client import WalletRpcClient
from chia.server.start_wallet import SERVICE_NAME
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.coin_record import CoinRecord
from chia.util.bech32m import decode_puzzle_hash, encode_puzzle_hash
from chia.util.config import load_config
from chia.util.default_root import DEFAULT_ROOT_PATH
from chia.util.ints import uint64, uint128
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.wallet_types import WalletType
@ -18,10 +23,6 @@ from chia.wallet.util.wallet_types import WalletType
async def async_list(args: Dict[str, Any], wallet_client: WalletRpcClient, fingerprint: int) -> None:
wallet_id: int = args["id"]
min_coin_amount = Decimal(args["min_coin_amount"])
max_coin_amount = Decimal(args["max_coin_amount"])
excluded_coin_ids = args["excluded_coin_ids"]
excluded_amounts = args["excluded_amounts"]
addr_prefix = args["addr_prefix"]
show_unconfirmed = args["show_unconfirmed"]
paginate = args["paginate"]
@ -36,15 +37,9 @@ async def async_list(args: Dict[str, Any], wallet_client: WalletRpcClient, finge
if not await wallet_client.get_synced():
print("Wallet not synced. Please wait.")
return
final_min_coin_amount: uint64 = uint64(int(min_coin_amount * mojo_per_unit))
final_max_coin_amount: uint64 = uint64(int(max_coin_amount * mojo_per_unit))
final_excluded_amounts: List[uint64] = [uint64(int(Decimal(amount) * mojo_per_unit)) for amount in excluded_amounts]
conf_coins, unconfirmed_removals, unconfirmed_additions = await wallet_client.get_spendable_coins(
wallet_id=wallet_id,
max_coin_amount=final_max_coin_amount,
min_coin_amount=final_min_coin_amount,
excluded_amounts=final_excluded_amounts,
excluded_coin_ids=excluded_coin_ids,
coin_selection_config=CMDCoinSelectionConfigLoader.from_json_dict(args).to_coin_selection_config(mojo_per_unit),
)
print(f"There are a total of {len(conf_coins) + len(unconfirmed_additions)} coins in wallet {wallet_id}.")
print(f"{len(conf_coins)} confirmed coins.")
@ -107,10 +102,7 @@ def print_coins(
async def async_combine(args: Dict[str, Any], wallet_client: WalletRpcClient, fingerprint: int) -> None:
wallet_id: int = args["id"]
min_coin_amount = Decimal(args["min_coin_amount"])
excluded_amounts = args["excluded_amounts"]
number_of_coins = args["number_of_coins"]
max_amount = Decimal(args["max_amount"])
target_coin_amount = Decimal(args["target_coin_amount"])
target_coin_ids: List[bytes32] = [bytes32.from_hexstr(coin_id) for coin_id in args["target_coin_ids"]]
largest = bool(args["largest"])
@ -127,24 +119,25 @@ async def async_combine(args: Dict[str, Any], wallet_client: WalletRpcClient, fi
print("Wallet not synced. Please wait.")
return
is_xch: bool = wallet_type == WalletType.STANDARD_WALLET # this lets us know if we are directly combining Chia
final_max_amount = uint64(int(max_amount * mojo_per_unit)) if not target_coin_ids else uint64(0)
final_min_coin_amount: uint64 = uint64(int(min_coin_amount * mojo_per_unit))
final_excluded_amounts: List[uint64] = [uint64(int(Decimal(amount) * mojo_per_unit)) for amount in excluded_amounts]
final_target_coin_amount = uint64(int(target_coin_amount * mojo_per_unit))
config = load_config(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME)
loaded_tx_config = CMDTXConfigLoader.from_json_dict(args).to_tx_config(mojo_per_unit, config, fingerprint)
if final_target_coin_amount != 0: # if we have a set target, just use standard coin selection.
removals: List[Coin] = await wallet_client.select_coins(
amount=(final_target_coin_amount + final_fee) if is_xch else final_target_coin_amount,
wallet_id=wallet_id,
max_coin_amount=final_max_amount,
min_coin_amount=final_min_coin_amount,
excluded_amounts=final_excluded_amounts + [final_target_coin_amount], # dont reuse coins of same amount.
coin_selection_config=dataclasses.replace(
loaded_tx_config.coin_selection_config,
excluded_coin_amounts=[
*loaded_tx_config.coin_selection_config.excluded_coin_amounts,
final_target_coin_amount,
],
), # dont reuse coins of same amount.
)
else:
conf_coins, _, _ = await wallet_client.get_spendable_coins(
wallet_id=wallet_id,
max_coin_amount=final_max_amount,
min_coin_amount=final_min_coin_amount,
excluded_amounts=final_excluded_amounts,
coin_selection_config=loaded_tx_config.coin_selection_config,
)
if len(target_coin_ids) > 0:
conf_coins = [cr for cr in conf_coins if cr.name in target_coin_ids]
@ -171,7 +164,7 @@ async def async_combine(args: Dict[str, Any], wallet_client: WalletRpcClient, fi
target_ph: bytes32 = decode_puzzle_hash(await wallet_client.get_next_address(wallet_id, False))
additions = [{"amount": (total_amount - final_fee) if is_xch else total_amount, "puzzle_hash": target_ph}]
transaction: TransactionRecord = await wallet_client.send_transaction_multi(
wallet_id, additions, removals, final_fee
wallet_id, additions, loaded_tx_config, removals, final_fee
)
tx_id = transaction.name.hex()
print(f"Transaction sent: {tx_id}")
@ -216,8 +209,10 @@ async def async_split(args: Dict[str, Any], wallet_client: WalletRpcClient, fing
# we always use new addresses
target_ph: bytes32 = decode_puzzle_hash(await wallet_client.get_next_address(wallet_id, new_address=True))
additions.append({"amount": final_amount_per_coin, "puzzle_hash": target_ph})
config = load_config(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME)
loaded_tx_config = CMDTXConfigLoader.from_json_dict(args).to_tx_config(mojo_per_unit, config, fingerprint)
transaction: TransactionRecord = await wallet_client.send_transaction_multi(
wallet_id, additions, [removal_coin_record.coin], final_fee
wallet_id, additions, loaded_tx_config, [removal_coin_record.coin], final_fee
)
tx_id = transaction.name.hex()
print(f"Transaction sent: {tx_id}")

View File

@ -5,7 +5,7 @@ from typing import List, Optional
import click
from chia.cmds.cmds_util import execute_with_wallet
from chia.cmds.cmds_util import coin_selection_args, execute_with_wallet, tx_config_args
from chia.util.config import load_config, selected_network_address_prefix
@ -26,35 +26,12 @@ def coins_cmd(ctx: click.Context) -> None:
@click.option("-f", "--fingerprint", help="Set the fingerprint to specify which key to use", type=int)
@click.option("-i", "--id", help="Id of the wallet to use", type=int, default=1, show_default=True, required=True)
@click.option("-u", "--show-unconfirmed", help="Separately display unconfirmed coins.", is_flag=True)
@click.option(
"--min-amount",
help="Ignore coins worth less then this much XCH or CAT units",
type=str,
default="0",
)
@click.option(
"--max-amount",
help="Ignore coins worth more then this much XCH or CAT units",
type=str,
default="0",
)
@click.option(
"--exclude-coin",
"coins_to_exclude",
multiple=True,
help="prevent this coin from being included.",
)
@click.option(
"--exclude-amount",
"amounts_to_exclude",
multiple=True,
help="Exclude any coins with this XCH or CAT amount from being included.",
)
@click.option(
"--paginate/--no-paginate",
default=None,
help="Prompt for each page of data. Defaults to true for interactive consoles, otherwise false.",
)
@coin_selection_args
@click.pass_context
def list_cmd(
ctx: click.Context,
@ -62,8 +39,8 @@ def list_cmd(
fingerprint: int,
id: int,
show_unconfirmed: bool,
min_amount: str,
max_amount: str,
min_coin_amount: str,
max_coin_amount: str,
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
paginate: Optional[bool],
@ -72,8 +49,8 @@ def list_cmd(
address_prefix = selected_network_address_prefix(config)
extra_params = {
"id": id,
"max_coin_amount": max_amount,
"min_coin_amount": min_amount,
"max_coin_amount": max_coin_amount,
"min_coin_amount": min_coin_amount,
"excluded_amounts": amounts_to_exclude,
"excluded_coin_ids": coins_to_exclude,
"addr_prefix": address_prefix,
@ -103,18 +80,6 @@ def list_cmd(
type=str,
default="0",
)
@click.option(
"--min-amount",
help="Ignore coins worth less then this much XCH or CAT units",
type=str,
default="0",
)
@click.option(
"--exclude-amount",
"amounts_to_exclude",
multiple=True,
help="Exclude any coins with this XCH or CAT amount from being included.",
)
@click.option(
"-n",
"--number-of-coins",
@ -123,12 +88,6 @@ def list_cmd(
show_default=True,
help="The number of coins we are combining.",
)
@click.option(
"--max-amount",
help="Ignore coins worth more then this much XCH or CAT units",
type=str,
default="0", # 0 means no limit
)
@click.option(
"-m",
"--fee",
@ -150,29 +109,34 @@ def list_cmd(
default=False,
help="Sort coins from largest to smallest or smallest to largest.",
)
@tx_config_args
def combine_cmd(
wallet_rpc_port: Optional[int],
fingerprint: int,
id: int,
target_amount: str,
min_amount: str,
amounts_to_exclude: List[int],
number_of_coins: int,
max_amount: str,
fee: str,
input_coins: List[str],
largest_first: bool,
reuse: bool,
min_coin_amount: str,
max_coin_amount: str,
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
extra_params = {
"id": id,
"target_coin_amount": target_amount,
"min_coin_amount": min_amount,
"excluded_amounts": amounts_to_exclude,
"number_of_coins": number_of_coins,
"max_amount": max_amount,
"fee": fee,
"target_coin_ids": list(input_coins),
"largest": largest_first,
"reuse_puzhash": True if reuse else None,
"max_coin_amount": max_coin_amount,
"min_coin_amount": min_coin_amount,
"excluded_amounts": amounts_to_exclude,
"excluded_coin_ids": coins_to_exclude,
}
from .coin_funcs import async_combine
@ -213,6 +177,7 @@ def combine_cmd(
required=True,
)
@click.option("-t", "--target-coin-id", type=str, required=True, help="The coin id of the coin we are splitting.")
@tx_config_args
def split_cmd(
wallet_rpc_port: Optional[int],
fingerprint: int,
@ -221,6 +186,11 @@ def split_cmd(
fee: str,
amount_per_coin: str,
target_coin_id: str,
reuse: bool,
min_coin_amount: str,
max_coin_amount: str,
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
extra_params = {
"id": id,
@ -228,6 +198,11 @@ def split_cmd(
"fee": fee,
"amount_per_coin": amount_per_coin,
"target_coin_id": target_coin_id,
"reuse_puzhash": True if reuse else None,
"max_coin_amount": max_coin_amount,
"min_coin_amount": min_coin_amount,
"excluded_amounts": amounts_to_exclude,
"excluded_coin_ids": coins_to_exclude,
}
from .coin_funcs import async_split

View File

@ -6,7 +6,7 @@ from typing import Any, Dict, List, Optional, Tuple
import click
from chia.cmds.check_wallet_db import help_text as check_help_text
from chia.cmds.cmds_util import execute_with_wallet
from chia.cmds.cmds_util import execute_with_wallet, tx_config_args
from chia.cmds.coins import coins_cmd
from chia.cmds.plotnft import validate_fee
from chia.wallet.transaction_sorting import SortKey
@ -165,34 +165,6 @@ def get_transactions_cmd(
@click.option(
"-o", "--override", help="Submits transaction without checking for unusual values", is_flag=True, default=False
)
@click.option(
"-ma",
"--min-coin-amount",
help="Ignore coins worth less then this much XCH or CAT units",
type=str,
required=False,
default="0",
)
@click.option(
"-l",
"--max-coin-amount",
help="Ignore coins worth more then this much XCH or CAT units",
type=str,
required=False,
default="0",
)
@click.option(
"--exclude-coin",
"coins_to_exclude",
multiple=True,
help="Exclude this coin from being spent.",
)
@click.option(
"--reuse",
help="Reuse existing address for the change.",
is_flag=True,
default=False,
)
@click.option(
"--clawback_time",
help="The seconds that the recipient needs to wait to claim the fund."
@ -200,6 +172,7 @@ def get_transactions_cmd(
type=int,
default=0,
)
@tx_config_args
def send_cmd(
wallet_rpc_port: Optional[int],
fingerprint: int,
@ -209,12 +182,13 @@ def send_cmd(
fee: str,
address: str,
override: bool,
min_coin_amount: str,
max_coin_amount: str,
coins_to_exclude: Tuple[str],
reuse: bool,
clawback_time: int,
) -> None: # pragma: no cover
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
extra_params = {
"id": id,
"amount": amount,
@ -222,11 +196,12 @@ def send_cmd(
"fee": fee,
"address": address,
"override": override,
"min_coin_amount": min_coin_amount,
"max_coin_amount": max_coin_amount,
"excluded_coin_ids": list(coins_to_exclude),
"reuse_puzhash": True if reuse else None,
"clawback_time": clawback_time,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
import asyncio
@ -467,12 +442,7 @@ def add_token_cmd(wallet_rpc_port: Optional[int], asset_id: str, token_name: str
@click.option(
"-m", "--fee", help="A fee to add to the offer when it gets taken, in XCH", default="0", show_default=True
)
@click.option(
"--reuse",
help="Reuse existing address for the offer.",
is_flag=True,
default=False,
)
@tx_config_args
def make_offer_cmd(
wallet_rpc_port: Optional[int],
fingerprint: int,
@ -481,6 +451,10 @@ def make_offer_cmd(
filepath: str,
fee: str,
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
extra_params = {
"offers": offer,
@ -488,6 +462,10 @@ def make_offer_cmd(
"filepath": filepath,
"fee": fee,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
import asyncio
@ -557,12 +535,7 @@ def get_offers_cmd(
@click.option(
"-m", "--fee", help="The fee to use when pushing the completed offer, in XCH", default="0", show_default=True
)
@click.option(
"--reuse",
help="Reuse existing address for the offer.",
is_flag=True,
default=False,
)
@tx_config_args
def take_offer_cmd(
path_or_hex: str,
wallet_rpc_port: Optional[int],
@ -570,12 +543,20 @@ def take_offer_cmd(
examine_only: bool,
fee: str,
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
extra_params = {
"file": path_or_hex,
"examine_only": examine_only,
"fee": fee,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
import asyncio
@ -755,20 +736,31 @@ def did_get_details_cmd(wallet_rpc_port: Optional[int], fingerprint: int, coin_i
@click.option("-f", "--fingerprint", help="Set the fingerprint to specify which key to use", type=int)
@click.option("-i", "--id", help="Id of the DID wallet to use", type=int, required=True)
@click.option("-d", "--metadata", help="The new whole metadata in json format", type=str, required=True)
@click.option(
"--reuse",
help="Reuse existing address for the change.",
is_flag=True,
default=False,
)
@tx_config_args
def did_update_metadata_cmd(
wallet_rpc_port: Optional[int], fingerprint: int, id: int, metadata: str, reuse: bool
wallet_rpc_port: Optional[int],
fingerprint: int,
id: int,
metadata: str,
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
import asyncio
from .wallet_funcs import update_did_metadata
extra_params = {"did_wallet_id": id, "metadata": metadata, "reuse_puzhash": reuse}
extra_params = {
"did_wallet_id": id,
"metadata": metadata,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, update_did_metadata))
@ -901,12 +893,7 @@ def did_message_spend_cmd(
show_default=True,
callback=validate_fee,
)
@click.option(
"--reuse",
help="Reuse existing address for the change.",
is_flag=True,
default=False,
)
@tx_config_args
def did_transfer_did(
wallet_rpc_port: Optional[int],
fingerprint: int,
@ -915,6 +902,10 @@ def did_transfer_did(
reset_recovery: bool,
fee: str,
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
import asyncio
@ -926,6 +917,10 @@ def did_transfer_did(
"target_address": target_address,
"fee": fee,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, transfer_did))
@ -1015,12 +1010,7 @@ def nft_sign_message(wallet_rpc_port: Optional[int], fingerprint: int, nft_id: s
default=0,
show_default=True,
)
@click.option(
"--reuse",
help="Reuse existing address for the change.",
is_flag=True,
default=False,
)
@tx_config_args
def nft_mint_cmd(
wallet_rpc_port: Optional[int],
fingerprint: int,
@ -1039,6 +1029,10 @@ def nft_mint_cmd(
fee: str,
royalty_percentage_fraction: int,
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
import asyncio
@ -1070,6 +1064,10 @@ def nft_mint_cmd(
"fee": fee,
"royalty_percentage": royalty_percentage_fraction,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, mint_nft))
@ -1097,12 +1095,7 @@ def nft_mint_cmd(
show_default=True,
callback=validate_fee,
)
@click.option(
"--reuse",
help="Reuse existing address for the change.",
is_flag=True,
default=False,
)
@tx_config_args
def nft_add_uri_cmd(
wallet_rpc_port: Optional[int],
fingerprint: int,
@ -1113,6 +1106,10 @@ def nft_add_uri_cmd(
license_uri: str,
fee: str,
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
import asyncio
@ -1126,6 +1123,10 @@ def nft_add_uri_cmd(
"license_uri": license_uri,
"fee": fee,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, add_uri_to_nft))
@ -1151,12 +1152,7 @@ def nft_add_uri_cmd(
show_default=True,
callback=validate_fee,
)
@click.option(
"--reuse",
help="Reuse existing address for the change.",
is_flag=True,
default=False,
)
@tx_config_args
def nft_transfer_cmd(
wallet_rpc_port: Optional[int],
fingerprint: int,
@ -1165,6 +1161,10 @@ def nft_transfer_cmd(
target_address: str,
fee: str,
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
import asyncio
@ -1176,6 +1176,10 @@ def nft_transfer_cmd(
"target_address": target_address,
"fee": fee,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, transfer_nft))
@ -1220,12 +1224,7 @@ def nft_list_cmd(wallet_rpc_port: Optional[int], fingerprint: int, id: int) -> N
show_default=True,
callback=validate_fee,
)
@click.option(
"--reuse",
help="Reuse existing address for the change.",
is_flag=True,
default=False,
)
@tx_config_args
def nft_set_did_cmd(
wallet_rpc_port: Optional[int],
fingerprint: int,
@ -1234,6 +1233,10 @@ def nft_set_did_cmd(
nft_coin_id: str,
fee: str,
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None:
import asyncio
@ -1245,6 +1248,10 @@ def nft_set_did_cmd(
"nft_coin_id": nft_coin_id,
"fee": fee,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, set_nft_did))
@ -1481,12 +1488,7 @@ def _get_vcs(
)
@click.option("-p", "--new-proof-hash", help="The new proof hash to update the VC to", type=str, required=True)
@click.option("-m", "--fee", help="Blockchain fee for update transaction, in XCH", type=str, required=False)
@click.option(
"--reuse-puzhash/--generate-new-puzhash",
help="Send the VC back to the same puzzle hash it came from (ignored if --new-puzhash is specified)",
default=False,
show_default=True,
)
@tx_config_args
def _spend_vc(
wallet_rpc_port: Optional[int],
fingerprint: int,
@ -1494,7 +1496,11 @@ def _spend_vc(
new_puzhash: Optional[str],
new_proof_hash: str,
fee: str,
reuse_puzhash: bool,
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None: # pragma: no cover
import asyncio
@ -1507,7 +1513,11 @@ def _spend_vc(
"new_puzhash": new_puzhash,
"new_proof_hash": new_proof_hash,
"fee": fee,
"reuse_puzhash": reuse_puzhash,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, spend_vc))
@ -1593,19 +1603,18 @@ def _get_proofs_for_root(
required=False,
)
@click.option("-m", "--fee", help="Blockchain fee for revocation transaction, in XCH", type=str, required=False)
@click.option(
"--reuse-puzhash/--generate-new-puzhash",
help="Send the VC back to the same puzzle hash it came from (ignored if --new-puzhash is specified)",
default=False,
show_default=True,
)
@tx_config_args
def _revoke_vc(
wallet_rpc_port: Optional[int],
fingerprint: int,
parent_coin_id: Optional[str],
vc_id: Optional[str],
fee: str,
reuse_puzhash: bool,
reuse: bool,
min_amount: Optional[str],
max_amount: Optional[str],
coins_to_exclude: List[str],
amounts_to_exclude: List[int],
) -> None: # pragma: no cover
import asyncio
@ -1617,6 +1626,10 @@ def _revoke_vc(
"parent_coin_id": parent_coin_id,
"vc_id": vc_id,
"fee": fee,
"reuse_puzhash": reuse_puzhash,
"reuse_puzhash": True if reuse else None,
"min_coin_amount": min_amount,
"max_coin_amount": max_amount,
"excluded_coin_ids": coins_to_exclude,
"excluded_amounts": amounts_to_exclude,
}
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, revoke_vc))

View File

@ -10,7 +10,7 @@ from datetime import datetime
from decimal import Decimal
from typing import Any, Awaitable, Callable, Dict, List, Optional, Tuple, Union
from chia.cmds.cmds_util import transaction_status_msg, transaction_submitted_msg
from chia.cmds.cmds_util import CMDTXConfigLoader, transaction_status_msg, transaction_submitted_msg
from chia.cmds.peer_funcs import print_connections
from chia.cmds.units import units
from chia.rpc.wallet_rpc_client import WalletRpcClient
@ -245,12 +245,10 @@ async def send(args: dict, wallet_client: WalletRpcClient, fingerprint: int) ->
fee = Decimal(args["fee"])
address = args["address"]
override = args["override"]
min_coin_amount = Decimal(args["min_coin_amount"])
max_coin_amount = Decimal(args["max_coin_amount"])
excluded_coin_ids: List[str] = args["excluded_coin_ids"]
memo = args["memo"]
reuse_puzhash = args["reuse_puzhash"]
clawback_time_lock = args["clawback_time"]
config = load_config(DEFAULT_ROOT_PATH, "config.yaml")
tx_config = CMDTXConfigLoader.from_json_dict(args).to_tx_config(units["chia"], config, fingerprint)
if memo is None:
memos = None
else:
@ -277,20 +275,15 @@ async def send(args: dict, wallet_client: WalletRpcClient, fingerprint: int) ->
final_fee: uint64 = uint64(int(fee * units["chia"])) # fees are always in XCH mojos
final_amount: uint64 = uint64(int(amount * mojo_per_unit))
final_min_coin_amount: uint64 = uint64(int(min_coin_amount * mojo_per_unit))
final_max_coin_amount: uint64 = uint64(int(max_coin_amount * mojo_per_unit))
if typ == WalletType.STANDARD_WALLET:
print("Submitting transaction...")
res = await wallet_client.send_transaction(
wallet_id,
final_amount,
address,
tx_config,
final_fee,
memos,
final_min_coin_amount,
final_max_coin_amount,
excluded_coin_ids=excluded_coin_ids,
reuse_puzhash=reuse_puzhash,
puzzle_decorator_override=[
{"decorator": PuzzleDecoratorType.CLAWBACK.name, "clawback_timelock": clawback_time_lock}
]
@ -301,14 +294,11 @@ async def send(args: dict, wallet_client: WalletRpcClient, fingerprint: int) ->
print("Submitting transaction...")
res = await wallet_client.cat_spend(
wallet_id,
tx_config,
final_amount,
address,
final_fee,
memos,
final_min_coin_amount,
final_max_coin_amount,
excluded_coin_ids=excluded_coin_ids,
reuse_puzhash=reuse_puzhash,
)
else:
print("Only standard wallet and CAT wallets are supported")
@ -381,7 +371,6 @@ async def make_offer(args: dict, wallet_client: WalletRpcClient, fingerprint: in
requests: List[str] = args["requests"]
filepath: str = args["filepath"]
fee: int = int(Decimal(args["fee"]) * units["chia"])
reuse_puzhash: Optional[bool] = args["reuse_puzhash"]
config = load_config(DEFAULT_ROOT_PATH, "config.yaml")
if [] in [offers, requests]:
@ -522,7 +511,10 @@ async def make_offer(args: dict, wallet_client: WalletRpcClient, fingerprint: in
else:
with open(pathlib.Path(filepath), "w") as file:
offer, trade_record = await wallet_client.create_offer_for_ids(
offer_dict, driver_dict=driver_dict, fee=fee, reuse_puzhash=reuse_puzhash
offer_dict,
CMDTXConfigLoader.from_json_dict(args).to_tx_config(units["chia"], config, fingerprint),
driver_dict=driver_dict,
fee=fee,
)
if offer is not None:
file.write(offer.to_bech32())
@ -751,7 +743,9 @@ async def take_offer(args: dict, wallet_client: WalletRpcClient, fingerprint: in
print()
confirmation = input("Would you like to take this offer? (y/n): ")
if confirmation in ["y", "yes"]:
trade_record = await wallet_client.take_offer(offer, fee=fee)
trade_record = await wallet_client.take_offer(
offer, CMDTXConfigLoader.from_json_dict(args).to_tx_config(units["chia"], config, fingerprint), fee=fee
)
print(f"Accepted offer with ID {trade_record.trade_id}")
print(f"Use chia wallet get_offers --id {trade_record.trade_id} -f {fingerprint} to view its status")
@ -1021,6 +1015,7 @@ async def mint_nft(args: Dict, wallet_client: WalletRpcClient, fingerprint: int)
target_address,
hash,
uris,
CMDTXConfigLoader.from_json_dict(args).to_tx_config(units["chia"], config, fingerprint),
metadata_hash,
metadata_uris,
license_hash,
@ -1030,7 +1025,6 @@ async def mint_nft(args: Dict, wallet_client: WalletRpcClient, fingerprint: int)
fee,
royalty_percentage,
did_id,
reuse_puzhash=args["reuse_puzhash"],
)
spend_bundle = response["spend_bundle"]
print(f"NFT minted Successfully with spend bundle: {spend_bundle}")
@ -1076,7 +1070,11 @@ async def transfer_nft(args: Dict, wallet_client: WalletRpcClient, fingerprint:
target_address = ensure_valid_address(args["target_address"], allowed_types={AddressType.XCH}, config=config)
fee: int = int(Decimal(args["fee"]) * units["chia"])
response = await wallet_client.transfer_nft(
wallet_id, nft_coin_id, target_address, fee, reuse_puzhash=args["reuse_puzhash"]
wallet_id,
nft_coin_id,
target_address,
fee,
CMDTXConfigLoader.from_json_dict(args).to_tx_config(units["chia"], config, fingerprint),
)
spend_bundle = response["spend_bundle"]
print(f"NFT transferred successfully with spend bundle: {spend_bundle}")
@ -1143,8 +1141,13 @@ async def set_nft_did(args: Dict, wallet_client: WalletRpcClient, fingerprint: i
nft_coin_id = args["nft_coin_id"]
fee: int = int(Decimal(args["fee"]) * units["chia"])
try:
config = load_config(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME)
response = await wallet_client.set_nft_did(
wallet_id, did_id, nft_coin_id, fee, reuse_puzhash=args["reuse_puzhash"]
wallet_id,
did_id,
nft_coin_id,
fee,
CMDTXConfigLoader.from_json_dict(args).to_tx_config(units["chia"], config, fingerprint),
)
spend_bundle = response["spend_bundle"]
print(f"Transaction to set DID on NFT has been initiated with: {spend_bundle}")
@ -1337,10 +1340,10 @@ async def spend_vc(args: Dict, wallet_client: WalletRpcClient, fingerprint: int)
config = load_config(DEFAULT_ROOT_PATH, "config.yaml", SERVICE_NAME)
txs = await wallet_client.vc_spend(
bytes32.from_hexstr(args["vc_id"]),
CMDTXConfigLoader.from_json_dict(args).to_tx_config(units["chia"], config, fingerprint),
new_puzhash=None if args["new_puzhash"] is None else bytes32.from_hexstr(args["new_puzhash"]),
new_proof_hash=bytes32.from_hexstr(args["new_proof_hash"]),
fee=uint64(0) if args["fee"] is None else uint64(int(Decimal(args["fee"]) * units["chia"])),
reuse_puzhash=args["reuse_puzhash"],
)
print("Proofs successfully updated!")
@ -1393,8 +1396,8 @@ async def revoke_vc(args: Dict, wallet_client: WalletRpcClient, fingerprint: int
parent_id = bytes32.from_hexstr(args["parent_coin_id"])
txs = await wallet_client.vc_revoke(
parent_id,
CMDTXConfigLoader.from_json_dict(args).to_tx_config(units["chia"], config, fingerprint),
fee=uint64(0) if args["fee"] is None else uint64(int(Decimal(args["fee"]) * units["chia"])),
reuse_puzhash=args["reuse_puzhash"],
)
print("VC successfully revoked!")

View File

@ -47,6 +47,7 @@ from chia.util.path import path_from_root
from chia.wallet.trade_record import TradeRecord
from chia.wallet.trading.offer import Offer as TradingOffer
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
async def get_plugin_info(url: str) -> Tuple[str, Dict[str, Any]]:
@ -754,6 +755,9 @@ class DataLayer:
driver_dict={},
fee=fee,
validate_only=False,
# TODO: probably shouldn't be default but due to peculiarities in the RPC, we're using a stop gap.
# This is not a change in behavior, the default was already implicit.
tx_config=DEFAULT_TX_CONFIG,
)
if wallet_offer is None:
raise Exception("offer is None despite validate_only=False")
@ -838,6 +842,9 @@ class DataLayer:
offer=offer,
solver=solver,
fee=fee,
# TODO: probably shouldn't be default but due to peculiarities in the RPC, we're using a stop gap.
# This is not a change in behavior, the default was already implicit.
tx_config=DEFAULT_TX_CONFIG,
)
return trade_record

View File

@ -51,6 +51,7 @@ from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.merkle_utils import _simplify_merkle_proof
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import CoinSelectionConfig, TXConfig, TXConfigLoader
from chia.wallet.util.wallet_sync_utils import fetch_coin_spend, fetch_coin_spend_for_coin_state
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet import Wallet
@ -289,20 +290,21 @@ class DataLayerWallet:
async def generate_new_reporter(
self,
initial_root: bytes32,
tx_config: TXConfig,
fee: uint64 = uint64(0),
) -> Tuple[TransactionRecord, TransactionRecord, bytes32]:
"""
Creates the initial singleton, which includes spending an origin coin, the launcher, and creating a singleton
"""
coins: Set[Coin] = await self.standard_wallet.select_coins(uint64(fee + 1))
coins: Set[Coin] = await self.standard_wallet.select_coins(uint64(fee + 1), tx_config.coin_selection_config)
if coins is None:
raise ValueError("Not enough coins to create new data layer singleton")
launcher_parent: Coin = list(coins)[0]
launcher_coin: Coin = Coin(launcher_parent.name(), SINGLETON_LAUNCHER.get_tree_hash(), uint64(1))
inner_puzzle: Program = await self.standard_wallet.get_new_puzzle()
inner_puzzle: Program = await self.standard_wallet.get_puzzle(new=not tx_config.reuse_puzhash)
full_puzzle: Program = create_host_fullpuz(inner_puzzle, initial_root, launcher_coin.name())
genesis_launcher_solution: Program = Program.to(
@ -313,6 +315,7 @@ class DataLayerWallet:
create_launcher_tx_record: Optional[TransactionRecord] = await self.standard_wallet.generate_signed_transaction(
amount=uint64(1),
puzzle_hash=SINGLETON_LAUNCHER.get_tree_hash(),
tx_config=tx_config,
fee=fee,
origin_id=launcher_parent.name(),
coins=coins,
@ -375,11 +378,13 @@ class DataLayerWallet:
self,
fee: uint64,
announcement_to_assert: Announcement,
tx_config: TXConfig,
coin_announcement: bool = True,
) -> TransactionRecord:
chia_tx = await self.standard_wallet.generate_signed_transaction(
amount=uint64(0),
puzzle_hash=await self.standard_wallet.get_new_puzzlehash(),
puzzle_hash=await self.standard_wallet.get_puzzle_hash(new=not tx_config.reuse_puzhash),
tx_config=tx_config,
fee=fee,
negative_change_allowed=False,
coin_announcements_to_consume={announcement_to_assert} if coin_announcement else None,
@ -392,6 +397,7 @@ class DataLayerWallet:
self,
launcher_id: bytes32,
root_hash: Optional[bytes32],
tx_config: TXConfig,
new_puz_hash: Optional[bytes32] = None,
new_amount: Optional[uint64] = None,
fee: uint64 = uint64(0),
@ -416,7 +422,7 @@ class DataLayerWallet:
# Make the child's puzzles
if new_puz_hash is None:
new_puz_hash = (await self.standard_wallet.get_new_puzzle()).get_tree_hash()
new_puz_hash = await self.standard_wallet.get_puzzle_hash(new=not tx_config.reuse_puzhash)
assert new_puz_hash is not None
next_full_puz_hash: bytes32 = create_host_fullpuz(new_puz_hash, root_hash, launcher_id).get_tree_hash_precalc(
new_puz_hash
@ -595,7 +601,7 @@ class DataLayerWallet:
assert dl_tx.spend_bundle is not None
if fee > 0:
chia_tx = await self.create_tandem_xch_tx(
fee, Announcement(current_coin.name(), b"$"), coin_announcement=True
fee, Announcement(current_coin.name(), b"$"), tx_config, coin_announcement=True
)
assert chia_tx.spend_bundle is not None
aggregate_bundle = SpendBundle.aggregate([dl_tx.spend_bundle, chia_tx.spend_bundle])
@ -620,6 +626,7 @@ class DataLayerWallet:
self,
amounts: List[uint64],
puzzle_hashes: List[bytes32],
tx_config: TXConfig,
fee: uint64 = uint64(0),
coins: Set[Coin] = set(),
memos: Optional[List[List[bytes]]] = None, # ignored
@ -655,6 +662,7 @@ class DataLayerWallet:
return await self.create_update_state_spend(
launcher_id,
new_root_hash,
tx_config,
puzzle_hashes[0],
amounts[0],
fee,
@ -720,11 +728,12 @@ class DataLayerWallet:
return collected
async def create_new_mirror(
self, launcher_id: bytes32, amount: uint64, urls: List[bytes], fee: uint64 = uint64(0)
self, launcher_id: bytes32, amount: uint64, urls: List[bytes], tx_config: TXConfig, fee: uint64 = uint64(0)
) -> List[TransactionRecord]:
create_mirror_tx_record: Optional[TransactionRecord] = await self.standard_wallet.generate_signed_transaction(
amount=amount,
puzzle_hash=create_mirror_puzzle().get_tree_hash(),
tx_config=tx_config,
fee=fee,
primaries=[],
memos=[launcher_id, *(url for url in urls)],
@ -734,7 +743,7 @@ class DataLayerWallet:
return [create_mirror_tx_record]
async def delete_mirror(
self, mirror_id: bytes32, peer: WSChiaConnection, fee: uint64 = uint64(0)
self, mirror_id: bytes32, peer: WSChiaConnection, tx_config: TXConfig, fee: uint64 = uint64(0)
) -> List[TransactionRecord]:
mirror: Mirror = await self.get_mirror(mirror_id)
mirror_coin: Coin = (await self.wallet_state_manager.wallet_node.get_coin_state([mirror.coin_id], peer=peer))[
@ -752,7 +761,7 @@ class DataLayerWallet:
await self.standard_wallet.hack_populate_secret_key_for_puzzle_hash(parent_coin.puzzle_hash)
parent_inner_puzzle: Program = self.standard_wallet.puzzle_for_pk(inner_puzzle_derivation.pubkey)
new_puzhash: bytes32 = await self.get_new_puzzlehash()
new_puzhash: bytes32 = await self.standard_wallet.get_puzzle_hash(new=not tx_config.reuse_puzhash)
excess_fee: int = fee - mirror_coin.amount
inner_sol: Program = self.standard_wallet.make_solution(
primaries=[Payment(new_puzhash, uint64(mirror_coin.amount - fee))] if excess_fee < 0 else [],
@ -796,6 +805,7 @@ class DataLayerWallet:
chia_tx: TransactionRecord = await self.wallet_state_manager.main_wallet.generate_signed_transaction(
uint64(1),
new_puzhash,
tx_config,
fee=uint64(excess_fee),
coin_announcements_to_consume={Announcement(mirror_coin.name(), b"$")},
)
@ -975,10 +985,17 @@ class DataLayerWallet:
else:
fee = uint64(0)
assert self.wallet_state_manager.wallet_node.logged_in_fingerprint is not None
all_txs.extend(
await self.create_update_state_spend(
launcher_id,
singleton.root,
TXConfigLoader().autofill(
self.wallet_state_manager.config,
self.wallet_state_manager.wallet_node.logged_in_fingerprint,
self.wallet_state_manager.constants,
),
fee=fee,
)
)
@ -1126,6 +1143,7 @@ class DataLayerWallet:
offer_dict: Dict[Optional[bytes32], int],
driver_dict: Dict[bytes32, PuzzleInfo],
solver: Solver,
tx_config: TXConfig,
fee: uint64 = uint64(0),
old: bool = False,
) -> Offer:
@ -1146,10 +1164,11 @@ class DataLayerWallet:
except KeyError:
this_solver = solver["0x" + launcher.hex()]
new_root: bytes32 = this_solver["new_root"]
new_ph: bytes32 = await wallet_state_manager.main_wallet.get_new_puzzlehash()
new_ph: bytes32 = await wallet_state_manager.main_wallet.get_puzzle_hash(new=not tx_config.reuse_puzhash)
txs: List[TransactionRecord] = await dl_wallet.generate_signed_transaction(
[uint64(1)],
[new_ph],
tx_config,
fee=fee_left_to_pay,
launcher_id=launcher,
new_root_hash=new_root,
@ -1302,10 +1321,7 @@ class DataLayerWallet:
async def select_coins(
self,
amount: uint64,
exclude: Optional[List[Coin]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
coin_selection_config: CoinSelectionConfig,
) -> Set[Coin]:
raise RuntimeError("DataLayerWallet does not support select_coins()")

View File

@ -50,6 +50,7 @@ from chia.wallet.derive_keys import find_owner_sk
from chia.wallet.sign_coin_spends import sign_coin_spends
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG, CoinSelectionConfig, TXConfig
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet import Wallet
from chia.wallet.wallet_coin_record import WalletCoinRecord
@ -75,6 +76,7 @@ class PoolWallet:
standard_wallet: Wallet
wallet_id: int
next_transaction_fee: uint64 = uint64(0)
next_tx_config: TXConfig = DEFAULT_TX_CONFIG
target_state: Optional[PoolState] = None
_owner_sk_and_index: Optional[Tuple[PrivateKey, uint32]] = None
@ -296,6 +298,7 @@ class PoolWallet:
if self.target_state == latest_state:
self.target_state = None
self.next_transaction_fee = uint64(0)
self.next_tx_config = DEFAULT_TX_CONFIG
break
await self.update_pool_config()
@ -390,6 +393,7 @@ class PoolWallet:
wallet_state_manager: Any,
main_wallet: Wallet,
initial_target_state: PoolState,
tx_config: TXConfig,
fee: uint64 = uint64(0),
p2_singleton_delay_time: Optional[uint64] = None,
p2_singleton_delayed_ph: Optional[bytes32] = None,
@ -429,6 +433,7 @@ class PoolWallet:
wallet_state_manager.constants.GENESIS_CHALLENGE,
p2_singleton_delay_time,
p2_singleton_delayed_ph,
tx_config,
)
if spend_bundle is None:
@ -491,11 +496,13 @@ class PoolWallet:
async def generate_fee_transaction(
self,
fee: uint64,
tx_config: TXConfig,
coin_announcements: Optional[Set[Announcement]] = None,
) -> TransactionRecord:
fee_tx = await self.standard_wallet.generate_signed_transaction(
uint64(0),
(await self.standard_wallet.get_new_puzzlehash()),
tx_config,
fee=fee,
origin_id=None,
coins=None,
@ -516,7 +523,9 @@ class PoolWallet:
if fee_tx is not None:
await self.wallet_state_manager.add_pending_transaction(dataclasses.replace(fee_tx, spend_bundle=None))
async def generate_travel_transactions(self, fee: uint64) -> Tuple[TransactionRecord, Optional[TransactionRecord]]:
async def generate_travel_transactions(
self, fee: uint64, tx_config: TXConfig
) -> Tuple[TransactionRecord, Optional[TransactionRecord]]:
# target_state is contained within pool_wallet_state
pool_wallet_info: PoolWalletInfo = await self.get_current_state()
@ -594,7 +603,7 @@ class PoolWallet:
assert signed_spend_bundle is not None
fee_tx: Optional[TransactionRecord] = None
if fee > 0:
fee_tx = await self.generate_fee_transaction(fee)
fee_tx = await self.generate_fee_transaction(fee, tx_config)
assert fee_tx.spend_bundle is not None
signed_spend_bundle = SpendBundle.aggregate([signed_spend_bundle, fee_tx.spend_bundle])
@ -629,12 +638,13 @@ class PoolWallet:
genesis_challenge: bytes32,
delay_time: uint64,
delay_ph: bytes32,
tx_config: TXConfig,
) -> Tuple[SpendBundle, bytes32, bytes32]:
"""
Creates the initial singleton, which includes spending an origin coin, the launcher, and creating a singleton
with the "pooling" inner state, which can be either self pooling or using a pool
"""
coins: Set[Coin] = await standard_wallet.select_coins(uint64(amount + fee))
coins: Set[Coin] = await standard_wallet.select_coins(uint64(amount + fee), tx_config.coin_selection_config)
if coins is None:
raise ValueError("Not enough coins to create pool wallet")
@ -680,6 +690,7 @@ class PoolWallet:
create_launcher_tx_record: Optional[TransactionRecord] = await standard_wallet.generate_signed_transaction(
amount,
genesis_launcher_puz.get_tree_hash(),
tx_config,
fee,
coins,
None,
@ -703,7 +714,7 @@ class PoolWallet:
return full_spend, puzzle_hash, launcher_coin.name()
async def join_pool(
self, target_state: PoolState, fee: uint64
self, target_state: PoolState, fee: uint64, tx_config: TXConfig
) -> Tuple[uint64, TransactionRecord, Optional[TransactionRecord]]:
if target_state.state != FARMING_TO_POOL.value:
raise ValueError(f"join_pool must be called with target_state={FARMING_TO_POOL} (FARMING_TO_POOL)")
@ -745,10 +756,13 @@ class PoolWallet:
self.target_state = target_state
self.next_transaction_fee = fee
travel_tx, fee_tx = await self.generate_travel_transactions(fee)
self.next_tx_config = tx_config
travel_tx, fee_tx = await self.generate_travel_transactions(fee, tx_config)
return total_fee, travel_tx, fee_tx
async def self_pool(self, fee: uint64) -> Tuple[uint64, TransactionRecord, Optional[TransactionRecord]]:
async def self_pool(
self, fee: uint64, tx_config: TXConfig
) -> Tuple[uint64, TransactionRecord, Optional[TransactionRecord]]:
if await self.have_unconfirmed_transaction():
raise ValueError(
"Cannot self pool due to unconfirmed transaction. If this is stuck, delete the unconfirmed transaction."
@ -782,11 +796,12 @@ class PoolWallet:
SELF_POOLING, owner_puzzlehash, owner_pubkey, pool_url=None, relative_lock_height=uint32(0)
)
self.next_transaction_fee = fee
travel_tx, fee_tx = await self.generate_travel_transactions(fee)
self.next_tx_config = tx_config
travel_tx, fee_tx = await self.generate_travel_transactions(fee, tx_config)
return total_fee, travel_tx, fee_tx
async def claim_pool_rewards(
self, fee: uint64, max_spends_in_tx: Optional[int]
self, fee: uint64, max_spends_in_tx: Optional[int], tx_config: TXConfig
) -> Tuple[TransactionRecord, Optional[TransactionRecord]]:
# Search for p2_puzzle_hash coins, and spend them with the singleton
if await self.have_unconfirmed_transaction():
@ -864,7 +879,7 @@ class PoolWallet:
if fee > 0:
absorb_announce = Announcement(first_coin_record.coin.name(), b"$")
assert absorb_announce is not None
fee_tx = await self.generate_fee_transaction(fee, coin_announcements={absorb_announce})
fee_tx = await self.generate_fee_transaction(fee, tx_config, coin_announcements={absorb_announce})
assert fee_tx.spend_bundle is not None
full_spend = SpendBundle.aggregate([fee_tx.spend_bundle, claim_spend])
@ -935,7 +950,7 @@ class PoolWallet:
assert self.target_state.relative_lock_height >= self.MINIMUM_RELATIVE_LOCK_HEIGHT
assert self.target_state.pool_url is not None
await self.generate_travel_transactions(self.next_transaction_fee)
await self.generate_travel_transactions(self.next_transaction_fee, self.next_tx_config)
async def have_unconfirmed_transaction(self) -> bool:
unconfirmed: List[TransactionRecord] = await self.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(
@ -969,14 +984,7 @@ class PoolWallet:
async def coin_added(self, coin: Coin, height: uint32, peer: WSChiaConnection) -> None:
pass
async def select_coins(
self,
amount: uint64,
exclude: Optional[List[Coin]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
) -> Set[Coin]:
async def select_coins(self, amount: uint64, coin_selection_config: CoinSelectionConfig) -> Set[Coin]:
raise RuntimeError("PoolWallet does not support select_coins()")
def require_derivation_paths(self) -> bool:

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,7 @@ from chia.wallet.trading.offer import Offer
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.transaction_sorting import SortKey
from chia.wallet.util.query_filter import TransactionTypeFilter
from chia.wallet.util.tx_config import CoinSelectionConfig, TXConfig
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.vc_wallet.vc_store import VCRecord
from chia.wallet.wallet_coin_store import GetCoinRecords
@ -184,14 +185,10 @@ class WalletRpcClient(RpcClient):
wallet_id: int,
amount: uint64,
address: str,
tx_config: TXConfig,
fee: uint64 = uint64(0),
memos: Optional[List[str]] = None,
min_coin_amount: uint64 = uint64(0),
max_coin_amount: uint64 = uint64(0),
excluded_amounts: Optional[List[uint64]] = None,
excluded_coin_ids: Optional[List[str]] = None,
puzzle_decorator_override: Optional[List[Dict[str, Union[str, int, bool]]]] = None,
reuse_puzhash: Optional[bool] = None,
) -> TransactionRecord:
if memos is None:
send_dict: Dict = {
@ -199,12 +196,7 @@ class WalletRpcClient(RpcClient):
"amount": amount,
"address": address,
"fee": fee,
"min_coin_amount": min_coin_amount,
"max_coin_amount": max_coin_amount,
"excluded_coin_amounts": excluded_amounts,
"excluded_coin_ids": excluded_coin_ids,
"puzzle_decorator": puzzle_decorator_override,
"reuse_puzhash": reuse_puzhash,
}
else:
send_dict = {
@ -213,18 +205,19 @@ class WalletRpcClient(RpcClient):
"address": address,
"fee": fee,
"memos": memos,
"min_coin_amount": min_coin_amount,
"max_coin_amount": max_coin_amount,
"excluded_coin_amounts": excluded_amounts,
"excluded_coin_ids": excluded_coin_ids,
"puzzle_decorator": puzzle_decorator_override,
"reuse_puzhash": reuse_puzhash,
}
send_dict.update(tx_config.to_json_dict())
res = await self.fetch("send_transaction", send_dict)
return TransactionRecord.from_json_dict_convenience(res["transaction"])
async def send_transaction_multi(
self, wallet_id: int, additions: List[Dict], coins: List[Coin] = None, fee: uint64 = uint64(0)
self,
wallet_id: int,
additions: List[Dict],
tx_config: TXConfig,
coins: List[Coin] = None,
fee: uint64 = uint64(0),
) -> TransactionRecord:
# Converts bytes to hex for puzzle hashes
additions_hex = []
@ -275,14 +268,11 @@ class WalletRpcClient(RpcClient):
async def create_signed_transactions(
self,
additions: List[Dict],
tx_config: TXConfig,
coins: List[Coin] = None,
fee: uint64 = uint64(0),
coin_announcements: Optional[List[Announcement]] = None,
puzzle_announcements: Optional[List[Announcement]] = None,
min_coin_amount: uint64 = uint64(0),
max_coin_amount: uint64 = uint64(0),
excluded_coins: Optional[List[Coin]] = None,
excluded_amounts: Optional[List[uint64]] = None,
wallet_id: Optional[int] = None,
) -> List[TransactionRecord]:
# Converts bytes to hex for puzzle hashes
@ -295,9 +285,7 @@ class WalletRpcClient(RpcClient):
request: Dict[str, Any] = {
"additions": additions_hex,
"fee": fee,
"min_coin_amount": min_coin_amount,
"max_coin_amount": max_coin_amount,
"excluded_coin_amounts": excluded_amounts,
**tx_config.to_json_dict(),
}
if coin_announcements is not None and len(coin_announcements) > 0:
@ -324,10 +312,6 @@ class WalletRpcClient(RpcClient):
coins_json = [c.to_json_dict() for c in coins]
request["coins"] = coins_json
if excluded_coins is not None and len(excluded_coins) > 0:
excluded_coins_json = [excluded_coin.to_json_dict() for excluded_coin in excluded_coins]
request["excluded_coins"] = excluded_coins_json
if wallet_id:
request["wallet_id"] = wallet_id
@ -337,24 +321,20 @@ class WalletRpcClient(RpcClient):
async def create_signed_transaction(
self,
additions: List[Dict],
tx_config: TXConfig,
coins: List[Coin] = None,
fee: uint64 = uint64(0),
coin_announcements: Optional[List[Announcement]] = None,
puzzle_announcements: Optional[List[Announcement]] = None,
min_coin_amount: uint64 = uint64(0),
excluded_coins: Optional[List[Coin]] = None,
excluded_amounts: Optional[List[uint64]] = None,
wallet_id: Optional[int] = None,
) -> TransactionRecord:
txs: List[TransactionRecord] = await self.create_signed_transactions(
additions=additions,
tx_config=tx_config,
coins=coins,
fee=fee,
coin_announcements=coin_announcements,
puzzle_announcements=puzzle_announcements,
min_coin_amount=min_coin_amount,
excluded_coins=excluded_coins,
excluded_amounts=excluded_amounts,
wallet_id=wallet_id,
)
if len(txs) == 0:
@ -366,20 +346,12 @@ class WalletRpcClient(RpcClient):
self,
amount: int,
wallet_id: int,
excluded_coins: Optional[List[Coin]] = None,
min_coin_amount: uint64 = uint64(0),
max_coin_amount: uint64 = uint64(0),
excluded_amounts: Optional[List[uint64]] = None,
coin_selection_config: CoinSelectionConfig,
) -> List[Coin]:
if excluded_coins is None:
excluded_coins = []
request = {
"amount": amount,
"wallet_id": wallet_id,
"min_coin_amount": min_coin_amount,
"max_coin_amount": max_coin_amount,
"excluded_coins": [excluded_coin.to_json_dict() for excluded_coin in excluded_coins],
"excluded_coin_amounts": excluded_amounts,
**coin_selection_config.to_json_dict(),
}
response: Dict[str, List[Dict]] = await self.fetch("select_coins", request)
return [Coin.from_json_dict(coin) for coin in response["coins"]]
@ -390,24 +362,14 @@ class WalletRpcClient(RpcClient):
async def get_spendable_coins(
self,
wallet_id: int,
excluded_coins: Optional[List[Coin]] = None,
min_coin_amount: uint64 = uint64(0),
max_coin_amount: uint64 = uint64(0),
excluded_amounts: Optional[List[uint64]] = None,
excluded_coin_ids: Optional[List[str]] = None,
coin_selection_config: CoinSelectionConfig,
) -> Tuple[List[CoinRecord], List[CoinRecord], List[Coin]]:
"""
We return a tuple containing: (confirmed records, unconfirmed removals, unconfirmed additions)
"""
if excluded_coins is None:
excluded_coins = []
request = {
"wallet_id": wallet_id,
"min_coin_amount": min_coin_amount,
"max_coin_amount": max_coin_amount,
"excluded_coins": [excluded_coin.to_json_dict() for excluded_coin in excluded_coins],
"excluded_coin_amounts": excluded_amounts,
"excluded_coin_ids": excluded_coin_ids,
**coin_selection_config.to_json_dict(),
}
response: Dict[str, List[Dict]] = await self.fetch("get_spendable_coins", request)
confirmed_wrs = [CoinRecord.from_json_dict(coin) for coin in response["confirmed_records"]]
@ -481,13 +443,13 @@ class WalletRpcClient(RpcClient):
wallet_id: int,
recovery_list: List[str],
num_verification: int,
reuse_puzhash: Optional[bool] = None,
tx_config: TXConfig,
) -> Dict:
request: Dict[str, Any] = {
"wallet_id": wallet_id,
"new_list": recovery_list,
"num_verifications_required": num_verification,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
response = await self.fetch("did_update_recovery_ids", request)
return response
@ -514,12 +476,12 @@ class WalletRpcClient(RpcClient):
self,
wallet_id: int,
metadata: Dict,
reuse_puzhash: Optional[bool] = None,
tx_config: TXConfig,
) -> Dict:
request: Dict[str, Any] = {
"wallet_id": wallet_id,
"metadata": metadata,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
response = await self.fetch("did_update_metadata", request)
return response
@ -582,14 +544,14 @@ class WalletRpcClient(RpcClient):
address: str,
fee: int,
with_recovery: bool,
reuse_puzhash: Optional[bool] = None,
tx_config: TXConfig,
) -> Dict:
request: Dict[str, Any] = {
"wallet_id": wallet_id,
"inner_address": address,
"fee": fee,
"with_recovery_info": with_recovery,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
response = await self.fetch("did_transfer_did", request)
return response
@ -727,28 +689,20 @@ class WalletRpcClient(RpcClient):
async def cat_spend(
self,
wallet_id: int,
tx_config: TXConfig,
amount: Optional[uint64] = None,
inner_address: Optional[str] = None,
fee: uint64 = uint64(0),
memos: Optional[List[str]] = None,
min_coin_amount: uint64 = uint64(0),
max_coin_amount: uint64 = uint64(0),
excluded_amounts: Optional[List[uint64]] = None,
excluded_coin_ids: Optional[List[str]] = None,
additions: Optional[List[Dict[str, Any]]] = None,
removals: Optional[List[Coin]] = None,
cat_discrepancy: Optional[Tuple[int, Program, Program]] = None, # (extra_delta, tail_reveal, tail_solution)
reuse_puzhash: Optional[bool] = None,
) -> TransactionRecord:
send_dict: Dict[str, Any] = {
"wallet_id": wallet_id,
"fee": fee,
"memos": memos if memos else [],
"min_coin_amount": min_coin_amount,
"max_coin_amount": max_coin_amount,
"excluded_coin_amounts": excluded_amounts,
"excluded_coin_ids": excluded_coin_ids,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
if amount is not None and inner_address is not None:
send_dict["amount"] = amount
@ -775,13 +729,11 @@ class WalletRpcClient(RpcClient):
async def create_offer_for_ids(
self,
offer_dict: Dict[Union[uint32, str], int],
tx_config: TXConfig,
driver_dict: Dict[str, Any] = None,
solver: Dict[str, Any] = None,
fee=uint64(0),
validate_only: bool = False,
min_coin_amount: uint64 = uint64(0),
max_coin_amount: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> Tuple[Optional[Offer], TradeRecord]:
send_dict: Dict[str, int] = {str(key): value for key, value in offer_dict.items()}
@ -789,9 +741,7 @@ class WalletRpcClient(RpcClient):
"offer": send_dict,
"validate_only": validate_only,
"fee": fee,
"min_coin_amount": min_coin_amount,
"max_coin_amount": max_coin_amount,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
if driver_dict is not None:
req["driver_dict"] = driver_dict
@ -815,16 +765,14 @@ class WalletRpcClient(RpcClient):
async def take_offer(
self,
offer: Offer,
tx_config: TXConfig,
solver: Dict[str, Any] = None,
fee=uint64(0),
min_coin_amount: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> TradeRecord:
req = {
"offer": offer.to_bech32(),
"fee": fee,
"min_coin_amount": min_coin_amount,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
if solver is not None:
req["solver"] = solver
@ -891,6 +839,7 @@ class WalletRpcClient(RpcClient):
target_address,
hash,
uris,
tx_config: TXConfig,
meta_hash="",
meta_uris=[],
license_hash="",
@ -900,7 +849,6 @@ class WalletRpcClient(RpcClient):
fee=0,
royalty_percentage=0,
did_id=None,
reuse_puzhash: Optional[bool] = None,
):
request: Dict[str, Any] = {
"wallet_id": wallet_id,
@ -917,7 +865,7 @@ class WalletRpcClient(RpcClient):
"royalty_percentage": royalty_percentage,
"did_id": did_id,
"fee": fee,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
response = await self.fetch("nft_mint_nft", request)
return response
@ -929,7 +877,7 @@ class WalletRpcClient(RpcClient):
key,
uri,
fee,
reuse_puzhash: Optional[bool] = None,
tx_config: TXConfig,
):
request: Dict[str, Any] = {
"wallet_id": wallet_id,
@ -937,7 +885,7 @@ class WalletRpcClient(RpcClient):
"uri": uri,
"key": key,
"fee": fee,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
response = await self.fetch("nft_add_uri", request)
return response
@ -969,14 +917,14 @@ class WalletRpcClient(RpcClient):
nft_coin_id,
target_address,
fee,
reuse_puzhash: Optional[bool] = None,
tx_config: TXConfig,
):
request: Dict[str, Any] = {
"wallet_id": wallet_id,
"nft_coin_id": nft_coin_id,
"target_address": target_address,
"fee": fee,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
response = await self.fetch("nft_transfer_nft", request)
return response
@ -997,14 +945,14 @@ class WalletRpcClient(RpcClient):
did_id,
nft_coin_id,
fee,
reuse_puzhash: Optional[bool] = None,
tx_config: TXConfig,
):
request: Dict[str, Any] = {
"wallet_id": wallet_id,
"did_id": did_id,
"nft_coin_id": nft_coin_id,
"fee": fee,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
response = await self.fetch("nft_set_nft_did", request)
return response
@ -1020,6 +968,7 @@ class WalletRpcClient(RpcClient):
metadata_list: List[Dict[str, Any]],
royalty_percentage: Optional[int],
royalty_address: Optional[str],
tx_config: TXConfig,
target_list: Optional[List[str]] = None,
mint_number_start: Optional[int] = 1,
mint_total: Optional[int] = None,
@ -1030,7 +979,6 @@ class WalletRpcClient(RpcClient):
did_lineage_parent: Optional[str] = None,
mint_from_did: Optional[bool] = False,
fee: Optional[int] = 0,
reuse_puzhash: Optional[bool] = None,
) -> Dict:
request = {
"wallet_id": wallet_id,
@ -1047,7 +995,7 @@ class WalletRpcClient(RpcClient):
"did_lineage_parent": did_lineage_parent,
"mint_from_did": mint_from_did,
"fee": fee,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
}
response = await self.fetch("nft_mint_bulk", request)
return response
@ -1225,11 +1173,11 @@ class WalletRpcClient(RpcClient):
async def vc_spend(
self,
vc_id: bytes32,
tx_config: TXConfig,
new_puzhash: Optional[bytes32] = None,
new_proof_hash: Optional[bytes32] = None,
provider_inner_puzhash: Optional[bytes32] = None,
fee: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> List[TransactionRecord]:
response = await self.fetch(
"vc_spend",
@ -1241,7 +1189,7 @@ class WalletRpcClient(RpcClient):
if provider_inner_puzhash is not None
else provider_inner_puzhash,
"fee": fee,
"reuse_puzhash": reuse_puzhash,
**tx_config.to_json_dict(),
},
)
return [TransactionRecord.from_json_dict_convenience(tx) for tx in response["transactions"]]
@ -1256,10 +1204,10 @@ class WalletRpcClient(RpcClient):
async def vc_revoke(
self,
vc_parent_id: bytes32,
tx_config: TXConfig,
fee: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> List[TransactionRecord]:
response = await self.fetch(
"vc_revoke", {"vc_parent_id": vc_parent_id.hex(), "fee": fee, "reuse_puzhash": reuse_puzhash}
"vc_revoke", {"vc_parent_id": vc_parent_id.hex(), "fee": fee, **tx_config.to_json_dict()}
)
return [TransactionRecord.from_json_dict_convenience(tx) for tx in response["transactions"]]

View File

@ -27,6 +27,7 @@ from chia.util.config import lock_and_load_config, save_config
from chia.util.ints import uint8, uint32, uint64, uint128
from chia.wallet.payment import Payment
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.wallet import Wallet
from chia.wallet.wallet_node import WalletNode
from chia.wallet.wallet_state_manager import WalletStateManager
@ -616,6 +617,7 @@ class FullNodeSimulator(FullNodeAPI):
tx = await wallet.generate_signed_transaction(
amount=outputs_group[0].amount,
puzzle_hash=outputs_group[0].puzzle_hash,
tx_config=DEFAULT_TX_CONFIG,
primaries=outputs_group[1:],
)
await wallet.push_transaction(tx=tx)

View File

@ -52,6 +52,7 @@ from chia.wallet.uncurried_puzzle import uncurry_puzzle
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.curry_and_treehash import calculate_hash_of_quoted_mod_hash, curry_and_treehash
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG, CoinSelectionConfig, TXConfig
from chia.wallet.util.wallet_sync_utils import fetch_coin_spend_for_coin_state
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet import Wallet
@ -91,6 +92,7 @@ class CATWallet:
wallet: Wallet,
cat_tail_info: Dict[str, Any],
amount: uint64,
tx_config: TXConfig,
name: Optional[str] = None,
) -> "CATWallet":
self = CATWallet()
@ -122,6 +124,7 @@ class CATWallet:
self,
cat_tail_info,
amount,
tx_config,
)
assert self.cat_info.limitations_program_hash != empty_bytes
except Exception:
@ -305,7 +308,7 @@ class CATWallet:
if self.cost_of_single_tx is None:
coin = spendable[0].coin
txs = await self.generate_signed_transaction(
[uint64(coin.amount)], [coin.puzzle_hash], coins={coin}, ignore_max_send_amount=True
[uint64(coin.amount)], [coin.puzzle_hash], DEFAULT_TX_CONFIG, coins={coin}, ignore_max_send_amount=True
)
assert txs[0].spend_bundle
program: BlockGenerator = simple_solution_generator(txs[0].spend_bundle)
@ -480,10 +483,7 @@ class CATWallet:
async def select_coins(
self,
amount: uint64,
exclude: Optional[List[Coin]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
coin_selection_config: CoinSelectionConfig,
) -> Set[Coin]:
"""
Returns a set of coins that can be used for generating a new transaction.
@ -497,18 +497,13 @@ class CATWallet:
unconfirmed_removals: Dict[bytes32, Coin] = await self.wallet_state_manager.unconfirmed_removals_for_wallet(
self.id()
)
if max_coin_amount is None:
max_coin_amount = uint64(self.wallet_state_manager.constants.MAX_COIN_AMOUNT)
coins = await select_coins(
spendable_amount,
max_coin_amount,
coin_selection_config,
spendable_coins,
unconfirmed_removals,
self.log,
uint128(amount),
exclude,
min_coin_amount,
excluded_coin_amounts,
)
assert sum(c.amount for c in coins) >= amount
return coins
@ -565,11 +560,8 @@ class CATWallet:
self,
fee: uint64,
amount_to_claim: uint64,
tx_config: TXConfig,
announcement_to_assert: Optional[Announcement] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
reuse_puzhash: Optional[bool] = None,
) -> Tuple[TransactionRecord, Optional[Announcement]]:
"""
This function creates a non-CAT transaction to pay fees, contribute funds for issuance, and absorb melt value.
@ -577,31 +569,21 @@ class CATWallet:
wallet_state_manager lock
"""
announcement = None
if reuse_puzhash is None:
reuse_puzhash_config = self.wallet_state_manager.config.get("reuse_public_key_for_change", None)
if reuse_puzhash_config is None:
reuse_puzhash = False
else:
reuse_puzhash = reuse_puzhash_config.get(
str(self.wallet_state_manager.wallet_node.logged_in_fingerprint), False
)
if fee > amount_to_claim:
chia_coins = await self.standard_wallet.select_coins(
fee,
min_coin_amount=min_coin_amount,
max_coin_amount=max_coin_amount,
excluded_coin_amounts=excluded_coin_amounts,
tx_config.coin_selection_config,
)
origin_id = list(chia_coins)[0].name()
chia_tx = await self.standard_wallet.generate_signed_transaction(
uint64(0),
(await self.standard_wallet.get_puzzle_hash(not reuse_puzhash)),
(await self.standard_wallet.get_puzzle_hash(not tx_config.reuse_puzhash)),
tx_config,
fee=uint64(fee - amount_to_claim),
coins=chia_coins,
origin_id=origin_id, # We specify this so that we know the coin that is making the announcement
negative_change_allowed=False,
coin_announcements_to_consume={announcement_to_assert} if announcement_to_assert is not None else None,
reuse_puzhash=reuse_puzhash,
)
assert chia_tx.spend_bundle is not None
@ -618,18 +600,16 @@ class CATWallet:
else:
chia_coins = await self.standard_wallet.select_coins(
fee,
min_coin_amount=min_coin_amount,
max_coin_amount=max_coin_amount,
excluded_coin_amounts=excluded_coin_amounts,
tx_config.coin_selection_config,
)
selected_amount = sum([c.amount for c in chia_coins])
chia_tx = await self.standard_wallet.generate_signed_transaction(
uint64(selected_amount + amount_to_claim - fee),
(await self.standard_wallet.get_puzzle_hash(not reuse_puzhash)),
(await self.standard_wallet.get_puzzle_hash(not tx_config.reuse_puzhash)),
tx_config,
coins=chia_coins,
negative_change_allowed=True,
coin_announcements_to_consume={announcement_to_assert} if announcement_to_assert is not None else None,
reuse_puzhash=reuse_puzhash,
)
assert chia_tx.spend_bundle is not None
@ -638,16 +618,12 @@ class CATWallet:
async def generate_unsigned_spendbundle(
self,
payments: List[Payment],
tx_config: TXConfig,
fee: uint64 = uint64(0),
cat_discrepancy: Optional[Tuple[int, Program, Program]] = None, # (extra_delta, tail_reveal, tail_solution)
coins: Optional[Set[Coin]] = None,
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
excluded_coins: Optional[Set[Coin]] = None,
reuse_puzhash: Optional[bool] = None,
) -> Tuple[SpendBundle, Optional[TransactionRecord]]:
if coin_announcements_to_consume is not None:
coin_announcements_bytes: Optional[Set[bytes32]] = {a.name() for a in coin_announcements_to_consume}
@ -665,26 +641,11 @@ class CATWallet:
extra_delta, tail_reveal, tail_solution = 0, Program.to([]), Program.to([])
payment_amount: int = sum([p.amount for p in payments])
starting_amount: int = payment_amount - extra_delta
if reuse_puzhash is None:
reuse_puzhash_config = self.wallet_state_manager.config.get("reuse_public_key_for_change", None)
if reuse_puzhash_config is None:
reuse_puzhash = False
else:
reuse_puzhash = reuse_puzhash_config.get(
str(self.wallet_state_manager.wallet_node.logged_in_fingerprint), False
)
if coins is None:
if excluded_coins is None:
excluded_coins = set()
cat_coins = await self.select_coins(
uint64(starting_amount),
exclude=list(excluded_coins),
min_coin_amount=min_coin_amount,
max_coin_amount=max_coin_amount,
excluded_coin_amounts=excluded_coin_amounts,
tx_config.coin_selection_config,
)
elif excluded_coins is not None:
raise ValueError("Can't exclude coins when also specifically including coins")
else:
cat_coins = coins
@ -708,7 +669,7 @@ class CATWallet:
derivation_record = await self.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(
list(cat_coins)[0].puzzle_hash
)
if derivation_record is not None and reuse_puzhash:
if derivation_record is not None and tx_config.reuse_puzhash:
change_puzhash = self.standard_wallet.puzzle_hash_for_pk(derivation_record.pubkey)
for payment in payments:
if change_puzhash == payment.puzzle_hash and change == payment.amount:
@ -733,11 +694,8 @@ class CATWallet:
chia_tx, _ = await self.create_tandem_xch_tx(
fee,
uint64(regular_chia_to_claim),
tx_config,
announcement_to_assert=announcement,
min_coin_amount=min_coin_amount,
max_coin_amount=max_coin_amount,
excluded_coin_amounts=excluded_coin_amounts,
reuse_puzhash=reuse_puzhash,
)
innersol = self.standard_wallet.make_solution(
primaries=primaries,
@ -749,10 +707,7 @@ class CATWallet:
chia_tx, _ = await self.create_tandem_xch_tx(
fee,
uint64(regular_chia_to_claim),
min_coin_amount=min_coin_amount,
max_coin_amount=max_coin_amount,
excluded_coin_amounts=excluded_coin_amounts,
reuse_puzhash=reuse_puzhash,
tx_config,
)
innersol = self.standard_wallet.make_solution(
primaries=primaries,
@ -810,19 +765,15 @@ class CATWallet:
self,
amounts: List[uint64],
puzzle_hashes: List[bytes32],
tx_config: TXConfig,
fee: uint64 = uint64(0),
coins: Optional[Set[Coin]] = None,
ignore_max_send_amount: bool = False,
memos: Optional[List[List[bytes]]] = None,
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
reuse_puzhash: Optional[bool] = None,
**kwargs: Unpack[GSTOptionalArgs],
) -> List[TransactionRecord]:
excluded_cat_coins: Optional[Set[Coin]] = kwargs.get("excluded_cat_coins", None)
# (extra_delta, tail_reveal, tail_solution)
cat_discrepancy: Optional[Tuple[int, Program, Program]] = kwargs.get("cat_discrepancy", None)
if memos is None:
@ -844,16 +795,12 @@ class CATWallet:
raise ValueError(f"Can't send more than {max_send} mojos in a single transaction")
unsigned_spend_bundle, chia_tx = await self.generate_unsigned_spendbundle(
payments,
tx_config,
fee,
cat_discrepancy=cat_discrepancy, # (extra_delta, tail_reveal, tail_solution)
coins=coins,
coin_announcements_to_consume=coin_announcements_to_consume,
puzzle_announcements_to_consume=puzzle_announcements_to_consume,
min_coin_amount=min_coin_amount,
max_coin_amount=max_coin_amount,
excluded_coin_amounts=excluded_coin_amounts,
excluded_coins=excluded_cat_coins,
reuse_puzhash=reuse_puzhash,
)
spend_bundle = await self.sign(unsigned_spend_bundle)
# TODO add support for array in stored records
@ -937,10 +884,9 @@ class CATWallet:
self,
asset_id: Optional[bytes32],
amount: uint64,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
coin_selection_config: CoinSelectionConfig,
) -> Set[Coin]:
balance = await self.get_confirmed_balance()
if balance < amount:
raise Exception(f"insufficient funds in wallet {self.id()}")
return await self.select_coins(amount, min_coin_amount=min_coin_amount, max_coin_amount=max_coin_amount)
return await self.select_coins(amount, coin_selection_config)

View File

@ -7,30 +7,21 @@ from typing import Dict, List, Optional, Set
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.util.ints import uint64, uint128
from chia.wallet.util.tx_config import CoinSelectionConfig
from chia.wallet.wallet_coin_record import WalletCoinRecord
async def select_coins(
spendable_amount: uint128,
max_coin_amount: uint64,
coin_selection_config: CoinSelectionConfig,
spendable_coins: List[WalletCoinRecord],
unconfirmed_removals: Dict[bytes32, Coin],
log: logging.Logger,
amount: uint128,
exclude: Optional[List[Coin]] = None,
min_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
) -> Set[Coin]:
"""
Returns a set of coins that can be used for generating a new transaction.
"""
if exclude is None:
exclude = []
if min_coin_amount is None:
min_coin_amount = uint64(0)
if excluded_coin_amounts is None:
excluded_coin_amounts = []
if amount > spendable_amount:
error_msg = (
f"Can't select amount higher than our spendable balance. Amount: {amount}, spendable: {spendable_amount}"
@ -45,13 +36,17 @@ async def select_coins(
valid_spendable_coins: List[Coin] = []
for coin_record in spendable_coins: # remove all the unconfirmed coins, excluded coins and dust.
if coin_record.coin.name() in unconfirmed_removals:
coin_name: bytes32 = coin_record.coin.name()
if coin_name in unconfirmed_removals:
continue
if coin_record.coin in exclude:
if coin_name in coin_selection_config.excluded_coin_ids:
continue
if coin_record.coin.amount < min_coin_amount or coin_record.coin.amount > max_coin_amount:
if (
coin_record.coin.amount < coin_selection_config.min_coin_amount
or coin_record.coin.amount > coin_selection_config.max_coin_amount
):
continue
if coin_record.coin.amount in excluded_coin_amounts:
if coin_record.coin.amount in coin_selection_config.excluded_coin_amounts:
continue
valid_spendable_coins.append(coin_record.coin)
sum_spendable_coins += coin_record.coin.amount
@ -95,7 +90,9 @@ async def select_coins(
log.debug(f"Selected closest greater coin: {smallest_coin.name()}")
return {smallest_coin}
elif smaller_coin_sum > amount:
coin_set: Optional[Set[Coin]] = knapsack_coin_algorithm(smaller_coins, amount, max_coin_amount, max_num_coins)
coin_set: Optional[Set[Coin]] = knapsack_coin_algorithm(
smaller_coins, amount, coin_selection_config.max_coin_amount, max_num_coins
)
log.debug(f"Selected coins from knapsack algorithm: {coin_set}")
if coin_set is None:
coin_set = sum_largest_coins(amount, smaller_coins)

View File

@ -43,6 +43,7 @@ from chia.wallet.singleton import (
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG, CoinSelectionConfig, TXConfig
from chia.wallet.util.wallet_sync_utils import fetch_coin_spend, fetch_coin_spend_for_coin_state
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet import CHIP_0002_SIGN_MESSAGE_PREFIX, Wallet
@ -123,7 +124,7 @@ class DIDWallet:
raise ValueError("Not enough balance")
try:
spend_bundle = await self.generate_new_decentralised_id(amount, fee)
spend_bundle = await self.generate_new_decentralised_id(amount, DEFAULT_TX_CONFIG, fee)
except Exception:
await wallet_state_manager.user_store.delete_wallet(self.id())
raise
@ -323,10 +324,7 @@ class DIDWallet:
async def select_coins(
self,
amount: uint64,
exclude: Optional[List[Coin]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
coin_selection_config: CoinSelectionConfig,
) -> Set[Coin]:
"""
Returns a set of coins that can be used for generating a new transaction.
@ -349,18 +347,13 @@ class DIDWallet:
unconfirmed_removals: Dict[bytes32, Coin] = await self.wallet_state_manager.unconfirmed_removals_for_wallet(
self.wallet_info.id
)
if max_coin_amount is None:
max_coin_amount = uint64(self.wallet_state_manager.constants.MAX_COIN_AMOUNT)
coins = await select_coins(
spendable_amount,
max_coin_amount,
coin_selection_config,
spendable_coins,
unconfirmed_removals,
self.log,
uint128(amount),
exclude,
min_coin_amount,
excluded_coin_amounts,
)
assert sum(c.amount for c in coins) >= amount
return coins
@ -566,10 +559,10 @@ class DIDWallet:
def get_name(self):
return self.wallet_info.name
async def create_update_spend(self, fee: uint64 = uint64(0), reuse_puzhash: Optional[bool] = None):
async def create_update_spend(self, tx_config: TXConfig, fee: uint64 = uint64(0)):
assert self.did_info.current_inner is not None
assert self.did_info.origin_coin is not None
coins = await self.select_coins(uint64(1))
coins = await self.select_coins(uint64(1), tx_config.coin_selection_config)
assert coins is not None
coin = coins.pop()
new_inner_puzzle = await self.get_new_did_innerpuz()
@ -625,7 +618,7 @@ class DIDWallet:
if fee > 0:
announcement_to_make = coin.name()
chia_tx = await self.standard_wallet.create_tandem_xch_tx(
fee, Announcement(coin.name(), announcement_to_make), reuse_puzhash=reuse_puzhash
fee, tx_config, Announcement(coin.name(), announcement_to_make)
)
else:
announcement_to_make = None
@ -661,7 +654,7 @@ class DIDWallet:
new_puzhash: bytes32,
fee: uint64,
with_recovery: bool,
reuse_puzhash: Optional[bool] = None,
tx_config: TXConfig,
) -> TransactionRecord:
"""
Transfer the current DID to another owner
@ -672,7 +665,7 @@ class DIDWallet:
"""
assert self.did_info.current_inner is not None
assert self.did_info.origin_coin is not None
coins = await self.select_coins(uint64(1))
coins = await self.select_coins(uint64(1), tx_config.coin_selection_config)
assert coins is not None
coin = coins.pop()
backup_ids = []
@ -722,7 +715,7 @@ class DIDWallet:
if fee > 0:
announcement_to_make = coin.name()
chia_tx = await self.standard_wallet.create_tandem_xch_tx(
fee, Announcement(coin.name(), announcement_to_make), reuse_puzhash=reuse_puzhash
fee, tx_config, Announcement(coin.name(), announcement_to_make)
)
else:
chia_tx = None
@ -754,6 +747,7 @@ class DIDWallet:
# The message spend can tests\wallet\rpc\test_wallet_rpc.py send messages and also change your innerpuz
async def create_message_spend(
self,
tx_config: TXConfig,
coin_announcements: Optional[Set[bytes]] = None,
puzzle_announcements: Optional[Set[bytes]] = None,
coin_announcements_to_assert: Optional[Set[Announcement]] = None,
@ -762,7 +756,7 @@ class DIDWallet:
):
assert self.did_info.current_inner is not None
assert self.did_info.origin_coin is not None
coins = await self.select_coins(uint64(1))
coins = await self.select_coins(uint64(1), tx_config.coin_selection_config)
assert coins is not None
coin = coins.pop()
innerpuz: Program = self.did_info.current_inner
@ -809,10 +803,10 @@ class DIDWallet:
return await self.sign(unsigned_spend_bundle)
# This is used to cash out, or update the id_list
async def create_exit_spend(self, puzhash: bytes32):
async def create_exit_spend(self, puzhash: bytes32, tx_config: TXConfig):
assert self.did_info.current_inner is not None
assert self.did_info.origin_coin is not None
coins = await self.select_coins(uint64(1))
coins = await self.select_coins(uint64(1), tx_config.coin_selection_config)
assert coins is not None
coin = coins.pop()
message_puz = Program.to((1, [[51, puzhash, coin.amount - 1, [puzhash]], [51, 0x00, -113]]))
@ -867,7 +861,7 @@ class DIDWallet:
# Pushes a SpendBundle to create a message coin on the blockchain
# Returns a SpendBundle for the recoverer to spend the message coin
async def create_attestment(
self, recovering_coin_name: bytes32, newpuz: bytes32, pubkey: G1Element
self, recovering_coin_name: bytes32, newpuz: bytes32, pubkey: G1Element, tx_config: TXConfig
) -> Tuple[SpendBundle, str]:
"""
Create an attestment
@ -878,7 +872,7 @@ class DIDWallet:
"""
assert self.did_info.current_inner is not None
assert self.did_info.origin_coin is not None
coins = await self.select_coins(uint64(1))
coins = await self.select_coins(uint64(1), tx_config.coin_selection_config)
assert coins is not None and coins != set()
coin = coins.pop()
message = did_wallet_puzzles.create_recovery_message_puzzle(recovering_coin_name, newpuz, pubkey)
@ -943,10 +937,12 @@ class DIDWallet:
await self.wallet_state_manager.add_pending_transaction(did_record)
return message_spend_bundle, attest_str
async def get_info_for_recovery(self) -> Optional[Tuple[bytes32, bytes32, uint64]]:
async def get_info_for_recovery(
self, coin_selection_config: CoinSelectionConfig
) -> Optional[Tuple[bytes32, bytes32, uint64]]:
assert self.did_info.current_inner is not None
assert self.did_info.origin_coin is not None
coins = await self.select_coins(uint64(1))
coins = await self.select_coins(uint64(1), coin_selection_config)
if coins is not None:
coin = coins.pop()
parent = coin.parent_coin_info
@ -1213,12 +1209,14 @@ class DIDWallet:
agg_sig = AugSchemeMPL.aggregate(sigs)
return SpendBundle.aggregate([spend_bundle, SpendBundle([], agg_sig)])
async def generate_new_decentralised_id(self, amount: uint64, fee: uint64 = uint64(0)) -> Optional[SpendBundle]:
async def generate_new_decentralised_id(
self, amount: uint64, tx_config: TXConfig, fee: uint64 = uint64(0)
) -> Optional[SpendBundle]:
"""
This must be called under the wallet state manager lock
"""
coins = await self.standard_wallet.select_coins(uint64(amount + fee))
coins = await self.standard_wallet.select_coins(uint64(amount + fee), tx_config.coin_selection_config)
if coins is None:
return None
@ -1238,6 +1236,7 @@ class DIDWallet:
tx_record: Optional[TransactionRecord] = await self.standard_wallet.generate_signed_transaction(
amount,
genesis_launcher_puz.get_tree_hash(),
tx_config,
fee,
coins,
None,

View File

@ -51,6 +51,7 @@ from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.uncurried_puzzle import uncurry_puzzle
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import CoinSelectionConfig, TXConfig
from chia.wallet.util.wallet_sync_utils import fetch_coin_spend
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet import CHIP_0002_SIGN_MESSAGE_PREFIX, Wallet
@ -311,6 +312,7 @@ class NFTWallet:
async def get_did_approval_info(
self,
nft_ids: List[bytes32],
tx_config: TXConfig,
did_id: Optional[bytes32] = None,
) -> Tuple[bytes32, SpendBundle]:
"""Get DID spend with announcement created we need to transfer NFT with did with current inner hash of DID
@ -326,7 +328,7 @@ class NFTWallet:
self.log.debug("Found a DID wallet, checking did: %r == %r", wallet.get_my_DID(), did_id)
if bytes32.fromhex(wallet.get_my_DID()) == did_id:
self.log.debug("Creating announcement from DID for nft_ids: %s", nft_ids)
did_bundle = await wallet.create_message_spend(puzzle_announcements=nft_ids)
did_bundle = await wallet.create_message_spend(tx_config, puzzle_announcements=nft_ids)
self.log.debug("Sending DID announcement from puzzle: %s", did_bundle.removals())
did_inner_hash = wallet.did_info.current_inner.get_tree_hash()
break
@ -337,13 +339,13 @@ class NFTWallet:
async def generate_new_nft(
self,
metadata: Program,
tx_config: TXConfig,
target_puzzle_hash: Optional[bytes32] = None,
royalty_puzzle_hash: Optional[bytes32] = None,
percentage: uint16 = uint16(0),
did_id: Optional[bytes] = None,
fee: uint64 = uint64(0),
push_tx: bool = True,
reuse_puzhash: Optional[bool] = None,
) -> Optional[SpendBundle]:
"""
This must be called under the wallet state manager lock
@ -357,7 +359,7 @@ class NFTWallet:
percentage = uint16(percentage)
except ValueError:
raise ValueError("Percentage must be lower than 655%")
coins = await self.standard_wallet.select_coins(uint64(amount + fee))
coins = await self.standard_wallet.select_coins(uint64(amount + fee), tx_config.coin_selection_config)
if coins is None:
return None
origin = coins.copy().pop()
@ -400,6 +402,7 @@ class NFTWallet:
tx_record: Optional[TransactionRecord] = await self.standard_wallet.generate_signed_transaction(
uint64(amount),
nft_puzzles.LAUNCHER_PUZZLE_HASH,
tx_config,
fee,
coins,
None,
@ -425,7 +428,7 @@ class NFTWallet:
did_inner_hash = b""
if did_id is not None:
if did_id != b"":
did_inner_hash, did_bundle = await self.get_did_approval_info([launcher_coin.name()])
did_inner_hash, did_bundle = await self.get_did_approval_info([launcher_coin.name()], tx_config)
bundles_to_agg.append(did_bundle)
nft_coin = NFTCoinInfo(
nft_id=launcher_coin.name(),
@ -439,12 +442,12 @@ class NFTWallet:
txs = await self.generate_signed_transaction(
[uint64(eve_coin.amount)],
[target_puzzle_hash],
tx_config,
nft_coin=nft_coin,
new_owner=did_id,
new_did_inner_hash=did_inner_hash,
additional_bundles=bundles_to_agg,
memos=[[target_puzzle_hash]],
reuse_puzhash=reuse_puzhash,
)
txs.append(dataclasses.replace(tx_record, spend_bundle=None))
if push_tx:
@ -495,8 +498,8 @@ class NFTWallet:
nft_coin_info: NFTCoinInfo,
key: str,
uri: str,
tx_config: TXConfig,
fee: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> Optional[SpendBundle]:
uncurried_nft = UncurriedNFT.uncurry(*nft_coin_info.full_puzzle.uncurry())
assert uncurried_nft is not None
@ -510,10 +513,10 @@ class NFTWallet:
txs = await self.generate_signed_transaction(
[uint64(nft_coin_info.coin.amount)],
[puzzle_hash],
tx_config,
fee,
{nft_coin_info.coin},
metadata_update=(key, uri),
reuse_puzhash=reuse_puzhash,
)
for tx in txs:
await self.wallet_state_manager.add_pending_transaction(tx)
@ -618,13 +621,13 @@ class NFTWallet:
self,
amounts: List[uint64],
puzzle_hashes: List[bytes32],
tx_config: TXConfig,
fee: uint64 = uint64(0),
coins: Optional[Set[Coin]] = None,
memos: Optional[List[List[bytes]]] = None,
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
ignore_max_send_amount: bool = False,
reuse_puzhash: Optional[bool] = None,
**kwargs: Unpack[GSTOptionalArgs],
) -> List[TransactionRecord]:
nft_coin: Optional[NFTCoinInfo] = kwargs.get("nft_coin", None)
@ -648,6 +651,7 @@ class NFTWallet:
payment_sum = sum([p.amount for p in payments])
unsigned_spend_bundle, chia_tx = await self.generate_unsigned_spendbundle(
payments,
tx_config,
fee,
coins=coins,
nft_coin=nft_coin,
@ -657,7 +661,6 @@ class NFTWallet:
new_did_inner_hash=new_did_inner_hash,
trade_prices_list=trade_prices_list,
metadata_update=metadata_update,
reuse_puzhash=reuse_puzhash,
)
spend_bundle = await self.sign(unsigned_spend_bundle)
spend_bundle = SpendBundle.aggregate([spend_bundle] + additional_bundles)
@ -694,6 +697,7 @@ class NFTWallet:
async def generate_unsigned_spendbundle(
self,
payments: List[Payment],
tx_config: TXConfig,
fee: uint64 = uint64(0),
coins: Optional[Set[Coin]] = None,
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
@ -703,7 +707,6 @@ class NFTWallet:
trade_prices_list: Optional[Program] = None,
metadata_update: Optional[Tuple[str, str]] = None,
nft_coin: Optional[NFTCoinInfo] = None,
reuse_puzhash: Optional[bool] = None,
) -> Tuple[SpendBundle, Optional[TransactionRecord]]:
if nft_coin is None:
if coins is None or not len(coins) == 1:
@ -727,7 +730,7 @@ class NFTWallet:
if fee > 0:
announcement_to_make = nft_coin.coin.name()
chia_tx = await self.standard_wallet.create_tandem_xch_tx(
fee, Announcement(nft_coin.coin.name(), announcement_to_make), reuse_puzhash=reuse_puzhash
fee, tx_config, Announcement(nft_coin.coin.name(), announcement_to_make)
)
else:
announcement_to_make = None
@ -797,9 +800,8 @@ class NFTWallet:
wallet_state_manager: Any,
offer_dict: Dict[Optional[bytes32], int],
driver_dict: Dict[bytes32, PuzzleInfo],
tx_config: TXConfig,
fee: uint64,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
old: bool = False,
) -> Offer:
DESIRED_OFFER_MOD = OFFER_MOD_OLD if old else OFFER_MOD
@ -903,7 +905,7 @@ class NFTWallet:
else:
coin_amount_needed = abs(amount) + royalty_amount
offered_coins: Set[Coin] = await wallet.get_coins_to_offer(
asset, coin_amount_needed, min_coin_amount, max_coin_amount
asset, coin_amount_needed, tx_config.coin_selection_config
)
if len(offered_coins) == 0:
raise ValueError(f"Did not have asset ID {asset.hex() if asset is not None else 'XCH'} to offer")
@ -950,6 +952,7 @@ class NFTWallet:
tx = await wallet.generate_signed_transaction(
abs(amount),
DESIRED_OFFER_MOD_HASH,
tx_config,
primaries=[Payment(DESIRED_OFFER_MOD_HASH, uint64(payment_sum))]
if payment_sum > 0 or old
else [],
@ -963,6 +966,7 @@ class NFTWallet:
txs = await wallet.generate_signed_transaction(
[abs(amount)],
[DESIRED_OFFER_MOD_HASH],
tx_config,
fee=fee_left_to_pay,
coins=offered_coins_by_asset[asset],
puzzle_announcements_to_consume=announcements_to_assert,
@ -977,6 +981,7 @@ class NFTWallet:
txs = await wallet.generate_signed_transaction(
[abs(amount), sum(p.amount for _, p in payments)],
[DESIRED_OFFER_MOD_HASH, DESIRED_OFFER_MOD_HASH],
tx_config,
fee=fee_left_to_pay,
coins=offered_coins_by_asset[asset],
puzzle_announcements_to_consume=announcements_to_assert,
@ -1097,9 +1102,9 @@ class NFTWallet:
self,
nft_list: List[NFTCoinInfo],
did_id: bytes,
tx_config: TXConfig,
fee: uint64 = uint64(0),
announcement_ids: List[bytes32] = [],
reuse_puzhash: Optional[bool] = None,
) -> List[TransactionRecord]:
self.log.debug("Setting NFT DID with parameters: nft=%s did=%s", nft_list, did_id)
did_inner_hash = b""
@ -1110,7 +1115,7 @@ class NFTWallet:
for nft_coin_info in nft_list:
nft_ids.append(nft_coin_info.nft_id)
if did_id != b"":
did_inner_hash, did_bundle = await self.get_did_approval_info(announcement_ids, bytes32(did_id))
did_inner_hash, did_bundle = await self.get_did_approval_info(announcement_ids, tx_config, bytes32(did_id))
if len(announcement_ids) > 0:
spend_bundles.append(did_bundle)
@ -1124,11 +1129,11 @@ class NFTWallet:
await self.generate_signed_transaction(
[uint64(nft_coin_info.coin.amount)],
puzzle_hashes_to_sign,
tx_config,
fee,
{nft_coin_info.coin},
new_owner=did_id,
new_did_inner_hash=did_inner_hash,
reuse_puzhash=reuse_puzhash,
)
)
first = False
@ -1149,8 +1154,8 @@ class NFTWallet:
self,
nft_list: List[NFTCoinInfo],
puzzle_hash: bytes32,
tx_config: TXConfig,
fee: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> List[TransactionRecord]:
self.log.debug("Transfer NFTs %s to %s", nft_list, puzzle_hash.hex())
nft_tx_record = []
@ -1164,11 +1169,11 @@ class NFTWallet:
await self.generate_signed_transaction(
[uint64(nft_coin_info.coin.amount)],
[puzzle_hash],
tx_config,
coins={nft_coin_info.coin},
fee=fee,
new_owner=b"",
new_did_inner_hash=b"",
reuse_puzhash=reuse_puzhash,
)
)
first = False
@ -1188,8 +1193,8 @@ class NFTWallet:
self,
nft_coin_info: NFTCoinInfo,
did_id: bytes,
tx_config: TXConfig,
fee: uint64 = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> SpendBundle:
self.log.debug("Setting NFT DID with parameters: nft=%s did=%s", nft_coin_info, did_id)
unft = UncurriedNFT.uncurry(*nft_coin_info.full_puzzle.uncurry())
@ -1199,18 +1204,18 @@ class NFTWallet:
did_inner_hash = b""
additional_bundles = []
if did_id != b"":
did_inner_hash, did_bundle = await self.get_did_approval_info([nft_id], bytes32(did_id))
did_inner_hash, did_bundle = await self.get_did_approval_info([nft_id], tx_config, bytes32(did_id))
additional_bundles.append(did_bundle)
nft_tx_record = await self.generate_signed_transaction(
[uint64(nft_coin_info.coin.amount)],
puzzle_hashes_to_sign,
tx_config,
fee,
{nft_coin_info.coin},
new_owner=did_id,
new_did_inner_hash=did_inner_hash,
additional_bundles=additional_bundles,
reuse_puzhash=reuse_puzhash,
)
spend_bundle = SpendBundle.aggregate([x.spend_bundle for x in nft_tx_record if x.spend_bundle is not None])
if spend_bundle:
@ -1225,6 +1230,7 @@ class NFTWallet:
async def mint_from_did(
self,
metadata_list: List[Dict[str, Any]],
tx_config: TXConfig,
target_list: Optional[List[bytes32]] = [],
mint_number_start: Optional[int] = 1,
mint_total: Optional[int] = None,
@ -1235,7 +1241,6 @@ class NFTWallet:
did_coin: Optional[Coin] = None,
did_lineage_parent: Optional[bytes32] = None,
fee: Optional[uint64] = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> SpendBundle:
"""
Minting NFTs from the DID linked wallet, also used for bulk minting NFTs.
@ -1287,7 +1292,7 @@ class NFTWallet:
# Ensure we have a did coin and its next inner puzzle hash
if did_coin is None:
coins = await did_wallet.select_coins(uint64(1))
coins = await did_wallet.select_coins(uint64(1), tx_config.coin_selection_config)
assert coins is not None
did_coin = coins.pop()
innerpuz: Program = did_wallet.did_info.current_inner
@ -1305,7 +1310,7 @@ class NFTWallet:
assert isinstance(fee, uint64)
total_amount = len(metadata_list) + fee
if xch_coins is None:
xch_coins = await self.standard_wallet.select_coins(uint64(total_amount))
xch_coins = await self.standard_wallet.select_coins(uint64(total_amount), tx_config.coin_selection_config)
assert len(xch_coins) > 0
# set the chunk size for the spend bundle we're going to create
@ -1407,12 +1412,12 @@ class NFTWallet:
eve_txs = await self.generate_signed_transaction(
[uint64(eve_coin.amount)],
[target_ph],
tx_config,
nft_coin=nft_coin,
new_owner=b"",
new_did_inner_hash=b"",
additional_bundles=[],
memos=[[target_ph]],
reuse_puzhash=reuse_puzhash,
)
eve_sb = eve_txs[0].spend_bundle
assert eve_sb is not None
@ -1512,13 +1517,13 @@ class NFTWallet:
async def mint_from_xch(
self,
metadata_list: List[Dict[str, Any]],
tx_config: TXConfig,
target_list: Optional[List[bytes32]] = [],
mint_number_start: Optional[int] = 1,
mint_total: Optional[int] = None,
xch_coins: Optional[Set[Coin]] = None,
xch_change_ph: Optional[bytes32] = None,
fee: Optional[uint64] = uint64(0),
reuse_puzhash: Optional[bool] = None,
) -> SpendBundle:
"""
Minting NFTs from a single XCH spend using intermediate launcher puzzle
@ -1544,7 +1549,7 @@ class NFTWallet:
assert isinstance(fee, uint64)
total_amount = len(metadata_list) + fee
if xch_coins is None:
xch_coins = await self.standard_wallet.select_coins(uint64(total_amount))
xch_coins = await self.standard_wallet.select_coins(uint64(total_amount), tx_config.coin_selection_config)
assert len(xch_coins) > 0
funding_coin = xch_coins.copy().pop()
@ -1644,12 +1649,12 @@ class NFTWallet:
eve_txs = await self.generate_signed_transaction(
[uint64(eve_coin.amount)],
[target_ph],
tx_config,
nft_coin=nft_coin,
new_owner=b"",
new_did_inner_hash=b"",
additional_bundles=[],
memos=[[target_ph]],
reuse_puzhash=reuse_puzhash,
)
eve_sb = eve_txs[0].spend_bundle
assert eve_sb is not None
@ -1712,10 +1717,7 @@ class NFTWallet:
async def select_coins(
self,
amount: uint64,
exclude: Optional[List[Coin]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
coin_selection_config: CoinSelectionConfig,
) -> Set[Coin]:
raise RuntimeError("NFTWallet does not support select_coins()")

View File

@ -19,6 +19,7 @@ from chia.wallet.notification_store import Notification, NotificationStore
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.compute_memos import compute_memos_for_spend
from chia.wallet.util.notifications import construct_notification
from chia.wallet.util.tx_config import TXConfig
from chia.wallet.util.wallet_types import WalletType
@ -82,9 +83,11 @@ class NotificationManager:
return True
async def send_new_notification(
self, target: bytes32, msg: bytes, amount: uint64, fee: uint64 = uint64(0)
self, target: bytes32, msg: bytes, amount: uint64, tx_config: TXConfig, fee: uint64 = uint64(0)
) -> TransactionRecord:
coins: Set[Coin] = await self.wallet_state_manager.main_wallet.select_coins(uint64(amount + fee))
coins: Set[Coin] = await self.wallet_state_manager.main_wallet.select_coins(
uint64(amount + fee), tx_config.coin_selection_config
)
origin_coin: bytes32 = next(iter(coins)).name()
notification_puzzle: Program = construct_notification(target, amount)
notification_hash: bytes32 = notification_puzzle.get_tree_hash()
@ -98,6 +101,7 @@ class NotificationManager:
chia_tx = await self.wallet_state_manager.main_wallet.generate_signed_transaction(
amount,
notification_hash,
tx_config,
fee,
coins=coins,
origin_id=origin_coin,

View File

@ -19,6 +19,7 @@ from chia.wallet.lineage_proof import LineageProof
from chia.wallet.payment import Payment
from chia.wallet.puzzles.load_clvm import load_clvm_maybe_recompile
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.tx_config import TXConfig
GENESIS_BY_ID_MOD = load_clvm_maybe_recompile("genesis_by_coin_id.clsp")
GENESIS_BY_PUZHASH_MOD = load_clvm_maybe_recompile("genesis_by_puzzle_hash.clsp")
@ -41,7 +42,7 @@ class LimitationsProgram:
@classmethod
async def generate_issuance_bundle(
cls, wallet, cat_tail_info: Dict, amount: uint64
cls, wallet, cat_tail_info: Dict, amount: uint64, tx_config: TXConfig
) -> Tuple[TransactionRecord, SpendBundle]:
raise NotImplementedError("Need to implement 'generate_issuance_bundle' on limitations programs")
@ -69,8 +70,10 @@ class GenesisById(LimitationsProgram):
return Program.to([])
@classmethod
async def generate_issuance_bundle(cls, wallet, _: Dict, amount: uint64) -> Tuple[TransactionRecord, SpendBundle]:
coins = await wallet.standard_wallet.select_coins(amount)
async def generate_issuance_bundle(
cls, wallet, _: Dict, amount: uint64, tx_config: TXConfig
) -> Tuple[TransactionRecord, SpendBundle]:
coins = await wallet.standard_wallet.select_coins(amount, tx_config.coin_selection_config)
origin = coins.copy().pop()
origin_id = origin.name()
@ -86,7 +89,7 @@ class GenesisById(LimitationsProgram):
minted_cat_puzzle_hash: bytes32 = construct_cat_puzzle(CAT_MOD, tail.get_tree_hash(), cat_inner).get_tree_hash()
tx_record: TransactionRecord = await wallet.standard_wallet.generate_signed_transaction(
amount, minted_cat_puzzle_hash, uint64(0), coins, origin_id=origin_id
amount, minted_cat_puzzle_hash, tx_config, uint64(0), coins, origin_id=origin_id
)
assert tx_record.spend_bundle is not None

View File

@ -30,6 +30,7 @@ from chia.wallet.trading.trade_store import TradeStore
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.query_filter import HashFilter
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import TXConfig
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet import Wallet
from chia.wallet.wallet_coin_record import WalletCoinRecord
@ -221,7 +222,7 @@ class TradeManager:
self.wallet_state_manager.state_changed("offer_failed")
async def cancel_pending_offer_safely(
self, trade_id: bytes32, fee: uint64 = uint64(0)
self, trade_id: bytes32, tx_config: TXConfig, fee: uint64 = uint64(0)
) -> Optional[List[TransactionRecord]]:
"""This will create a transaction that includes coins that were offered"""
self.log.info(f"Secure-Cancel pending offer with id trade_id {trade_id.hex()}")
@ -246,7 +247,10 @@ class TradeManager:
if fee_to_pay > coin.amount:
selected_coins: Set[Coin] = await wallet.select_coins(
uint64(fee_to_pay - coin.amount),
exclude=[coin],
dataclasses.replace(
tx_config.coin_selection_config,
exculded_coin_ids=[*tx_config.coin_selection_config.excluded_coin_ids, coin.name()],
),
)
selected_coins.add(coin)
else:
@ -254,6 +258,12 @@ class TradeManager:
tx = await wallet.generate_signed_transaction(
uint64(sum([c.amount for c in selected_coins]) - fee_to_pay),
new_ph,
dataclasses.replace(
tx_config,
coin_selection_config=dataclasses.replace(
tx_config.coin_selection_config, excluded_coin_ids=[]
),
),
fee=fee_to_pay,
coins=selected_coins,
ignore_max_send_amount=True,
@ -262,7 +272,17 @@ class TradeManager:
else:
# ATTENTION: new_wallets
txs = await wallet.generate_signed_transaction(
[coin.amount], [new_ph], fee=fee_to_pay, coins={coin}, ignore_max_send_amount=True
[coin.amount],
[new_ph],
dataclasses.replace(
tx_config,
coin_selection_config=dataclasses.replace(
tx_config.coin_selection_config, excluded_coin_ids=[]
),
),
fee=fee_to_pay,
coins={coin},
ignore_max_send_amount=True,
)
all_txs.extend(txs)
fee_to_pay = uint64(0)
@ -297,7 +317,7 @@ class TradeManager:
return all_txs
async def cancel_pending_offers(
self, trades: List[TradeRecord], fee: uint64 = uint64(0), secure: bool = True
self, trades: List[TradeRecord], tx_config: TXConfig, fee: uint64 = uint64(0), secure: bool = True
) -> Optional[List[TransactionRecord]]:
"""This will create a transaction that includes coins that were offered"""
@ -325,7 +345,10 @@ class TradeManager:
if fee_to_pay > coin.amount:
selected_coins: Set[Coin] = await wallet.select_coins(
uint64(fee_to_pay - coin.amount),
exclude=[coin],
dataclasses.replace(
tx_config.coin_selection_config,
exculded_coin_ids=[*tx_config.coin_selection_config.excluded_coin_ids, coin.name()],
),
)
selected_coins.add(coin)
else:
@ -333,6 +356,12 @@ class TradeManager:
tx: TransactionRecord = await wallet.generate_signed_transaction(
uint64(sum([c.amount for c in selected_coins]) - fee_to_pay),
new_ph,
dataclasses.replace(
tx_config,
coin_selection_config=dataclasses.replace(
tx_config.coin_selection_config, excluded_coin_ids=[]
),
),
fee=fee_to_pay,
coins=selected_coins,
ignore_max_send_amount=True,
@ -343,7 +372,17 @@ class TradeManager:
else:
# ATTENTION: new_wallets
txs = await wallet.generate_signed_transaction(
[coin.amount], [new_ph], fee=fee_to_pay, coins={coin}, ignore_max_send_amount=True
[coin.amount],
[new_ph],
dataclasses.replace(
tx_config,
coin_selection_config=dataclasses.replace(
tx_config.coin_selection_config, excluded_coin_ids=[]
),
),
fee=fee_to_pay,
coins={coin},
ignore_max_send_amount=True,
)
for tx in txs:
if tx is not None and tx.spend_bundle is not None:
@ -406,13 +445,11 @@ class TradeManager:
async def create_offer_for_ids(
self,
offer: Dict[Union[int, bytes32], int],
tx_config: TXConfig,
driver_dict: Optional[Dict[bytes32, PuzzleInfo]] = None,
solver: Optional[Solver] = None,
fee: uint64 = uint64(0),
validate_only: bool = False,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
reuse_puzhash: Optional[bool] = None,
) -> Union[Tuple[Literal[True], TradeRecord, None], Tuple[Literal[False], None, str]]:
if driver_dict is None:
driver_dict = {}
@ -420,12 +457,10 @@ class TradeManager:
solver = Solver({})
result = await self._create_offer_for_ids(
offer,
tx_config,
driver_dict,
solver,
fee=fee,
min_coin_amount=min_coin_amount,
max_coin_amount=max_coin_amount,
reuse_puzhash=reuse_puzhash,
)
if not result[0] or result[1] is None:
raise Exception(f"Error creating offer: {result[2]}")
@ -455,13 +490,11 @@ class TradeManager:
async def _create_offer_for_ids(
self,
offer_dict: Dict[Union[int, bytes32], int],
tx_config: TXConfig,
driver_dict: Optional[Dict[bytes32, PuzzleInfo]] = None,
solver: Optional[Solver] = None,
fee: uint64 = uint64(0),
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
old: bool = False,
reuse_puzhash: Optional[bool] = None,
) -> Union[Tuple[Literal[True], Offer, None], Tuple[Literal[False], None, str]]:
"""
Offer is dictionary of wallet ids and amount
@ -470,14 +503,6 @@ class TradeManager:
driver_dict = {}
if solver is None:
solver = Solver({})
if reuse_puzhash is None:
reuse_puzhash_config = self.wallet_state_manager.config.get("reuse_public_key_for_change", None)
if reuse_puzhash_config is None:
reuse_puzhash = False
else:
reuse_puzhash = reuse_puzhash_config.get(
str(self.wallet_state_manager.wallet_node.logged_in_fingerprint), False
)
try:
coins_to_offer: Dict[Union[int, bytes32], List[Coin]] = {}
requested_payments: Dict[Optional[bytes32], List[Payment]] = {}
@ -492,7 +517,7 @@ class TradeManager:
if isinstance(id, int):
wallet_id = uint32(id)
wallet = self.wallet_state_manager.wallets[wallet_id]
p2_ph: bytes32 = await wallet.get_puzzle_hash(new=not reuse_puzhash)
p2_ph: bytes32 = await wallet.get_puzzle_hash(new=not tx_config.reuse_puzhash)
if wallet.type() != WalletType.STANDARD_WALLET:
if callable(getattr(wallet, "get_asset_id", None)): # ATTENTION: new wallets
asset_id = bytes32(bytes.fromhex(wallet.get_asset_id()))
@ -502,7 +527,9 @@ class TradeManager:
f"Cannot request assets from wallet id {wallet.id()} without more information"
)
else:
p2_ph = await self.wallet_state_manager.main_wallet.get_puzzle_hash(new=not reuse_puzhash)
p2_ph = await self.wallet_state_manager.main_wallet.get_puzzle_hash(
new=not tx_config.reuse_puzhash
)
asset_id = id
wallet = await self.wallet_state_manager.get_wallet_for_asset_id(asset_id.hex())
memos = [p2_ph]
@ -529,7 +556,7 @@ class TradeManager:
if wallet.type() == WalletType.STANDARD_WALLET:
amount_to_select += fee
coins_to_offer[id] = await wallet.get_coins_to_offer(
asset_id, uint64(amount_to_select), min_coin_amount, max_coin_amount
asset_id, uint64(amount_to_select), tx_config.coin_selection_config
)
# Note: if we use check_for_special_offer_making, this is not used.
elif amount == 0:
@ -554,7 +581,7 @@ class TradeManager:
raise ValueError(f"Wallet for asset id {asset_id} is not properly integrated with TradeManager")
potential_special_offer: Optional[Offer] = await self.check_for_special_offer_making(
offer_dict_no_ints, driver_dict, solver, fee, min_coin_amount, max_coin_amount, old
offer_dict_no_ints, driver_dict, tx_config, solver, fee, old
)
if potential_special_offer is not None:
@ -581,10 +608,10 @@ class TradeManager:
tx = await wallet.generate_signed_transaction(
abs(offer_dict[id]),
OFFER_MOD_OLD_HASH if old else Offer.ph(),
tx_config,
fee=fee_left_to_pay,
coins=set(selected_coins),
puzzle_announcements_to_consume=announcements_to_assert,
reuse_puzhash=reuse_puzhash,
)
all_transactions.append(tx)
elif wallet.type() == WalletType.NFT:
@ -595,10 +622,10 @@ class TradeManager:
# [abs(offer_dict[id])],
amounts,
[OFFER_MOD_OLD_HASH if old else Offer.ph()],
tx_config,
fee=fee_left_to_pay,
coins=set(selected_coins),
puzzle_announcements_to_consume=announcements_to_assert,
reuse_puzhash=reuse_puzhash,
)
all_transactions.extend(txs)
else:
@ -606,10 +633,10 @@ class TradeManager:
txs = await wallet.generate_signed_transaction(
[abs(offer_dict[id])],
[OFFER_MOD_OLD_HASH if old else Offer.ph()],
tx_config,
fee=fee_left_to_pay,
coins=set(selected_coins),
puzzle_announcements_to_consume=announcements_to_assert,
reuse_puzhash=reuse_puzhash,
)
all_transactions.extend(txs)
@ -744,11 +771,9 @@ class TradeManager:
self,
offer: Offer,
peer: WSChiaConnection,
tx_config: TXConfig,
solver: Optional[Solver] = None,
fee: uint64 = uint64(0),
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
reuse_puzhash: Optional[bool] = None,
) -> Tuple[TradeRecord, List[TransactionRecord]]:
if solver is None:
solver = Solver({})
@ -776,13 +801,11 @@ class TradeManager:
raise ValueError("This offer is no longer valid")
result = await self._create_offer_for_ids(
take_offer_dict,
tx_config,
offer.driver_dict,
solver,
fee=fee,
min_coin_amount=min_coin_amount,
max_coin_amount=max_coin_amount,
old=offer.old,
reuse_puzhash=reuse_puzhash,
)
if not result[0] or result[1] is None:
raise ValueError(result[2])
@ -842,10 +865,9 @@ class TradeManager:
self,
offer_dict: Dict[Optional[bytes32], int],
driver_dict: Dict[bytes32, PuzzleInfo],
tx_config: TXConfig,
solver: Solver,
fee: uint64 = uint64(0),
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
old: bool = False,
) -> Optional[Offer]:
for puzzle_info in driver_dict.values():
@ -856,7 +878,7 @@ class TradeManager:
== AssetType.ROYALTY_TRANSFER_PROGRAM.value
):
return await NFTWallet.make_nft1_offer(
self.wallet_state_manager, offer_dict, driver_dict, fee, min_coin_amount, max_coin_amount, old
self.wallet_state_manager, offer_dict, driver_dict, tx_config, fee, old
)
elif (
puzzle_info.check_type(
@ -868,7 +890,7 @@ class TradeManager:
and puzzle_info.also()["updater_hash"] == ACS_MU_PH # type: ignore
):
return await DataLayerWallet.make_update_offer(
self.wallet_state_manager, offer_dict, driver_dict, solver, fee, old
self.wallet_state_manager, offer_dict, driver_dict, solver, tx_config, fee, old
)
return None

View File

@ -0,0 +1,121 @@
from __future__ import annotations
import dataclasses
from typing import Any, Dict, List, Optional, Type, TypeVar
from chia.consensus.constants import ConsensusConstants
from chia.consensus.default_constants import DEFAULT_CONSTANTS
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.util.ints import uint64
from chia.util.streamable import Streamable, streamable
@dataclasses.dataclass(frozen=True)
class CoinSelectionConfig:
min_coin_amount: uint64
max_coin_amount: uint64
excluded_coin_amounts: List[uint64]
excluded_coin_ids: List[bytes32]
def to_json_dict(self) -> Dict[str, Any]:
return CoinSelectionConfigLoader(
self.min_coin_amount,
self.max_coin_amount,
self.excluded_coin_amounts,
self.excluded_coin_ids,
).to_json_dict()
@dataclasses.dataclass(frozen=True)
class TXConfig:
coin_selection_config: CoinSelectionConfig
reuse_puzhash: bool
def to_json_dict(self) -> Dict[str, Any]:
return TXConfigLoader(
self.coin_selection_config.min_coin_amount,
self.coin_selection_config.max_coin_amount,
self.coin_selection_config.excluded_coin_amounts,
self.coin_selection_config.excluded_coin_ids,
self.reuse_puzhash,
).to_json_dict()
_T_CoinSelectionConfigLoader = TypeVar("_T_CoinSelectionConfigLoader", bound="CoinSelectionConfigLoader")
@streamable
@dataclasses.dataclass(frozen=True)
class CoinSelectionConfigLoader(Streamable):
min_coin_amount: Optional[uint64] = None
max_coin_amount: Optional[uint64] = None
excluded_coin_amounts: Optional[List[uint64]] = None
excluded_coin_ids: Optional[List[bytes32]] = None
def autofill(
self,
constants: ConsensusConstants,
) -> CoinSelectionConfig:
return CoinSelectionConfig(
min_coin_amount=uint64(0) if self.min_coin_amount is None else self.min_coin_amount,
max_coin_amount=uint64(constants.MAX_COIN_AMOUNT) if self.max_coin_amount is None else self.max_coin_amount,
excluded_coin_amounts=[] if self.excluded_coin_amounts is None else self.excluded_coin_amounts,
excluded_coin_ids=[] if self.excluded_coin_ids is None else self.excluded_coin_ids,
)
@classmethod
def from_json_dict(
cls: Type[_T_CoinSelectionConfigLoader], json_dict: Dict[str, Any]
) -> _T_CoinSelectionConfigLoader:
if "excluded_coins" in json_dict:
excluded_coins: List[Coin] = [Coin.from_json_dict(c) for c in json_dict["excluded_coins"]]
excluded_coin_ids: List[str] = [c.name().hex() for c in excluded_coins]
if "excluded_coin_ids" in json_dict:
json_dict["excluded_coin_ids"] = [*excluded_coin_ids, *json_dict["excluded_coin_ids"]]
json_dict["excluded_coin_ids"] = excluded_coin_ids
return super().from_json_dict(json_dict)
@streamable
@dataclasses.dataclass(frozen=True)
class TXConfigLoader(Streamable):
min_coin_amount: Optional[uint64] = None
max_coin_amount: Optional[uint64] = None
excluded_coin_amounts: Optional[List[uint64]] = None
excluded_coin_ids: Optional[List[bytes32]] = None
reuse_puzhash: Optional[bool] = None
def autofill(
self,
config: Dict[str, Any],
logged_in_fingerprint: int,
constants: ConsensusConstants,
) -> TXConfig:
if self.reuse_puzhash is None:
reuse_puzhash_config = config.get("reuse_public_key_for_change", None)
if reuse_puzhash_config is None:
reuse_puzhash = False
else:
reuse_puzhash = reuse_puzhash_config.get(str(logged_in_fingerprint), False)
else:
reuse_puzhash = self.reuse_puzhash
return TXConfig(
CoinSelectionConfig(
min_coin_amount=uint64(0) if self.min_coin_amount is None else self.min_coin_amount,
max_coin_amount=uint64(constants.MAX_COIN_AMOUNT)
if self.max_coin_amount is None
else self.max_coin_amount,
excluded_coin_amounts=[] if self.excluded_coin_amounts is None else self.excluded_coin_amounts,
excluded_coin_ids=[] if self.excluded_coin_ids is None else self.excluded_coin_ids,
),
reuse_puzhash=reuse_puzhash,
)
DEFAULT_COIN_SELECTION_CONFIG = CoinSelectionConfig(uint64(0), uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT), [], [])
DEFAULT_TX_CONFIG = TXConfig(
DEFAULT_COIN_SELECTION_CONFIG,
False,
)

View File

@ -24,6 +24,7 @@ from chia.wallet.sign_coin_spends import sign_coin_spends
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import CoinSelectionConfig, TXConfig
from chia.wallet.util.wallet_sync_utils import fetch_coin_spend_for_coin_state
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.vc_wallet.vc_drivers import VerifiedCredential
@ -138,6 +139,7 @@ class VCWallet:
async def launch_new_vc(
self,
provider_did: bytes32,
tx_config: TXConfig,
inner_puzzle_hash: Optional[bytes32] = None,
fee: uint64 = uint64(0),
) -> Tuple[VCRecord, List[TransactionRecord]]:
@ -157,11 +159,11 @@ class VCWallet:
if not found_did:
raise ValueError(f"You don't own the DID {provider_did.hex()}") # pragma: no cover
# Mint VC
coins = await self.standard_wallet.select_coins(uint64(1 + fee), min_coin_amount=uint64(1 + fee))
coins = await self.standard_wallet.select_coins(uint64(1 + fee), tx_config.coin_selection_config)
if len(coins) == 0:
raise ValueError("Cannot find a coin to mint the verified credential.") # pragma: no cover
if inner_puzzle_hash is None:
inner_puzzle_hash = await self.standard_wallet.get_puzzle_hash(new=False) # pragma: no cover
if inner_puzzle_hash is None: # pragma: no cover
inner_puzzle_hash = await self.standard_wallet.get_puzzle_hash(new=not tx_config.reuse_puzhash)
original_coin = coins.pop()
dpuz, coin_spends, vc = VerifiedCredential.launch(
original_coin,
@ -207,13 +209,13 @@ class VCWallet:
async def generate_signed_transaction(
self,
vc_id: bytes32,
tx_config: TXConfig,
fee: uint64 = uint64(0),
new_inner_puzhash: Optional[bytes32] = None,
coin_announcements: Optional[Set[bytes]] = None,
puzzle_announcements: Optional[Set[bytes]] = None,
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
reuse_puzhash: Optional[bool] = None,
**kwargs: Unpack[GSTOptionalArgs],
) -> List[TransactionRecord]:
new_proof_hash: Optional[bytes32] = kwargs.get(
@ -257,7 +259,7 @@ class VCWallet:
if fee > 0:
announcement_to_make = vc_record.vc.coin.name()
chia_tx = await self.wallet_state_manager.main_wallet.create_tandem_xch_tx(
fee, Announcement(vc_record.vc.coin.name(), announcement_to_make), reuse_puzhash=reuse_puzhash
fee, tx_config, Announcement(vc_record.vc.coin.name(), announcement_to_make)
)
if coin_announcements is None:
coin_announcements = set((announcement_to_make,))
@ -305,7 +307,9 @@ class VCWallet:
assert isinstance(wallet, DIDWallet)
if bytes32.fromhex(wallet.get_my_DID()) == vc_record.vc.proof_provider:
self.log.debug("Creating announcement from DID for vc: %s", vc_id.hex())
did_bundle = await wallet.create_message_spend(puzzle_announcements={bytes(did_announcement)})
did_bundle = await wallet.create_message_spend(
tx_config, puzzle_announcements={bytes(did_announcement)}
)
spend_bundles.append(did_bundle)
break
else:
@ -343,7 +347,11 @@ class VCWallet:
return tx_list
async def revoke_vc(
self, parent_id: bytes32, peer: WSChiaConnection, fee: uint64 = uint64(0), reuse_puzhash: Optional[bool] = None
self,
parent_id: bytes32,
peer: WSChiaConnection,
tx_config: TXConfig,
fee: uint64 = uint64(0),
) -> List[TransactionRecord]:
vc_coin_states: List[CoinState] = await self.wallet_state_manager.wallet_node.get_coin_state(
[parent_id], peer=peer
@ -365,17 +373,19 @@ class VCWallet:
else:
raise ValueError(f"You don't own the DID {vc.proof_provider.hex()}") # pragma: no cover
recovery_info: Optional[Tuple[bytes32, bytes32, uint64]] = await did_wallet.get_info_for_recovery()
recovery_info: Optional[Tuple[bytes32, bytes32, uint64]] = await did_wallet.get_info_for_recovery(
tx_config.coin_selection_config
)
if recovery_info is None:
raise RuntimeError("DID could not currently be accessed while trying to revoke VC") # pragma: no cover
_, provider_inner_puzhash, _ = recovery_info
# Generate spend specific nonce
coins = await did_wallet.select_coins(uint64(1))
coins = await did_wallet.select_coins(uint64(1), tx_config.coin_selection_config)
assert coins is not None
coins.add(vc.coin)
if fee > 0:
coins.update(await self.standard_wallet.select_coins(fee))
coins.update(await self.standard_wallet.select_coins(fee, tx_config.coin_selection_config))
sorted_coins: List[Coin] = sorted(coins, key=Coin.name)
sorted_coin_list: List[List[Union[bytes32, uint64]]] = [coin_as_list(c) for c in sorted_coins]
nonce: bytes32 = Program.to(sorted_coin_list).get_tree_hash()
@ -384,6 +394,7 @@ class VCWallet:
# Assemble final bundle
expected_did_announcement, vc_spend = vc.activate_backdoor(provider_inner_puzhash, announcement_nonce=nonce)
did_spend: SpendBundle = await did_wallet.create_message_spend(
tx_config,
puzzle_announcements={expected_did_announcement},
coin_announcements_to_assert={vc_announcement},
)
@ -408,7 +419,7 @@ class VCWallet:
)
if fee > 0:
chia_tx: TransactionRecord = await self.wallet_state_manager.main_wallet.create_tandem_xch_tx(
fee, vc_announcement, reuse_puzhash
fee, tx_config, vc_announcement
)
assert tx.spend_bundle is not None
assert chia_tx.spend_bundle is not None
@ -421,10 +432,7 @@ class VCWallet:
async def select_coins(
self,
amount: uint64,
exclude: Optional[List[Coin]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
coin_selection_config: CoinSelectionConfig,
) -> Set[Coin]:
raise RuntimeError("VCWallet does not support select_coins()") # pragma: no cover

View File

@ -44,6 +44,7 @@ from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.puzzle_decorator import PuzzleDecoratorManager
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG, CoinSelectionConfig, TXConfig
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet_coin_record import WalletCoinRecord
from chia.wallet.wallet_info import WalletInfo
@ -92,7 +93,11 @@ class Wallet:
if self.cost_of_single_tx is None:
coin = spendable[0].coin
tx = await self.generate_signed_transaction(
uint64(coin.amount), coin.puzzle_hash, coins={coin}, ignore_max_send_amount=True
uint64(coin.amount),
coin.puzzle_hash,
DEFAULT_TX_CONFIG,
coins={coin},
ignore_max_send_amount=True,
)
assert tx.spend_bundle is not None
program: BlockGenerator = simple_solution_generator(tx.spend_bundle)
@ -204,6 +209,19 @@ class Wallet:
await self.hack_populate_secret_key_for_puzzle_hash(puzzle.get_tree_hash())
return puzzle
async def get_puzzle(self, new: bool) -> Program:
if new:
return await self.get_new_puzzle()
else:
record: Optional[
DerivationRecord
] = await self.wallet_state_manager.get_current_derivation_record_for_wallet(self.id())
if record is None:
return await self.get_new_puzzle()
puzzle = puzzle_for_pk(record.pubkey)
await self.hack_populate_secret_key_for_puzzle_hash(puzzle.get_tree_hash())
return puzzle
async def get_puzzle_hash(self, new: bool) -> bytes32:
if new:
return await self.get_new_puzzlehash()
@ -213,6 +231,7 @@ class Wallet:
] = await self.wallet_state_manager.get_current_derivation_record_for_wallet(self.id())
if record is None:
return await self.get_new_puzzlehash()
await self.hack_populate_secret_key_for_puzzle_hash(record.puzzle_hash)
return record.puzzle_hash
async def get_new_puzzlehash(self) -> bytes32:
@ -261,10 +280,7 @@ class Wallet:
async def select_coins(
self,
amount: uint64,
exclude: Optional[List[Coin]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
coin_selection_config: CoinSelectionConfig,
) -> Set[Coin]:
"""
Returns a set of coins that can be used for generating a new transaction.
@ -280,18 +296,13 @@ class Wallet:
unconfirmed_removals: Dict[bytes32, Coin] = await self.wallet_state_manager.unconfirmed_removals_for_wallet(
self.id()
)
if max_coin_amount is None:
max_coin_amount = uint64(self.wallet_state_manager.constants.MAX_COIN_AMOUNT)
coins = await select_coins(
spendable_amount,
max_coin_amount,
coin_selection_config,
spendable_coins,
unconfirmed_removals,
self.log,
uint128(amount),
exclude,
min_coin_amount,
excluded_coin_amounts,
)
assert sum(c.amount for c in coins) >= amount
return coins
@ -300,6 +311,7 @@ class Wallet:
self,
amount: uint64,
newpuzzlehash: bytes32,
tx_config: TXConfig,
fee: uint64 = uint64(0),
origin_id: Optional[bytes32] = None,
coins: Optional[Set[Coin]] = None,
@ -309,12 +321,7 @@ class Wallet:
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
memos: Optional[List[bytes]] = None,
negative_change_allowed: bool = False,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
excluded_coins: Optional[Set[Coin]] = None,
puzzle_decorator_override: Optional[List[Dict[str, Any]]] = None,
reuse_puzhash: Optional[bool] = None,
) -> List[CoinSpend]:
"""
Generates a unsigned transaction in form of List(Puzzle, Solutions)
@ -329,15 +336,6 @@ class Wallet:
primaries.extend(primaries_input)
total_amount = amount + sum(primary.amount for primary in primaries) + fee
if reuse_puzhash is None:
reuse_puzhash_config = self.wallet_state_manager.config.get("reuse_public_key_for_change", None)
if reuse_puzhash_config is None:
reuse_puzhash = False
else:
reuse_puzhash = reuse_puzhash_config.get(
str(self.wallet_state_manager.wallet_node.logged_in_fingerprint), False
)
total_balance = await self.get_spendable_balance()
if not ignore_max_send_amount:
max_send = await self.get_max_send_amount()
@ -349,18 +347,10 @@ class Wallet:
raise ValueError(
f"Can't spend more than wallet balance: {total_balance} mojos, tried to spend: {total_amount} mojos"
)
excluded_coins_list: Optional[List[Coin]] = None
if excluded_coins is not None:
excluded_coins_list = list(excluded_coins)
coins = await self.select_coins(
uint64(total_amount),
min_coin_amount=min_coin_amount,
max_coin_amount=max_coin_amount,
excluded_coin_amounts=excluded_coin_amounts,
exclude=excluded_coins_list,
tx_config.coin_selection_config,
)
elif excluded_coins is not None:
raise ValueError("Can't exclude coins when also specifically including coins")
assert len(coins) > 0
self.log.info(f"coins is not None {coins}")
@ -406,7 +396,7 @@ class Wallet:
target_primary.append(Payment(newpuzzlehash, amount, memos))
if change > 0:
if reuse_puzhash:
if tx_config.reuse_puzhash:
change_puzzle_hash: bytes32 = coin.puzzle_hash
for primary in primaries:
if change_puzzle_hash == primary.puzzle_hash and change == primary.amount:
@ -484,6 +474,7 @@ class Wallet:
self,
amount: uint64,
puzzle_hash: bytes32,
tx_config: TXConfig,
fee: uint64 = uint64(0),
coins: Optional[Set[Coin]] = None,
primaries: Optional[List[Payment]] = None,
@ -491,12 +482,7 @@ class Wallet:
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
memos: Optional[List[bytes]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
excluded_coins: Optional[Set[Coin]] = None,
puzzle_decorator_override: Optional[List[Dict[str, Any]]] = None,
reuse_puzhash: Optional[bool] = None,
**kwargs: Unpack[GSTOptionalArgs],
) -> TransactionRecord:
origin_id: Optional[bytes32] = kwargs.get("origin_id", None)
@ -515,6 +501,7 @@ class Wallet:
transaction = await self._generate_unsigned_transaction(
amount,
puzzle_hash,
tx_config,
fee,
origin_id,
coins,
@ -524,12 +511,7 @@ class Wallet:
puzzle_announcements_to_consume,
memos,
negative_change_allowed,
min_coin_amount=min_coin_amount,
max_coin_amount=max_coin_amount,
excluded_coin_amounts=excluded_coin_amounts,
excluded_coins=excluded_coins,
puzzle_decorator_override=puzzle_decorator_override,
reuse_puzhash=reuse_puzhash,
)
assert len(transaction) > 0
self.log.info("About to sign a transaction: %s", transaction)
@ -574,25 +556,17 @@ class Wallet:
async def create_tandem_xch_tx(
self,
fee: uint64,
tx_config: TXConfig,
announcement_to_assert: Optional[Announcement] = None,
reuse_puzhash: Optional[bool] = None,
) -> TransactionRecord:
chia_coins = await self.select_coins(fee)
if reuse_puzhash is None:
reuse_puzhash_config = self.wallet_state_manager.config.get("reuse_public_key_for_change", None)
if reuse_puzhash_config is None:
reuse_puzhash = False
else:
reuse_puzhash = reuse_puzhash_config.get(
str(self.wallet_state_manager.wallet_node.logged_in_fingerprint), False
)
chia_coins = await self.select_coins(fee, tx_config.coin_selection_config)
chia_tx = await self.generate_signed_transaction(
uint64(0),
(await self.get_puzzle_hash(not reuse_puzhash)),
(await self.get_puzzle_hash(not tx_config.reuse_puzhash)),
tx_config,
fee=fee,
coins=chia_coins,
coin_announcements_to_consume={announcement_to_assert} if announcement_to_assert is not None else None,
reuse_puzhash=reuse_puzhash,
)
assert chia_tx.spend_bundle is not None
return chia_tx
@ -606,15 +580,14 @@ class Wallet:
self,
asset_id: Optional[bytes32],
amount: uint64,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
coin_selection_config: CoinSelectionConfig,
) -> Set[Coin]:
if asset_id is not None:
raise ValueError(f"The standard wallet cannot offer coins with asset id {asset_id}")
balance = await self.get_spendable_balance()
if balance < amount:
raise Exception(f"insufficient funds in wallet {self.id()}")
return await self.select_coins(amount, min_coin_amount=min_coin_amount, max_coin_amount=max_coin_amount)
return await self.select_coins(amount, coin_selection_config)
# WSChiaConnection is only imported for type checking
async def coin_added(

View File

@ -12,6 +12,7 @@ from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.spend_bundle import SpendBundle
from chia.util.ints import uint32, uint64, uint128
from chia.wallet.nft_wallet.nft_info import NFTCoinInfo
from chia.wallet.util.tx_config import CoinSelectionConfig
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet_coin_record import WalletCoinRecord
from chia.wallet.wallet_info import WalletInfo
@ -34,10 +35,7 @@ class WalletProtocol(Protocol):
async def select_coins(
self,
amount: uint64,
exclude: Optional[List[Coin]] = None,
min_coin_amount: Optional[uint64] = None,
max_coin_amount: Optional[uint64] = None,
excluded_coin_amounts: Optional[List[uint64]] = None,
coin_selection_config: CoinSelectionConfig,
) -> Set[Coin]:
...
@ -81,7 +79,6 @@ class GSTOptionalArgs(TypedDict):
add_pending_singleton: NotRequired[bool]
announce_new_state: NotRequired[bool]
# CATWallet
excluded_cat_coins: NotRequired[Optional[Set[Coin]]]
cat_discrepancy: NotRequired[Optional[Tuple[int, Program, Program]]]
# NFTWallet
nft_coin: NotRequired[Optional[NFTCoinInfo]]

View File

@ -1,6 +1,7 @@
from __future__ import annotations
import asyncio
import dataclasses
import logging
import multiprocessing.context
import time
@ -82,6 +83,7 @@ from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.puzzle_decorator import PuzzleDecoratorManager
from chia.wallet.util.query_filter import HashFilter
from chia.wallet.util.transaction_type import CLAWBACK_TRANSACTION_TYPES, TransactionType
from chia.wallet.util.tx_config import TXConfig, TXConfigLoader
from chia.wallet.util.wallet_sync_utils import (
PeerRequestException,
fetch_coin_spend_for_coin_state,
@ -709,12 +711,26 @@ class WalletStateManager:
current_timestamp = self.blockchain.get_latest_timestamp()
clawback_coins: Dict[Coin, ClawbackMetadata] = {}
tx_fee = uint64(self.config.get("auto_claim", {}).get("tx_fee", 0))
min_amount = uint64(self.config.get("auto_claim", {}).get("min_amount", 0))
assert self.wallet_node.logged_in_fingerprint is not None
tx_config_loader: TXConfigLoader = TXConfigLoader.from_json_dict(self.config.get("auto_claim", {}))
tx_config: TXConfig = tx_config_loader.autofill(
self.config,
self.wallet_node.logged_in_fingerprint,
self.constants,
)
if tx_config_loader.min_coin_amount is None:
tx_config_loader = dataclasses.replace(
tx_config_loader,
min_coin_amount=self.config.get("auto_claim", {}).get("min_amount"),
)
unspent_coins = await self.coin_store.get_coin_records(
coin_type=CoinType.CLAWBACK,
wallet_type=WalletType.STANDARD_WALLET,
spent_range=UInt32Range(stop=uint32(0)),
amount_range=UInt64Range(start=uint64(min_amount)),
amount_range=UInt64Range(
start=tx_config.coin_selection_config.min_coin_amount,
stop=tx_config.coin_selection_config.max_coin_amount,
),
)
for coin in unspent_coins.records:
try:
@ -724,14 +740,16 @@ class WalletStateManager:
if current_timestamp - coin_timestamp >= metadata.time_lock:
clawback_coins[coin.coin] = metadata
if len(clawback_coins) >= self.config.get("auto_claim", {}).get("batch_size", 50):
await self.spend_clawback_coins(clawback_coins, tx_fee)
await self.spend_clawback_coins(clawback_coins, tx_fee, tx_config)
clawback_coins = {}
except Exception as e:
self.log.error(f"Failed to claim clawback coin {coin.coin.name().hex()}: %s", e)
if len(clawback_coins) > 0:
await self.spend_clawback_coins(clawback_coins, tx_fee)
await self.spend_clawback_coins(clawback_coins, tx_fee, tx_config)
async def spend_clawback_coins(self, clawback_coins: Dict[Coin, ClawbackMetadata], fee: uint64) -> List[bytes32]:
async def spend_clawback_coins(
self, clawback_coins: Dict[Coin, ClawbackMetadata], fee: uint64, tx_config: TXConfig
) -> List[bytes32]:
assert len(clawback_coins) > 0
coin_spends: List[CoinSpend] = []
message: bytes32 = std_hash(b"".join([c.name() for c in clawback_coins.keys()]))
@ -783,7 +801,7 @@ class WalletStateManager:
spend_bundle: SpendBundle = await self.main_wallet.sign_transaction(coin_spends)
if fee > 0:
chia_tx = await self.main_wallet.create_tandem_xch_tx(
fee, Announcement(coin_spends[0].coin.name(), message)
fee, tx_config, Announcement(coin_spends[0].coin.name(), message)
)
assert chia_tx.spend_bundle is not None
spend_bundle = SpendBundle.aggregate([spend_bundle, chia_tx.spend_bundle])

View File

@ -53,6 +53,7 @@ from chia.util.limited_semaphore import LimitedSemaphore
from chia.util.recursive_replace import recursive_replace
from chia.util.vdf_prover import get_vdf_info_and_proof
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from tests.blockchain.blockchain_test_utils import _validate_and_add_block, _validate_and_add_block_no_error
from tests.connection_utils import add_dummy_connection, connect_and_get_peer
from tests.core.full_node.stores.test_coin_store import get_future_reward_coins
@ -138,6 +139,7 @@ class TestFullNodeBlockCompression:
tr: TransactionRecord = await wallet.generate_signed_transaction(
tx_size,
ph,
DEFAULT_TX_CONFIG,
)
await wallet.push_transaction(tx=tr)
await time_out_assert(
@ -170,6 +172,7 @@ class TestFullNodeBlockCompression:
tr: TransactionRecord = await wallet.generate_signed_transaction(
20000,
ph,
DEFAULT_TX_CONFIG,
)
await wallet.push_transaction(tx=tr)
await time_out_assert(
@ -206,6 +209,7 @@ class TestFullNodeBlockCompression:
tr: TransactionRecord = await wallet.generate_signed_transaction(
30000,
ph,
DEFAULT_TX_CONFIG,
)
await wallet.push_transaction(tx=tr)
await time_out_assert(
@ -217,6 +221,7 @@ class TestFullNodeBlockCompression:
tr: TransactionRecord = await wallet.generate_signed_transaction(
40000,
ph,
DEFAULT_TX_CONFIG,
)
await wallet.push_transaction(tx=tr)
await time_out_assert(
@ -229,6 +234,7 @@ class TestFullNodeBlockCompression:
tr: TransactionRecord = await wallet.generate_signed_transaction(
50000,
ph,
DEFAULT_TX_CONFIG,
)
await wallet.push_transaction(tx=tr)
await time_out_assert(
@ -241,6 +247,7 @@ class TestFullNodeBlockCompression:
tr: TransactionRecord = await wallet.generate_signed_transaction(
3000000000000,
ph,
DEFAULT_TX_CONFIG,
)
await wallet.push_transaction(tx=tr)
await time_out_assert(
@ -269,6 +276,7 @@ class TestFullNodeBlockCompression:
tr: TransactionRecord = await wallet.generate_signed_transaction(
30000,
Program.to(1).get_tree_hash(),
DEFAULT_TX_CONFIG,
)
extra_spend = SpendBundle(
[
@ -314,6 +322,7 @@ class TestFullNodeBlockCompression:
tr: TransactionRecord = await wallet.generate_signed_transaction(
30000,
Program.to(1).get_tree_hash(),
DEFAULT_TX_CONFIG,
)
extra_spend = SpendBundle(
[

View File

@ -13,6 +13,7 @@ from chia.simulator.simulator_protocol import FarmNewBlockProtocol
from chia.simulator.time_out_assert import time_out_assert
from chia.types.peer_info import PeerInfo
from chia.util.ints import uint16, uint32
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
class TestTransactions:
@ -81,7 +82,7 @@ class TestTransactions:
await time_out_assert(20, peak_height, num_blocks, full_node_api_1)
await time_out_assert(20, peak_height, num_blocks, full_node_api_2)
tx = await wallet_0.wallet_state_manager.main_wallet.generate_signed_transaction(10, ph1, 0)
tx = await wallet_0.wallet_state_manager.main_wallet.generate_signed_transaction(10, ph1, DEFAULT_TX_CONFIG, 0)
await wallet_0.wallet_state_manager.main_wallet.push_transaction(tx)
await time_out_assert(
@ -153,7 +154,9 @@ class TestTransactions:
)
await time_out_assert(20, wallet_0.wallet_state_manager.main_wallet.get_confirmed_balance, funds)
tx = await wallet_0.wallet_state_manager.main_wallet.generate_signed_transaction(10, token_bytes(), 0)
tx = await wallet_0.wallet_state_manager.main_wallet.generate_signed_transaction(
10, token_bytes(), DEFAULT_TX_CONFIG, 0
)
await wallet_0.wallet_state_manager.main_wallet.push_transaction(tx)
await time_out_assert(

View File

@ -44,6 +44,7 @@ from chia.types.spend_bundle_conditions import Spend, SpendBundleConditions
from chia.util.errors import Err, ValidationError
from chia.util.ints import uint16, uint32, uint64
from chia.wallet.payment import Payment
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.wallet import Wallet
from chia.wallet.wallet_coin_record import WalletCoinRecord
from chia.wallet.wallet_node import WalletNode
@ -1443,7 +1444,9 @@ async def test_identical_spend_aggregation_e2e(simulator_and_wallet: SimulatorsA
for _ in range(2):
await farm_a_block(full_node_api, wallet_node, ph)
other_recipients = [Payment(puzzle_hash=p, amount=uint64(200), memos=[]) for p in phs[1:]]
tx = await wallet.generate_signed_transaction(uint64(200), phs[0], primaries=other_recipients)
tx = await wallet.generate_signed_transaction(
uint64(200), phs[0], DEFAULT_TX_CONFIG, primaries=other_recipients
)
assert tx.spend_bundle is not None
await send_to_mempool(full_node_api, tx.spend_bundle)
await farm_a_block(full_node_api, wallet_node, ph)
@ -1458,10 +1461,9 @@ async def test_identical_spend_aggregation_e2e(simulator_and_wallet: SimulatorsA
wallet, coins, ph = await make_setup_and_coins(full_node_api, wallet_node)
# Make sure spending AB then BC would generate a conflict for the latter
tx_a = await wallet.generate_signed_transaction(uint64(30), ph, coins={coins[0].coin})
tx_b = await wallet.generate_signed_transaction(uint64(30), ph, coins={coins[1].coin})
tx_c = await wallet.generate_signed_transaction(uint64(30), ph, coins={coins[2].coin})
tx_a = await wallet.generate_signed_transaction(uint64(30), ph, DEFAULT_TX_CONFIG, coins={coins[0].coin})
tx_b = await wallet.generate_signed_transaction(uint64(30), ph, DEFAULT_TX_CONFIG, coins={coins[1].coin})
tx_c = await wallet.generate_signed_transaction(uint64(30), ph, DEFAULT_TX_CONFIG, coins={coins[2].coin})
assert tx_a.spend_bundle is not None
assert tx_b.spend_bundle is not None
assert tx_c.spend_bundle is not None
@ -1475,7 +1477,9 @@ async def test_identical_spend_aggregation_e2e(simulator_and_wallet: SimulatorsA
# Make sure DE and EF would aggregate on E when E is eligible for deduplication
# Create a coin with the identity puzzle hash
tx = await wallet.generate_signed_transaction(uint64(200), IDENTITY_PUZZLE_HASH, coins={coins[3].coin})
tx = await wallet.generate_signed_transaction(
uint64(200), IDENTITY_PUZZLE_HASH, DEFAULT_TX_CONFIG, coins={coins[3].coin}
)
assert tx.spend_bundle is not None
await send_to_mempool(full_node_api, tx.spend_bundle)
await farm_a_block(full_node_api, wallet_node, ph)
@ -1498,10 +1502,20 @@ async def test_identical_spend_aggregation_e2e(simulator_and_wallet: SimulatorsA
e_announcement = Announcement(e_coin_id, message)
# Create transactions D and F that consume an announcement created by E
tx_d = await wallet.generate_signed_transaction(
uint64(100), ph, fee=uint64(0), coins={coins[4].coin}, coin_announcements_to_consume={e_announcement}
uint64(100),
ph,
DEFAULT_TX_CONFIG,
fee=uint64(0),
coins={coins[4].coin},
coin_announcements_to_consume={e_announcement},
)
tx_f = await wallet.generate_signed_transaction(
uint64(150), ph, fee=uint64(0), coins={coins[5].coin}, coin_announcements_to_consume={e_announcement}
uint64(150),
ph,
DEFAULT_TX_CONFIG,
fee=uint64(0),
coins={coins[5].coin},
coin_announcements_to_consume={e_announcement},
)
assert tx_d.spend_bundle is not None
assert tx_f.spend_bundle is not None
@ -1529,7 +1543,7 @@ async def test_identical_spend_aggregation_e2e(simulator_and_wallet: SimulatorsA
g_coin = coins[6].coin
g_coin_id = g_coin.name()
tx_g = await wallet.generate_signed_transaction(
uint64(13), ph, coins={g_coin}, coin_announcements_to_consume={e_announcement}
uint64(13), ph, DEFAULT_TX_CONFIG, coins={g_coin}, coin_announcements_to_consume={e_announcement}
)
assert tx_g.spend_bundle is not None
sb_e2g = SpendBundle.aggregate([sb_e2, tx_g.spend_bundle])

View File

@ -34,6 +34,7 @@ from chia.util.config import load_config
from chia.util.ints import uint16, uint32, uint64
from chia.wallet.derive_keys import find_authentication_sk, find_owner_sk
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet_node import WalletNode
from chia.wallet.wallet_node_api import WalletNodeAPI
@ -469,7 +470,7 @@ class TestPoolWalletRpc:
assert len(await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(2)) == 0
tr: TransactionRecord = await client.send_transaction(
1, uint64(100), encode_puzzle_hash(status.p2_singleton_puzzle_hash, "txch")
1, uint64(100), encode_puzzle_hash(status.p2_singleton_puzzle_hash, "txch"), DEFAULT_TX_CONFIG
)
await full_node_api.wait_transaction_records_entered_mempool(records=[tr])

View File

@ -22,6 +22,7 @@ from chia.simulator.time_out_assert import time_out_assert
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.peer_info import PeerInfo
from chia.util.ints import uint16, uint32, uint64
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.wallet_node import WalletNode
test_constants_modified = test_constants.replace(
@ -166,6 +167,7 @@ class TestSimulation:
tx = await wallet.generate_signed_transaction(
uint64(10),
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
DEFAULT_TX_CONFIG,
uint64(0),
)
await wallet.push_transaction(tx)
@ -339,6 +341,7 @@ class TestSimulation:
tx = await wallet.generate_signed_transaction(
amount=uint64(tx_amount),
puzzle_hash=await wallet_node.wallet_state_manager.main_wallet.get_new_puzzlehash(),
tx_config=DEFAULT_TX_CONFIG,
coins={coin},
)
await wallet.push_transaction(tx)
@ -384,6 +387,7 @@ class TestSimulation:
await wallet.generate_signed_transaction(
amount=uint64(tx_amount),
puzzle_hash=await wallet_node.wallet_state_manager.main_wallet.get_new_puzzlehash(),
tx_config=DEFAULT_TX_CONFIG,
coins={coin},
)
for coin in coins

View File

@ -10,6 +10,7 @@ from chia.simulator.block_tools import BlockTools
from chia.simulator.full_node_simulator import FullNodeSimulator, backoff_times
from chia.types.peer_info import PeerInfo
from chia.util.ints import uint16, uint64
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.wallet_node import WalletNode
@ -160,6 +161,7 @@ async def test_wait_transaction_records_entered_mempool(
tx = await wallet.generate_signed_transaction(
amount=uint64(tx_amount),
puzzle_hash=await wallet_node.wallet_state_manager.main_wallet.get_new_puzzlehash(),
tx_config=DEFAULT_TX_CONFIG,
coins={coin},
)
await wallet.push_transaction(tx)
@ -194,6 +196,7 @@ async def test_process_transaction_records(
tx = await wallet.generate_signed_transaction(
amount=uint64(tx_amount),
puzzle_hash=await wallet_node.wallet_state_manager.main_wallet.get_new_puzzlehash(),
tx_config=DEFAULT_TX_CONFIG,
coins={coin},
)
await wallet.push_transaction(tx)

View File

@ -1,6 +1,7 @@
from __future__ import annotations
import asyncio
import dataclasses
import tempfile
from pathlib import Path
from typing import List
@ -32,6 +33,7 @@ from chia.wallet.derive_keys import _derive_path_unhardened, master_sk_to_wallet
from chia.wallet.lineage_proof import LineageProof
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import puzzle_hash_for_pk
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.tx_config import DEFAULT_COIN_SELECTION_CONFIG, DEFAULT_TX_CONFIG
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet_info import WalletInfo
from chia.wallet.wallet_interested_store import WalletInterestedStore
@ -74,7 +76,11 @@ class TestCATWallet:
async with wallet_node.wallet_state_manager.lock:
cat_wallet: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node.wallet_state_manager,
wallet,
{"identifier": "genesis_by_id"},
uint64(100),
DEFAULT_TX_CONFIG,
)
# The next 2 lines are basically a noop, it just adds test coverage
cat_wallet = await CATWallet.create(wallet_node.wallet_state_manager, wallet, cat_wallet.wallet_info)
@ -136,10 +142,18 @@ class TestCATWallet:
async with wallet_node.wallet_state_manager.lock:
cat_wallet_1: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node.wallet_state_manager,
wallet,
{"identifier": "genesis_by_id"},
uint64(100),
DEFAULT_TX_CONFIG,
)
cat_wallet_2: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(200)
wallet_node.wallet_state_manager,
wallet,
{"identifier": "genesis_by_id"},
uint64(200),
DEFAULT_TX_CONFIG,
)
proofs_1 = await cat_wallet_1.lineage_store.get_all_lineage_proofs()
@ -189,7 +203,11 @@ class TestCATWallet:
async with wallet_node.wallet_state_manager.lock:
cat_wallet: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node.wallet_state_manager,
wallet,
{"identifier": "genesis_by_id"},
uint64(100),
DEFAULT_TX_CONFIG,
)
tx_queue: List[TransactionRecord] = await wallet_node.wallet_state_manager.tx_store.get_not_sent()
tx_record = tx_queue[0]
@ -208,7 +226,9 @@ class TestCATWallet:
assert cat_wallet.cat_info.limitations_program_hash == cat_wallet_2.cat_info.limitations_program_hash
cat_2_hash = await cat_wallet_2.get_new_inner_hash()
tx_records = await cat_wallet.generate_signed_transaction([uint64(60)], [cat_2_hash], fee=uint64(1))
tx_records = await cat_wallet.generate_signed_transaction(
[uint64(60)], [cat_2_hash], DEFAULT_TX_CONFIG, fee=uint64(1)
)
tx_id = None
for tx_record in tx_records:
await wallet.wallet_state_manager.add_pending_transaction(tx_record)
@ -233,7 +253,7 @@ class TestCATWallet:
await time_out_assert(30, cat_wallet_2.get_confirmed_balance, 60)
await time_out_assert(30, cat_wallet_2.get_unconfirmed_balance, 60)
coins = await cat_wallet_2.select_coins(uint64(60))
coins = await cat_wallet_2.select_coins(uint64(60), DEFAULT_COIN_SELECTION_CONFIG)
assert len(coins) == 1
coin = coins.pop()
tx_id = coin.name().hex()
@ -241,7 +261,7 @@ class TestCATWallet:
assert len(memos[tx_id]) == 2
assert list(memos[tx_id].values())[0][0] == cat_2_hash.hex()
cat_hash = await cat_wallet.get_new_inner_hash()
tx_records = await cat_wallet_2.generate_signed_transaction([uint64(15)], [cat_hash])
tx_records = await cat_wallet_2.generate_signed_transaction([uint64(15)], [cat_hash], DEFAULT_TX_CONFIG)
for tx_record in tx_records:
await wallet.wallet_state_manager.add_pending_transaction(tx_record)
@ -296,7 +316,11 @@ class TestCATWallet:
async with wallet_node.wallet_state_manager.lock:
cat_wallet: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node.wallet_state_manager,
wallet,
{"identifier": "genesis_by_id"},
uint64(100),
DEFAULT_TX_CONFIG,
)
tx_queue: List[TransactionRecord] = await wallet_node.wallet_state_manager.tx_store.get_not_sent()
tx_record = tx_queue[0]
@ -316,7 +340,7 @@ class TestCATWallet:
cat_2_hash = await cat_wallet_2.get_new_inner_hash()
tx_records = await cat_wallet.generate_signed_transaction(
[uint64(60)], [cat_2_hash], fee=uint64(1), reuse_puzhash=True
[uint64(60)], [cat_2_hash], dataclasses.replace(DEFAULT_TX_CONFIG, reuse_puzhash=True), fee=uint64(1)
)
for tx_record in tx_records:
await wallet.wallet_state_manager.add_pending_transaction(tx_record)
@ -345,7 +369,7 @@ class TestCATWallet:
await time_out_assert(30, cat_wallet_2.get_unconfirmed_balance, 60)
cat_hash = await cat_wallet.get_new_inner_hash()
tx_records = await cat_wallet_2.generate_signed_transaction([uint64(15)], [cat_hash])
tx_records = await cat_wallet_2.generate_signed_transaction([uint64(15)], [cat_hash], DEFAULT_TX_CONFIG)
for tx_record in tx_records:
await wallet.wallet_state_manager.add_pending_transaction(tx_record)
@ -395,7 +419,11 @@ class TestCATWallet:
async with wallet_node.wallet_state_manager.lock:
cat_wallet: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node.wallet_state_manager,
wallet,
{"identifier": "genesis_by_id"},
uint64(100),
DEFAULT_TX_CONFIG,
)
for i in range(1, num_blocks):
@ -453,7 +481,11 @@ class TestCATWallet:
async with wallet_node.wallet_state_manager.lock:
cat_wallet: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node.wallet_state_manager,
wallet,
{"identifier": "genesis_by_id"},
uint64(100),
DEFAULT_TX_CONFIG,
)
tx_records: List[TransactionRecord] = await wallet_node.wallet_state_manager.tx_store.get_not_sent()
await full_node_api.process_transaction_records(records=tx_records)
@ -471,7 +503,9 @@ class TestCATWallet:
assert cat_wallet.cat_info.limitations_program_hash == cat_wallet_2.cat_info.limitations_program_hash
cat_2_hash = await cat_wallet_2.get_new_inner_hash()
tx_records = await cat_wallet.generate_signed_transaction([uint64(60)], [cat_2_hash], fee=uint64(1))
tx_records = await cat_wallet.generate_signed_transaction(
[uint64(60)], [cat_2_hash], DEFAULT_TX_CONFIG, fee=uint64(1)
)
for tx_record in tx_records:
await wallet.wallet_state_manager.add_pending_transaction(tx_record)
await full_node_api.process_transaction_records(records=tx_records)
@ -486,7 +520,9 @@ class TestCATWallet:
await time_out_assert(20, cat_wallet_2.get_unconfirmed_balance, 60)
cc2_ph = await cat_wallet_2.get_new_cat_puzzle_hash()
tx_record = await wallet.wallet_state_manager.main_wallet.generate_signed_transaction(10, cc2_ph, 0)
tx_record = await wallet.wallet_state_manager.main_wallet.generate_signed_transaction(
10, cc2_ph, DEFAULT_TX_CONFIG, 0
)
await wallet.wallet_state_manager.add_pending_transaction(tx_record)
await full_node_api.process_transaction_records(records=[tx_record])
@ -543,7 +579,11 @@ class TestCATWallet:
async with wallet_node_0.wallet_state_manager.lock:
cat_wallet_0: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_0.wallet_state_manager, wallet_0, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node_0.wallet_state_manager,
wallet_0,
{"identifier": "genesis_by_id"},
uint64(100),
DEFAULT_TX_CONFIG,
)
tx_records: List[TransactionRecord] = await wallet_node_0.wallet_state_manager.tx_store.get_not_sent()
await full_node_api.process_transaction_records(records=tx_records)
@ -568,7 +608,9 @@ class TestCATWallet:
cat_1_hash = await cat_wallet_1.get_new_inner_hash()
cat_2_hash = await cat_wallet_2.get_new_inner_hash()
tx_records = await cat_wallet_0.generate_signed_transaction([uint64(60), uint64(20)], [cat_1_hash, cat_2_hash])
tx_records = await cat_wallet_0.generate_signed_transaction(
[uint64(60), uint64(20)], [cat_1_hash, cat_2_hash], DEFAULT_TX_CONFIG
)
for tx_record in tx_records:
await wallet_0.wallet_state_manager.add_pending_transaction(tx_record)
await full_node_api.process_transaction_records(records=tx_records)
@ -584,11 +626,11 @@ class TestCATWallet:
cat_hash = await cat_wallet_0.get_new_inner_hash()
tx_records = await cat_wallet_1.generate_signed_transaction([uint64(15)], [cat_hash])
tx_records = await cat_wallet_1.generate_signed_transaction([uint64(15)], [cat_hash], DEFAULT_TX_CONFIG)
for tx_record in tx_records:
await wallet_1.wallet_state_manager.add_pending_transaction(tx_record)
tx_records_2 = await cat_wallet_2.generate_signed_transaction([uint64(20)], [cat_hash])
tx_records_2 = await cat_wallet_2.generate_signed_transaction([uint64(20)], [cat_hash], DEFAULT_TX_CONFIG)
for tx_record in tx_records_2:
await wallet_2.wallet_state_manager.add_pending_transaction(tx_record)
@ -607,11 +649,11 @@ class TestCATWallet:
print(len(txs))
# Test with Memo
tx_records_3: TransactionRecord = await cat_wallet_1.generate_signed_transaction(
[uint64(30)], [cat_hash], memos=[[b"Markus Walburg"]]
[uint64(30)], [cat_hash], DEFAULT_TX_CONFIG, memos=[[b"Markus Walburg"]]
)
with pytest.raises(ValueError):
await cat_wallet_1.generate_signed_transaction(
[uint64(30)], [cat_hash], memos=[[b"too"], [b"many"], [b"memos"]]
[uint64(30)], [cat_hash], DEFAULT_TX_CONFIG, memos=[[b"too"], [b"many"], [b"memos"]]
)
for tx_record in tx_records_3:
@ -664,7 +706,11 @@ class TestCATWallet:
async with wallet_node.wallet_state_manager.lock:
cat_wallet: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(100000)
wallet_node.wallet_state_manager,
wallet,
{"identifier": "genesis_by_id"},
uint64(100000),
DEFAULT_TX_CONFIG,
)
tx_records: List[TransactionRecord] = await wallet_node.wallet_state_manager.tx_store.get_not_sent()
await full_node_api.process_transaction_records(records=tx_records)
@ -682,7 +728,9 @@ class TestCATWallet:
amounts.append(uint64(i))
puzzle_hashes.append(cat_2_hash)
spent_coint = (await cat_wallet.get_cat_spendable_coins())[0].coin
tx_records = await cat_wallet.generate_signed_transaction(amounts, puzzle_hashes, coins={spent_coint})
tx_records = await cat_wallet.generate_signed_transaction(
amounts, puzzle_hashes, DEFAULT_TX_CONFIG, coins={spent_coint}
)
for tx_record in tx_records:
await wallet.wallet_state_manager.add_pending_transaction(tx_record)
await full_node_api.process_transaction_records(records=tx_records)
@ -711,6 +759,7 @@ class TestCATWallet:
[transaction_record] = await cat_wallet.generate_signed_transaction(
[max_sent_amount - 1],
[ph],
DEFAULT_TX_CONFIG,
)
assert transaction_record.amount == uint64(max_sent_amount - 1)
@ -719,6 +768,7 @@ class TestCATWallet:
[transaction_record] = await cat_wallet.generate_signed_transaction(
[max_sent_amount],
[ph],
DEFAULT_TX_CONFIG,
)
assert transaction_record.amount == uint64(max_sent_amount)
@ -728,6 +778,7 @@ class TestCATWallet:
await cat_wallet.generate_signed_transaction(
[max_sent_amount + 1],
[ph],
DEFAULT_TX_CONFIG,
)
@pytest.mark.parametrize(
@ -776,7 +827,11 @@ class TestCATWallet:
async with wallet_node.wallet_state_manager.lock:
cat_wallet: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node.wallet_state_manager,
wallet,
{"identifier": "genesis_by_id"},
uint64(100),
DEFAULT_TX_CONFIG,
)
tx_records: List[TransactionRecord] = await wallet_node.wallet_state_manager.tx_store.get_not_sent()
await full_node_api.process_transaction_records(records=tx_records)
@ -786,7 +841,9 @@ class TestCATWallet:
assert cat_wallet.cat_info.limitations_program_hash is not None
cat_2_hash = await wallet2.get_new_puzzlehash()
tx_records = await cat_wallet.generate_signed_transaction([uint64(60)], [cat_2_hash], memos=[[cat_2_hash]])
tx_records = await cat_wallet.generate_signed_transaction(
[uint64(60)], [cat_2_hash], DEFAULT_TX_CONFIG, memos=[[cat_2_hash]]
)
for tx_record in tx_records:
await wallet.wallet_state_manager.add_pending_transaction(tx_record)
@ -816,7 +873,9 @@ class TestCATWallet:
}
# Then we send another transaction
tx_records = await cat_wallet.generate_signed_transaction([uint64(10)], [cat_2_hash], memos=[[cat_2_hash]])
tx_records = await cat_wallet.generate_signed_transaction(
[uint64(10)], [cat_2_hash], DEFAULT_TX_CONFIG, memos=[[cat_2_hash]]
)
for tx_record in tx_records:
await wallet.wallet_state_manager.add_pending_transaction(tx_record)
@ -835,7 +894,7 @@ class TestCATWallet:
await time_out_assert(30, cat_wallet_2.get_unconfirmed_balance, 70)
cat_hash = await cat_wallet.get_new_inner_hash()
tx_records = await cat_wallet_2.generate_signed_transaction([uint64(5)], [cat_hash])
tx_records = await cat_wallet_2.generate_signed_transaction([uint64(5)], [cat_hash], DEFAULT_TX_CONFIG)
for tx_record in tx_records:
await wallet.wallet_state_manager.add_pending_transaction(tx_record)
@ -913,7 +972,7 @@ class TestCATWallet:
cat_amount_0 = uint64(100)
cat_amount_1 = uint64(5)
tx = await client_0.send_transaction(1, cat_amount_0, addr)
tx = await client_0.send_transaction(1, cat_amount_0, addr, DEFAULT_TX_CONFIG)
spend_bundle = tx.spend_bundle
assert spend_bundle is not None

View File

@ -26,6 +26,7 @@ from chia.wallet.trading.offer import Offer
from chia.wallet.trading.trade_status import TradeStatus
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG, TXConfig
buffer_blocks = 4
@ -75,16 +76,26 @@ class TestCATTrades:
wallet_maker = wallet_node_maker.wallet_state_manager.main_wallet
wallet_taker = wallet_node_taker.wallet_state_manager.main_wallet
tx_config: TXConfig = dataclasses.replace(DEFAULT_TX_CONFIG, reuse_puzhash=reuse_puzhash)
# Create two new CATs, one in each wallet
async with wallet_node_maker.wallet_state_manager.lock:
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_maker.wallet_state_manager, wallet_maker, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node_maker.wallet_state_manager,
wallet_maker,
{"identifier": "genesis_by_id"},
uint64(100),
tx_config,
)
await asyncio.sleep(1)
async with wallet_node_taker.wallet_state_manager.lock:
new_cat_wallet_taker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_taker.wallet_state_manager, wallet_taker, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node_taker.wallet_state_manager,
wallet_taker,
{"identifier": "genesis_by_id"},
uint64(100),
tx_config,
)
await asyncio.sleep(1)
@ -176,7 +187,7 @@ class TestCATTrades:
else:
# chia_for_cat
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
chia_for_cat, fee=uint64(1), reuse_puzhash=reuse_puzhash
chia_for_cat, tx_config, fee=uint64(1)
)
await asyncio.sleep(1)
assert error is None
@ -187,8 +198,8 @@ class TestCATTrades:
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
tx_config,
fee=uint64(1),
reuse_puzhash=reuse_puzhash,
)
assert trade_take is not None
assert tx_records is not None
@ -284,7 +295,7 @@ class TestCATTrades:
)
await trade_manager_maker.save_trade(*create_tr_for_offer(old_maker_offer))
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(cat_for_chia)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(cat_for_chia, tx_config)
assert error is None
assert success is True
assert trade_make is not None
@ -292,6 +303,7 @@ class TestCATTrades:
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
tx_config,
)
assert trade_take is not None
assert tx_records is not None
@ -348,9 +360,7 @@ class TestCATTrades:
)
await trade_manager_maker.save_trade(*create_tr_for_offer(old_maker_offer))
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
cat_for_cat, reuse_puzhash=reuse_puzhash
)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(cat_for_cat, tx_config)
await asyncio.sleep(1)
assert error is None
assert success is True
@ -358,7 +368,7 @@ class TestCATTrades:
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
reuse_puzhash=reuse_puzhash,
tx_config,
)
await time_out_assert(15, full_node.txs_in_mempool, True, tx_records)
assert trade_take is not None
@ -442,6 +452,7 @@ class TestCATTrades:
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
chia_for_multiple_cat,
tx_config,
driver_dict=driver_dict,
)
await asyncio.sleep(1)
@ -452,6 +463,7 @@ class TestCATTrades:
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
tx_config,
)
await time_out_assert(15, full_node.txs_in_mempool, True, tx_records)
assert trade_take is not None
@ -501,7 +513,7 @@ class TestCATTrades:
await trade_manager_maker.save_trade(*create_tr_for_offer(old_maker_offer))
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
multiple_cat_for_chia,
multiple_cat_for_chia, tx_config
)
await asyncio.sleep(1)
assert error is None
@ -510,6 +522,7 @@ class TestCATTrades:
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
tx_config,
)
await time_out_assert(15, full_node.txs_in_mempool, True, tx_records)
assert trade_take is not None
@ -558,9 +571,7 @@ class TestCATTrades:
)
await trade_manager_maker.save_trade(*create_tr_for_offer(old_maker_offer))
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
chia_and_cat_for_cat,
)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_and_cat_for_cat, tx_config)
await asyncio.sleep(1)
assert error is None
assert success is True
@ -569,6 +580,7 @@ class TestCATTrades:
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
tx_config,
)
await time_out_assert(15, full_node.txs_in_mempool, True, tx_records)
assert trade_take is not None
@ -624,7 +636,11 @@ class TestCATTrades:
async with wallet_node_maker.wallet_state_manager.lock:
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_maker.wallet_state_manager, wallet_maker, {"identifier": "genesis_by_id"}, xch_to_cat_amount
wallet_node_maker.wallet_state_manager,
wallet_maker,
{"identifier": "genesis_by_id"},
xch_to_cat_amount,
DEFAULT_TX_CONFIG,
)
tx_records: List[TransactionRecord] = await wallet_node_maker.wallet_state_manager.tx_store.get_not_sent()
@ -653,7 +669,7 @@ class TestCATTrades:
trade_rec = await trade_manager.get_trade_by_id(trade.trade_id)
return TradeStatus(trade_rec.status)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(cat_for_chia)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(cat_for_chia, DEFAULT_TX_CONFIG)
await asyncio.sleep(1)
assert error is None
assert success is True
@ -681,7 +697,7 @@ class TestCATTrades:
fee = uint64(2_000_000_000_000)
txs = await trade_manager_maker.cancel_pending_offer_safely(trade_make.trade_id, fee=fee)
txs = await trade_manager_maker.cancel_pending_offer_safely(trade_make.trade_id, DEFAULT_TX_CONFIG, fee=fee)
await time_out_assert(15, get_trade_and_status, TradeStatus.PENDING_CANCEL, trade_manager_maker, trade_make)
await full_node.process_transaction_records(records=txs)
@ -704,10 +720,10 @@ class TestCATTrades:
peer = wallet_node_taker.get_full_node_peer()
with pytest.raises(ValueError, match="This offer is no longer valid"):
await trade_manager_taker.respond_to_offer(Offer.from_bytes(trade_make.offer), peer)
await trade_manager_taker.respond_to_offer(Offer.from_bytes(trade_make.offer), peer, DEFAULT_TX_CONFIG)
# Now we're going to create the other way around for test coverage sake
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_for_cat)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_for_cat, DEFAULT_TX_CONFIG)
assert error is None
assert success is True
assert trade_make is not None
@ -717,9 +733,11 @@ class TestCATTrades:
ValueError,
match=f"Do not have a wallet for asset ID: {cat_wallet_maker.get_asset_id()} to fulfill offer",
):
await trade_manager_taker.respond_to_offer(Offer.from_bytes(trade_make.offer), peer)
await trade_manager_taker.respond_to_offer(Offer.from_bytes(trade_make.offer), peer, DEFAULT_TX_CONFIG)
txs = await trade_manager_maker.cancel_pending_offer_safely(trade_make.trade_id, fee=uint64(0))
txs = await trade_manager_maker.cancel_pending_offer_safely(
trade_make.trade_id, DEFAULT_TX_CONFIG, fee=uint64(0)
)
await time_out_assert(15, get_trade_and_status, TradeStatus.PENDING_CANCEL, trade_manager_maker, trade_make)
await full_node.process_transaction_records(records=txs)
@ -738,7 +756,11 @@ class TestCATTrades:
async with wallet_node_maker.wallet_state_manager.lock:
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_maker.wallet_state_manager, wallet_maker, {"identifier": "genesis_by_id"}, xch_to_cat_amount
wallet_node_maker.wallet_state_manager,
wallet_maker,
{"identifier": "genesis_by_id"},
xch_to_cat_amount,
DEFAULT_TX_CONFIG,
)
tx_records: List[TransactionRecord] = await wallet_node_maker.wallet_state_manager.tx_store.get_not_sent()
@ -761,12 +783,14 @@ class TestCATTrades:
trade_rec = await trade_manager.get_trade_by_id(trade.trade_id)
return TradeStatus(trade_rec.status)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_for_cat)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_for_cat, DEFAULT_TX_CONFIG)
await time_out_assert(10, get_trade_and_status, TradeStatus.PENDING_ACCEPT, trade_manager_maker, trade_make)
assert error is None
assert success is True
assert trade_make is not None
txs = await trade_manager_maker.cancel_pending_offer_safely(trade_make.trade_id, fee=uint64(0))
txs = await trade_manager_maker.cancel_pending_offer_safely(
trade_make.trade_id, DEFAULT_TX_CONFIG, fee=uint64(0)
)
await time_out_assert(15, get_trade_and_status, TradeStatus.PENDING_CANCEL, trade_manager_maker, trade_make)
await full_node.process_transaction_records(records=txs)
@ -785,7 +809,11 @@ class TestCATTrades:
async with wallet_node_maker.wallet_state_manager.lock:
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_maker.wallet_state_manager, wallet_maker, {"identifier": "genesis_by_id"}, xch_to_cat_amount
wallet_node_maker.wallet_state_manager,
wallet_maker,
{"identifier": "genesis_by_id"},
xch_to_cat_amount,
DEFAULT_TX_CONFIG,
)
tx_records: List[TransactionRecord] = await wallet_node_maker.wallet_state_manager.tx_store.get_not_sent()
@ -812,20 +840,20 @@ class TestCATTrades:
return TradeStatus(trade_rec.status)
raise ValueError("Couldn't find the trade record")
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_for_cat)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_for_cat, DEFAULT_TX_CONFIG)
await time_out_assert(10, get_trade_and_status, TradeStatus.PENDING_ACCEPT, trade_manager_maker, trade_make)
assert error is None
assert success is True
assert trade_make is not None
peer = wallet_node_taker.get_full_node_peer()
offer = Offer.from_bytes(trade_make.offer)
tr1, txs1 = await trade_manager_taker.respond_to_offer(offer, peer, fee=uint64(10))
tr1, txs1 = await trade_manager_taker.respond_to_offer(offer, peer, DEFAULT_TX_CONFIG, fee=uint64(10))
# we shouldn't be able to respond to a duplicate offer
with pytest.raises(ValueError):
await trade_manager_taker.respond_to_offer(offer, peer, fee=uint64(10))
await trade_manager_taker.respond_to_offer(offer, peer, DEFAULT_TX_CONFIG, fee=uint64(10))
await time_out_assert(15, get_trade_and_status, TradeStatus.PENDING_CONFIRM, trade_manager_taker, tr1)
# pushing into mempool while already in it should fail
tr2, txs2 = await trade_manager_trader.respond_to_offer(offer, peer, fee=uint64(10))
tr2, txs2 = await trade_manager_trader.respond_to_offer(offer, peer, DEFAULT_TX_CONFIG, fee=uint64(10))
assert await trade_manager_trader.get_coins_of_interest()
offer_tx_records: List[TransactionRecord] = await wallet_node_maker.wallet_state_manager.tx_store.get_not_sent()
await full_node.process_transaction_records(records=offer_tx_records)
@ -843,7 +871,11 @@ class TestCATTrades:
async with wallet_node_maker.wallet_state_manager.lock:
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_maker.wallet_state_manager, wallet_maker, {"identifier": "genesis_by_id"}, xch_to_cat_amount
wallet_node_maker.wallet_state_manager,
wallet_maker,
{"identifier": "genesis_by_id"},
xch_to_cat_amount,
DEFAULT_TX_CONFIG,
)
tx_records: List[TransactionRecord] = await wallet_node_maker.wallet_state_manager.tx_store.get_not_sent()
@ -869,7 +901,7 @@ class TestCATTrades:
return TradeStatus(trade_rec.status)
raise ValueError("Couldn't find the trade record")
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_for_cat)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_for_cat, DEFAULT_TX_CONFIG)
await time_out_assert(10, get_trade_and_status, TradeStatus.PENDING_ACCEPT, trade_manager_maker, trade_make)
assert error is None
assert success is True
@ -878,7 +910,7 @@ class TestCATTrades:
offer = Offer.from_bytes(trade_make.offer)
bundle = dataclasses.replace(offer._bundle, aggregated_signature=G2Element())
offer = dataclasses.replace(offer, _bundle=bundle)
tr1, txs1 = await trade_manager_taker.respond_to_offer(offer, peer, fee=uint64(10))
tr1, txs1 = await trade_manager_taker.respond_to_offer(offer, peer, DEFAULT_TX_CONFIG, fee=uint64(10))
wallet_node_taker.wallet_tx_resend_timeout_secs = 0 # don't wait for resend
await wallet_node_taker._resend_queue()
await wallet_node_taker._resend_queue()
@ -902,7 +934,11 @@ class TestCATTrades:
async with wallet_node_maker.wallet_state_manager.lock:
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_maker.wallet_state_manager, wallet_maker, {"identifier": "genesis_by_id"}, xch_to_cat_amount
wallet_node_maker.wallet_state_manager,
wallet_maker,
{"identifier": "genesis_by_id"},
xch_to_cat_amount,
DEFAULT_TX_CONFIG,
)
tx_records: List[TransactionRecord] = await wallet_node_maker.wallet_state_manager.tx_store.get_not_sent()
@ -928,13 +964,15 @@ class TestCATTrades:
return TradeStatus(trade_rec.status)
raise ValueError("Couldn't find the trade record")
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_for_cat)
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(chia_for_cat, DEFAULT_TX_CONFIG)
await time_out_assert(10, get_trade_and_status, TradeStatus.PENDING_ACCEPT, trade_manager_maker, trade_make)
assert error is None
assert success is True
assert trade_make is not None
peer = wallet_node_taker.get_full_node_peer()
offer = Offer.from_bytes(trade_make.offer)
tr1, txs1 = await trade_manager_taker.respond_to_offer(offer, peer, fee=uint64(1000000000000))
tr1, txs1 = await trade_manager_taker.respond_to_offer(
offer, peer, DEFAULT_TX_CONFIG, fee=uint64(1000000000000)
)
await full_node.process_transaction_records(records=txs1)
await time_out_assert(15, get_trade_and_status, TradeStatus.CONFIRMED, trade_manager_taker, tr1)

View File

@ -14,6 +14,7 @@ from chia.wallet.trade_record import TradeRecord
from chia.wallet.trading.offer import Offer
from chia.wallet.trading.trade_status import TradeStatus
from chia.wallet.util.merkle_utils import build_merkle_tree, simplify_merkle_proof
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
async def is_singleton_confirmed_and_root(dl_wallet: DataLayerWallet, lid: bytes32, root: bytes32) -> bool:
@ -69,7 +70,9 @@ async def test_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_compat: b
fee = uint64(1_999_999_999_999)
dl_record, std_record, launcher_id_maker = await dl_wallet_maker.generate_new_reporter(maker_root, fee=fee)
dl_record, std_record, launcher_id_maker = await dl_wallet_maker.generate_new_reporter(
maker_root, DEFAULT_TX_CONFIG, fee=fee
)
assert await dl_wallet_maker.get_latest_singleton(launcher_id_maker) is not None
await wsm_maker.add_pending_transaction(dl_record)
await wsm_maker.add_pending_transaction(std_record)
@ -78,7 +81,9 @@ async def test_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_compat: b
maker_funds -= 1
await time_out_assert(15, is_singleton_confirmed_and_root, True, dl_wallet_maker, launcher_id_maker, maker_root)
dl_record, std_record, launcher_id_taker = await dl_wallet_taker.generate_new_reporter(taker_root, fee=fee)
dl_record, std_record, launcher_id_taker = await dl_wallet_taker.generate_new_reporter(
taker_root, DEFAULT_TX_CONFIG, fee=fee
)
assert await dl_wallet_taker.get_latest_singleton(launcher_id_taker) is not None
await wsm_taker.add_pending_transaction(dl_record)
await wsm_taker.add_pending_transaction(std_record)
@ -123,6 +128,7 @@ async def test_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_compat: b
else:
success, offer_maker, error = await trade_manager_maker.create_offer_for_ids(
{launcher_id_maker: -1, launcher_id_taker: 1},
DEFAULT_TX_CONFIG,
solver=Solver(
{
launcher_id_maker.hex(): {
@ -162,6 +168,7 @@ async def test_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_compat: b
offer_taker, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(offer_maker.offer),
peer,
DEFAULT_TX_CONFIG,
solver=Solver(
{
launcher_id_taker.hex(): {
@ -247,7 +254,7 @@ async def test_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_compat: b
await time_out_assert(15, is_singleton_generation, True, dl_wallet_taker, launcher_id_taker, 2)
txs = await dl_wallet_taker.create_update_state_spend(launcher_id_taker, bytes32([2] * 32))
txs = await dl_wallet_taker.create_update_state_spend(launcher_id_taker, bytes32([2] * 32), DEFAULT_TX_CONFIG)
for tx in txs:
await wallet_node_taker.wallet_state_manager.add_pending_transaction(tx)
await full_node_api.process_transaction_records(records=txs)
@ -269,13 +276,13 @@ async def test_dl_offer_cancellation(wallets_prefarm: Any, trusted: bool) -> Non
ROWS = [bytes32([i] * 32) for i in range(0, 10)]
root, _ = build_merkle_tree(ROWS)
dl_record, std_record, launcher_id = await dl_wallet.generate_new_reporter(root)
dl_record, std_record, launcher_id = await dl_wallet.generate_new_reporter(root, DEFAULT_TX_CONFIG)
assert await dl_wallet.get_latest_singleton(launcher_id) is not None
await wsm.add_pending_transaction(dl_record)
await wsm.add_pending_transaction(std_record)
await full_node_api.process_transaction_records(records=[dl_record, std_record])
await time_out_assert(15, is_singleton_confirmed_and_root, True, dl_wallet, launcher_id, root)
dl_record_2, std_record_2, launcher_id_2 = await dl_wallet.generate_new_reporter(root)
dl_record_2, std_record_2, launcher_id_2 = await dl_wallet.generate_new_reporter(root, DEFAULT_TX_CONFIG)
await wsm.add_pending_transaction(dl_record_2)
await wsm.add_pending_transaction(std_record_2)
await full_node_api.process_transaction_records(records=[dl_record_2, std_record_2])
@ -288,6 +295,7 @@ async def test_dl_offer_cancellation(wallets_prefarm: Any, trusted: bool) -> Non
success, offer, error = await trade_manager.create_offer_for_ids(
{launcher_id: -1, launcher_id_2: 1},
DEFAULT_TX_CONFIG,
solver=Solver(
{
launcher_id.hex(): {
@ -307,7 +315,9 @@ async def test_dl_offer_cancellation(wallets_prefarm: Any, trusted: bool) -> Non
assert success is True
assert offer is not None
cancellation_txs = await trade_manager.cancel_pending_offer_safely(offer.trade_id, fee=uint64(2_000_000_000_000))
cancellation_txs = await trade_manager.cancel_pending_offer_safely(
offer.trade_id, DEFAULT_TX_CONFIG, fee=uint64(2_000_000_000_000)
)
assert len(cancellation_txs) == 3
await time_out_assert(15, get_trade_and_status, TradeStatus.PENDING_CANCEL, trade_manager, offer)
await full_node_api.process_transaction_records(records=cancellation_txs)
@ -346,7 +356,9 @@ async def test_multiple_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_
fee = uint64(1_999_999_999_999)
dl_record, std_record, launcher_id_maker_1 = await dl_wallet_maker.generate_new_reporter(maker_root, fee=fee)
dl_record, std_record, launcher_id_maker_1 = await dl_wallet_maker.generate_new_reporter(
maker_root, DEFAULT_TX_CONFIG, fee=fee
)
assert await dl_wallet_maker.get_latest_singleton(launcher_id_maker_1) is not None
await wsm_maker.add_pending_transaction(dl_record)
await wsm_maker.add_pending_transaction(std_record)
@ -354,7 +366,9 @@ async def test_multiple_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_
maker_funds -= fee
maker_funds -= 1
await time_out_assert(15, is_singleton_confirmed_and_root, True, dl_wallet_maker, launcher_id_maker_1, maker_root)
dl_record, std_record, launcher_id_maker_2 = await dl_wallet_maker.generate_new_reporter(maker_root, fee=fee)
dl_record, std_record, launcher_id_maker_2 = await dl_wallet_maker.generate_new_reporter(
maker_root, DEFAULT_TX_CONFIG, fee=fee
)
assert await dl_wallet_maker.get_latest_singleton(launcher_id_maker_2) is not None
await wsm_maker.add_pending_transaction(dl_record)
await wsm_maker.add_pending_transaction(std_record)
@ -363,7 +377,9 @@ async def test_multiple_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_
maker_funds -= 1
await time_out_assert(15, is_singleton_confirmed_and_root, True, dl_wallet_maker, launcher_id_maker_2, maker_root)
dl_record, std_record, launcher_id_taker_1 = await dl_wallet_taker.generate_new_reporter(taker_root, fee=fee)
dl_record, std_record, launcher_id_taker_1 = await dl_wallet_taker.generate_new_reporter(
taker_root, DEFAULT_TX_CONFIG, fee=fee
)
assert await dl_wallet_taker.get_latest_singleton(launcher_id_taker_1) is not None
await wsm_taker.add_pending_transaction(dl_record)
await wsm_taker.add_pending_transaction(std_record)
@ -371,7 +387,9 @@ async def test_multiple_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_
taker_funds -= fee
taker_funds -= 1
await time_out_assert(15, is_singleton_confirmed_and_root, True, dl_wallet_taker, launcher_id_taker_1, taker_root)
dl_record, std_record, launcher_id_taker_2 = await dl_wallet_taker.generate_new_reporter(taker_root, fee=fee)
dl_record, std_record, launcher_id_taker_2 = await dl_wallet_taker.generate_new_reporter(
taker_root, DEFAULT_TX_CONFIG, fee=fee
)
assert await dl_wallet_taker.get_latest_singleton(launcher_id_taker_2) is not None
await wsm_taker.add_pending_transaction(dl_record)
await wsm_taker.add_pending_transaction(std_record)
@ -420,6 +438,7 @@ async def test_multiple_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_
else:
success, offer_maker, error = await trade_manager_maker.create_offer_for_ids(
{launcher_id_maker_1: -1, launcher_id_taker_1: 1, launcher_id_maker_2: -1, launcher_id_taker_2: 1},
DEFAULT_TX_CONFIG,
solver=Solver(
{
launcher_id_maker_1.hex(): {
@ -455,6 +474,7 @@ async def test_multiple_dl_offers(wallets_prefarm: Any, trusted: bool, forwards_
offer_taker, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(offer_maker.offer),
peer,
DEFAULT_TX_CONFIG,
solver=Solver(
{
launcher_id_taker_1.hex(): {

View File

@ -18,6 +18,7 @@ from chia.types.peer_info import PeerInfo
from chia.util.ints import uint16, uint32, uint64
from chia.wallet.db_wallet.db_wallet_puzzles import create_mirror_puzzle
from chia.wallet.util.merkle_tree import MerkleTree
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
pytestmark = pytest.mark.data_layer
@ -68,7 +69,7 @@ class TestDLWallet:
for i in range(0, 2):
dl_record, std_record, launcher_id = await dl_wallet.generate_new_reporter(
current_root, fee=uint64(1999999999999)
current_root, DEFAULT_TX_CONFIG, fee=uint64(1999999999999)
)
assert await dl_wallet.get_latest_singleton(launcher_id) is not None
@ -120,7 +121,7 @@ class TestDLWallet:
for i in range(0, 2):
dl_record, std_record, launcher_id = await dl_wallet.generate_new_reporter(
current_root, fee=uint64(1999999999999)
current_root, DEFAULT_TX_CONFIG, fee=uint64(1999999999999)
)
expected_launcher_ids.add(launcher_id)
@ -183,7 +184,7 @@ class TestDLWallet:
current_tree = MerkleTree(nodes)
current_root = current_tree.calculate_root()
dl_record, std_record, launcher_id = await dl_wallet_0.generate_new_reporter(current_root)
dl_record, std_record, launcher_id = await dl_wallet_0.generate_new_reporter(current_root, DEFAULT_TX_CONFIG)
assert await dl_wallet_0.get_latest_singleton(launcher_id) is not None
@ -200,7 +201,7 @@ class TestDLWallet:
for i in range(0, 5):
new_root = MerkleTree([Program.to("root").get_tree_hash()]).calculate_root()
txs = await dl_wallet_0.create_update_state_spend(launcher_id, new_root)
txs = await dl_wallet_0.create_update_state_spend(launcher_id, new_root, DEFAULT_TX_CONFIG)
for tx in txs:
await wallet_node_0.wallet_state_manager.add_pending_transaction(tx)
@ -255,7 +256,7 @@ class TestDLWallet:
current_tree = MerkleTree(nodes)
current_root = current_tree.calculate_root()
dl_record, std_record, launcher_id = await dl_wallet.generate_new_reporter(current_root)
dl_record, std_record, launcher_id = await dl_wallet.generate_new_reporter(current_root, DEFAULT_TX_CONFIG)
assert await dl_wallet.get_latest_singleton(launcher_id) is not None
@ -275,6 +276,7 @@ class TestDLWallet:
txs = await dl_wallet.generate_signed_transaction(
[previous_record.lineage_proof.amount],
[previous_record.inner_puzzle_hash],
DEFAULT_TX_CONFIG,
launcher_id=previous_record.launcher_id,
new_root_hash=new_root,
fee=uint64(1999999999999),
@ -284,6 +286,7 @@ class TestDLWallet:
await dl_wallet.generate_signed_transaction(
[previous_record.lineage_proof.amount],
[previous_record.inner_puzzle_hash],
DEFAULT_TX_CONFIG,
coins=set([txs[0].spend_bundle.removals()[0]]),
fee=uint64(1999999999999),
)
@ -305,7 +308,7 @@ class TestDLWallet:
previous_record = await dl_wallet.get_latest_singleton(launcher_id)
new_root = MerkleTree([Program.to("new root").get_tree_hash()]).calculate_root()
txs = await dl_wallet.create_update_state_spend(launcher_id, new_root)
txs = await dl_wallet.create_update_state_spend(launcher_id, new_root, DEFAULT_TX_CONFIG)
new_record = await dl_wallet.get_latest_singleton(launcher_id)
assert new_record is not None
assert new_record != previous_record
@ -367,7 +370,7 @@ class TestDLWallet:
return False
return latest_singleton.confirmed
dl_record, std_record, launcher_id = await dl_wallet_0.generate_new_reporter(current_root)
dl_record, std_record, launcher_id = await dl_wallet_0.generate_new_reporter(current_root, DEFAULT_TX_CONFIG)
initial_record = await dl_wallet_0.get_latest_singleton(launcher_id)
assert initial_record is not None
@ -391,13 +394,13 @@ class TestDLWallet:
# Because these have the same fee, the one that gets pushed first will win
report_txs = await dl_wallet_1.create_update_state_spend(
launcher_id, current_record.root, fee=uint64(2000000000000)
launcher_id, current_record.root, DEFAULT_TX_CONFIG, fee=uint64(2000000000000)
)
record_1 = await dl_wallet_1.get_latest_singleton(launcher_id)
assert record_1 is not None
assert current_record != record_1
update_txs = await dl_wallet_0.create_update_state_spend(
launcher_id, bytes32([0] * 32), fee=uint64(2000000000000)
launcher_id, bytes32([0] * 32), DEFAULT_TX_CONFIG, fee=uint64(2000000000000)
)
record_0 = await dl_wallet_0.get_latest_singleton(launcher_id)
assert record_0 is not None
@ -454,7 +457,7 @@ class TestDLWallet:
assert await dl_wallet_0.get_singleton_record(record_0.coin_id) is None
update_txs_1 = await dl_wallet_0.create_update_state_spend(
launcher_id, bytes32([1] * 32), fee=uint64(2000000000000)
launcher_id, bytes32([1] * 32), DEFAULT_TX_CONFIG, fee=uint64(2000000000000)
)
record_1 = await dl_wallet_0.get_latest_singleton(launcher_id)
assert record_1 is not None
@ -467,7 +470,7 @@ class TestDLWallet:
for tx in update_txs_1:
await wallet_node_0.wallet_state_manager.tx_store.delete_transaction_record(tx.name)
update_txs_0 = await dl_wallet_0.create_update_state_spend(launcher_id, bytes32([2] * 32))
update_txs_0 = await dl_wallet_0.create_update_state_spend(launcher_id, bytes32([2] * 32), DEFAULT_TX_CONFIG)
record_0 = await dl_wallet_0.get_latest_singleton(launcher_id)
assert record_0 is not None
assert record_0 != record_1
@ -536,14 +539,14 @@ async def test_mirrors(wallets_prefarm: Any, trusted: bool) -> None:
async with wsm_2.lock:
dl_wallet_2 = await DataLayerWallet.create_new_dl_wallet(wsm_2)
dl_record, std_record, launcher_id_1 = await dl_wallet_1.generate_new_reporter(bytes32([0] * 32))
dl_record, std_record, launcher_id_1 = await dl_wallet_1.generate_new_reporter(bytes32([0] * 32), DEFAULT_TX_CONFIG)
assert await dl_wallet_1.get_latest_singleton(launcher_id_1) is not None
await wsm_1.add_pending_transaction(dl_record)
await wsm_1.add_pending_transaction(std_record)
await full_node_api.process_transaction_records(records=[dl_record, std_record])
await time_out_assert(15, is_singleton_confirmed_and_root, True, dl_wallet_1, launcher_id_1, bytes32([0] * 32))
dl_record, std_record, launcher_id_2 = await dl_wallet_2.generate_new_reporter(bytes32([0] * 32))
dl_record, std_record, launcher_id_2 = await dl_wallet_2.generate_new_reporter(bytes32([0] * 32), DEFAULT_TX_CONFIG)
assert await dl_wallet_2.get_latest_singleton(launcher_id_2) is not None
await wsm_2.add_pending_transaction(dl_record)
await wsm_2.add_pending_transaction(std_record)
@ -557,7 +560,9 @@ async def test_mirrors(wallets_prefarm: Any, trusted: bool) -> None:
await time_out_assert(15, is_singleton_confirmed_and_root, True, dl_wallet_1, launcher_id_2, bytes32([0] * 32))
await time_out_assert(15, is_singleton_confirmed_and_root, True, dl_wallet_2, launcher_id_1, bytes32([0] * 32))
txs = await dl_wallet_1.create_new_mirror(launcher_id_2, uint64(3), [b"foo", b"bar"], fee=uint64(1_999_999_999_999))
txs = await dl_wallet_1.create_new_mirror(
launcher_id_2, uint64(3), [b"foo", b"bar"], DEFAULT_TX_CONFIG, fee=uint64(1_999_999_999_999)
)
additions: List[Coin] = []
for tx in txs:
if tx.spend_bundle is not None:
@ -574,7 +579,7 @@ async def test_mirrors(wallets_prefarm: Any, trusted: bool) -> None:
15, dl_wallet_2.get_mirrors_for_launcher, [dataclasses.replace(mirror, ours=False)], launcher_id_2
)
txs = await dl_wallet_1.delete_mirror(mirror.coin_id, peer_1, fee=uint64(2_000_000_000_000))
txs = await dl_wallet_1.delete_mirror(mirror.coin_id, peer_1, DEFAULT_TX_CONFIG, fee=uint64(2_000_000_000_000))
for tx in txs:
await wsm_1.add_pending_transaction(tx)
await full_node_api.process_transaction_records(records=txs)

View File

@ -21,6 +21,7 @@ from chia.util.ints import uint16, uint64
from chia.wallet.did_wallet.did_wallet import DIDWallet
from chia.wallet.singleton import create_singleton_puzzle
from chia.wallet.util.address_type import AddressType
from chia.wallet.util.tx_config import DEFAULT_COIN_SELECTION_CONFIG, DEFAULT_TX_CONFIG
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet import CHIP_0002_SIGN_MESSAGE_PREFIX
@ -195,7 +196,7 @@ class TestDIDWallet:
did_wallet_2 = await DIDWallet.create_new_did_wallet_from_recovery(
wallet_node_2.wallet_state_manager, wallet_2, backup_data
)
coins = await did_wallet_1.select_coins(1)
coins = await did_wallet_1.select_coins(1, DEFAULT_COIN_SELECTION_CONFIG)
coin = coins.copy().pop()
assert did_wallet_2.did_info.temp_coin == coin
newpuzhash = await did_wallet_2.get_new_did_inner_hash()
@ -203,7 +204,7 @@ class TestDIDWallet:
(await did_wallet_2.wallet_state_manager.get_unused_derivation_record(did_wallet_2.wallet_info.id)).pubkey
)
message_spend_bundle, attest_data = await did_wallet_0.create_attestment(
did_wallet_2.did_info.temp_coin.name(), newpuzhash, pubkey
did_wallet_2.did_info.temp_coin.name(), newpuzhash, pubkey, DEFAULT_TX_CONFIG
)
spend_bundle_list = await wallet_node_0.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(
did_wallet_0.id()
@ -239,7 +240,7 @@ class TestDIDWallet:
assert wallet.wallet_state_manager.wallets[wallet.id()] == wallet
some_ph = 32 * b"\2"
await did_wallet_2.create_exit_spend(some_ph)
await did_wallet_2.create_exit_spend(some_ph, DEFAULT_TX_CONFIG)
spend_bundle_list = await wallet_node_2.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(
did_wallet_2.id()
@ -347,7 +348,7 @@ class TestDIDWallet:
assert did_wallet_3.did_info.backup_ids == recovery_list
await time_out_assert(15, did_wallet_3.get_confirmed_balance, 201)
await time_out_assert(15, did_wallet_3.get_unconfirmed_balance, 201)
coins = await did_wallet_3.select_coins(1)
coins = await did_wallet_3.select_coins(1, DEFAULT_COIN_SELECTION_CONFIG)
coin = coins.pop()
backup_data = did_wallet_3.create_backup()
@ -364,12 +365,16 @@ class TestDIDWallet:
await did_wallet_4.wallet_state_manager.get_unused_derivation_record(did_wallet_2.wallet_info.id)
).pubkey
new_ph = did_wallet_4.did_info.temp_puzhash
message_spend_bundle, attest1 = await did_wallet.create_attestment(coin.name(), new_ph, pubkey)
message_spend_bundle, attest1 = await did_wallet.create_attestment(
coin.name(), new_ph, pubkey, DEFAULT_TX_CONFIG
)
spend_bundle_list = await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(did_wallet.id())
spend_bundle = spend_bundle_list[0].spend_bundle
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, spend_bundle.name())
message_spend_bundle2, attest2 = await did_wallet_2.create_attestment(coin.name(), new_ph, pubkey)
message_spend_bundle2, attest2 = await did_wallet_2.create_attestment(
coin.name(), new_ph, pubkey, DEFAULT_TX_CONFIG
)
spend_bundle_list = await wallet_node_2.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(
did_wallet_2.id()
)
@ -448,7 +453,7 @@ class TestDIDWallet:
await time_out_assert(15, did_wallet.get_confirmed_balance, 101)
await time_out_assert(15, did_wallet.get_unconfirmed_balance, 101)
coins = await did_wallet.select_coins(1)
coins = await did_wallet.select_coins(1, DEFAULT_COIN_SELECTION_CONFIG)
coin = coins.pop()
info = Program.to([])
pubkey = (await did_wallet.wallet_state_manager.get_unused_derivation_record(did_wallet.wallet_info.id)).pubkey
@ -503,7 +508,7 @@ class TestDIDWallet:
await time_out_assert(15, did_wallet.get_confirmed_balance, 101)
await time_out_assert(15, did_wallet.get_unconfirmed_balance, 101)
# Delete the coin and wallet
coins = await did_wallet.select_coins(uint64(1))
coins = await did_wallet.select_coins(uint64(1), DEFAULT_COIN_SELECTION_CONFIG)
coin = coins.pop()
await wallet_node.wallet_state_manager.coin_store.delete_coin_record(coin.name())
await time_out_assert(15, did_wallet.get_confirmed_balance, 0)
@ -526,7 +531,7 @@ class TestDIDWallet:
recovery_list = [bytes32.fromhex(did_wallet.get_my_DID())]
await did_wallet.update_recovery_list(recovery_list, uint64(1))
assert did_wallet.did_info.backup_ids == recovery_list
await did_wallet.create_update_spend()
await did_wallet.create_update_spend(DEFAULT_TX_CONFIG)
spend_bundle_list = await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(did_wallet.id())
spend_bundle = spend_bundle_list[0].spend_bundle
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, spend_bundle.name())
@ -535,7 +540,7 @@ class TestDIDWallet:
await time_out_assert(15, did_wallet.get_confirmed_balance, 101)
await time_out_assert(15, did_wallet.get_unconfirmed_balance, 101)
# Delete the coin and change inner puzzle
coins = await did_wallet.select_coins(uint64(1))
coins = await did_wallet.select_coins(uint64(1), DEFAULT_COIN_SELECTION_CONFIG)
coin = coins.pop()
await wallet_node.wallet_state_manager.coin_store.delete_coin_record(coin.name())
await time_out_assert(15, did_wallet.get_confirmed_balance, 0)
@ -607,7 +612,7 @@ class TestDIDWallet:
recovery_list = [bytes.fromhex(did_wallet_2.get_my_DID())]
await did_wallet.update_recovery_list(recovery_list, uint64(1))
assert did_wallet.did_info.backup_ids == recovery_list
await did_wallet.create_update_spend()
await did_wallet.create_update_spend(DEFAULT_TX_CONFIG)
spend_bundle_list = await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(did_wallet.id())
@ -629,13 +634,13 @@ class TestDIDWallet:
backup_data,
)
new_ph = await did_wallet_3.get_new_did_inner_hash()
coins = await did_wallet_2.select_coins(1)
coins = await did_wallet_2.select_coins(1, DEFAULT_COIN_SELECTION_CONFIG)
coin = coins.pop()
pubkey = (
await did_wallet_3.wallet_state_manager.get_unused_derivation_record(did_wallet_3.wallet_info.id)
).pubkey
await time_out_assert(15, did_wallet.get_confirmed_balance, 101)
attest_data = (await did_wallet.create_attestment(coin.name(), new_ph, pubkey))[1]
attest_data = (await did_wallet.create_attestment(coin.name(), new_ph, pubkey, DEFAULT_TX_CONFIG))[1]
spend_bundle_list = await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(did_wallet.id())
spend_bundle = spend_bundle_list[0].spend_bundle
@ -668,13 +673,13 @@ class TestDIDWallet:
wallet2,
backup_data,
)
coins = await did_wallet.select_coins(1)
coins = await did_wallet.select_coins(1, DEFAULT_COIN_SELECTION_CONFIG)
coin = coins.pop()
new_ph = await did_wallet_4.get_new_did_inner_hash()
pubkey = (
await did_wallet_4.wallet_state_manager.get_unused_derivation_record(did_wallet_4.wallet_info.id)
).pubkey
attest1 = (await did_wallet_3.create_attestment(coin.name(), new_ph, pubkey))[1]
attest1 = (await did_wallet_3.create_attestment(coin.name(), new_ph, pubkey, DEFAULT_TX_CONFIG))[1]
spend_bundle_list = await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(
did_wallet_3.id()
)
@ -762,7 +767,7 @@ class TestDIDWallet:
await time_out_assert(15, did_wallet_1.get_unconfirmed_balance, 101)
# Transfer DID
new_puzhash = await wallet2.get_new_puzzlehash()
await did_wallet_1.transfer_did(new_puzhash, fee, with_recovery)
await did_wallet_1.transfer_did(new_puzhash, fee, with_recovery, DEFAULT_TX_CONFIG)
spend_bundle_list = await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(
did_wallet_1.id()
)
@ -832,7 +837,7 @@ class TestDIDWallet:
await time_out_assert(15, did_wallet_1.get_confirmed_balance, 101)
await time_out_assert(15, did_wallet_1.get_unconfirmed_balance, 101)
await did_wallet_1.update_recovery_list([bytes(ph)], 1)
await did_wallet_1.create_update_spend()
await did_wallet_1.create_update_spend(DEFAULT_TX_CONFIG)
await full_node_api.farm_blocks_to_wallet(1, wallet)
await time_out_assert(15, did_wallet_1.get_confirmed_balance, 101)
await time_out_assert(15, did_wallet_1.get_unconfirmed_balance, 101)
@ -890,26 +895,38 @@ class TestDIDWallet:
did_wallet_1.did_info.current_inner, did_wallet_1.did_info.origin_coin.name()
)
assert response["metadata"]["twitter"] == "twitter"
assert response["latest_coin"] == (await did_wallet_1.select_coins(uint64(1))).pop().name().hex()
assert (
response["latest_coin"]
== (await did_wallet_1.select_coins(uint64(1), DEFAULT_COIN_SELECTION_CONFIG)).pop().name().hex()
)
assert response["num_verification"] == 0
assert response["recovery_list_hash"] == Program(Program.to([])).get_tree_hash().hex()
assert decode_puzzle_hash(response["p2_address"]).hex() == response["hints"][0]
# Test non-singleton coin
coin = (await wallet.select_coins(uint64(1))).pop()
coin = (await wallet.select_coins(uint64(1), DEFAULT_COIN_SELECTION_CONFIG)).pop()
assert coin.amount % 2 == 1
response = await api_0.did_get_info({"coin_id": coin.name().hex()})
assert not response["success"]
# Test multiple odd coins
odd_amount = uint64(1)
coin_1 = (await wallet.select_coins(odd_amount, exclude=[coin])).pop()
coin_1 = (
await wallet.select_coins(
odd_amount, dataclasses.replace(DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[coin.name()])
)
).pop()
assert coin_1.amount % 2 == 0
tx = await wallet.generate_signed_transaction(
odd_amount,
ph1,
dataclasses.replace(
DEFAULT_TX_CONFIG,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[coin.name()]
),
),
fee,
excluded_coins=set([coin]),
)
await wallet.push_transaction(tx)
await full_node_api.process_transaction_records(records=[tx])
@ -1032,7 +1049,7 @@ class TestDIDWallet:
metadata = {}
metadata["Twitter"] = "http://www.twitter.com"
await did_wallet_1.update_metadata(metadata)
await did_wallet_1.create_update_spend(fee)
await did_wallet_1.create_update_spend(DEFAULT_TX_CONFIG, fee)
transaction_records = await wallet_node.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(
did_wallet_1.id()
)

View File

@ -25,6 +25,7 @@ from chia.wallet.trading.offer import Offer
from chia.wallet.trading.trade_status import TradeStatus
from chia.wallet.uncurried_puzzle import uncurry_puzzle
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from tests.wallet.cat_wallet.test_trades import create_tr_for_offer
# from clvm_tools.binutils import disassemble
@ -137,6 +138,7 @@ async def test_nft_offer_sell_nft(
sb = await nft_wallet_maker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash,
royalty_puzhash,
royalty_basis_pts,
@ -188,7 +190,7 @@ async def test_nft_offer_sell_nft(
)
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_did_nft_for_xch, {}, fee=maker_fee
offer_did_nft_for_xch, DEFAULT_TX_CONFIG, {}, fee=maker_fee
)
assert success is True
assert error is None
@ -199,7 +201,10 @@ async def test_nft_offer_sell_nft(
peer = wallet_node_taker.get_full_node_peer()
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer), peer, fee=uint64(taker_fee)
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
DEFAULT_TX_CONFIG,
fee=uint64(taker_fee),
)
await time_out_assert(20, mempool_not_empty, True, full_node_api)
@ -310,6 +315,7 @@ async def test_nft_offer_request_nft(
sb = await nft_wallet_taker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash,
royalty_puzhash,
royalty_basis_pts,
@ -364,7 +370,7 @@ async def test_nft_offer_request_nft(
)
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_dict, driver_dict, fee=maker_fee
offer_dict, DEFAULT_TX_CONFIG, driver_dict, fee=maker_fee
)
assert success is True
assert error is None
@ -374,7 +380,10 @@ async def test_nft_offer_request_nft(
peer = wallet_node_taker.get_full_node_peer()
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer), peer, fee=uint64(taker_fee)
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
DEFAULT_TX_CONFIG,
fee=uint64(taker_fee),
)
await time_out_assert(20, mempool_not_empty, True, full_node_api)
assert trade_take is not None
@ -482,6 +491,7 @@ async def test_nft_offer_sell_did_to_did(
sb = await nft_wallet_maker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash,
royalty_puzhash,
royalty_basis_pts,
@ -551,7 +561,7 @@ async def test_nft_offer_sell_did_to_did(
)
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_did_nft_for_xch, {}, fee=maker_fee
offer_did_nft_for_xch, DEFAULT_TX_CONFIG, {}, fee=maker_fee
)
assert success is True
assert error is None
@ -561,7 +571,10 @@ async def test_nft_offer_sell_did_to_did(
peer = wallet_node_taker.get_full_node_peer()
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer), peer, fee=uint64(taker_fee)
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
DEFAULT_TX_CONFIG,
fee=uint64(taker_fee),
)
await time_out_assert(20, mempool_not_empty, True, full_node_api)
assert trade_take is not None
@ -675,6 +688,7 @@ async def test_nft_offer_sell_nft_for_cat(
sb = await nft_wallet_maker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash,
royalty_puzhash,
royalty_basis_pts,
@ -711,7 +725,11 @@ async def test_nft_offer_sell_nft_for_cat(
async with wallet_node_maker.wallet_state_manager.lock:
full_node_api.full_node.log.warning(f"Mempool size: {full_node_api.full_node.mempool_manager.mempool.size()}")
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_maker.wallet_state_manager, wallet_maker, {"identifier": "genesis_by_id"}, uint64(cats_to_mint)
wallet_node_maker.wallet_state_manager,
wallet_maker,
{"identifier": "genesis_by_id"},
uint64(cats_to_mint),
DEFAULT_TX_CONFIG,
)
await time_out_assert(20, mempool_not_empty, True, full_node_api)
@ -728,7 +746,10 @@ async def test_nft_offer_sell_nft_for_cat(
ph_taker_cat_1 = await wallet_taker.get_new_puzzlehash()
ph_taker_cat_2 = await wallet_taker.get_new_puzzlehash()
cat_tx_records = await cat_wallet_maker.generate_signed_transaction(
[cats_to_trade, cats_to_trade], [ph_taker_cat_1, ph_taker_cat_2], memos=[[ph_taker_cat_1], [ph_taker_cat_2]]
[cats_to_trade, cats_to_trade],
[ph_taker_cat_1, ph_taker_cat_2],
DEFAULT_TX_CONFIG,
memos=[[ph_taker_cat_1], [ph_taker_cat_2]],
)
for tx_record in cat_tx_records:
await wallet_maker.wallet_state_manager.add_pending_transaction(tx_record)
@ -762,7 +783,7 @@ async def test_nft_offer_sell_nft_for_cat(
)
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_did_nft_for_xch, {}, fee=maker_fee
offer_did_nft_for_xch, DEFAULT_TX_CONFIG, {}, fee=maker_fee
)
assert success is True
@ -773,7 +794,10 @@ async def test_nft_offer_sell_nft_for_cat(
peer = wallet_node_taker.get_full_node_peer()
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer), peer, fee=uint64(taker_fee)
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
DEFAULT_TX_CONFIG,
fee=uint64(taker_fee),
)
await time_out_assert(20, mempool_not_empty, True, full_node_api)
assert trade_take is not None
@ -882,6 +906,7 @@ async def test_nft_offer_request_nft_for_cat(
sb = await nft_wallet_taker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash,
royalty_puzhash,
royalty_basis_pts,
@ -917,7 +942,11 @@ async def test_nft_offer_request_nft_for_cat(
cats_to_trade = uint64(20000)
async with wallet_node_maker.wallet_state_manager.lock:
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_maker.wallet_state_manager, wallet_maker, {"identifier": "genesis_by_id"}, uint64(cats_to_mint)
wallet_node_maker.wallet_state_manager,
wallet_maker,
{"identifier": "genesis_by_id"},
uint64(cats_to_mint),
DEFAULT_TX_CONFIG,
)
await time_out_assert(20, mempool_not_empty, True, full_node_api)
@ -943,7 +972,7 @@ async def test_nft_offer_request_nft_for_cat(
extra_change = cats_to_mint - (2 * cats_to_trade)
amounts.append(uint64(extra_change))
puzzle_hashes.append(ph_taker_cat_1)
cat_tx_records = await cat_wallet_maker.generate_signed_transaction(amounts, puzzle_hashes)
cat_tx_records = await cat_wallet_maker.generate_signed_transaction(amounts, puzzle_hashes, DEFAULT_TX_CONFIG)
for tx_record in cat_tx_records:
await wallet_maker.wallet_state_manager.add_pending_transaction(tx_record)
await full_node_api.process_transaction_records(records=cat_tx_records)
@ -984,7 +1013,7 @@ async def test_nft_offer_request_nft_for_cat(
await trade_manager_maker.save_trade(*create_tr_for_offer(old_maker_offer))
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_dict, driver_dict, fee=maker_fee
offer_dict, DEFAULT_TX_CONFIG, driver_dict, fee=maker_fee
)
assert success is True
assert error is None
@ -994,7 +1023,10 @@ async def test_nft_offer_request_nft_for_cat(
peer = wallet_node_taker.get_full_node_peer()
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer), peer, fee=uint64(taker_fee)
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
DEFAULT_TX_CONFIG,
fee=uint64(taker_fee),
)
await time_out_assert(20, mempool_not_empty, True, full_node_api)
assert trade_take is not None
@ -1089,6 +1121,7 @@ async def test_nft_offer_sell_cancel(self_hostname: str, two_wallet_nodes: Any,
sb = await nft_wallet_maker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash,
royalty_puzhash,
royalty_basis_pts,
@ -1118,11 +1151,11 @@ async def test_nft_offer_sell_cancel(self_hostname: str, two_wallet_nodes: Any,
offer_did_nft_for_xch = {nft_to_offer_asset_id: -1, wallet_maker.id(): xch_requested}
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_did_nft_for_xch, {}, fee=maker_fee
offer_did_nft_for_xch, DEFAULT_TX_CONFIG, {}, fee=maker_fee
)
FEE = uint64(2000000000000)
txs = await trade_manager_maker.cancel_pending_offer_safely(trade_make.trade_id, fee=FEE)
txs = await trade_manager_maker.cancel_pending_offer_safely(trade_make.trade_id, DEFAULT_TX_CONFIG, fee=FEE)
async def get_trade_and_status(trade_manager: Any, trade: Any) -> TradeStatus:
trade_rec = await trade_manager.get_trade_by_id(trade.trade_id)
@ -1206,6 +1239,7 @@ async def test_nft_offer_sell_cancel_in_batch(self_hostname: str, two_wallet_nod
sb = await nft_wallet_maker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash,
royalty_puzhash,
royalty_basis_pts,
@ -1236,11 +1270,11 @@ async def test_nft_offer_sell_cancel_in_batch(self_hostname: str, two_wallet_nod
offer_did_nft_for_xch = {nft_to_offer_asset_id: -1, wallet_maker.id(): xch_requested}
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_did_nft_for_xch, {}, fee=maker_fee
offer_did_nft_for_xch, DEFAULT_TX_CONFIG, {}, fee=maker_fee
)
FEE = uint64(2000000000000)
txs = await trade_manager_maker.cancel_pending_offers([trade_make], fee=FEE, secure=True)
txs = await trade_manager_maker.cancel_pending_offers([trade_make], DEFAULT_TX_CONFIG, fee=FEE, secure=True)
async def get_trade_and_status(trade_manager: Any, trade: Any) -> TradeStatus:
trade_rec = await trade_manager.get_trade_by_id(trade.trade_id)
@ -1339,11 +1373,11 @@ async def test_complex_nft_offer(
CAT_AMOUNT = uint64(100000000)
async with wsm_maker.lock:
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wsm_maker, wallet_maker, {"identifier": "genesis_by_id"}, CAT_AMOUNT
wsm_maker, wallet_maker, {"identifier": "genesis_by_id"}, CAT_AMOUNT, DEFAULT_TX_CONFIG
)
async with wsm_maker.lock:
cat_wallet_taker: CATWallet = await CATWallet.create_new_cat_wallet(
wsm_taker, wallet_taker, {"identifier": "genesis_by_id"}, CAT_AMOUNT
wsm_taker, wallet_taker, {"identifier": "genesis_by_id"}, CAT_AMOUNT, DEFAULT_TX_CONFIG
)
cat_spend_bundle_maker = (
await wallet_node_maker.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(wallet_maker.id())
@ -1419,6 +1453,7 @@ async def test_complex_nft_offer(
with pytest.raises(ValueError):
await nft_wallet_maker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash_maker,
royalty_puzhash_maker,
royalty_basis_pts_maker, # type: ignore
@ -1428,6 +1463,7 @@ async def test_complex_nft_offer(
else:
sb_maker = await nft_wallet_maker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash_maker,
royalty_puzhash_maker,
uint16(royalty_basis_pts_maker),
@ -1436,6 +1472,7 @@ async def test_complex_nft_offer(
sb_taker_1 = await nft_wallet_taker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash_taker,
royalty_puzhash_taker,
royalty_basis_pts_taker_1,
@ -1460,6 +1497,7 @@ async def test_complex_nft_offer(
# MAke one more NFT for the taker
sb_taker_2 = await nft_wallet_taker.generate_new_nft(
metadata,
DEFAULT_TX_CONFIG,
target_puzhash_taker,
royalty_puzhash_taker,
royalty_basis_pts_taker_2,
@ -1526,7 +1564,7 @@ async def test_complex_nft_offer(
)
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
complex_nft_offer, driver_dict=driver_dict, fee=FEE
complex_nft_offer, DEFAULT_TX_CONFIG, driver_dict=driver_dict, fee=FEE
)
assert error is None
assert success
@ -1536,6 +1574,7 @@ async def test_complex_nft_offer(
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
wallet_node_taker.get_full_node_peer(),
DEFAULT_TX_CONFIG,
fee=FEE,
)
# all done for this test
@ -1544,6 +1583,7 @@ async def test_complex_nft_offer(
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
wallet_node_taker.get_full_node_peer(),
DEFAULT_TX_CONFIG,
fee=FEE,
)
assert trade_take is not None
@ -1648,7 +1688,7 @@ async def test_complex_nft_offer(
)
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
complex_nft_offer, driver_dict=driver_dict, fee=uint64(0)
complex_nft_offer, DEFAULT_TX_CONFIG, driver_dict=driver_dict, fee=uint64(0)
)
assert error is None
assert success
@ -1657,6 +1697,7 @@ async def test_complex_nft_offer(
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
wallet_node_taker.get_full_node_peer(),
DEFAULT_TX_CONFIG,
fee=uint64(0),
)
assert trade_take is not None

View File

@ -1,5 +1,6 @@
from __future__ import annotations
import dataclasses
from secrets import token_bytes
from typing import Any, Dict
@ -23,6 +24,7 @@ from chia.wallet.did_wallet.did_wallet import DIDWallet
from chia.wallet.nft_wallet.nft_wallet import NFTWallet
from chia.wallet.nft_wallet.uncurry_nft import UncurriedNFT
from chia.wallet.util.address_type import AddressType
from chia.wallet.util.tx_config import DEFAULT_COIN_SELECTION_CONFIG, DEFAULT_TX_CONFIG
async def nft_count(wallet: NFTWallet) -> int:
@ -110,7 +112,7 @@ async def test_nft_mint_from_did(self_hostname: str, two_wallet_nodes: Any, trus
target_list = [(await wallet_1.get_new_puzzlehash()) for x in range(mint_total)]
sb = await nft_wallet_maker.mint_from_did(
metadata_list, target_list=target_list, mint_number_start=1, mint_total=mint_total, fee=fee
metadata_list, DEFAULT_TX_CONFIG, target_list=target_list, mint_number_start=1, mint_total=mint_total, fee=fee
)
await api_0.push_tx({"spend_bundle": bytes(sb).hex()})
@ -255,13 +257,17 @@ async def test_nft_mint_from_did_rpc(
royalty_percentage = 300
fee = 100
required_amount = n + (fee * n)
xch_coins = await client.select_coins(amount=required_amount, wallet_id=wallet_maker.id())
xch_coins = await client.select_coins(
amount=required_amount, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG, wallet_id=wallet_maker.id()
)
funding_coin = xch_coins[0]
assert funding_coin.amount >= required_amount
funding_coin_dict = xch_coins[0].to_json_dict()
chunk = 5
next_coin = funding_coin
did_coin = (await client.select_coins(amount=1, wallet_id=2))[0]
did_coin = (
await client.select_coins(amount=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG, wallet_id=2)
)[0]
did_lineage_parent = None
spends = []
nft_ids = set([])
@ -281,6 +287,7 @@ async def test_nft_mint_from_did_rpc(
did_lineage_parent=did_lineage_parent,
mint_from_did=True,
fee=fee,
tx_config=DEFAULT_TX_CONFIG,
)
assert resp["success"]
sb: SpendBundle = SpendBundle.from_json_dict(resp["spend_bundle"])
@ -439,13 +446,17 @@ async def test_nft_mint_from_did_rpc_no_royalties(
royalty_address = None
royalty_percentage = None
required_amount = n
xch_coins = await client.select_coins(amount=required_amount, wallet_id=wallet_maker.id())
xch_coins = await client.select_coins(
amount=required_amount, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG, wallet_id=wallet_maker.id()
)
funding_coin = xch_coins[0]
assert funding_coin.amount >= required_amount
funding_coin_dict = xch_coins[0].to_json_dict()
chunk = 5
next_coin = funding_coin
did_coin = (await client.select_coins(amount=1, wallet_id=2))[0]
did_coin = (
await client.select_coins(amount=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG, wallet_id=2)
)[0]
did_lineage_parent = None
spends = []
@ -464,6 +475,7 @@ async def test_nft_mint_from_did_rpc_no_royalties(
did_coin=did_coin.to_json_dict(),
did_lineage_parent=did_lineage_parent,
mint_from_did=True,
tx_config=DEFAULT_TX_CONFIG,
)
assert resp["success"]
sb: SpendBundle = SpendBundle.from_json_dict(resp["spend_bundle"])
@ -573,14 +585,20 @@ async def test_nft_mint_from_did_multiple_xch(self_hostname: str, two_wallet_nod
]
# Grab two coins for testing that we can create a bulk minting with more than 1 xch coin
xch_coins_1 = await wallet_maker.select_coins(amount=10000)
xch_coins_2 = await wallet_maker.select_coins(amount=10000, exclude=xch_coins_1)
xch_coins_1 = await wallet_maker.select_coins(amount=10000, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG)
xch_coins_2 = await wallet_maker.select_coins(
amount=10000,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[c.name() for c in xch_coins_1]
),
)
xch_coins = xch_coins_1.union(xch_coins_2)
target_list = [ph_taker for x in range(mint_total)]
sb = await nft_wallet_maker.mint_from_did(
metadata_list,
DEFAULT_TX_CONFIG,
target_list=target_list,
mint_number_start=1,
mint_total=mint_total,
@ -682,7 +700,7 @@ async def test_nft_mint_from_xch(self_hostname: str, two_wallet_nodes: Any, trus
target_list = [(await wallet_1.get_new_puzzlehash()) for x in range(mint_total)]
sb = await nft_wallet_maker.mint_from_xch(
metadata_list, target_list=target_list, mint_number_start=1, mint_total=mint_total, fee=fee
metadata_list, DEFAULT_TX_CONFIG, target_list=target_list, mint_number_start=1, mint_total=mint_total, fee=fee
)
await api_0.push_tx({"spend_bundle": bytes(sb).hex()})
@ -826,7 +844,9 @@ async def test_nft_mint_from_xch_rpc(
royalty_percentage = 300
fee = 100
required_amount = n + (fee * n)
xch_coins = await client.select_coins(amount=required_amount, wallet_id=wallet_maker.id())
xch_coins = await client.select_coins(
amount=required_amount, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG, wallet_id=wallet_maker.id()
)
funding_coin = xch_coins[0]
assert funding_coin.amount >= required_amount
funding_coin_dict = xch_coins[0].to_json_dict()
@ -848,6 +868,7 @@ async def test_nft_mint_from_xch_rpc(
xch_change_target=funding_coin_dict["puzzle_hash"],
mint_from_did=False,
fee=fee,
tx_config=DEFAULT_TX_CONFIG,
)
assert resp["success"]
sb: SpendBundle = SpendBundle.from_json_dict(resp["spend_bundle"])
@ -971,14 +992,20 @@ async def test_nft_mint_from_xch_multiple_xch(self_hostname: str, two_wallet_nod
]
# Grab two coins for testing that we can create a bulk minting with more than 1 xch coin
xch_coins_1 = await wallet_maker.select_coins(amount=10000)
xch_coins_2 = await wallet_maker.select_coins(amount=10000, exclude=xch_coins_1)
xch_coins_1 = await wallet_maker.select_coins(amount=10000, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG)
xch_coins_2 = await wallet_maker.select_coins(
amount=10000,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[c.name() for c in xch_coins_1]
),
)
xch_coins = xch_coins_1.union(xch_coins_2)
target_list = [ph_taker for x in range(mint_total)]
sb = await nft_wallet_maker.mint_from_xch(
metadata_list,
DEFAULT_TX_CONFIG,
target_list=target_list,
mint_number_start=1,
mint_total=mint_total,

View File

@ -1,5 +1,6 @@
from __future__ import annotations
import dataclasses
import sys
from secrets import token_bytes
from typing import Any, Dict, Optional
@ -22,6 +23,7 @@ from chia.wallet.trading.offer import Offer
from chia.wallet.trading.trade_status import TradeStatus
from chia.wallet.uncurried_puzzle import uncurry_puzzle
from chia.wallet.util.debug_spend_bundle import disassemble
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from tests.wallet.nft_wallet.test_nft_1_offers import mempool_not_empty
@ -31,16 +33,14 @@ async def get_trade_and_status(trade_manager, trade) -> TradeStatus: # type: ig
@pytest.mark.parametrize(
"trusted",
[False],
)
@pytest.mark.parametrize(
"forwards_compat",
[True, False],
)
@pytest.mark.parametrize(
"reuse_puzhash",
[True, False],
"trusted,forwards_compat,reuse_puzhash",
[
[True, True, False],
[True, False, True],
[True, False, False],
[False, False, True],
[False, False, False],
],
)
@pytest.mark.asyncio
async def test_nft_offer_with_fee(
@ -54,6 +54,8 @@ async def test_nft_offer_with_fee(
wallet_maker = wallet_node_0.wallet_state_manager.main_wallet
wallet_taker = wallet_node_1.wallet_state_manager.main_wallet
tx_config = dataclasses.replace(DEFAULT_TX_CONFIG, reuse_puzhash=reuse_puzhash)
maker_ph = await wallet_maker.get_new_puzzlehash()
taker_ph = await wallet_taker.get_new_puzzlehash()
token_ph = bytes32(token_bytes())
@ -103,7 +105,7 @@ async def test_nft_offer_with_fee(
]
)
sb = await nft_wallet_maker.generate_new_nft(metadata)
sb = await nft_wallet_maker.generate_new_nft(metadata, tx_config)
assert sb
await time_out_assert_not_none(20, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
@ -147,7 +149,7 @@ async def test_nft_offer_with_fee(
)
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_nft_for_xch, driver_dict, fee=maker_fee, reuse_puzhash=reuse_puzhash
offer_nft_for_xch, tx_config, driver_dict, fee=maker_fee
)
assert success is True
assert error is None
@ -159,8 +161,8 @@ async def test_nft_offer_with_fee(
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
peer,
tx_config,
fee=taker_fee,
reuse_puzhash=reuse_puzhash and not forwards_compat,
)
assert trade_take is not None
assert tx_records is not None
@ -242,7 +244,7 @@ async def test_nft_offer_with_fee(
)
else:
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_xch_for_nft, driver_dict_to_buy, fee=maker_fee
offer_xch_for_nft, tx_config, driver_dict_to_buy, fee=maker_fee
)
assert success is True
assert error is None
@ -251,7 +253,7 @@ async def test_nft_offer_with_fee(
taker_fee = uint64(1)
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer), peer, fee=taker_fee
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer), peer, tx_config, fee=taker_fee
)
assert trade_take is not None
@ -332,7 +334,7 @@ async def test_nft_offer_cancellations(self_hostname: str, two_wallet_nodes: Any
]
)
sb = await nft_wallet_maker.generate_new_nft(metadata)
sb = await nft_wallet_maker.generate_new_nft(metadata, DEFAULT_TX_CONFIG)
assert sb
await time_out_assert_not_none(20, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
@ -355,7 +357,7 @@ async def test_nft_offer_cancellations(self_hostname: str, two_wallet_nodes: Any
offer_nft_for_xch = {wallet_maker.id(): xch_request, nft_asset_id: -1}
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_nft_for_xch, driver_dict, fee=maker_fee
offer_nft_for_xch, DEFAULT_TX_CONFIG, driver_dict, fee=maker_fee
)
assert success is True
assert error is None
@ -366,7 +368,7 @@ async def test_nft_offer_cancellations(self_hostname: str, two_wallet_nodes: Any
cancel_fee = uint64(10)
txs = await trade_manager_maker.cancel_pending_offer_safely(trade_make.trade_id, fee=cancel_fee)
txs = await trade_manager_maker.cancel_pending_offer_safely(trade_make.trade_id, DEFAULT_TX_CONFIG, fee=cancel_fee)
await time_out_assert(20, get_trade_and_status, TradeStatus.PENDING_CANCEL, trade_manager_maker, trade_make)
await full_node_api.process_transaction_records(records=txs)
@ -445,7 +447,7 @@ async def test_nft_offer_with_metadata_update(self_hostname: str, two_wallet_nod
]
)
sb = await nft_wallet_maker.generate_new_nft(metadata)
sb = await nft_wallet_maker.generate_new_nft(metadata, DEFAULT_TX_CONFIG)
assert sb
await time_out_assert_not_none(20, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
@ -460,7 +462,9 @@ async def test_nft_offer_with_metadata_update(self_hostname: str, two_wallet_nod
url_to_add = "https://new_url.com"
key = "mu"
fee_for_update = uint64(10)
update_sb = await nft_wallet_maker.update_metadata(nft_to_update, key, url_to_add, fee=fee_for_update)
update_sb = await nft_wallet_maker.update_metadata(
nft_to_update, key, url_to_add, DEFAULT_TX_CONFIG, fee=fee_for_update
)
mempool_mgr = full_node_api.full_node.mempool_manager
await time_out_assert_not_none(20, mempool_mgr.get_spendbundle, update_sb.name()) # type: ignore
@ -487,7 +491,7 @@ async def test_nft_offer_with_metadata_update(self_hostname: str, two_wallet_nod
offer_nft_for_xch = {wallet_maker.id(): xch_request, nft_asset_id: -1}
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_nft_for_xch, driver_dict, fee=maker_fee
offer_nft_for_xch, DEFAULT_TX_CONFIG, driver_dict, fee=maker_fee
)
assert success is True
assert error is None
@ -497,7 +501,7 @@ async def test_nft_offer_with_metadata_update(self_hostname: str, two_wallet_nod
peer = wallet_node_1.get_full_node_peer()
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
Offer.from_bytes(trade_make.offer), peer, fee=taker_fee
Offer.from_bytes(trade_make.offer), peer, DEFAULT_TX_CONFIG, fee=taker_fee
)
assert trade_take is not None
@ -568,6 +572,8 @@ async def test_nft_offer_nft_for_cat(
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(token_ph))
await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_0, wallet_node_1], timeout=20)
tx_config = dataclasses.replace(DEFAULT_TX_CONFIG, reuse_puzhash=reuse_puzhash)
# Create NFT wallets and nfts for maker and taker
nft_wallet_maker = await NFTWallet.create_new_nft_wallet(
wallet_node_0.wallet_state_manager, wallet_maker, name="NFT WALLET 1"
@ -587,7 +593,7 @@ async def test_nft_offer_nft_for_cat(
]
)
sb = await nft_wallet_maker.generate_new_nft(metadata)
sb = await nft_wallet_maker.generate_new_nft(metadata, tx_config)
assert sb
await time_out_assert_not_none(20, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
@ -601,7 +607,11 @@ async def test_nft_offer_nft_for_cat(
cats_to_mint = 10000
async with wallet_node_0.wallet_state_manager.lock:
cat_wallet_maker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_0.wallet_state_manager, wallet_maker, {"identifier": "genesis_by_id"}, uint64(cats_to_mint)
wallet_node_0.wallet_state_manager,
wallet_maker,
{"identifier": "genesis_by_id"},
uint64(cats_to_mint),
tx_config,
)
await time_out_assert(20, mempool_not_empty, True, full_node_api)
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(token_ph))
@ -609,7 +619,11 @@ async def test_nft_offer_nft_for_cat(
async with wallet_node_1.wallet_state_manager.lock:
cat_wallet_taker: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node_1.wallet_state_manager, wallet_taker, {"identifier": "genesis_by_id"}, uint64(cats_to_mint)
wallet_node_1.wallet_state_manager,
wallet_taker,
{"identifier": "genesis_by_id"},
uint64(cats_to_mint),
tx_config,
)
await time_out_assert(20, mempool_not_empty, True, full_node_api)
@ -652,7 +666,7 @@ async def test_nft_offer_nft_for_cat(
).index
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_nft_for_cat, driver_dict, fee=maker_fee, reuse_puzhash=reuse_puzhash
offer_nft_for_cat, tx_config, driver_dict, fee=maker_fee
)
assert success is True
assert error is None
@ -664,8 +678,8 @@ async def test_nft_offer_nft_for_cat(
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
Offer.from_bytes(trade_make.offer),
peer,
tx_config,
fee=taker_fee,
reuse_puzhash=reuse_puzhash,
)
assert trade_take is not None
@ -736,7 +750,7 @@ async def test_nft_offer_nft_for_cat(
}
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_multi_cats_for_nft, driver_dict_to_buy, fee=maker_fee
offer_multi_cats_for_nft, tx_config, driver_dict_to_buy, fee=maker_fee
)
assert success is True
assert error is None
@ -745,7 +759,7 @@ async def test_nft_offer_nft_for_cat(
taker_fee = uint64(1)
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
Offer.from_bytes(trade_make.offer), peer, fee=taker_fee
Offer.from_bytes(trade_make.offer), peer, tx_config, fee=taker_fee
)
assert trade_take is not None
@ -833,7 +847,7 @@ async def test_nft_offer_nft_for_nft(self_hostname: str, two_wallet_nodes: Any,
]
)
sb = await nft_wallet_maker.generate_new_nft(metadata)
sb = await nft_wallet_maker.generate_new_nft(metadata, DEFAULT_TX_CONFIG)
assert sb
await time_out_assert_not_none(20, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
@ -843,7 +857,7 @@ async def test_nft_offer_nft_for_nft(self_hostname: str, two_wallet_nodes: Any,
("h", "0xD4584AD463139FA8C0D9F68F4B59F183"),
]
)
sb_2 = await nft_wallet_taker.generate_new_nft(metadata_2)
sb_2 = await nft_wallet_taker.generate_new_nft(metadata_2, DEFAULT_TX_CONFIG)
assert sb_2
await time_out_assert_not_none(20, full_node_api.full_node.mempool_manager.get_spendbundle, sb_2.name())
@ -875,7 +889,7 @@ async def test_nft_offer_nft_for_nft(self_hostname: str, two_wallet_nodes: Any,
offer_nft_for_nft = {nft_to_take_asset_id: 1, nft_to_offer_asset_id: -1}
success, trade_make, error = await trade_manager_maker.create_offer_for_ids(
offer_nft_for_nft, driver_dict, fee=maker_fee
offer_nft_for_nft, DEFAULT_TX_CONFIG, driver_dict, fee=maker_fee
)
assert success is True
assert error is None
@ -885,7 +899,7 @@ async def test_nft_offer_nft_for_nft(self_hostname: str, two_wallet_nodes: Any,
peer = wallet_node_1.get_full_node_peer()
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
Offer.from_bytes(trade_make.offer), peer, fee=taker_fee
Offer.from_bytes(trade_make.offer), peer, DEFAULT_TX_CONFIG, fee=taker_fee
)
assert trade_take is not None

View File

@ -24,6 +24,7 @@ from chia.wallet.did_wallet.did_wallet import DIDWallet
from chia.wallet.nft_wallet.nft_wallet import NFTWallet
from chia.wallet.util.address_type import AddressType
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet import CHIP_0002_SIGN_MESSAGE_PREFIX
from chia.wallet.wallet_state_manager import WalletStateManager
@ -132,7 +133,7 @@ async def test_nft_wallet_creation_automatically(self_hostname: str, two_wallet_
]
)
sb = await nft_wallet_0.generate_new_nft(metadata)
sb = await nft_wallet_0.generate_new_nft(metadata, DEFAULT_TX_CONFIG)
assert sb
await time_out_assert_not_none(30, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
@ -143,7 +144,9 @@ async def test_nft_wallet_creation_automatically(self_hostname: str, two_wallet_
coins = await nft_wallet_0.get_current_nfts()
assert len(coins) == 1, "nft not generated"
txs = await nft_wallet_0.generate_signed_transaction([uint64(coins[0].coin.amount)], [ph1], coins={coins[0].coin})
txs = await nft_wallet_0.generate_signed_transaction(
[uint64(coins[0].coin.amount)], [ph1], DEFAULT_TX_CONFIG, coins={coins[0].coin}
)
assert len(txs) == 1
assert txs[0].spend_bundle is not None
await wallet_node_0.wallet_state_manager.add_pending_transaction(txs[0])
@ -227,7 +230,7 @@ async def test_nft_wallet_creation_and_transfer(self_hostname: str, two_wallet_n
await time_out_assert(30, wallet_0.get_unconfirmed_balance, 2000000000000)
await time_out_assert(30, wallet_0.get_confirmed_balance, 2000000000000)
sb = await nft_wallet_0.generate_new_nft(metadata)
sb = await nft_wallet_0.generate_new_nft(metadata, DEFAULT_TX_CONFIG)
assert sb
# ensure hints are generated
assert compute_memos(sb)
@ -261,7 +264,7 @@ async def test_nft_wallet_creation_and_transfer(self_hostname: str, two_wallet_n
await time_out_assert(10, wallet_0.get_unconfirmed_balance, 4000000000000 - 1)
await time_out_assert(10, wallet_0.get_confirmed_balance, 4000000000000)
sb = await nft_wallet_0.generate_new_nft(metadata)
sb = await nft_wallet_0.generate_new_nft(metadata, DEFAULT_TX_CONFIG)
assert sb
# ensure hints are generated
assert compute_memos(sb)
@ -278,7 +281,9 @@ async def test_nft_wallet_creation_and_transfer(self_hostname: str, two_wallet_n
nft_wallet_1 = await NFTWallet.create_new_nft_wallet(
wallet_node_1.wallet_state_manager, wallet_1, name="NFT WALLET 2"
)
txs = await nft_wallet_0.generate_signed_transaction([uint64(coins[1].coin.amount)], [ph1], coins={coins[1].coin})
txs = await nft_wallet_0.generate_signed_transaction(
[uint64(coins[1].coin.amount)], [ph1], DEFAULT_TX_CONFIG, coins={coins[1].coin}
)
assert len(txs) == 1
assert txs[0].spend_bundle is not None
await wallet_node_0.wallet_state_manager.add_pending_transaction(txs[0])
@ -298,7 +303,9 @@ async def test_nft_wallet_creation_and_transfer(self_hostname: str, two_wallet_n
await time_out_assert(30, wallet_1.get_pending_change_balance, 0)
# Send it back to original owner
txs = await nft_wallet_1.generate_signed_transaction([uint64(coins[0].coin.amount)], [ph], coins={coins[0].coin})
txs = await nft_wallet_1.generate_signed_transaction(
[uint64(coins[0].coin.amount)], [ph], DEFAULT_TX_CONFIG, coins={coins[0].coin}
)
assert len(txs) == 1
assert txs[0].spend_bundle is not None
await wallet_node_1.wallet_state_manager.add_pending_transaction(txs[0])
@ -988,7 +995,7 @@ async def test_nft_transfer_nft_with_did(self_hostname: str, two_wallet_nodes: A
assert len(wallet_1.wallet_state_manager.wallets) == 1, "NFT wallet shouldn't exist yet"
assert len(wallet_0.wallet_state_manager.wallets) == 3
# transfer DID to the other wallet
tx = await did_wallet.transfer_did(ph1, uint64(0), True)
tx = await did_wallet.transfer_did(ph1, uint64(0), True, DEFAULT_TX_CONFIG)
assert tx
for i in range(1, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph1))

View File

@ -53,6 +53,7 @@ from chia.wallet.util.address_type import AddressType
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.query_filter import AmountFilter, HashFilter, TransactionTypeFilter
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import DEFAULT_COIN_SELECTION_CONFIG, DEFAULT_TX_CONFIG
from chia.wallet.util.wallet_types import CoinType, WalletType
from chia.wallet.wallet import Wallet
from chia.wallet.wallet_coin_record import WalletCoinRecord
@ -302,7 +303,7 @@ async def test_send_transaction(wallet_rpc_environment: WalletRpcTestEnvironment
addr = encode_puzzle_hash(await wallet_2.get_new_puzzlehash(), "txch")
tx_amount = uint64(15600000)
with pytest.raises(ValueError):
await client.send_transaction(1, uint64(100000000000000001), addr)
await client.send_transaction(1, uint64(100000000000000001), addr, DEFAULT_TX_CONFIG)
# Tests sending a basic transaction
tx = await client.send_transaction(
@ -310,8 +311,14 @@ async def test_send_transaction(wallet_rpc_environment: WalletRpcTestEnvironment
tx_amount,
addr,
memos=["this is a basic tx"],
excluded_amounts=[uint64(250000000000)],
excluded_coin_ids=[bytes32([0] * 32).hex()],
tx_config=dataclasses.replace(
DEFAULT_TX_CONFIG,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG,
excluded_coin_amounts=[uint64(250000000000)],
excluded_coin_ids=[bytes32([0] * 32)],
),
),
)
transaction_id = tx.name
@ -348,6 +355,7 @@ async def test_push_transactions(wallet_rpc_environment: WalletRpcTestEnvironmen
tx = await client.create_signed_transaction(
outputs,
tx_config=DEFAULT_TX_CONFIG,
fee=uint64(100),
)
@ -371,7 +379,7 @@ async def test_get_balance(wallet_rpc_environment: WalletRpcTestEnvironment):
await full_node_api.farm_blocks_to_wallet(2, wallet)
async with wallet_node.wallet_state_manager.lock:
cat_wallet: CATWallet = await CATWallet.create_new_cat_wallet(
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(100)
wallet_node.wallet_state_manager, wallet, {"identifier": "genesis_by_id"}, uint64(100), DEFAULT_TX_CONFIG
)
await assert_get_balance(wallet_rpc_client, wallet_node, wallet)
await assert_get_balance(wallet_rpc_client, wallet_node, cat_wallet)
@ -413,6 +421,7 @@ async def test_get_farmed_amount_with_fee(wallet_rpc_environment: WalletRpcTestE
tx = await wallet.generate_signed_transaction(
amount=uint64(5),
puzzle_hash=bytes32([0] * 32),
tx_config=DEFAULT_TX_CONFIG,
fee=uint64(fee_amount),
)
await wallet.push_transaction(tx)
@ -498,7 +507,9 @@ async def test_create_signed_transaction(
selected_coin = None
if select_coin:
selected_coin = await wallet_1_rpc.select_coins(amount=amount_total, wallet_id=wallet_id)
selected_coin = await wallet_1_rpc.select_coins(
amount=amount_total, wallet_id=wallet_id, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
)
assert len(selected_coin) == 1
tx = await wallet_1_rpc.create_signed_transaction(
@ -507,7 +518,13 @@ async def test_create_signed_transaction(
fee=amount_fee,
wallet_id=wallet_id,
# shouldn't actually block it
excluded_amounts=[uint64(selected_coin[0].amount)] if selected_coin is not None else [],
tx_config=dataclasses.replace(
DEFAULT_TX_CONFIG,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG,
excluded_coin_amounts=[uint64(selected_coin[0].amount)] if selected_coin is not None else [],
),
),
)
change_expected = not selected_coin or selected_coin[0].amount - amount_total > 0
assert_tx_amounts(tx, outputs, amount_fee=amount_fee, change_expected=change_expected, is_cat=is_cat)
@ -563,7 +580,7 @@ async def test_create_signed_transaction_with_coin_announcement(wallet_rpc_envir
]
outputs = await create_tx_outputs(wallet_2, [(signed_tx_amount, None)])
tx_res: TransactionRecord = await client.create_signed_transaction(
outputs, coin_announcements=tx_coin_announcements
outputs, tx_config=DEFAULT_TX_CONFIG, coin_announcements=tx_coin_announcements
)
assert_tx_amounts(tx_res, outputs, amount_fee=uint64(0), change_expected=True)
await assert_push_tx_error(client_node, tx_res)
@ -593,7 +610,9 @@ async def test_create_signed_transaction_with_puzzle_announcement(wallet_rpc_env
),
]
outputs = await create_tx_outputs(wallet_2, [(signed_tx_amount, None)])
tx_res = await client.create_signed_transaction(outputs, puzzle_announcements=tx_puzzle_announcements)
tx_res = await client.create_signed_transaction(
outputs, tx_config=DEFAULT_TX_CONFIG, puzzle_announcements=tx_puzzle_announcements
)
assert_tx_amounts(tx_res, outputs, amount_fee=uint64(0), change_expected=True)
await assert_push_tx_error(client_node, tx_res)
@ -608,11 +627,21 @@ async def test_create_signed_transaction_with_excluded_coins(wallet_rpc_environm
await generate_funds(full_node_api, env.wallet_1)
async def it_does_not_include_the_excluded_coins() -> None:
selected_coins = await wallet_1_rpc.select_coins(amount=250000000000, wallet_id=1)
selected_coins = await wallet_1_rpc.select_coins(
amount=250000000000, wallet_id=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
)
assert len(selected_coins) == 1
outputs = await create_tx_outputs(wallet_1, [(uint64(250000000000), None)])
tx = await wallet_1_rpc.create_signed_transaction(outputs, excluded_coins=selected_coins)
tx = await wallet_1_rpc.create_signed_transaction(
outputs,
dataclasses.replace(
DEFAULT_TX_CONFIG,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[c.name() for c in selected_coins]
),
),
)
assert len(tx.removals) == 1
assert tx.removals[0] != selected_coins[0]
@ -620,12 +649,22 @@ async def test_create_signed_transaction_with_excluded_coins(wallet_rpc_environm
await assert_push_tx_error(full_node_rpc, tx)
async def it_throws_an_error_when_all_spendable_coins_are_excluded() -> None:
selected_coins = await wallet_1_rpc.select_coins(amount=1750000000000, wallet_id=1)
selected_coins = await wallet_1_rpc.select_coins(
amount=1750000000000, wallet_id=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
)
assert len(selected_coins) == 1
outputs = await create_tx_outputs(wallet_1, [(uint64(1750000000000), None)])
with pytest.raises(ValueError):
await wallet_1_rpc.create_signed_transaction(outputs, excluded_coins=selected_coins)
await wallet_1_rpc.create_signed_transaction(
outputs,
dataclasses.replace(
DEFAULT_TX_CONFIG,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[c.name() for c in selected_coins]
),
),
)
await it_does_not_include_the_excluded_coins()
await it_throws_an_error_when_all_spendable_coins_are_excluded()
@ -652,6 +691,7 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
wallet_id=1,
amount=uint64(500),
address=encode_puzzle_hash(wallet_2_puzhash, "txch"),
tx_config=DEFAULT_TX_CONFIG,
fee=uint64(0),
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
)
@ -662,6 +702,7 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
wallet_id=1,
amount=uint64(500),
address=encode_puzzle_hash(wallet_1_puzhash, "txch"),
tx_config=DEFAULT_TX_CONFIG,
fee=uint64(0),
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
)
@ -744,7 +785,9 @@ async def test_send_transaction_multi(wallet_rpc_environment: WalletRpcTestEnvir
generated_funds = await generate_funds(full_node_api, env.wallet_1)
removals = await client.select_coins(1750000000000, wallet_id=1) # we want a coin that won't be selected by default
removals = await client.select_coins(
1750000000000, wallet_id=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
) # we want a coin that won't be selected by default
outputs = await create_tx_outputs(wallet_2, [(uint64(1), ["memo_1"]), (uint64(2), ["memo_2"])])
amount_outputs = sum(output["amount"] for output in outputs)
amount_fee = uint64(amount_outputs + 1)
@ -752,6 +795,7 @@ async def test_send_transaction_multi(wallet_rpc_environment: WalletRpcTestEnvir
send_tx_res: TransactionRecord = await client.send_transaction_multi(
1,
outputs,
DEFAULT_TX_CONFIG,
coins=removals,
fee=amount_fee,
)
@ -806,7 +850,7 @@ async def test_get_transactions(wallet_rpc_environment: WalletRpcTestEnvironment
# Test RELEVANCE
await client.send_transaction(
1, uint64(1), encode_puzzle_hash(await wallet.get_new_puzzlehash(), "txch")
1, uint64(1), encode_puzzle_hash(await wallet.get_new_puzzlehash(), "txch"), DEFAULT_TX_CONFIG
) # Create a pending tx
all_transactions = await client.get_transactions(1, sort_key=SortKey.RELEVANCE)
@ -823,7 +867,7 @@ async def test_get_transactions(wallet_rpc_environment: WalletRpcTestEnvironment
# Test get_transactions to address
ph_by_addr = await wallet.get_new_puzzlehash()
await client.send_transaction(1, uint64(1), encode_puzzle_hash(ph_by_addr, "txch"))
await client.send_transaction(1, uint64(1), encode_puzzle_hash(ph_by_addr, "txch"), DEFAULT_TX_CONFIG)
await client.farm_block(encode_puzzle_hash(ph_by_addr, "txch"))
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
tx_for_address = await client.get_transactions(1, to_address=encode_puzzle_hash(ph_by_addr, "txch"))
@ -965,14 +1009,20 @@ async def test_cat_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
with pytest.raises(ValueError):
await client.cat_spend(
cat_0_id,
dataclasses.replace(
DEFAULT_TX_CONFIG,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG,
excluded_coin_amounts=[uint64(20)],
excluded_coin_ids=[bytes32([0] * 32)],
),
),
uint64(4),
addr_1,
uint64(0),
["the cat memo"],
excluded_amounts=[uint64(20)],
excluded_coin_ids=[bytes32([0] * 32).hex()],
)
tx_res = await client.cat_spend(cat_0_id, uint64(4), addr_1, uint64(0), ["the cat memo"])
tx_res = await client.cat_spend(cat_0_id, DEFAULT_TX_CONFIG, uint64(4), addr_1, uint64(0), ["the cat memo"])
assert tx_res.wallet_id == cat_0_id
spend_bundle = tx_res.spend_bundle
assert spend_bundle is not None
@ -982,7 +1032,7 @@ async def test_cat_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
await farm_transaction_block(full_node_api, wallet_node)
# Test CAT spend with a fee
tx_res = await client.cat_spend(cat_0_id, uint64(1), addr_1, uint64(5_000_000), ["the cat memo"])
tx_res = await client.cat_spend(cat_0_id, DEFAULT_TX_CONFIG, uint64(1), addr_1, uint64(5_000_000), ["the cat memo"])
assert tx_res.wallet_id == cat_0_id
spend_bundle = tx_res.spend_bundle
assert spend_bundle is not None
@ -990,8 +1040,12 @@ async def test_cat_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
await farm_transaction(full_node_api, wallet_node, spend_bundle)
# Test CAT spend with a fee and pre-specified removals / coins
removals = await client.select_coins(amount=uint64(2), wallet_id=cat_0_id)
tx_res = await client.cat_spend(cat_0_id, uint64(1), addr_1, uint64(5_000_000), ["the cat memo"], removals=removals)
removals = await client.select_coins(
amount=uint64(2), wallet_id=cat_0_id, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
)
tx_res = await client.cat_spend(
cat_0_id, DEFAULT_TX_CONFIG, uint64(1), addr_1, uint64(5_000_000), ["the cat memo"], removals=removals
)
assert tx_res.wallet_id == cat_0_id
spend_bundle = tx_res.spend_bundle
assert spend_bundle is not None
@ -1010,7 +1064,9 @@ async def test_cat_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
await time_out_assert(20, get_confirmed_balance, 6, client_2, cat_1_id)
# Test CAT coin selection
selected_coins = await client.select_coins(amount=1, wallet_id=cat_0_id)
selected_coins = await client.select_coins(
amount=1, wallet_id=cat_0_id, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
)
assert len(selected_coins) > 0
@ -1041,7 +1097,9 @@ async def test_offer_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment)
await wallet_2_rpc.create_wallet_for_existing_cat(cat_asset_id)
wallet_2_address = await wallet_2_rpc.get_next_address(cat_wallet_id, False)
adds = [{"puzzle_hash": decode_puzzle_hash(wallet_2_address), "amount": uint64(4), "memos": ["the cat memo"]}]
tx_res = await wallet_1_rpc.send_transaction_multi(cat_wallet_id, additions=adds, fee=uint64(0))
tx_res = await wallet_1_rpc.send_transaction_multi(
cat_wallet_id, additions=adds, tx_config=DEFAULT_TX_CONFIG, fee=uint64(0)
)
spend_bundle = tx_res.spend_bundle
assert spend_bundle is not None
await farm_transaction(full_node_api, wallet_node, spend_bundle)
@ -1055,7 +1113,7 @@ async def test_offer_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment)
await wallet_1_rpc.get_coin_records_by_names([a.name() for a in spend_bundle.additions() if a.amount == 4])
# Create an offer of 5 chia for one CAT
offer, trade_record = await wallet_1_rpc.create_offer_for_ids(
{uint32(1): -5, cat_asset_id.hex(): 1}, validate_only=True
{uint32(1): -5, cat_asset_id.hex(): 1}, DEFAULT_TX_CONFIG, validate_only=True
)
all_offers = await wallet_1_rpc.get_all_offers()
assert len(all_offers) == 0
@ -1065,6 +1123,7 @@ async def test_offer_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment)
offer, trade_record = await wallet_1_rpc.create_offer_for_ids(
{uint32(1): -5, cat_asset_id.hex(): 1},
DEFAULT_TX_CONFIG,
driver_dict=driver_dict,
fee=uint64(1),
)
@ -1085,7 +1144,7 @@ async def test_offer_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment)
assert TradeStatus(all_offers[0].status) == TradeStatus.PENDING_ACCEPT
assert all_offers[0].offer == bytes(offer)
trade_record = await wallet_2_rpc.take_offer(offer, fee=uint64(1))
trade_record = await wallet_2_rpc.take_offer(offer, DEFAULT_TX_CONFIG, fee=uint64(1))
assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CONFIRM
await wallet_1_rpc.cancel_offer(offer.name(), secure=False)
@ -1100,7 +1159,7 @@ async def test_offer_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment)
assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CANCEL
new_offer, new_trade_record = await wallet_1_rpc.create_offer_for_ids(
{uint32(1): -5, cat_wallet_id: 1}, fee=uint64(1)
{uint32(1): -5, cat_wallet_id: 1}, DEFAULT_TX_CONFIG, fee=uint64(1)
)
all_offers = await wallet_1_rpc.get_all_offers()
assert len(all_offers) == 2
@ -1172,7 +1231,7 @@ async def test_get_coin_records_by_names(wallet_rpc_environment: WalletRpcTestEn
generated_funds = await generate_funds(full_node_api, env.wallet_1, 5)
address = encode_puzzle_hash(await env.wallet_1.wallet.get_new_puzzlehash(), "txch")
# Spend half of it back to the same wallet get some spent coins in the wallet
tx = await client.send_transaction(1, uint64(generated_funds / 2), address)
tx = await client.send_transaction(1, uint64(generated_funds / 2), address, DEFAULT_TX_CONFIG)
assert tx.spend_bundle is not None
await time_out_assert(20, tx_in_mempool, True, client, tx.name)
await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
@ -1261,7 +1320,7 @@ async def test_did_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
await farm_transaction_block(full_node_api, wallet_1_node)
# Update recovery list
res = await wallet_1_rpc.update_did_recovery_list(did_wallet_id_0, [did_id_0], 1)
res = await wallet_1_rpc.update_did_recovery_list(did_wallet_id_0, [did_id_0], 1, DEFAULT_TX_CONFIG)
assert res["success"]
res = await wallet_1_rpc.get_did_recovery_list(did_wallet_id_0)
assert res["num_required"] == 1
@ -1272,8 +1331,8 @@ async def test_did_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
# Update metadata
with pytest.raises(ValueError, match="wallet id 1 is of type Wallet but type DIDWallet is required"):
await wallet_1_rpc.update_did_metadata(wallet_1_id, {"Twitter": "Https://test"})
res = await wallet_1_rpc.update_did_metadata(did_wallet_id_0, {"Twitter": "Https://test"})
await wallet_1_rpc.update_did_metadata(wallet_1_id, {"Twitter": "Https://test"}, DEFAULT_TX_CONFIG)
res = await wallet_1_rpc.update_did_metadata(did_wallet_id_0, {"Twitter": "Https://test"}, DEFAULT_TX_CONFIG)
assert res["success"]
await farm_transaction_block(full_node_api, wallet_1_node)
@ -1286,7 +1345,7 @@ async def test_did_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
# Transfer DID
addr = encode_puzzle_hash(await wallet_2.get_new_puzzlehash(), "txch")
res = await wallet_1_rpc.did_transfer_did(did_wallet_id_0, addr, 0, True)
res = await wallet_1_rpc.did_transfer_did(did_wallet_id_0, addr, 0, True, DEFAULT_TX_CONFIG)
assert res["success"]
await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
@ -1333,6 +1392,7 @@ async def test_nft_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
None,
"0xD4584AD463139FA8C0D9F68F4B59F185",
["https://www.chia.net/img/branding/chia-logo.svg"],
DEFAULT_TX_CONFIG,
)
assert res["success"]
@ -1362,7 +1422,7 @@ async def test_nft_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
assert nft_info["nft_coin_id"][2:] == (await nft_wallet.get_current_nfts())[0].coin.name().hex()
addr = encode_puzzle_hash(await wallet_2.get_new_puzzlehash(), "txch")
res = await wallet_1_rpc.transfer_nft(nft_wallet_id, nft_id, addr, 0)
res = await wallet_1_rpc.transfer_nft(nft_wallet_id, nft_id, addr, 0, DEFAULT_TX_CONFIG)
assert res["success"]
await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
await farm_transaction_block(full_node_api, wallet_1_node)
@ -1426,7 +1486,7 @@ async def test_key_and_address_endpoints(wallet_rpc_environment: WalletRpcTestEn
addr = encode_puzzle_hash(ph, "txch")
tx_amount = uint64(15600000)
created_tx = await client.send_transaction(1, tx_amount, addr)
created_tx = await client.send_transaction(1, tx_amount, addr, DEFAULT_TX_CONFIG)
await time_out_assert(20, tx_in_mempool, True, client, created_tx.name)
assert len(await wallet.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(1)) == 1
@ -1522,7 +1582,7 @@ async def test_key_and_address_endpoints(wallet_rpc_environment: WalletRpcTestEn
assert await get_unconfirmed_balance(client, int(wallets[0]["id"])) == 0
with pytest.raises(ValueError):
await client.send_transaction(wallets[0]["id"], uint64(100), addr)
await client.send_transaction(wallets[0]["id"], uint64(100), addr, DEFAULT_TX_CONFIG)
# Delete all keys
await client.delete_all_keys()
@ -1547,7 +1607,7 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
for tx_amount in tx_amounts:
funds -= tx_amount
# create coins for tests
tx = await client.send_transaction(1, tx_amount, addr)
tx = await client.send_transaction(1, tx_amount, addr, DEFAULT_TX_CONFIG)
spend_bundle = tx.spend_bundle
assert spend_bundle is not None
for coin in spend_bundle.additions():
@ -1559,13 +1619,21 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
await time_out_assert(20, get_confirmed_balance, funds, client, 1)
# test min coin amount
min_coins: List[Coin] = await client_2.select_coins(amount=1000, wallet_id=1, min_coin_amount=uint64(1001))
min_coins: List[Coin] = await client_2.select_coins(
amount=1000,
wallet_id=1,
coin_selection_config=dataclasses.replace(DEFAULT_COIN_SELECTION_CONFIG, min_coin_amount=uint64(1001)),
)
assert min_coins is not None
assert len(min_coins) == 1 and min_coins[0].amount == uint64(10000)
# test max coin amount
max_coins: List[Coin] = await client_2.select_coins(
amount=2000, wallet_id=1, min_coin_amount=uint64(999), max_coin_amount=uint64(9999)
amount=2000,
wallet_id=1,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG, min_coin_amount=uint64(999), max_coin_amount=uint64(9999)
),
)
assert max_coins is not None
assert len(max_coins) == 2 and max_coins[0].amount == uint64(1000)
@ -1573,7 +1641,9 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
# test excluded coin amounts
non_1000_amt: int = sum(a for a in tx_amounts if a != 1000)
excluded_amt_coins: List[Coin] = await client_2.select_coins(
amount=non_1000_amt, wallet_id=1, excluded_amounts=[uint64(1000)]
amount=non_1000_amt,
wallet_id=1,
coin_selection_config=dataclasses.replace(DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_amounts=[uint64(1000)]),
)
assert excluded_amt_coins is not None
assert (
@ -1583,23 +1653,47 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
# test excluded coins
with pytest.raises(ValueError):
await client_2.select_coins(amount=5000, wallet_id=1, excluded_coins=min_coins)
excluded_test = await client_2.select_coins(amount=1300, wallet_id=1, excluded_coins=coin_300)
await client_2.select_coins(
amount=5000,
wallet_id=1,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[c.name() for c in min_coins]
),
)
excluded_test = await client_2.select_coins(
amount=1300,
wallet_id=1,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[c.name() for c in coin_300]
),
)
assert len(excluded_test) == 2
for coin in excluded_test:
assert coin != coin_300[0]
# test get coins
all_coins, _, _ = await client_2.get_spendable_coins(
wallet_id=1, excluded_coin_ids=[c.name().hex() for c in excluded_amt_coins]
wallet_id=1,
coin_selection_config=dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[c.name() for c in excluded_amt_coins]
),
)
assert excluded_amt_coins not in all_coins
all_coins, _, _ = await client_2.get_spendable_coins(wallet_id=1, excluded_amounts=[uint64(1000)])
all_coins, _, _ = await client_2.get_spendable_coins(
wallet_id=1,
coin_selection_config=dataclasses.replace(DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_amounts=[uint64(1000)]),
)
assert excluded_amt_coins not in all_coins
all_coins_2, _, _ = await client_2.get_spendable_coins(wallet_id=1, max_coin_amount=uint64(999))
all_coins_2, _, _ = await client_2.get_spendable_coins(
wallet_id=1,
coin_selection_config=dataclasses.replace(DEFAULT_COIN_SELECTION_CONFIG, max_coin_amount=uint64(999)),
)
assert all_coins_2[0].coin == coin_300[0]
with pytest.raises(ValueError): # validate fail on invalid coin id.
await client_2.get_spendable_coins(wallet_id=1, excluded_coin_ids=["a"])
await client_2.get_spendable_coins(
wallet_id=1,
coin_selection_config=dataclasses.replace(DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[b"a"]),
)
@pytest.mark.asyncio
@ -2005,7 +2099,12 @@ async def test_set_wallet_resync_on_startup(wallet_rpc_environment: WalletRpcTes
nft_wallet_id = nft_wallet["wallet_id"]
address = await wc.get_next_address(env.wallet_1.wallet.id(), True)
await wc.mint_nft(
nft_wallet_id, royalty_address=address, target_address=address, hash="deadbeef", uris=["http://test.nft"]
nft_wallet_id,
tx_config=DEFAULT_TX_CONFIG,
royalty_address=address,
target_address=address,
hash="deadbeef",
uris=["http://test.nft"],
)
await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
await farm_transaction_block(full_node_api, env.wallet_1.node)
@ -2140,7 +2239,7 @@ async def test_cat_spend_run_tail(wallet_rpc_environment: WalletRpcTestEnvironme
)
tx_amount = uint64(100)
tx = await client.send_transaction(1, tx_amount, addr)
tx = await client.send_transaction(1, tx_amount, addr, DEFAULT_TX_CONFIG)
transaction_id = tx.name
spend_bundle = tx.spend_bundle
assert spend_bundle is not None
@ -2183,6 +2282,7 @@ async def test_cat_spend_run_tail(wallet_rpc_environment: WalletRpcTestEnvironme
tx = await client.cat_spend(
cat_wallet_id,
amount=uint64(0),
tx_config=DEFAULT_TX_CONFIG,
inner_address=encode_puzzle_hash(our_ph, "txch"),
cat_discrepancy=(tx_amount * -1, Program.to(None), Program.to(None)),
)

View File

@ -25,6 +25,7 @@ from chia.types.condition_with_args import ConditionWithArgs
from chia.types.peer_info import PeerInfo
from chia.types.spend_bundle import SpendBundle
from chia.util.ints import uint16, uint32, uint64
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.wallet import Wallet
from chia.wallet.wallet_state_manager import WalletStateManager
from tests.connection_utils import add_dummy_connection
@ -185,7 +186,7 @@ class TestSimpleSyncProtocol:
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
tx_record = await wallet.generate_signed_transaction(uint64(10), puzzle_hash, uint64(0))
tx_record = await wallet.generate_signed_transaction(uint64(10), puzzle_hash, DEFAULT_TX_CONFIG, uint64(0))
assert len(tx_record.spend_bundle.removals()) == 1
spent_coin = tx_record.spend_bundle.removals()[0]
assert spent_coin.puzzle_hash == puzzle_hash
@ -199,7 +200,9 @@ class TestSimpleSyncProtocol:
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
tx_record = await wallet.generate_signed_transaction(uint64(10), SINGLETON_LAUNCHER_HASH, uint64(0))
tx_record = await wallet.generate_signed_transaction(
uint64(10), SINGLETON_LAUNCHER_HASH, DEFAULT_TX_CONFIG, uint64(0)
)
await wallet.push_transaction(tx_record)
await full_node_api.process_transaction_records(records=[tx_record])
@ -207,7 +210,7 @@ class TestSimpleSyncProtocol:
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
# Send a transaction to make sure the wallet is still running
tx_record = await wallet.generate_signed_transaction(uint64(10), junk_ph, uint64(0))
tx_record = await wallet.generate_signed_transaction(uint64(10), junk_ph, DEFAULT_TX_CONFIG, uint64(0))
await wallet.push_transaction(tx_record)
await full_node_api.process_transaction_records(records=[tx_record])
@ -267,7 +270,9 @@ class TestSimpleSyncProtocol:
coins = set()
coins.add(coin_to_spend)
tx_record = await standard_wallet.generate_signed_transaction(uint64(10), puzzle_hash, uint64(0), coins=coins)
tx_record = await standard_wallet.generate_signed_transaction(
uint64(10), puzzle_hash, DEFAULT_TX_CONFIG, uint64(0), coins=coins
)
await standard_wallet.push_transaction(tx_record)
await full_node_api.process_transaction_records(records=[tx_record])
@ -287,7 +292,9 @@ class TestSimpleSyncProtocol:
# Test getting notification for coin that is about to be created
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
tx_record = await standard_wallet.generate_signed_transaction(uint64(10), puzzle_hash, uint64(0))
tx_record = await standard_wallet.generate_signed_transaction(
uint64(10), puzzle_hash, DEFAULT_TX_CONFIG, uint64(0)
)
tx_record.spend_bundle.additions()

View File

@ -30,6 +30,7 @@ from chia.wallet.nft_wallet.nft_wallet import NFTWallet
from chia.wallet.payment import Payment
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.util.wallet_sync_utils import PeerRequestException
from chia.wallet.wallet_coin_record import WalletCoinRecord
from chia.wallet.wallet_weight_proof_handler import get_wp_fork_point
@ -513,7 +514,9 @@ class TestWalletSync:
payees.append(Payment(payee_ph, uint64(i + 100)))
payees.append(Payment(payee_ph, uint64(i + 200)))
tx: TransactionRecord = await wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
@ -724,7 +727,9 @@ class TestWalletSync:
payees.append(Payment(payee_ph, uint64(dust_value)))
# construct and send tx
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
# advance the chain and sync both wallets
@ -784,7 +789,9 @@ class TestWalletSync:
# This greatly speeds up the overall process
if dust_remaining % 100 == 0 and dust_remaining != new_dust:
# construct and send tx
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
last_block: Optional[BlockRecord] = full_node_api.full_node.blockchain.get_peak()
@ -797,7 +804,9 @@ class TestWalletSync:
# Only need to create tx if there was new dust to be added
if new_dust >= 1:
# construct and send tx
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
# advance the chain and sync both wallets
@ -844,7 +853,9 @@ class TestWalletSync:
payees.append(Payment(payee_ph, uint64(xch_spam_amount)))
# construct and send tx
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
# advance the chain and sync both wallets
@ -883,7 +894,9 @@ class TestWalletSync:
payees.append(Payment(payee_ph, uint64(dust_value)))
# construct and send tx
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
# advance the chain and sync both wallets
@ -942,7 +955,9 @@ class TestWalletSync:
large_dust_balance += dust_value
# construct and send tx
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
# advance the chain and sync both wallets
@ -978,7 +993,9 @@ class TestWalletSync:
payees = [Payment(payee_ph, uint64(balance))]
# construct and send tx
tx: TransactionRecord = await dust_wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await dust_wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
# advance the chain and sync both wallets
@ -1021,7 +1038,9 @@ class TestWalletSync:
# This greatly speeds up the overall process
if coins_remaining % 100 == 0 and coins_remaining != spam_filter_after_n_txs:
# construct and send tx
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
last_block: Optional[BlockRecord] = full_node_api.full_node.blockchain.get_peak()
@ -1032,7 +1051,9 @@ class TestWalletSync:
coins_remaining -= 1
# construct and send tx
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await farm_wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
# advance the chain and sync both wallets
@ -1061,7 +1082,9 @@ class TestWalletSync:
payees = [Payment(payee_ph, uint64(1))]
# construct and send tx
tx: TransactionRecord = await dust_wallet.generate_signed_transaction(uint64(0), ph, primaries=payees)
tx: TransactionRecord = await dust_wallet.generate_signed_transaction(
uint64(0), ph, DEFAULT_TX_CONFIG, primaries=payees
)
await full_node_api.send_transaction(SendTransaction(tx.spend_bundle))
# advance the chain and sync both wallets
@ -1137,6 +1160,7 @@ class TestWalletSync:
txs = await farm_nft_wallet.generate_signed_transaction(
[uint64(nft_coins[0].coin.amount)],
[dust_ph],
DEFAULT_TX_CONFIG,
coins={nft_coins[0].coin},
)
assert len(txs) == 1
@ -1273,7 +1297,9 @@ class TestWalletSync:
await time_out_assert(30, wallet.get_confirmed_balance, 2_000_000_000_000)
tx = await wallet.generate_signed_transaction(1_000_000_000_000, bytes32([0] * 32), memos=[ph])
tx = await wallet.generate_signed_transaction(
1_000_000_000_000, bytes32([0] * 32), DEFAULT_TX_CONFIG, memos=[ph]
)
await wallet_node.wallet_state_manager.add_pending_transaction(tx)
async def tx_in_mempool():

View File

@ -1,5 +1,6 @@
from __future__ import annotations
import dataclasses
import logging
import time
from random import randrange
@ -19,6 +20,7 @@ from chia.wallet.coin_selection import (
select_smallest_coin_over_target,
sum_largest_coins,
)
from chia.wallet.util.tx_config import DEFAULT_COIN_SELECTION_CONFIG
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.wallet_coin_record import WalletCoinRecord
@ -87,7 +89,7 @@ class TestCoinSelection:
for target_amount in coin_amounts[:100]: # select the first 100 values
result: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -116,7 +118,7 @@ class TestCoinSelection:
print("Target amount: ", target_amount)
result: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -136,7 +138,7 @@ class TestCoinSelection:
for target_amount in [50000, 25000, 15000, 10000, 9000, 3000]: # select the first 100 values
dusty_result: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -167,7 +169,7 @@ class TestCoinSelection:
for target_amount in [20000, 15000, 10000, 5000]: # select the first 100 values
dusty_below_target: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
new_coin_list,
{},
logging.getLogger("test"),
@ -198,7 +200,7 @@ class TestCoinSelection:
for target_amount in [50000, 10001, 10000, 9999]:
dusty_below_target: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
new_coin_list,
{},
logging.getLogger("test"),
@ -224,7 +226,7 @@ class TestCoinSelection:
for target_amount in [10000, 9999]:
await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -235,7 +237,7 @@ class TestCoinSelection:
for target_amount in [10001, 20000]:
await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -255,7 +257,7 @@ class TestCoinSelection:
target_amount = uint128(40)
exact_match_result: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -269,7 +271,7 @@ class TestCoinSelection:
target_amount = uint128(153)
match_2: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -282,7 +284,7 @@ class TestCoinSelection:
target_amount = uint128(541)
match_3: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -296,7 +298,7 @@ class TestCoinSelection:
target_amount = spendable_amount
match_all: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -316,7 +318,7 @@ class TestCoinSelection:
target_amount = uint128(625)
smallest_result: Set[Coin] = await select_coins(
greater_spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
greater_coin_list,
{},
logging.getLogger("test"),
@ -334,7 +336,7 @@ class TestCoinSelection:
target_amount = uint128(50000)
single_greater_result: Set[Coin] = await select_coins(
single_greater_spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
single_greater_coin_list,
{},
logging.getLogger("test"),
@ -354,7 +356,7 @@ class TestCoinSelection:
target_amount = uint128(70000)
multiple_greater_result: Set[Coin] = await select_coins(
multiple_greater_spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
multiple_greater_coin_list,
{},
logging.getLogger("test"),
@ -384,7 +386,7 @@ class TestCoinSelection:
target_amount = spendable_amount - 1
result: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -450,12 +452,11 @@ class TestCoinSelection:
for min_coin_amount in [10, 100, 200, 300, 1000]:
result: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
dataclasses.replace(DEFAULT_COIN_SELECTION_CONFIG, min_coin_amount=uint64(min_coin_amount)),
coin_list,
{},
logging.getLogger("test"),
uint128(target_amount),
min_coin_amount=uint64(min_coin_amount),
)
assert result is not None # this should never happen
assert sum(coin.amount for coin in result) >= target_amount
@ -483,12 +484,11 @@ class TestCoinSelection:
# test that excluded coins are not included in the result
selected_coins: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
dataclasses.replace(DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[c.name() for c in excluded_coins]),
spendable_wallet_coin_records,
{},
logging.getLogger("test"),
amount=target_amount,
exclude=excluded_coins,
)
assert selected_coins is not None
@ -501,12 +501,13 @@ class TestCoinSelection:
with pytest.raises(ValueError):
await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
dataclasses.replace(
DEFAULT_COIN_SELECTION_CONFIG, excluded_coin_ids=[c.name() for c in excluded_all_coins]
),
spendable_wallet_coin_records,
{},
logging.getLogger("test"),
amount=target_amount,
exclude=excluded_all_coins,
)
@pytest.mark.asyncio
@ -522,7 +523,7 @@ class TestCoinSelection:
target_amount = uint128(0)
zero_amount_result: Set[Coin] = await select_coins(
spendable_amount,
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
coin_list,
{},
logging.getLogger("test"),
@ -535,7 +536,7 @@ class TestCoinSelection:
with pytest.raises(ValueError):
await select_coins(
uint128(0),
uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT),
DEFAULT_COIN_SELECTION_CONFIG,
[],
{},
logging.getLogger("test"),

View File

@ -16,6 +16,7 @@ from chia.types.peer_info import PeerInfo
from chia.util.db_wrapper import DBWrapper2
from chia.util.ints import uint16, uint32, uint64
from chia.wallet.notification_store import NotificationStore
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
# For testing backwards compatibility with a DB change to add height
@ -134,7 +135,7 @@ async def test_notifications(self_hostname: str, two_wallet_nodes: Any, trusted:
allow_height = peak.height + 1
if case == "allow_larger":
allow_larger_height = peak.height + 1
tx = await notification_manager_1.send_new_notification(ph_2, msg, AMOUNT, fee=FEE)
tx = await notification_manager_1.send_new_notification(ph_2, msg, AMOUNT, DEFAULT_TX_CONFIG, fee=FEE)
await wsm_1.add_pending_transaction(tx)
await time_out_assert_not_none(
5,

View File

@ -27,6 +27,7 @@ from chia.wallet.payment import Payment
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.transaction_type import TransactionType
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.util.wallet_types import CoinType
from chia.wallet.wallet import CHIP_0002_SIGN_MESSAGE_PREFIX
from chia.wallet.wallet_node import WalletNode, get_wallet_db_path
@ -113,6 +114,7 @@ class TestWalletSimulator:
tx = await wallet.generate_signed_transaction(
uint64(tx_amount),
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
DEFAULT_TX_CONFIG,
uint64(0),
)
await wallet.push_transaction(tx)
@ -160,8 +162,8 @@ class TestWalletSimulator:
tx = await wallet.generate_signed_transaction(
uint64(tx_amount),
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
dataclasses.replace(DEFAULT_TX_CONFIG, reuse_puzhash=True),
uint64(0),
reuse_puzhash=True,
)
assert tx.spend_bundle is not None
assert len(tx.spend_bundle.coin_spends) == 1
@ -217,6 +219,7 @@ class TestWalletSimulator:
tx1 = await wallet.generate_signed_transaction(
uint64(500),
normal_puzhash,
DEFAULT_TX_CONFIG,
uint64(0),
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 10}],
)
@ -232,6 +235,7 @@ class TestWalletSimulator:
tx2 = await wallet.generate_signed_transaction(
uint64(500),
await wallet_1.get_new_puzzlehash(),
DEFAULT_TX_CONFIG,
uint64(0),
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 10}],
)
@ -247,6 +251,7 @@ class TestWalletSimulator:
tx3 = await wallet.generate_signed_transaction(
uint64(500),
normal_puzhash,
DEFAULT_TX_CONFIG,
uint64(0),
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 10}],
)
@ -324,6 +329,7 @@ class TestWalletSimulator:
tx = await wallet.generate_signed_transaction(
uint64(500),
normal_puzhash,
DEFAULT_TX_CONFIG,
uint64(0),
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 500}],
memos=[b"Test"],
@ -449,6 +455,7 @@ class TestWalletSimulator:
tx = await wallet.generate_signed_transaction(
uint64(500),
normal_puzhash,
DEFAULT_TX_CONFIG,
uint64(0),
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
)
@ -540,6 +547,7 @@ class TestWalletSimulator:
tx = await wallet.generate_signed_transaction(
uint64(500),
normal_puzhash,
DEFAULT_TX_CONFIG,
uint64(0),
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
)
@ -637,6 +645,7 @@ class TestWalletSimulator:
tx = await wallet.generate_signed_transaction(
uint64(500),
normal_puzhash,
DEFAULT_TX_CONFIG,
uint64(0),
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 500}],
)
@ -752,6 +761,7 @@ class TestWalletSimulator:
tx = await wallet_0.wallet_state_manager.main_wallet.generate_signed_transaction(
uint64(10),
bytes32(32 * b"0"),
DEFAULT_TX_CONFIG,
uint64(0),
)
assert tx.spend_bundle is not None
@ -808,6 +818,7 @@ class TestWalletSimulator:
tx = await wallet_0.generate_signed_transaction(
uint64(tx_amount),
await wallet_node_1.wallet_state_manager.main_wallet.get_new_puzzlehash(),
DEFAULT_TX_CONFIG,
uint64(0),
)
@ -827,7 +838,7 @@ class TestWalletSimulator:
tx_amount = 5
tx = await wallet_1.generate_signed_transaction(
uint64(tx_amount), await wallet_0.get_new_puzzlehash(), uint64(0)
uint64(tx_amount), await wallet_0.get_new_puzzlehash(), DEFAULT_TX_CONFIG, uint64(0)
)
await wallet_1.push_transaction(tx)
await full_node_api_0.wait_transaction_records_entered_mempool(records=[tx])
@ -920,6 +931,7 @@ class TestWalletSimulator:
tx = await wallet.generate_signed_transaction(
uint64(tx_amount),
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
DEFAULT_TX_CONFIG,
uint64(tx_fee),
)
assert tx.spend_bundle is not None
@ -985,7 +997,9 @@ class TestWalletSimulator:
tx_amount = 3200000000000
tx_fee = 10
ph_2 = await wallet_1.get_new_puzzlehash()
tx = await wallet.generate_signed_transaction(uint64(tx_amount), ph_2, uint64(tx_fee), memos=[ph_2])
tx = await wallet.generate_signed_transaction(
uint64(tx_amount), ph_2, DEFAULT_TX_CONFIG, uint64(tx_fee), memos=[ph_2]
)
tx_id = tx.name.hex()
assert tx.spend_bundle is not None
@ -1049,7 +1063,9 @@ class TestWalletSimulator:
await time_out_assert(20, wallet.get_confirmed_balance, expected_confirmed_balance)
primaries = [Payment(ph, uint64(1000000000 + i)) for i in range(60)]
tx_split_coins = await wallet.generate_signed_transaction(uint64(1), ph, uint64(0), primaries=primaries)
tx_split_coins = await wallet.generate_signed_transaction(
uint64(1), ph, DEFAULT_TX_CONFIG, uint64(0), primaries=primaries
)
assert tx_split_coins.spend_bundle is not None
await wallet.push_transaction(tx_split_coins)
@ -1062,6 +1078,7 @@ class TestWalletSimulator:
transaction_record = await wallet.generate_signed_transaction(
uint64(max_sent_amount - 1),
ph,
DEFAULT_TX_CONFIG,
uint64(0),
)
@ -1071,6 +1088,7 @@ class TestWalletSimulator:
transaction_record = await wallet.generate_signed_transaction(
uint64(max_sent_amount),
ph,
DEFAULT_TX_CONFIG,
uint64(0),
)
@ -1081,6 +1099,7 @@ class TestWalletSimulator:
await wallet.generate_signed_transaction(
uint64(max_sent_amount + 1),
ph,
DEFAULT_TX_CONFIG,
uint64(0),
)
@ -1127,6 +1146,7 @@ class TestWalletSimulator:
tx = await wallet.generate_signed_transaction(
uint64(tx_amount),
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
DEFAULT_TX_CONFIG,
uint64(tx_fee),
)
assert tx.spend_bundle is not None
@ -1208,14 +1228,16 @@ class TestWalletSimulator:
# Ensure that we use a coin that we will not reorg out
tx_amount = 1000
coins = await wallet.select_coins(amount=uint64(tx_amount))
coins = await wallet.select_coins(
amount=uint64(tx_amount), coin_selection_config=DEFAULT_TX_CONFIG.coin_selection_config
)
coin = next(iter(coins))
reorg_height = full_node_api.full_node.blockchain.get_peak_height()
assert reorg_height is not None
reorg_funds = await full_node_api.farm_blocks_to_wallet(count=reorg_block_count, wallet=wallet)
tx = await wallet.generate_signed_transaction(uint64(tx_amount), ph2, coins={coin})
tx = await wallet.generate_signed_transaction(uint64(tx_amount), ph2, DEFAULT_TX_CONFIG, coins={coin})
assert tx.spend_bundle is not None
await wallet.push_transaction(tx)
await full_node_api.process_transaction_records(records=[tx])
@ -1434,12 +1456,13 @@ class TestWalletSimulator:
await time_out_assert(20, wallet.get_unconfirmed_balance, expected_confirmed_balance)
AMOUNT_TO_SEND = 4000000000000
coins = await wallet.select_coins(uint64(AMOUNT_TO_SEND))
coins = await wallet.select_coins(uint64(AMOUNT_TO_SEND), DEFAULT_TX_CONFIG.coin_selection_config)
coin_list = list(coins)
tx = await wallet.generate_signed_transaction(
uint64(AMOUNT_TO_SEND),
await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(),
DEFAULT_TX_CONFIG,
uint64(0),
coins=coins,
origin_id=coin_list[2].name(),

View File

@ -16,6 +16,7 @@ from chia.types.peer_info import PeerInfo
from chia.types.spend_bundle import SpendBundle
from chia.util.ints import uint16, uint64
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.wallet_node import WalletNode
@ -62,7 +63,9 @@ async def test_wallet_tx_retry(
await farm_blocks(full_node_1, reward_ph, 2)
await full_node_1.wait_for_wallet_synced(wallet_node=wallet_node_1, timeout=wait_secs)
transaction: TransactionRecord = await wallet_1.generate_signed_transaction(uint64(100), reward_ph)
transaction: TransactionRecord = await wallet_1.generate_signed_transaction(
uint64(100), reward_ph, DEFAULT_TX_CONFIG
)
sb1: Optional[SpendBundle] = transaction.spend_bundle
assert sb1 is not None
await wallet_1.push_transaction(transaction)

View File

@ -12,6 +12,7 @@ from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.peer_info import PeerInfo
from chia.util.ints import uint16, uint64
from chia.wallet.did_wallet.did_wallet import DIDWallet
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
from chia.wallet.util.wallet_types import WalletType
from chia.wallet.vc_wallet.vc_store import VCProofs, VCRecord
@ -86,6 +87,7 @@ async def test_vc_lifecycle(self_hostname: str, two_wallet_nodes_services: Any,
proof_root: bytes32 = proofs.root()
txs = await client_0.vc_spend(
vc_record.vc.launcher_id,
DEFAULT_TX_CONFIG,
new_proof_hash=proof_root,
fee=uint64(100),
)
@ -99,7 +101,7 @@ async def test_vc_lifecycle(self_hostname: str, two_wallet_nodes_services: Any,
assert vc_record_updated.vc.proof_hash == proof_root
# Do a mundane spend
txs = await client_0.vc_spend(vc_record.vc.launcher_id)
txs = await client_0.vc_spend(vc_record.vc.launcher_id, DEFAULT_TX_CONFIG)
spend_bundle = next(tx.spend_bundle for tx in txs if tx.spend_bundle is not None)
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, spend_bundle.name())
await full_node_api.farm_blocks_to_wallet(count=num_blocks, wallet=wallet_1)
@ -128,7 +130,7 @@ async def test_vc_lifecycle(self_hostname: str, two_wallet_nodes_services: Any,
assert fetched_proofs[proof_root.hex()] == proofs.key_value_pairs
# Revoke VC
txs = await client_0.vc_revoke(vc_record_updated.vc.coin.parent_coin_info, uint64(1))
txs = await client_0.vc_revoke(vc_record_updated.vc.coin.parent_coin_info, DEFAULT_TX_CONFIG, uint64(1))
confirmed_balance -= 1
spend_bundle = next(tx.spend_bundle for tx in txs if tx.spend_bundle is not None)
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, spend_bundle.name())