mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-11-10 12:29:49 +03:00
nft royalty edge cases (#14789)
* nft royalty edge cases * making tests faster * Update tests/wallet/nft_wallet/test_nft_1_offers.py Co-authored-by: Matt Hauff <quexington@gmail.com> * flake --------- Co-authored-by: Matt Hauff <quexington@gmail.com>
This commit is contained in:
parent
766c33cd33
commit
a6f423522b
@ -347,6 +347,11 @@ class NFTWallet:
|
||||
# For a DID enabled NFT wallet it cannot mint NFT0. Mint NFT1 instead.
|
||||
did_id = self.did_id
|
||||
amount = uint64(1)
|
||||
# ensure percentage is uint16
|
||||
try:
|
||||
percentage = uint16(percentage)
|
||||
except ValueError:
|
||||
raise ValueError("Percentage must be lower than 655%")
|
||||
coins = await self.standard_wallet.select_coins(uint64(amount + fee))
|
||||
if coins is None:
|
||||
return None
|
||||
@ -663,7 +668,6 @@ class NFTWallet:
|
||||
payments.append(Payment(puzhash, amount, memos_with_hint))
|
||||
|
||||
payment_sum = sum([p.amount for p in payments])
|
||||
|
||||
unsigned_spend_bundle, chia_tx = await self.generate_unsigned_spendbundle(
|
||||
payments,
|
||||
fee,
|
||||
@ -869,16 +873,23 @@ class NFTWallet:
|
||||
for asset, amount in royalty_nft_asset_dict.items(): # royalty enabled NFTs
|
||||
transfer_info = driver_dict[asset].also().also() # type: ignore
|
||||
assert isinstance(transfer_info, PuzzleInfo)
|
||||
royalty_percentage_raw = transfer_info["transfer_program"]["royalty_percentage"]
|
||||
assert royalty_percentage_raw is not None
|
||||
# clvm encodes large ints as bytes
|
||||
if isinstance(royalty_percentage_raw, bytes):
|
||||
royalty_percentage = int_from_bytes(royalty_percentage_raw)
|
||||
else:
|
||||
royalty_percentage = int(royalty_percentage_raw)
|
||||
if amount > 0:
|
||||
required_royalty_info.append(
|
||||
(
|
||||
asset,
|
||||
bytes32(transfer_info["transfer_program"]["royalty_address"]),
|
||||
uint16(transfer_info["transfer_program"]["royalty_percentage"]),
|
||||
uint16(royalty_percentage),
|
||||
)
|
||||
)
|
||||
else:
|
||||
offered_royalty_percentages[asset] = uint16(transfer_info["transfer_program"]["royalty_percentage"])
|
||||
offered_royalty_percentages[asset] = uint16(royalty_percentage)
|
||||
|
||||
royalty_payments: Dict[Optional[bytes32], List[Tuple[bytes32, Payment]]] = {}
|
||||
for asset, amount in fungible_asset_dict.items(): # offered fungible items
|
||||
@ -950,6 +961,7 @@ class NFTWallet:
|
||||
additional_bundles: List[SpendBundle] = []
|
||||
# standard pays the fee if possible
|
||||
fee_left_to_pay: uint64 = uint64(0) if None in offer_dict and offer_dict[None] < 0 else fee
|
||||
|
||||
for asset, amount in offer_dict.items():
|
||||
if amount < 0:
|
||||
if asset is None:
|
||||
|
@ -3,7 +3,6 @@ from __future__ import annotations
|
||||
import dataclasses
|
||||
import logging
|
||||
import time
|
||||
import traceback
|
||||
from typing import Any, Dict, List, Optional, Set, Tuple, Union
|
||||
|
||||
from typing_extensions import Literal
|
||||
@ -597,8 +596,7 @@ class TradeManager:
|
||||
return True, offer, None
|
||||
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc()
|
||||
self.log.error(f"Error with creating trade offer: {type(e)}{tb}")
|
||||
self.log.exception("Error creating trade offer")
|
||||
return False, None, str(e)
|
||||
|
||||
async def maybe_create_wallets_for_offer(self, offer: Offer) -> None:
|
||||
|
@ -1272,7 +1272,14 @@ async def test_nft_offer_sell_cancel_in_batch(self_hostname: str, two_wallet_nod
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
"forwards_compat,royalty_pts",
|
||||
[(True, (200, 500, 500)), (False, (200, 500, 500)), (False, (0, 0, 0))],
|
||||
[
|
||||
(True, (200, 500, 500)),
|
||||
(False, (200, 500, 500)),
|
||||
(False, (0, 0, 0)), # test that we can have 0 royalty
|
||||
(False, (65000, 65534, 65535)), # test that we can reach max royalty
|
||||
(False, (10000, 10001, 10005)), # tests 100% royalty is not allowed
|
||||
(False, (100000, 10001, 10005)), # 1000% shouldn't work
|
||||
],
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
# @pytest.mark.skip
|
||||
@ -1316,12 +1323,30 @@ async def test_complex_nft_offer(
|
||||
for i in range(0, 2):
|
||||
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_maker))
|
||||
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_taker))
|
||||
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_taker))
|
||||
if royalty_pts[0] > 60000:
|
||||
blocks_needed = 9
|
||||
else:
|
||||
blocks_needed = 3
|
||||
if not forwards_compat:
|
||||
for i in range(blocks_needed):
|
||||
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_taker))
|
||||
else:
|
||||
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_taker))
|
||||
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_token))
|
||||
await full_node_api.wait_for_wallets_synced(wallet_nodes=[wallet_node_maker, wallet_node_taker], timeout=30)
|
||||
|
||||
funds_maker = sum([calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, 3)])
|
||||
funds_taker = sum([calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, 4)])
|
||||
if forwards_compat:
|
||||
funds_taker = sum(
|
||||
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, 4)]
|
||||
)
|
||||
else:
|
||||
funds_taker = sum(
|
||||
[
|
||||
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
|
||||
for i in range(1, 3 + blocks_needed)
|
||||
]
|
||||
)
|
||||
|
||||
await time_out_assert(30, wallet_maker.get_unconfirmed_balance, funds_maker)
|
||||
await time_out_assert(30, wallet_maker.get_confirmed_balance, funds_maker)
|
||||
@ -1391,7 +1416,7 @@ async def test_complex_nft_offer(
|
||||
royalty_puzhash_maker = ph_maker
|
||||
royalty_puzhash_taker = ph_taker
|
||||
royalty_basis_pts_maker, royalty_basis_pts_taker_1, royalty_basis_pts_taker_2 = (
|
||||
uint16(royalty_pts[0]),
|
||||
royalty_pts[0],
|
||||
uint16(royalty_pts[1]),
|
||||
uint16(royalty_pts[2]),
|
||||
)
|
||||
@ -1408,14 +1433,25 @@ async def test_complex_nft_offer(
|
||||
("h", "0xD4584AD463139FA8C0D9F68F4B59F185"),
|
||||
]
|
||||
)
|
||||
if royalty_basis_pts_maker > 65535:
|
||||
with pytest.raises(ValueError):
|
||||
await nft_wallet_maker.generate_new_nft(
|
||||
metadata,
|
||||
target_puzhash_maker,
|
||||
royalty_puzhash_maker,
|
||||
royalty_basis_pts_maker, # type: ignore
|
||||
did_id_maker,
|
||||
)
|
||||
return
|
||||
else:
|
||||
sb_maker = await nft_wallet_maker.generate_new_nft(
|
||||
metadata,
|
||||
target_puzhash_maker,
|
||||
royalty_puzhash_maker,
|
||||
uint16(royalty_basis_pts_maker),
|
||||
did_id_maker,
|
||||
)
|
||||
|
||||
sb_maker = await nft_wallet_maker.generate_new_nft(
|
||||
metadata,
|
||||
target_puzhash_maker,
|
||||
royalty_puzhash_maker,
|
||||
royalty_basis_pts_maker,
|
||||
did_id_maker,
|
||||
)
|
||||
sb_taker_1 = await nft_wallet_taker.generate_new_nft(
|
||||
metadata,
|
||||
target_puzhash_taker,
|
||||
@ -1508,12 +1544,21 @@ async def test_complex_nft_offer(
|
||||
assert error is None
|
||||
assert success
|
||||
assert trade_make is not None
|
||||
|
||||
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
|
||||
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
|
||||
wallet_node_taker.get_full_node_peer(),
|
||||
fee=FEE,
|
||||
)
|
||||
if royalty_basis_pts_maker == 10000:
|
||||
with pytest.raises(ValueError):
|
||||
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
|
||||
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
|
||||
wallet_node_taker.get_full_node_peer(),
|
||||
fee=FEE,
|
||||
)
|
||||
# all done for this test
|
||||
return
|
||||
else:
|
||||
trade_take, tx_records = await trade_manager_taker.respond_to_offer(
|
||||
old_maker_offer if forwards_compat else Offer.from_bytes(trade_make.offer),
|
||||
wallet_node_taker.get_full_node_peer(),
|
||||
fee=FEE,
|
||||
)
|
||||
assert trade_take is not None
|
||||
assert tx_records is not None
|
||||
await full_node_api.process_transaction_records(records=tx_records)
|
||||
@ -1521,7 +1566,7 @@ async def test_complex_nft_offer(
|
||||
# Now let's make sure the final wallet state is correct
|
||||
maker_royalty_summary = NFTWallet.royalty_calculation(
|
||||
{
|
||||
nft_to_offer_asset_id_maker: (royalty_puzhash_maker, royalty_basis_pts_maker),
|
||||
nft_to_offer_asset_id_maker: (royalty_puzhash_maker, uint16(royalty_basis_pts_maker)),
|
||||
},
|
||||
{
|
||||
None: uint64(XCH_REQUESTED),
|
||||
|
Loading…
Reference in New Issue
Block a user