通过例子学Vyper(一)

学习一门语言,最好的方法就是动手去实现一个案例。

本文通过一个官方的公开拍卖合约示例来介绍Vyper编程。

当我们开始用Vyper进行智能合约编程时,要记住一个重要的原则:

所有Vyper语法都是有效的Python3语法,但并不是所有的Python3语法都可以在Vyper中使用。

在这个合约中,我们将实现一个简单的公开拍卖功能,通过该合约参与者可以在有限的时间内提交出价,直至拍卖结束,最高的出价者竞拍成功,合约自动将竞拍款支付给受益人。

以下是代码:

# 公开拍卖

# 拍卖参数
# beneficiary是受益人的以太坊地址,将获得出价最高者的竞拍款
# auction_start是竞拍开始时间,auction_end是结束时间
beneficiary: public(address)
auction_start: public(timestamp)
auction_end: public(timestamp)

# 保存当前最高出价的信息
# highest_bidder是最高出价人以太坊地址
# highest_bid是当前最高出价
highest_bidder: public(address)
highest_bid: public(wei_value)

# 用于标识拍卖是否结束,为True时拍卖结束
ended: public(bool)

# 构造函数,进行初始化
# '_beneficiary'参数代表受益人地址
# '_bidding_time'参数代表拍卖持续的时长
@public
def __init__(_beneficiary: address, _bidding_time: timedelta):
    self.beneficiary = _beneficiary
    self.auction_start = block.timestamp
    self.auction_end = self.auction_start + _bidding_time

# 竞价函数,通过调用该函数发送以太币参与竞拍
# 当竞拍结束时,你没有赢得拍卖,以太币将被退还
@public
@payable
def bid():
    # 检查拍卖是否结束了
    assert block.timestamp < self.auction_end
    # 检查出价是否比当前最高价高
    assert msg.value > self.highest_bid
    if not self.highest_bid == 0:
        # 退还之前最高出价者的资金
        send(self.highest_bidder, self.highest_bid)
    self.highest_bidder = msg.sender
    self.highest_bid = msg.value


# 结束竞拍,将最高出价发送给受益人
@public
def end_auction():
    # 1. 判断合约是否结束
    # 检查是否超出拍卖的最后时间
    assert block.timestamp >= self.auction_end
    # 检查该合约是否已经被调用过
    assert not self.ended

    # 2. 标记为竞拍结束
    self.ended = True

    # 3. 发送以太币给受益人
    send(self.beneficiary, self.highest_bid)

该拍卖合约非常简单,仅包含一个构造函数,两个方法,以及一些状态变量。下面我们来详细讨论这个合约。

一、合约名称

我们会发现这个代码没有类似Solidity的“contract OpenAuction”的表述,这是因为Vyper的语法跟Python的模块命名类似,合约名就是文件名,即这个合约叫OpenAuction的话,就把上面这段代码保存为一个名叫OpenAuction.vy的文件。

二、变量声明

Vyper是静态类型语言,要事先声明所有变量的数据类型。

放在文件开头定义的变量为全局变量。

beneficiary: public(address)
auction_start: public(timestamp)
auction_end: public(timestamp)
highest_bidder: public(address)
highest_bid: public(wei_value)
ended: public(bool)
  • beneficiary被定义为一个公开类型的地址变量。这个beneficiary地址就是拍卖受益人的地址,拍卖完成后,拍卖款就会转入这个地址。

  • auction_startauction_end是公开类型的时间戳变量。这两个变量用来记录拍卖的起始和结束时间。

  • highest_bidderhighest_bid表示当前最高出价人的地址和出价金额,分别是一个地址变量和一个以太币金额变量。

  • ended是一个布尔值变量,用于标记拍卖是否结束。

关键字 说明
public 几乎在所有的语言中表示的意义都相同,就是可以被外部合约访问。没有声明为public的变量只能在合约内被访问。public还为变量创建了一个“getter”函数,可通过外部调用访问contract.beneficiary()
address 是以太坊特有的一种数据类型,表示该变量被定义为存储一个以太坊地址,即一个长度为20个字节的十六进制钱包地址,比如像这样ca35b7d915458ef540ade6068dfe2f44e8fa733c
timestamp 是以太坊特有的一种数据类型,代表的是当前块的Unix时间戳(从1970/1/1 00:00:00 UTC开始所经过的秒数)。
wei_value 以太币金额,以wei为单位。
bool 跟其他语言的布尔值变量一样,有TrueFalse两个值。

三、构造函数

@public
def __init__(_beneficiary: address, _bidding_time: timedelta):
    self.beneficiary = _beneficiary
    self.auction_start = block.timestamp
    self.auction_end = self.auction_start + _bidding_time

Vyper的构造函数定义跟Python的类构造函数一样,用__init__表示。

在函数的前面有一个装饰器@public,这表示该函数可以被外部调用。Vyper语言里的其他装饰器还包括:

装饰器 说明
@private 表示只能在合约内部调用
@constant 表示合约状态不能被改变
@payable 表示可以接收以太币转账
@nonrentant 表示只能被调用一次,防止重入攻击

其中@public@private是强制二选一的,其他的装饰器视情况可选。

构造函数包含两个参数:1、_beneficiaryaddress类型,代表受益人地址;2、_bidding_timetimedelta类型,代表拍卖持续的时长。

关键字 单位 说明
timestamp 1秒 表示一个时刻
timedelta 1秒 表示一段时间长度,以秒为单位

注:两个timedelta类型的变量可以相加,一个 timestamp类型的变量与一个 timedelta类型的时间变量也可相加,但是两个 timestamp类型的变量不能相加。

构造函数通过self关键字来指代合约本身,将函数参数赋值给合约的变量。在构造函数里,我们看到有一个block对象,通过它获得了当前区块的时间。block是一个以太坊默认对象,在任何的Vyper合约中都能调用,不用声明。与block对象类似的还有msg对象。

四、功能函数

这个智能合约里包含两个功能函数,竞价函数与结束函数。

这两个函数的功能都已经在上面的代码注释中进行了比较详细的解释,这里主要解说一下代码里的一些知识点。

@payable装饰器说明bid()函数可接收以太币,想要进行投标的用户可以调用该方法并发送一定数量的以太币。合约通过内置对象msgmsg.sender方法获取访问用户的以太坊地址,通过msg.value方法获取访问用户发送的以太币数量。

注意!下方高能!

msg.sender将在内部函数调用之间发生变化。当从外部调用函数时,它对于第一个函数调用是正确的,就是调用函数的人的地址。但是,在合约内部函数互相调用之后,msg.sender将会引用合同本身而不是事务的发送者。这是一个容易造成安全隐患的大坑!在设计智能合约的时候,要牢记安全性,保持代码简单,可读性强,安全第一!

bid()end_auction()这两个函数里,最主要的是使用了Vyper语言内置函数里面的断言函数assert发送函数send

  • 断言函数assert相当于传统编程语言里的if,当判断条件为False时,将终止后面语句的执行,并把剩余的gas返回给合约调用方。

  • 发送函数send顾名思义,就是从当前地址转账以太币到指定地址。

好了,这个例子到此就解释完毕了,其实还是挺简单的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354

推荐阅读更多精彩内容