solidity 中 Eth 和 Usd 到底如何转换
在Solidity中通过预言机(Oracle)实现ETH与USD的换算,核心是利用预言机提供的实时ETH/USD价格数据,结合整数运算处理精度问题。以下是详细步骤和代码示例,带你从零实现。<理解预言机的同学可以先看第五点>
一、核心原理回顾
- 预言机的作用:提供ETH与USD的实时汇率(如1 ETH = 2000.12345678 USD),但返回的是放大后的整数(如200012345678,放大了1e8倍,保留8位小数)。
- 单位转换:ETH在链上以
wei
为最小单位(1 ETH = 1e18 wei),USD通常以“美元分”或“美元单位”计算(需明确精度,如1 USD = 1e18单位,避免小数)。 - 运算逻辑:利用整数乘法和除法处理换算,避免小数运算(Solidity不直接支持小数)。
二、准备工作:选择预言机
最常用的是Chainlink预言机,它提供标准化的价格接口AggregatorV3Interface
。不同网络的预言机地址不同(如以太坊主网、Sepolia测试网等),需提前查询(Chainlink地址列表)。
以Sepolia测试网的ETH/USD价格预言机为例,地址为:0x694AA1769357215DE4FAC081bf1f309aDC325306
。
三、完整实现步骤
1. 引入预言机接口
Chainlink的AggregatorV3Interface
定义了获取价格的方法,需导入或直接定义接口。
2. 初始化预言机
在合约构造函数中,传入预言机地址,初始化接口实例。
3. 获取实时ETH/USD价格
调用预言机的latestRoundData()
方法,获取放大后的价格(整数),并检查数据新鲜度(避免使用过时价格)。
4. 实现ETH转USD的函数
已知ETH数量(以wei为单位),计算对应的USD金额。
5. 实现USD转ETH的函数
已知USD金额,计算对应的ETH数量(以wei为单位)。
四、代码示例(附详细注释)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;// 引入Chainlink预言机接口(或直接定义)
interface AggregatorV3Interface {function latestRoundData()externalviewreturns (uint80 roundId, // 轮次IDint256 answer, // 价格(放大后的整数)uint256 startedAt, // 开始时间uint256 updatedAt, // 更新时间uint80 answeredInRound // 回答轮次);
}contract EthUsdConverter {// 预言机实例(ETH/USD价格源)AggregatorV3Interface public priceFeed;// 常量定义(精度控制)uint256 public constant ETH_DECIMALS = 1e18; // 1 ETH = 1e18 weiuint256 public constant PRICE_DECIMALS = 1e8; // 预言机价格放大倍数(8位小数)uint256 public constant USD_DECIMALS = 1e18; // 假设USD以1e18为单位(可根据需求调整)// 构造函数:初始化预言机(Sepolia测试网ETH/USD地址)constructor() {priceFeed = AggregatorV3Interface(0x694AA1769357215DE4FAC081bf1f309aDC325306);}/*** 内部函数:获取最新ETH/USD价格(放大后的整数,如200012345678)* 并检查价格是否新鲜(1小时内更新)*/function getLatestEthUsdPrice() internal view returns (uint256) {(, int256 price,, uint256 updatedAt,) = priceFeed.latestRoundData();// 检查价格是否过时(超过1小时)require(updatedAt > block.timestamp - 3600, "Price is stale");// 确保价格为正数require(price > 0, "Invalid price");return uint256(price);}/*** 功能1:ETH转USD(输入wei,返回USD单位)* 公式:USD = (ETH_wei × 预言机价格) ÷ (ETH_DECIMALS × PRICE_DECIMALS)*/function ethToUsd(uint256 ethWei) external view returns (uint256) {uint256 ethUsdPrice = getLatestEthUsdPrice(); // 预言机价格(放大1e8后)// 计算:(ethWei * 价格) / (1e18 * 1e8) → 转换为USDuint256 usd = (ethWei * ethUsdPrice) / (ETH_DECIMALS * PRICE_DECIMALS);return usd * USD_DECIMALS; // 按USD精度返回(可选)}/*** 功能2:USD转ETH(输入USD单位,返回wei)* 公式:ETH_wei = (USD × ETH_DECIMALS × PRICE_DECIMALS) ÷ (预言机价格 × USD_DECIMALS)*/function usdToEth(uint256 usd) external view returns (uint256) {uint256 ethUsdPrice = getLatestEthUsdPrice(); // 预言机价格(放大1e8后)// 计算:(usd * 1e18 * 1e8) / (价格 * 1e18) → 简化为 (usd * 1e8) / 价格uint256 ethWei = (usd * PRICE_DECIMALS) / ethUsdPrice;return ethWei;}
}
五、关键公式解析
1. ETH转USD(已知ETH数量,求USD)
- 现实公式:
USD金额 = ETH数量(ETH) × ETH/USD价格(USD/ETH)
- 链上转换(ETH以wei为单位):
ETH数量(ETH)= ethWei ÷ 1e18
(将wei转为ETH)ETH/USD价格 = 预言机价格 ÷ 1e8
(将放大后的整数转为实际价格)- 合并得:
USD = (ethWei × 预言机价格) ÷ (1e18 × 1e8)
2. USD转ETH(已知USD金额,求ETH)
- 现实公式:
ETH数量(ETH)= USD金额 ÷ ETH/USD价格(USD/ETH)
- 链上转换(ETH以wei为单位):
ETH数量(wei)= ETH数量(ETH) × 1e18
- 合并得:
ETH_wei = (USD金额 × 1e18 × 1e8) ÷ 预言机价格
六、测试与验证
假设预言机返回的ETH/USD价格为200012345678
(即2000.12345678 USD/ETH):
-
测试
ethToUsd(1e18)
(1 ETH):
计算:(1e18 × 200012345678) ÷ (1e18 × 1e8) = 200012345678 ÷ 1e8 = 2000.12345678
→ 返回2000.12345678 USD(按USD_DECIMALS转换后为对应整数)。 -
测试
usdToEth(200012345678)
(2000.12345678 USD):
计算:(200012345678 × 1e8) ÷ 200012345678 = 1e8
→ 1e8 wei?不,这里需要注意USD的单位:如果USD_DECIMALS是1e18,实际输入的USD应为2000.12345678 × 1e18,计算后得到1e18 wei(1 ETH)。
七、注意事项
- 价格新鲜度:必须检查
updatedAt
,避免使用过时价格(如超过1小时)。 - 精度匹配:根据业务需求调整
USD_DECIMALS
(如1 USD = 1e6单位表示“分”)。 - 异常处理:确保预言机返回的价格为正数,避免计算错误。
- 网络适配:不同网络的预言机地址不同(如主网与测试网),需对应修改。
通过以上步骤,你可以在Solidity中利用预言机实现ETH与USD的精准换算,核心是理解“放大倍数”和“整数运算”的逻辑,避免小数误差。