solidity合约迁移到ink! 的原型数据

  • cloudweisz
  • 更新于 2022-06-10 02:53
  • 阅读 2079

uniswap v3

由于rust语言并不是直接为合约设计的。所以在rust的原始数据类型里面并没有u256,i256,u512,i512等数据类型。但是uniswap v3中有大量使用到U256和I256等数据类型。所以在ink!中必须找到替代方案才能完成uniswap v3 到ink!的迁移工作。 首先为项目创造一个单独的原型crate,取名为:primitrives,用于存放项目中需要用到的数据原型。大致的数据类型有:

pub use sp_core::U256;
pub type Address = AccountId;
pub type Uint24 = u32;
pub type Uint16 = u16;
pub type Int24 = i32;
pub type Uint8 = u8;
pub type Uint160 = WrapperU256;
pub type Uint256 = WrapperU256;
pub type U160 = U256;
pub type I56 = i64;
pub type I256 = i128;
pub type Int256 = i128;
pub type Uint128 = u128;
pub type Uint96 = u128;
pub type Uint80 = u128;

感谢substance内有一个sp-core的crate内有U256的数据类型。crate的信息为:

[dependencies.sp-core]
default-features = false
git = 'https://github.com/paritytech/substrate.git'
version = '6.0.0'

该crate中有一个U256(4)的结构,内部是一个[u64;4]的数组。U256具有实现了大部分的数学运行,包括加减乘除以及次方,左移,右移,求余等操作。 使用U256如果要保存到合约的数据中时,需要实现SpreadLayoutPackedLayoutSpreadAllocate的这三个trait。由于这三个trait和U256都不在当前的crate中,rust由于孤儿原则,所以必须用一个新的数据类型对U256进行封装,故我们创建了一个数据类型进行封装。

#[derive(Default,Debug,Clone,Copy, PartialEq, Eq,Encode, Decode)]
// #[cfg_attr(feature = "std", derive(TypeInfo))]
pub struct WrapperU256 {
    pub value: U256,
}

由于U256本身没有实现这三个trait,所以我们不能直接使用derive实现这三个接口。只能手动实现这三个trait。

impl SpreadLayout for WrapperU256 {
    const FOOTPRINT: u64 = 4;
    const REQUIRES_DEEP_CLEAN_UP: bool = true;
    fn pull_spread(ptr: &mut ink_primitives::KeyPtr) -> Self {
        let slice: [u64; 4] = SpreadLayout::pull_spread(ptr);
        Self { value: U256(slice) }
    }

    fn push_spread(&self, ptr: &mut ink_primitives::KeyPtr) {
        SpreadLayout::push_spread(&self.value.0, ptr);
    }

    fn clear_spread(&self, ptr: &mut ink_primitives::KeyPtr) {
        SpreadLayout::clear_spread(&self.value.0, ptr);
    }
}

impl PackedLayout for WrapperU256 {
    fn pull_packed(&mut self, at: &ink_primitives::Key) {
        self.value.0.pull_packed(at);
    }

    fn push_packed(&self, at: &ink_primitives::Key) {
        self.value.0.push_packed(at);
    }

    fn clear_packed(&self, at: &ink_primitives::Key) {
        self.value.0.clear_packed(at);
    }
}

impl SpreadAllocate for WrapperU256{
    fn allocate_spread(ptr: &mut ink_primitives::KeyPtr) -> Self {
        ptr.next_for::<WrapperU256>();
        // Id::U8(0)
        WrapperU256::new()
    }
}

由此我们基本上可以正常在ink!中使用U256了。但是在使用tickMath的时候,我们仍然遇到了一些麻烦。这里需要对I256做or运算。但是sp-core里面仍然找不到I256这样的数据类型。 所以我们只能用一个U256类型并标记正负值来表示I256.但是负值的是正值的反值的补码减去加1.这个一定要理解才可以处理or操作。后续如果我们自己实现了I256.则可以不再这么复杂。附上代码:

// let i5:U256 = U256::from(123u32);
        // i4 = !i4;
        // i4 = i4.saturating_add(U256::from(1));
        // let mut i6:U256 = i4|i5;
        // i6= U256::from_big_endian(&[0xff_u8;32]).saturating_sub(i6).saturating_add(U256::from(1));
        let log_2 = !log_2;
        let log_2 = log_2.saturating_add(U256::from(1u32));
        let log_2 = or(&log_2,&shl(w, &f));
        let log_2 = U256::from_big_endian(&[0xff_u8;32]).saturating_sub(log_2).saturating_add(U256::from(1));
        let r = shr(&f,&r);
        return (log_2,r);
点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
cloudweisz
cloudweisz
十多年的java金融领域经验。后转型做过以太坊的DEFI项目。现专注于web3领域的区块链和合约。