mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-09-11 18:58:59 +03:00
Add extra_conditions
as an option to transaction endpoints (#15911)
Add extra_conditions as an argument to all transaction methods
This commit is contained in:
parent
05500ea840
commit
6af4f86171
@ -288,6 +288,24 @@ def tx_config_args(func: Callable[..., None]) -> Callable[..., None]:
|
||||
)(coin_selection_args(func))
|
||||
|
||||
|
||||
def timelock_args(func: Callable[..., None]) -> Callable[..., None]:
|
||||
return click.option(
|
||||
"--valid-at",
|
||||
help="UNIX timestamp at which the associated transactions become valid",
|
||||
type=int,
|
||||
required=False,
|
||||
default=None,
|
||||
)(
|
||||
click.option(
|
||||
"--expires-at",
|
||||
help="UNIX timestamp at which the associated transactions expire",
|
||||
type=int,
|
||||
required=False,
|
||||
default=None,
|
||||
)(func)
|
||||
)
|
||||
|
||||
|
||||
@streamable
|
||||
@dataclasses.dataclass(frozen=True)
|
||||
class CMDCoinSelectionConfigLoader(Streamable):
|
||||
|
@ -25,7 +25,7 @@ from chia.types.condition_opcodes import ConditionOpcode
|
||||
from chia.types.spend_bundle import SpendBundle
|
||||
from chia.util.ints import uint8, uint32, uint64, uint128
|
||||
from chia.util.streamable import Streamable, streamable
|
||||
from chia.wallet.conditions import UnknownCondition
|
||||
from chia.wallet.conditions import Condition, UnknownCondition
|
||||
from chia.wallet.db_wallet.db_wallet_puzzles import (
|
||||
ACS_MU,
|
||||
ACS_MU_PH,
|
||||
@ -292,6 +292,7 @@ class DataLayerWallet:
|
||||
initial_root: bytes32,
|
||||
tx_config: TXConfig,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[TransactionRecord, TransactionRecord, bytes32]:
|
||||
"""
|
||||
Creates the initial singleton, which includes spending an origin coin, the launcher, and creating a singleton
|
||||
@ -322,6 +323,7 @@ class DataLayerWallet:
|
||||
primaries=None,
|
||||
ignore_max_send_amount=False,
|
||||
coin_announcements_to_consume={announcement},
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
assert create_launcher_tx_record is not None and create_launcher_tx_record.spend_bundle is not None
|
||||
|
||||
@ -406,6 +408,7 @@ class DataLayerWallet:
|
||||
sign: bool = True,
|
||||
add_pending_singleton: bool = True,
|
||||
announce_new_state: bool = False,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
singleton_record, parent_lineage = await self.get_spendable_singleton_info(launcher_id)
|
||||
|
||||
@ -541,6 +544,17 @@ class DataLayerWallet:
|
||||
],
|
||||
)
|
||||
]
|
||||
if root_hash != singleton_record.root:
|
||||
extra_conditions = (
|
||||
*extra_conditions,
|
||||
UnknownCondition(
|
||||
opcode=Program.to(-24),
|
||||
args=[
|
||||
ACS_MU,
|
||||
Program.to([[(root_hash, None), ACS_MU_PH], None]),
|
||||
],
|
||||
),
|
||||
)
|
||||
inner_sol: Program = self.standard_wallet.make_solution(
|
||||
primaries=primaries,
|
||||
coin_announcements={b"$"} if fee > 0 else None,
|
||||
@ -550,17 +564,7 @@ class DataLayerWallet:
|
||||
puzzle_announcements_to_assert={a.name() for a in puzzle_announcements_to_consume}
|
||||
if puzzle_announcements_to_consume is not None
|
||||
else None,
|
||||
conditions=[
|
||||
UnknownCondition(
|
||||
opcode=Program.to(-24),
|
||||
args=[
|
||||
ACS_MU,
|
||||
Program.to([[(root_hash, None), ACS_MU_PH], None]),
|
||||
],
|
||||
)
|
||||
]
|
||||
if root_hash != singleton_record.root
|
||||
else [],
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
db_layer_sol = Program.to([inner_sol])
|
||||
full_sol = Program.to(
|
||||
@ -639,6 +643,7 @@ class DataLayerWallet:
|
||||
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
ignore_max_send_amount: bool = False, # ignored
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
**kwargs: Unpack[GSTOptionalArgs],
|
||||
) -> List[TransactionRecord]:
|
||||
launcher_id: Optional[bytes32] = kwargs.get("launcher_id", None)
|
||||
@ -677,6 +682,7 @@ class DataLayerWallet:
|
||||
sign,
|
||||
add_pending_singleton,
|
||||
announce_new_state,
|
||||
extra_conditions,
|
||||
)
|
||||
|
||||
async def get_spendable_singleton_info(self, launcher_id: bytes32) -> Tuple[SingletonRecord, LineageProof]:
|
||||
@ -734,7 +740,13 @@ class DataLayerWallet:
|
||||
return collected
|
||||
|
||||
async def create_new_mirror(
|
||||
self, launcher_id: bytes32, amount: uint64, urls: List[bytes], tx_config: TXConfig, fee: uint64 = uint64(0)
|
||||
self,
|
||||
launcher_id: bytes32,
|
||||
amount: uint64,
|
||||
urls: List[bytes],
|
||||
tx_config: TXConfig,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
create_mirror_tx_record: Optional[TransactionRecord] = await self.standard_wallet.generate_signed_transaction(
|
||||
amount=amount,
|
||||
@ -744,12 +756,18 @@ class DataLayerWallet:
|
||||
primaries=[],
|
||||
memos=[launcher_id, *(url for url in urls)],
|
||||
ignore_max_send_amount=False,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
assert create_mirror_tx_record is not None and create_mirror_tx_record.spend_bundle is not None
|
||||
return [create_mirror_tx_record]
|
||||
|
||||
async def delete_mirror(
|
||||
self, mirror_id: bytes32, peer: WSChiaConnection, tx_config: TXConfig, fee: uint64 = uint64(0)
|
||||
self,
|
||||
mirror_id: bytes32,
|
||||
peer: WSChiaConnection,
|
||||
tx_config: TXConfig,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
mirror: Mirror = await self.get_mirror(mirror_id)
|
||||
mirror_coin: Coin = (await self.wallet_state_manager.wallet_node.get_coin_state([mirror.coin_id], peer=peer))[
|
||||
@ -770,6 +788,7 @@ class DataLayerWallet:
|
||||
inner_sol: Program = self.standard_wallet.make_solution(
|
||||
primaries=[Payment(new_puzhash, uint64(mirror_coin.amount - fee))] if excess_fee < 0 else [],
|
||||
coin_announcements={b"$"} if excess_fee > 0 else None,
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
mirror_spend = CoinSpend(
|
||||
mirror_coin,
|
||||
|
@ -46,6 +46,7 @@ from chia.types.coin_record import CoinRecord
|
||||
from chia.types.coin_spend import CoinSpend, compute_additions
|
||||
from chia.types.spend_bundle import SpendBundle
|
||||
from chia.util.ints import uint32, uint64, uint128
|
||||
from chia.wallet.conditions import Condition
|
||||
from chia.wallet.derive_keys import find_owner_sk
|
||||
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import puzzle_hash_for_synthetic_public_key
|
||||
from chia.wallet.sign_coin_spends import sign_coin_spends
|
||||
@ -398,6 +399,7 @@ class PoolWallet:
|
||||
fee: uint64 = uint64(0),
|
||||
p2_singleton_delay_time: Optional[uint64] = None,
|
||||
p2_singleton_delayed_ph: Optional[bytes32] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[TransactionRecord, bytes32, bytes32]:
|
||||
"""
|
||||
A "plot NFT", or pool wallet, represents the idea of a set of plots that all pay to
|
||||
@ -435,6 +437,7 @@ class PoolWallet:
|
||||
p2_singleton_delay_time,
|
||||
p2_singleton_delayed_ph,
|
||||
tx_config,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
|
||||
if spend_bundle is None:
|
||||
@ -644,6 +647,7 @@ class PoolWallet:
|
||||
delay_time: uint64,
|
||||
delay_ph: bytes32,
|
||||
tx_config: TXConfig,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[SpendBundle, bytes32, bytes32]:
|
||||
"""
|
||||
Creates the initial singleton, which includes spending an origin coin, the launcher, and creating a singleton
|
||||
@ -702,6 +706,7 @@ class PoolWallet:
|
||||
False,
|
||||
announcement_set,
|
||||
origin_id=launcher_parent.name(),
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
assert create_launcher_tx_record is not None and create_launcher_tx_record.spend_bundle is not None
|
||||
|
||||
|
@ -2,12 +2,13 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import traceback
|
||||
from typing import Any, Callable, Coroutine, Dict, List, Optional
|
||||
from typing import Any, Callable, Coroutine, Dict, List, Optional, Tuple
|
||||
|
||||
import aiohttp
|
||||
|
||||
from chia.types.blockchain_format.coin import Coin
|
||||
from chia.util.json_util import obj_to_response
|
||||
from chia.wallet.conditions import Condition, conditions_from_json_dicts
|
||||
from chia.wallet.util.tx_config import TXConfig, TXConfigLoader
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -63,6 +64,11 @@ def tx_endpoint(
|
||||
config=self.service.wallet_state_manager.config,
|
||||
logged_in_fingerprint=self.service.logged_in_fingerprint,
|
||||
)
|
||||
return await func(self, request, *args, tx_config=tx_config, **kwargs)
|
||||
|
||||
extra_conditions: Tuple[Condition, ...] = tuple()
|
||||
if "extra_conditions" in request:
|
||||
extra_conditions = tuple(conditions_from_json_dicts(request["extra_conditions"]))
|
||||
|
||||
return await func(self, request, *args, tx_config=tx_config, extra_conditions=extra_conditions, **kwargs)
|
||||
|
||||
return rpc_endpoint
|
||||
|
@ -43,6 +43,7 @@ from chia.util.ws_message import WsRpcMessage, create_payload_dict
|
||||
from chia.wallet.cat_wallet.cat_constants import DEFAULT_CATS
|
||||
from chia.wallet.cat_wallet.cat_info import CRCATInfo
|
||||
from chia.wallet.cat_wallet.cat_wallet import CATWallet
|
||||
from chia.wallet.conditions import Condition
|
||||
from chia.wallet.derive_keys import (
|
||||
MAX_POOL_WALLETS,
|
||||
master_sk_to_farmer_sk,
|
||||
@ -630,7 +631,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def create_new_wallet(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
wallet_state_manager = self.service.wallet_state_manager
|
||||
|
||||
@ -819,6 +823,7 @@ class WalletRpcApi:
|
||||
fee,
|
||||
request.get("p2_singleton_delay_time", None),
|
||||
delayed_address,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
except Exception as e:
|
||||
raise ValueError(str(e))
|
||||
@ -1008,7 +1013,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def send_transaction(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
if await self.service.wallet_state_manager.synced() is False:
|
||||
raise ValueError("Wallet needs to be fully synced before sending transactions")
|
||||
@ -1040,6 +1048,7 @@ class WalletRpcApi:
|
||||
fee,
|
||||
memos=memos,
|
||||
puzzle_decorator_override=request.get("puzzle_decorator", None),
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
await wallet.push_transaction(tx)
|
||||
|
||||
@ -1072,7 +1081,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def spend_clawback_coins(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""Spend clawback coins that were sent (to claw them back) or received (to claim them).
|
||||
|
||||
@ -1107,7 +1119,7 @@ class WalletRpcApi:
|
||||
tx_id_list.extend(
|
||||
(
|
||||
await self.service.wallet_state_manager.spend_clawback_coins(
|
||||
coins, tx_fee, tx_config, request.get("force", False)
|
||||
coins, tx_fee, tx_config, request.get("force", False), extra_conditions=extra_conditions
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -1118,7 +1130,7 @@ class WalletRpcApi:
|
||||
tx_id_list.extend(
|
||||
(
|
||||
await self.service.wallet_state_manager.spend_clawback_coins(
|
||||
coins, tx_fee, tx_config, request.get("force", False)
|
||||
coins, tx_fee, tx_config, request.get("force", False), extra_conditions=extra_conditions
|
||||
)
|
||||
)
|
||||
)
|
||||
@ -1143,7 +1155,12 @@ class WalletRpcApi:
|
||||
return {}
|
||||
|
||||
@tx_endpoint
|
||||
async def select_coins(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def select_coins(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
if await self.service.wallet_state_manager.synced() is False:
|
||||
raise ValueError("Wallet needs to be fully synced before selecting coins")
|
||||
|
||||
@ -1355,7 +1372,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def send_notification(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
tx: TransactionRecord = await self.service.wallet_state_manager.notification_manager.send_new_notification(
|
||||
bytes32.from_hexstr(request["target"]),
|
||||
@ -1363,6 +1383,7 @@ class WalletRpcApi:
|
||||
uint64(request["amount"]),
|
||||
tx_config,
|
||||
request.get("fee", uint64(0)),
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
await self.service.wallet_state_manager.add_pending_transaction(tx)
|
||||
return {"tx": tx.to_json_dict_convenience(self.service.config)}
|
||||
@ -1519,7 +1540,11 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def cat_spend(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG, hold_lock: bool = True
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
hold_lock: bool = True,
|
||||
) -> EndpointResult:
|
||||
if await self.service.wallet_state_manager.synced() is False:
|
||||
raise ValueError("Wallet needs to be fully synced.")
|
||||
@ -1582,6 +1607,7 @@ class WalletRpcApi:
|
||||
cat_discrepancy=cat_discrepancy,
|
||||
coins=coins,
|
||||
memos=memos if memos else None,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
for tx in txs:
|
||||
await wallet.standard_wallet.push_transaction(tx)
|
||||
@ -1594,6 +1620,7 @@ class WalletRpcApi:
|
||||
cat_discrepancy=cat_discrepancy,
|
||||
coins=coins,
|
||||
memos=memos if memos else None,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
for tx in txs:
|
||||
await wallet.standard_wallet.push_transaction(tx)
|
||||
@ -1623,7 +1650,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def create_offer_for_ids(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
offer: Dict[str, int] = request["offer"]
|
||||
fee: uint64 = uint64(request.get("fee", 0))
|
||||
@ -1666,6 +1696,7 @@ class WalletRpcApi:
|
||||
solver=solver,
|
||||
fee=fee,
|
||||
validate_only=validate_only,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
if result[0]:
|
||||
success, trade_record, error = result
|
||||
@ -1766,7 +1797,12 @@ class WalletRpcApi:
|
||||
}
|
||||
|
||||
@tx_endpoint
|
||||
async def take_offer(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def take_offer(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
offer_hex: str = request["offer"]
|
||||
|
||||
###
|
||||
@ -1805,6 +1841,7 @@ class WalletRpcApi:
|
||||
tx_config,
|
||||
fee=fee,
|
||||
solver=solver,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
return {"trade_record": trade_record.to_json_dict_convenience()}
|
||||
|
||||
@ -1860,17 +1897,29 @@ class WalletRpcApi:
|
||||
return {"total": total, "my_offers_count": my_offers_count, "taken_offers_count": taken_offers_count}
|
||||
|
||||
@tx_endpoint
|
||||
async def cancel_offer(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def cancel_offer(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
wsm = self.service.wallet_state_manager
|
||||
secure = request["secure"]
|
||||
trade_id = bytes32.from_hexstr(request["trade_id"])
|
||||
fee: uint64 = uint64(request.get("fee", 0))
|
||||
async with self.service.wallet_state_manager.lock:
|
||||
await wsm.trade_manager.cancel_pending_offers([bytes32(trade_id)], tx_config, fee=fee, secure=secure)
|
||||
await wsm.trade_manager.cancel_pending_offers(
|
||||
[bytes32(trade_id)], tx_config, fee=fee, secure=secure, extra_conditions=extra_conditions
|
||||
)
|
||||
return {}
|
||||
|
||||
@tx_endpoint
|
||||
async def cancel_offers(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def cancel_offers(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
secure = request["secure"]
|
||||
batch_fee: uint64 = uint64(request.get("batch_fee", 0))
|
||||
batch_size = request.get("batch_size", 5)
|
||||
@ -1909,7 +1958,9 @@ class WalletRpcApi:
|
||||
continue
|
||||
|
||||
async with self.service.wallet_state_manager.lock:
|
||||
await trade_mgr.cancel_pending_offers(list(records.keys()), tx_config, batch_fee, secure, records)
|
||||
await trade_mgr.cancel_pending_offers(
|
||||
list(records.keys()), tx_config, batch_fee, secure, records, extra_conditions=extra_conditions
|
||||
)
|
||||
log.info(f"Cancelled offers {start} to {end} ...")
|
||||
# If fewer records were returned than requested, we're done
|
||||
if len(trades) < batch_size:
|
||||
@ -1936,7 +1987,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def did_update_recovery_ids(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
||||
@ -1952,14 +2006,19 @@ class WalletRpcApi:
|
||||
update_success = await wallet.update_recovery_list(recovery_list, new_amount_verifications_required)
|
||||
# Update coin with new ID info
|
||||
if update_success:
|
||||
spend_bundle = await wallet.create_update_spend(tx_config, fee=uint64(request.get("fee", 0)))
|
||||
spend_bundle = await wallet.create_update_spend(
|
||||
tx_config, fee=uint64(request.get("fee", 0)), extra_conditions=extra_conditions
|
||||
)
|
||||
if spend_bundle is not None:
|
||||
success = True
|
||||
return {"success": success}
|
||||
|
||||
@tx_endpoint
|
||||
async def did_message_spend(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
||||
@ -1970,7 +2029,9 @@ class WalletRpcApi:
|
||||
for pa in request.get("puzzle_announcements", []):
|
||||
puzzle_announcements.add(bytes.fromhex(pa))
|
||||
|
||||
spend_bundle = await wallet.create_message_spend(tx_config, coin_announcements, puzzle_announcements)
|
||||
spend_bundle = await wallet.create_message_spend(
|
||||
tx_config, coin_announcements, puzzle_announcements, extra_conditions=extra_conditions
|
||||
)
|
||||
return {"success": True, "spend_bundle": spend_bundle}
|
||||
|
||||
async def did_get_info(self, request: Dict[str, Any]) -> EndpointResult:
|
||||
@ -2202,7 +2263,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def did_update_metadata(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
||||
@ -2213,7 +2277,9 @@ class WalletRpcApi:
|
||||
update_success = await wallet.update_metadata(metadata)
|
||||
# Update coin with new ID info
|
||||
if update_success:
|
||||
spend_bundle = await wallet.create_update_spend(tx_config, uint64(request.get("fee", 0)))
|
||||
spend_bundle = await wallet.create_update_spend(
|
||||
tx_config, uint64(request.get("fee", 0)), extra_conditions=extra_conditions
|
||||
)
|
||||
if spend_bundle is not None:
|
||||
return {"wallet_id": wallet_id, "success": True, "spend_bundle": spend_bundle}
|
||||
else:
|
||||
@ -2301,7 +2367,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def did_create_attest(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=DIDWallet)
|
||||
@ -2314,6 +2383,7 @@ class WalletRpcApi:
|
||||
bytes32.from_hexstr(request["puzhash"]),
|
||||
pubkey,
|
||||
tx_config,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
if info is not None and spend_bundle is not None:
|
||||
return {
|
||||
@ -2369,7 +2439,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def did_transfer_did(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
if await self.service.wallet_state_manager.synced() is False:
|
||||
raise ValueError("Wallet needs to be fully synced.")
|
||||
@ -2382,6 +2455,7 @@ class WalletRpcApi:
|
||||
uint64(request.get("fee", 0)),
|
||||
request.get("with_recovery_info", True),
|
||||
tx_config,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
|
||||
return {
|
||||
@ -2394,7 +2468,12 @@ class WalletRpcApi:
|
||||
# NFT Wallet
|
||||
##########################################################################################
|
||||
@tx_endpoint
|
||||
async def nft_mint_nft(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def nft_mint_nft(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
log.debug("Got minting RPC request: %s", request)
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
assert self.service.wallet_state_manager
|
||||
@ -2453,6 +2532,7 @@ class WalletRpcApi:
|
||||
royalty_amount,
|
||||
did_id,
|
||||
fee,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
nft_id = None
|
||||
assert spend_bundle is not None
|
||||
@ -2505,7 +2585,12 @@ class WalletRpcApi:
|
||||
return {"wallet_id": wallet_id, "success": True, "nft_list": nft_info_list}
|
||||
|
||||
@tx_endpoint
|
||||
async def nft_set_nft_did(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def nft_set_nft_did(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
nft_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=NFTWallet)
|
||||
did_id = request.get("did_id", b"")
|
||||
@ -2518,12 +2603,21 @@ class WalletRpcApi:
|
||||
return {"success": False, "error": "The NFT doesn't support setting a DID."}
|
||||
|
||||
fee = uint64(request.get("fee", 0))
|
||||
spend_bundle = await nft_wallet.set_nft_did(nft_coin_info, did_id, tx_config, fee=fee)
|
||||
spend_bundle = await nft_wallet.set_nft_did(
|
||||
nft_coin_info,
|
||||
did_id,
|
||||
tx_config,
|
||||
fee=fee,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
return {"wallet_id": wallet_id, "success": True, "spend_bundle": spend_bundle}
|
||||
|
||||
@tx_endpoint
|
||||
async def nft_set_did_bulk(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""
|
||||
Bulk set DID for NFTs across different wallets.
|
||||
@ -2574,9 +2668,15 @@ class WalletRpcApi:
|
||||
for wallet_id, nft_list in nft_dict.items():
|
||||
nft_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=NFTWallet)
|
||||
if not first:
|
||||
tx_list.extend(await nft_wallet.set_bulk_nft_did(nft_list, did_id, tx_config))
|
||||
tx_list.extend(
|
||||
await nft_wallet.set_bulk_nft_did(nft_list, did_id, tx_config, extra_conditions=extra_conditions)
|
||||
)
|
||||
else:
|
||||
tx_list.extend(await nft_wallet.set_bulk_nft_did(nft_list, did_id, tx_config, fee, nft_ids))
|
||||
tx_list.extend(
|
||||
await nft_wallet.set_bulk_nft_did(
|
||||
nft_list, did_id, tx_config, fee, nft_ids, extra_conditions=extra_conditions
|
||||
)
|
||||
)
|
||||
for coin in nft_list:
|
||||
coin_ids.append(coin.coin.name())
|
||||
first = False
|
||||
@ -2609,7 +2709,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def nft_transfer_bulk(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""
|
||||
Bulk transfer NFTs to an address.
|
||||
@ -2655,9 +2758,17 @@ class WalletRpcApi:
|
||||
for wallet_id, nft_list in nft_dict.items():
|
||||
nft_wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=NFTWallet)
|
||||
if not first:
|
||||
tx_list.extend(await nft_wallet.bulk_transfer_nft(nft_list, puzzle_hash, tx_config))
|
||||
tx_list.extend(
|
||||
await nft_wallet.bulk_transfer_nft(
|
||||
nft_list, puzzle_hash, tx_config, extra_conditions=extra_conditions
|
||||
)
|
||||
)
|
||||
else:
|
||||
tx_list.extend(await nft_wallet.bulk_transfer_nft(nft_list, puzzle_hash, tx_config, fee))
|
||||
tx_list.extend(
|
||||
await nft_wallet.bulk_transfer_nft(
|
||||
nft_list, puzzle_hash, tx_config, fee, extra_conditions=extra_conditions
|
||||
)
|
||||
)
|
||||
for coin in nft_list:
|
||||
coin_ids.append(coin.coin.name())
|
||||
first = False
|
||||
@ -2744,7 +2855,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def nft_transfer_nft(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
address = request["target_address"]
|
||||
@ -2772,6 +2886,7 @@ class WalletRpcApi:
|
||||
fee=fee,
|
||||
new_owner=b"",
|
||||
new_did_inner_hash=b"",
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
spend_bundle: Optional[SpendBundle] = None
|
||||
for tx in txs:
|
||||
@ -2852,7 +2967,12 @@ class WalletRpcApi:
|
||||
return {"success": True, "nft_info": nft_info}
|
||||
|
||||
@tx_endpoint
|
||||
async def nft_add_uri(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def nft_add_uri(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
# Note metadata updater can only add one uri for one field per spend.
|
||||
# If you want to add multiple uris for one field, you need to spend multiple times.
|
||||
@ -2867,7 +2987,9 @@ class WalletRpcApi:
|
||||
nft_coin_info = await nft_wallet.get_nft_coin_by_id(nft_coin_id)
|
||||
|
||||
fee = uint64(request.get("fee", 0))
|
||||
spend_bundle = await nft_wallet.update_metadata(nft_coin_info, key, uri, tx_config, fee=fee)
|
||||
spend_bundle = await nft_wallet.update_metadata(
|
||||
nft_coin_info, key, uri, tx_config, fee=fee, extra_conditions=extra_conditions
|
||||
)
|
||||
return {"wallet_id": wallet_id, "success": True, "spend_bundle": spend_bundle}
|
||||
|
||||
async def nft_calculate_royalties(self, request: Dict[str, Any]) -> EndpointResult:
|
||||
@ -2880,7 +3002,12 @@ class WalletRpcApi:
|
||||
)
|
||||
|
||||
@tx_endpoint
|
||||
async def nft_mint_bulk(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def nft_mint_bulk(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
if await self.service.wallet_state_manager.synced() is False:
|
||||
raise ValueError("Wallet needs to be fully synced.")
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
@ -2974,6 +3101,7 @@ class WalletRpcApi:
|
||||
did_lineage_parent=did_lineage_parent,
|
||||
fee=fee,
|
||||
tx_config=tx_config,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
else:
|
||||
sb = await nft_wallet.mint_from_xch(
|
||||
@ -2985,6 +3113,7 @@ class WalletRpcApi:
|
||||
xch_change_ph=xch_change_ph,
|
||||
fee=fee,
|
||||
tx_config=tx_config,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
nft_id_list = []
|
||||
for cs in sb.coin_spends:
|
||||
@ -3085,7 +3214,11 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def create_signed_transaction(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG, hold_lock: bool = True
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
hold_lock: bool = True,
|
||||
) -> EndpointResult:
|
||||
if "wallet_id" in request:
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
@ -3173,6 +3306,7 @@ class WalletRpcApi:
|
||||
memos=memos_0,
|
||||
coin_announcements_to_consume=coin_announcements,
|
||||
puzzle_announcements_to_consume=puzzle_announcements,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
signed_tx = tx.to_json_dict_convenience(self.service.config)
|
||||
|
||||
@ -3191,6 +3325,7 @@ class WalletRpcApi:
|
||||
memos=[memos_0] + [output.memos for output in additional_outputs],
|
||||
coin_announcements_to_consume=coin_announcements,
|
||||
puzzle_announcements_to_consume=puzzle_announcements,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
signed_txs = [tx.to_json_dict_convenience(self.service.config) for tx in txs]
|
||||
|
||||
@ -3206,7 +3341,12 @@ class WalletRpcApi:
|
||||
# Pool Wallet
|
||||
##########################################################################################
|
||||
@tx_endpoint
|
||||
async def pw_join_pool(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def pw_join_pool(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
fee = uint64(request.get("fee", 0))
|
||||
wallet_id = uint32(request["wallet_id"])
|
||||
wallet = self.service.wallet_state_manager.get_wallet(id=wallet_id, required_type=PoolWallet)
|
||||
@ -3234,7 +3374,12 @@ class WalletRpcApi:
|
||||
return {"total_fee": total_fee, "transaction": tx, "fee_transaction": fee_tx}
|
||||
|
||||
@tx_endpoint
|
||||
async def pw_self_pool(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def pw_self_pool(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
# Leaving a pool requires two state transitions.
|
||||
# First we transition to PoolSingletonState.LEAVING_POOL
|
||||
# Then we transition to FARMING_TO_POOL or SELF_POOLING
|
||||
@ -3251,7 +3396,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def pw_absorb_rewards(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""Perform a sweep of the p2_singleton rewards controlled by the pool wallet singleton"""
|
||||
if await self.service.wallet_state_manager.synced() is False:
|
||||
@ -3284,7 +3432,12 @@ class WalletRpcApi:
|
||||
# DataLayer Wallet
|
||||
##########################################################################################
|
||||
@tx_endpoint
|
||||
async def create_new_dl(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def create_new_dl(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""Initialize the DataLayer Wallet (only one can exist)"""
|
||||
if self.service.wallet_state_manager is None:
|
||||
raise ValueError("The wallet service is not currently initialized")
|
||||
@ -3298,7 +3451,10 @@ class WalletRpcApi:
|
||||
try:
|
||||
async with self.service.wallet_state_manager.lock:
|
||||
dl_tx, std_tx, launcher_id = await dl_wallet.generate_new_reporter(
|
||||
bytes32.from_hexstr(request["root"]), tx_config, fee=request.get("fee", uint64(0))
|
||||
bytes32.from_hexstr(request["root"]),
|
||||
tx_config,
|
||||
fee=request.get("fee", uint64(0)),
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
await self.service.wallet_state_manager.add_pending_transaction(dl_tx)
|
||||
await self.service.wallet_state_manager.add_pending_transaction(std_tx)
|
||||
@ -3371,7 +3527,12 @@ class WalletRpcApi:
|
||||
return {"singletons": records_json}
|
||||
|
||||
@tx_endpoint
|
||||
async def dl_update_root(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def dl_update_root(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""Get the singleton record for the latest singleton of a launcher ID"""
|
||||
if self.service.wallet_state_manager is None:
|
||||
raise ValueError("The wallet service is not currently initialized")
|
||||
@ -3383,6 +3544,7 @@ class WalletRpcApi:
|
||||
bytes32.from_hexstr(request["new_root"]),
|
||||
tx_config,
|
||||
fee=uint64(request.get("fee", 0)),
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
for record in records:
|
||||
await self.service.wallet_state_manager.add_pending_transaction(record)
|
||||
@ -3390,7 +3552,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def dl_update_multiple(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""Update multiple singletons with new merkle roots"""
|
||||
if self.service.wallet_state_manager is None:
|
||||
@ -3403,7 +3568,10 @@ class WalletRpcApi:
|
||||
tx_records: List[TransactionRecord] = []
|
||||
for launcher, root in request["updates"].items():
|
||||
records = await wallet.create_update_state_spend(
|
||||
bytes32.from_hexstr(launcher), bytes32.from_hexstr(root), tx_config
|
||||
bytes32.from_hexstr(launcher),
|
||||
bytes32.from_hexstr(root),
|
||||
tx_config,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
tx_records.extend(records)
|
||||
# Now that we have all the txs, we need to aggregate them all into just one spend
|
||||
@ -3461,7 +3629,12 @@ class WalletRpcApi:
|
||||
return {"mirrors": mirrors_json}
|
||||
|
||||
@tx_endpoint
|
||||
async def dl_new_mirror(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def dl_new_mirror(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""Add a new on chain message for a specific singleton"""
|
||||
if self.service.wallet_state_manager is None:
|
||||
raise ValueError("The wallet service is not currently initialized")
|
||||
@ -3474,6 +3647,7 @@ class WalletRpcApi:
|
||||
[bytes(url, "utf8") for url in request["urls"]],
|
||||
tx_config,
|
||||
fee=request.get("fee", uint64(0)),
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
for tx in txs:
|
||||
await self.service.wallet_state_manager.add_pending_transaction(tx)
|
||||
@ -3484,7 +3658,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def dl_delete_mirror(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""Remove an existing mirror for a specific singleton"""
|
||||
if self.service.wallet_state_manager is None:
|
||||
@ -3498,6 +3675,7 @@ class WalletRpcApi:
|
||||
self.service.get_full_node_peer(),
|
||||
tx_config,
|
||||
fee=request.get("fee", uint64(0)),
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
for tx in txs:
|
||||
await self.service.wallet_state_manager.add_pending_transaction(tx)
|
||||
@ -3510,7 +3688,12 @@ class WalletRpcApi:
|
||||
# Verified Credential
|
||||
##########################################################################################
|
||||
@tx_endpoint
|
||||
async def vc_mint(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def vc_mint(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""
|
||||
Mint a verified credential using the assigned DID
|
||||
:param request: We require 'did_id' that will be minting the VC and options for a new 'target_address' as well
|
||||
@ -3534,7 +3717,9 @@ class WalletRpcApi:
|
||||
puzhash = decode_puzzle_hash(parsed_request.target_address)
|
||||
|
||||
vc_wallet: VCWallet = await self.service.wallet_state_manager.get_or_create_vc_wallet()
|
||||
vc_record, tx_list = await vc_wallet.launch_new_vc(did_id, tx_config, puzhash, parsed_request.fee)
|
||||
vc_record, tx_list = await vc_wallet.launch_new_vc(
|
||||
did_id, tx_config, puzhash, parsed_request.fee, extra_conditions=extra_conditions
|
||||
)
|
||||
for tx in tx_list:
|
||||
await self.service.wallet_state_manager.add_pending_transaction(tx)
|
||||
return {
|
||||
@ -3590,7 +3775,12 @@ class WalletRpcApi:
|
||||
}
|
||||
|
||||
@tx_endpoint
|
||||
async def vc_spend(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def vc_spend(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""
|
||||
Spend a verified credential
|
||||
:param request: Required 'vc_id' launcher id of the vc we wish to spend. Optional paramaters for a 'new_puzhash'
|
||||
@ -3619,6 +3809,7 @@ class WalletRpcApi:
|
||||
parsed_request.new_puzhash,
|
||||
new_proof_hash=parsed_request.new_proof_hash,
|
||||
provider_inner_puzhash=parsed_request.provider_inner_puzhash,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
for tx in txs:
|
||||
await self.service.wallet_state_manager.add_pending_transaction(tx)
|
||||
@ -3661,7 +3852,12 @@ class WalletRpcApi:
|
||||
return {"proofs": vc_proofs.key_value_pairs}
|
||||
|
||||
@tx_endpoint
|
||||
async def vc_revoke(self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG) -> EndpointResult:
|
||||
async def vc_revoke(
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""
|
||||
Revoke an on chain VC provided the correct DID is available
|
||||
:param request: required 'vc_parent_id' for the VC coin. Standard transaction params 'fee' & 'reuse_puzhash'.
|
||||
@ -3682,6 +3878,7 @@ class WalletRpcApi:
|
||||
self.service.get_full_node_peer(),
|
||||
tx_config,
|
||||
parsed_request.fee,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
for tx in txs:
|
||||
await self.service.wallet_state_manager.add_pending_transaction(tx)
|
||||
@ -3692,7 +3889,10 @@ class WalletRpcApi:
|
||||
|
||||
@tx_endpoint
|
||||
async def crcat_approve_pending(
|
||||
self, request: Dict[str, Any], tx_config: TXConfig = DEFAULT_TX_CONFIG
|
||||
self,
|
||||
request: Dict[str, Any],
|
||||
tx_config: TXConfig = DEFAULT_TX_CONFIG,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> EndpointResult:
|
||||
"""
|
||||
Moving any "pending approval" CR-CATs into the spendable balance of the wallet
|
||||
|
@ -12,6 +12,7 @@ from chia.types.blockchain_format.sized_bytes import bytes32
|
||||
from chia.types.coin_record import CoinRecord
|
||||
from chia.util.bech32m import encode_puzzle_hash
|
||||
from chia.util.ints import uint16, uint32, uint64
|
||||
from chia.wallet.conditions import Condition
|
||||
from chia.wallet.notification_store import Notification
|
||||
from chia.wallet.trade_record import TradeRecord
|
||||
from chia.wallet.trading.offer import Offer
|
||||
@ -189,6 +190,7 @@ class WalletRpcClient(RpcClient):
|
||||
fee: uint64 = uint64(0),
|
||||
memos: Optional[List[str]] = None,
|
||||
puzzle_decorator_override: Optional[List[Dict[str, Union[str, int, bool]]]] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> TransactionRecord:
|
||||
if memos is None:
|
||||
send_dict: Dict = {
|
||||
@ -197,6 +199,7 @@ class WalletRpcClient(RpcClient):
|
||||
"address": address,
|
||||
"fee": fee,
|
||||
"puzzle_decorator": puzzle_decorator_override,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
}
|
||||
else:
|
||||
send_dict = {
|
||||
@ -206,6 +209,7 @@ class WalletRpcClient(RpcClient):
|
||||
"fee": fee,
|
||||
"memos": memos,
|
||||
"puzzle_decorator": puzzle_decorator_override,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
}
|
||||
send_dict.update(tx_config.to_json_dict())
|
||||
res = await self.fetch("send_transaction", send_dict)
|
||||
@ -250,10 +254,16 @@ class WalletRpcClient(RpcClient):
|
||||
coin_ids: List[bytes32],
|
||||
fee: int = 0,
|
||||
force: bool = False,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Dict:
|
||||
response = await self.fetch(
|
||||
"spend_clawback_coins",
|
||||
{"coin_ids": [cid.hex() for cid in coin_ids], "fee": fee, "force": force},
|
||||
{
|
||||
"coin_ids": [cid.hex() for cid in coin_ids],
|
||||
"fee": fee,
|
||||
"force": force,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
},
|
||||
)
|
||||
return response
|
||||
|
||||
@ -282,6 +292,7 @@ class WalletRpcClient(RpcClient):
|
||||
coin_announcements: Optional[List[Announcement]] = None,
|
||||
puzzle_announcements: Optional[List[Announcement]] = None,
|
||||
wallet_id: Optional[int] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
# Converts bytes to hex for puzzle hashes
|
||||
additions_hex = []
|
||||
@ -293,6 +304,7 @@ class WalletRpcClient(RpcClient):
|
||||
request: Dict[str, Any] = {
|
||||
"additions": additions_hex,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
|
||||
@ -452,11 +464,13 @@ class WalletRpcClient(RpcClient):
|
||||
recovery_list: List[str],
|
||||
num_verification: int,
|
||||
tx_config: TXConfig,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Dict:
|
||||
request: Dict[str, Any] = {
|
||||
"wallet_id": wallet_id,
|
||||
"new_list": recovery_list,
|
||||
"num_verifications_required": num_verification,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
response = await self.fetch("did_update_recovery_ids", request)
|
||||
@ -470,12 +484,18 @@ class WalletRpcClient(RpcClient):
|
||||
return response
|
||||
|
||||
async def did_message_spend(
|
||||
self, wallet_id: int, puzzle_announcements: List[str], coin_announcements: List[str], tx_config: TXConfig
|
||||
self,
|
||||
wallet_id: int,
|
||||
puzzle_announcements: List[str],
|
||||
coin_announcements: List[str],
|
||||
tx_config: TXConfig,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Dict:
|
||||
request: Dict[str, Any] = {
|
||||
"wallet_id": wallet_id,
|
||||
"coin_announcements": coin_announcements,
|
||||
"puzzle_announcements": puzzle_announcements,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
response = await self.fetch("did_message_spend", request)
|
||||
@ -486,10 +506,12 @@ class WalletRpcClient(RpcClient):
|
||||
wallet_id: int,
|
||||
metadata: Dict,
|
||||
tx_config: TXConfig,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Dict:
|
||||
request: Dict[str, Any] = {
|
||||
"wallet_id": wallet_id,
|
||||
"metadata": metadata,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
response = await self.fetch("did_update_metadata", request)
|
||||
@ -527,7 +549,13 @@ class WalletRpcClient(RpcClient):
|
||||
return response
|
||||
|
||||
async def did_create_attest(
|
||||
self, wallet_id: int, coin_name: str, pubkey: str, puzhash: str, file_name: str
|
||||
self,
|
||||
wallet_id: int,
|
||||
coin_name: str,
|
||||
pubkey: str,
|
||||
puzhash: str,
|
||||
file_name: str,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Dict:
|
||||
request: Dict[str, Any] = {
|
||||
"wallet_id": wallet_id,
|
||||
@ -535,6 +563,7 @@ class WalletRpcClient(RpcClient):
|
||||
"pubkey": pubkey,
|
||||
"puzhash": puzhash,
|
||||
"filename": file_name,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
}
|
||||
response = await self.fetch("did_create_attest", request)
|
||||
return response
|
||||
@ -554,12 +583,14 @@ class WalletRpcClient(RpcClient):
|
||||
fee: int,
|
||||
with_recovery: bool,
|
||||
tx_config: TXConfig,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Dict:
|
||||
request: Dict[str, Any] = {
|
||||
"wallet_id": wallet_id,
|
||||
"inner_address": address,
|
||||
"fee": fee,
|
||||
"with_recovery_info": with_recovery,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
response = await self.fetch("did_transfer_did", request)
|
||||
@ -587,6 +618,7 @@ class WalletRpcClient(RpcClient):
|
||||
fee: uint64,
|
||||
p2_singleton_delay_time: Optional[uint64] = None,
|
||||
p2_singleton_delayed_ph: Optional[bytes32] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> TransactionRecord:
|
||||
request: Dict[str, Any] = {
|
||||
"wallet_type": "pool_wallet",
|
||||
@ -598,6 +630,7 @@ class WalletRpcClient(RpcClient):
|
||||
"state": state,
|
||||
},
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
}
|
||||
if p2_singleton_delay_time is not None:
|
||||
request["p2_singleton_delay_time"] = p2_singleton_delay_time
|
||||
@ -707,11 +740,13 @@ class WalletRpcClient(RpcClient):
|
||||
additions: Optional[List[Dict[str, Any]]] = None,
|
||||
removals: Optional[List[Coin]] = None,
|
||||
cat_discrepancy: Optional[Tuple[int, Program, Program]] = None, # (extra_delta, tail_reveal, tail_solution)
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> TransactionRecord:
|
||||
send_dict: Dict[str, Any] = {
|
||||
"wallet_id": wallet_id,
|
||||
"fee": fee,
|
||||
"memos": memos if memos else [],
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
if amount is not None and inner_address is not None:
|
||||
@ -744,6 +779,7 @@ class WalletRpcClient(RpcClient):
|
||||
solver: Dict[str, Any] = None,
|
||||
fee=uint64(0),
|
||||
validate_only: bool = False,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[Optional[Offer], TradeRecord]:
|
||||
send_dict: Dict[str, int] = {str(key): value for key, value in offer_dict.items()}
|
||||
|
||||
@ -751,6 +787,7 @@ class WalletRpcClient(RpcClient):
|
||||
"offer": send_dict,
|
||||
"validate_only": validate_only,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
if driver_dict is not None:
|
||||
@ -778,10 +815,12 @@ class WalletRpcClient(RpcClient):
|
||||
tx_config: TXConfig,
|
||||
solver: Dict[str, Any] = None,
|
||||
fee=uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> TradeRecord:
|
||||
req = {
|
||||
"offer": offer.to_bech32(),
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
if solver is not None:
|
||||
@ -829,9 +868,23 @@ class WalletRpcClient(RpcClient):
|
||||
|
||||
return records
|
||||
|
||||
async def cancel_offer(self, trade_id: bytes32, tx_config: TXConfig, fee=uint64(0), secure: bool = True):
|
||||
async def cancel_offer(
|
||||
self,
|
||||
trade_id: bytes32,
|
||||
tx_config: TXConfig,
|
||||
fee=uint64(0),
|
||||
secure: bool = True,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
):
|
||||
await self.fetch(
|
||||
"cancel_offer", {"trade_id": trade_id.hex(), "secure": secure, "fee": fee, **tx_config.to_json_dict()}
|
||||
"cancel_offer",
|
||||
{
|
||||
"trade_id": trade_id.hex(),
|
||||
"secure": secure,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
},
|
||||
)
|
||||
|
||||
async def cancel_offers(
|
||||
@ -842,6 +895,7 @@ class WalletRpcClient(RpcClient):
|
||||
batch_size: int = 5,
|
||||
cancel_all: bool = False,
|
||||
asset_id: Optional[bytes32] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> None:
|
||||
await self.fetch(
|
||||
"cancel_offers",
|
||||
@ -852,6 +906,7 @@ class WalletRpcClient(RpcClient):
|
||||
"batch_size": batch_size,
|
||||
"cancel_all": cancel_all,
|
||||
"asset_id": None if asset_id is None else asset_id.hex(),
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
},
|
||||
)
|
||||
@ -883,6 +938,7 @@ class WalletRpcClient(RpcClient):
|
||||
fee=0,
|
||||
royalty_percentage=0,
|
||||
did_id=None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
):
|
||||
request: Dict[str, Any] = {
|
||||
"wallet_id": wallet_id,
|
||||
@ -899,6 +955,7 @@ class WalletRpcClient(RpcClient):
|
||||
"royalty_percentage": royalty_percentage,
|
||||
"did_id": did_id,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
response = await self.fetch("nft_mint_nft", request)
|
||||
@ -912,6 +969,7 @@ class WalletRpcClient(RpcClient):
|
||||
uri,
|
||||
fee,
|
||||
tx_config: TXConfig,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
):
|
||||
request: Dict[str, Any] = {
|
||||
"wallet_id": wallet_id,
|
||||
@ -919,6 +977,7 @@ class WalletRpcClient(RpcClient):
|
||||
"uri": uri,
|
||||
"key": key,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
response = await self.fetch("nft_add_uri", request)
|
||||
@ -952,12 +1011,14 @@ class WalletRpcClient(RpcClient):
|
||||
target_address,
|
||||
fee,
|
||||
tx_config: TXConfig,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
):
|
||||
request: Dict[str, Any] = {
|
||||
"wallet_id": wallet_id,
|
||||
"nft_coin_id": nft_coin_id,
|
||||
"target_address": target_address,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
response = await self.fetch("nft_transfer_nft", request)
|
||||
@ -980,12 +1041,14 @@ class WalletRpcClient(RpcClient):
|
||||
nft_coin_id,
|
||||
fee,
|
||||
tx_config: TXConfig,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
):
|
||||
request: Dict[str, Any] = {
|
||||
"wallet_id": wallet_id,
|
||||
"did_id": did_id,
|
||||
"nft_coin_id": nft_coin_id,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
response = await self.fetch("nft_set_nft_did", request)
|
||||
@ -1013,6 +1076,7 @@ class WalletRpcClient(RpcClient):
|
||||
did_lineage_parent: Optional[str] = None,
|
||||
mint_from_did: Optional[bool] = False,
|
||||
fee: Optional[int] = 0,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Dict:
|
||||
request = {
|
||||
"wallet_id": wallet_id,
|
||||
@ -1029,14 +1093,24 @@ class WalletRpcClient(RpcClient):
|
||||
"did_lineage_parent": did_lineage_parent,
|
||||
"mint_from_did": mint_from_did,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
}
|
||||
response = await self.fetch("nft_mint_bulk", request)
|
||||
return response
|
||||
|
||||
# DataLayer
|
||||
async def create_new_dl(self, root: bytes32, fee: uint64) -> Tuple[List[TransactionRecord], bytes32]:
|
||||
request = {"root": root.hex(), "fee": fee}
|
||||
async def create_new_dl(
|
||||
self,
|
||||
root: bytes32,
|
||||
fee: uint64,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[List[TransactionRecord], bytes32]:
|
||||
request = {
|
||||
"root": root.hex(),
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
}
|
||||
response = await self.fetch("create_new_dl", request)
|
||||
txs: List[TransactionRecord] = [
|
||||
TransactionRecord.from_json_dict_convenience(tx) for tx in response["transactions"]
|
||||
@ -1066,16 +1140,31 @@ class WalletRpcClient(RpcClient):
|
||||
response = await self.fetch("dl_singletons_by_root", request)
|
||||
return [SingletonRecord.from_json_dict(single) for single in response["singletons"]]
|
||||
|
||||
async def dl_update_root(self, launcher_id: bytes32, new_root: bytes32, fee: uint64) -> TransactionRecord:
|
||||
request = {"launcher_id": launcher_id.hex(), "new_root": new_root.hex(), "fee": fee}
|
||||
async def dl_update_root(
|
||||
self,
|
||||
launcher_id: bytes32,
|
||||
new_root: bytes32,
|
||||
fee: uint64,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> TransactionRecord:
|
||||
request = {
|
||||
"launcher_id": launcher_id.hex(),
|
||||
"new_root": new_root.hex(),
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
}
|
||||
response = await self.fetch("dl_update_root", request)
|
||||
return TransactionRecord.from_json_dict_convenience(response["tx_record"])
|
||||
|
||||
async def dl_update_multiple(self, update_dictionary: Dict[bytes32, bytes32]) -> List[TransactionRecord]:
|
||||
async def dl_update_multiple(
|
||||
self,
|
||||
update_dictionary: Dict[bytes32, bytes32],
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
updates_as_strings: Dict[str, str] = {}
|
||||
for lid, root in update_dictionary.items():
|
||||
updates_as_strings[str(lid)] = str(root)
|
||||
request = {"updates": updates_as_strings}
|
||||
request = {"updates": updates_as_strings, "extra_conditions": list(extra_conditions)}
|
||||
response = await self.fetch("dl_update_multiple", request)
|
||||
return [TransactionRecord.from_json_dict_convenience(tx) for tx in response["tx_records"]]
|
||||
|
||||
@ -1107,7 +1196,12 @@ class WalletRpcClient(RpcClient):
|
||||
return [Mirror.from_json_dict(mirror) for mirror in response["mirrors"]]
|
||||
|
||||
async def dl_new_mirror(
|
||||
self, launcher_id: bytes32, amount: uint64, urls: List[bytes], fee: uint64 = uint64(0)
|
||||
self,
|
||||
launcher_id: bytes32,
|
||||
amount: uint64,
|
||||
urls: List[bytes],
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
response = await self.fetch(
|
||||
path="dl_new_mirror",
|
||||
@ -1116,16 +1210,23 @@ class WalletRpcClient(RpcClient):
|
||||
"amount": amount,
|
||||
"urls": [url.decode("utf8") for url in urls],
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
},
|
||||
)
|
||||
return [TransactionRecord.from_json_dict_convenience(tx) for tx in response["transactions"]]
|
||||
|
||||
async def dl_delete_mirror(self, coin_id: bytes32, fee: uint64 = uint64(0)) -> List[TransactionRecord]:
|
||||
async def dl_delete_mirror(
|
||||
self,
|
||||
coin_id: bytes32,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
response = await self.fetch(
|
||||
path="dl_delete_mirror",
|
||||
request_json={
|
||||
"coin_id": coin_id.hex(),
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
},
|
||||
)
|
||||
return [TransactionRecord.from_json_dict_convenience(tx) for tx in response["transactions"]]
|
||||
@ -1160,7 +1261,12 @@ class WalletRpcClient(RpcClient):
|
||||
return response["success"]
|
||||
|
||||
async def send_notification(
|
||||
self, target: bytes32, msg: bytes, amount: uint64, fee: uint64 = uint64(0)
|
||||
self,
|
||||
target: bytes32,
|
||||
msg: bytes,
|
||||
amount: uint64,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> TransactionRecord:
|
||||
response = await self.fetch(
|
||||
"send_notification",
|
||||
@ -1169,6 +1275,7 @@ class WalletRpcClient(RpcClient):
|
||||
"message": msg.hex(),
|
||||
"amount": amount,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
},
|
||||
)
|
||||
return TransactionRecord.from_json_dict_convenience(response["tx"])
|
||||
@ -1182,7 +1289,12 @@ class WalletRpcClient(RpcClient):
|
||||
return response["pubkey"], response["signature"], response["signing_mode"]
|
||||
|
||||
async def vc_mint(
|
||||
self, did_id: bytes32, tx_config: TXConfig, target_address: Optional[bytes32] = None, fee: uint64 = uint64(0)
|
||||
self,
|
||||
did_id: bytes32,
|
||||
tx_config: TXConfig,
|
||||
target_address: Optional[bytes32] = None,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[VCRecord, List[TransactionRecord]]:
|
||||
response = await self.fetch(
|
||||
"vc_mint",
|
||||
@ -1190,6 +1302,7 @@ class WalletRpcClient(RpcClient):
|
||||
"did_id": encode_puzzle_hash(did_id, "rpc"),
|
||||
"target_address": encode_puzzle_hash(target_address, "rpc") if target_address is not None else None,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
},
|
||||
)
|
||||
@ -1213,6 +1326,7 @@ class WalletRpcClient(RpcClient):
|
||||
new_proof_hash: Optional[bytes32] = None,
|
||||
provider_inner_puzhash: Optional[bytes32] = None,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
response = await self.fetch(
|
||||
"vc_spend",
|
||||
@ -1224,6 +1338,7 @@ class WalletRpcClient(RpcClient):
|
||||
if provider_inner_puzhash is not None
|
||||
else provider_inner_puzhash,
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
},
|
||||
)
|
||||
@ -1241,9 +1356,16 @@ class WalletRpcClient(RpcClient):
|
||||
vc_parent_id: bytes32,
|
||||
tx_config: TXConfig,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
response = await self.fetch(
|
||||
"vc_revoke", {"vc_parent_id": vc_parent_id.hex(), "fee": fee, **tx_config.to_json_dict()}
|
||||
"vc_revoke",
|
||||
{
|
||||
"vc_parent_id": vc_parent_id.hex(),
|
||||
"fee": fee,
|
||||
"extra_conditions": list(extra_conditions),
|
||||
**tx_config.to_json_dict(),
|
||||
},
|
||||
)
|
||||
return [TransactionRecord.from_json_dict_convenience(tx) for tx in response["transactions"]]
|
||||
|
||||
|
@ -618,6 +618,7 @@ class CATWallet:
|
||||
coins: Optional[Set[Coin]] = None,
|
||||
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[SpendBundle, Optional[TransactionRecord]]:
|
||||
if coin_announcements_to_consume is not None:
|
||||
coin_announcements_bytes: Optional[Set[bytes32]] = {a.name() for a in coin_announcements_to_consume}
|
||||
@ -681,19 +682,18 @@ class CATWallet:
|
||||
announcement: Announcement
|
||||
|
||||
for coin in cat_coins:
|
||||
extra_conditions: List[Condition] = []
|
||||
if cat_discrepancy is not None:
|
||||
extra_conditions.append(
|
||||
UnknownCondition(
|
||||
opcode=Program.to(51),
|
||||
args=[
|
||||
Program.to(None),
|
||||
Program.to(-113),
|
||||
tail_reveal,
|
||||
tail_solution,
|
||||
],
|
||||
)
|
||||
cat_condition = UnknownCondition(
|
||||
opcode=Program.to(51),
|
||||
args=[
|
||||
Program.to(None),
|
||||
Program.to(-113),
|
||||
tail_reveal,
|
||||
tail_solution,
|
||||
],
|
||||
)
|
||||
if first:
|
||||
extra_conditions = (*extra_conditions, cat_condition)
|
||||
if first:
|
||||
first = False
|
||||
announcement = Announcement(coin.name(), std_hash(b"".join([c.name() for c in cat_coins])))
|
||||
@ -778,6 +778,7 @@ class CATWallet:
|
||||
memos: Optional[List[List[bytes]]] = None,
|
||||
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
**kwargs: Unpack[GSTOptionalArgs],
|
||||
) -> List[TransactionRecord]:
|
||||
# (extra_delta, tail_reveal, tail_solution)
|
||||
@ -807,6 +808,7 @@ class CATWallet:
|
||||
coins=coins,
|
||||
coin_announcements_to_consume=coin_announcements_to_consume,
|
||||
puzzle_announcements_to_consume=puzzle_announcements_to_consume,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
spend_bundle = await self.sign(unsigned_spend_bundle)
|
||||
# TODO add support for array in stored records
|
||||
|
@ -20,6 +20,7 @@ from chia.types.coin_spend import CoinSpend
|
||||
from chia.types.spend_bundle import SpendBundle
|
||||
from chia.util.condition_tools import conditions_dict_for_solution, pkm_pairs_for_conditions_dict
|
||||
from chia.util.ints import uint32, uint64, uint128
|
||||
from chia.wallet.conditions import Condition
|
||||
from chia.wallet.derivation_record import DerivationRecord
|
||||
from chia.wallet.derive_keys import master_sk_to_wallet_sk_unhardened
|
||||
from chia.wallet.did_wallet import did_wallet_puzzles
|
||||
@ -531,7 +532,9 @@ class DIDWallet:
|
||||
def get_name(self):
|
||||
return self.wallet_info.name
|
||||
|
||||
async def create_update_spend(self, tx_config: TXConfig, fee: uint64 = uint64(0)):
|
||||
async def create_update_spend(
|
||||
self, tx_config: TXConfig, fee: uint64 = uint64(0), extra_conditions: Tuple[Condition, ...] = tuple()
|
||||
):
|
||||
assert self.did_info.current_inner is not None
|
||||
assert self.did_info.origin_coin is not None
|
||||
coin = await self.get_coin()
|
||||
@ -543,6 +546,7 @@ class DIDWallet:
|
||||
p2_solution = self.standard_wallet.make_solution(
|
||||
primaries=[Payment(new_inner_puzzle.get_tree_hash(), uint64(coin.amount), [p2_puzzle.get_tree_hash()])],
|
||||
coin_announcements={coin.name()},
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
innersol: Program = Program.to([1, p2_solution])
|
||||
# full solution is (corehash parent_info my_amount innerpuz_reveal solution)
|
||||
@ -625,6 +629,7 @@ class DIDWallet:
|
||||
fee: uint64,
|
||||
with_recovery: bool,
|
||||
tx_config: TXConfig,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> TransactionRecord:
|
||||
"""
|
||||
Transfer the current DID to another owner
|
||||
@ -651,6 +656,7 @@ class DIDWallet:
|
||||
p2_solution = self.standard_wallet.make_solution(
|
||||
primaries=[Payment(new_did_puzhash, uint64(coin.amount), [new_puzhash])],
|
||||
coin_announcements={coin.name()},
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
# Need to include backup list reveal here, even we are don't recover
|
||||
# innerpuz solution is
|
||||
@ -720,6 +726,7 @@ class DIDWallet:
|
||||
puzzle_announcements: Optional[Set[bytes]] = None,
|
||||
coin_announcements_to_assert: Optional[Set[Announcement]] = None,
|
||||
puzzle_announcements_to_assert: Optional[Set[Announcement]] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
):
|
||||
assert self.did_info.current_inner is not None
|
||||
assert self.did_info.origin_coin is not None
|
||||
@ -750,6 +757,7 @@ class DIDWallet:
|
||||
puzzle_announcements_to_assert={a.name() for a in puzzle_announcements_to_assert}
|
||||
if puzzle_announcements_to_assert is not None
|
||||
else None,
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
# innerpuz solution is (mode p2_solution)
|
||||
innersol: Program = Program.to([1, p2_solution])
|
||||
@ -833,7 +841,12 @@ class DIDWallet:
|
||||
# Pushes a SpendBundle to create a message coin on the blockchain
|
||||
# Returns a SpendBundle for the recoverer to spend the message coin
|
||||
async def create_attestment(
|
||||
self, recovering_coin_name: bytes32, newpuz: bytes32, pubkey: G1Element, tx_config: TXConfig
|
||||
self,
|
||||
recovering_coin_name: bytes32,
|
||||
newpuz: bytes32,
|
||||
pubkey: G1Element,
|
||||
tx_config: TXConfig,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[SpendBundle, str]:
|
||||
"""
|
||||
Create an attestment
|
||||
@ -857,6 +870,7 @@ class DIDWallet:
|
||||
Payment(innerpuz.get_tree_hash(), uint64(coin.amount), [p2_puzzle.get_tree_hash()]),
|
||||
Payment(innermessage, uint64(0)),
|
||||
],
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
innersol = Program.to([1, p2_solution])
|
||||
|
||||
@ -1276,14 +1290,21 @@ class DIDWallet:
|
||||
await self.wallet_state_manager.add_pending_transaction(did_record)
|
||||
return full_spend
|
||||
|
||||
async def generate_eve_spend(self, coin: Coin, full_puzzle: Program, innerpuz: Program):
|
||||
async def generate_eve_spend(
|
||||
self,
|
||||
coin: Coin,
|
||||
full_puzzle: Program,
|
||||
innerpuz: Program,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
):
|
||||
assert self.did_info.origin_coin is not None
|
||||
uncurried = did_wallet_puzzles.uncurry_innerpuz(innerpuz)
|
||||
assert uncurried is not None
|
||||
p2_puzzle = uncurried[0]
|
||||
# innerpuz solution is (mode p2_solution)
|
||||
p2_solution = self.standard_wallet.make_solution(
|
||||
primaries=[Payment(innerpuz.get_tree_hash(), uint64(coin.amount), [p2_puzzle.get_tree_hash()])]
|
||||
primaries=[Payment(innerpuz.get_tree_hash(), uint64(coin.amount), [p2_puzzle.get_tree_hash()])],
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
innersol = Program.to([1, p2_solution])
|
||||
# full solution is (lineage_proof my_amount inner_solution)
|
||||
|
@ -340,6 +340,7 @@ class NFTWallet:
|
||||
did_id: Optional[bytes] = None,
|
||||
fee: uint64 = uint64(0),
|
||||
push_tx: bool = True,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Optional[SpendBundle]:
|
||||
"""
|
||||
This must be called under the wallet state manager lock
|
||||
@ -403,6 +404,7 @@ class NFTWallet:
|
||||
False,
|
||||
announcement_set,
|
||||
origin_id=origin.name(),
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
genesis_launcher_solution = Program.to([eve_fullpuz_hash, amount, []])
|
||||
|
||||
@ -494,6 +496,7 @@ class NFTWallet:
|
||||
uri: str,
|
||||
tx_config: TXConfig,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Optional[SpendBundle]:
|
||||
uncurried_nft = UncurriedNFT.uncurry(*nft_coin_info.full_puzzle.uncurry())
|
||||
assert uncurried_nft is not None
|
||||
@ -511,6 +514,7 @@ class NFTWallet:
|
||||
fee,
|
||||
{nft_coin_info.coin},
|
||||
metadata_update=(key, uri),
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
for tx in txs:
|
||||
await self.wallet_state_manager.add_pending_transaction(tx)
|
||||
@ -622,6 +626,7 @@ class NFTWallet:
|
||||
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
ignore_max_send_amount: bool = False,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
**kwargs: Unpack[GSTOptionalArgs],
|
||||
) -> List[TransactionRecord]:
|
||||
nft_coin: Optional[NFTCoinInfo] = kwargs.get("nft_coin", None)
|
||||
@ -655,6 +660,7 @@ class NFTWallet:
|
||||
new_did_inner_hash=new_did_inner_hash,
|
||||
trade_prices_list=trade_prices_list,
|
||||
metadata_update=metadata_update,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
spend_bundle = await self.sign(unsigned_spend_bundle)
|
||||
spend_bundle = SpendBundle.aggregate([spend_bundle] + additional_bundles)
|
||||
@ -701,6 +707,7 @@ class NFTWallet:
|
||||
trade_prices_list: Optional[Program] = None,
|
||||
metadata_update: Optional[Tuple[str, str]] = None,
|
||||
nft_coin: Optional[NFTCoinInfo] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[SpendBundle, Optional[TransactionRecord]]:
|
||||
if nft_coin is None:
|
||||
if coins is None or not len(coins) == 1:
|
||||
@ -730,7 +737,6 @@ class NFTWallet:
|
||||
announcement_to_make = None
|
||||
chia_tx = None
|
||||
|
||||
extra_conditions: List[Condition] = []
|
||||
unft = UncurriedNFT.uncurry(*nft_coin.full_puzzle.uncurry())
|
||||
assert unft is not None
|
||||
if unft.supports_did:
|
||||
@ -743,7 +749,8 @@ class NFTWallet:
|
||||
)
|
||||
if derivation_record is not None:
|
||||
new_owner = unft.owner_did
|
||||
extra_conditions.append(
|
||||
extra_conditions = (
|
||||
*extra_conditions,
|
||||
UnknownCondition(
|
||||
opcode=Program.to(-10),
|
||||
args=[
|
||||
@ -751,17 +758,18 @@ class NFTWallet:
|
||||
Program.to(trade_prices_list),
|
||||
Program.to(new_did_inner_hash),
|
||||
],
|
||||
)
|
||||
),
|
||||
)
|
||||
if metadata_update is not None:
|
||||
extra_conditions.append(
|
||||
extra_conditions = (
|
||||
*extra_conditions,
|
||||
UnknownCondition(
|
||||
opcode=Program.to(-24),
|
||||
args=[
|
||||
NFT_METADATA_UPDATER,
|
||||
Program.to(metadata_update),
|
||||
],
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
innersol: Program = self.standard_wallet.make_solution(
|
||||
@ -1107,6 +1115,7 @@ class NFTWallet:
|
||||
tx_config: TXConfig,
|
||||
fee: uint64 = uint64(0),
|
||||
announcement_ids: List[bytes32] = [],
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
self.log.debug("Setting NFT DID with parameters: nft=%s did=%s", nft_list, did_id)
|
||||
did_inner_hash = b""
|
||||
@ -1127,6 +1136,7 @@ class NFTWallet:
|
||||
puzzle_hashes_to_sign = [unft.p2_puzzle.get_tree_hash()]
|
||||
if not first:
|
||||
fee = uint64(0)
|
||||
extra_conditions = tuple()
|
||||
nft_tx_record.extend(
|
||||
await self.generate_signed_transaction(
|
||||
[uint64(nft_coin_info.coin.amount)],
|
||||
@ -1136,6 +1146,7 @@ class NFTWallet:
|
||||
{nft_coin_info.coin},
|
||||
new_owner=did_id,
|
||||
new_did_inner_hash=did_inner_hash,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
)
|
||||
first = False
|
||||
@ -1158,6 +1169,7 @@ class NFTWallet:
|
||||
puzzle_hash: bytes32,
|
||||
tx_config: TXConfig,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
self.log.debug("Transfer NFTs %s to %s", nft_list, puzzle_hash.hex())
|
||||
nft_tx_record = []
|
||||
@ -1167,6 +1179,7 @@ class NFTWallet:
|
||||
for nft_coin_info in nft_list:
|
||||
if not first:
|
||||
fee = uint64(0)
|
||||
extra_conditions = tuple()
|
||||
nft_tx_record.extend(
|
||||
await self.generate_signed_transaction(
|
||||
[uint64(nft_coin_info.coin.amount)],
|
||||
@ -1176,6 +1189,7 @@ class NFTWallet:
|
||||
fee=fee,
|
||||
new_owner=b"",
|
||||
new_did_inner_hash=b"",
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
)
|
||||
first = False
|
||||
@ -1197,6 +1211,7 @@ class NFTWallet:
|
||||
did_id: bytes,
|
||||
tx_config: TXConfig,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> SpendBundle:
|
||||
self.log.debug("Setting NFT DID with parameters: nft=%s did=%s", nft_coin_info, did_id)
|
||||
unft = UncurriedNFT.uncurry(*nft_coin_info.full_puzzle.uncurry())
|
||||
@ -1218,6 +1233,7 @@ class NFTWallet:
|
||||
new_owner=did_id,
|
||||
new_did_inner_hash=did_inner_hash,
|
||||
additional_bundles=additional_bundles,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
spend_bundle = SpendBundle.aggregate([x.spend_bundle for x in nft_tx_record if x.spend_bundle is not None])
|
||||
if spend_bundle:
|
||||
@ -1243,6 +1259,7 @@ class NFTWallet:
|
||||
did_coin: Optional[Coin] = None,
|
||||
did_lineage_parent: Optional[bytes32] = None,
|
||||
fee: Optional[uint64] = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> SpendBundle:
|
||||
"""
|
||||
Minting NFTs from the DID linked wallet, also used for bulk minting NFTs.
|
||||
@ -1475,6 +1492,7 @@ class NFTWallet:
|
||||
coin_announcements=did_coin_announcement,
|
||||
coin_announcements_to_assert=did_announcements,
|
||||
puzzle_announcements_to_assert=puzzle_assertions,
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
did_inner_sol: Program = Program.to([1, did_p2_solution])
|
||||
did_full_puzzle: Program = chia.wallet.singleton.create_singleton_puzzle(
|
||||
@ -1524,6 +1542,7 @@ class NFTWallet:
|
||||
xch_coins: Optional[Set[Coin]] = None,
|
||||
xch_change_ph: Optional[bytes32] = None,
|
||||
fee: Optional[uint64] = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> SpendBundle:
|
||||
"""
|
||||
Minting NFTs from a single XCH spend using intermediate launcher puzzle
|
||||
@ -1695,6 +1714,7 @@ class NFTWallet:
|
||||
coin_announcements=xch_announcement if len(xch_coins) > 1 else None,
|
||||
coin_announcements_to_assert=coin_announcements,
|
||||
puzzle_announcements_to_assert=puzzle_assertions,
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
primary_announcement_hash = Announcement(xch_coin.name(), message).name()
|
||||
first = False
|
||||
|
@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional, Set
|
||||
from typing import Any, Dict, List, Optional, Set, Tuple
|
||||
|
||||
from blspy import G2Element
|
||||
|
||||
@ -15,6 +15,7 @@ from chia.types.coin_spend import CoinSpend
|
||||
from chia.types.spend_bundle import SpendBundle
|
||||
from chia.util.db_wrapper import DBWrapper2
|
||||
from chia.util.ints import uint32, uint64
|
||||
from chia.wallet.conditions import Condition
|
||||
from chia.wallet.notification_store import Notification, NotificationStore
|
||||
from chia.wallet.transaction_record import TransactionRecord
|
||||
from chia.wallet.util.compute_memos import compute_memos_for_spend
|
||||
@ -83,7 +84,13 @@ class NotificationManager:
|
||||
return True
|
||||
|
||||
async def send_new_notification(
|
||||
self, target: bytes32, msg: bytes, amount: uint64, tx_config: TXConfig, fee: uint64 = uint64(0)
|
||||
self,
|
||||
target: bytes32,
|
||||
msg: bytes,
|
||||
amount: uint64,
|
||||
tx_config: TXConfig,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> TransactionRecord:
|
||||
coins: Set[Coin] = await self.wallet_state_manager.main_wallet.select_coins(
|
||||
uint64(amount + fee), tx_config.coin_selection_config
|
||||
@ -107,6 +114,7 @@ class NotificationManager:
|
||||
origin_id=origin_coin,
|
||||
coin_announcements_to_consume={Announcement(notification_coin.name(), b"")},
|
||||
memos=[target, msg],
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
full_tx: TransactionRecord = dataclasses.replace(
|
||||
chia_tx, spend_bundle=SpendBundle.aggregate([chia_tx.spend_bundle, extra_spend_bundle])
|
||||
|
@ -17,6 +17,7 @@ from chia.types.spend_bundle import SpendBundle
|
||||
from chia.util.db_wrapper import DBWrapper2
|
||||
from chia.util.hash import std_hash
|
||||
from chia.util.ints import uint32, uint64
|
||||
from chia.wallet.conditions import Condition
|
||||
from chia.wallet.db_wallet.db_wallet_puzzles import ACS_MU_PH
|
||||
from chia.wallet.nft_wallet.nft_wallet import NFTWallet
|
||||
from chia.wallet.outer_puzzles import AssetType
|
||||
@ -228,6 +229,7 @@ class TradeManager:
|
||||
fee: uint64 = uint64(0),
|
||||
secure: bool = True, # Cancel with a transaction on chain
|
||||
trade_cache: Dict[bytes32, TradeRecord] = {}, # Optional pre-fetched trade records for optimization
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Optional[List[TransactionRecord]]:
|
||||
"""This will create a transaction that includes coins that were offered"""
|
||||
|
||||
@ -282,6 +284,7 @@ class TradeManager:
|
||||
fee=fee_to_pay,
|
||||
coins=selected_coins,
|
||||
ignore_max_send_amount=True,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
if tx is not None and tx.spend_bundle is not None:
|
||||
bundles.append(tx.spend_bundle)
|
||||
@ -298,6 +301,7 @@ class TradeManager:
|
||||
fee=fee_to_pay,
|
||||
coins={coin},
|
||||
ignore_max_send_amount=True,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
for tx in txs:
|
||||
if tx is not None and tx.spend_bundle is not None:
|
||||
@ -305,6 +309,7 @@ class TradeManager:
|
||||
cancellation_additions.extend(tx.spend_bundle.additions())
|
||||
all_txs.append(dataclasses.replace(tx, spend_bundle=None))
|
||||
fee_to_pay = uint64(0)
|
||||
extra_conditions = tuple()
|
||||
|
||||
all_txs.append(
|
||||
TransactionRecord(
|
||||
@ -358,6 +363,7 @@ class TradeManager:
|
||||
solver: Optional[Solver] = None,
|
||||
fee: uint64 = uint64(0),
|
||||
validate_only: bool = False,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
taking: bool = False,
|
||||
) -> Union[Tuple[Literal[True], TradeRecord, None], Tuple[Literal[False], None, str]]:
|
||||
if driver_dict is None:
|
||||
@ -370,6 +376,7 @@ class TradeManager:
|
||||
driver_dict,
|
||||
solver,
|
||||
fee=fee,
|
||||
extra_conditions=extra_conditions,
|
||||
taking=taking,
|
||||
)
|
||||
if not result[0] or result[1] is None:
|
||||
@ -404,6 +411,7 @@ class TradeManager:
|
||||
driver_dict: Optional[Dict[bytes32, PuzzleInfo]] = None,
|
||||
solver: Optional[Solver] = None,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
taking: bool = False,
|
||||
) -> Union[Tuple[Literal[True], Offer, None], Tuple[Literal[False], None, str]]:
|
||||
"""
|
||||
@ -526,6 +534,7 @@ class TradeManager:
|
||||
fee=fee_left_to_pay,
|
||||
coins=set(selected_coins),
|
||||
puzzle_announcements_to_consume=announcements_to_assert,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
all_transactions.append(tx)
|
||||
elif wallet.type() == WalletType.NFT:
|
||||
@ -540,6 +549,7 @@ class TradeManager:
|
||||
fee=fee_left_to_pay,
|
||||
coins=set(selected_coins),
|
||||
puzzle_announcements_to_consume=announcements_to_assert,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
all_transactions.extend(txs)
|
||||
else:
|
||||
@ -551,11 +561,13 @@ class TradeManager:
|
||||
fee=fee_left_to_pay,
|
||||
coins=set(selected_coins),
|
||||
puzzle_announcements_to_consume=announcements_to_assert,
|
||||
extra_conditions=extra_conditions,
|
||||
add_authorizations_to_cr_cats=False,
|
||||
)
|
||||
all_transactions.extend(txs)
|
||||
|
||||
fee_left_to_pay = uint64(0)
|
||||
extra_conditions = tuple()
|
||||
|
||||
total_spend_bundle = SpendBundle.aggregate(
|
||||
[x.spend_bundle for x in all_transactions if x.spend_bundle is not None]
|
||||
@ -696,6 +708,7 @@ class TradeManager:
|
||||
tx_config: TXConfig,
|
||||
solver: Optional[Solver] = None,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[TradeRecord, List[TransactionRecord]]:
|
||||
if solver is None:
|
||||
solver = Solver({})
|
||||
@ -727,6 +740,7 @@ class TradeManager:
|
||||
offer.driver_dict,
|
||||
solver,
|
||||
fee=fee,
|
||||
extra_conditions=extra_conditions,
|
||||
taking=True,
|
||||
)
|
||||
if not result[0] or result[1] is None:
|
||||
|
@ -24,6 +24,7 @@ from chia.wallet.cat_wallet.cat_info import CRCATInfo
|
||||
from chia.wallet.cat_wallet.cat_utils import CAT_MOD, construct_cat_puzzle
|
||||
from chia.wallet.cat_wallet.cat_wallet import CATWallet
|
||||
from chia.wallet.coin_selection import select_coins
|
||||
from chia.wallet.conditions import Condition, UnknownCondition
|
||||
from chia.wallet.lineage_proof import LineageProof
|
||||
from chia.wallet.outer_puzzles import AssetType
|
||||
from chia.wallet.payment import Payment
|
||||
@ -388,6 +389,7 @@ class CRCATWallet(CATWallet):
|
||||
coins: Optional[Set[Coin]] = None,
|
||||
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
add_authorizations_to_cr_cats: bool = True,
|
||||
) -> Tuple[SpendBundle, List[TransactionRecord]]:
|
||||
if coin_announcements_to_consume is not None: # pragma: no cover
|
||||
@ -485,6 +487,19 @@ class CRCATWallet(CATWallet):
|
||||
self.info.authorized_providers, self.info.proofs_checker.flags
|
||||
)
|
||||
|
||||
if cat_discrepancy is not None:
|
||||
cat_condition = UnknownCondition(
|
||||
opcode=Program.to(51),
|
||||
args=[
|
||||
Program.to(None),
|
||||
Program.to(-113),
|
||||
tail_reveal,
|
||||
tail_solution,
|
||||
],
|
||||
)
|
||||
if first:
|
||||
extra_conditions = (*extra_conditions, cat_condition)
|
||||
|
||||
crcat: CRCAT = self.coin_record_to_crcat(coin)
|
||||
vc_announcements_to_make.append(crcat.expected_announcement())
|
||||
if first:
|
||||
@ -502,6 +517,7 @@ class CRCATWallet(CATWallet):
|
||||
coin_announcements={announcement.message},
|
||||
coin_announcements_to_assert=coin_announcements_bytes,
|
||||
puzzle_announcements_to_assert=puzzle_announcements_bytes,
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
elif regular_chia_to_claim > fee:
|
||||
chia_tx, xch_announcement = await self.create_tandem_xch_tx(
|
||||
@ -514,6 +530,7 @@ class CRCATWallet(CATWallet):
|
||||
primaries=primaries,
|
||||
coin_announcements={announcement.message},
|
||||
coin_announcements_to_assert={xch_announcement.name()},
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
else:
|
||||
innersol = self.standard_wallet.make_solution(
|
||||
@ -521,17 +538,13 @@ class CRCATWallet(CATWallet):
|
||||
coin_announcements={announcement.message},
|
||||
coin_announcements_to_assert=coin_announcements_bytes,
|
||||
puzzle_announcements_to_assert=puzzle_announcements_bytes,
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
else:
|
||||
innersol = self.standard_wallet.make_solution(
|
||||
primaries=[],
|
||||
coin_announcements_to_assert={announcement.name()},
|
||||
)
|
||||
if first and cat_discrepancy is not None:
|
||||
# TODO: This line is a hack, make_solution should allow us to pass extra conditions to it
|
||||
innersol = Program.to(
|
||||
[[], (1, Program.to([51, None, -113, tail_reveal, tail_solution]).cons(innersol.at("rfr"))), []]
|
||||
)
|
||||
inner_derivation_record = (
|
||||
await self.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(
|
||||
crcat.inner_puzzle_hash
|
||||
@ -611,6 +624,7 @@ class CRCATWallet(CATWallet):
|
||||
memos: Optional[List[List[bytes]]] = None,
|
||||
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
**kwargs: Unpack[GSTOptionalArgs],
|
||||
) -> List[TransactionRecord]:
|
||||
# (extra_delta, tail_reveal, tail_solution)
|
||||
@ -651,6 +665,7 @@ class CRCATWallet(CATWallet):
|
||||
coins=coins,
|
||||
coin_announcements_to_consume=coin_announcements_to_consume,
|
||||
puzzle_announcements_to_consume=puzzle_announcements_to_consume,
|
||||
extra_conditions=extra_conditions,
|
||||
add_authorizations_to_cr_cats=add_authorizations_to_cr_cats,
|
||||
)
|
||||
|
||||
|
@ -10,6 +10,7 @@ from chia.types.coin_spend import CoinSpend, compute_additions
|
||||
from chia.util.hash import std_hash
|
||||
from chia.util.ints import uint64
|
||||
from chia.util.streamable import Streamable, streamable
|
||||
from chia.wallet.conditions import Condition
|
||||
from chia.wallet.lineage_proof import LineageProof
|
||||
from chia.wallet.puzzles.load_clvm import load_clvm_maybe_recompile
|
||||
from chia.wallet.puzzles.singleton_top_layer_v1_1 import (
|
||||
@ -337,6 +338,7 @@ class VerifiedCredential(Streamable):
|
||||
new_inner_puzzle_hash: bytes32,
|
||||
memos: List[bytes32],
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[Program, List[CoinSpend], _T_VerifiedCredential]:
|
||||
"""
|
||||
Launch a VC.
|
||||
@ -408,6 +410,7 @@ class VerifiedCredential(Streamable):
|
||||
[52, fee],
|
||||
[61, std_hash(launcher_coin.name() + launcher_solution.get_tree_hash())],
|
||||
[61, std_hash(second_launcher_coin.name() + launch_dpuz.get_tree_hash())],
|
||||
*[cond.to_program() for cond in extra_conditions],
|
||||
]
|
||||
)
|
||||
|
||||
|
@ -20,7 +20,7 @@ from chia.types.coin_spend import CoinSpend
|
||||
from chia.types.spend_bundle import SpendBundle
|
||||
from chia.util.hash import std_hash
|
||||
from chia.util.ints import uint32, uint64, uint128
|
||||
from chia.wallet.conditions import UnknownCondition
|
||||
from chia.wallet.conditions import Condition, UnknownCondition
|
||||
from chia.wallet.did_wallet.did_wallet import DIDWallet
|
||||
from chia.wallet.payment import Payment
|
||||
from chia.wallet.puzzle_drivers import Solver
|
||||
@ -155,6 +155,7 @@ class VCWallet:
|
||||
tx_config: TXConfig,
|
||||
inner_puzzle_hash: Optional[bytes32] = None,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> Tuple[VCRecord, List[TransactionRecord]]:
|
||||
"""
|
||||
Given the DID ID of a proof provider, mint a brand new VC with an empty slot for proofs.
|
||||
@ -184,6 +185,7 @@ class VCWallet:
|
||||
inner_puzzle_hash,
|
||||
[inner_puzzle_hash],
|
||||
fee=fee,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
solution = solution_for_conditions(dpuz.rest())
|
||||
original_puzzle = await self.standard_wallet.puzzle_for_puzzle_hash(original_coin.puzzle_hash)
|
||||
@ -224,6 +226,7 @@ class VCWallet:
|
||||
puzzle_announcements: Optional[Set[bytes]] = None,
|
||||
coin_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
**kwargs: Unpack[GSTOptionalArgs],
|
||||
) -> List[TransactionRecord]:
|
||||
new_proof_hash: Optional[bytes32] = kwargs.get(
|
||||
@ -296,13 +299,14 @@ class VCWallet:
|
||||
magic_condition = vc_record.vc.magic_condition_for_self_revoke()
|
||||
else:
|
||||
magic_condition = vc_record.vc.standard_magic_condition()
|
||||
extra_conditions = (*extra_conditions, UnknownCondition.from_program(magic_condition))
|
||||
innersol: Program = self.standard_wallet.make_solution(
|
||||
primaries=primaries,
|
||||
coin_announcements=coin_announcements,
|
||||
puzzle_announcements=puzzle_announcements,
|
||||
coin_announcements_to_assert=coin_announcements_bytes,
|
||||
puzzle_announcements_to_assert=puzzle_announcements_bytes,
|
||||
conditions=[UnknownCondition.from_program(magic_condition)],
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
did_announcement, coin_spend, vc = vc_record.vc.do_spend(inner_puzzle, innersol, new_proof_hash)
|
||||
spend_bundles = [await self.wallet_state_manager.sign_transaction([coin_spend])]
|
||||
@ -358,6 +362,7 @@ class VCWallet:
|
||||
peer: WSChiaConnection,
|
||||
tx_config: TXConfig,
|
||||
fee: uint64 = uint64(0),
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[TransactionRecord]:
|
||||
vc_coin_states: List[CoinState] = await self.wallet_state_manager.wallet_node.get_coin_state(
|
||||
[parent_id], peer=peer
|
||||
@ -405,6 +410,7 @@ class VCWallet:
|
||||
tx_config,
|
||||
puzzle_announcements={expected_did_announcement},
|
||||
coin_announcements_to_assert={vc_announcement},
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
final_bundle: SpendBundle = SpendBundle.aggregate([SpendBundle([vc_spend], G2Element()), did_spend])
|
||||
tx: TransactionRecord = TransactionRecord(
|
||||
|
@ -203,7 +203,7 @@ class Wallet:
|
||||
coin_announcements_to_assert: Optional[Set[bytes32]] = None,
|
||||
puzzle_announcements: Optional[Set[bytes]] = None,
|
||||
puzzle_announcements_to_assert: Optional[Set[bytes32]] = None,
|
||||
conditions: List[Condition] = [],
|
||||
conditions: Tuple[Condition, ...] = tuple(),
|
||||
fee: uint64 = uint64(0),
|
||||
) -> Program:
|
||||
assert fee >= 0
|
||||
@ -277,6 +277,7 @@ class Wallet:
|
||||
memos: Optional[List[bytes]] = None,
|
||||
negative_change_allowed: bool = False,
|
||||
puzzle_decorator_override: Optional[List[Dict[str, Any]]] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[CoinSpend]:
|
||||
"""
|
||||
Generates a unsigned transaction in form of List(Puzzle, Solutions)
|
||||
@ -371,6 +372,7 @@ class Wallet:
|
||||
coin_announcements={message},
|
||||
coin_announcements_to_assert=coin_announcements_bytes,
|
||||
puzzle_announcements_to_assert=puzzle_announcements_bytes,
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
solution = decorator_manager.solve(inner_puzzle, target_primary, solution)
|
||||
primary_announcement_hash = Announcement(coin.name(), message).name()
|
||||
@ -427,6 +429,7 @@ class Wallet:
|
||||
puzzle_announcements_to_consume: Optional[Set[Announcement]] = None,
|
||||
memos: Optional[List[bytes]] = None,
|
||||
puzzle_decorator_override: Optional[List[Dict[str, Any]]] = None,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
**kwargs: Unpack[GSTOptionalArgs],
|
||||
) -> TransactionRecord:
|
||||
origin_id: Optional[bytes32] = kwargs.get("origin_id", None)
|
||||
@ -456,6 +459,7 @@ class Wallet:
|
||||
memos,
|
||||
negative_change_allowed,
|
||||
puzzle_decorator_override=puzzle_decorator_override,
|
||||
extra_conditions=extra_conditions,
|
||||
)
|
||||
assert len(transaction) > 0
|
||||
self.log.info("About to sign a transaction: %s", transaction)
|
||||
|
@ -18,6 +18,7 @@ from typing import (
|
||||
List,
|
||||
Optional,
|
||||
Set,
|
||||
Tuple,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
@ -63,6 +64,7 @@ from chia.wallet.cat_wallet.cat_constants import DEFAULT_CATS
|
||||
from chia.wallet.cat_wallet.cat_info import CATInfo, CRCATInfo
|
||||
from chia.wallet.cat_wallet.cat_utils import CAT_MOD, CAT_MOD_HASH, construct_cat_puzzle, match_cat_puzzle
|
||||
from chia.wallet.cat_wallet.cat_wallet import CATWallet
|
||||
from chia.wallet.conditions import Condition
|
||||
from chia.wallet.db_wallet.db_wallet_puzzles import MIRROR_PUZZLE_HASH
|
||||
from chia.wallet.derivation_record import DerivationRecord
|
||||
from chia.wallet.derive_keys import (
|
||||
@ -809,7 +811,12 @@ class WalletStateManager:
|
||||
await self.spend_clawback_coins(clawback_coins, tx_fee, tx_config)
|
||||
|
||||
async def spend_clawback_coins(
|
||||
self, clawback_coins: Dict[Coin, ClawbackMetadata], fee: uint64, tx_config: TXConfig, force: bool = False
|
||||
self,
|
||||
clawback_coins: Dict[Coin, ClawbackMetadata],
|
||||
fee: uint64,
|
||||
tx_config: TXConfig,
|
||||
force: bool = False,
|
||||
extra_conditions: Tuple[Condition, ...] = tuple(),
|
||||
) -> List[bytes32]:
|
||||
assert len(clawback_coins) > 0
|
||||
coin_spends: List[CoinSpend] = []
|
||||
@ -850,6 +857,7 @@ class WalletStateManager:
|
||||
)
|
||||
],
|
||||
coin_announcements=None if len(coin_spends) > 0 or fee == 0 else {message},
|
||||
conditions=extra_conditions,
|
||||
)
|
||||
coin_spend: CoinSpend = generate_clawback_spend_bundle(coin, metadata, inner_puzzle, inner_solution)
|
||||
coin_spends.append(coin_spend)
|
||||
|
55
tests/cmds/test_timelock_args.py
Normal file
55
tests/cmds/test_timelock_args.py
Normal file
@ -0,0 +1,55 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional
|
||||
|
||||
import click
|
||||
from click.testing import CliRunner
|
||||
|
||||
from chia.cmds.cmds_util import timelock_args
|
||||
|
||||
|
||||
def test_timelock_args() -> None:
|
||||
@click.command()
|
||||
@timelock_args
|
||||
def test_cmd(
|
||||
valid_at: Optional[int],
|
||||
expires_at: Optional[int],
|
||||
) -> None:
|
||||
print(valid_at)
|
||||
print(expires_at)
|
||||
|
||||
runner = CliRunner()
|
||||
|
||||
result = runner.invoke(
|
||||
test_cmd,
|
||||
[
|
||||
"--valid-at",
|
||||
"0",
|
||||
"--expires-at",
|
||||
"0",
|
||||
],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
|
||||
assert "0\n0\n" == result.output
|
||||
|
||||
result = runner.invoke(
|
||||
test_cmd,
|
||||
[
|
||||
"--valid-at",
|
||||
"4294967295",
|
||||
"--expires-at",
|
||||
"4294967295",
|
||||
],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
|
||||
assert "4294967295\n4294967295\n" == result.output
|
||||
|
||||
result = runner.invoke(
|
||||
test_cmd,
|
||||
[],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
|
||||
assert "None\nNone\n" == result.output
|
Loading…
Reference in New Issue
Block a user