美文网首页NEO 开发
用 NEO 智能合约实现 NFT

用 NEO 智能合约实现 NFT

作者: ZhangHQ | 来源:发表于2018-12-08 15:28 被阅读0次

    用 NEO 智能合约实现 NFT

    NFT 是什么

    NFT(Non-Fungible Token)即非同质化代币,我们经常接触的数字货币 BTC、ETH 等都可以称为同质化代币,因为每个 BTC 都是一样的,价值和属性都一样;如果我们想用数字货币做更多事情,比如货币功能以外的资产登记、权证记录等,这时候需要的每一份“资产”都是独一无二的,它可以有自己的属性,可以单独修改,因此便有了NFT 的概念,即非同质化代币。

    这里就讲讲如何在 NEO 区块链上使用智能合约实现 NFT。

    需求

    实现一套会员系统,成为会员后可以拥有一个 NFT 的证书,每个证书有唯一的编号标识,该证书可以记录会员的贡献值,贡献值达到一定数值可以进行升级,证书还可以转让出去,卖出后新的拥有者会享有证书附带的特权。

    实现

    设计合约时,可以按这个思路出发:从需求中提取合约要实现的功能,由功能来决定合约要提供的接口,然后细化每个接口的实现思路和权限等。

    根据前面描述的需求,我们的证书合约需要具备发行证书、给证书加积分、证书升级、转卖证书的功能,由此可以得出合约要实现的接口:

    • 发行/购买证书:Deploy
    • 给证书加积分:AddPoint
    • 证书升级:Upgrade
    • 转卖证书:Exchange

    除了以上基本功能外,我们还需要一些辅助功能,比如查询某个账户上有没有证书;所拥有的证书有多少积分,等级是多少;已经发行了多少个证书等:

    • 查询证书信息:GetNftInfo
    • 查询发行的数量:GetNftCount
    • 查询转卖信息:GetTxInfo

    有了以上的设计,基本思路和实现方案已经清楚了,接下来就要开发合约了,开发前的配置准备工作可以参考 NEO 的智能合约开发文档。各接口实现代码和说明如下:

     public class NFT : SmartContract
        {
    
            public static object Main(string method, object[] args)
            {
                var magicstr = "NFT";
                if (Runtime.Trigger == TriggerType.Verification)
                {
                    return false;
                }
                else if (Runtime.Trigger == TriggerType.VerificationR)
                {
                    return true;
                }
                else if (Runtime.Trigger == TriggerType.Application)
                {
                    //入口处取到调用脚本
                    var callscript = ExecutionEngine.CallingScriptHash;
    
                    //传入address获取nft信息
                    if (method == "GetNftInfo")
                    {
                        byte[] address = (byte[]) args[0];
                        if (address.Length == 0) return false;
                        StorageMap addressMap = Storage.CurrentContext.CreateMap("addressMap");
                        byte[] tokenId = addressMap.Get(address);
                        if (tokenId.Length == 0) return false;
                        return GetNftByTokenId(tokenId);
                    }
    
                    //传入txid 获取nft交易信息
                    if (method == "GetTxInfo")
                    {
                        byte[] txid = (byte[]) args[0];
                        if (txid.Length == 0) return false;
                        return GetTxInfoByTxid(txid);
                    }
    
                    //获取已发行的nft数量
                    if (method == "GetNftCount")
                    {
                        StorageMap nftCountMap = Storage.CurrentContext.CreateMap("nftCountMap");
                        return nftCountMap.Get("nftCount").AsBigInteger();
                    }
    
                    //给一个address发行nft
                    if (method == "Deploy")
                    {
                        byte[] address = (byte[]) args[0];
                        if (address.Length == 0) return false;
                        StorageMap addressMap = Storage.CurrentContext.CreateMap("addressMap");
                        //用当前交易的交易二次hash作为nft的id
                        var tokenId = Hash256((ExecutionEngine.ScriptContainer as Transaction).Hash);
                        var newNftInfo = CreateNft(address, tokenId);
                        if (SaveNftInfo(newNftInfo))
                        {
                            addressMap.Put(address, tokenId);
                            AddNftCount();
                            SetTxInfo(null, address, tokenId);
                            return true;
                        }
    
                        return false;
                    }
    
                    //转手交易
                    if (method == "Exchange")
                    {
                        byte[] from = (byte[]) args[0];
                        byte[] to = (byte[]) args[1];
                        if (from.Length == 0 || to.Length == 0)
                            return false;
                        StorageMap addressMap = Storage.CurrentContext.CreateMap("addressMap");
                        byte[] toTokenId = addressMap.Get(to);
                        byte[] fromTokenId = addressMap.Get(from);
                        var fromNftInfo = GetNftByTokenId(fromTokenId);
                        fromNftInfo.Owner = to;
                        if (SaveNftInfo(fromNftInfo))
                        {
                            addressMap.Delete(from);
                            addressMap.Put(to, fromTokenId);
                            SetTxInfo(from, to, fromTokenId);
                            return true;
                        }
    
                        return false;
                    }
    
                    //升级
                    if (method == "Upgrade")
                    {
                        byte[] address = (byte[]) args[0];
                        StorageMap addressMap = Storage.CurrentContext.CreateMap("addressMap");
                        byte[] tokenId = addressMap.Get(address);
                        if (tokenId.Length == 0) return false;
                        var nftInfo = GetNftByTokenId(tokenId);
                        nftInfo.Rank += 1;
                        SaveNftInfo(nftInfo);
                        return true;
                    }
    
                    //加分
                    if (method == "AddPoint")
                    {
                        byte[] address = (byte[]) args[0];
                        BigInteger pointValue = (BigInteger) args[1];
                        if (address.Length == 0) return false;
                        StorageMap addressMap = Storage.CurrentContext.CreateMap("addressMap");
                        byte[] tokenId = addressMap.Get(address);
                        if (tokenId.Length == 0) return false;
                        var nftInfo = GetNftByTokenId(tokenId);
                        nftInfo.Point += pointValue;
                        if (SaveNftInfo(nftInfo))
                            return true;
                        return false;
                    }
                }
    
                return false;
            }
            
            //new一个新nft
            public static NFTInfo CreateNft(byte[] owner, byte[] tokenId)
            {
                var nftInfo = new NFTInfo();
                nftInfo.TokenId = tokenId;
                nftInfo.Owner = owner;
                nftInfo.Point= 0;
                nftInfo.Rank = 1;
                return nftInfo;
            }
    
            //增加已发行的数量
            public static void AddNftCount()
            {
                StorageMap nftCountMap = Storage.CurrentContext.CreateMap("nftCountMap");
                var oldCount = nftCountMap.Get("nftCount").AsBigInteger();
                nftCountMap.Put("nftCount", oldCount + 1);
            }
    
            //保存nft信息
            public static bool SaveNftInfo(NFTInfo nftInfo)
            {
                StorageMap userNftInfoMap = Storage.CurrentContext.CreateMap("userNftInfoMap");
                byte[] nftInfoBytes = Helper.Serialize(nftInfo);
                userNftInfoMap.Put(nftInfo.TokenId, nftInfoBytes);
                return true;
            }
    
            //传入TokenID获得nft信息
            public static NFTInfo GetNftByTokenId(byte[] tokenId)
            {
                StorageMap userNftInfoMap = Storage.CurrentContext.CreateMap("userNftInfoMap");
                byte[] data = userNftInfoMap.Get(tokenId);
                var nftInfo = new NFTInfo();
                if (data.Length > 0)
                    nftInfo = data.Deserialize() as NFTInfo;
                return nftInfo;
            }
    
            //保存交易信息
            public static void SetTxInfo(byte[] from, byte[] to, byte[] tokenId)
            {
                ExchangeInfo info = new ExchangeInfo();
                info.@from = from;
                info.to = to;
                info.tokenId = tokenId;
                byte[] exInfo = Neo.SmartContract.Framework.Helper.Serialize(info);
                //当前执行的ScriptContainer的Transaction Hash作为txid
                var txid = (ExecutionEngine.ScriptContainer as Transaction).Hash;
                StorageMap ExchangeInfoMap = Storage.CurrentContext.CreateMap("txInfoMap");
                ExchangeInfoMap.Put(txid, exInfo);
            }
    
            //通过txid获取交易信息
            public static ExchangeInfo GetTxInfoByTxid(byte[] txid)
            {
                ExchangeInfo info = new ExchangeInfo();
                StorageMap ExchangeInfoMap = Storage.CurrentContext.CreateMap("txInfoMap");
                var data = ExchangeInfoMap.Get(txid);
                if (data.Length > 0)
                    info = data.Deserialize() as ExchangeInfo;
                return info;
            }
    
        }
    
        //交易信息
        public class ExchangeInfo
        {
            public byte[] from;
            public byte[] to;
            public byte[] tokenId;
        }
    
        //证书信息
        public class NFTInfo
        {
            public byte[] TokenId; //tokenid 证书ID
            public byte[] Owner; //所有者 address
            public BigInteger Rank; //等级
            public BigInteger Point; //积分值
        }
    
    

    这样就实现了我们前面设计的接口,使用时编译发布合约到 NEO 网络上就可以了。

    本文主要介绍如何结合 NEO 智能合约实现一个 NFT 合约以及开发 NEO 智能合约的基本思路和技术,省略了许多检查的部分,实际使用中我们可以结合需求来随意扩展,比如限制等级,控制数量,付费购买检查等。这里是一个更标准化的 NFT 合约实现:NFT Contract

    相关文章

      网友评论

        本文标题:用 NEO 智能合约实现 NFT

        本文链接:https://www.haomeiwen.com/subject/nauqhqtx.html