Scroll 网络赎回失败与 Redstone Oracles 技术分析

  • Jesen
  • 发布于 16小时前
  • 阅读 92

本文以事故为核心,聚焦 Redstone Oracles 的技术细节、失败原因、解决方案及预防措施,结构清晰,注重知识点讲解。

在 Scroll 网络(Layer 2,链 ID:534352)上,我尝试通过疑似 Loanshark 的借贷协议(loanshark)赎回抵押的 0.023162 ETH,但调用 CETH 合约(地址:0xF017f9CF11558d143E603d56Ec81E4E3B6d39D7F)的 redeemredeemUnderlying 方法失败。通过 Tenderly 工具分析,错误源于 Redstone Oracles 的 _extractByteSizeOfUnsignedMetadata 函数,提示交易 calldata 缺少或包含无效的 Redstone payload。最终,我通过 JavaScript 脚本结合 Redstone 的 evm-connector 库成功赎回资产。

本文以事故为核心,聚焦 Redstone Oracles 的技术细节、失败原因、解决方案及预防措施,结构清晰,注重知识点讲解。

1. 事故背景与经过

1.1 事故描述

我在 Scroll 网络上通过借贷协议抵押了 0.023162 ETH,试图赎回时,通过 Scrollscan 调用 CETH 合约的 redeemredeemUnderlying 方法失败。Tenderly 分析显示错误发生在 Redstone Oracles 的 _extractByteSizeOfUnsignedMetadata 函数,提示 calldata 缺少有效 Redstone payload。最终,我通过脚本使用 Redstone 的 evm-connector 库成功赎回。

相关合约

  • CETH:0xF017f9CF11558d143E603d56Ec81E4E3B6d39D7F
  • Comptroller:0xEFB0697700E5c489073a9BDF7EF94a2B2bc884a5

