NFT代币合约

简介

什么是NFT代币?

  • NFT代币全称为 非同质化代币(Non-Fungible Token)

  • 是一种基于区块链技术的加密货币资产,其特点在于每一个代币都是独一无二且不可互换的。这与比特币、以太坊等同质化代币(Fungible Token)不同,后者的每一个单位都是相同的,可以互换。

  • NFT 的主要特性

    • 唯一性:
      每一个 NFT 都包含独特的信息,使其与其他 NFT 区别开来。这种唯一性可以用于表示数字资产的所有权和真实性。

    • 不可分割性:
      大多数 NFT 是不可分割的,不能像比特币那样分成更小的单位进行交易。每一个 NFT 通常作为一个整体进行买卖。

    • 所有权和可验证性:
      由于 NFT 存储在区块链上,它们的所有权和交易历史是公开可验证的。每个所有者的信息和交易记录都可以在区块链上查询,确保了透明性和安全性。

    • 互操作性:
      NFT 通常遵循特定的标准(例如,以太坊的 ERC-721 和 ERC-1155 标准),使它们可以在不同的平台和应用之间互操作。这意味着一个平台上创建的 NFT 可以在另一个平台上展示或交易。

  • NFT 的应用场景

    • 数字艺术:
      艺术家可以创建数字艺术作品,并通过 NFT 证明其真实性和所有权。NFT 允许艺术家在区块链上销售和转移他们的作品,同时保留作品的版权和原始性。

    • 收藏品:
      类似于实体世界中的收藏品(如稀有卡片、邮票等),数字收藏品也可以通过 NFT 表示。这些数字收藏品可以是游戏中的道具、虚拟宠物、数字纪念品等。

    • 游戏:
      游戏开发者可以通过 NFT 创建和销售游戏内的物品、角色和皮肤。玩家可以拥有和交易这些数字资产,并且可以在不同游戏之间互操作。

    • 虚拟地产:
      在虚拟世界或元宇宙(Metaverse)中,土地和财产可以通过 NFT 表示。用户可以购买、出售和开发这些虚拟地产。

    • 身份和证书:
      NFT 可以用于表示数字身份和证书,例如学位证书、活动门票、会员资格等。这些证书可以存储在区块链上,确保其真实性和可验证性。

  • NFT 是一种创新的区块链技术应用,通过其独特性、不可分割性、所有权和可验证性等特性,使其在数字艺术、收藏品、游戏、虚拟地产和身份认证等领域具有广泛的应用前景。NFT 的发展正在改变我们对数字资产的理解和使用方式。

