Make tests pass for takers

This commit is contained in:
Matt Hauff 2022-06-14 14:05:27 -07:00
parent 2a1322adbc
commit 7ee3f8845b
No known key found for this signature in database
GPG Key ID: 3CBA6CFC81A00E46
4 changed files with 77 additions and 43 deletions

View File

@ -863,11 +863,11 @@ class NFTWallet:
if len(offer_dict) != 2 or (amounts[0] > 0 == amounts[1] > 0):
raise ValueError("Royalty enabled NFTs only support offering/requesting one NFT for one currency")
offered_asset_id = list(offer_dict.items())[0][0]
if offered_asset_id is None:
first_asset_id = list(offer_dict.items())[0][0]
if first_asset_id is None:
nft: bool = False
else:
nft = driver_dict[offered_asset_id].check_type(
nft = driver_dict[first_asset_id].check_type(
[
AssetType.SINGLETON.value,
AssetType.METADATA.value,
@ -876,8 +876,14 @@ class NFTWallet:
)
offered: bool = list(offer_dict.items())[0][1] < 0
if offered:
offered_asset_id: Optional[bytes32] = first_asset_id
requested_asset_id: Optional[bytes32] = list(offer_dict.items())[1][0]
else:
offered_asset_id = list(offer_dict.items())[1][0]
requested_asset_id = first_asset_id
if nft and offered:
if nft == offered:
assert offered_asset_id is not None # hello mypy
wallet = await wallet_state_manager.get_wallet_for_asset_id(offered_asset_id.hex())
p2_ph = await wallet_state_manager.main_wallet.get_new_puzzlehash()
@ -905,12 +911,8 @@ class NFTWallet:
transaction_bundles: List[SpendBundle] = [tx.spend_bundle for tx in txs if tx.spend_bundle is not None]
total_spend_bundle = SpendBundle.aggregate(transaction_bundles)
# Clear the owner field in the driver dict
driver_dict[offered_asset_id].info["also"]["also"]["owner"] = "()"
return Offer(notarized_payments, total_spend_bundle, driver_dict)
else:
requested_asset_id: Optional[bytes32] = list(offer_dict.items())[0][0]
assert isinstance(requested_asset_id, bytes32)
requested_info = driver_dict[requested_asset_id]
transfer_info = requested_info.also().also() # type: ignore
@ -921,7 +923,6 @@ class NFTWallet:
requested_payments: Dict[Optional[bytes32], List[Payment]] = {
requested_asset_id: [Payment(p2_ph, uint64(offer_dict[requested_asset_id]), [p2_ph])]
}
offered_asset_id = list(offer_dict.items())[1][0]
offered_amount = uint64(abs(offer_dict[offered_asset_id]))
royalty_amount = uint64(offered_amount * royalty_percentage / 10000)
if offered_amount == royalty_amount:
@ -941,6 +942,17 @@ class NFTWallet:
notarized_payments = Offer.notarize_payments(requested_payments, pmt_coins)
announcements_to_assert = Offer.calculate_announcements(notarized_payments, driver_dict)
# Calculate the royalty announcement separately
announcements_to_assert.extend(
Offer.calculate_announcements(
{
offered_asset_id: [
NotarizedPayment(royalty_address, royalty_amount, [royalty_address], requested_asset_id)
]
},
driver_dict,
)
)
if wallet.type() == WalletType.STANDARD_WALLET:
tx = await wallet.generate_signed_transaction(
@ -973,7 +985,7 @@ class NFTWallet:
assert royalty_coin
# make the royalty payment solution
# ((nft_launcher_id . ((ROYALTY_ADDRESS, royalty_amount, (ROYALTY_ADDRESS)))))
royalty_sol = Program.to([[offered_asset_id, [royalty_address, royalty_amount, [royalty_address]]]])
royalty_sol = Program.to([[requested_asset_id, [royalty_address, royalty_amount, [royalty_address]]]])
royalty_spend = SpendBundle([CoinSpend(royalty_coin, OFFER_MOD, royalty_sol)], G2Element())
total_spend_bundle = SpendBundle.aggregate([txn_spend_bundle, royalty_spend])

View File

@ -540,13 +540,16 @@ class TradeManager:
removal_dict.setdefault(wallet_id, [])
removal_dict[wallet_id].append(removal)
all_removals: List[bytes32] = [r.name() for removals in removal_dict.values() for r in removals]
for wid, grouped_removals in removal_dict.items():
wallet = self.wallet_state_manager.wallets[wid]
to_puzzle_hash = bytes32([1] * 32) # We use all zeros to be clear not to send here
removal_tree_hash = Program.to([coin_as_list(rem) for rem in grouped_removals]).get_tree_hash()
# We also need to calculate the sent amount
removed: int = sum(c.amount for c in grouped_removals)
change_coins: List[Coin] = addition_dict[wid] if wid in addition_dict else []
potential_change_coins: List[Coin] = addition_dict[wid] if wid in addition_dict else []
change_coins: List[Coin] = [c for c in potential_change_coins if c.parent_coin_info in all_removals]
change_amount: int = sum(c.amount for c in change_coins)
sent_amount: int = removed - change_amount
txs.append(
@ -573,38 +576,34 @@ class TradeManager:
return txs
async def respond_to_offer(self, offer: Offer, fee=uint64(0)) -> Tuple[bool, Optional[TradeRecord], Optional[str]]:
potential_special_offer: Optional[Offer] = await self.check_for_special_offer_taking(offer, fee=fee)
if potential_special_offer is not None:
complete_offer: Offer = potential_special_offer
else:
take_offer_dict: Dict[Union[bytes32, int], int] = {}
arbitrage: Dict[Optional[bytes32], int] = offer.arbitrage()
for asset_id, amount in arbitrage.items():
if asset_id is None:
wallet = self.wallet_state_manager.main_wallet
key: Union[bytes32, int] = int(wallet.id())
take_offer_dict: Dict[Union[bytes32, int], int] = {}
arbitrage: Dict[Optional[bytes32], int] = offer.arbitrage()
for asset_id, amount in arbitrage.items():
if asset_id is None:
wallet = self.wallet_state_manager.main_wallet
key: Union[bytes32, int] = int(wallet.id())
else:
# ATTENTION: new wallets
wallet = await self.wallet_state_manager.get_wallet_for_asset_id(asset_id.hex())
if wallet is None and amount < 0:
return False, None, f"Do not have a wallet for asset ID: {asset_id} to fulfill offer"
elif wallet is None or wallet.type() == WalletType.NFT:
key = asset_id
else:
# ATTENTION: new wallets
wallet = await self.wallet_state_manager.get_wallet_for_asset_id(asset_id.hex())
if wallet is None and amount < 0:
return False, None, f"Do not have a wallet for asset ID: {asset_id} to fulfill offer"
elif wallet is None or wallet.type() == WalletType.NFT:
key = asset_id
else:
key = int(wallet.id())
take_offer_dict[key] = amount
key = int(wallet.id())
take_offer_dict[key] = amount
# First we validate that all of the coins in this offer exist
valid: bool = await self.check_offer_validity(offer)
if not valid:
return False, None, "This offer is no longer valid"
# First we validate that all of the coins in this offer exist
valid: bool = await self.check_offer_validity(offer)
if not valid:
return False, None, "This offer is no longer valid"
success, take_offer, error = await self._create_offer_for_ids(take_offer_dict, offer.driver_dict, fee=fee)
if not success or take_offer is None:
return False, None, error
success, take_offer, error = await self._create_offer_for_ids(take_offer_dict, offer.driver_dict, fee=fee)
if not success or take_offer is None:
return False, None, error
complete_offer = Offer.aggregate([offer, take_offer])
assert complete_offer.is_valid()
complete_offer = Offer.aggregate([offer, take_offer])
assert complete_offer.is_valid()
final_spend_bundle: SpendBundle = complete_offer.to_valid_spend()

View File

@ -146,7 +146,7 @@ class Offer:
parent_puzzle: Program = parent_spend.puzzle_reveal.to_program()
parent_solution: Program = parent_spend.solution.to_program()
additions: List[Coin] = parent_spend.additions()
additions: List[Coin] = [a for a in parent_spend.additions() if a not in self.bundle.removals()]
puzzle_driver = match_puzzle(parent_puzzle)
if puzzle_driver is not None:
@ -167,7 +167,7 @@ class Offer:
a
for a in additions_w_amount
if a.puzzle_hash
== construct_puzzle(puzzle_driver, OFFER_HASH).get_tree_hash(OFFER_HASH)
== construct_puzzle(puzzle_driver, OFFER_HASH).get_tree_hash(OFFER_HASH) # type: ignore
]
if len(additions_w_amount_and_puzhash) == 1:
coins_for_this_spend.append(additions_w_amount_and_puzhash[0])

View File

@ -23,6 +23,7 @@ from chia.wallet.did_wallet.did_wallet import DIDWallet
from chia.wallet.nft_wallet.nft_wallet import NFTWallet
from chia.wallet.outer_puzzles import create_asset_id, match_puzzle
from chia.wallet.puzzle_drivers import PuzzleInfo
from chia.wallet.trading.offer import Offer
from chia.wallet.util.compute_memos import compute_memos
# from chia.wallet.util.wallet_types import WalletType
@ -145,7 +146,7 @@ async def test_nft_offer_sell_nft(two_wallet_nodes: Any, trusted: Any) -> None:
# maker create offer: NFT for xch
trade_manager_maker = wallet_maker.wallet_state_manager.trade_manager
# trade_manager_taker = wallet_taker.wallet_state_manager.trade_manager
trade_manager_taker = wallet_taker.wallet_state_manager.trade_manager
coins_maker = nft_wallet_maker.nft_wallet_info.my_nft_coins
assert len(coins_maker) == 1
@ -170,6 +171,17 @@ async def test_nft_offer_sell_nft(two_wallet_nodes: Any, trusted: Any) -> None:
assert error is None
assert trade_make is not None
success, trade_take, error = await trade_manager_taker.respond_to_offer(
Offer.from_bytes(trade_make.offer), fee=uint64(1)
)
await asyncio.sleep(1)
assert error is None
assert success is True
assert trade_take is not None
for _ in range(1, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_maker))
@pytest.mark.parametrize(
"trusted",
@ -275,7 +287,7 @@ async def test_nft_offer_request_nft(two_wallet_nodes: Any, trusted: Any) -> Non
# maker create offer: NFT for xch
trade_manager_maker = wallet_maker.wallet_state_manager.trade_manager
# trade_manager_taker = wallet_taker.wallet_state_manager.trade_manager
trade_manager_taker = wallet_taker.wallet_state_manager.trade_manager
coins_maker = nft_wallet_maker.nft_wallet_info.my_nft_coins
assert len(coins_maker) == 0
@ -299,3 +311,14 @@ async def test_nft_offer_request_nft(two_wallet_nodes: Any, trusted: Any) -> Non
assert success is True
assert error is None
assert trade_make is not None
success, trade_take, error = await trade_manager_taker.respond_to_offer(
Offer.from_bytes(trade_make.offer), fee=uint64(1)
)
await asyncio.sleep(1)
assert error is None
assert success is True
assert trade_take is not None
for _ in range(1, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_maker))