Damn Vulnerable DeFi(二)
链接: https://www.damnvulnerabledefi.xyz/challenges/unstoppable/
存在一个代币化金库,其中已存入 100 万枚 DVT 代币。该金库当前提供免费闪电贷服务,此权益将持续至宽限期结束。
为在完全无权限化(Web3 核心术语,指无需中心化机构审核,任何地址均可自由与合约交互)上线前排查所有漏洞,开发者决定在测试网(区块链专用测试环境,用于验证合约功能,不涉及真实资产与资金)运行公开测试版。同时,还部署了一个监控合约,用于检查闪电贷功能的可用性(“liveness” 此处特指合约功能是否正常运行,无卡顿、中断或失效情况)。
初始余额为 10 枚 DVT 代币,请证明存在让该金库停止运作的方法(“halt the vault” 意为使金库核心功能失效,而非单纯停止部署),且目标必须是让它彻底停止提供闪电贷服务。
第一步,先在remix中写完注释
有两个文件
- UnstoppableLender.sol
- ReceiverUnstoppable.sol
第二步,尝试部署到测试网
2.1 部署遇到报错

1 | |
补充说明(贴合Solidity开发场景)
核心术语精准解析:
- abstract contract:抽象合约(Solidity中用
abstract关键字标记的合约,包含未实现的抽象方法,无法直接部署,需由子合约实现所有抽象方法后才能部署); - abstract parent’s methods:抽象父合约的方法(父合约中仅声明函数签名、无具体实现的方法,子合约必须重写并实现逻辑);
- inherited contract’s constructor:继承合约的构造函数(Solidity中继承合约时,需显式调用父合约构造函数并传入参数,否则编译报错)。
- abstract contract:抽象合约(Solidity中用
语法与语境适配:
原文是Solidity编译器的典型警告/错误提示,翻译时未直译(避免生硬),而是按中文技术文档的表达习惯拆分因果逻辑——先点明核心问题(合约可能为抽象合约),再说明两类常见诱因,符合开发者排查问题的思维习惯。常见场景补充:
该提示常出现在以下情况:- 子合约继承了抽象父合约,但未实现父合约中标记为
virtual的抽象方法; - 继承带参数的父合约时,未通过
constructor() ParentContract(参数)或super正确调用父构造函数; - 误将普通合约标记为
abstract,但未包含抽象方法(编译器会提示冗余)。
- 子合约继承了抽象父合约,但未实现父合约中标记为
2.2 部署ReceiverUnstoppable.sol


不知道如何部署 UnstoppableLender 金库合约,用remix部署的适合提示:This contract may be abstract, it may not implement an abstract parent’s methods completely or it may not invoke an inherited contract’s constructor correctly.
后来部署成功了
- UnstoppableLender.sol
- ReceiverUnstoppable.sol
还是不明白该金库停止运作的方法是什么?
也不明白普通用户该如何调用该智能合约
《1. Unstoppable Walkthrough - Damn Vulnerable DeFi》
https://www.youtube.com/watch?v=lwIHKtI2_9A
这个视频一直在解析和讲解solidity代码,我希望视频作者去实际部署合约,实际去攻击一下。
你的需求非常合理!纯代码解析确实不够直观,实际部署合约+手动复现攻击流程,能更清晰地验证漏洞原理和攻击效果——毕竟DeFi安全的核心是“实操验证”,很多细节(比如链上余额同步、交易回滚报错)只有在真实部署后才能直观感受到。
如果想让视频作者补充这类实操内容,或者自己跟着复现,这里可以提供一套 “本地/测试网实操复现步骤”(完全还原视频中的Unstoppable挑战,新手也能跟着做):
一、前置准备工具
- 开发环境:Node.js + Hardhat(以太坊开发框架,视频中作者大概率也用的Hardhat,因为Damn Vulnerable DeFi默认适配Hardhat)
- 测试网:可选 Goerli/Sepolia测试网(需要少量测试ETH,可从水龙头领取),或本地Hardhat节点(无需真实测试币,最快最方便)
- 钱包:MetaMask(连接测试网/本地节点)
- 依赖:Damn Vulnerable DeFi源码(直接拉取官方仓库)
二、实操步骤(本地Hardhat节点版,无需测试币)
1. 拉取Damn Vulnerable DeFi源码并初始化
1 | |
2. 查看目标合约(对应视频中的“Unstoppable”挑战)
核心合约路径:contracts/unstoppable/
UnstoppableLender.sol:借贷池合约(提供闪电贷、存款功能)ReceiverUnstoppable.sol:闪电贷接收者合约(用于测试闪电贷是否可用)DamnValuableToken.sol:DVT代币合约(ERC20标准)
3. 编写“攻击脚本”(对应视频中的攻击思路)
在 scripts/ 文件夹下新建 attack-unstoppable.js,代码逻辑:
- 部署DVT代币、UnstoppableLender借贷池(初始化100万DVT到借贷池)
- 部署攻击者账户(初始100个DVT,和视频一致)
- 攻击者绕过存款函数,直接向借贷池转账1个DVT
- 测试闪电贷是否失效(调用借贷池的flashLoan函数,观察是否回滚)
脚本完整代码:
1 | |
4. 启动本地Hardhat节点并执行攻击脚本
1 | |

在hardhat又遇到了这个问题; commonjs和typescript的问题。
5. 观察执行结果(验证攻击成功)
成功执行后,终端会输出:
1 | |
关键验证点:
- 攻击后,借贷池的链上余额(1000001)≠ 合约内poolBalance(1000000)
- 调用flashLoan时触发
Assertion failed(断言失败),交易回滚,闪电贷完全不可用——和视频中的漏洞原理完全一致!
三、如果想让视频作者补充这类内容,可以这样反馈
给视频作者(Blue Alder)的评论/私信模板:
1 | |
四、拓展:测试网部署版(更贴近真实场景)
如果想在Sepolia测试网复现(让合约上真实链),只需修改2步:
- 配置Hardhat的Sepolia网络(在
hardhat.config.js中添加):1
2
3
4
5
6
7
8
9
10
11
12require("@nomiclabs/hardhat-waffle");
require("dotenv").config();
module.exports = {
solidity: "0.8.17", // 对应Damn Vulnerable DeFi的sol版本
networks: {
sepolia: {
url: `https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY}`, // 用Infura/Alchemy的RPC
accounts: [process.env.PRIVATE_KEY], // 你的MetaMask私钥(需有Sepolia测试ETH)
},
},
}; - 执行脚本时指定Sepolia网络:
1
npx hardhat run scripts/attack-unstoppable.js --network sepolia
之后可以在 Etherscan Sepolia 上查看合约地址、转账记录和失败的闪电贷交易,完全还原真实攻击场景~
通过这套实操流程,能把视频中的“代码逻辑”转化为“可感知的链上结果”,彻底理解这个漏洞的核心(状态变量与链上余额不同步导致断言失效)!
问题 什么是yarn?
1 | |
npm install -g yarn
yarn -v
1.22.22
什么是yarn?
Yarn 是一款 JavaScript/TypeScript 项目的包管理器,核心作用是 下载、管理项目依赖(第三方代码库),并确保项目在不同环境下的依赖版本一致——简单说,它和你之前可能听过的 npm(Node.js 自带的包管理器)功能类似,但在速度、稳定性、安全性上有优化。
结合你正在做的 DVDF(区块链智能合约 CTF)项目,用通俗的方式拆解 Yarn 的核心价值:
一、Yarn 解决了什么问题?
你克隆的 DVDF 项目,不是一个孤立的代码文件夹——它依赖很多第三方工具:比如编译 Solidity 合约的 hardhat、操作区块链的 ethers.js、测试用的 chai 等。这些“依赖”就像盖房子需要的“砖头、水泥”,不能自己从零写。
没有包管理器的话,你得手动去每个依赖的官网下载、解压、放到指定文件夹,还得注意版本匹配(比如 A 依赖需要 B 依赖的 1.0 版,你下了 2.0 版就会报错)。而 Yarn 会帮你:
- 自动识别项目需要的依赖(从项目的
package.json文件读取); - 一键下载所有依赖到项目的
node_modules文件夹; - 记录依赖的精确版本(生成
yarn.lock文件),确保你在自己电脑、别人电脑上跑的依赖版本完全一致,避免“我这能跑,你那跑不了”的问题。
二、Yarn 和 npm 的关系(为什么 DVDF 用 Yarn?)
- 同源:两者都是 Node.js 生态的包管理器,都从 npm 官方仓库(全球最大的 JS 依赖仓库)下载依赖;
- 差异:Yarn 是 Facebook 当年为了解决 npm 的痛点(比如下载慢、版本不一致、依赖重复)开发的,后来 npm 也借鉴了 Yarn 的优点,但很多项目(比如 DVDF)还是习惯用 Yarn,因为它的锁文件(
yarn.lock)更稳定,多人协作时不易出问题; - 互通性:对于 DVDF 这类项目,你用
yarn install和npm install本质上都能安装依赖,但项目的package.json里可能指定了用 Yarn 执行脚本(比如yarn unstoppable),所以用 Yarn 更贴合教程。
三、你在 DVDF 中会用到的 Yarn 核心命令(必记)
yarn install:进入项目目录后执行,下载package.json里列出的所有依赖(第一次克隆项目后必跑);yarn xxx:执行项目脚本(DVDF 已经写好的测试脚本),比如:yarn unstoppable:运行第一个“Unstoppable”挑战的测试(部署合约、执行攻击、验证结果);yarn other-challenge:后续其他挑战的脚本(比如yarn naive-receiver、yarn trigonometry等);
yarn add 依赖名:如果后续你自己写攻击合约,需要额外安装依赖(比如某个工具库)时用;yarn remove 依赖名:删除不需要的依赖。
总结
Yarn 就是一个“智能依赖管家”,专门帮 JS/TS 项目(包括区块链智能合约项目)处理第三方代码的下载、管理、版本一致性问题。你不用深入研究它的原理,只要记住“克隆 DVDF 后先跑 yarn install,然后用 yarn 挑战名 运行测试”,就能跟着视频教程顺利推进挑战~
问题 yarn unstoppable命令是什么意思
yarn unstoppable 是 Damn Vulnerable DEFI(DVDF)项目中预定义的“测试脚本命令”,核心作用是 一键执行“Unstoppable”挑战的完整流程——包括部署漏洞合约、执行攻击逻辑、验证攻击是否成功,最终告诉你“挑战是否破解”。
结合你之前看的视频和项目背景,用通俗的方式拆解:
一、这个命令的本质:执行项目里写好的“自动化测试脚本”
DVDF 项目的 package.json 文件(项目配置文件)中,提前定义了一系列“脚本”,格式类似:
1 | |
所以 yarn unstoppable 本质是 通过 Yarn 调用这个预定义脚本,背后实际执行的是:hardhat test test/unstoppable.js
(补充:Hardhat 是区块链开发工具,用来编译合约、部署合约、运行测试,DVDF 项目的核心工具)
二、命令执行后会做什么?(完整流程)
运行 yarn unstoppable 后,终端会自动执行 test/unstoppable.js 文件里的所有代码,流程和视频里讲的完全一致:
- 环境初始化:启动一个本地测试区块链(Hardhat 内置的“虚拟区块链”,不用连真实以太坊网络);
- 合约部署:
- 部署
DVD代币合约(创建 100 万枚代币,分配给资金池); - 部署漏洞合约
UnstoppableLender(资金池合约,持有 100 万 DVD 代币,提供闪电贷); - 给攻击者地址分配 100 枚 DVD 代币(符合挑战初始条件);
- 部署
- 执行攻击逻辑:脚本里已经写好了视频中讲的“攻击代码”——调用
DVD代币的transfer函数,把攻击者的 1 枚代币直接转入UnstoppableLender合约(绕过depositToken函数,导致poolBalance和实际余额不一致); - 验证攻击结果:
- 尝试调用
UnstoppableLender的flashLoan函数(模拟正常用户申请闪电贷); - 因为断言
poolBalance == balanceBefore失败,交易回滚,说明资金池被“拒绝服务”,攻击成功;
- 尝试调用
- 输出结果:终端会显示
✓ Test passed(测试通过),证明挑战破解成功;如果失败会显示错误信息(比如漏洞没利用成功,flashLoan还能正常调用)。
三、关键注意点
- **必须先执行
yarn install**:yarn unstoppable依赖 Hardhat、ethers.js 等工具(项目依赖),如果没安装依赖,会报错“找不到 hardhat”或“找不到模块”; - 不用手动写攻击代码:DVDF 的测试脚本里已经包含了攻击逻辑(视频里讲的“直接转代币”),你只需要运行命令,就能看到漏洞利用的完整过程;
- 可以修改脚本调试:如果想自己尝试其他攻击方式,比如转 10 枚代币而不是 1 枚,或者验证“正常存款是否会触发漏洞”,可以打开
test/unstoppable.js文件,修改里面的攻击代码,再重新运行yarn unstoppable验证效果。
总结
yarn unstoppable 就是 DVDF 为“Unstoppable”挑战提供的 “一键运行测试”快捷命令——它帮你省去了手动部署合约、调用函数的繁琐步骤,自动完成“环境搭建 → 漏洞利用 → 结果验证”的全流程,让你直观看到漏洞如何被利用,以及挑战是否破解成功。
后续其他挑战(比如 naive-receiver、trigonometry 等),也会用 yarn 挑战名 的方式运行,逻辑完全一样~
Damn Vulnerable DeFi的介绍
Damn Vulnerable DeFi
Damn Vulnerable DeFi 是一个为开发者、安全研究人员和教育者提供的智能合约安全练习平台。
这是有史以来最复杂的易受攻击的 Solidity 智能合约集合,它包括闪电贷、价格预言机、治理、NFTs、去中心化交易所(DEX)、借贷池、智能合约钱包、时间锁、金库、元交易、代币分发、可升级性等。
使用 Damn Vulnerable DeFi 来:
- 提升你的审计和漏洞挖掘技能。
- 学习如何在实际场景中检测、测试和修复缺陷,成为一名具有安全意识的开发者。
- 基准智能合约安全工具。
- 创作智能合约安全相关的教育内容,例如文章、教程、演讲、课程、研讨会、培训、CTF 等。
安装
- 克隆仓库。
- 检出最新版本(例如,
git checkout v4.1.0)。 - 将
.env.sample文件重命名为.env并添加有效的 RPC URL。仅当挑战需要复制主网状态时,才需要此步骤。 - 安装 Foundry,或使用提供的 devcontainer(在 VSCode 中,通过命令 “Devcontainer: Open Folder in Container…” 打开该仓库作为 devcontainer)。
- 运行
forge build来初始化项目。
使用
每个挑战包括:
- 位于
src/<challenge-name>/README.md的提示。 - 位于
src/<challenge-name>/中的一组合约。 - 位于
test/<challenge-name>/<ChallengeName>.t.sol的 Foundry 测试。
要解决一个挑战:
- 阅读挑战的提示。
- 揭示挑战智能合约中的缺陷。
- 在相应的测试文件中编写解决方案。
- 使用
forge test --mp test/<challenge-name>/<ChallengeName>.t.sol尝试你的解决方案。
对于限制交易次数的挑战,你可能需要使用 --isolate 标志来运行测试。
如果测试通过,你就解决了这个挑战!
挑战可能有不止一种解决方案。
规则
- 必须始终使用玩家账户。
- 不得修改挑战的初始或最终条件。
- 你可以编写并部署你自己的智能合约。
- 必要时,你可以使用 Foundry 的 cheatcodes 来推进时间。
- 你可以导入未安装的外部库,尽管通常不需要。
故障排除
你可以在讨论区向社区寻求帮助。
免责声明
本仓库中的所有代码、实践和模式都是极其脆弱的,仅供教育用途。
不要在生产环境中使用。
问题 Damn Vulnerable DeFi好像是用fountry去测试,而不是hardhat去测试?
你观察得很准!Damn Vulnerable DeFi(DVDF)的新版本(v4+)确实默认用 Foundry 作为测试框架,而不是旧版本的 Hardhat——这也是你之前用 hardhat test 一直报错的核心原因之一!
之前我们按旧版本的 Hardhat 思路折腾,完全走偏了方向,现在纠正过来:先理清 Foundry 和 Hardhat 的区别,再用 Foundry 正确运行挑战。
一、先明确:DVDF 新旧版本的测试框架差异
| 版本 | 默认测试框架 | 测试文件格式 | 运行命令 |
|---|---|---|---|
| 旧版本(v2.x/v3.x) | Hardhat(JavaScript/TypeScript) | 单个 .js/.ts 文件(如 unstoppable.js) |
yarn unstoppable 或 npx hardhat test |
| 新版本(v4.x+) | Foundry(Solidity 原生测试) | 测试文件夹(如 test/unstoppable/)+ Solidity 测试文件(.t.sol) |
forge test(Foundry 命令) |
简单说:新版本 DVDF 弃用了 Hardhat,改用 Foundry 写测试——所以你用 Hardhat 命令跑 Foundry 格式的测试文件,自然会报错“找不到模块”“测试入口错误”。
二、什么是 Foundry?为什么 DVDF 要用它?
Foundry 是一个 Solidity 原生的区块链开发/测试框架,和 Hardhat 的核心区别:
- 测试语言不同:Hardhat 用 JavaScript/TypeScript 写测试脚本;Foundry 直接用 Solidity 写测试(
.t.sol文件),不用切换语言,对智能合约开发者更友好; - 测试速度更快:Foundry 是 Rust 编写的,执行效率比 Hardhat 高很多,尤其适合复杂的 DeFi 合约测试;
- 交互更直观:测试逻辑直接用 Solidity 调用合约函数,和实际合约交互逻辑完全一致,不用写 ethers.js 等工具的调用代码。
DVDF 新版本切换到 Foundry,是因为它更贴合“智能合约安全测试”的场景——漏洞分析和攻击逻辑都用 Solidity 实现,更接近真实黑客攻击的流程。
三、现在解决问题:用 Foundry 运行 Unstoppable 挑战
核心步骤:安装 Foundry → 用 Foundry 命令运行测试(不用再管 Hardhat 和 Yarn 脚本了)。
第一步:安装 Foundry(Linux/Kali 系统)
按 Foundry 官方教程安装,步骤简单:
1 | |
验证安装成功:
1 | |
第二步:进入 DVDF 项目目录,用 Foundry 运行测试
Foundry 的核心测试命令是 forge test,可以指定测试文件夹/文件运行:
1 | |
--match-path test/unstoppable/*:只运行unstoppable文件夹下的所有测试(避免跑其他挑战);-vv:显示详细测试日志(能看到合约部署、攻击执行、断言结果),方便观察漏洞利用过程。
四、关键说明:Foundry 测试的核心逻辑(和视频教程对应)
新版本 DVDF 的 test/unstoppable/ 文件夹里,通常有两个关键文件:
UnstoppableLender.sol:漏洞合约(和视频里的一致,提供闪电贷,有poolBalance断言漏洞);Unstoppable.t.sol:Foundry 测试文件(Solidity 编写),核心逻辑和视频一致:- 部署
DVD代币、UnstoppableLender资金池; - 给攻击者分配 100 枚
DVD; - 攻击逻辑:调用
DVD.transfer直接转 1 枚代币到资金池(绕过depositToken); - 验证:尝试调用
flashLoan,断言交易回滚(证明攻击成功)。
- 部署
运行 forge test 后,终端会输出:
1 | |
PASS 表示测试通过,攻击成功!
五、如果仍想使用 Hardhat(贴合旧视频教程)
如果你的视频教程是基于旧版本 DVDF(用 Hardhat),不想学 Foundry,还是按之前的“降级方案”来:
1 | |
总结
你发现的“用 Foundry 测试”是关键!之前的所有报错,本质是“用 Hardhat 命令跑 Foundry 格式的测试文件”导致的不兼容。
现在的选择:
- 想学新版本、贴合当前 DVDF 主流用法 → 安装 Foundry,用
forge test --match-path test/unstoppable/* -vv运行挑战; - 想贴合旧视频教程、省时间 → 降级到 v2.5.0,用 Hardhat +
yarn unstoppable运行。
两种方案都能成功,按你的学习需求选择即可~ 若安装 Foundry 或运行 forge test 时遇到问题,随时告诉我!