1.2 时间线

  1. 发现问题:Loanshark 网站未显示市场信息,API(https://api.redstone.finance/prices?symbol=ETH&provider=redstone-rapid&limit=1)报错。
  2. 初次尝试:在 Scrollscan 手动调用 redeemredeemUnderlying,均失败。
  3. 社区求助:在 Discord 询问,未获有效解答,遭遇诈骗信息。
  4. 错误定位:Tenderly 追踪显示错误在 _extractByteSizeOfUnsignedMetadata
  5. 解决方案:编写脚本,调试位数和库版本问题,成功赎回。

2. Redstone Oracles 技术解析

2.1 Redstone Oracles 简介

Redstone Oracles 是一个去中心化预言机系统,用于将链下数据(如价格)注入智能合约。它通过在交易 calldata 末尾附加 payload 传递数据,适用于 DeFi 协议(如借贷、DEX),支持价格喂价、链下计算等。

2.2 Redstone Payload 结构

Redstone payload 是附加在 calldata 末尾的数据包,包含:

  • Redstone Marker:9 字节标识符(0x000002ed57011e0000),位于末尾。
  • Unsigned Metadata Size:3 字节(uint24),表示元数据字节数。
  • Unsigned Metadata:可变长度,包含额外信息(如数据来源),可能为空。
  • Data Packages
    • 签名(65 字节):验证数据真实性。
    • 数据点数量(3 字节):指定数据点个数。
    • 数据点值大小(4 字节):通常 32 字节。
    • 数据点
    • Data Feed ID(32 字节):如 keccak256("ETH/USD")
    • (32 字节):如价格(精度 1e8)。
    • 时间戳(6 字节):数据生成时间。
  • 数据包数量(2 字节):位于元数据之后。

示例

[...交易数据...][数据包][元数据][大小: 3字节][marker: 9字节]

数据包(ETH/USD):

[签名: 65字节][数据点数: 1][值大小: 32][ETH/USD ID][价格: 3000e8][时间戳]

2.3 _extractByteSizeOfUnsignedMetadata 函数详解

  • 功能:从 calldata 提取元数据大小,计算负偏移(calldataNegativeOffset),用于解析 payload。
  • 代码
    function _extractByteSizeOfUnsignedMetadata() internal pure returns (uint256) {
      bool hasValidRedstoneMarker;
      assembly {
          let calldataLast32Bytes := calldataload(sub(calldatasize(), 32))
          hasValidRedstoneMarker := eq(REDSTONE_MARKER_MASK, and(calldataLast32Bytes, REDSTONE_MARKER_MASK))
      }
      if (!hasValidRedstoneMarker) revert CalldataMustHaveValidPayload();
      uint24 unsignedMetadataByteSize;
      if (41 > msg.data.length) revert CalldataOverOrUnderFlow();
      assembly {
          unsignedMetadataByteSize := calldataload(sub(calldatasize(), 41))
      }
      uint256 calldataNegativeOffset = unsignedMetadataByteSize + 3 + 9;
      if (calldataNegativeOffset + 2 > msg.data.length) revert IncorrectUnsignedMetadataSize();
      return calldataNegativeOffset;
    }
  • 逻辑
    1. 检查 calldata 末尾是否含 Redstone marker。
    2. 从末尾倒数 41 字节提取元数据大小(uint24)。
    3. 计算负偏移:元数据大小 + 3 + 9
    4. 验证偏移有效性。
    5. 返回偏移量。
  • 错误
    • CalldataMustHaveValidPayload:无 marker。
    • CalldataOverOrUnderFlow:calldata 过短。
    • IncorrectUnsignedMetadataSize:偏移无效。

2.4 借贷协议中的 Redstone 应用

  • 作用ComptrollerredeemAllowed 函数依赖 Redstone 价格数据(如 ETH/USD),用于:
    • 计算赎回资产价值。
    • 验证抵押率(确保赎回后不低于最低要求)。
    • 检查市场流动性。
  • 流程
    1. CETH 调用 redeemredeemUnderlying
    2. 调用 Comptroller.redeemAllowed,通过 ProxyConnector 转发 calldata。
    3. ProxyConnector 使用 CalldataExtractor 解析 payload,提取价格。
    4. 无有效 payload,交易失败。

3. 事故原因分析

3.1 核心问题:缺少 Redstone Payload

  • 问题:在 Scrollscan 手动调用 redeem 时,未附加 Redstone payload,_extractByteSizeOfUnsignedMetadata 无法找到 marker,抛出 CalldataMustHaveValidPayload
  • 原因:Scrollscan 不支持自动附加 payload,需通过前端或脚本实现。
  • 影响Comptroller 无法获取价格数据,赎回验证失败。

3.2 次要问题:格式、签名与网络配置

  • 格式错误:payload 可能缺少 marker、无效元数据大小或数据点。
  • 签名问题:无效签名可能触发 SignerNotAuthorised
  • 时间戳问题:时间戳不一致或为零,可能抛出 DataPackageTimestampMustNotBeZeroDataPackageTimestampsMustBeEqual
  • 网络配置:Scroll 网络需特定 Redstone 数据提供者,API 报错(https://api.redstone.finance/prices)暗示配置问题。

3.3 Scroll 网络的特性

  • Layer 2 特性:低 gas 成本,但需适配 oracle 配置。
  • 手动调用局限:Scrollscan 仅支持基本调用,复杂交互需脚本或前端。

4. 解决方案

4.1 解决思路

  • 附加 Payload:使用 Redstone evm-connector 生成包含 ETH/USD 价格的 payload。
  • 网络配置:连接 Scroll 网络(RPC:https://rpc.scroll.io,链 ID:534352)。
  • 脚本自动化:处理 gas 限制、数据格式问题。

4.2 成功脚本解析

以下是成功赎回的脚本:

require('dotenv').config();
const ethers = require('ethers'); // 5.7.2
const { WrapperBuilder } = require('@redstone-finance/evm-connector'); // 0.7.3

const scrollRpcUrl = 'https://rpc.scroll.io';
const cethAddress = '0xF017f9CF11558d143E603d56Ec81E4E3B6d39D7F';
const cethAbi = ['function redeemUnderlying(uint redeemAmount) external returns (uint)'];
const redstoneConfig = {
  dataServiceId: 'redstone-primary-prod',
  uniqueSignersCount: 1,
  dataPackagesIds: ['ETH']
};

async function executeRedeem() {
  const provider = new ethers.providers.JsonRpcProvider(scrollRpcUrl);
  const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
  const cethContract = new ethers.Contract(cethAddress, cethAbi, signer);
  const wrappedCethContract = WrapperBuilder.wrap(cethContract).usingDataService(redstoneConfig);
  const tx = await wrappedCethContract.redeemUnderlying(ethers.utils.parseUnits('1', 18), { gasLimit: 1000000 });
  const receipt = await tx.wait();
  console.log('赎回成功! 交易哈希:', receipt.transactionHash);
}

executeRedeem().catch(console.error);

关键点

  • WrapperBuilder:自动附加包含 ETH/USD 价格的 payload。
  • 版本控制ethers@5.7.2evm-connector@0.7.3 确保兼容性。
  • 错误处理:验证网络、余额、合约地址,高 gas 限制(1000000)。

4.3 运行结果

  • 成功赎回 0.023162 ETH,交易哈希可在 Scrollscan 查看。
  • 脚本解决了 payload 缺失问题,满足 Comptroller 需求。

5. 关键知识点与预防措施

5.1 Redstone Oracles 核心知识

  • 数据注入:通过 calldata 附加 payload,高效传递链下数据。
  • 安全机制:签名和时间戳防止篡改和重放攻击。
  • 应用场景:价格喂价、链下计算、随机数生成。

5.2 借贷协议数据依赖

  • ComptrollerredeemAllowed 需 Redstone 价格数据验证赎回。
  • 无有效 payload,交易失败。

5.3 预防措施

  1. 使用 SDK:通过 evm-connector 自动附加 payload,避免手动调用。
  2. 验证配置:确保 feed ID(如 ETH)和数据服务(redstone-primary-prod)正确,参考 Redstone 文档.
  3. 测试网络:在 Scroll Sepolia 测试配置,参考 Scroll 文档.
  4. 调试工具
    • Scrollscan:查询合约和交易。
    • Tenderly:分析错误。
    • ethers.js:验证 calldata。
  5. 安全措施:保护私钥,警惕诈骗。

结论

事故原因:在 Scrollscan 手动调用 redeem 时,缺少 Redstone payload,导致 _extractByteSizeOfUnsignedMetadata 抛出错误。Comptroller 依赖价格数据验证赎回,无 payload 导致失败。

解决方案:使用 evm-connector 脚本生成 payload,成功调用 redeemUnderlying,赎回 ETH。

经验教训

  • DeFi 协议需正确配置预言机数据。
  • 手动调用复杂合约需谨慎,优先使用脚本。
  • 调试工具和 SDK 是解决问题关键。
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Jesen
Jesen
江湖只有他的大名,没有他的介绍。