Skip to content
Open
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
20 changes: 11 additions & 9 deletions chia/_tests/cmds/wallet/test_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
SendTransactionResponse,
SpendClawbackCoins,
SpendClawbackCoinsResponse,
TakeOffer,
TakeOfferResponse,
TransactionRecordWithMetadata,
WalletInfoResponse,
Expand Down Expand Up @@ -1055,29 +1056,30 @@ def test_take_offer(capsys: object, get_test_cli_clients: tuple[TestRpcClients,
class TakeOfferRpcClient(TestWalletRpcClient):
async def take_offer(
self,
offer: Offer,
request: TakeOffer,
tx_config: TXConfig,
solver: Optional[dict[str, Any]] = None,
fee: uint64 = uint64(0),
push: bool = True,
extra_conditions: tuple[Condition, ...] = tuple(),
timelock_info: ConditionValidTimes = ConditionValidTimes(),
) -> TakeOfferResponse:
self.add_to_log("take_offer", (offer, tx_config, solver, fee, push, timelock_info))
self.add_to_log(
"take_offer",
(request.parsed_offer, tx_config, request.solver, request.fee, request.push, timelock_info),
)
return TakeOfferResponse(
[STD_UTX],
[STD_TX],
offer,
request.parsed_offer,
TradeRecord(
confirmed_at_index=uint32(0),
accepted_at_time=uint64(123456789),
created_at_time=uint64(12345678),
is_my_offer=False,
sent=uint32(1),
sent_to=[("aaaaa", uint8(1), None)],
offer=bytes(offer),
offer=bytes(request.parsed_offer),
taken_offer=None,
coins_of_interest=offer.get_involved_coins(),
trade_id=offer.name(),
coins_of_interest=request.parsed_offer.get_involved_coins(),
trade_id=request.parsed_offer.name(),
status=uint32(TradeStatus.PENDING_ACCEPT.value),
valid_times=ConditionValidTimes(),
),
Expand Down
12 changes: 11 additions & 1 deletion chia/_tests/wallet/rpc/test_wallet_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
SetWalletResyncOnStartup,
SpendClawbackCoins,
SplitCoins,
TakeOffer,
VerifySignature,
VerifySignatureResponse,
)
Expand Down Expand Up @@ -1607,7 +1608,16 @@ async def test_offer_endpoints(wallet_environments: WalletTestFramework, wallet_
assert offer_count.my_offers_count == 1
assert offer_count.taken_offers_count == 0

trade_record = (await env_2.rpc_client.take_offer(offer, wallet_environments.tx_config, fee=uint64(1))).trade_record
trade_record = (
await env_2.rpc_client.take_offer(
TakeOffer(
offer=offer.to_bech32(),
fee=uint64(1),
push=True,
),
wallet_environments.tx_config,
)
).trade_record
assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CONFIRM

await env_1.rpc_client.cancel_offer(offer.name(), wallet_environments.tx_config, secure=False)
Expand Down
7 changes: 3 additions & 4 deletions chia/cmds/wallet_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
SignMessageByID,
SignMessageByIDResponse,
SpendClawbackCoins,
TakeOffer,
VCAddProofs,
VCGet,
VCGetList,
Expand Down Expand Up @@ -892,11 +893,9 @@ async def take_offer(
print()
cli_confirm("Would you like to take this offer? (y/n): ")
res = await wallet_client.take_offer(
offer,
fee=fee,
tx_config=CMDTXConfigLoader().to_tx_config(units["chia"], config, fingerprint),
push=push,
TakeOffer(offer=offer.to_bech32(), fee=fee, push=push),
timelock_info=condition_valid_times,
tx_config=CMDTXConfigLoader().to_tx_config(units["chia"], config, fingerprint),
)
if push:
print(f"Accepted offer with ID {res.trade_record.trade_id}")
Expand Down
41 changes: 22 additions & 19 deletions chia/data_layer/data_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
DLUpdateRoot,
LauncherRootPair,
LogIn,
TakeOffer,
)
from chia.wallet.wallet_rpc_client import WalletRpcClient

Expand Down Expand Up @@ -1231,22 +1232,26 @@ async def take_offer(
)
)

solver: dict[str, Any] = {
"proofs_of_inclusion": proofs_of_inclusion,
**{
"0x" + our_offer_store.store_id.hex(): {
"new_root": "0x" + root.hex(),
"dependencies": [
{
"launcher_id": "0x" + their_offer_store.store_id.hex(),
"values_to_prove": ["0x" + entry.node_hash.hex() for entry in their_offer_store.proofs],
}
for their_offer_store in maker
],
}
for our_offer_store in taker
},
}
solver = Solver(
{
"proofs_of_inclusion": proofs_of_inclusion,
**{
"0x" + our_offer_store.store_id.hex(): {
"new_root": "0x" + root.hex(),
"dependencies": [
{
"launcher_id": "0x" + their_offer_store.store_id.hex(),
"values_to_prove": [
"0x" + entry.node_hash.hex() for entry in their_offer_store.proofs
],
}
for their_offer_store in maker
],
}
for our_offer_store in taker
},
}
)

await self.data_store.clean_node_table()

Expand All @@ -1256,9 +1261,7 @@ async def take_offer(

trade_record = (
await self.wallet_rpc.take_offer(
offer=offer,
solver=solver,
fee=fee,
TakeOffer(offer=offer.to_bech32(), solver=solver, fee=fee, push=True),
# 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,
Expand Down
11 changes: 11 additions & 0 deletions chia/wallet/wallet_request_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -1938,6 +1938,17 @@ class CreateOfferForIDsResponse(_OfferEndpointResponse):
pass


@streamable
@dataclass(frozen=True)
class TakeOffer(TransactionEndpointRequest):
offer: str = field(default_factory=default_raise)
solver: Optional[Solver] = None

@cached_property
def parsed_offer(self) -> Offer:
return Offer.from_bech32(self.offer)


@streamable
@dataclass(frozen=True)
class TakeOfferResponse(_OfferEndpointResponse): # Inheriting for de-dup sake
Expand Down
40 changes: 16 additions & 24 deletions chia/wallet/wallet_rpc_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
from chia.wallet.nft_wallet.uncurry_nft import UncurriedNFT
from chia.wallet.notification_store import Notification
from chia.wallet.outer_puzzles import AssetType
from chia.wallet.puzzle_drivers import PuzzleInfo, Solver
from chia.wallet.puzzle_drivers import PuzzleInfo
from chia.wallet.puzzles import p2_delegated_conditions
from chia.wallet.puzzles.clawback.metadata import AutoClaimSettings, ClawbackMetadata
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import puzzle_hash_for_synthetic_public_key
Expand Down Expand Up @@ -284,6 +284,8 @@
StrayCAT,
SubmitTransactions,
SubmitTransactionsResponse,
TakeOffer,
TakeOfferResponse,
TransactionRecordWithMetadata,
VCAddProofs,
VCGet,
Expand Down Expand Up @@ -2324,44 +2326,34 @@ async def check_offer_validity(self, request: CheckOfferValidity) -> CheckOfferV
)

@tx_endpoint(push=True)
@marshal
async def take_offer(
self,
request: dict[str, Any],
request: TakeOffer,
action_scope: WalletActionScope,
extra_conditions: tuple[Condition, ...] = tuple(),
) -> EndpointResult:
offer_hex: str = request["offer"]

offer = Offer.from_bech32(offer_hex)
fee: uint64 = uint64(request.get("fee", 0))
maybe_marshalled_solver: Optional[dict[str, Any]] = request.get("solver")
solver: Optional[Solver]
if maybe_marshalled_solver is None:
solver = None
else:
solver = Solver(info=maybe_marshalled_solver)

) -> TakeOfferResponse:
peer = self.service.get_full_node_peer()
trade_record = await self.service.wallet_state_manager.trade_manager.respond_to_offer(
offer,
request.parsed_offer,
peer,
action_scope,
fee=fee,
solver=solver,
fee=request.fee,
solver=request.solver,
extra_conditions=extra_conditions,
)

async with action_scope.use() as interface:
interface.side_effects.signing_responses.append(
SigningResponse(bytes(offer._bundle.aggregated_signature), trade_record.trade_id)
SigningResponse(bytes(request.parsed_offer._bundle.aggregated_signature), trade_record.trade_id)
)

return {
"trade_record": trade_record.to_json_dict_convenience(),
"offer": Offer.from_bytes(trade_record.offer).to_bech32(),
"transactions": None, # tx_endpoint wrapper will take care of this
"signing_responses": None, # tx_endpoint wrapper will take care of this
}
return TakeOfferResponse(
[], # tx_endpoint will fill in this default value
[], # tx_endpoint will fill in this default value
Offer.from_bytes(trade_record.offer),
trade_record,
)

async def get_offer(self, request: dict[str, Any]) -> EndpointResult:
trade_mgr = self.service.wallet_state_manager.trade_manager
Expand Down
23 changes: 7 additions & 16 deletions chia/wallet/wallet_rpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@
SplitCoinsResponse,
SubmitTransactions,
SubmitTransactionsResponse,
TakeOffer,
TakeOfferResponse,
VCAddProofs,
VCGet,
Expand Down Expand Up @@ -690,26 +691,16 @@ async def check_offer_validity(self, request: CheckOfferValidity) -> CheckOfferV

async def take_offer(
self,
offer: Offer,
request: TakeOffer,
tx_config: TXConfig,
solver: Optional[dict[str, Any]] = None,
fee: int = 0,
extra_conditions: tuple[Condition, ...] = tuple(),
timelock_info: ConditionValidTimes = ConditionValidTimes(),
push: bool = True,
) -> TakeOfferResponse:
req = {
"offer": offer.to_bech32(),
"fee": fee,
"extra_conditions": conditions_to_json_dicts(extra_conditions),
"push": push,
**tx_config.to_json_dict(),
**timelock_info.to_json_dict(),
}
if solver is not None:
req["solver"] = solver
res = await self.fetch("take_offer", req)
return json_deserialize_with_clvm_streamable(res, TakeOfferResponse)
return TakeOfferResponse.from_json_dict(
await self.fetch(
"take_offer", request.json_serialize_for_transport(tx_config, extra_conditions, timelock_info)
)
)

async def get_offer(self, trade_id: bytes32, file_contents: bool = False) -> TradeRecord:
res = await self.fetch("get_offer", {"trade_id": trade_id.hex(), "file_contents": file_contents})
Expand Down
Loading