Skip to content
36 changes: 19 additions & 17 deletions chia/_tests/cmds/wallet/test_notifications.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
from __future__ import annotations

from pathlib import Path
from typing import cast

from chia_rs.sized_bytes import bytes32
from chia_rs.sized_ints import uint32, uint64

from chia._tests.cmds.cmd_test_utils import TestRpcClients, TestWalletRpcClient, logType, run_cli_command_and_assert
from chia._tests.cmds.wallet.test_consts import FINGERPRINT, FINGERPRINT_ARG, get_bytes32
from chia._tests.cmds.wallet.test_consts import FINGERPRINT, FINGERPRINT_ARG, STD_TX, STD_UTX, get_bytes32
from chia.util.bech32m import encode_puzzle_hash
from chia.wallet.conditions import ConditionValidTimes
from chia.wallet.conditions import Condition, ConditionValidTimes
from chia.wallet.notification_store import Notification
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.wallet_request_types import DeleteNotifications, GetNotifications, GetNotificationsResponse
from chia.wallet.util.tx_config import TXConfig
from chia.wallet.wallet_request_types import (
DeleteNotifications,
GetNotifications,
GetNotificationsResponse,
SendNotification,
SendNotificationResponse,
)

test_condition_valid_times: ConditionValidTimes = ConditionValidTimes(min_time=uint64(100), max_time=uint64(150))

