Dapp-Learning 实战:基于 Hardhat 组合 Aave V3 与 Uniswap V3 构建一键做多/做空杠杆合约

示例工程区块链【免费下载链接】Dapp-LearningDapp learning project for developers at all stages. Becoming and cultivating sovereign individuals. Nonprofit organization.项目地址https://gitcode.com/gh_mirrors/da/Dapp-Learning点击查看免费下载导读本文以 Dapp-Learning 仓库中的 21-aave-uni-loan 样例项目为主线讲解如何用 Hardhat 测试框架驱动一个名为AaveApe的聚合合约它在同一笔交易内完成AAVE 质押 → AAVE 借贷 → Uniswap V3 兑换 → 再次存入 AAVE的闭环从而对两种资产同时实现做多与做空并通过闪电贷一键赎回平仓。读完本文你将掌握 AAVE V3 的 Pool Addresses Provider 入口、Credit Delegation 授权机制、Uniswap V3 SwapRouter 的 exactInputSingle/exactOutputSingle 调用以及基于主网 fork 的 Hardhat 测试与利息查询脚本的完整实战方案。一、项目背景为什么需要 AaveApeDeFi 中借贷 兑换是两个独立协议能力普通用户需要分多笔交易才能完成杠杆操作既费 Gas 又暴露中间状态风险。AaveApe 的思路是把它们组合进一个合约AAVE负责资产的存入supply与借出borrow提供杠杆的资金来源Uniswap负责资产兑换把借来的资产换成想要做多的资产Hardhat负责开发、部署、主网 fork 测试与脚本运行。从仓库目录结构可以清晰看到项目的完整组成contracts合约与接口、ignition/modules部署模块、scripts借贷/查询脚本、test主网 fork 测试。四个核心合约文件为 AaveApe.sol、AaveApePlus.sol、AaveApePlusV2.sol 与公共基类 AaveUniswapBase.sol分别对应基础版Uniswap 闪电兑换版Balancer ParaSwap 聚合版三档实现。二、合约交互入口两个协议的总机2.1 AAVE V3Pool Addresses ProviderAAVE V3 的交互入口是Pool Addresses Provider地址供应者。之所以不直接写死 Pool 地址是因为 AAVE 会通过升级 Pool / PoolDataProvider / PriceOracle 合约来修复 Bug而 Addresses Provider 可以动态返回这三个合约的最新地址集成方无需改动代码。三个核心合约职责如下合约职责Pool负责 存入supply/ 借贷borrow/ 闪电贷flashLoanPoolDataProvider提供 用户 / 池子 中相关的借贷信息余额、利率、配置PriceOracle价格预言机返回资产的 USD 报价基类 AaveUniswapBase.sol 在构造函数中固化ADDRESSES_PROVIDER并提供三个封装函数按需取最新地址LENDING_POOL()调用ADDRESSES_PROVIDER.getPool()拿到当前 Pool 代理地址并转成IPool接口getPriceOracle()getPriceOracle()返回价格预言机getProtocolDataProvider()getPoolDataProvider()返回数据提供者。对应接口定义见 IPoolAddressesProvider.sol 与 IPool.sol。2.2 Uniswap V3SwapRouterUniswap V3 的交互入口是SwapRouter通过它可以完成与 Uniswap V3 的所有交互单跳/多跳兑换。本仓库使用的接口为 ISwapRouter.sol其中两个关键方法exactInputSingle(ExactInputSingleParams)精确输入、按路径滑点输出最多数量用于做多时把借出的 B 全部换成 AexactOutputSingle(ExactOutputSingleParams)精确输出、输入尽量少的数量用于赎回时用 A 精确凑够偿还 B 的数额。两个结构体的字段包括tokenIn / tokenOut / fee / recipient / deadline / amountIn / amountOutMinimum或amountOut / amountInMaximum以及sqrtPriceLimitX96这些参数在 AaveApe 的ape与closePosition中均有完整体现。三、功能要点四个基础能力组合出杠杆策略AaveApe 合约主要有四个功能质押资产到 AAVEsupply从 AAVE 进行借贷borrow含 Credit Delegation到 Uniswap 进行资产置换swap从 AAVE 进行闪电贷flashLoan通过组合这四个功能可以实现自动做多、做空以及赎回平仓。3.1 做多同时做空另一种资产假设你有两种资产其中资产 A 想要做多资产 B 想要做空。Ape 合约在一笔交易中同时完成根据用户当前在 AAVE 质押的资产 A 的价值计算可借的最大数额的资产 B调用getAvailableBorrowInAsset从 AAVE 借贷资产 B_lendingPool.borrow(...)onBehalfOf为用户地址通过 Uniswap V3 把借出的资产 B 全部兑换为资产 A把兑换出的资产 A 继续存入 AAVE_lendingPool.supply(...)抵押物增加循环后可继续借更多 B。3.2 做空从 AAVE 借出资产 B 后Ape 通过 Uniswap V3 将 B 全部兑换为 A再把 A 存入 AAVE 作为抵押。若 B 相对 A 贬值赎回平仓时归还的 B 变少剩余 A 即为做空 B 的收益。3.3 赎回unwindApe通过 AAVE V3 的闪电贷借入偿还债务所需的 B在回调executeOperation内完成用抵押的 aToken 从 AAVE 取回 A → Uniswap 将 A 换成 B → 归还 AAVE 债务与闪电贷本金 手续费若有多余的 A 则再次为用户存入 AAVE。详细实现见下文源码剖析。3.4 前置条件Credit Delegation 授权需要注意在从 AAVE 中借贷资产 B时需要用户预先授权 Ape 合约使 Ape 能以用户名义借贷这就是 AAVE 的Credit Delegation信用委托机制。用户需要对目标资产的债务代币StableDebtToken / VariableDebtToken调用approveDelegation(aaveApeAddress, amount)。在 scripts/loan.js 与测试脚本中delegateCreditToTheApe正是通过assetDebtTokenapproveDelegation完成无限额委托。四、源码级实现剖析AaveApe 的完整调用链4.1 基类AaveUniswapBaseAaveUniswapBase.sol 是所有版本共用的基类持有三个 immutable 状态IPoolAddressesProvider public immutable ADDRESSES_PROVIDER; ISwapRouter public immutable UNISWAP_ROUTER; address public immutable UNISWAP_ROUTER_ADDRESS;构造函数接收lendingPoolAddressesProviderAddress与uniswapRouterAddress两个地址AaveApe的构造函数原样透传见 AaveApe.sol。4.2 可借额度计算getAvailableBorrowInAssetAaveApe.sol 中function getAvailableBorrowInAsset(address borrowAsset, address ape) public view returns (uint256) { // availableBorrowsBase V3 USD based (, , uint256 availableBorrowsBase, , , ) LENDING_POOL().getUserAccountData(ape); return getAssetAmount(borrowAsset, availableBorrowsBase); }getUserAccountData返回的第三项availableBorrowsBase是 AAVE V3 以 USD8 位精度计的可借额度getAssetAmount则通过预言机价格与资产 decimals 换算成目标资产数量uint256 assetAmount amountIn * 10**decimals / assetPrice;4.3 开仓主流程ape 函数AaveApe.sol 的ape(apeAsset, borrowAsset, interestRateMode)完整展示了四个步骤的调用链getAvailableBorrowInAsset计算最大可借量无额度时require(borrowAmount 0, Requires credit on Aave!)直接回滚_lendingPool.borrow(borrowAsset, borrowAmount, interestRateMode, 0, msg.sender)以用户名义借出 BIERC20(borrowAsset).approve(UNISWAP_ROUTER_ADDRESS, borrowAmount)授权 Router构造ISwapRouter.ExactInputSingleParams调用exactInputSinglefee由getBestPool(borrowAsset, apeAsset).fee()动态选择amountOutMinimum: 0、sqrtPriceLimitX96: 0不做价格保护示例演示用途授权 Pool 后_lendingPool.supply(apeAsset, outputAmount, msg.sender, 0)将兑换出的 A 存入 AAVE抵押物增长发出Ape事件记录开仓明细。superApe则在for循环中重复调用ape实现多次杠杆循环looping。4.4 池子选择getBestPoolUniswap V3 同一交易对存在多个不同费率池子。getBestPoolAaveApe.sol遍历v3Fees [100, 500, 3000, 10000]四档费率通过IUniswapV3Factory(0x1F98431c8aD98523631AE4a59f267346ea31F984)所有链通用常量地址的getPool(token0, token1, fee)查询池子并挑选liquidity()最大者作为最优流动性池。测试用例get max liquidity pool of WEH/DAI断言 WETH/DAI 一定存在非零地址池子见 test_aave_ape.js。4.5 闪电贷平仓unwindApe executeOperation平仓链路分两步第一步unwindApeAaveApe.sol通过getProtocolDataProvider().getUserReserveData(borrowAsset, msg.sender)读取用户的 stableDebt / variableDebt按interestRateMode1稳定2浮动确定repayAmount无债务时require(repayAmount 0, Requires debt on Aave!)构造flashLoan(receiverAddress, assets, amounts, modes[0], onBehalfOfaddress(this), paramsabi.encode(msg.sender, apeAsset, interestRateMode), referralCode0)发起闪电贷params中编码了真正需要平仓的用户地址。第二步回调executeOperationAaveApe.sol双重校验msg.sender ADDRESSES_PROVIDER.getPool()且initiator address(this)防止他人伪造回调计算amountOwing repayAmount premiums[0]本金 闪电贷手续费abi.decode(params, (address, address, uint256))还原用户与资产信息后调用内部函数closePosition。内部函数closePositionAaveApe.sol顺序执行授权 Pool 并用_lendingPool.repay(borrowAsset, repayAmount, rateMode, ape)归还 AAVE 债务计算可提取抵押取可借额度换算值与用户 aToken 余额的较小者_aToken.transferFrom(ape, address(this), maxCollateralAmount)将用户的 aToken 转入合约再_lendingPool.withdraw(apeAsset, maxCollateralAmount, address(this))取回 A授权 Router 后调用exactOutputSingleamountOut amountOwing、amountInMaximum maxCollateralAmount精确兑换出足够的 BleftoverAmount maxCollateralAmount - amountIn若有剩余 A 则_lendingPool.supply(apeAsset, leftoverAmount, ape, 0)为用户存回 AAVE授权 Pool 以归还闪电贷本金 手续费发出Ape事件标记平仓完成。测试 test_aave_ape.js 完整覆盖了这些分支无抵押回滚、未授权回滚、未给 aToken 授权回滚、抵押不足回滚以及存入 5 ETH → 委托信用 → ape → approve aToken → unwindApe后aBalanceAfter aBalanceBefore且debtBalanceAfter 0的成功路径。五、进阶版本AaveApePlus 与 AaveApePlusV25.1 AaveApePlusUniswap V3 Flash Swap 免手续费杠杆AaveApePlus.sol 把兑换从 Router 调用升级为Uniswap V3 池内 flash swap先借资产后结算省去对 Router 的授权步骤并引入滑点保护与健康因子检查flashApe(apeAsset, borrowAsset, borrowAmount, interestRateMode)L30-L60根据pool.token0() borrowAsset决定zeroForOne方向用TickMath.MIN_SQRT_RATIO 1 / MAX_SQRT_RATIO - 1作为价格极限调用pool.swap(...)完成借贷 兑换 抵押三步最后require(newHealthFactor 1e18, health factor 1!)校验用户健康因子uniswapV3SwapCallbackL149-L198是 Uniswap V3 的回调入口根据data中解码出的isFlashUnwind标志区分开仓/平仓开仓时把换得的 Asupply进 AAVE 并borrow出 B 还给池子平仓时先repayAAVE 债务、transferFrom用户的 aToken 并withdraw再用 A 归还 flash swapflashUnwindL62-L126中apeAssetToDebtAmount apeAssetToDebtAmount - apeAssetToDebtAmount.percentMul(pool.fee() / 100 50)显式预留了 0.3% 池子手续费 0.5% 滑点缓冲。测试见 test_aave_ape_plus.js其中还包含两种 ape 资产、赎回金额超过单一抵押物的场景先 WETH 换 WBTC 再质押 WBTC 做多再用 WBTC 抵押物平仓 DAI 债务。5.2 AaveApePlusV2Balancer V2 闪电贷 ParaSwap 聚合兑换AaveApePlusV2.sol 是更贴近生产环境的实现闪电贷来源可切换_checkVaultLiquidity先检查 Balancer V2 Vault常量地址0xBA12222222228d8Ba445958a75a0704d566BF2C8所有链通用流动性是否足够够则走vault.flashLoan不够则回退 AAVEflashLoanL135-L161因此实现了receiveFlashLoan与executeOperation双回调兑换走ParaSwap Augustus_paraSwap校验AUGUSTUS_REGISTRY.isValidAugustus后对getTokenTransferProxy授权再address(augustus).call(psp.swapCallData)执行离线聚合报价的 calldata失败时用 assembly 原样回滚 revert 原因L164-L183构造函数接收augustusRegistry并通过require(!augustusRegistry.isValidAugustus(address(0)), ...)校验注册表有效性getMaxCollateralAmount在可换得抵押物基础上再上浮 3% 作为缓冲assetAmount * 103 / 100。测试 test_aave_ape_plus_v2.js 预先硬编码了两段 ParaSwap calldataDAI→WETH 与 WETH→DAI并专门用一个crvUSD场景验证Balancer Vault 流动性不足时回退 AAVE 闪电贷的分支。六、操作步骤从部署到查询利息6.1 准备环境变量项目通过dotenv读取.env。原文档给出的初始化命令为cp .env.example .env需要配置的环境变量及用途与 hardhat.config.js 中process.env的引用一一对应环境变量用途ETHERSCAN_API_KEY用于合约验证etherscan.verifyINFURA_ID用于连接各以太坊网络ropsten/kovan/main/optimism 等ALCHEMY_IDPolygon 网络 RPCpolygon-mainnet.g.alchemy.com原文档说明在 Polygon 网络借贷时发现 Infura 网络延迟导致交易失败因此改用 Alchemy 验证PRIVATE_KEY用于发送交易各网络accounts数组TARGET_ADDRESS目标用户地址query.js用它查询该用户在 AAVE 上借贷所支付的所有利息6.2 部署合约// deploy aaveape npx hardhat ignition deploy ./ignition/modules/AaveApe.js --network maticIgnition 部署模块 AaveApe.js 会先检查当前网络是否存在于hardhat.config.js的networkAddressMapping中不存在则抛错提示添加配置然后从映射中取出lendingPoolAddressesProviderAddress与uniswapRouterAddress作为AaveApe构造函数参数完成部署。AaveApePlus.js、AaveApePlusV2.js部署模块结构相同其中 V2 传入的是augustusRegistryAddress。6.3 验证合约// contract verify npx hardhat verify --network matic 0x4699f609F4FD97A3cf74CB63EFf5cd1200Dfe3dA 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb 0xE592427A0AEce92De3Edee1F18E0157C05861564验证命令需要在构造函数参数中提供两个地址AAVE V3 的 Pool Addresses Provider 与 Uniswap V3 SwapRouter。各网络的这两个地址均配置在 hardhat.config.js 的networkAddressMapping中例如 Polygonmatic上为0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb与0xE592427A0AEce92De3Edee1F18E0157C05861564主网与 localhost 的 Provider 地址为0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9eOptimism 与 matic 相同。6.4 进行借贷// open max position on aave npx hardhat run scripts/loan.js --network maticscripts/loan.js 的完整流程为通过 WETH GatewayIWrappedTokenGatewayV3depositETH存入 0.1 ETH 作为初始抵押对 DAI 的浮动债务代币执行approveDelegation委托信用给 AaveApe调用aaveApeflashApe, 2)借贷 1000 DAI注意脚本实际调用的是升级版AaveApePlus的 flashApe注释中保留了ape与superApe的调用示例打印开仓前后 WETH 的 aToken 余额与 DAI 债务余额授权 aToken 后调用flashUnwind平仓验证债务清零最后通过withdrawETH取回 ETH。6.5 查询用户支付利息总额npx hardhat run scripts/query.js --network matic需要注意原文档强调应在 matic 上运行本脚本因为 matic 上所有可借贷币种的 APY 均使用浮动 APY如果使用其他网络需要修改代码中计算 interest部分传入getDebtToken接口的参数利率模式。scripts/query.js 的数据来源有两路链上通过getUserAccountData打印健康因子healthFactor、总抵押totalCollateralBase、清算阈值、LTV通过getReserveData打印 DAI 的浮动借贷利率、存款利率与借贷指数通过getAvailableBorrowInAsset打印用户可借 DAI 的 USD 价值TheGraph 子图脚本内置 GraphQL 查询querySql按用户地址拉取borrowHistory与repayHistory并按url映射matic / main / optimism 三个子图端点汇总。利息的计算公式为利息 累计已还(repay) 当前债务(currentDebt) - 累计已借(borrow)其中currentDebt通过对应债务代币的balanceOf实链读取最终按币种 decimals 归一化输出current total interest。6.6 主网 fork 测试hardhat.config.js 的hardhat网络配置了主网 forkingRPC 使用 Alchemy 主网端点三个测试文件 test_aave_ape.js、test_aave_ape_plus.js、test_aave_ape_plus_v2.js 均在 fork 出的主网状态上运行合约直接部署、networkAddressMapping中的地址真实可用、WETH/DAI/USDC/WBTC 池子真实存在因此可以端到端验证借贷、兑换、闪电贷全流程而不消耗真实资金。此外 package.json 依赖nomicfoundation/hardhat-toolbox、hardhat ^2.22.2、uniswap/v3-core、axios与graphql其中uniswap/v3-core为 ISwapRouter 接口提供IUniswapV3SwapCallback等基础类型。七、安全注意事项与扩展方向从源码与测试中可以提炼出几条对实际开发有参考价值的经验闪电贷回调鉴权executeOperation/receiveFlashLoan必须同时校验msg.sender与initiator防止外部合约冒充发起方见 AaveApe.sol 与 AaveApePlusV2.sol滑点与手续费预留示例代码中amountOutMinimum: 0仅为教学简化生产环境应结合预言机报价设置最小输出AaveApePlus 中显式扣减池子手续费与 0.5% 缓冲、V2 中 3% 抵押缓冲都是更稳健的实践授权面最小化用户只需对 AaveApe 合约委托债务代币授权与 aToken 授权脚本中以ethers.MaxUint256一次性授权是演示简化实际可收敛到单次所需额度利率模式一致性interestRateMode1稳定、2浮动贯穿 borrow / repay / getDebtToken 全链路平仓与查询脚本必须保持一致否则债务无法正确匹配多链适配networkAddressMapping已内置 matic / optimism / main / localhost 四套地址hardhat.config.js部署新网络时只需补充 Provider、Router、WETH Gateway 与资产地址即可无需修改合约代码。结语本样例以不到两百行核心合约代码串起了 AAVE V3 借贷、Uniswap V3 兑换、闪电贷与信用委托四大 DeFi 原语并通过 Hardhat 主网 fork 测试完成了全链路验证。无论是想理解杠杆聚合器类似杠杆 farming / 循环借贷的底层逻辑还是想学习如何编写集成多个 DeFi 协议的合约21-aave-uni-loan 目录下的合约、脚本与测试都是可直接对照学习的完整范例。赞分享示例工程区块链【免费下载链接】Dapp-LearningDapp learning project for developers at all stages. Becoming and cultivating sovereign individuals. Nonprofit organization.项目地址https://gitcode.com/gh_mirrors/da/Dapp-Learning点击查看免费下载相关推荐Aave V3 闪电贷实战基于 Dapp-Learning 的合约开发与 Sepolia 测试网部署全解析Aave V3 闪电贷实战基于 Dapp Learning 的合约开发与 Sepolia 测试网部署全解析 闪电贷Flash Loan是无抵押借贷的经典示例工程区块链WTF Solidity 第 57 讲闪电贷Flashloan实战——Uniswap V2 / V3 与 AAVE V3 合约实现WTF Solidity 第 57 讲闪电贷Flashloan实战——Uniswap V2 / V3 与 AAVE V3 合约实现 本讲是 WTF Sol示例工程区块链教程Dapp-Learning 实战基于 Aave V3 闪电贷的无抵押借贷合约开发与 Sepolia 部署全流程Dapp Learning 实战基于 Aave V3 闪电贷的无抵押借贷合约开发与 Sepolia 部署全流程 本文是 Dapp Learning 仓库 ba示例工程区块链上一篇ctf-wiki 格式化字符串漏洞实战64 位偏移计算、GOT/返回地址劫持、栈迁移与无源码盲打下一篇Lesson overview创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
报考提示:本文涉及的批次、材料要求可能随上级文件调整,报名前建议再确认一次。你所在的工种、城市、当前进度如果拿不准,可以直接电话 18236992212 或在线预约,我们按你的情况单独捋一遍流程,不白跑。
证书真伪提醒:凡是说"不用考试直接拿证""花钱买证""包过免考"的,基本都是假证或骗局。正规特种作业操作证必须本人参考、本人答题,办下来的证在应急管理部官网、河南省厅平台都能查到电子记录。查不到的证,上岗被查到要担责任,千万别图省事。拿不准的,先打 18236992212 问一句。
报考流程

