锁仓合约示例
锁仓合约实现一个这样的功能:指定一个时间戳(timestamp),在区块链系统的时间到达该指定的时间之前,任何人也不能从该合约中将资金取出,到达指定的时间后,合约持有者可以将资金取出。
代码中通过区块链中最新区块的时间来获得当前时间(误差大约在 15 秒以内)。详情可参考 Blockchain 类 , Header 类 。
该合约可以部署到区块链上供其他人调用。本文将介绍如何在钱包中部署一个锁仓合约。
创建钱包
-
在 Neo-GUI 客户端中,点击
钱包
->创建钱包数据库
,创建一个钱包。 -
右键单击钱包中的账户地址,选择
查看私钥
,将显示的公钥复制。
获得公钥的字节数组
下面我们写一个本地程序,把公钥转成字节数组,C# 代码如下:
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
// 这里替换为上一步复制的公钥
byte[] b = HexToBytes("0285eab65f4a0126e4b85b4e5d8b7e303aff7efb360d595f2e3189bb90487ad5aa");
foreach (var item in b)
{
Console.Write($"{item}, ");
}
Console.ReadLine();
}
static byte[] HexToBytes(string hexString)
{
hexString = hexString.Trim();
byte[] returnBytes = new byte[hexString.Length / 2];
for (int i = 0; i < returnBytes.Length; i++)
{
returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
}
return returnBytes;
}
}
}
运行后,会在屏幕中输出公钥的 byte 数组,将其复制下来,下一步会用到。
编写锁仓合约
在 Visual Studio 中创建智能合约项目,编写如下的智能合约。
using Neo.SmartContract.Framework.Services.Neo;
namespace Neo.SmartContract
{
public class Lock : Framework.SmartContract
{
public static bool Main(uint timestamp, byte[] pubkey, byte[] signature)
{
Header header = Blockchain.GetHeader(Blockchain.GetHeight());
if (header.Timestamp < 1588327800) // 2020-5-1 18:10
return false;
// 这里粘贴上一步复制的公钥字节数组
return VerifySignature(signature, new byte[] { 2, 133, 234, 182, 95, 74, 1, 38, 228, 184, 91, 78, 93, 139, 126, 48, 58, 255, 126, 251, 54, 13, 89, 95, 46, 49, 137, 187, 144, 72, 122, 213, 170 });
}
}
}
以上代码有两个地方需要修改:
-
在合约代码中粘贴上一步复制的公钥字节数组
-
更改示例代码中的锁仓时间,该时间为 Unix 时间戳。此时间戳可以自己写代码计算出来,也可以直接在网上查询 Unix 时间戳在线转换 。
替换好以上两个地方后编译合约,生成文件 Lock.avm 。
获取合约脚本
可以选择以下一种方法获取合约脚本:
-
使用如下的 C# 代码读取 .avm 文件:
byte[] bytes = System.IO.File.ReadAllBytes("Lock.avm"); for (int i = 0; i < bytes.Length; i++) Console.Write(bytes[i].ToString("x2"));
-
使用 Neo-GUI 客户端获取:
-
在客户端中点击
高级
->部署合约
-
在右下角点击
加载
,选择编译后的 .avm 文件 -
在
代码
框显示出合约脚本,将其复制备用。
-
创建合约地址
-
在Neo-GUI中点击鼠标右键 ->
创建合约地址
->自定义
,使用上一步生成的合约脚本创建合约地址。 -
在
导入自定义合约
对话框中设置以下选项:a. 形参列表:参考 智能合约参数和返回值 ,由于我们的合约中有一个 signature 参数,所以此处要填写 00 。
b. 脚本代码:填写上一步复制的合约脚本代码。
c. 私钥:可选参数,当合约执行过程中需要签名时,设置用于签名的私钥。
测试
下面就可以对刚创建的合约账户进行测试,在Neo-GUI中点击 交易
-> 转账
向合约账户转入一笔资产,再将其转出。
为了保证测试的准确性,钱包中的标准账户里最好不要有资产,或者转账金额要大于标准账户资产,以确定资产是从合约账户转出。
如果操作正确,转出资产时会发生以下情况:
在当前时间小于锁仓时间时,转账将不会确认,即转账失败。
这时点击 钱包
-> 重建钱包索引
,大约 5 分钟后,未确认的转账会消失,资产恢复到之前的状态。
在当前时间大于锁仓时间时,转账会成功。