Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CHIA-424] Port chia wallet coins to @tx_out_cmd #18023

Merged
merged 1 commit into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion chia/_tests/cmds/cmd_test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,9 @@ async def send_transaction_multi(
tx_config: TXConfig,
coins: Optional[List[Coin]] = None,
fee: uint64 = uint64(0),
push: bool = True,
) -> SendTransactionMultiResponse:
self.add_to_log("send_transaction_multi", (wallet_id, additions, tx_config, coins, fee))
self.add_to_log("send_transaction_multi", (wallet_id, additions, tx_config, coins, fee, push))
name = bytes32([2] * 32)
return SendTransactionMultiResponse(
[STD_UTX],
Expand Down
3 changes: 3 additions & 0 deletions chia/_tests/cmds/wallet/test_coins.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ async def select_coins(
Coin(get_bytes32(3), get_bytes32(4), uint64(1234560000)),
],
1000000000,
True,
),
(
1,
Expand All @@ -152,6 +153,7 @@ async def select_coins(
Coin(get_bytes32(5), get_bytes32(6), uint64(300000000000)),
],
1000000000,
True,
),
],
}
Expand Down Expand Up @@ -213,6 +215,7 @@ async def get_coin_records_by_names(
DEFAULT_TX_CONFIG,
[Coin(get_bytes32(1), get_bytes32(2), uint64(100000000000))],
1000000000,
True,
)
],
}
Expand Down
41 changes: 24 additions & 17 deletions chia/cmds/coin_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ async def async_combine(
target_coin_amount: Decimal,
target_coin_ids_str: Sequence[str],
largest_first: bool,
) -> None:
push: bool,
) -> List[TransactionRecord]:
async with get_wallet_client(wallet_rpc_port, fingerprint) as (wallet_client, fingerprint, config):
target_coin_ids: List[bytes32] = [bytes32.from_hexstr(coin_id) for coin_id in target_coin_ids_str]
final_fee = uint64(int(fee * units["chia"]))
Expand All @@ -135,10 +136,10 @@ async def async_combine(
mojo_per_unit = get_mojo_per_unit(wallet_type)
except LookupError:
print(f"Wallet id: {wallet_id} not found.")
return
return []
if not await wallet_client.get_synced():
print("Wallet not synced. Please wait.")
return
return []
is_xch: bool = wallet_type == WalletType.STANDARD_WALLET # this lets us know if we are directly combining Chia

tx_config = CMDTXConfigLoader(
Expand All @@ -165,10 +166,10 @@ async def async_combine(
conf_coins = [cr for cr in conf_coins if cr.name in target_coin_ids]
if len(conf_coins) == 0:
print("No coins to combine.")
return
return []
if len(conf_coins) == 1:
print("Only one coin found, you need at least two coins to combine.")
return
return []
if largest_first:
conf_coins.sort(key=lambda r: r.coin.amount, reverse=True)
else:
Expand All @@ -181,15 +182,18 @@ async def async_combine(
total_amount: uint128 = uint128(sum(coin.amount for coin in removals))
if is_xch and total_amount - final_fee <= 0:
print("Total amount is less than 0 after fee, exiting.")
return
return []
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, tx_config, removals, final_fee)
await wallet_client.send_transaction_multi(wallet_id, additions, tx_config, removals, final_fee, push=push)
).transaction
tx_id = transaction.name.hex()
print(f"Transaction sent: {tx_id}")
print(f"To get status, use command: chia wallet get_transaction -f {fingerprint} -tx 0x{tx_id}")
if push:
print(f"Transaction sent: {tx_id}")
print(f"To get status, use command: chia wallet get_transaction -f {fingerprint} -tx 0x{tx_id}")

return [transaction]


async def async_split(
Expand All @@ -202,22 +206,23 @@ async def async_split(
amount_per_coin: Decimal,
target_coin_id_str: str,
# TODO: [add TXConfig args]
) -> None:
push: bool,
) -> List[TransactionRecord]:
async with get_wallet_client(wallet_rpc_port, fingerprint) as (wallet_client, fingerprint, config):
final_fee = uint64(int(fee * units["chia"]))
target_coin_id: bytes32 = bytes32.from_hexstr(target_coin_id_str)
if number_of_coins > 500:
print(f"{number_of_coins} coins is greater then the maximum limit of 500 coins.")
return
return []
try:
wallet_type = await get_wallet_type(wallet_id=wallet_id, wallet_client=wallet_client)
mojo_per_unit = get_mojo_per_unit(wallet_type)
except LookupError:
print(f"Wallet id: {wallet_id} not found.")
return
return []
if not await wallet_client.get_synced():
print("Wallet not synced. Please wait.")
return
return []
is_xch: bool = wallet_type == WalletType.STANDARD_WALLET # this lets us know if we are directly spitting Chia
final_amount_per_coin = uint64(int(amount_per_coin * mojo_per_unit))
total_amount = final_amount_per_coin * number_of_coins
Expand All @@ -231,7 +236,7 @@ async def async_split(
f"is less than the total amount of the split: {total_amount / mojo_per_unit}, exiting."
)
print("Try using a smaller fee or amount.")
return
return []
additions: List[Dict[str, Union[uint64, bytes32]]] = []
for i in range(number_of_coins): # for readability.
# we always use new addresses
Expand All @@ -244,12 +249,13 @@ async def async_split(

transaction: TransactionRecord = (
await wallet_client.send_transaction_multi(
wallet_id, additions, tx_config, [removal_coin_record.coin], final_fee
wallet_id, additions, tx_config, [removal_coin_record.coin], final_fee, push=push
)
).transaction
tx_id = transaction.name.hex()
print(f"Transaction sent: {tx_id}")
print(f"To get status, use command: chia wallet get_transaction -f {fingerprint} -tx 0x{tx_id}")
if push:
print(f"Transaction sent: {tx_id}")
print(f"To get status, use command: chia wallet get_transaction -f {fingerprint} -tx 0x{tx_id}")
dust_threshold = config.get("xch_spam_amount", 1000000) # min amount per coin in mojo
spam_filter_after_n_txs = config.get("spam_filter_after_n_txs", 200) # how many txs to wait before filtering
if final_amount_per_coin < dust_threshold and wallet_type == WalletType.STANDARD_WALLET:
Expand All @@ -259,3 +265,4 @@ async def async_split(
f"{'will' if number_of_coins > spam_filter_after_n_txs else 'may'} not show up in your wallet unless "
f"you decrease the dust limit to below {final_amount_per_coin} mojos or disable it by setting it to 0."
)
return [transaction]
18 changes: 13 additions & 5 deletions chia/cmds/coins.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import asyncio
from decimal import Decimal
from typing import Optional, Sequence
from typing import List, Optional, Sequence

import click

from chia.cmds import options
from chia.cmds.cmds_util import tx_out_cmd
from chia.wallet.transaction_record import TransactionRecord


@click.group("coins", help="Manage your wallets coins")
Expand Down Expand Up @@ -150,6 +152,7 @@ def list_cmd(
default=False,
help="Sort coins from largest to smallest or smallest to largest.",
)
@tx_out_cmd
def combine_cmd(
wallet_rpc_port: Optional[int],
fingerprint: int,
Expand All @@ -162,10 +165,11 @@ def combine_cmd(
fee: str,
input_coins: Sequence[str],
largest_first: bool,
) -> None:
push: bool,
) -> List[TransactionRecord]:
from .coin_funcs import async_combine

asyncio.run(
return asyncio.run(
async_combine(
wallet_rpc_port=wallet_rpc_port,
fingerprint=fingerprint,
Expand All @@ -178,6 +182,7 @@ def combine_cmd(
target_coin_amount=Decimal(target_amount),
target_coin_ids_str=input_coins,
largest_first=largest_first,
push=push,
)
)

Expand Down Expand Up @@ -216,6 +221,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_out_cmd
def split_cmd(
wallet_rpc_port: Optional[int],
fingerprint: int,
Expand All @@ -224,10 +230,11 @@ def split_cmd(
fee: str,
amount_per_coin: str,
target_coin_id: str,
) -> None:
push: bool,
) -> List[TransactionRecord]:
from .coin_funcs import async_split

asyncio.run(
return asyncio.run(
async_split(
wallet_rpc_port=wallet_rpc_port,
fingerprint=fingerprint,
Expand All @@ -236,5 +243,6 @@ def split_cmd(
number_of_coins=number_of_coins,
amount_per_coin=Decimal(amount_per_coin),
target_coin_id_str=target_coin_id,
push=push,
)
)
Loading