blockchain - truffle - 创建erc-721 create nft call contract
访问量: 124
refer to:
(本参考这个)
https://docs.infura.io/infura/tutorials/layer-2-networks/using-aurora-to-deploy-an-ethereum-smart-contract
(其实这个也很有用,从标题来看,我还没细看)
https://docs.infura.io/infura/tutorials/ethereum/create-an-nft-using-truffle
1. mkdir test_erc_721
2. truffle init
3. 编辑truffle-config.js 内容如下:
$ cat truffle-config.js
require('dotenv').config();
const HDWalletProvider = require('@truffle/hdwallet-provider');
const { INFURA_API_URL, MNEMONIC } = process.env;
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*"
},
goerli: {
provider: () => new HDWalletProvider(MNEMONIC, INFURA_API_URL),
network_id: '5',
gas: 5500000,
networkCheckTimeout: 1000000,
timeoutBlocks: 200,
addressIndex: 2
}
},
// 注意这个版本,很有用
compilers: {
solc: {
version: "^0.8.0",
}
}
};
4. npm install @openzeppelin/contracts
5. npm install --save dotenv
6. 在contracts 目录下,创建 MyTestNft.sol 内容如下 :
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyTestNft is ERC721URIStorage {
uint256 private _tokensCount = 0;
address public minter = address(0);
modifier onlyMinter(){
require(
minter == msg.sender,
'Invalid Minter'
);
_;
}
constructor() ERC721("MyTestNft", "MTN") {
minter = msg.sender;
}
function mint(address to) external onlyMinter {
uint256 tokenId = _tokensCount + 1;
_mint(to, tokenId);
_tokensCount = tokenId;
}
function burn(uint256 tokenId) external {
_burn(tokenId);
_tokensCount -= 1;
}
function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
require(minter == msg.sender || to == minter, 'Invalid Transfer');
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public virtual override {
require(minter == msg.sender || to == minter, 'Invalid Transfer');
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
}
6.2 并且创建对应的migration文件:$ vim migrations/2_deploy_contracts.js
内容如下:const MyTestNft = artifacts.require('MyTestNft.sol');
module.exports = function(deployer) {
deployer.deploy(MyTestNft);
}
7. 运行:$ truffle migrate --network goerli --verbose-rpc --interactive
Starting migrations... ====================== > Network name: 'goerli' > Network id: 5 > Block gas limit: 29970676 (0x1c950f4) 1_initial_migration.js ====================== Deploying 'Migrations' ---------------------- > transaction hash: 0x90efe7d70f5ba7c5164cbf59f2afa41360662818ceedab9ea27972a62f0bc697 > Blocks: 0 Seconds: 4 > contract address: 0xeA2Cb7c1E9574B158350fAE01202ED47A32cfCf8 > block number: 7082520 > block timestamp: 1655593578 > account: 0xc0dD5021e298dB57bEF361C735cd1C04cef2E48A > balance: 7.466584663503196232 > gas used: 193243 (0x2f2db) > gas price: 2.500000007 gwei > value sent: 0 ETH > total cost: 0.000483107501352701 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.000483107501352701 ETH 2_deploy_contracts.js ===================== Deploying 'MyTestNft' --------------------- > transaction hash: 0xb8231f2ebc2a55ca10a0635cb7c41fa954cf942ab62858a6bf42a86dcc17dd72 > Blocks: 1 Seconds: 24 > contract address: 0x81Ec27587694f9996a69dc26230643dD619cfaba > block number: 7082523 > block timestamp: 1655593623 > account: 0xc0dD5021e298dB57bEF361C735cd1C04cef2E48A > balance: 7.459741808484036238 > gas used: 2691404 (0x29114c) > gas price: 2.500000007 gwei > value sent: 0 ETH > total cost: 0.006728510018839828 ETH > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.006728510018839828 ETH Summary ======= > Total deployments: 2 > Final cost: 0.007211617520192529 ETH
8. 对该NFT的 contract verify
我们看到目标contract已经部署到了eth goerli网络上,先一步进行verify (为了方便我们使用remix 进行调试)
这里不能简单的使用 ether 提供的GUI进行verify, 因为无论是 json 文件还是多个sol文件,都不行
我另外写了一个文章,在这里: http://siwei.me/blog/posts/blockchain-truffle-nft-erc-721-contract-verify
8. 对该NFT的调用
8.1 mint 一个nft
8.2 查询该nft owner
8.3 转移给其他人
8.4 查询该nft owner
8.5 mint一个nft
8.6 销毁之
8.7 根据owner, 查看balance
8.8 根据nft id , 查看owner
运行下面代码即可:
const Web3 = require('web3')
const fs = require('fs')
async function main(file_name_without_suffix, contract_address){
const { abi } = JSON.parse(fs.readFileSync("build/contracts/" +file_name_without_suffix+'.json'))
// step1. 初始化web3 实例,增加json rpc server
const web3 = new Web3(
new Web3.providers.HttpProvider( 'HTTP://192.168.10.54:3355')
)
let private_key = "5da76275302d9b9fb14240871db41bfbd9ff08362150c0a8b24f0fd69e??????"
// step2. 创建signer
const signer = web3.eth.accounts.privateKeyToAccount(private_key)
web3.eth.accounts.wallet.add(signer)
// step3. 创建contract, abi是关键
const contract = new web3.eth.Contract(abi, contract_address)
let result = ''
result = await contract.methods.minter().call()
console.info("minter: ", result)
result = await contract.methods.name().call()
console.info("name: ", result)
result = await contract.methods.symbol().call()
console.info("symbol: ", result)
let target_address = '0xDEC781c67a86570c004c7840BE1AddAF51C39487'
let tx = ''
tx = await contract.methods.mint(target_address)
let from = signer.address
console.info("== now let's mine one: ,from: ", from)
result = await tx
.send({from: from, gas: await tx.estimateGas()})
.once("transactionHash" , (txHash) => {
console.info("mining transaction...", txHash)
})
.on('error', (error) => {
console.info("--- on error: ", error)
})
console.info("mint result: ", result)
result = await contract.methods.balanceOf(target_address).call()
console.info(`balance of ${target_address}: `, result)
result = await contract.methods.ownerOf(1).call()
console.info("ownerOf n: ", result)
tx = await contract.methods.burn(1)
result = await tx
.send({from: from, gas: await tx.estimateGas()})
.once("transactionHash", (txHash) => {
console.info("burning id: ", 1)
})
console.info(" burn result: ", result)
}
console.info("== 使用方式: $ node call.js TestContract 0xa1b2..z9 (该TestContract.json 和 必须存在)")
main(process.argv[2], process.argv[3]).then( () => process.exit(0) )