因为公司需要搞NFT藏品,并且需要在opensea网站中显示出来。
opensea目前支持的链有下图所示的链,所以想显示在opensea中显示就必须上到下面所显示的链中才能
开发流程
拥有一个钱包 ------> 充值对应链的虚拟币 ------> 开发ERC-271合约 ------> 发布合约(保存好合约地址)------> 发布NFT ------> (发布成功后)打开opensea,通过钱包登录就可以在个人中心看到发布的NFT
1、拥有一个钱包
钱包市场上有很多个,我们常用的是“欧易”、“火币”、这些都方便买币和卖币,国外更加多,我选择“MetaMask”,没有其他的原因,是因为可以在谷歌浏览以插件的方式安装,并且可以查看钱包的私钥,私钥是关键,因为发布合约时需要。
至于买币还是在“欧易”、“火币”上购买吧,可以把“MetaMask”钱包导入到“欧易”、“火币”!
web3钱包是可以离线自己生成的,可以通过代码生成“钱包地址、钱包私钥”,每个钱包软件都通过私钥导入web3钱包。
2、充值对应链的虚拟币
每个链所用的虚拟币都是不一样的,以太坊用的是ETH,Polygon用的是MATIC,为什么一定要买对应的虚拟币呢?因为发布合约、发起交易都需要gas费用,这个gas费用收的币就是链用的虚拟币。智能合约发布和交易(即是修改数据的接口)需要收gas费用,读取接口不收gas费。
3、开发ERC-271合约
可以在网上看看别人写的复制过来,像我这样的新手可以直接用以太坊的例子:https://docs.openzeppelin.com/contracts/4.x/erc721,了解合约中的函数可以看看:https://learnblockchain.cn/article/4663
想方便在线开发查错和发布的,可以直接使用https://remix.ethereum.org,remix是常用的,也方便测试环境测试,也可以在发布到正式环境,使用方法可百度
4、发布合约(保存好合约地址)
为了方便,我目前都是在remix发布的
5、发布NFT
可以在remix发布的,但没有办法做到动态,所以我用PHP发布,gas费用这里我是调得很大了,可以再调小一些,如果gas费过小,会返回gas费过小或者发布的时间会很长。
composer require sc0vu/web3.php dev-master composer require digitaldonkey/ethereum-php dev-master composer require web3p/ethereum-tx dev-master
<?php namespace app\common\library; use app\common\library\Nftcontract; use Ethereum\Ethereum; use PhpOffice\PhpSpreadsheet\Writer\Ods\Content; use Web3\Web3; use Web3\Utils; use Web3\Contract; use Web3p\EthereumTx\Transaction; use Web3\Contracts\Ethabi; use Web3\Contracts\Types\Address; use Web3\Contracts\Types\Boolean; use Web3\Contracts\Types\Bytes; use Web3\Contracts\Types\DynamicBytes; use Web3\Contracts\Types\Integer; use Web3\Contracts\Types\IType; use Web3\Contracts\Types\Str; use Web3\Contracts\Types\Uinteger; use EthTool\Callback; /** * NFT接口 */ class Nft { protected $noNeedLogin = ['*']; protected $noNeedRight = ['*']; public $nonce; public $hash; public $abi; //合约ABI public $addr; //合约地址 public $chainId = 137; public $rpcurl = "https://rpc.ankr.com/polygon"; public $web3; public $eth; /** * 构造方法 * @access public */ public function __construct() { set_time_limit(0); $this->abi = Nftcontract::getAbi(); $this->addr = Nftcontract::getAddr(); //链接区块链内乡 try { $this->web3 = new Web3($this->rpcurl); $this->web3->clientVersion(function ($err, $version) { if ($err !== null) { //do something return; } if (isset($version)) { echo 'Client Version: ' . $version; } }); } catch (\Exception $e) { // $message = '获取发生异常的程序文件名称:'.$e->getFile().",出错行:" . $e->getLine().',详情:' . $e->getMessage(); die('web3 连接失败'); } // try{ // $this->eth = new Ethereum($this->rpcurl); // // echo '::::::::::::::::::Ethereum插件版本:'; // // echo $eth->eth_protocolVersion()->val(); // } catch (\Exception $exception) { // die('Ethereum 连接失败'); // } } /** * 铸造 * */ public function casting($form_address, $form_privatekey, $tokenURI) { try { //回调 $cb = new Callback; //帐号参数 $formaddress = $form_address; $privatekey = $form_privatekey; //合约读取数据 $contract = new Contract($this->web3->provider, $this->abi); //铸造 //获取NONCE $this->web3->getEth()->getTransactionCount($formaddress, 'pending', $cb); $nonce = (int)$cb->result->value; $ethabi = new Ethabi([ 'address' => new Address, 'bool' => new Boolean, 'bytes' => new Bytes, 'dynamicBytes' => new DynamicBytes, 'int' => new Integer, 'string' => new Str, 'uint' => new Uinteger, ]); //构建DATA $param_data = $ethabi->encodeParameters( ['address', 'string'], [$formaddress, $tokenURI] ); $param_data = Utils::stripZero($param_data); $method_id = $ethabi->encodeFunctionSignature("awardItem(address,string)"); $eth = $this->web3->eth; //使用web3发送交易 // dump($nonce); // 估算燃料费 // $contract->at($this->addr)->estimateGas("awardItem", $formaddress, $tokenURI, [ // 'from' => $formaddress, // 'gas' => '0x900b20' // ], $cb); $contract->at($this->addr)->estimateGas( "awardItem", $formaddress, $tokenURI, [ 'from' => $formaddress ], function ($err, $result) use (&$estimatedGas) { if ($err !== null) { throw $err; } // dump((int)$result->value); $gas = (int)$result->value; $estimatedGas = bcmul($gas, 2, 0); } ); $gas = '0x' . $estimatedGas; // $gas = (int)$cb->result->value; // $gas = bcmul($gas, 1.2, 0); // $gas = 19999000999999999999999999999999999999999; // dump($estimatedGas); $gasPrice = '0x' . Utils::toWei('5', 'gwei')->toHex(); //交易参数,设置燃料费 // $gasLimit = '0x' . dechex($gas); // $gasLimit = '0x200b20'; $Transaction_data = [ 'nonce' => '0x' . dechex($nonce), 'to' => $this->addr, 'gas' => $gas, 'gasPrice' => $gasPrice, 'gasLimit' => '0x' . $estimatedGas * 2, 'chainId' => $this->chainId, 'data' => $method_id . $param_data, ]; // dump($Transaction_data); //构建交易 $transaction = new Transaction($Transaction_data); //加密 $signedTransaction = $transaction->sign($privatekey); //私钥 // $txHash = ''; // $eth->sendRawTransaction('0x' . $transaction->serialize(), function ($err, $transaction) use ($eth, $formaddress, &$txHash) { // if ($err !== null) { // echo 'Error: ' . $err->getMessage(); // return; // } // echo 'Mint tx hash: ' . $transaction . PHP_EOL; // $txHash = $transaction; // }); // $transaction = confirmTx($eth, $txHash); // if (!$transaction) { // throw new \Error('Transaction was not confirmed.'); // } // exit; //发送交易 $eth->sendRawTransaction('0x' . $signedTransaction, $cb); return $cb->result; } catch (\Exception $e) { // dump($e->getTraceAsString()); $message = '获取发生异常的程序文件名称:' . $e->getFile() . ",出错行:" . $e->getLine() . ',详情:' . $e->getMessage(); dump($message); return false; } } /** * transferFrom * */ public function transferFrom($form_address, $form_privatekey, $to_address, $tokenId) { try { //回调 $cb = new Callback; //帐号参数 $formaddress = $form_address; $privatekey = $form_privatekey; //合约读取数据 $contract = new Contract($this->web3->provider, $this->abi); //铸造 //获取NONCE $this->web3->getEth()->getTransactionCount($formaddress, 'pending', $cb); $nonce = (int)$cb->result->value; $ethabi = new Ethabi([ 'address' => new Address, 'bool' => new Boolean, 'bytes' => new Bytes, 'dynamicBytes' => new DynamicBytes, 'int' => new Integer, 'string' => new Str, 'uint' => new Uinteger, ]); //构建DATA $param_data = $ethabi->encodeParameters( ['address', 'address', 'uint256'], [$formaddress, $to_address, $tokenId] ); $param_data = Utils::stripZero($param_data); $method_id = $ethabi->encodeFunctionSignature("transferFrom(address,address,uint256)"); $eth = $this->web3->eth; //使用web3发送交易 //估算燃料费 // $contract->at($this->addr)->estimateGas("transferFrom", $formaddress, $to_address, $tokenId, [ // 'from' => $formaddress, // 'gas' => '0x200b20' // ], $cb); $contract->at($this->addr)->estimateGas( "transferFrom", $formaddress, $to_address, $tokenId, [ 'from' => $formaddress ], function ($err,$result) use (&$estimatedGas) { if ($err !== null) { throw $err; } // dump((int)$result->value); $gas = (int)$result->value; $estimatedGas = bcmul($gas, 2, 0); } ); $gas = '0x' . $estimatedGas; // $gas = (int)$cb->result->value; // $gas = bcmul($gas, 1.2, 0); // $gas = 19999000999999999999999999999999999999999; // dump($estimatedGas); $gasPrice = '0x' . Utils::toWei('5', 'gwei')->toHex(); //交易参数,设置燃料费 // $gasLimit = '0x' . dechex($gas); // $gasLimit = '0x200b20'; $Transaction_data = [ 'nonce' => '0x' . dechex($nonce), 'to' => $this->addr, 'gas' => $gas, 'gasPrice' => $gasPrice, 'gasLimit' => '0x' . $estimatedGas * 2, 'chainId' => $this->chainId, 'data' => $method_id . $param_data, ]; // $gas = (int)$cb->result->value; // $gas = bcmul($gas, 1.2, 0); //交易参数,设置燃料费 // $gasLimit = '0x' . dechex($gas); //构建交易 $transaction = new Transaction($Transaction_data); //加密 $signedTransaction = $transaction->sign($privatekey); //私钥 //发送交易 $eth->sendRawTransaction('0x' . $signedTransaction, $cb); return $cb->result; } catch (\Exception $e) { return false; } } //查询交易 public function getTransactionByHash($hash) { //回调 $cb = new Callback; //HASH查询 $eth = $this->web3->eth; //交易查询 $eth->getTransactionByHash($hash, $cb); return $cb->result; } //查询详细交易 public function getTransactionReceipt($hash) { //回调 $cb = new Callback; //HASH查询 $eth = $this->web3->eth; //交易查询 $eth->getTransactionReceipt($hash, $cb); return $cb->result; } //获取图片地址,通过token_id public function tokenURI($token_id) { $contract = new Contract($this->rpcurl, $this->abi); $callback = new Callback(); $contract->at($this->addr)->call('tokenURI', $token_id, $callback); return $callback->result; } //获取NFT拥有者,通过token_id public function ownerOf($token_id) { $contract = new Contract($this->rpcurl, $this->abi); $callback = new Callback(); $contract->at($this->addr)->call('ownerOf', $token_id, $callback); return $callback->result; } //获取owner地址代币数量 public function balanceOf($owner) { $contract = new Contract($this->rpcurl, $this->abi); $callback = new Callback(); $contract->at($this->addr)->call('balanceOf', $owner, $callback); return $callback->result; } // 获取token的授权者地址 public function getApproved($token_id) { $contract = new Contract($this->rpcurl, $this->abi); $callback = new Callback(); $contract->at($this->addr)->call('getApproved', $token_id, $callback); return $callback->result; } //判断 owner是否授权给operate public function isApprovedForAll($owner, $operator) { $contract = new Contract($this->rpcurl, $this->abi); $callback = new Callback(); $contract->at($this->addr)->call('isApprovedForAll', $owner, $operator, $callback); return $callback->result; } // 获取代币标识 public function symbol() { $contract = new Contract($this->rpcurl, $this->abi); $callback = new Callback(); $contract->at($this->addr)->call('symbol', '', $callback); return $callback->result; } // 获取代币名称 public function name() { $contract = new Contract($this->rpcurl, $this->abi); $callback = new Callback(); $contract->at($this->addr)->call('name', '', $callback); return $callback->result; } }
标签:cb,gas,第一次,callback,contract,NFT,result,new,心得 From: https://www.cnblogs.com/zhangzhijian/p/16941906.html