创建文章

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Solution Thumbnail

使用.net在Algorand区块链上进行NFT开发

简介

本解决方案的视频版请参照:https://www.bilibili.com/video/BV1s54y1h7oB/

最近NFT越来越流行了。如果你是一个区块链的爱好者或者从业人员连NFT是什么都不知道,那你是真的落伍了。那么在Algorand区块链上能否进行NFT的开发呢?今天我们就来探讨一下这个问题。

一、基本概念

但为了使所有读者都能更好的理解此解决方案,我先介绍一下什么是NFT。

我先举一个例子。小明是一个杀猪的,他赚了100块钱。而我呢,我是一名工程师,也赚了100块钱。那么小明的这100块钱和我的这100块钱有没有什么区别呢?绝大多数情况下,这两个100块钱是完全没有任何区别的。这种情况就叫做同质化货币。但是有一些东西就不大一样。比方说我家的一只小狗和小明家的一只小狗,即使品种一样,然后长得也差不多,但是我们还是不愿意互换。这两者之间是有很大区别的,我们可以说在世界上没有两只相同的小狗。这种情况下我们叫非同质化代币(Non-Fungible Token),也就是NFT。说白了NFT是一种代币,但每一个NFT拥有独特且唯一的标识,两两不可互换,最小单位是1且不可分割。

NFT的用处还是非常广泛的,例如在游戏中,我们可以把装备设计的更具各性化,并让玩家真正的“拥有”这件装备,那么此时最好的做法就是将这件装备设计成NFT。再比如说数字产品的知识产权保护:数字产品虽然可以复制,但数字产品的创作者是其唯一的拥有者,而且拥有者也是可以转让的。这些情景都非常适合使用NFT对其进行数字化。

我们都知道algorand是实现了标准化资产(ASA)的,那么algorand里面有没有实现NFT呢?实际上是没有的,但我们可以通过一定手段实现类似于NFT的代币。下面就让我们一起使用dotnet-algorand-sdk来实现一个NFT代币并进行一些相关操作吧。

二、NFT设计概述

Algorand是支持智能合约的,所以你当然可以使用智能合约来实现NFT。但我们也可以根据algorand的系统中已经设计好的ASA来加以改造,来生成更加安全、稳定的NFT类代币。

图一:Algorand区块连中ASA与NFT特征的相关性

图一:Algorand区块连中ASA与NFT特征的相关性

我们可以把NFT当作一个总数量为1且不可再分的代币,这样ASA就有了唯一性。

对于现在非常流行的数字艺术品的应用,我们可以再对ASA稍加改进,使之能够存储相关的电子文件。电子文件的存储与需要配合IPFS系统完成的,具体做法如下:

  1. 生成文件(通常为图片)

  2. 上传到IPFS中(返回32字节的hash)

  3. 将Hash写入到 MetaDataHash 字段(由于Algorand设计的限制,其实这里只使用了步骤2中hash的前24个字节)

  4. 将IPFS地址写入到URL字段(由于Algorand设计限制,URL长度只能在32字节以内,所以这里可能需要使用地址缩短的服务)

  5. 生成NFT

NFT生成需要注意的问题:

  1. NFT真伪鉴别。在以太坊网络中,一种ERC721代币可以生成若干个NFT代币,我们也可以根据这种代币的合约地址来判别一个NFT代币是否为“真币”。比方说,一副名家画作在以太坊中的电子拷贝被制作成了一个NFT,那么我们可以通过辨认其智能合约地址来判断是不是“真品”。而在Algorand中,并没有合约地址这一说,与之功能基本类似的是Asset ID。在Algorand区块链中,你只能通过Asset ID来判断一个NFT的真伪。任何人都可以发布相同名字、缩写、MeatdataHash及URL都相同的代币,甚至一个账号也可以创建多个任何信息(除了Asset ID)都相同的NFT。

  2. 在Algorand网络中,一个账号想要接收一种ASA,必须进行Opt In操作。而每一枚NFT其实都是一种ASA资产。这就造成了一个问题,那就是一个用户在接收一个NFT之前,必须对这种资产进行Opt In操作。

毕竟ASA在设计之初并没有考虑到NFT的问题,所以使用ASA来实现NFT功能时难免会出现各种问题。如果大家发现新的问题或者更有趣的解决方案,请随时与我讨论。

三、程序设计概述