Expand All @@ -26,20 +31,17 @@ def test_notifications_send(capsys: object, get_test_cli_clients: tuple[TestRpcC
class NotificationsSendRpcClient(TestWalletRpcClient):
async def send_notification(
self,
target: bytes32,
msg: bytes,
amount: uint64,
fee: uint64 = uint64(0),
push: bool = True,
request: SendNotification,
tx_config: TXConfig,
extra_conditions: tuple[Condition, ...] = tuple(),
timelock_info: ConditionValidTimes = ConditionValidTimes(),
) -> TransactionRecord:
self.add_to_log("send_notification", (target, msg, amount, fee, push, timelock_info))

class FakeTransactionRecord:
def __init__(self, name: str) -> None:
self.name = name
) -> SendNotificationResponse:
self.add_to_log(
"send_notification",
(request.target, request.message, request.amount, request.fee, request.push, timelock_info),
)

return cast(TransactionRecord, FakeTransactionRecord(get_bytes32(2).hex()))
return SendNotificationResponse([STD_UTX], [STD_TX], tx=STD_TX)

inst_rpc_client = NotificationsSendRpcClient()
test_rpc_clients.wallet_rpc_client = inst_rpc_client
Expand Down
45 changes: 27 additions & 18 deletions chia/_tests/wallet/rpc/test_wallet_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
PushTX,
RoyaltyAsset,
SelectCoins,
SendNotification,
SendTransaction,
SetWalletResyncOnStartup,
SpendClawbackCoins,
Expand Down Expand Up @@ -2621,21 +2622,25 @@ async def test_notification_rpcs(wallet_rpc_environment: WalletRpcTestEnvironmen
env.wallet_2.node.config["enable_notifications"] = True
env.wallet_2.node.config["required_notification_amount"] = 100000000000
async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
tx = await client.send_notification(
await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager),
b"hello",
uint64(100000000000),
fee=uint64(100000000000),
response = await client.send_notification(
SendNotification(
target=(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager)),
message=b"hello",
amount=uint64(100000000000),
fee=uint64(100000000000),
push=True,
),
tx_config=DEFAULT_TX_CONFIG,
)

assert tx.spend_bundle is not None
assert response.tx.spend_bundle is not None
await time_out_assert(
5,
full_node_api.full_node.mempool_manager.get_spendbundle,
tx.spend_bundle,
tx.spend_bundle.name(),
response.tx.spend_bundle,
response.tx.spend_bundle.name(),
)
await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
await farm_transaction(full_node_api, wallet_node, response.tx.spend_bundle)
await time_out_assert(20, env.wallet_2.wallet.get_confirmed_balance, uint64(100000000000))

notification = (await client_2.get_notifications(GetNotifications())).notifications[0]
Expand All @@ -2648,21 +2653,25 @@ async def test_notification_rpcs(wallet_rpc_environment: WalletRpcTestEnvironmen
assert [] == (await client_2.get_notifications(GetNotifications([notification.id]))).notifications

async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
tx = await client.send_notification(
await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager),
b"hello",
uint64(100000000000),
fee=uint64(100000000000),
response = await client.send_notification(
SendNotification(
target=(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager)),
message=b"hello",
amount=uint64(100000000000),
fee=uint64(100000000000),
push=True,
),
tx_config=DEFAULT_TX_CONFIG,
)

assert tx.spend_bundle is not None
assert response.tx.spend_bundle is not None
await time_out_assert(
5,
full_node_api.full_node.mempool_manager.get_spendbundle,
tx.spend_bundle,
tx.spend_bundle.name(),
response.tx.spend_bundle,
response.tx.spend_bundle.name(),
)
await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
await farm_transaction(full_node_api, wallet_node, response.tx.spend_bundle)
await time_out_assert(20, env.wallet_2.wallet.get_confirmed_balance, uint64(200000000000))

notification = (await client_2.get_notifications(GetNotifications())).notifications[0]
Expand Down
23 changes: 15 additions & 8 deletions chia/cmds/wallet_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
NFTSetNFTDID,
NFTTransferNFT,
RoyaltyAsset,
SendNotification,
SendTransaction,
SendTransactionResponse,
SignMessageByAddress,
Expand Down Expand Up @@ -1576,19 +1577,25 @@ async def send_notification(
async with get_wallet_client(root_path, wallet_rpc_port, fp) as (wallet_client, fingerprint, _):
amount: uint64 = cli_amount.convert_amount(units["chia"])

tx = await wallet_client.send_notification(
address.puzzle_hash,
message,
amount,
fee,
push=push,
response = await wallet_client.send_notification(
SendNotification(
address.puzzle_hash,
message,
amount,
fee=fee,
push=push,
),
tx_config=DEFAULT_TX_CONFIG,
timelock_info=condition_valid_times,
)

if push:
print("Notification sent successfully.")
print(f"To get status, use command: chia wallet get_transaction -f {fingerprint} -tx 0x{tx.name}")
return [tx]
print(
"To get status, use command: chia wallet get_transaction"
f" -f {fingerprint} -tx 0x{response.transactions[0].name}"
)
return response.transactions


async def get_notifications(
Expand Down
14 changes: 14 additions & 0 deletions chia/wallet/wallet_request_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,20 @@ class SpendClawbackCoinsResponse(TransactionEndpointResponse):
transaction_ids: list[bytes32]


@streamable
@dataclass(frozen=True)
class SendNotification(TransactionEndpointRequest):
target: bytes32 = field(default_factory=default_raise)
message: bytes = field(default_factory=default_raise)
amount: uint64 = uint64(0)


@streamable
@dataclass(frozen=True)
class SendNotificationResponse(TransactionEndpointResponse):
tx: TransactionRecord


@streamable
@dataclass(frozen=True)
class PushTransactions(TransactionEndpointRequest):
Expand Down
18 changes: 11 additions & 7 deletions chia/wallet/wallet_rpc_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@
PWStatusResponse,
SelectCoins,
SelectCoinsResponse,
SendNotification,
SendNotificationResponse,
SendTransaction,
SendTransactionResponse,
SetWalletResyncOnStartup,
Expand Down Expand Up @@ -1937,22 +1939,24 @@ async def delete_notifications(self, request: DeleteNotifications) -> Empty:
return Empty()

@tx_endpoint(push=True)
@marshal
async def send_notification(
self,
request: dict[str, Any],
request: SendNotification,
action_scope: WalletActionScope,
extra_conditions: tuple[Condition, ...] = tuple(),
) -> EndpointResult:
) -> SendNotificationResponse:
await self.service.wallet_state_manager.notification_manager.send_new_notification(
bytes32.from_hexstr(request["target"]),
bytes.fromhex(request["message"]),
uint64(request["amount"]),
request.target,
request.message,
request.amount,
action_scope,
request.get("fee", uint64(0)),
request.fee,
extra_conditions=extra_conditions,
)

return {"tx": None, "transactions": None} # tx_endpoint wrapper will take care of this
# tx_endpoint will take care of these default values
return SendNotificationResponse([], [], tx=REPLACEABLE_TRANSACTION_RECORD)

@marshal
async def verify_signature(self, request: VerifySignature) -> VerifySignatureResponse:
Expand Down
27 changes: 9 additions & 18 deletions chia/wallet/wallet_rpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@
PWStatusResponse,
SelectCoins,
SelectCoinsResponse,
SendNotification,
SendNotificationResponse,
SendTransaction,
SendTransactionMultiResponse,
SendTransactionResponse,
Expand Down Expand Up @@ -1088,27 +1090,16 @@ async def delete_notifications(self, request: DeleteNotifications) -> None:

async def send_notification(
self,
target: bytes32,
msg: bytes,
amount: uint64,
fee: uint64 = uint64(0),
request: SendNotification,
tx_config: TXConfig,
extra_conditions: tuple[Condition, ...] = tuple(),
timelock_info: ConditionValidTimes = ConditionValidTimes(),
push: bool = True,
) -> TransactionRecord:
response = await self.fetch(
"send_notification",
{
"target": target.hex(),
"message": msg.hex(),
"amount": amount,
"fee": fee,
"extra_conditions": conditions_to_json_dicts(extra_conditions),
"push": push,
**timelock_info.to_json_dict(),
},
) -> SendNotificationResponse:
return SendNotificationResponse.from_json_dict(
await self.fetch(
"send_notification", request.json_serialize_for_transport(tx_config, extra_conditions, timelock_info)
)
)
return TransactionRecord.from_json_dict(response["tx"])

async def sign_message_by_address(self, request: SignMessageByAddress) -> SignMessageByAddressResponse:
return SignMessageByAddressResponse.from_json_dict(
Expand Down
Loading