首页 > 其他分享 >第一次搞NFT的心得

第一次搞NFT的心得

时间:2022-12-01 16:59:01浏览次数:34  
标签:cb gas 第一次 callback contract NFT result new 心得

因为公司需要搞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

相关文章