为了便于大家使用,本文会设计一个简单的应用程序,实现NFT的生成、Opt In、转移、查询NFT相关属性等操作。为了简单起见,将程序设计成无界面的命令行行式,具体功能描述如下:

  1. 根据输入的相关参数生成NFT。

  2. Opt In NFT代币

  3. 查询账号持有的NFT(根据创建者)

  4. 查询具体NFT的详细信息

  5. NFT转账

使用界面如下:

图二:程序界面

图二、程序界面

关于软件更具体的使用方法,会在本解决方案的第五节:操作模拟中进行更详细的介绍。

四、NFT相关操作

本章讲述有关NFT相关操作的代码。从本质上讲,NFT是一种ASA,所以如果大家有学习过之前的教程《使用.net进行Algorand开发系列教程之ASA转账》和《使用.net进行Algorand开发系列教程之ASA的创建及管理》,那么大家会对后面的操作非常熟悉。后面主要讲述了NFT的创建、NFT的Opt In及NFT转账。

4.1 NTF的创建

NFT是一种有特定特征的ASA,所以NFT的创建与ASA的创建大同小异,主要代码如下:

static long? CreateNFT(string nftName, string nftUrl, string metadataHash)
{
  if(act.Address.ToString() != reliableAddress)
  {

    Console.WriteLine("只有可信赖的地址生成的NFT会被本程序识别!");
    return 0;
  }

  var transParams = algodApiInstance.TransactionParams();

  // Create the Asset
  // Total number of this asset available for circulation
  //var ap = new AssetParams(creator: act.Address.ToString(), name: nftName, unitName: "NFT", total: 1,
  //  decimals: 0, url: nftUrl, metadataHash: Encoding.ASCII.GetBytes(metadataHash))

  var ap = new AssetParams(creator: act.Address.ToString(), name: nftName, unitName: "NFT", total: 1, decimals: 0, url: nftUrl, 
    metadataHash: Encoding.ASCII.GetBytes(StrToHexByte(metadataHash.Substring(0, 48))));

  var tx = Utils.GetCreateAssetTransaction(ap, transParams, "NFT creation transaction");

  // Sign the Transaction by sender
  SignedTransaction signedTx = act.SignTransaction(tx);

  // send the transaction to the network and
  // wait for the transaction to be confirmed
  long? assetID = 0;
  try
  {
    var id = Utils.SubmitTransaction(algodApiInstance, signedTx);
    Console.WriteLine("Transaction ID: " + id);
    Console.WriteLine("Confirmed Round is: " +
      Utils.WaitTransactionToComplete(algodApiInstance, id.TxId).ConfirmedRound);

    // Now that the transaction is confirmed we can get the assetID
    var ptx = algodApiInstance.PendingTransactionInformation(id.TxId);
    assetID = ptx.AssetIndex;
  }
  catch (Exception e)
  {
    Console.WriteLine(e.StackTrace);
    return 0;
  }

  Console.WriteLine("AssetID = " + assetID);
  // now the asset already created
  return assetID;
}

4.2 NFT的Opt In操作

static void OptInNFT(long? assetID)
{
  var transParams = algodApiInstance.TransactionParams();   
  var tx = Utils.GetAssetOptingInTransaction(act.Address, assetID, transParams, "opt in transaction"); 
  var signedTx = act.SignTransaction(tx);

  try
  {
    var id = Utils.SubmitTransaction(algodApiInstance, signedTx);
    Console.WriteLine("Transaction ID: " + id.TxId);
    Console.WriteLine("Confirmed Round is: " +
      Utils.WaitTransactionToComplete(algodApiInstance, id.TxId).ConfirmedRound);

    // We can now list the account information for acct3 
    // and see that it can accept the new asseet
    var actInfo = algodApiInstance.AccountInformation(act.Address.ToString());
    Console.WriteLine(actInfo);
  }
  catch (Exception e)
  {
    Console.WriteLine(e.Message);
    return;
  }
}

4.3 NFT转账

