Web3.0安全开发实践:Clarity最佳实践总结

在过去的一段时间里,CertiK团队对比特币生态系统及其发展进行了深入研究。同时,团队还审计了多个比特币项目以及基于不同编程语言的智能合约,包括OKX的BRC-20钱包和MVC DAO的sCrypt智能合约实现。
现在,我们的研究重点转向了Clarity。CertiK团队在圆满完成多个Clarity漏洞赏金项目后,获得了更多关于其安全问题和常见实践的洞见。本文将分享这些见解以及经验,以期可以帮助到生态建设者。
Clarity是一种由Hiro PBC、Algorand和其他利益相关者共同开发的智能合约语言。目前,它已在Stacks链(比特币侧链)上得到应用。Clarity的主要目标是提供高度的可预测性和安全性,确保智能合约按预期执行,不会产生任何出乎意料的副作用。
接下来,我们将探讨Clarity智能合约背后的概念,以及使用Clarity编程的最佳实践和安全检查清单。
Clarity语言
Clarity的设计源自对智能合约工程中漏洞的深入分析,特别是对Solidity中观察到的漏洞的研究。它的关键特性包括以下几点:
-
可解释语言:确保所见即所得。
-
可判定属性:保证可预测结果和有限执行。
-
安全措施:防范重入攻击、溢出和下溢,这些对保持合约完整性至关重要。
-
自定义代币支持:简化开发流程,便于创建和管理代币。
-
事务后置条件:通过验证执行后的状态变化来增强安全性。
Clarity的独特之处在于它从LISP语言中汲取灵感,LISP以其处理符号信息的简洁性和强大功能而闻名。在Clarity中,一切都以“列表中的列表”或“表达式中的表达式”的形式表示。这种嵌套结构是Clarity的核心特点,使其语言具有高度的表达性和灵活性。函数定义、变量声明和函数参数都被封装在括号内,强调了语言的语法统一性。
以下是定义一个简单Clarity函数的示例:
(define-data-var count int 0) //State Variable Declaration(define-public (increase-number (number int)) //Function definition(let((current-count count))(var-set count (+ 1 number))(ok (var-get count))))(increase-number 1) //Function call
通过理解和利用这些嵌套表达式,开发者可以创建符合Stacks区块链功能要求的安全高效的智能合约。这种方法不仅增强了可读性,还确保合约的确定性和可预测性——这是保持去中心化应用安全性和可信度的关键。
Clarity与Solidity的区别
1. 解释型与编译型
-
Clarity:Clarity是一种解释型语言,意味着源代码直接发送到Stacks区块链并在区块链上执行,而无须编译成字节码。
-
Solidity:Solidity代码首先需要编译成字节码,然后将字节码部署到区块链上。EVM(以太坊虚拟机)会验证这些字节码,并调度相应的操作码进行执行。
2. 无动态调度
-
Clarity不支持动态调度,并且不是图灵完备的,这意味着要执行的函数是预先确定的。这个特性简化了执行模型,并有助于防止重入攻击,使Clarity本身更加安全。

