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如果要保存到合约的数据中时,需要实现SpreadLayout
、PackedLayout
和SpreadAllocate
的这三个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);
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!