从咨询到拿证,六步走完

不管这篇资讯讲的是哪个工种,报名到取证的流程都是这六步,照着走不绕弯。

01

咨询定工种

说清岗位和单位要求,确认该考哪类证。

02

材料预审

按清单准备,拍照发来免费预审。

03

报名建档

提交报名信息,同步本批次窗口。

04

考前辅导

理论题库加实操要点针对性训练。

05

参加考试

理论机考加实操考核,按批次安排。

06

取证复审

查证领证,到期前提醒复审换证。

报名咨询前台接待

正规培训通道

走应急管理部门认可的报名与培训渠道,本人参考本人答题。

材料免费预审

报名前拍照发来逐项核对,缺什么错什么当场指出来。

批次提前通知

河南应急厅批次一有消息,第一时间同步报名学员。

费用透明无隐形

报名前把费用明细一次性说清,包含哪些、怎么收都写明。

电话咨询

18236992212,说清工种和城市,我们按你的情况给建议。

邮箱咨询

809451989@qq.com,材料拍照发来,免费预审。

在线预约

留下姓名、电话、工种,我们安排专人回访对接。

濮阳 / 许昌

两地设服务点,就近安排报名与考试对接。

常见问题

关于报考,常被问到的几个问题

看完这篇资讯,下面这些问题顺便一起答了。