Clarity智能合约安全
安全一直是DeFi领域的头等大事,尤其是在Stacks网络扮演关键角色的比特币DeFi生态系统中。截至2024年8月,Stacks生态系统中的总锁仓价值(TVL)已达到约为8000万美元,因此强大的安全措施变得尤为重要。
截至目前,Stacks已经发生了多起安全事件,导致超过200万美元的损失。这些事件突显了对Clarity智能合约进行安全审计的必要性。
安全事件案例
2024年4月11日,Stacks网络上的借贷协议Zest Protocol(比特币L2)遭遇了一次重大漏洞攻击,攻击目标是协议的借款池(Borrow Pool),导致损失约322,000STX(折约100万美元)。这次黑客攻击事件迄今为止是比特币DeFi生态系统中损失最严重的事件。
Zest Protocol的借款功能在合约pool-borrow.clar中定义,允许用户通过提供抵押物来借入资产。该功能的参数包括池储备、价格预言机、借入的资产、流动性提供者代币、抵押资产列表、借款金额、费用计算器、利率模式和所有者:
(define-public (borrow(pool-reserve principal)(oracle <oracle-trait>)(asset-to-borrow <ft>)(lp <ft>)(assets (list 100 { asset: <ft>, lp-token: <ft>, oracle: <oracle-trait> }))(amount-to-be-borrowed uint)(fee-calculator principal)(interest-rate-mode uint)(owner principal))
pool-borrow-v1-1.clar 中的借款函数
攻击者利用了assets(资产)参数,该参数是一个最多包含100种资产的列表,用作抵押物。其漏洞源于合约未能成功验证抵押资产的唯一性。更具体地说,合约在验证资产存在性时未检查重复项。这个疏忽使攻击者能够通过多次列出同一资产操纵抵押物的价值。
其他协议也遭遇过类似的安全漏洞攻击。例如,2021年10月,一名攻击者从Arkadiko Swap中窃取了约400,000枚STX和740,000枚USDA(总计约150万美元)。攻击者利用了Arkadiko Swap智能合约代码中的一个漏洞,该漏洞未能在创建新的交易对时正确验证LP代币。该漏洞使攻击者能够零成本铸造大量LP代币,随后从STX/USDA池中提取底层资产,影响了该池总价值的25%的资产。
Clarity智能合约的最佳实践与检查清单
我们总结了广泛研究后取得的经验,并为Clarity智能合约开发者编制了最佳实践和检查清单。以下是关键点:
1. 避免使用-panic函数
在Clarity智能合约中解包值时,避免使用unwrap-panic和unwrap-err-panic等函数。当这些函数解包失败时,它们会以运行时错误中止调用,却也没有为与合约交互的应用程序提供有意义的信息。但如果选择使用unwrap!和unwrap-err!,并附加明确的错误代码。这个方法不仅能够提高了错误的处理能力,还便于调试,并增强了智能合约的韧性。使用具体的错误代码可以使调用应用程序更高效地处理错误,并根据上下文采取适当的措施。
2. 避免使用tx-sender进行验证
在Clarity智能合约中滥用tx-sender变量进行身份验证可能导致安全漏洞,类似于Solidity中SWC-115列出的漏洞。tx-sender变量标识调用链的发起者,类似于Solidity中的tx.origin。使用tx-sender进行验证可能会引发网络钓鱼攻击,攻击者可以欺骗用户并在易受攻击的合约上执行经过身份验证的操作。

tx-sender与contract-caller的对比
另一方面,contract-caller表示当前调用的发送者。通过避免使用tx-sender进行身份验证,并采用更安全的替代方案如contract-caller,开发者可以降低网络钓鱼攻击和跨站脚本攻击的风险。
3. 模块化合约设计以增强灵活性和未来可升级性
一旦智能合约部署到区块链上,它就变得不可修改。与传统应用开发相比,这种不可变性带来了挑战,这意味着它不可以随时进行更新和修复。在智能合约开发中,确保灵活性和未来可升级性需要采取战略方法,因为一旦合约部署,就没有直接的方法可以更新合约代码。
解决这些挑战,开发者应考虑以下原则:
保持逻辑分离:避免创建一个处理所有功能的单一合约。而应该,通过将智能合约模块化,将其拆分为更小、独立的并且可以相互交互的组件。这种方法不仅使合约更易于管理和理解,还能在不影响整个系统的情况下替换或升级单个组件。
无状态合约:该合约可以在区块链上存储最少量的数据,从而减少了未来更改的复杂性和潜在影响。通过将状态保留在合约外部并作为输入参数传递,您可以更新逻辑而无须修改合约的状态。
避免硬编码变量:将值直接硬编码到合约代码中可能导致其缺乏灵活性,且妨碍未来的更新。相反,若将关键变量定义为可配置的参数,这些参数则可以通过合约函数进行设置或调整。
4. 避免基于区块高度(block-hight)的时间计算
在Clarity智能合约中,避免依赖block-height关键字进行时间敏感的计算。Stacks链的区块时间可能会随着网络升级而变化,例如Nakamoto版本的发布将会减少区块时间。而应该使用burn-block-height关键字,它反映了底层比特币区块链的当前区块高度。比特币的区块时间更稳定,不太可能发生变化,从而确保合约操作的更高准确性和可靠性。这种做法有助于保持一致性,并防止由于Stacks区块时间波动而引发的潜在问题。
5. 正确处理函数中的返回值
在开发Clarity智能合约时,必须正确处理函数的布尔返回值,尤其是处理像verify-mined()等函数时。
该函数返回三种可能的值:(ok true)、(ok false)或错误。如果返回(ok true),表示交易已在指定区块成功挖掘。如果返回(ok false),则表示交易未被挖掘,而错误则表示Merkle证明存在问题。
在使用try!检查ok/error,但未能验证响应类型中封装的布尔值时,会出现一个常见问题。这种疏忽可能导致即使交易未在区块中被挖掘(即返回值为(ok false)),函数也不会失败。结果是验证者可能会合作签署一个未被挖掘的交易,使其未经检查就通过索引器。这一漏洞使得未经验证的未挖掘和潜在恶意的交易得以处理,从而导致安全漏洞和系统内未经授权的操作。
为了降低这种风险,请确保您的代码检查错误并明确验证函数返回的布尔值。这种做法有助于维护合约的完整性和安全性,确保只处理有效的挖矿交易。
6. 在Clarity中正确使用contract-call?
在开发Clarity智能合约时,必须使用contract-call?函数正确实现合约间调用。该函数从被调用的智能合约返回一个Response(响应)类型的结果。
contract-call?的两种类型:
-
静态调用(Static Call):被调用的是一个已知的不变合约,在调用者合约部署时可在链上使用。第一个参数是被调用者的本金,然后是方法名称及其参数。
(contract-call?.registrarregister-namename-to-register)
-
动态调用(Dynamic Call):将被调用者作为参数传递,并将其类型化为特征引用(trait reference)。通过引用特征,代码可以更加灵活和可重用。
(define-public (swap (token-a <can-transfer-tokens>)(amount-a uint)(owner-a principal)(token-b <can-transfer-tokens>)(amount-b uint)(owner-b principal)))(begin(unwrap! (contract-call? token-a transfer-from? owner-a owner-b amount-a))(unwrap! (contract-call? token-b transfer-from? owner-b owner-a amount-b))))
在处理合约调用时,请注意以下限制:
-
在静态调用中,被调用者智能合约在创建时必须存在。
-
智能合约的调用图中不得存在循环。这可以防止递归(和重入)。这种结构可以通过对调用图的静态分析检测出来,并将被网络拒绝。
-
contract-call?仅用于合约间调用。当调用者同时也是被调用者时,如果尝试执行,则会中止交易。
结语
CertiK已对Clarity智能合约安全进行了广泛地研究。作为一家在智能合约安全领域拥有丰富经验的Web3.0头部安全审计公司,CertiK已发现并报告了多个基于Clarity的漏洞赏金项目中的漏洞。如需了解我们之前的风险分析报告,可以访问我们的博客。
相关文章:
Web3.0安全开发实践:Clarity最佳实践总结
在过去的一段时间里,CertiK团队对比特币生态系统及其发展进行了深入研究。同时,团队还审计了多个比特币项目以及基于不同编程语言的智能合约,包括OKX的BRC-20钱包和MVC DAO的sCrypt智能合约实现。 现在,我们的研究重点转向了Clar…...
基于Springboot+Vue动漫推荐平台管理系统(源码+lw+讲解部署+PPT)
前言 详细视频演示 论文参考 系统介绍 系统概述 核心功能 用户角色与功能 具体实现截图 1. 热门动漫功能 2. 文章专栏功能 3. 会员分享功能 4. 热门动漫管理功能(管理员端) 5. 动漫分类管理功能 技术栈 后端框架SpringBoot 前端框架Vue …...
秋意浓,森林披金装
秋意浓,森林披金装, 枫叶如火,漫山遍野狂。 松间轻风送寒意, 鸟鸣悠扬入云翔。 林间小径蜿蜒行, 落叶铺成金色毯。 溪水潺潺绕石转, 映出天边一抹霞。 野菊点缀在草间, 白云悠悠随意闲。…...
Chrome离线安装包下载
1、问Chrome的官网:https://www.google.cn/chrome/ 直接下载的是在线安装包,安装需要联网。 2、如果需要在无法联网的设备上安装Chrome,需要在上面的地址后面加上?standalone1。 Chrome离线安装包下载地址:https://www.google.c…...
安卓手机5G网络频繁掉4G 问题解决 手机5G网络优化方案
问题环境 在某个长期停留的位置(例如:躺平)使用手机时网络突然从5G跳到4G,偶尔跳来跳去导致网络体验很差,经过调整5G网络情况下网速及其他体验都要更好,基于这样的情况使用一种简单的操作,锁定5…...
使用LLaMA-Factory微调时的问题与解决方案记录
文章目录 如何指定微调使用的显卡如何解决显卡通信导致的报错模型微调的实际epoch和step如何计算如何实现多卡全量微调模型微调后的结果如何查看模型测试后的指标如何理解如何指定微调使用的显卡 启动网页时使用这种执行命令 CUDA_VISIBLE_DEVICES=5,6,7 llamafactory-cli we…...
Go语言switch语句
在Go语言中,switch,是一个高度灵活,其功能强大的控制结构,相比较Java中的switch,更受到语言重视。 目录 1.基础用法2.多值匹配3.不指定表达式的 switch4.使用 fallthrough 强制进入下一个分支5.使用类型断言的 switch…...
JavaScript DOM使用
DOM Document Object Model 简单而言,就是JavaScript将HTML文档的各个组成部分封装为对象。 封装的对象分别为: Document:整个HTML的文档对象 Element:元素对象(也就是HTML中的标签) Attribute:…...
人工智能|计算机视觉——微表情识别(Micro expression recognition)的研究现状
一、简述 微表情是一种特殊的面部表情,与普通的表情相比,微表情主要有以下特点: 持续时间短,通常只有1/25s~1/3s;动作强度低,难以察觉;在无意识状态下产生,通常难以掩饰或伪装;对微表情的分析通常需要在视频中,而普通表情在图像中就可以分析。由于微表情在无意识状态…...
耿恭坚守城池的方法
疏勒城之战中,耿恭坚守城池的方法主要有以下几点: 选择有利地势:耿恭深知疏勒城依山傍水、地势险要,易守难攻,于是果断放弃金满城,移师至疏勒城据守,为长期坚守创造了良好的地理条件.运用心理战…...
小兔鲜项目总结——项目亮点
目录 1、基于业务的逻辑组件拆分思想2、长页面吸顶交互的实现3、自定义图片懒加载指令并封装为插件4、画板插槽组件等业务通用组件封装5、通用逻辑函数的封装6、列表无限加载7、路由缓存问题的处理 小兔鲜项目其实在暑假之前就已经做完了,但是一直没有空做总结&…...
Cesium的ClearCommand的流程
ClearCommand是在每帧渲染前可以将显存的一些状态置为初始值,就如同把擦黑板。当然也包括在绘制过程中擦掉部分的数据,就如同画家在开始绘制的时候会画导览线(如透视线),轮廓出来后这些导览线就会被擦除。 我画了一个…...
Fakelocation Server服务器/专业版 ubuntu
前言:需要Ubuntu系统 Fakelocation开源文件系统需求 Ubuntu | Fakelocation | 任务一 任务一 更新Ubuntu(安装下载不再赘述) sudo -i # 提权 sudo apt update # 更新软件包列表 sudo apt upgrade # 升级已安装的软…...
Spring AI Alibaba 快速入门
Spring AI Alibaba 实现了与阿里云通义模型的完整适配,接下来,我们将学习如何使用 spring ai alibaba 开发一个基于通义模型服务的智能聊天应用。 一、快速体验示例 注意:因为 Spring AI Alibaba 基于 Spring Boot 3.x 开发,因此…...
Docker Registry(镜像仓库)详解
Docker Registry(镜像仓库)详解 Docker Registry,即Docker镜像仓库,是Docker生态系统中一个至关重要的组件。它负责存储、管理和分发Docker镜像,为Docker容器提供镜像资源。本文将深入探讨Docker Registry的功能、结构…...
RTOS学习笔记---“二值信号量”和“互斥信号量”
在实时操作系统(RTOS)中,“二值信号量”和“互斥信号量”是两种常见的同步机制,用于线程之间的协调与资源管理。尽管它们有相似之处,都基于信号量概念,但它们的用途和行为存在重要区别。 1. 二值信号量&…...
Oracle-物化视图基本操作
-- 物化视图 -- 与普通视图的区别:真实存在数据的 普通视图的数据在基表 物化视图看成是, 一个定时运行的计算JOB一个存计算结果的表 创建时生成数据: 分为两种:build immediate 和 build deferred, build immediate是在创…...
(功能测试)测试报告
其中的统计分析和测试结果确认是必须要有的; 测试过程回顾:测试的时间和阶段,是否出现延期,与预期的任务计划是否匹配; !统计分析:统计写多少用例,用例覆盖情况如何(100%…...
【LeetCode每日一题】——746.使用最小花费爬楼梯
文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时空频度】九【代码实现】十【提交结果】 一【题目类别】 数组 二【题目难度】 简单 三【题目编号】 746.使用最小花费爬楼梯 四【题目描述】 给你一…...
程序里sendStringParametersAsUnicode=true的配置导致sql server cpu使用率高问题处理
一 问题描述 近期生产环境几台sql server从库cpu使用率总是打满,发现抓的带变量值的慢sql,手动代入变量值执行并不慢,秒级返回,不知道问题出在哪里。 二 问题排查 用扩展事件或者sql profiler抓慢sql,抓到了变量值&…...
从‘轨迹抖动’到‘借道避障’:一次看懂特斯拉FSD和国内Robotaxi的决策逻辑差异
特斯拉FSD与国内Robotaxi的决策逻辑差异:从轨迹抖动到借道避障的技术哲学 当一辆自动驾驶汽车在高速公路上遇到前方车辆突然切入时,特斯拉的摄像头会如何反应?而搭载激光雷达的国产Robotaxi又会做出什么不同的决策?这种差异不仅仅…...
为什么你的C盘空间总是不够用?可能是Windows驱动文件在悄悄“发胖“
为什么你的C盘空间总是不够用?可能是Windows驱动文件在悄悄"发胖" 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 想象一下这样的场景:你的电脑C盘明明…...
Windows 11终极优化指南:用Win11Debloat实现系统加速51%的免费方案
Windows 11终极优化指南:用Win11Debloat实现系统加速51%的免费方案 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to decl…...
5大突破让暗黑2单机体验翻倍:PlugY插件全方位应用指南
5大突破让暗黑2单机体验翻倍:PlugY插件全方位应用指南 【免费下载链接】PlugY PlugY, The Survival Kit - Plug-in for Diablo II Lord of Destruction 项目地址: https://gitcode.com/gh_mirrors/pl/PlugY 当你第10次因储物箱满被迫丢弃装备时,当…...
从数学原理到代码实现:手把手推导Transformer时间复杂度公式(附PyTorch示例)
从数学原理到代码实现:手把手推导Transformer时间复杂度公式(附PyTorch示例) 在自然语言处理领域,Transformer架构已经成为事实上的标准模型。但当我们处理长文本序列时,经常会遇到计算资源急剧增加的问题。这背后的核…...
第二桌面 + 小龙虾:让企业AI智能体安全落地、全员可用
本文发布于2026年4月1日。引言:从“养虾”到“用虾”,AI落地需要新底座过去几个月,OpenClaw(昵称“小龙虾”)在开发者圈子里火得一塌糊涂。这个开源AI智能体网关,能听懂人话,还能替你操作电脑、…...
Vue-Super-Flow隐藏玩法:不画图,只填空!手把手教你打造可配置的流程图答题组件
Vue-Super-Flow隐藏玩法:不画图,只填空!手把手教你打造可配置的流程图答题组件 在Vue生态中,流程图工具通常被用来构建复杂的可视化编辑界面。但你是否想过,这些工具还能用来做些什么?本文将带你探索一个全…...
VictoriaMetrics 集群版实战指南:架构解析与最佳实践
1. VictoriaMetrics集群版架构深度解析 第一次接触VictoriaMetrics集群版时,我被它简洁的组件划分惊艳到了。与常见的时序数据库不同,它的三大核心组件vmstorage、vminsert、vmselect各司其职,这种设计让横向扩展变得异常灵活。在实际部署中&…...
新手入门指南:基于快马生成的代码理解设备配对功能实现
今天想和大家分享一个特别适合新手学习的设备配对功能实现案例。这个例子用最基础的HTML、CSS和原生JavaScript就能完成,特别适合刚接触前端开发的朋友理解交互逻辑。 项目结构设计 整个项目分为三个部分:两个模拟设备(用不同图标表示&#x…...
COMSOL相场法/水平集方法多孔介质两相驱替模型案例 附随机孔隙度几何程序 助力学习两相流驱替模拟
COMSOL相场法(/水平集方法)多孔介质驱替模型案例,可以提供随机孔隙度几何程序。 提供基于COMSOL中相场方法模拟多孔介质两相驱替(水气、油水等等)的算例(也可以定做水平集驱替的算例)࿰…...
