From 850cbf53bb9af215ecb0e4fbb89ec11e9eec6495 Mon Sep 17 00:00:00 2001 From: Izumi Hoshino Date: Wed, 10 Jun 2026 03:39:04 +0900 Subject: [PATCH] [CHIA-4224] Added `offer_only` option to `create_offer_for_ids` (#18680) * Added `offer_only` option to `create_offer_for_ids` * Added a test * Addressed review comment * Fixed CI error * Increased test coverage --- chia/_tests/wallet/rpc/test_wallet_rpc.py | 14 ++++++++++++++ chia/cmds/wallet_funcs.py | 2 ++ chia/data_layer/data_layer.py | 2 ++ chia/wallet/wallet_request_types.py | 14 ++++++++++++++ chia/wallet/wallet_rpc_api.py | 6 ++++++ chia/wallet/wallet_rpc_client.py | 12 +++++++----- 6 files changed, 45 insertions(+), 5 deletions(-) diff --git a/chia/_tests/wallet/rpc/test_wallet_rpc.py b/chia/_tests/wallet/rpc/test_wallet_rpc.py index 16952deaaa..e8baad64c2 100644 --- a/chia/_tests/wallet/rpc/test_wallet_rpc.py +++ b/chia/_tests/wallet/rpc/test_wallet_rpc.py @@ -114,6 +114,7 @@ from chia.wallet.wallet_request_types import ( CreateNewWallet, CreateNewWalletType, CreateOfferForIDs, + CreateOfferForIDsResponse, CreateSignedTransaction, DefaultCAT, DeleteKey, @@ -1588,6 +1589,18 @@ async def test_offer_endpoints(wallet_environments: WalletTestFramework, wallet_ all_offers = (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records assert len(all_offers) == 0 + offer_only_res = await env_1.rpc_client.create_offer_for_ids( + CreateOfferForIDs( + offer={str(1): "-5", cat_asset_id.hex(): "1"}, + validate_only=True, + offer_only=True, + ), + tx_config=wallet_environments.tx_config, + ) + assert offer_only_res.offer is not None + assert not hasattr(offer_only_res, "trade_record") + assert offer_only_res.to_json_dict() == {"offer": offer_only_res.offer.to_bech32()} + driver_dict = { cat_asset_id: PuzzleInfo( { @@ -1676,6 +1689,7 @@ async def test_offer_endpoints(wallet_environments: WalletTestFramework, wallet_ CreateOfferForIDs(offer={str(1): "-5", str(cat_wallet_id): "1"}, fee=uint64(1)), tx_config=wallet_environments.tx_config, ) + assert isinstance(create_res, CreateOfferForIDsResponse) all_offers = (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records assert len(all_offers) == 2 offer_count = await env_1.rpc_client.get_offers_count() diff --git a/chia/cmds/wallet_funcs.py b/chia/cmds/wallet_funcs.py index 7ef2d83eff..c303af3f25 100644 --- a/chia/cmds/wallet_funcs.py +++ b/chia/cmds/wallet_funcs.py @@ -57,6 +57,7 @@ from chia.wallet.wallet_request_types import ( CreateNewWallet, CreateNewWalletType, CreateOfferForIDs, + CreateOfferForIDsResponse, DeleteNotifications, DeleteUnconfirmedTransactions, DIDFindLostDID, @@ -686,6 +687,7 @@ async def make_offer( ).to_tx_config(units["chia"], config, fingerprint), timelock_info=condition_valid_times, ) + assert isinstance(res, CreateOfferForIDsResponse) if res.offer is not None: file.write(res.offer.to_bech32()) print(f"Created offer with ID {res.trade_record.trade_id}") diff --git a/chia/data_layer/data_layer.py b/chia/data_layer/data_layer.py index a015794fe0..929a8211b8 100644 --- a/chia/data_layer/data_layer.py +++ b/chia/data_layer/data_layer.py @@ -70,6 +70,7 @@ from chia.wallet.wallet_request_types import ( CancelOffer, CreateNewDL, CreateOfferForIDs, + CreateOfferForIDsResponse, DLDeleteMirror, DLGetMirrors, DLHistory, @@ -1213,6 +1214,7 @@ class DataLayer: # This is not a change in behavior, the default was already implicit. tx_config=DEFAULT_TX_CONFIG, ) + assert isinstance(res, CreateOfferForIDsResponse) offer = Offer( trade_id=res.trade_record.trade_id, diff --git a/chia/wallet/wallet_request_types.py b/chia/wallet/wallet_request_types.py index 2477b04a79..bd449f2ca8 100644 --- a/chia/wallet/wallet_request_types.py +++ b/chia/wallet/wallet_request_types.py @@ -2166,6 +2166,7 @@ class CreateOfferForIDs(TransactionEndpointRequest): driver_dict: dict[bytes32, PuzzleInfo] | None = None solver: Solver | None = None validate_only: bool = False + offer_only: bool = False @property def offer_spec(self) -> dict[int | bytes32, int]: @@ -2185,6 +2186,19 @@ class CreateOfferForIDsResponse(_OfferEndpointResponse): pass +@streamable +@dataclass(kw_only=True, frozen=True) +class CreateOfferForIDsOfferOnlyResponse(Streamable): + offer: Offer + + def to_json_dict(self) -> dict[str, Any]: + return {"offer": self.offer.to_bech32()} + + @classmethod + def from_json_dict(cls, json_dict: dict[str, Any]) -> Self: + return cls(offer=Offer.from_bech32(json_dict["offer"])) + + @streamable @dataclass(kw_only=True, frozen=True) class TakeOffer(TransactionEndpointRequest): diff --git a/chia/wallet/wallet_rpc_api.py b/chia/wallet/wallet_rpc_api.py index 72694de1e7..2595ffd39d 100644 --- a/chia/wallet/wallet_rpc_api.py +++ b/chia/wallet/wallet_rpc_api.py @@ -530,6 +530,12 @@ def tx_endpoint( dataclasses.replace(tx, trade_id=new_trade.trade_id) ) + if func.__name__ == "create_offer_for_ids" and request.get("offer_only", False): + response.pop("trade_record", None) + response.pop("transactions", None) + response.pop("unsigned_transactions", None) + return response + return response return rpc_endpoint diff --git a/chia/wallet/wallet_rpc_client.py b/chia/wallet/wallet_rpc_client.py index d995a8007b..8ece79ebd6 100644 --- a/chia/wallet/wallet_rpc_client.py +++ b/chia/wallet/wallet_rpc_client.py @@ -42,6 +42,7 @@ from chia.wallet.wallet_request_types import ( CreateNewWallet, CreateNewWalletResponse, CreateOfferForIDs, + CreateOfferForIDsOfferOnlyResponse, CreateOfferForIDsResponse, CreateSignedTransaction, CreateSignedTransactionsResponse, @@ -587,12 +588,13 @@ class WalletRpcClient(RpcClient): tx_config: TXConfig, extra_conditions: tuple[Condition, ...] = tuple(), timelock_info: ConditionValidTimes = ConditionValidTimes(), - ) -> CreateOfferForIDsResponse: - return CreateOfferForIDsResponse.from_json_dict( - await self.fetch( - "create_offer_for_ids", request.json_serialize_for_transport(tx_config, extra_conditions, timelock_info) - ) + ) -> CreateOfferForIDsResponse | CreateOfferForIDsOfferOnlyResponse: + response = await self.fetch( + "create_offer_for_ids", request.json_serialize_for_transport(tx_config, extra_conditions, timelock_info) ) + if request.offer_only: + return CreateOfferForIDsOfferOnlyResponse.from_json_dict(response) + return CreateOfferForIDsResponse.from_json_dict(response) async def get_offer_summary(self, request: GetOfferSummary) -> GetOfferSummaryResponse: return GetOfferSummaryResponse.from_json_dict(await self.fetch("get_offer_summary", request.to_json_dict()))