NFT代币案例及故事

  1. Beeple的《Everydays: The First 5000 Days》
    案例:
    数字艺术家Beeple(本名Mike Winkelmann)创作的《Everydays: The First 5000 Days》是一幅由5000张每天创作的图像拼接而成的数字画作。

    故事:
    Beeple每天创作并发布一张数字艺术作品,连续5000天从未间断。2021年3月,这幅作品在佳士得拍卖行以6934万美元的价格售出,成为历史上最昂贵的NFT艺术品。这次拍卖引发了广泛关注,标志着NFT艺术品进入主流市场。

  2. CryptoPunks
    案例:
    CryptoPunks是一系列10,000个独特的24x24像素艺术图像,每个CryptoPunk都是由Larva Labs在以太坊区块链上创建的NFT。

    故事:
    CryptoPunks最初是免费发布的,任何拥有以太坊钱包的人都可以领取。然而,随着NFT市场的发展,这些早期的NFT收藏品变得极其珍贵。一些稀有的CryptoPunks,如外星人、僵尸和猿人,曾以数百万美元的价格售出。例如,CryptoPunk #7804在2021年以4200 ETH(约750万美元)的价格售出。

  3. NBA Top Shot
    案例:
    NBA Top Shot是由Dapper Labs与NBA合作推出的平台,用户可以购买、出售和交易NBA比赛的精彩瞬间,这些瞬间以NFT的形式存在。

    故事:
    NBA Top Shot的NFT包含了NBA比赛中的关键时刻视频片段,每个片段都是独一无二的收藏品。2021年初,NBA Top Shot迅速走红,许多瞬间的价格飙升。例如,勒布朗·詹姆斯的一个扣篮瞬间曾以超过20万美元的价格售出。这一平台吸引了大量体育迷和收藏家的关注,推动了NFT在体育界的应用。

  4. Decentraland
    案例:
    Decentraland是一个基于区块链的虚拟现实平台,用户可以在其中购买、出售和开发虚拟地产,这些地产以NFT的形式存在。

    故事:
    Decentraland的用户可以使用加密货币购买虚拟土地,开发自己的虚拟世界和应用。2021年,一块虚拟土地曾以90万美元的价格售出,这显示了虚拟地产的潜在价值。Decentraland的成功也带动了其他类似项目的发展,虚拟现实和元宇宙成为了新的投资热点。

  5. Jack Dorsey的首条推文
    案例:
    Twitter创始人兼CEO Jack Dorsey将他在2006年发布的第一条推文“just setting up my twttr”作为NFT进行拍卖。

    故事:
    这条历史性的推文在2021年3月被作为NFT在Valuables平台上拍卖,最终以超过290万美元的价格售出。Dorsey表示,他将拍卖所得的全部收益捐给慈善机构。这一事件展示了NFT在数字内容所有权和收藏品市场中的潜力。

这些案例展示了NFT在艺术、体育、虚拟现实和数字内容领域的广泛应用和潜力,也突显了NFT市场的快速增长和巨大的商业价值。

环境部署与合约编写

配置环境

  1. 使用VScode编辑器
    vscode
  2. 安装Solidity插件
    Solidity 是一种面向对象的高级静态语言,用于实现智能合约,运行于 以太坊虚拟机(EVM)
    在这里插入图片描述
  3. 安装node.js
    Node.js是一个JavaScript 运行时环境,用于构建服务器端应用程序,便于开发人员使用JS编写服务器端代码,实现前后端一体化
    在这里插入图片描述
  4. 安装truffle
    Truffle 是一个功能强大、灵活易用的以太坊智能合约开发框架,广泛应用于以太坊生态系统中的智能合约开发、测试和部署
npm install -g truffle

在这里插入图片描述

  1. 安装Ganache
    Ganache 是一个用于以太坊开发和测试的个人区块链网络,它提供了一个简单易用的方式来模拟以太坊网络,并且不需要实际连接到真实的区块链网络。
    在这里插入图片描述
    首先使用初始化命令对环境进行初始化(在vscode终端中进行)
truffle init

初始化环境之后 修改配置文件
在VScode 中打开truffle-config.js这个文件
在这里插入图片描述
在文件中添加这两段代码,第一段代码是根据Ganache网络写的(注意:这里的from 地址为Ganache网络中真实存在的地址,这里我选的是第一个),第二段代码是修改自己solidity的版本

  1. 下载Pinata并获取密钥
    首先需要注册Pinata的账户,然后在VScode终端中输入安装命令
npm install @pinata/sdk@1.1.0

Pinata 是一个提供 IPFS(InterPlanetary File System)服务的公司,专注于为用户提供简单易用的文件上传、管理和分发服务。IPFS 是一种分布式文件系统,旨在创建一个更开放、弹性和分散的网络。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
将复制的密钥信息保存到某个文件中

然后编写一个上传图片的代码 (目的是使用一张图片作为NFT标识)以下是一个案例

const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');

const API_KEY = '8243868a73ce0b3c69a6';
const API_SECRET = '8314e946fe8551b1053c3af4147da5bc720cc94ba27a783ba05f0d045797fbcb';
const PINATA_BASE_URL = 'https://api.pinata.cloud';

