首页 / 资讯中心 / 文章详情

Vyper 实战入门:Simple Open Auction 公开拍卖合约逐行解析

Vyper 实战入门:Simple Open Auction 公开拍卖合约逐行解析 ★ FEATURED ARTICLE
编程语言编译器区块链【免费下载链接】vyperPythonic Smart Contract Language for the EVM项目地址https://gitcode.com/gh_mirrors/vy/vyper点击查看免费下载本文以 Vyper 官方文档中的 Simple Open Auction简单公开拍卖示例为主线完整拆解一个可运行的 Vyper 拍卖合约从public状态变量与自动生成的 getter、deploy构造函数到payable出价、withdrawal 取款模式再到endAuction的检查—执行—交互三阶段收尾流程。读完后你将掌握用 Vyper 编写带状态管理、ETH 转移与再入防护的合约的基本套路并能对照仓库中的源码与测试理解每个机制背后的实现。原文档明确提示This is example code for learning purposes. Do not use in production without thorough review and testing.这是学习用途的示例代码未经充分审查和测试请勿用于生产环境。完整合约源码见 examples/auctions/simple_open_auction.vy本文所有行号均基于该文件。1. 合约总体结构与业务模型示例属于 Vyper by Example 系列的开篇。业务模型很直接参与者在限定的时间窗口内提交出价bid拍卖结束后由部署时指定的受益人beneficiary收到最高出价的 ETH。从代码结构看整个合约只有 4 个函数1 个构造函数和 3 个可外部调用的方法bid、withdraw、endAuction加上 7 个状态变量。Vyper 语法与 Python 相似但它是独立语言有自己的类型系统、装饰器如deploy、external和关键字。文件首行通过#pragma version 0.3.10声明了所需的编译器版本范围这一行也说明了当前仓库版本对示例的兼容性前提。# Open Auction # Auction params # Beneficiary receives money from the highest bidder beneficiary: public(address) auctionStart: public(uint256) auctionEnd: public(uint256) # Current state of auction highestBidder: public(address) highestBid: public(uint256) # Set to true at the end, disallows any change ended: public(bool) # Keep track of refunded bids so we can follow the withdraw pattern pendingReturns: public(HashMap[address, uint256])7 个状态变量按职责分为两组变量类型职责beneficiaryaddress最高出价款的接收方auctionStart/auctionEnduint256以块时间戳秒表示的出价窗口起止highestBidder/highestBidaddress/uint256当前最高出价人与出价weiendedbool标记拍卖是否已正式结束之后禁止任何变更pendingReturnsHashMap[address, uint256]键值对记录每位被超越者的待退款金额用于执行 withdrawal 模式public标注与 getter 自动生成所有变量都写成public(类型)的形式。原文档解释public让变量可被外部合约调用并自动生成一个 getter 函数如contract.beneficiary()不加public则为私有声明仅同合约内的方法可访问。从源码看getter 的生成发生在语义分析阶段vyper/semantics/analysis/getters.py 中的generate_public_variable_getters会遍历 AST 中所有is_public的VariableDecl节点按变量的getter_signature构造一个同名的externalview函数返回self.varHashMap/DynArray变量还会为每个下标生成带参数arg0、arg1… 的查询函数并挂到模块命名空间。这解释了为何测试中可以直接调用auction_contract.beneficiary()、auction_contract.pendingReturns(k1)等无参或带下标的只读方法——它们并不是手写方法而是编译器合成的 getter。2. 构造函数deploy与block.timestampdeploy def __init__(_beneficiary: address, _auction_start: uint256, _bidding_time: uint256): self.beneficiary _beneficiary self.auctionStart _auction_start # auction start time can be in the past, present or future self.auctionEnd self.auctionStart _bidding_time assert block.timestamp self.auctionEnd # auction end time should be in the future构造参数为_beneficiary: address、_auction_start: uint256、_bidding_time: uint256其中_bidding_time是出价窗口时长秒而不是结束时间本身。先存下受益人与开始时间再由self.auctionStart _bidding_time计算self.auctionEnd注意开始时间允许是过去、现在或未来。末尾的assert block.timestamp self.auctionEnd强制要求结束时点必须在未来部署时若传入非法参数整笔部署交易会 revert。block是 Vyper 内置对象提供当前块信息时间戳、编号、hash 等另一个内置对象msg提供调用方信息后文的bid()会用到。3.bid()payable出价与assert校验external payable def bid(): # Check if bidding period has started. assert block.timestamp self.auctionStart # Check if bidding period is over. assert block.timestamp self.auctionEnd # Check if bid is high enough assert msg.value self.highestBid # Track the refund for the previous high bidder self.pendingReturns[self.highestBidder] self.highestBid # Track new high bid self.highestBidder msg.sender self.highestBid msg.value关键点payable装饰器允许调用者在方法调用之外随交易附带 ETH。出价者调用bid()时随交易发送的金额即为出价本身不含 gas 费。在类型层面payable将函数可变性标记为StateMutability.PAYABLE见 vyper/semantics/types/function.py 的is_payable属性反向地向非 payable 函数传value会在语义分析期抛出CallViolation(Cannot send ether to nonpayable function)同文件约 L784-L787。msg.sender/msg.valuemsg内置变量分别给出调用者地址与随交易发送的 ETH 数量wei。三道assert顺序执行窗口未开始、窗口已结束、新出价未严格大于当前最高出价任一不成立即抛出错误并回滚整笔交易。这也意味着 0 wei 出价、以及追平当前最高价equal bid都会失败——仓库测试 tests/functional/examples/auctions/test_simple_open_auction.py 的test_bid正是用tx_failed()验证了这两种情况value0被拒、value1之后再次value1被拒并验证更高出价会覆盖highestBidder/highestBid。退款记账通过校验后先把前最高出价人的金额累加进self.pendingReturns[self.highestBidder]遵循安全的取款模式再更新highestBidder和highestBid。测试中对应断言被超越者调用withdraw()前pendingReturns余额增加、取款后归零且账户余额上升。4.withdraw()withdrawal 取款模式external def withdraw(): pending_amount: uint256 self.pendingReturns[msg.sender] self.pendingReturns[msg.sender] 0 send(msg.sender, pending_amount)源码注释合约第 50-53 行解释了为什么不在bid()里直接退款如果在bid()中向被超越者直接转账一个恶意的出价合约可以拒收/阻塞这笔退款从而卡死后续所有更高出价。采用 withdrawal 模式后每个出价者自己拉取pull自己的退款读出待退金额、先清零防止重入时二次退款、再发送资金。测试test_bid末尾验证了该闭环withdraw(senderk1)后账户余额增加且pendingReturns(k1) 0。从编译器实现看send是一个内置函数vyper/builtins/functions.py 中的Send类将其生成 IR[assert, [call, gas, to, value, 0, 0, 0, 0]]默认 gas stipend 为 0即send()在转账失败时会使整笔交易 revert而不是静默吞掉失败——这是 Vyper 与传统 EVM 脚本中send 不检查返回值写法的区别。5.endAuction()三阶段模式收尾external def endAuction(): # 1. Conditions assert block.timestamp self.auctionEnd assert not self.ended # 2. Effects self.ended True # 3. Interaction send(self.beneficiary, self.highestBid)合约内的大段注释第 60-75 行给出了一条重要工程准则与外部合约交互调用函数或发送 ETH的函数应拆成三个阶段——Conditions检查断言当前时间已过auctionEnd断言self.ended尚未置位。后者防止重复调用——若拍卖已结束任何再次调用都可能被恶意利用必须显式拦截。Effects执行将self.ended置为True正式关闭拍卖。Interaction交互send(self.beneficiary, self.highestBid)把最高出价转给受益人。注释进一步说明三个阶段若混杂外部合约可能回调re-entrancy进入本合约修改状态或重复触发副作用例如重复打款内部函数若包含外部交互也应视为交互阶段的一部分。本示例中send恰好是最后一个语句天然满足该模式。对应测试test_end_auction验证了完整生命周期未到期时endAuction()失败 → 时间推进EXPIRY秒后调用成功且受益人余额精确增加最高出价 → 结束后再bid()失败、再次endAuction()也失败不能重复结束。6. 编译与运行验证示例文件可直接用 Vyper 编译器编译命令行入口见 vyper/cli/vyper_compile.py 对应的vyper compile命令需先通过pip install vyper安装编译器#pragma version 0.3.10决定当前安装版本是否满足该示例的编译前提vyper compile examples/auctions/simple_open_auction.vy --show-source-map --show-method-ids行为层面的正确性由功能测试套件覆盖tests/functional/examples/auctions/test_simple_open_auction.py 使用仓库内置的模拟链环境tests/evm_backends 提供 pyevm 等后端三个测试函数分别覆盖test_initial_state部署后受益人、起止时间auctionEnd auctionStart EXPIRY、ended is False、最高出价为 0 等初始状态test_bid0 出价/等额出价被拒、多次抬价、pendingReturns累计与withdraw()取款test_end_auction到期前不可结束、到期后受益人收款、结束后不可再出价且不可重复结束。7. 小结与扩展方向这个示例用不到百行代码展示了 Vyper 合约的核心骨架public状态变量 自动 getter、deploy构造器、external payable收币入口、msg.sender/msg.value/block.timestamp内置变量、assert校验回滚、HashMap状态记账以及 withdrawal 模式与检查—执行—交互三阶段两大安全模式。原文档也指出这是一个功能最简barebones的实现可以在此基础上继续改进。若希望在此基础上深入学习仓库提供了直接的同系列进阶案例docs/vyper-by-example/blind-auction.rst盲拍涉及keccak256哈希密封与HashMap多键存储以及 examples/auctions/blind_auction.vy 的完整实现其余示例代币、众筹、治理投票、DeFi 等的入口在 docs/vyper-by-example/index.rst。赞分享编程语言编译器区块链【免费下载链接】vyperPythonic Smart Contract Language for the EVM项目地址https://gitcode.com/gh_mirrors/vy/vyper点击查看免费下载相关推荐Pot-Desktop一款划词翻译与截图 OCR 工具5 分钟装好就能用Pot Desktop一款划词翻译与截图 OCR 工具5 分钟装好就能用 如果你经常读外文资料还常遇到图片里的文字选不中、复制不了那么一个同时做划词翻译桌面应用AI 应用Solidity智能合约开发盲拍与公开拍卖的实现详解Solidity智能合约开发盲拍与公开拍卖的实现详解 公开拍卖合约基础 在区块链上实现拍卖系统是智能合约的经典应用场景。我们先从最简单的公开拍卖合约开始讲解编程语言编译器区块链draw.io Desktop离线桌面画图工具数据不出机器draw.io Desktop离线桌面画图工具数据不出机器 画一张内部网络拓扑要先把草图传到在线编辑器才敢动笔导出的图贴进文档连线歪了还得逐根手调d大数据数据湖数据工程上一篇Laravel-Lang 项目使用教程下一篇React-Component/Form 开源项目教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站