mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-11-13 03:12:24 +03:00
Merge remote-tracking branch 'origin/release/1.4.0' into new_nft1_chialisp
This commit is contained in:
commit
bbe80db0ca
@ -1 +1 @@
|
|||||||
Subproject commit b5c6bbc649333621c626b02799a037cc79d42a59
|
Subproject commit 1cb1a8e7b7ab8025744a4205e2444b87621ccd1b
|
@ -487,11 +487,15 @@ def nft_cmd():
|
|||||||
default=None,
|
default=None,
|
||||||
)
|
)
|
||||||
@click.option("-f", "--fingerprint", help="Set the fingerprint to specify which wallet to use", type=int)
|
@click.option("-f", "--fingerprint", help="Set the fingerprint to specify which wallet to use", type=int)
|
||||||
def nft_wallet_create_cmd(wallet_rpc_port: Optional[int], fingerprint: int) -> None:
|
@click.option("-di", "--did-id", help="DID Id to use", type=str)
|
||||||
|
@click.option("-n", "--name", help="Set the NFT wallet name", type=str)
|
||||||
|
def nft_wallet_create_cmd(
|
||||||
|
wallet_rpc_port: Optional[int], fingerprint: int, did_id: Optional[str], name: Optional[str]
|
||||||
|
) -> None:
|
||||||
import asyncio
|
import asyncio
|
||||||
from .wallet_funcs import execute_with_wallet, create_nft_wallet
|
from .wallet_funcs import execute_with_wallet, create_nft_wallet
|
||||||
|
|
||||||
extra_params: Dict[str, Any] = {}
|
extra_params: Dict[str, Any] = {"did_id": did_id, "name": name}
|
||||||
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, create_nft_wallet))
|
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, create_nft_wallet))
|
||||||
|
|
||||||
|
|
||||||
@ -524,6 +528,14 @@ def nft_wallet_create_cmd(wallet_rpc_port: Optional[int], fingerprint: int) -> N
|
|||||||
show_default=True,
|
show_default=True,
|
||||||
callback=validate_fee,
|
callback=validate_fee,
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
"-rp",
|
||||||
|
"--royalty-percentage-fraction",
|
||||||
|
help="NFT royalty percentage fraction in basis points. Example: 175 would represent 1.75%",
|
||||||
|
type=int,
|
||||||
|
default=0,
|
||||||
|
show_default=True,
|
||||||
|
)
|
||||||
def nft_mint_cmd(
|
def nft_mint_cmd(
|
||||||
wallet_rpc_port: Optional[int],
|
wallet_rpc_port: Optional[int],
|
||||||
fingerprint: int,
|
fingerprint: int,
|
||||||
@ -539,6 +551,7 @@ def nft_mint_cmd(
|
|||||||
series_total: Optional[int],
|
series_total: Optional[int],
|
||||||
series_number: Optional[int],
|
series_number: Optional[int],
|
||||||
fee: str,
|
fee: str,
|
||||||
|
royalty_percentage_fraction: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
import asyncio
|
import asyncio
|
||||||
from .wallet_funcs import execute_with_wallet, mint_nft
|
from .wallet_funcs import execute_with_wallet, mint_nft
|
||||||
@ -566,6 +579,7 @@ def nft_mint_cmd(
|
|||||||
"series_total": series_total,
|
"series_total": series_total,
|
||||||
"series_number": series_number,
|
"series_number": series_number,
|
||||||
"fee": fee,
|
"fee": fee,
|
||||||
|
"royalty_percentage": royalty_percentage_fraction,
|
||||||
}
|
}
|
||||||
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, mint_nft))
|
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, mint_nft))
|
||||||
|
|
||||||
@ -668,3 +682,44 @@ def nft_list_cmd(wallet_rpc_port: Optional[int], fingerprint: int, id: int) -> N
|
|||||||
|
|
||||||
extra_params = {"wallet_id": id}
|
extra_params = {"wallet_id": id}
|
||||||
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, list_nfts))
|
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, list_nfts))
|
||||||
|
|
||||||
|
|
||||||
|
@nft_cmd.command("set_did", short_help="Set a DID on an NFT")
|
||||||
|
@click.option(
|
||||||
|
"-wp",
|
||||||
|
"--wallet-rpc-port",
|
||||||
|
help="Set the port where the Wallet is hosting the RPC interface. See the rpc_port under wallet in config.yaml",
|
||||||
|
type=int,
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
@click.option("-f", "--fingerprint", help="Set the fingerprint to specify which wallet to use", type=int)
|
||||||
|
@click.option("-i", "--id", help="Id of the NFT wallet to use", type=int, required=True)
|
||||||
|
@click.option("-di", "--did-id", help="DID Id to set on the NFT", type=str, required=True)
|
||||||
|
@click.option("-ni", "--nft-coin-id", help="Id of the NFT coin to set the DID on", type=str, required=True)
|
||||||
|
@click.option(
|
||||||
|
"-m",
|
||||||
|
"--fee",
|
||||||
|
help="Set the fees per transaction, in XCH.",
|
||||||
|
type=str,
|
||||||
|
default="0",
|
||||||
|
show_default=True,
|
||||||
|
callback=validate_fee,
|
||||||
|
)
|
||||||
|
def nft_set_did_cmd(
|
||||||
|
wallet_rpc_port: Optional[int],
|
||||||
|
fingerprint: int,
|
||||||
|
id: int,
|
||||||
|
did_id: str,
|
||||||
|
nft_coin_id: str,
|
||||||
|
fee: str,
|
||||||
|
) -> None:
|
||||||
|
import asyncio
|
||||||
|
from .wallet_funcs import execute_with_wallet, set_nft_did
|
||||||
|
|
||||||
|
extra_params = {
|
||||||
|
"wallet_id": id,
|
||||||
|
"did_id": did_id,
|
||||||
|
"nft_coin_id": nft_coin_id,
|
||||||
|
"fee": fee,
|
||||||
|
}
|
||||||
|
asyncio.run(execute_with_wallet(wallet_rpc_port, fingerprint, extra_params, set_nft_did))
|
||||||
|
@ -682,8 +682,10 @@ async def get_did(args: Dict, wallet_client: WalletRpcClient, fingerprint: int)
|
|||||||
|
|
||||||
|
|
||||||
async def create_nft_wallet(args: Dict, wallet_client: WalletRpcClient, fingerprint: int) -> None:
|
async def create_nft_wallet(args: Dict, wallet_client: WalletRpcClient, fingerprint: int) -> None:
|
||||||
|
did_id = args["did_id"]
|
||||||
|
name = args["name"]
|
||||||
try:
|
try:
|
||||||
response = await wallet_client.create_new_nft_wallet(None)
|
response = await wallet_client.create_new_nft_wallet(did_id, name)
|
||||||
wallet_id = response["wallet_id"]
|
wallet_id = response["wallet_id"]
|
||||||
print(f"Successfully created an NFT wallet with id {wallet_id} on key {fingerprint}")
|
print(f"Successfully created an NFT wallet with id {wallet_id} on key {fingerprint}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -703,6 +705,7 @@ async def mint_nft(args: Dict, wallet_client: WalletRpcClient, fingerprint: int)
|
|||||||
series_total = args["series_total"]
|
series_total = args["series_total"]
|
||||||
series_number = args["series_number"]
|
series_number = args["series_number"]
|
||||||
fee = args["fee"]
|
fee = args["fee"]
|
||||||
|
royalty_percentage = args["royalty_percentage"]
|
||||||
try:
|
try:
|
||||||
response = await wallet_client.mint_nft(
|
response = await wallet_client.mint_nft(
|
||||||
wallet_id,
|
wallet_id,
|
||||||
@ -717,6 +720,7 @@ async def mint_nft(args: Dict, wallet_client: WalletRpcClient, fingerprint: int)
|
|||||||
series_total,
|
series_total,
|
||||||
series_number,
|
series_number,
|
||||||
fee,
|
fee,
|
||||||
|
royalty_percentage,
|
||||||
)
|
)
|
||||||
spend_bundle = response["spend_bundle"]
|
spend_bundle = response["spend_bundle"]
|
||||||
print(f"NFT minted Successfully with spend bundle: {spend_bundle}")
|
print(f"NFT minted Successfully with spend bundle: {spend_bundle}")
|
||||||
@ -763,13 +767,17 @@ async def list_nfts(args: Dict, wallet_client: WalletRpcClient, fingerprint: int
|
|||||||
|
|
||||||
for n in nft_list:
|
for n in nft_list:
|
||||||
nft = NFTInfo.from_json_dict(n)
|
nft = NFTInfo.from_json_dict(n)
|
||||||
|
if nft.owner_pubkey is None:
|
||||||
|
owner_pubkey = None
|
||||||
|
else:
|
||||||
|
owner_pubkey = nft.owner_pubkey.hex()
|
||||||
print()
|
print()
|
||||||
print(f"{'Launcher coin ID:'.ljust(26)} {nft.launcher_id}")
|
print(f"{'Launcher coin ID:'.ljust(26)} {nft.launcher_id}")
|
||||||
print(f"{'Launcher puzhash:'.ljust(26)} {nft.launcher_puzhash}")
|
print(f"{'Launcher puzhash:'.ljust(26)} {nft.launcher_puzhash}")
|
||||||
print(f"{'Current NFT coin ID:'.ljust(26)} {nft.nft_coin_id}")
|
print(f"{'Current NFT coin ID:'.ljust(26)} {nft.nft_coin_id}")
|
||||||
print(f"{'On-chain data/info:'.ljust(26)} {nft.chain_info}")
|
print(f"{'On-chain data/info:'.ljust(26)} {nft.chain_info}")
|
||||||
print(f"{'Owner DID:'.ljust(26)} {nft.owner_did}")
|
print(f"{'Owner DID:'.ljust(26)} {nft.owner_did}")
|
||||||
print(f"{'Owner pubkey:'.ljust(26)} {nft.owner_pubkey}")
|
print(f"{'Owner pubkey:'.ljust(26)} {owner_pubkey}")
|
||||||
print(f"{'Royalty percentage:'.ljust(26)} {nft.royalty_percentage}")
|
print(f"{'Royalty percentage:'.ljust(26)} {nft.royalty_percentage}")
|
||||||
print(f"{'Royalty puzhash:'.ljust(26)} {nft.royalty_puzzle_hash}")
|
print(f"{'Royalty puzhash:'.ljust(26)} {nft.royalty_puzzle_hash}")
|
||||||
print(f"{'NFT content hash:'.ljust(26)} {nft.data_hash.hex()}")
|
print(f"{'NFT content hash:'.ljust(26)} {nft.data_hash.hex()}")
|
||||||
@ -797,3 +805,16 @@ async def list_nfts(args: Dict, wallet_client: WalletRpcClient, fingerprint: int
|
|||||||
print(f"No NFTs found for wallet with id {wallet_id} on key {fingerprint}")
|
print(f"No NFTs found for wallet with id {wallet_id} on key {fingerprint}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to list NFTs for wallet with id {wallet_id} on key {fingerprint}: {e}")
|
print(f"Failed to list NFTs for wallet with id {wallet_id} on key {fingerprint}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
async def set_nft_did(args: Dict, wallet_client: WalletRpcClient, fingerprint: int) -> None:
|
||||||
|
wallet_id = args["wallet_id"]
|
||||||
|
did_id = args["did_id"]
|
||||||
|
nft_coin_id = args["nft_coin_id"]
|
||||||
|
fee = args["fee"]
|
||||||
|
try:
|
||||||
|
response = await wallet_client.set_nft_did(wallet_id, did_id, nft_coin_id, fee)
|
||||||
|
spend_bundle = response["spend_bundle"]
|
||||||
|
print(f"Transaction to set DID on NFT has been initiated with: {spend_bundle}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to set DID on NFT: {e}")
|
||||||
|
@ -14,6 +14,7 @@ from chia.types.peer_info import PeerInfo
|
|||||||
from chia.util.byte_types import hexstr_to_bytes
|
from chia.util.byte_types import hexstr_to_bytes
|
||||||
from chia.util.ints import uint16
|
from chia.util.ints import uint16
|
||||||
from chia.util.json_util import dict_to_json_str
|
from chia.util.json_util import dict_to_json_str
|
||||||
|
from chia.util.network import select_port
|
||||||
from chia.util.ws_message import create_payload, create_payload_dict, format_response, pong
|
from chia.util.ws_message import create_payload, create_payload_dict, format_response, pong
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -328,7 +329,13 @@ async def start_rpc_server(
|
|||||||
|
|
||||||
site = web.TCPSite(runner, self_hostname, int(rpc_port), ssl_context=rpc_server.ssl_context)
|
site = web.TCPSite(runner, self_hostname, int(rpc_port), ssl_context=rpc_server.ssl_context)
|
||||||
await site.start()
|
await site.start()
|
||||||
rpc_port = runner.addresses[0][1]
|
|
||||||
|
#
|
||||||
|
# On a dual-stack system, we want to get the (first) IPv4 port unless
|
||||||
|
# prefer_ipv6 is set in which case we use the IPv6 port
|
||||||
|
#
|
||||||
|
if rpc_port == 0:
|
||||||
|
rpc_port = select_port(root_path, runner.addresses)
|
||||||
|
|
||||||
async def cleanup():
|
async def cleanup():
|
||||||
await rpc_server.stop()
|
await rpc_server.stop()
|
||||||
|
@ -135,6 +135,7 @@ class WalletRpcApi:
|
|||||||
# NFT Wallet
|
# NFT Wallet
|
||||||
"/nft_mint_nft": self.nft_mint_nft,
|
"/nft_mint_nft": self.nft_mint_nft,
|
||||||
"/nft_get_nfts": self.nft_get_nfts,
|
"/nft_get_nfts": self.nft_get_nfts,
|
||||||
|
"/nft_get_by_did": self.nft_get_by_did,
|
||||||
"/nft_get_info": self.nft_get_info,
|
"/nft_get_info": self.nft_get_info,
|
||||||
"/nft_transfer_nft": self.nft_transfer_nft,
|
"/nft_transfer_nft": self.nft_transfer_nft,
|
||||||
"/nft_add_uri": self.nft_add_uri,
|
"/nft_add_uri": self.nft_add_uri,
|
||||||
@ -1388,6 +1389,16 @@ class WalletRpcApi:
|
|||||||
nft_info_list.append(nft_puzzles.get_nft_info_from_puzzle(nft))
|
nft_info_list.append(nft_puzzles.get_nft_info_from_puzzle(nft))
|
||||||
return {"wallet_id": wallet_id, "success": True, "nft_list": nft_info_list}
|
return {"wallet_id": wallet_id, "success": True, "nft_list": nft_info_list}
|
||||||
|
|
||||||
|
async def nft_get_by_did(self, request) -> Dict:
|
||||||
|
did_id: Optional[bytes32] = None
|
||||||
|
if "did_id" in request:
|
||||||
|
did_id = bytes32.from_hexstr(request["did_id"])
|
||||||
|
assert self.service.wallet_state_manager is not None
|
||||||
|
for wallet in self.service.wallet_state_manager.wallets.values():
|
||||||
|
if isinstance(wallet, NFTWallet) and wallet.get_did() == did_id:
|
||||||
|
return {"wallet_id": wallet.wallet_id, "success": True}
|
||||||
|
return {"error": f"Cannot find a NFT wallet DID = {did_id}", "success": False}
|
||||||
|
|
||||||
async def nft_transfer_nft(self, request):
|
async def nft_transfer_nft(self, request):
|
||||||
assert self.service.wallet_state_manager is not None
|
assert self.service.wallet_state_manager is not None
|
||||||
wallet_id = uint32(request["wallet_id"])
|
wallet_id = uint32(request["wallet_id"])
|
||||||
|
@ -650,3 +650,8 @@ class WalletRpcClient(RpcClient):
|
|||||||
request: Dict[str, Any] = {"wallet_id": wallet_id}
|
request: Dict[str, Any] = {"wallet_id": wallet_id}
|
||||||
response = await self.fetch("nft_get_nfts", request)
|
response = await self.fetch("nft_get_nfts", request)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
async def set_nft_did(self, wallet_id, did_id, nft_coin_id, fee):
|
||||||
|
request: Dict[str, Any] = {"wallet_id": wallet_id, "did_id": did_id, "nft_coin_id": nft_coin_id, "fee": fee}
|
||||||
|
response = await self.fetch("nft_set_nft_did", request)
|
||||||
|
return response
|
||||||
|
@ -30,7 +30,7 @@ from chia.types.blockchain_format.sized_bytes import bytes32
|
|||||||
from chia.types.peer_info import PeerInfo
|
from chia.types.peer_info import PeerInfo
|
||||||
from chia.util.errors import Err, ProtocolError
|
from chia.util.errors import Err, ProtocolError
|
||||||
from chia.util.ints import uint16
|
from chia.util.ints import uint16
|
||||||
from chia.util.network import is_in_network, is_localhost
|
from chia.util.network import is_in_network, is_localhost, select_port
|
||||||
from chia.util.ssl_check import verify_ssl_certs_and_keys
|
from chia.util.ssl_check import verify_ssl_certs_and_keys
|
||||||
|
|
||||||
max_message_size = 50 * 1024 * 1024 # 50MB
|
max_message_size = 50 * 1024 * 1024 # 50MB
|
||||||
@ -267,13 +267,19 @@ class ChiaServer:
|
|||||||
# this port from the socket itself and update self._port.
|
# this port from the socket itself and update self._port.
|
||||||
self.site = web.TCPSite(
|
self.site = web.TCPSite(
|
||||||
self.runner,
|
self.runner,
|
||||||
host="0.0.0.0",
|
host="", # should listen to both IPv4 and IPv6 on a dual-stack system
|
||||||
port=int(self._port),
|
port=int(self._port),
|
||||||
shutdown_timeout=3,
|
shutdown_timeout=3,
|
||||||
ssl_context=ssl_context,
|
ssl_context=ssl_context,
|
||||||
)
|
)
|
||||||
await self.site.start()
|
await self.site.start()
|
||||||
self._port = self.runner.addresses[0][1]
|
#
|
||||||
|
# On a dual-stack system, we want to get the (first) IPv4 port unless
|
||||||
|
# prefer_ipv6 is set in which case we use the IPv6 port
|
||||||
|
#
|
||||||
|
if self._port == 0:
|
||||||
|
self._port = select_port(self.root_path, self.runner.addresses)
|
||||||
|
|
||||||
self.log.info(f"Started listening on port: {self._port}")
|
self.log.info(f"Started listening on port: {self._port}")
|
||||||
|
|
||||||
async def incoming_connection(self, request):
|
async def incoming_connection(self, request):
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import socket
|
import socket
|
||||||
|
from pathlib import Path
|
||||||
from ipaddress import ip_address, IPv4Network, IPv6Network
|
from ipaddress import ip_address, IPv4Network, IPv6Network
|
||||||
from typing import Iterable, List, Tuple, Union, Any, Optional, Dict
|
from typing import Iterable, List, Tuple, Union, Any, Optional, Dict
|
||||||
from chia.server.outbound_message import NodeType
|
from chia.server.outbound_message import NodeType
|
||||||
from chia.types.blockchain_format.sized_bytes import bytes32
|
from chia.types.blockchain_format.sized_bytes import bytes32
|
||||||
from chia.types.peer_info import PeerInfo
|
from chia.types.peer_info import PeerInfo
|
||||||
|
from chia.util.config import load_config
|
||||||
from chia.util.ints import uint16
|
from chia.util.ints import uint16
|
||||||
|
|
||||||
|
|
||||||
@ -84,3 +86,21 @@ def is_trusted_inner(peer_host: str, peer_node_id: bytes32, trusted_peers: Dict,
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def select_port(root_path: Path, addresses: List[Any]) -> uint16:
|
||||||
|
global_config = load_config(root_path, "config.yaml")
|
||||||
|
prefer_ipv6 = global_config.get("prefer_ipv6", False)
|
||||||
|
selected_port: uint16
|
||||||
|
for address_string, port, *_ in addresses:
|
||||||
|
address = ip_address(address_string)
|
||||||
|
if address.version == 6 and prefer_ipv6:
|
||||||
|
selected_port = port
|
||||||
|
break
|
||||||
|
elif address.version == 4 and not prefer_ipv6:
|
||||||
|
selected_port = port
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
selected_port = addresses[0][1] # no matches, just use the first one in the list
|
||||||
|
|
||||||
|
return selected_port
|
||||||
|
@ -11,7 +11,11 @@ from chia.wallet.nft_wallet.nft_info import NFTCoinInfo, NFTInfo
|
|||||||
from chia.wallet.nft_wallet.uncurry_nft import UncurriedNFT
|
from chia.wallet.nft_wallet.uncurry_nft import UncurriedNFT
|
||||||
from chia.wallet.puzzles.cat_loader import CAT_MOD
|
from chia.wallet.puzzles.cat_loader import CAT_MOD
|
||||||
from chia.wallet.puzzles.load_clvm import load_clvm
|
from chia.wallet.puzzles.load_clvm import load_clvm
|
||||||
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import solution_for_conditions
|
from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import (
|
||||||
|
DEFAULT_HIDDEN_PUZZLE_HASH,
|
||||||
|
calculate_synthetic_public_key,
|
||||||
|
solution_for_conditions,
|
||||||
|
)
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
SINGLETON_TOP_LAYER_MOD = load_clvm("singleton_top_layer_v1_1.clvm")
|
SINGLETON_TOP_LAYER_MOD = load_clvm("singleton_top_layer_v1_1.clvm")
|
||||||
|
@ -64,7 +64,10 @@ class NFTWallet:
|
|||||||
nft_wallet_info: NFTWalletInfo
|
nft_wallet_info: NFTWalletInfo
|
||||||
standard_wallet: Wallet
|
standard_wallet: Wallet
|
||||||
wallet_id: int
|
wallet_id: int
|
||||||
did_id: Optional[bytes32]
|
|
||||||
|
@property
|
||||||
|
def did_id(self):
|
||||||
|
return self.nft_wallet_info.did_id
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create_new_nft_wallet(
|
async def create_new_nft_wallet(
|
||||||
@ -72,7 +75,7 @@ class NFTWallet:
|
|||||||
wallet_state_manager: Any,
|
wallet_state_manager: Any,
|
||||||
wallet: Wallet,
|
wallet: Wallet,
|
||||||
did_id: Optional[bytes32] = None,
|
did_id: Optional[bytes32] = None,
|
||||||
name: str = "",
|
name: Optional[str] = None,
|
||||||
in_transaction: bool = False,
|
in_transaction: bool = False,
|
||||||
) -> _T_NFTWallet:
|
) -> _T_NFTWallet:
|
||||||
"""
|
"""
|
||||||
@ -80,12 +83,14 @@ class NFTWallet:
|
|||||||
"""
|
"""
|
||||||
self = cls()
|
self = cls()
|
||||||
self.standard_wallet = wallet
|
self.standard_wallet = wallet
|
||||||
|
if name is None:
|
||||||
|
name = "NFT Wallet"
|
||||||
self.log = logging.getLogger(name if name else __name__)
|
self.log = logging.getLogger(name if name else __name__)
|
||||||
self.wallet_state_manager = wallet_state_manager
|
self.wallet_state_manager = wallet_state_manager
|
||||||
self.nft_wallet_info = NFTWalletInfo([], did_id)
|
self.nft_wallet_info = NFTWalletInfo([], did_id)
|
||||||
info_as_string = json.dumps(self.nft_wallet_info.to_json_dict())
|
info_as_string = json.dumps(self.nft_wallet_info.to_json_dict())
|
||||||
wallet_info = await wallet_state_manager.user_store.create_wallet(
|
wallet_info = await wallet_state_manager.user_store.create_wallet(
|
||||||
"NFT Wallet" if not name else name,
|
name,
|
||||||
uint32(WalletType.NFT.value),
|
uint32(WalletType.NFT.value),
|
||||||
info_as_string,
|
info_as_string,
|
||||||
in_transaction=in_transaction,
|
in_transaction=in_transaction,
|
||||||
@ -99,12 +104,6 @@ class NFTWallet:
|
|||||||
|
|
||||||
await self.wallet_state_manager.add_new_wallet(self, self.wallet_info.id, in_transaction=in_transaction)
|
await self.wallet_state_manager.add_new_wallet(self, self.wallet_info.id, in_transaction=in_transaction)
|
||||||
self.log.debug("Generated a new NFT wallet: %s", self.__dict__)
|
self.log.debug("Generated a new NFT wallet: %s", self.__dict__)
|
||||||
if not did_id:
|
|
||||||
# default profile wallet
|
|
||||||
self.log.debug("Standard NFT wallet created")
|
|
||||||
self.did_id = None
|
|
||||||
else:
|
|
||||||
self.did_id = did_id
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -244,7 +243,8 @@ class NFTWallet:
|
|||||||
if new_coin.puzzle_hash == child_puzzle.get_tree_hash():
|
if new_coin.puzzle_hash == child_puzzle.get_tree_hash():
|
||||||
child_coin = new_coin
|
child_coin = new_coin
|
||||||
break
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Rebuild NFT doesn't match the actual puzzle hash: {child_puzzle}")
|
||||||
launcher_coin_states: List[CoinState] = await self.wallet_state_manager.wallet_node.get_coin_state(
|
launcher_coin_states: List[CoinState] = await self.wallet_state_manager.wallet_node.get_coin_state(
|
||||||
[singleton_id]
|
[singleton_id]
|
||||||
)
|
)
|
||||||
@ -412,8 +412,6 @@ class NFTWallet:
|
|||||||
|
|
||||||
bundles_to_agg = [tx_record.spend_bundle, launcher_sb]
|
bundles_to_agg = [tx_record.spend_bundle, launcher_sb]
|
||||||
|
|
||||||
if not target_puzzle_hash:
|
|
||||||
target_puzzle_hash = p2_inner_puzzle.get_tree_hash()
|
|
||||||
record: Optional[DerivationRecord] = None
|
record: Optional[DerivationRecord] = None
|
||||||
# Create inner solution for eve spend
|
# Create inner solution for eve spend
|
||||||
if did_id is not None:
|
if did_id is not None:
|
||||||
@ -514,7 +512,7 @@ class NFTWallet:
|
|||||||
additional_bundles: List[SpendBundle] = [],
|
additional_bundles: List[SpendBundle] = [],
|
||||||
) -> TransactionRecord:
|
) -> TransactionRecord:
|
||||||
# Update NFT status
|
# Update NFT status
|
||||||
await self.update_coin_status(nft_coin_info.coin.name(), True)
|
|
||||||
coin = nft_coin_info.coin
|
coin = nft_coin_info.coin
|
||||||
amount = coin.amount
|
amount = coin.amount
|
||||||
if not additional_bundles:
|
if not additional_bundles:
|
||||||
@ -578,6 +576,7 @@ class NFTWallet:
|
|||||||
inner_solution = Program.to([solution_for_conditions(condition_list)])
|
inner_solution = Program.to([solution_for_conditions(condition_list)])
|
||||||
nft_tx_record = await self._make_nft_transaction(nft_coin_info, inner_solution, [puzzle_hash], fee)
|
nft_tx_record = await self._make_nft_transaction(nft_coin_info, inner_solution, [puzzle_hash], fee)
|
||||||
await self.standard_wallet.push_transaction(nft_tx_record)
|
await self.standard_wallet.push_transaction(nft_tx_record)
|
||||||
|
await self.update_coin_status(nft_coin_info.coin.name(), True)
|
||||||
self.wallet_state_manager.state_changed("nft_coin_updated", self.wallet_info.id)
|
self.wallet_state_manager.state_changed("nft_coin_updated", self.wallet_info.id)
|
||||||
return nft_tx_record.spend_bundle
|
return nft_tx_record.spend_bundle
|
||||||
|
|
||||||
@ -608,6 +607,7 @@ class NFTWallet:
|
|||||||
fee,
|
fee,
|
||||||
)
|
)
|
||||||
await self.standard_wallet.push_transaction(nft_tx_record)
|
await self.standard_wallet.push_transaction(nft_tx_record)
|
||||||
|
await self.update_coin_status(nft_coin_info.coin.name(), True)
|
||||||
self.wallet_state_manager.state_changed("nft_coin_transferred", self.wallet_info.id)
|
self.wallet_state_manager.state_changed("nft_coin_transferred", self.wallet_info.id)
|
||||||
return nft_tx_record.spend_bundle
|
return nft_tx_record.spend_bundle
|
||||||
|
|
||||||
@ -705,6 +705,7 @@ class NFTWallet:
|
|||||||
return await cls.create_new_nft_wallet(
|
return await cls.create_new_nft_wallet(
|
||||||
wallet_state_manager,
|
wallet_state_manager,
|
||||||
wallet,
|
wallet,
|
||||||
|
None,
|
||||||
name,
|
name,
|
||||||
in_transaction,
|
in_transaction,
|
||||||
)
|
)
|
||||||
|
@ -716,19 +716,18 @@ class WalletStateManager:
|
|||||||
"""
|
"""
|
||||||
wallet_id = None
|
wallet_id = None
|
||||||
wallet_type = None
|
wallet_type = None
|
||||||
self.log.debug("Handling NFT: %s", coin_spend)
|
|
||||||
did_id = uncurried_nft.owner_did
|
did_id = uncurried_nft.owner_did
|
||||||
for wallet_info in await self.get_all_wallet_info_entries():
|
self.log.debug("Handling NFT: %s, DID: %s", coin_spend, did_id)
|
||||||
if wallet_info.type == WalletType.NFT:
|
for wallet_info in await self.get_all_wallet_info_entries(wallet_type=WalletType.NFT):
|
||||||
nft_wallet_info: NFTWalletInfo = NFTWalletInfo.from_json_dict(json.loads(wallet_info.data))
|
nft_wallet_info: NFTWalletInfo = NFTWalletInfo.from_json_dict(json.loads(wallet_info.data))
|
||||||
if nft_wallet_info.did_id == did_id:
|
if nft_wallet_info.did_id == did_id:
|
||||||
self.log.debug(
|
self.log.debug(
|
||||||
"Checking NFT wallet %r and inner puzzle %s",
|
"Checking NFT wallet %r and inner puzzle %s",
|
||||||
wallet_info.name,
|
wallet_info.name,
|
||||||
uncurried_nft.inner_puzzle.get_tree_hash(),
|
uncurried_nft.inner_puzzle.get_tree_hash(),
|
||||||
)
|
)
|
||||||
wallet_id = wallet_info.id
|
wallet_id = wallet_info.id
|
||||||
wallet_type = WalletType.NFT
|
wallet_type = WalletType.NFT
|
||||||
|
|
||||||
if wallet_id is None:
|
if wallet_id is None:
|
||||||
self.log.info(
|
self.log.info(
|
||||||
@ -748,7 +747,6 @@ class WalletStateManager:
|
|||||||
self, coin_states: List[CoinState], peer: WSChiaConnection, fork_height: Optional[uint32]
|
self, coin_states: List[CoinState], peer: WSChiaConnection, fork_height: Optional[uint32]
|
||||||
) -> None:
|
) -> None:
|
||||||
# TODO: add comment about what this method does
|
# TODO: add comment about what this method does
|
||||||
|
|
||||||
# Input states should already be sorted by cs_height, with reorgs at the beginning
|
# Input states should already be sorted by cs_height, with reorgs at the beginning
|
||||||
curr_h = -1
|
curr_h = -1
|
||||||
for c_state in coin_states:
|
for c_state in coin_states:
|
||||||
|
@ -597,21 +597,36 @@ async def test_nft_with_did_wallet_creation(two_wallet_nodes: Any, trusted: Any)
|
|||||||
assert res.get("success")
|
assert res.get("success")
|
||||||
nft_wallet_p2_puzzle = res["wallet_id"]
|
nft_wallet_p2_puzzle = res["wallet_id"]
|
||||||
assert nft_wallet_p2_puzzle != nft_wallet_0_id
|
assert nft_wallet_p2_puzzle != nft_wallet_0_id
|
||||||
|
|
||||||
|
res = await api_0.nft_get_by_did({"did_id": hex_did_id})
|
||||||
|
assert nft_wallet_0_id == res["wallet_id"]
|
||||||
await time_out_assert(10, wallet_0.get_unconfirmed_balance, 5999999999999)
|
await time_out_assert(10, wallet_0.get_unconfirmed_balance, 5999999999999)
|
||||||
await time_out_assert(10, wallet_0.get_confirmed_balance, 5999999999999)
|
await time_out_assert(10, wallet_0.get_confirmed_balance, 5999999999999)
|
||||||
# Create a NFT with DID
|
# Create a NFT with DID
|
||||||
|
nft_ph: bytes32 = await wallet_0.get_new_puzzlehash()
|
||||||
resp = await api_0.nft_mint_nft(
|
resp = await api_0.nft_mint_nft(
|
||||||
{
|
{
|
||||||
"wallet_id": nft_wallet_0_id,
|
"wallet_id": nft_wallet_0_id,
|
||||||
"hash": "0xD4584AD463139FA8C0D9F68F4B59F185",
|
"hash": "0xD4584AD463139FA8C0D9F68F4B59F185",
|
||||||
"uris": ["https://www.chia.net/img/branding/chia-logo.svg"],
|
"uris": ["https://www.chia.net/img/branding/chia-logo.svg"],
|
||||||
|
"target_address": encode_puzzle_hash(nft_ph, "txch"),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert resp.get("success")
|
assert resp.get("success")
|
||||||
sb = resp["spend_bundle"]
|
sb = resp["spend_bundle"]
|
||||||
|
# ensure hints are generated correctly
|
||||||
|
memos = compute_memos(sb)
|
||||||
|
assert memos
|
||||||
|
puzhashes = []
|
||||||
|
for x in memos.values():
|
||||||
|
puzhashes.extend(list(x))
|
||||||
|
assert len(puzhashes) > 0
|
||||||
|
matched = 0
|
||||||
|
for puzhash in puzhashes:
|
||||||
|
if puzhash.hex() == nft_ph.hex():
|
||||||
|
matched += 1
|
||||||
|
assert matched > 0
|
||||||
|
|
||||||
# ensure hints are generated
|
|
||||||
assert compute_memos(sb)
|
|
||||||
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
|
await time_out_assert_not_none(5, full_node_api.full_node.mempool_manager.get_spendbundle, sb.name())
|
||||||
|
|
||||||
for i in range(1, num_blocks):
|
for i in range(1, num_blocks):
|
||||||
|
Loading…
Reference in New Issue
Block a user