async function uploadImageToPinata() {
    const imagePath = './GoldDog.webp'; // 确保图片路径正确
    const formData = new FormData();
    formData.append('file', fs.createReadStream(imagePath));

    try {
        const response = await axios.post(`${PINATA_BASE_URL}/pinning/pinFileToIPFS`, formData, {
            headers: {
                'pinata_api_key': API_KEY,
                'pinata_secret_api_key': API_SECRET,
                ...formData.getHeaders()
            }
        });

        console.log('File uploaded:', response.data);
    } catch (error) {
        console.error('Error uploading file:', error.message);
    }
}

uploadImageToPinata();

注意:修改API_KEY, APT_SECRET, imagePathAPT_KEY和API_SECRET是刚才复制的,imagePath是自己的图片,注意写对位置
编写完成后运行代码,会在Pinata中看到自己的图片
在这里插入图片描述
7. 下载OpenZepelin简化开发

npm install @openzeppelin/contracts@4.3.x

OpenZeppelin/Contracts 是一个用于安全智能合约开发的库。 它提供了ERC20、 ERC721、ERC777、ERC1155 等标准的实现,还提供Solidity 组件来构建自定义合同和更复杂的分散系统。

这个库提供了多种合约标准,可以帮助我们简化开发,不需要我们再去写其他的合约

编写智能合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "../node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "../node_modules/@openzeppelin/contracts/access/Ownable.sol";

contract NFTAvatar is ERC721URIStorage, Ownable {
    uint256 private _tokenIds;
    mapping(uint256 => string) private _artists;
    mapping(uint256 => string) private _descriptions;
    mapping(uint256 => string) private _creationDates;

    // 定义一个事件
    event NFTMinted(uint256 indexed tokenId, address recipient);

    constructor(
        string memory name,
        string memory symbol
    ) ERC721(name, symbol) Ownable() {
        _tokenIds = 0;
    }

    function mintNFT(
        address recipient,
        string memory tokenURI,
        string memory artist,
        string memory description,
        string memory creationDate
    ) public onlyOwner returns (uint256) {
        _tokenIds++;
        uint256 newItemId = _tokenIds;

        _mint(recipient, newItemId);
        _setTokenURI(newItemId, tokenURI);

        _artists[newItemId] = artist;
        _descriptions[newItemId] = description;
        _creationDates[newItemId] = creationDate;

        // 触发事件
        emit NFTMinted(newItemId, recipient);

        return newItemId;
    }

    function currentTokenId() public view returns (uint256) {
        return _tokenIds;
    }
    function getArtist(uint256 tokenId) public view returns (string memory) {
        return _artists[tokenId];
    }

    function getDescription(
        uint256 tokenId
    ) public view returns (string memory) {
        return _descriptions[tokenId];
    }

    function getCreationDate(
        uint256 tokenId
    ) public view returns (string memory) {
        return _creationDates[tokenId];
    }

    // 获取指定tokenId的NFT的所有者地址
    function getOwnerOfToken(uint256 tokenId) public view returns (address) {
        return ownerOf(tokenId);
    }

    // 安全转移NFT
    function safeTransferNFT(address from, address to, uint256 tokenId) public {
        // 调用ERC721标准的safeTransferFrom
        safeTransferFrom(from, to, tokenId, "");
    }
}

编写完成之后在VScode终端中输入truffle compile查看是否可以编译成功

编写部署代码

const NFTAvatar = artifacts.require("NFTAvatar");

module.exports = function (deployer) {
  deployer.deploy(NFTAvatar, "NFTAvatar", "NFTA").then(function(instance) {
    // 铸造一个NFT
    return instance.mintNFT(
      deployer.networks.development.from, // 假设部署账户就是接收者
      "https://gateway.pinata.cloud/ipfs/QmQ5PzKzksKXxbht1Nh9dqfUcbShnUCZcjDSRC4wzxpdpG", // IMGURI
      "xxx(艺术家姓名)", // artist
      "这是一件由著名艺术家xxx创作的数字艺术作品。它具有独特的视觉表现力和深刻的艺术价值。", // description
      "2024-05-012" // creationDate
    );
  });
}

