Skip to content

Commit 1b4972d

Browse files
committed
Port send_transaction
1 parent 35291ee commit 1b4972d

File tree

7 files changed

+157
-97
lines changed

7 files changed

+157
-97
lines changed

chia/_tests/pools/test_pool_rpc.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
PWJoinPool,
4949
PWSelfPool,
5050
PWStatus,
51+
SendTransaction,
5152
)
5253
from chia.wallet.wallet_rpc_client import WalletRpcClient
5354
from chia.wallet.wallet_service import WalletService
@@ -590,7 +591,13 @@ async def test_absorb_self(
590591

591592
tr: TransactionRecord = (
592593
await client.send_transaction(
593-
1, uint64(100), encode_puzzle_hash(status.p2_singleton_puzzle_hash, "txch"), DEFAULT_TX_CONFIG
594+
SendTransaction(
595+
wallet_id=uint32(1),
596+
amount=uint64(100),
597+
address=encode_puzzle_hash(status.p2_singleton_puzzle_hash, "txch"),
598+
push=True,
599+
),
600+
DEFAULT_TX_CONFIG,
594601
)
595602
).transaction
596603

chia/_tests/wallet/cat_wallet/test_cat_wallet.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
from chia.wallet.wallet_info import WalletInfo
4545
from chia.wallet.wallet_interested_store import WalletInterestedStore
4646
from chia.wallet.wallet_node import WalletNode
47-
from chia.wallet.wallet_request_types import GetTransactionMemo, PushTX
47+
from chia.wallet.wallet_request_types import GetTransactionMemo, PushTX, SendTransaction
4848
from chia.wallet.wallet_state_manager import WalletStateManager
4949

5050

@@ -1429,7 +1429,12 @@ async def test_cat_change_detection(wallet_environments: WalletTestFramework, wa
14291429
cat_amount_0 = uint64(100)
14301430
cat_amount_1 = uint64(5)
14311431

1432-
tx = (await env.rpc_client.send_transaction(1, cat_amount_0, addr, wallet_environments.tx_config)).transaction
1432+
tx = (
1433+
await env.rpc_client.send_transaction(
1434+
SendTransaction(wallet_id=uint32(1), amount=cat_amount_0, address=addr, push=True),
1435+
wallet_environments.tx_config,
1436+
)
1437+
).transaction
14331438
spend_bundle = tx.spend_bundle
14341439
assert spend_bundle is not None
14351440

chia/_tests/wallet/rpc/test_wallet_rpc.py

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
from chia.wallet.wallet_request_types import (
106106
AddKey,
107107
CheckDeleteKey,
108+
ClawbackPuzzleDecoratorOverride,
108109
CombineCoins,
109110
DefaultCAT,
110111
DeleteKey,
@@ -136,6 +137,7 @@
136137
PushTransactions,
137138
PushTX,
138139
RoyaltyAsset,
140+
SendTransaction,
139141
SetWalletResyncOnStartup,
140142
SplitCoins,
141143
VerifySignature,
@@ -378,24 +380,25 @@ async def test_send_transaction(wallet_rpc_environment: WalletRpcTestEnvironment
378380
addr = encode_puzzle_hash(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager), "txch")
379381
tx_amount = uint64(15600000)
380382
with pytest.raises(ValueError):
381-
await client.send_transaction(1, uint64(100000000000000001), addr, DEFAULT_TX_CONFIG)
383+
await client.send_transaction(
384+
SendTransaction(wallet_id=uint32(1), amount=uint64(100000000000000001), address=addr, push=True),
385+
DEFAULT_TX_CONFIG,
386+
)
382387

383388
# Tests sending a basic transaction
384389
extra_conditions = (Remark(Program.to(("test", None))),)
385390
non_existent_coin = Coin(bytes32.zeros, bytes32.zeros, uint64(0))
386391
tx_no_push = (
387392
await client.send_transaction(
388-
1,
389-
tx_amount,
390-
addr,
391-
memos=["this is a basic tx"],
393+
SendTransaction(
394+
wallet_id=uint32(1), amount=tx_amount, address=addr, memos=["this is a basic tx"], push=False
395+
),
392396
tx_config=DEFAULT_TX_CONFIG.override(
393397
excluded_coin_amounts=[uint64(250000000000)],
394398
excluded_coin_ids=[non_existent_coin.name()],
395399
reuse_puzhash=True,
396400
),
397401
extra_conditions=extra_conditions,
398-
push=False,
399402
)
400403
).transaction
401404
response = await client.fetch(
@@ -837,12 +840,14 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
837840
wallet_2_puzhash = await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager)
838841
tx = (
839842
await wallet_1_rpc.send_transaction(
840-
wallet_id=1,
841-
amount=uint64(500),
842-
address=encode_puzzle_hash(wallet_2_puzhash, "txch"),
843+
SendTransaction(
844+
wallet_id=uint32(1),
845+
amount=uint64(500),
846+
address=encode_puzzle_hash(wallet_2_puzhash, "txch"),
847+
puzzle_decorator=[ClawbackPuzzleDecoratorOverride(decorator="CLAWBACK", clawback_timelock=uint64(5))],
848+
push=True,
849+
),
843850
tx_config=DEFAULT_TX_CONFIG,
844-
fee=uint64(0),
845-
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
846851
)
847852
).transaction
848853
clawback_coin_id_1 = tx.additions[0].name()
@@ -851,12 +856,14 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
851856
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_2_node, timeout=20)
852857
tx = (
853858
await wallet_2_rpc.send_transaction(
854-
wallet_id=1,
855-
amount=uint64(500),
856-
address=encode_puzzle_hash(wallet_1_puzhash, "txch"),
859+
SendTransaction(
860+
wallet_id=uint32(1),
861+
amount=uint64(500),
862+
address=encode_puzzle_hash(wallet_1_puzhash, "txch"),
863+
puzzle_decorator=[ClawbackPuzzleDecoratorOverride(decorator="CLAWBACK", clawback_timelock=uint64(5))],
864+
push=True,
865+
),
857866
tx_config=DEFAULT_TX_CONFIG,
858-
fee=uint64(0),
859-
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
860867
)
861868
).transaction
862869
assert tx.spend_bundle is not None
@@ -1019,7 +1026,8 @@ async def test_get_transactions(wallet_rpc_environment: WalletRpcTestEnvironment
10191026
puzhash = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
10201027
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
10211028
await client.send_transaction(
1022-
1, uint64(1), encode_puzzle_hash(puzhash, "txch"), DEFAULT_TX_CONFIG
1029+
SendTransaction(wallet_id=uint32(1), amount=uint64(1), address=encode_puzzle_hash(puzhash, "txch"), push=True),
1030+
DEFAULT_TX_CONFIG,
10231031
) # Create a pending tx
10241032

10251033
with pytest.raises(ValueError, match="There is no known sort foo"):
@@ -1045,7 +1053,12 @@ async def test_get_transactions(wallet_rpc_environment: WalletRpcTestEnvironment
10451053
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
10461054
ph_by_addr = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
10471055
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
1048-
await client.send_transaction(1, uint64(1), encode_puzzle_hash(ph_by_addr, "txch"), DEFAULT_TX_CONFIG)
1056+
await client.send_transaction(
1057+
SendTransaction(
1058+
wallet_id=uint32(1), amount=uint64(1), address=encode_puzzle_hash(ph_by_addr, "txch"), push=True
1059+
),
1060+
DEFAULT_TX_CONFIG,
1061+
)
10491062
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
10501063
tx_for_address = (
10511064
await client.get_transactions(GetTransactions(uint32(1), to_address=encode_puzzle_hash(ph_by_addr, "txch")))
@@ -1795,7 +1808,12 @@ async def test_get_coin_records_by_names(wallet_rpc_environment: WalletRpcTestEn
17951808
await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
17961809

17971810
# Spend half of it back to the same wallet get some spent coins in the wallet
1798-
tx = (await client.send_transaction(1, uint64(generated_funds / 2), address, DEFAULT_TX_CONFIG)).transaction
1811+
tx = (
1812+
await client.send_transaction(
1813+
SendTransaction(wallet_id=uint32(1), amount=uint64(generated_funds / 2), address=address, push=True),
1814+
DEFAULT_TX_CONFIG,
1815+
)
1816+
).transaction
17991817
assert tx.spend_bundle is not None
18001818
await time_out_assert(20, tx_in_mempool, True, client, tx.name)
18011819
await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
@@ -2161,7 +2179,11 @@ async def test_key_and_address_endpoints(wallet_rpc_environment: WalletRpcTestEn
21612179
addr = encode_puzzle_hash(ph, "txch")
21622180
tx_amount = uint64(15600000)
21632181
await env.full_node.api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
2164-
created_tx = (await client.send_transaction(1, tx_amount, addr, DEFAULT_TX_CONFIG)).transaction
2182+
created_tx = (
2183+
await client.send_transaction(
2184+
SendTransaction(wallet_id=uint32(1), amount=tx_amount, address=addr, push=True), DEFAULT_TX_CONFIG
2185+
)
2186+
).transaction
21652187

21662188
await time_out_assert(20, tx_in_mempool, True, client, created_tx.name)
21672189
assert len(await wallet.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(1)) == 1
@@ -2224,7 +2246,10 @@ async def test_key_and_address_endpoints(wallet_rpc_environment: WalletRpcTestEn
22242246
assert await get_unconfirmed_balance(client, int(wallets[0].id)) == 0
22252247

22262248
with pytest.raises(ValueError):
2227-
await client.send_transaction(wallets[0].id, uint64(100), addr, DEFAULT_TX_CONFIG)
2249+
await client.send_transaction(
2250+
SendTransaction(wallet_id=uint32(wallets[0].id), amount=uint64(100), address=addr, push=True),
2251+
DEFAULT_TX_CONFIG,
2252+
)
22282253

22292254
# Delete all keys
22302255
await client.delete_all_keys()
@@ -2250,7 +2275,11 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
22502275
for tx_amount in tx_amounts:
22512276
funds -= tx_amount
22522277
# create coins for tests
2253-
tx = (await client.send_transaction(1, tx_amount, addr, DEFAULT_TX_CONFIG)).transaction
2278+
tx = (
2279+
await client.send_transaction(
2280+
SendTransaction(wallet_id=uint32(1), amount=tx_amount, address=addr, push=True), DEFAULT_TX_CONFIG
2281+
)
2282+
).transaction
22542283
spend_bundle = tx.spend_bundle
22552284
assert spend_bundle is not None
22562285
for coin in spend_bundle.additions():
@@ -2811,12 +2840,14 @@ async def test_set_wallet_resync_on_startup(wallet_rpc_environment: WalletRpcTes
28112840
# Test Clawback resync
28122841
tx = (
28132842
await wc.send_transaction(
2814-
wallet_id=1,
2815-
amount=uint64(500),
2816-
address=address,
2843+
SendTransaction(
2844+
wallet_id=uint32(1),
2845+
amount=uint64(500),
2846+
address=address,
2847+
puzzle_decorator=[ClawbackPuzzleDecoratorOverride(decorator="CLAWBACK", clawback_timelock=uint64(5))],
2848+
push=True,
2849+
),
28172850
tx_config=DEFAULT_TX_CONFIG,
2818-
fee=uint64(0),
2819-
puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
28202851
)
28212852
).transaction
28222853
clawback_coin_id = tx.additions[0].name()
@@ -2959,7 +2990,11 @@ async def test_cat_spend_run_tail(wallet_rpc_environment: WalletRpcTestEnvironme
29592990
)
29602991
tx_amount = uint64(100)
29612992

2962-
tx = (await client.send_transaction(1, tx_amount, addr, DEFAULT_TX_CONFIG)).transaction
2993+
tx = (
2994+
await client.send_transaction(
2995+
SendTransaction(wallet_id=uint32(1), amount=uint64(500), address=addr, push=True), DEFAULT_TX_CONFIG
2996+
)
2997+
).transaction
29632998
transaction_id = tx.name
29642999
spend_bundle = tx.spend_bundle
29653000
assert spend_bundle is not None

chia/cmds/wallet_funcs.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
from chia.wallet.wallet_coin_store import GetCoinRecords
4646
from chia.wallet.wallet_request_types import (
4747
CATSpendResponse,
48+
ClawbackPuzzleDecoratorOverride,
4849
DIDFindLostDID,
4950
DIDGetDID,
5051
DIDGetInfo,
@@ -68,6 +69,7 @@
6869
NFTSetNFTDID,
6970
NFTTransferNFT,
7071
RoyaltyAsset,
72+
SendTransaction,
7173
SendTransactionResponse,
7274
VCAddProofs,
7375
VCGet,
@@ -327,7 +329,7 @@ async def send(
327329
) -> list[TransactionRecord]:
328330
async with get_wallet_client(root_path, wallet_rpc_port, fp) as (wallet_client, fingerprint, config):
329331
if memo is None:
330-
memos = None
332+
memos = []
331333
else:
332334
memos = [memo]
333335

@@ -356,23 +358,29 @@ async def send(
356358
if typ == WalletType.STANDARD_WALLET:
357359
print("Submitting transaction...")
358360
res: Union[CATSpendResponse, SendTransactionResponse] = await wallet_client.send_transaction(
359-
wallet_id,
360-
final_amount,
361-
address.original_address,
362-
CMDTXConfigLoader(
361+
SendTransaction(
362+
wallet_id=uint32(wallet_id),
363+
amount=final_amount,
364+
address=address.original_address,
365+
fee=fee,
366+
memos=memos,
367+
push=push,
368+
puzzle_decorator=(
369+
[
370+
ClawbackPuzzleDecoratorOverride(
371+
PuzzleDecoratorType.CLAWBACK.name, clawback_timelock=uint64(clawback_time_lock)
372+
)
373+
]
374+
if clawback_time_lock > 0
375+
else None
376+
),
377+
),
378+
tx_config=CMDTXConfigLoader(
363379
min_coin_amount=min_coin_amount,
364380
max_coin_amount=max_coin_amount,
365381
excluded_coin_ids=list(excluded_coin_ids),
366382
reuse_puzhash=reuse_puzhash,
367383
).to_tx_config(mojo_per_unit, config, fingerprint),
368-
fee,
369-
memos,
370-
puzzle_decorator_override=(
371-
[{"decorator": PuzzleDecoratorType.CLAWBACK.name, "clawback_timelock": clawback_time_lock}]
372-
if clawback_time_lock > 0
373-
else None
374-
),
375-
push=push,
376384
timelock_info=condition_valid_times,
377385
)
378386
elif typ in {WalletType.CAT, WalletType.CRCAT, WalletType.RCAT}:

chia/wallet/wallet_request_types.py

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from chia.wallet.transaction_record import TransactionRecord
3131
from chia.wallet.transaction_sorting import SortKey
3232
from chia.wallet.util.clvm_streamable import json_deserialize_with_clvm_streamable
33+
from chia.wallet.util.puzzle_decorator_type import PuzzleDecoratorType
3334
from chia.wallet.util.query_filter import TransactionTypeFilter
3435
from chia.wallet.util.tx_config import TXConfig
3536
from chia.wallet.vc_wallet.vc_store import VCProofs, VCRecord
@@ -1017,6 +1018,39 @@ class TransactionEndpointResponse(Streamable):
10171018
transactions: list[TransactionRecord]
10181019

10191020

1021+
# utility for SendTransaction
1022+
@streamable
1023+
@dataclass(frozen=True)
1024+
class ClawbackPuzzleDecoratorOverride(Streamable):
1025+
decorator: str
1026+
clawback_timelock: uint64
1027+
1028+
def __post_init__(self) -> None:
1029+
if self.decorator != PuzzleDecoratorType.CLAWBACK.name:
1030+
raise ValueError("Invalid clawback puzzle decorator override specified")
1031+
super().__post_init__()
1032+
1033+
1034+
@streamable
1035+
@dataclass(frozen=True)
1036+
class SendTransaction(TransactionEndpointRequest):
1037+
wallet_id: uint32 = field(default_factory=default_raise)
1038+
amount: uint64 = field(default_factory=default_raise)
1039+
address: str = field(default_factory=default_raise)
1040+
memos: list[str] = field(default_factory=list)
1041+
# Technically this value was meant to support many types here
1042+
# However, only one is supported right now and there are no plans to extend
1043+
# So, as a slight hack, we'll specify that only Clawback is supported
1044+
puzzle_decorator: Optional[list[ClawbackPuzzleDecoratorOverride]] = None
1045+
1046+
1047+
@streamable
1048+
@dataclass(frozen=True)
1049+
class SendTransactionResponse(TransactionEndpointResponse):
1050+
transaction: TransactionRecord
1051+
transaction_id: bytes32
1052+
1053+
10201054
@streamable
10211055
@dataclass(frozen=True)
10221056
class PushTransactions(TransactionEndpointRequest):
@@ -1452,11 +1486,6 @@ class VCRevokeResponse(TransactionEndpointResponse):
14521486

14531487
# TODO: The section below needs corresponding request types
14541488
# TODO: The section below should be added to the API (currently only for client)
1455-
@streamable
1456-
@dataclass(frozen=True)
1457-
class SendTransactionResponse(TransactionEndpointResponse):
1458-
transaction: TransactionRecord
1459-
transaction_id: bytes32
14601489

14611490

14621491
@streamable

0 commit comments

Comments
 (0)