mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-09-20 16:08:51 +03:00
Quex.offer mod tests (#14478)
* add test * do some forwards compat stuff * Add a forwards compat example * fix test * Add more forwards compat tests * Add more forwads compat tests * Add forwards compatibility for nft1s * add forward compatibility for nft offers * Add forwards compatibility tests for DL offers * Update DL test offers * lint * isort * offer mod bytes * Fix compression test * isort again * Add special offers for <=3.7 (CATs) * Add special offers for <=3.7 (NFT1s) * Add special offers for <=3.7 (NFT0s) * Add special offers for <=3.7 (DLs) * Check for conflicting items during aggregation * isort * Return created old offers properly marked
This commit is contained in:
parent
ba74a983eb
commit
9cc25cc820
@ -1144,6 +1144,7 @@ class DataLayerWallet:
|
||||
driver_dict: Dict[bytes32, PuzzleInfo],
|
||||
solver: Solver,
|
||||
fee: uint64 = uint64(0),
|
||||
old: bool = False,
|
||||
) -> Offer:
|
||||
dl_wallet = None
|
||||
for wallet in wallet_state_manager.wallets.values():
|
||||
@ -1206,7 +1207,7 @@ class DataLayerWallet:
|
||||
for k, v in offer_dict.items()
|
||||
if v > 0
|
||||
}
|
||||
return Offer(requested_payments, SpendBundle.aggregate(all_bundles), driver_dict)
|
||||
return Offer(requested_payments, SpendBundle.aggregate(all_bundles), driver_dict, old)
|
||||
|
||||
@staticmethod
|
||||
async def finish_graftroot_solutions(offer: Offer, solver: Solver) -> Offer:
|
||||
@ -1280,7 +1281,7 @@ class DataLayerWallet:
|
||||
spend = new_spend
|
||||
new_spends.append(spend)
|
||||
|
||||
return Offer({}, SpendBundle(new_spends, offer.bundle.aggregated_signature), offer.driver_dict)
|
||||
return Offer({}, SpendBundle(new_spends, offer.bundle.aggregated_signature), offer.driver_dict, offer.old)
|
||||
|
||||
@staticmethod
|
||||
async def get_offer_summary(offer: Offer) -> Dict[str, Any]:
|
||||
|
@ -37,7 +37,14 @@ from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import (
|
||||
calculate_synthetic_secret_key,
|
||||
puzzle_for_pk,
|
||||
)
|
||||
from chia.wallet.trading.offer import OFFER_MOD, OFFER_MOD_HASH, NotarizedPayment, Offer
|
||||
from chia.wallet.trading.offer import (
|
||||
OFFER_MOD,
|
||||
OFFER_MOD_HASH,
|
||||
OFFER_MOD_OLD,
|
||||
OFFER_MOD_OLD_HASH,
|
||||
NotarizedPayment,
|
||||
Offer,
|
||||
)
|
||||
from chia.wallet.transaction_record import TransactionRecord
|
||||
from chia.wallet.uncurried_puzzle import uncurry_puzzle
|
||||
from chia.wallet.util.compute_memos import compute_memos
|
||||
@ -782,7 +789,10 @@ class NFTWallet:
|
||||
fee: uint64,
|
||||
min_coin_amount: Optional[uint64] = None,
|
||||
max_coin_amount: Optional[uint64] = None,
|
||||
old: bool = False,
|
||||
) -> Offer:
|
||||
DESIRED_OFFER_MOD = OFFER_MOD_OLD if old else OFFER_MOD
|
||||
DESIRED_OFFER_MOD_HASH = OFFER_MOD_OLD_HASH if old else OFFER_MOD_HASH
|
||||
# First, let's take note of all the royalty enabled NFTs
|
||||
royalty_nft_asset_dict: Dict[bytes32, int] = {}
|
||||
for asset, amount in offer_dict.items():
|
||||
@ -815,7 +825,9 @@ class NFTWallet:
|
||||
for asset, amount in fungible_asset_dict.items(): # requested fungible items
|
||||
if amount > 0 and offer_side_royalty_split > 0:
|
||||
settlement_ph: bytes32 = (
|
||||
OFFER_MOD_HASH if asset is None else construct_puzzle(driver_dict[asset], OFFER_MOD).get_tree_hash()
|
||||
DESIRED_OFFER_MOD_HASH
|
||||
if asset is None
|
||||
else construct_puzzle(driver_dict[asset], DESIRED_OFFER_MOD).get_tree_hash()
|
||||
)
|
||||
trade_prices.append([uint64(math.floor(amount / offer_side_royalty_split)), settlement_ph])
|
||||
|
||||
@ -881,13 +893,13 @@ class NFTWallet:
|
||||
notarized_payments: Dict[Optional[bytes32], List[NotarizedPayment]] = Offer.notarize_payments(
|
||||
requested_payments, list(all_offered_coins)
|
||||
)
|
||||
announcements_to_assert = Offer.calculate_announcements(notarized_payments, driver_dict)
|
||||
announcements_to_assert = Offer.calculate_announcements(notarized_payments, driver_dict, old)
|
||||
for asset, payments in royalty_payments.items():
|
||||
if asset is None: # xch offer
|
||||
offer_puzzle = OFFER_MOD
|
||||
royalty_ph = OFFER_MOD_HASH
|
||||
offer_puzzle = DESIRED_OFFER_MOD
|
||||
royalty_ph = DESIRED_OFFER_MOD_HASH
|
||||
else:
|
||||
offer_puzzle = construct_puzzle(driver_dict[asset], OFFER_MOD)
|
||||
offer_puzzle = construct_puzzle(driver_dict[asset], DESIRED_OFFER_MOD)
|
||||
royalty_ph = offer_puzzle.get_tree_hash()
|
||||
announcements_to_assert.extend(
|
||||
[
|
||||
@ -913,12 +925,12 @@ class NFTWallet:
|
||||
payments = royalty_payments[asset] if asset in royalty_payments else []
|
||||
tx = await wallet.generate_signed_transaction(
|
||||
abs(amount),
|
||||
Offer.ph(),
|
||||
DESIRED_OFFER_MOD_HASH,
|
||||
primaries=[
|
||||
AmountWithPuzzlehash(
|
||||
{
|
||||
"amount": uint64(sum(p.amount for _, p in payments)),
|
||||
"puzzlehash": Offer.ph(),
|
||||
"puzzlehash": DESIRED_OFFER_MOD_HASH,
|
||||
"memos": [],
|
||||
}
|
||||
)
|
||||
@ -931,7 +943,7 @@ class NFTWallet:
|
||||
elif asset not in fungible_asset_dict:
|
||||
txs = await wallet.generate_signed_transaction(
|
||||
[abs(amount)],
|
||||
[Offer.ph()],
|
||||
[DESIRED_OFFER_MOD_HASH],
|
||||
fee=fee_left_to_pay,
|
||||
coins=offered_coins_by_asset[asset],
|
||||
puzzle_announcements_to_consume=announcements_to_assert,
|
||||
@ -941,7 +953,7 @@ class NFTWallet:
|
||||
payments = royalty_payments[asset] if asset in royalty_payments else []
|
||||
txs = await wallet.generate_signed_transaction(
|
||||
[abs(amount), sum(p.amount for _, p in payments)],
|
||||
[Offer.ph(), Offer.ph()],
|
||||
[DESIRED_OFFER_MOD_HASH, DESIRED_OFFER_MOD_HASH],
|
||||
fee=fee_left_to_pay,
|
||||
coins=offered_coins_by_asset[asset],
|
||||
puzzle_announcements_to_consume=announcements_to_assert,
|
||||
@ -980,17 +992,19 @@ class NFTWallet:
|
||||
None,
|
||||
[
|
||||
Payment(
|
||||
Offer.ph(), uint64(sum(p.amount for _, p in duplicate_payments)), []
|
||||
DESIRED_OFFER_MOD_HASH,
|
||||
uint64(sum(p.amount for _, p in duplicate_payments)),
|
||||
[],
|
||||
).as_condition_args()
|
||||
],
|
||||
)
|
||||
).cons(inner_royalty_sol)
|
||||
|
||||
if asset is None: # xch offer
|
||||
offer_puzzle = OFFER_MOD
|
||||
royalty_ph = OFFER_MOD_HASH
|
||||
offer_puzzle = DESIRED_OFFER_MOD
|
||||
royalty_ph = DESIRED_OFFER_MOD_HASH
|
||||
else:
|
||||
offer_puzzle = construct_puzzle(driver_dict[asset], OFFER_MOD)
|
||||
offer_puzzle = construct_puzzle(driver_dict[asset], DESIRED_OFFER_MOD)
|
||||
royalty_ph = offer_puzzle.get_tree_hash()
|
||||
if royalty_coin is None:
|
||||
for tx in txs:
|
||||
@ -1031,7 +1045,7 @@ class NFTWallet:
|
||||
"sibling_solutions": "()",
|
||||
}
|
||||
)
|
||||
royalty_sol = solve_puzzle(driver_dict[asset], solver, OFFER_MOD, inner_royalty_sol)
|
||||
royalty_sol = solve_puzzle(driver_dict[asset], solver, DESIRED_OFFER_MOD, inner_royalty_sol)
|
||||
|
||||
new_coin_spend = CoinSpend(royalty_coin, offer_puzzle, royalty_sol)
|
||||
additional_bundles.append(SpendBundle([new_coin_spend], G2Element()))
|
||||
@ -1047,7 +1061,7 @@ class NFTWallet:
|
||||
# Finally, assemble the tx records properly
|
||||
txs_bundle = SpendBundle.aggregate([tx.spend_bundle for tx in all_transactions if tx.spend_bundle is not None])
|
||||
aggregate_bundle = SpendBundle.aggregate([txs_bundle, *additional_bundles])
|
||||
offer = Offer(notarized_payments, aggregate_bundle, driver_dict)
|
||||
offer = Offer(notarized_payments, aggregate_bundle, driver_dict, old)
|
||||
return offer
|
||||
|
||||
async def set_bulk_nft_did(
|
||||
|
@ -25,7 +25,7 @@ from chia.wallet.payment import Payment
|
||||
from chia.wallet.puzzle_drivers import PuzzleInfo, Solver
|
||||
from chia.wallet.puzzles.load_clvm import load_clvm_maybe_recompile
|
||||
from chia.wallet.trade_record import TradeRecord
|
||||
from chia.wallet.trading.offer import NotarizedPayment, Offer
|
||||
from chia.wallet.trading.offer import OFFER_MOD_OLD_HASH, NotarizedPayment, Offer
|
||||
from chia.wallet.trading.trade_status import TradeStatus
|
||||
from chia.wallet.trading.trade_store import TradeStore
|
||||
from chia.wallet.transaction_record import TransactionRecord
|
||||
@ -436,6 +436,7 @@ class TradeManager:
|
||||
fee: uint64 = uint64(0),
|
||||
min_coin_amount: Optional[uint64] = None,
|
||||
max_coin_amount: Optional[uint64] = None,
|
||||
old: bool = False,
|
||||
) -> Union[Tuple[Literal[True], Offer, None], Tuple[Literal[False], None, str]]:
|
||||
"""
|
||||
Offer is dictionary of wallet ids and amount
|
||||
@ -516,7 +517,7 @@ class TradeManager:
|
||||
raise ValueError(f"Wallet for asset id {asset_id} is not properly integrated with TradeManager")
|
||||
|
||||
potential_special_offer: Optional[Offer] = await self.check_for_special_offer_making(
|
||||
offer_dict_no_ints, driver_dict, solver, fee, min_coin_amount, max_coin_amount
|
||||
offer_dict_no_ints, driver_dict, solver, fee, min_coin_amount, max_coin_amount, old
|
||||
)
|
||||
|
||||
if potential_special_offer is not None:
|
||||
@ -526,7 +527,7 @@ class TradeManager:
|
||||
notarized_payments: Dict[Optional[bytes32], List[NotarizedPayment]] = Offer.notarize_payments(
|
||||
requested_payments, all_coins
|
||||
)
|
||||
announcements_to_assert = Offer.calculate_announcements(notarized_payments, driver_dict)
|
||||
announcements_to_assert = Offer.calculate_announcements(notarized_payments, driver_dict, old)
|
||||
|
||||
all_transactions: List[TransactionRecord] = []
|
||||
fee_left_to_pay: uint64 = fee
|
||||
@ -539,7 +540,7 @@ class TradeManager:
|
||||
if wallet.type() == WalletType.STANDARD_WALLET:
|
||||
tx = await wallet.generate_signed_transaction(
|
||||
abs(offer_dict[id]),
|
||||
Offer.ph(),
|
||||
OFFER_MOD_OLD_HASH if old else Offer.ph(),
|
||||
fee=fee_left_to_pay,
|
||||
coins=set(selected_coins),
|
||||
puzzle_announcements_to_consume=announcements_to_assert,
|
||||
@ -552,7 +553,7 @@ class TradeManager:
|
||||
txs = await wallet.generate_signed_transaction(
|
||||
# [abs(offer_dict[id])],
|
||||
amounts,
|
||||
[Offer.ph()],
|
||||
[OFFER_MOD_OLD_HASH if old else Offer.ph()],
|
||||
fee=fee_left_to_pay,
|
||||
coins=set(selected_coins),
|
||||
puzzle_announcements_to_consume=announcements_to_assert,
|
||||
@ -562,7 +563,7 @@ class TradeManager:
|
||||
# ATTENTION: new_wallets
|
||||
txs = await wallet.generate_signed_transaction(
|
||||
[abs(offer_dict[id])],
|
||||
[Offer.ph()],
|
||||
[OFFER_MOD_OLD_HASH if old else Offer.ph()],
|
||||
fee=fee_left_to_pay,
|
||||
coins=set(selected_coins),
|
||||
puzzle_announcements_to_consume=announcements_to_assert,
|
||||
@ -575,7 +576,7 @@ class TradeManager:
|
||||
[x.spend_bundle for x in all_transactions if x.spend_bundle is not None]
|
||||
)
|
||||
|
||||
offer = Offer(notarized_payments, total_spend_bundle, driver_dict)
|
||||
offer = Offer(notarized_payments, total_spend_bundle, driver_dict, old)
|
||||
return True, offer, None
|
||||
|
||||
except Exception as e:
|
||||
@ -735,6 +736,7 @@ class TradeManager:
|
||||
fee=fee,
|
||||
min_coin_amount=min_coin_amount,
|
||||
max_coin_amount=max_coin_amount,
|
||||
old=offer.old,
|
||||
)
|
||||
if not result[0] or result[1] is None:
|
||||
raise ValueError(result[2])
|
||||
@ -798,6 +800,7 @@ class TradeManager:
|
||||
fee: uint64 = uint64(0),
|
||||
min_coin_amount: Optional[uint64] = None,
|
||||
max_coin_amount: Optional[uint64] = None,
|
||||
old: bool = False,
|
||||
) -> Optional[Offer]:
|
||||
for puzzle_info in driver_dict.values():
|
||||
if (
|
||||
@ -807,7 +810,7 @@ class TradeManager:
|
||||
== AssetType.ROYALTY_TRANSFER_PROGRAM.value
|
||||
):
|
||||
return await NFTWallet.make_nft1_offer(
|
||||
self.wallet_state_manager, offer_dict, driver_dict, fee, min_coin_amount, max_coin_amount
|
||||
self.wallet_state_manager, offer_dict, driver_dict, fee, min_coin_amount, max_coin_amount, old
|
||||
)
|
||||
elif (
|
||||
puzzle_info.check_type(
|
||||
@ -819,7 +822,7 @@ class TradeManager:
|
||||
and puzzle_info.also()["updater_hash"] == ACS_MU_PH # type: ignore
|
||||
):
|
||||
return await DataLayerWallet.make_update_offer(
|
||||
self.wallet_state_manager, offer_dict, driver_dict, solver, fee
|
||||
self.wallet_state_manager, offer_dict, driver_dict, solver, fee, old
|
||||
)
|
||||
return None
|
||||
|
||||
|
@ -33,7 +33,7 @@ from chia.wallet.util.puzzle_compression import (
|
||||
)
|
||||
|
||||
OFFER_MOD_OLD = load_clvm_maybe_recompile("settlement_payments_old.clvm")
|
||||
OFFER_MOD = load_clvm_maybe_recompile("settlement_payments_old.clvm")
|
||||
OFFER_MOD = load_clvm_maybe_recompile("settlement_payments.clvm")
|
||||
OFFER_MOD_OLD_HASH = OFFER_MOD_OLD.get_tree_hash()
|
||||
OFFER_MOD_HASH = OFFER_MOD.get_tree_hash()
|
||||
ZERO_32 = bytes32([0] * 32)
|
||||
@ -71,6 +71,7 @@ class Offer:
|
||||
] # The key is the asset id of the asset being requested
|
||||
bundle: SpendBundle
|
||||
driver_dict: Dict[bytes32, PuzzleInfo] # asset_id -> asset driver
|
||||
old: bool = False
|
||||
|
||||
@staticmethod
|
||||
def ph() -> bytes32:
|
||||
@ -98,16 +99,20 @@ class Offer:
|
||||
# The announcements returned from this function must be asserted in whatever spend bundle is created by the wallet
|
||||
@staticmethod
|
||||
def calculate_announcements(
|
||||
notarized_payments: Dict[Optional[bytes32], List[NotarizedPayment]], driver_dict: Dict[bytes32, PuzzleInfo]
|
||||
notarized_payments: Dict[Optional[bytes32], List[NotarizedPayment]],
|
||||
driver_dict: Dict[bytes32, PuzzleInfo],
|
||||
old: bool = False,
|
||||
) -> List[Announcement]:
|
||||
announcements: List[Announcement] = []
|
||||
for asset_id, payments in notarized_payments.items():
|
||||
if asset_id is not None:
|
||||
if asset_id not in driver_dict:
|
||||
raise ValueError("Cannot calculate announcements without driver of requested item")
|
||||
settlement_ph: bytes32 = construct_puzzle(driver_dict[asset_id], OFFER_MOD).get_tree_hash()
|
||||
settlement_ph: bytes32 = construct_puzzle(
|
||||
driver_dict[asset_id], OFFER_MOD_OLD if old else OFFER_MOD
|
||||
).get_tree_hash()
|
||||
else:
|
||||
settlement_ph = OFFER_MOD_HASH
|
||||
settlement_ph = OFFER_MOD_OLD_HASH if old else OFFER_MOD_HASH
|
||||
|
||||
msg: bytes32 = Program.to((payments[0].nonce, [p.as_condition_args() for p in payments])).get_tree_hash()
|
||||
announcements.append(Announcement(settlement_ph, msg))
|
||||
@ -374,7 +379,8 @@ class Offer:
|
||||
total_requested_payments: Dict[Optional[bytes32], List[NotarizedPayment]] = {}
|
||||
total_bundle = SpendBundle([], G2Element())
|
||||
total_driver_dict: Dict[bytes32, PuzzleInfo] = {}
|
||||
for offer in offers:
|
||||
old: bool = False
|
||||
for i, offer in enumerate(offers):
|
||||
# First check for any overlap in inputs
|
||||
total_inputs: Set[Coin] = {cs.coin for cs in total_bundle.coin_spends}
|
||||
offer_inputs: Set[Coin] = {cs.coin for cs in offer.bundle.coin_spends}
|
||||
@ -394,8 +400,13 @@ class Offer:
|
||||
|
||||
total_bundle = SpendBundle.aggregate([total_bundle, offer.bundle])
|
||||
total_driver_dict.update(offer.driver_dict)
|
||||
if i == 0:
|
||||
old = offer.old
|
||||
else:
|
||||
if offer.old != old:
|
||||
raise ValueError("Attempting to aggregate two offers with different mods")
|
||||
|
||||
return cls(total_requested_payments, total_bundle, total_driver_dict)
|
||||
return cls(total_requested_payments, total_bundle, total_driver_dict, old)
|
||||
|
||||
# Validity is defined by having enough funds within the offer to satisfy both sides
|
||||
def is_valid(self) -> bool:
|
||||
@ -539,7 +550,11 @@ class Offer:
|
||||
requested_payments: Dict[Optional[bytes32], List[NotarizedPayment]] = {}
|
||||
driver_dict: Dict[bytes32, PuzzleInfo] = {}
|
||||
leftover_coin_spends: List[CoinSpend] = []
|
||||
old: bool = False
|
||||
for coin_spend in bundle.coin_spends:
|
||||
if not old and bytes(OFFER_MOD_OLD) in bytes(coin_spend):
|
||||
old = True
|
||||
|
||||
driver = match_puzzle(uncurry_puzzle(coin_spend.puzzle_reveal.to_program()))
|
||||
if driver is not None:
|
||||
asset_id = create_asset_id(driver)
|
||||
@ -560,7 +575,7 @@ class Offer:
|
||||
else:
|
||||
leftover_coin_spends.append(coin_spend)
|
||||
|
||||
return cls(requested_payments, SpendBundle(leftover_coin_spends, bundle.aggregated_signature), driver_dict)
|
||||
return cls(requested_payments, SpendBundle(leftover_coin_spends, bundle.aggregated_signature), driver_dict, old)
|
||||
|
||||
def name(self) -> bytes32:
|
||||
return self.to_spend_bundle().name()
|
||||
|
@ -13,7 +13,7 @@ from chia.util.ints import uint64
|
||||
from chia.wallet.cat_wallet.cat_utils import construct_cat_puzzle
|
||||
from chia.wallet.puzzles.cat_loader import CAT_MOD
|
||||
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import puzzle_for_pk
|
||||
from chia.wallet.trading.offer import OFFER_MOD
|
||||
from chia.wallet.trading.offer import OFFER_MOD, OFFER_MOD_OLD
|
||||
from chia.wallet.util.puzzle_compression import (
|
||||
LATEST_VERSION,
|
||||
compress_object_with_puzzles,
|
||||
@ -88,7 +88,8 @@ class TestPuzzleCompression:
|
||||
|
||||
def test_lowest_best_version(self):
|
||||
assert lowest_best_version([bytes(CAT_MOD)]) == 4
|
||||
assert lowest_best_version([bytes(OFFER_MOD)]) == 2
|
||||
assert lowest_best_version([bytes(OFFER_MOD_OLD)]) == 2
|
||||
assert lowest_best_version([bytes(OFFER_MOD)]) == 5
|
||||
|
||||
def test_version_override(self):
|
||||
coin_spend = CoinSpend(
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import replace
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import pytest
|
||||
@ -22,7 +23,7 @@ from chia.wallet.outer_puzzles import AssetType
|
||||
from chia.wallet.payment import Payment
|
||||
from chia.wallet.puzzle_drivers import PuzzleInfo
|
||||
from chia.wallet.puzzles.cat_loader import CAT_MOD
|
||||
from chia.wallet.trading.offer import NotarizedPayment, Offer
|
||||
from chia.wallet.trading.offer import OFFER_MOD, NotarizedPayment, Offer
|
||||
from tests.clvm.benchmark_costs import cost_of_spend_bundle
|
||||
|
||||
acs = Program.to(1)
|
||||
@ -299,6 +300,30 @@ class TestOfferLifecycle:
|
||||
}
|
||||
assert new_offer.is_valid()
|
||||
|
||||
# Test preventing TAIL from running during exchange
|
||||
blue_cat_puz: Program = construct_cat_puzzle(CAT_MOD, str_to_tail_hash("blue"), OFFER_MOD)
|
||||
blue_spend: CoinSpend = CoinSpend(
|
||||
Coin(bytes32(32), blue_cat_puz.get_tree_hash(), uint64(0)),
|
||||
blue_cat_puz,
|
||||
Program.to([[bytes32(32), [bytes32(32), 200, ["hey there"]]]]),
|
||||
)
|
||||
new_spends_list: List[CoinSpend] = [blue_spend, *new_offer.to_spend_bundle().coin_spends]
|
||||
tail_offer: Offer = Offer.from_spend_bundle(SpendBundle(new_spends_list, G2Element()))
|
||||
valid_spend = tail_offer.to_valid_spend(bytes32(32))
|
||||
real_blue_spend = [spend for spend in valid_spend.coin_spends if b"hey there" in bytes(spend)][0]
|
||||
real_blue_spend_replaced = replace(
|
||||
real_blue_spend,
|
||||
solution=real_blue_spend.solution.to_program().replace(
|
||||
ffrfrf=Program.to(-113), ffrfrr=Program.to([str_to_tail("blue"), []])
|
||||
),
|
||||
)
|
||||
valid_spend = SpendBundle(
|
||||
[real_blue_spend_replaced, *[spend for spend in valid_spend.coin_spends if spend != real_blue_spend]],
|
||||
G2Element(),
|
||||
)
|
||||
with pytest.raises(ValueError, match="clvm raise"):
|
||||
valid_spend.additions()
|
||||
|
||||
# Test (de)serialization
|
||||
assert Offer.from_bytes(bytes(new_offer)) == new_offer
|
||||
|
||||
@ -308,6 +333,7 @@ class TestOfferLifecycle:
|
||||
# Make sure we can actually spend the offer once it's valid
|
||||
arbitrage_ph: bytes32 = Program.to([3, [], [], 1]).get_tree_hash()
|
||||
offer_bundle: SpendBundle = new_offer.to_valid_spend(arbitrage_ph)
|
||||
|
||||
result = await sim_client.push_tx(offer_bundle)
|
||||
assert result == (MempoolInclusionStatus.SUCCESS, None)
|
||||
self.cost["complex offer"] = cost_of_spend_bundle(offer_bundle)
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user