同样的在终端中输入truffle console --network development进入开发环境,truffle migrate部署智能合约

编写获取TokenID的代码文件

写这个文件的目的是 查看当前NFT代币的ID以及当前NFT所有者

const NFTAvatar = artifacts.require("NFTAvatar");

module.exports = function(callback) {
    // 使用 async 以便使用 await
    async function getOwner() {
        const instance = await NFTAvatar.deployed();
        const tokenId = await instance.currentTokenId();  // 使用 instance 获取当前 Token ID
        console.log("Current Token ID:", tokenId.toString());

        try {
            let owner = await instance.ownerOf(tokenId);
            console.log(`Owner of token ${tokenId} is: ${owner}`);
        } catch (error) {
            console.error(`Failed to fetch owner for token ${tokenId}: ${error}`);
        }
    }

    getOwner().then(callback);
};

编写安全转移NFT代币的代码文件

const NFTAvatar = artifacts.require("NFTAvatar");

module.exports = function(callback) {
    // 使用 async 以便使用 await
    async function getOwner() {
        const instance = await NFTAvatar.deployed();
        const tokenId = await instance.currentTokenId();  // 使用 instance 获取当前 Token ID
        console.log("Current Token ID:", tokenId.toString());

        try {
            let owner = await instance.ownerOf(tokenId);
            console.log(`Owner of token ${tokenId} is: ${owner}`);
        } catch (error) {
            console.error(`Failed to fetch owner for token ${tokenId}: ${error}`);
        }
    }

    getOwner().then(callback);
};

编写此文件以实现 将NFT代币转移到另一个账户的功能

编写HTML网页文件