private static void TransferNFT(long? aid, string desAddress)
{
  var transParams = algodApiInstance.TransactionParams();
  ulong assetAmount = 1;
  var tx = Utils.GetTransferAssetTransaction(act.Address, new Address(desAddress), aid, assetAmount, transParams, null, "transfer message");

  var signedTx = act.SignTransaction(tx);
  try
  {
    var id = Utils.SubmitTransaction(algodApiInstance, signedTx);
    Console.WriteLine("Transaction ID: " + id.TxId);
    Console.WriteLine("Confirmed Round is: " +
      Utils.WaitTransactionToComplete(algodApiInstance, id.TxId).ConfirmedRound);
  }
  catch (Exception e)
  {
    //e.printStackTrace();
    Console.WriteLine(e.Message);
    return;
  }
}

注:以上的代码片断是无法独立运行的,只是作为程序的一部分完成相应的操作。如果你需要完整的代码,请参照https://github.com/RileyGe/algorand-nft

五、操作模拟

经过上面的编码工作,现在我们已经初步有了一个可以运行的基于Algorand的NFT操作软件了,下面以act1和act2两个用户来进行相关操作,并记录相关过程:

act1信息:

账号地址:7XVBE6T6FMUR6TI2XGSVSOPJHKQE2SDVPMFA3QUZNWM7IY6D4K2L23ZN2A

账号助记词:spray daughter bar job flush vessel yellow galaxy below neutral they elbow cereal short can crime resource depend social history enact merge lesson abstract brick

act2信息:

账号地址:AJNNFQN7DSR7QEY766V7JDG35OPM53ZSNF7CU264AWOOUGSZBMLMSKCRIU

账号助记词:place blouse sad pigeon wing warrior wild script problem team blouse camp soldier breeze twist mother vanish public glass code arrow execute convince ability there

操作模拟的具体流程如下:

图三:操作模拟的具体流程

图三、操作模拟的具体流程

首先需要打开程序,程序后面紧跟两个变量,分别表示Algorand区块链的接入点和秘钥。大家可以自建节点,也可以使用Algorand的BSN服务,但要注意purestake的服务部分功能不可用。

后续需要根据提示输入助记词来解锁账号(注,这里只是演示用,在实际生产环境中需要更好的保存助记词)。

图四:act1创建NFT

图四:act1创建NFT

该操作的详细结果可以参照Algorand浏览器:https://testnet.algoexplorer.io/tx/3QN4NK6DVTTUDQGD6KTPGVGOON3RPJ4GKJQKXN66ZUEVHRKXDEUQ

之后就可以进行NFT的查询。查询是按照以下规则进行的:

  1. 资产的创建者为act1

  2. 资产的UnitName为NFT

  3. 资产的总量为1

  4. 资产不可分

满足上面4个条件就被认为是NFT,查询结果如下:

图五:act1查询NFT列表

图五:act1查询NFT列表

对于每一个NFT都可以查看其详细信息:

图六:查询NFT的详细信息

图六:查询NFT的详细信息

在进行act2的操作时必须重新打开一个命令行(之前的命令行不需要关闭),然后根据提示输入act2的助记词,Opt In的界面如下:

图七:act2的Opt_In操作

图七:act2的Opt In操作

在act2进行了Opt In操作之后,act1就可以将自己有的NFT发送给act2了,操作界面如下:

图八:act1向act2进行NFT转账

图八:act1向act2进行NFT转账

转账操作的详细信息可以参照:https://testnet.algoexplorer.io/tx/BO7VRN3TVCQ424N75JCZAXENPDBQD3GZD3R6S5GQLHSUUCEZULSQ

转账后act2就拥有了NFT,act2进行查询的操作界面如下:

图九:act1的NFT资产列表

图九:act1的NFT资产列表

图十:act2查询NFT的详细信息

图十:act2查询NFT的详细信息

上述操作涵盖了NFT的一些基本操作,大家可以根据自己实际需求定制更加复杂的操作。

六、总结

本文主要阐述了如何应用 Algorand 区块链来构建NFT代币,并在自己的Dapp中使用NFT代币。

Algorand 区块链的NFT代币基于其标准资产ASA,继承了ASA的易用性与安全性。我们只需要少量的代码就可以构建出一个NFT资产。但同时也由于ASA并没有专门为NFT进行设计,所以基于Algorand区块链标准资产的NFT也有其局限性:如每个账户要进行NFT资产接收之前都要进行Opt In操作、代币中可存储的信息量不足(如无法保存原url地址等)等。

即使存在以上问题,我们仍然可以基于Algorand区块链构建NFT并进行更多创造性的工作。本文只是一个引子,希望能抛砖引玉,引出更多更好的应用。