IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 区块链 -> 使用Rust模拟ethers.js中的parseUnits -> 正文阅读

[区块链]使用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并不完善,特别是其中的错误处理很简单,这是下一步优化的方向。

  区块链 最新文章
盘点具备盈利潜力的几大加密板块,以及潜在
阅读笔记|让区块空间成为商品,打造Web3云
区块链1.0-比特币的数据结构
Team Finance被黑分析|黑客自建Token“瞒天
区块链≠绿色?波卡或成 Web3“生态环保”标
期货从入门到高深之手动交易系列D1课
以太坊基础---区块验证
进入以太坊合并的五个数字
经典同态加密算法Paillier解读 - 原理、实现
IPFS/Filecoin学习知识科普(四)
上一篇文章      下一篇文章      查看所有文章
加:2021-12-07 12:04:48  更:2021-12-07 12:05:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:36:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码