使用Rust模拟ethers.js中的parseUnits
Posted MateZero
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Rust模拟ethers.js中的parseUnits相关的知识,希望对你有一定的参考价值。
我们知道,在同以太坊区块链进行交互的编程语言中,javascript是最便捷的语言,没有之一。但是世界上的语言不只一种,我们有时也需要使用其它语言和以太坊区块链交互,例如Rust。为此,Rust中有一个crate叫web3,它其中有个类型U256来对应Solidity中的uint256。但是它却缺少了两个很常用的功能,就是去除精度后转化为人类易读的浮点数和它的反向操作。例如我们需要将值为500000000000000000精度为18的数显示为0.5
等。
在ethers.js中,提供了parseUnits和formatUnits这两个函数进行类似的操作,因此,作为学习Rust语言的一个练习 ,我们也模拟了这两个函数,代码如下:
convert.rs
///模仿ethers.js中的parseUnits和formatUnits
use std::error::Error;
use std::fmt;
use web3::types::U256;
#[derive(Debug)] // Allow the use of ":?" format specifier
pub enum ParseU256Error
FormatError,
DecimalsError,
// Allow the use of "" format specifier
impl fmt::Display for ParseU256Error
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
match *self
ParseU256Error::FormatError => write!(f, "Format Error!"),
ParseU256Error::DecimalsError => write!(f, "Decimals Error!"),
// 允许将此类型视为错误
impl Error for ParseU256Error
pub trait ParseFormat
type Error;
fn parse_units(source: &'static str, d: u32) -> Result<U256, Self::Error>;
fn format_units(&self, d: u32) -> Result<String, Self::Error>;
const ZEROS: &str = "000000000000000000";
impl ParseFormat for U256
type Error = ParseU256Error;
///直接将浮点字符串乘上精度转成U256
fn parse_units(source: &'static str, d: u32) -> Result<U256, ParseU256Error>
if d > 18
return Err(ParseU256Error::DecimalsError);
let decimals = U256::exp10(d as usize);
let strs: Vec<&str> = source.split(".").collect();
if strs.len() > 2
return Err(ParseU256Error::FormatError);
let inter = U256::from_dec_str(strs[0])
.unwrap()
.checked_mul(decimals)
.unwrap();
if strs.len() == 1
//只有整数部分
return Ok(inter);
let mut z: String = strs[1].to_string();
//小数部分需要补零
let frac = if strs[1].len() >= d as usize
&strs[1][..d as usize]
else
z.push_str(&ZEROS[..d as usize - strs[1].len()]);
&z[..]
;
let frac = U256::from_dec_str(frac).unwrap();
Ok(inter.checked_add(frac).unwrap())
///将U256转化为人类可读的浮点数字符串
fn format_units(&self, d: u32) -> Result<String, ParseU256Error>
if d > 18
return Err(ParseU256Error::DecimalsError);
let decimals = U256::exp10(d as usize);
let m = self.checked_rem(decimals).unwrap().to_string(); //模
let mut b = String::from(&ZEROS[..d as usize - m.len()]); //计算0的个数
b.push_str(&m[..]); //前面补零
let b = b.trim_end_matches('0');
let mut inter = self.checked_div(decimals).unwrap().to_string(); //商
//如果有余数
if m != "0"
inter.push('.');
inter.push_str(b);
Ok(inter.clone())
#[test]
fn test_wrap()
let source = "1.035000000000000000001";
let balance = U256::from(1_035_000_000_000_000_000u64);
let b = U256::parse_units(source, 18).unwrap();
assert_eq!(b, balance);
let s = balance.format_units(18).unwrap();
assert_eq!(s, "1.035");
let source2 = "13897";
let bal2 = U256::from(13_897_000_000_000 as u64);
let b2 = U256::parse_units(source2, 9).unwrap();
assert_eq!(b2, bal2);
let s2 = bal2.format_units(9).unwrap();
assert_eq!(s2, source2);
注意,我们这个转换精度不能超过18。
下面我们来看一下具体的操作。
main.rs
use std::str::FromStr;
use web3::types::Address,U256;
use web3::contract::Contract, Options;
mod convert;
use convert::ParseFormat;
#[tokio::main]
async fn main() -> web3::contract::Result<()>
const HTTP_URL: &str = "https://bsc-dataseed4.ninicoin.io";
const SAFE_MOON: &str = "0x8076C74C5e3F5852037F31Ff0093Eeb8c8ADd8D3";
let transport = web3::transports::Http::new(HTTP_URL)?;
let provider = web3::Web3::new(transport);
let safe_addr = Address::from_str(SAFE_MOON).unwrap();
let contract = Contract::from_json(provider.eth(), safe_addr, include_bytes!("../abi2.json")).unwrap();
let result = contract.query("_taxFee",(),None,Options::default(),None);
let tax_fee: U256 = result.await?;
println!("_taxFee:",tax_fee);
assert_eq!(tax_fee, 5.into());
let balance = provider.eth().balance(safe_addr, None).await?;
let balance = balance.format_units(18).unwrap();
println!("Balance: BNB",balance);
Ok(())
在上面的示例代码中,我们演示的了两个功能,第一个查询SafeMoon合约中的_taxFee
,另一个是查询了SafeMoon合约的BNB余额,运行结果如下(结果可能不同):
_taxFee:5
Balance:4957.85048317300265945 BNB
可以看到,大致实现了我们的需求。
上面的convert.rs
并不完善,特别是其中的错误处理很简单,这是下一步优化的方向。
以上是关于使用Rust模拟ethers.js中的parseUnits的主要内容,如果未能解决你的问题,请参考以下文章