编写此文件 以便我们在网页中查看

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>NFT Viewer</title>
</head>
<body>
    <h1>NFT Viewer</h1>
    <div id="tokenInfo"></div>
    <br>
    <div>
        <label for="ownerAddress">NFT Owner Address:</label>
        <input type="text" id="ownerAddress">
    </div><br>
    <div>
        <label for="transferAddress">Transfer Address:</label>
        <input type="text" id="transferAddress">
    </div><br>
    <button onclick="transferNFT()">Transfer NFT</button>

    <script src="https://cdn.jsdelivr.net/npm/web3@1.5.2/dist/web3.min.js"></script>
    <script>
        // 初始化 web3 实例
        const web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:7545"));

        // web3.eth.defaultAccount = "0x3c716f9ee390A4997a958c2818e15f59A94fCad1";

        // 定义合约地址和 ABI
        const contractAddress = '0xd1a9FB991fcFa782563437cD40911474F0F7591F'; // 替换为你的合约地址
        const contractABI = [
    {
      "inputs": [
        {
          "internalType": "string",
          "name": "name",
          "type": "string"
        },
        {
          "internalType": "string",
          "name": "symbol",
          "type": "string"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "constructor"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "approved",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "Approval",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "operator",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "bool",
          "name": "approved",
          "type": "bool"
        }
      ],
      "name": "ApprovalForAll",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "_fromTokenId",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "_toTokenId",
          "type": "uint256"
        }
      ],
      "name": "BatchMetadataUpdate",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "_tokenId",
          "type": "uint256"
        }
      ],
      "name": "MetadataUpdate",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "address",
          "name": "recipient",
          "type": "address"
        }
      ],
      "name": "NFTMinted",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "previousOwner",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "newOwner",
          "type": "address"
        }
      ],
      "name": "OwnershipTransferred",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "Transfer",
      "type": "event"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "approve",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "owner",
          "type": "address"
        }
      ],
      "name": "balanceOf",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "getApproved",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "owner",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "operator",
          "type": "address"
        }
      ],
      "name": "isApprovedForAll",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [],
      "name": "name",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [],
      "name": "owner",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "ownerOf",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [],
      "name": "renounceOwnership",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "safeTransferFrom",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        },
        {
          "internalType": "bytes",
          "name": "data",
          "type": "bytes"
        }
      ],
      "name": "safeTransferFrom",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "operator",
          "type": "address"
        },
        {
          "internalType": "bool",
          "name": "approved",
          "type": "bool"
        }
      ],
      "name": "setApprovalForAll",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "bytes4",
          "name": "interfaceId",
          "type": "bytes4"
        }
      ],
      "name": "supportsInterface",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [],
      "name": "symbol",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "tokenURI",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "transferFrom",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "newOwner",
          "type": "address"
        }
      ],
      "name": "transferOwnership",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "recipient",
          "type": "address"
        },
        {
          "internalType": "string",
          "name": "tokenURI",
          "type": "string"
        },
        {
          "internalType": "string",
          "name": "artist",
          "type": "string"
        },
        {
          "internalType": "string",
          "name": "description",
          "type": "string"
        },
        {
          "internalType": "string",
          "name": "creationDate",
          "type": "string"
        }
      ],
      "name": "mintNFT",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "currentTokenId",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "getArtist",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "getDescription",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "getCreationDate",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "getOwnerOfToken",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function",
      "constant": true
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "from",
          "type": "address"
        },
        {
          "internalType": "address",
          "name": "to",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "tokenId",
          "type": "uint256"
        }
      ],
      "name": "safeTransferNFT",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    }
  ];

        // 创建合约实例
        const contract = new web3.eth.Contract(contractABI, contractAddress);

        // 获取 NFT 的相关信息并显示在页面上
        async function displayTokenInfo() {
            try {
                const tokenId = await contract.methods.currentTokenId().call();
                const owner = await contract.methods.getOwnerOfToken(tokenId).call();

                // 设置默认发送者地址
                web3.eth.defaultAccount = owner;

                const artist = await contract.methods.getArtist(tokenId).call();
                const description = await contract.methods.getDescription(tokenId).call();
                const creationDate = await contract.methods.getCreationDate(tokenId).call();
                const tokenURI = await contract.methods.tokenURI(tokenId).call();

                document.getElementById('tokenInfo').innerHTML = `
                    <p>Token ID: ${tokenId}</p>
                    <p>NFT Owner: ${owner}</p>
                    <p>Artist: ${artist}</p>
                    <p>Description: ${description}</p>
                    <p>Creation Date: ${creationDate}</p>
                    <img src="${tokenURI}" style="max-width: 300px;">
                `;
            } catch (error) {
                console.error("Error fetching token info:", error);
            }
        }

        // 转移 NFT 资产的函数
        async function transferNFT() {

            const ownerAddress = document.getElementById('ownerAddress').value;
            const transferAddress = document.getElementById('transferAddress').value;

            try {
                const tokenId = await contract.methods.currentTokenId().call();
                await contract.methods.safeTransferNFT(ownerAddress, transferAddress, tokenId).send({ from: web3.eth.defaultAccount });
                alert('NFT successfully transferred.');
            } catch (error) {
                console.error("Error transferring NFT:", error);
                alert('Failed to transfer NFT.');
            }
        }

        // 页面加载时调用函数显示 NFT 的相关信息
        displayTokenInfo();
    </script>
</body>
</html>

注意:修改合约地址和ABI

合约地址需要在Gananche中点击上方的CONTRACTS然后点击中间的按钮
在这里插入图片描述
然后点击ADD PROJECT, 文件选择最开始修改的truffle-config.js文件 选择完成后点击RESTART保存
在这里插入图片描述
ABI在build目录下的NFTAvatar.json文件中
在这里插入图片描述

测试代码功能

在VScode中安装 live server插件,以便与实时预览静态网页和动态网站
安装完成之后就可以像下面这样打开网页了
在这里插入图片描述
以下就是打开的网页,可以查看到NFT的ID,所有者,作者,描述,甚至创建时间
同时还实现了转移NFT的功能
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值