Ethers BigNumber转USD计算结果异常,请求排查原因
以太坊转USD计算BigNumber结果异常问题
问题描述
将以太坊价值转换为USD法定货币价值时,计算结果不符合预期,问题源于BigNumber的计算逻辑。
尝试代码
const one = parseUnits("1"); const price = parseUnits("0.1"); const _rate = "1563.48"; const rate = parseUnits(_rate, 2); const usdPrice = price.lt(one) ? rate.mul(price) : rate.div(price);
结果对比
- 预期结果:
usdPrice = 156.348 - 实际结果:
usdPrice = 15634.8
问题原因
核心问题是parseUnits的小数位数不统一:
parseUnits("0.1")默认使用18位小数(对应以太坊wei单位),得到的是0.1 * 10^18的BigNumberparseUnits(_rate, 2)使用2位小数,得到的是1563.48 * 10^2的BigNumber
直接相乘时,结果为0.1*1563.48 * 10^(18+2) = 156.348 * 10^20,若直接转换为可读数值时未做对应位数的除法,就会得到15634.8(相当于把156.348 *10^20除以了10^18,忽略了rate的2位小数)。
修复方案
方案1:统一小数位数计算
将rate的小数位数改为18位,和以太坊单位保持一致,计算后通过除以one(即1*10^18)得到正确的USD数值:
const one = parseUnits("1"); const price = parseUnits("0.1"); const _rate = "1563.48"; const rate = parseUnits(_rate, 18); // 统一为18位小数 const usdPriceBigNumber = price.lt(one) ? rate.mul(price).div(one) : rate.div(price); // 转换为可读数值 const usdPrice = usdPriceBigNumber.div(parseUnits("1", 18)).toString();
方案2:计算后调整小数位数
直接计算后,除以10^(18+2)抵消两边的小数位放大:
const one = parseUnits("1"); const price = parseUnits("0.1"); const _rate = "1563.48"; const rate = parseUnits(_rate, 2); const decimalAdjust = parseUnits("1", 20); // 10^(18+2) const usdPriceBigNumber = price.lt(one) ? rate.mul(price).div(decimalAdjust) : rate.div(price).mul(parseUnits("1", 16)); // 转换为可读数值 const usdPrice = usdPriceBigNumber.toString();
方案3:先转换为实际数值再计算
先将price和rate转换为实际的ETH和USD/ETH数值,再进行计算,逻辑更直观:
const priceEth = parseUnits("0.1").div(parseUnits("1")); // 得到0.1的BigNumber表示 const rateUsdPerEth = parseUnits("1563.48", 2).div(parseUnits("1", 2)); // 得到1563.48的BigNumber表示 const usdPriceBigNumber = priceEth.mul(rateUsdPerEth); // 转换为可读数值 const usdPrice = usdPriceBigNumber.toString();
内容的提问来源于stack exchange,提问作者Xavier
相关产品推荐
相关产品推荐