我现在报名,大概多久能参加考试?

材料预审通过、报名建档后,一般排在最近的一个批次。具体时间取决于河南应急管理厅当期批次安排和机位,濮阳、许昌本地考点通常每月都有场次。报名时我们会告诉你本批次的报名截止时间和预计考试时间。

没有相关工作经验,能直接考吗?

大部分工种允许零基础报名,经正规培训后参考。部分岗位对学历、体检有要求,具体以工种对照条件为准。不确定自己符不符合的,先说说你的情况,我们帮你判断该报哪个。

考试没过可以补考吗?怎么收费?

理论和实操分别考核,单科不合格一般有补考机会,补考按当期批次重新排期。费用明细我们会在报名前一次性说清,没有隐形收费。

企业要一批人考证,能统一办理吗?

可以。建筑、化工、制造类企业批量申报走企业团报通道,统一建档、对公收费、台账整理一起办,安全管理员配套我们也能对接。

拿到证以后多久要复审?在哪复审?

特种作业操作证每 3 年复审一次,满 6 年需要换证。复审不必须回发证地,濮阳、许昌本地都能办,异地也能对接。建议提前一两个月开始准备,别等证书过期了才想起这件事。

怎么查自己的证是不是真的?

上应急管理部官网或河南省厅政务平台,输入身份证号和证件号就能查电子记录。查不到的、或者有人跟你说"不用考试直接拿证"的,基本都是假证,上岗被查到要担责任,别图省事吃这个亏。

整个下来大概要花多少钱?

不同工种费用不一样,跟培训课时、考试次数挂钩。我们会在报名前把费用明细一次性说清,包含哪些、不包含哪些写在明面上,没有隐形收费。补考另行排期,费用按当期标准走。

我条件好像不太够,还能考吗?

年龄、学历、体检这几项卡得最严,哪项差一点、怎么补,各工种要求不同。别自己猜,把你的情况说清楚——多大年龄、什么学历、有没有相关经验——我们帮你判断该报哪个工种、差的条件怎么补,能考就告诉你怎么考,不能考也不耽误你时间。

个人预约 / 企业团报

文章里没说清的,直接问我们

你的工种、城市、当前进度,说一句就行。材料、批次、费用按你的情况单独捋,不套模板。