#bindings #solidity #ethereum #evm #bindings-generator #array #contract-storage

bin+lib rustsol

Rust对Solidity合约存储布局的绑定

2个不稳定版本

0.3.0 2024年6月4日
0.2.0 2024年6月3日
0.1.1 2024年5月30日
0.1.0 2024年5月30日

魔法豆

MIT许可

68KB
1.5K SLoC

rustsol

描述

rustsol是一个用于生成Ethereum智能合约Rust存储绑定的工具。这些绑定可以用来检索合约中所有存储变量的存储槽、偏移量和大小,包括存储在映射和数组中的对象。当使用slots_getter初始化时,生成的结构体可以用来方便地访问这些存储变量的值。

绑定示例使用

获取合约变量的存储位置

let contract = generated_contract::UniswapV3Pool::new();
let (slot, offset, size_bytes) = contract.observations.at(42).tickCumulative.position();
println!("slot={}, offset={}, size_bytes={}", slot, offset, size_bytes);
// Output:
// slot=50, offset=4, size_bytes=7

使用提供的槽获取器获取合约变量的存储值

let contract = generated_contract::UniswapV3Pool::new();
contract.set_slots_getter(my_slots_getter);
let tick_value = contract.ticks.at(-92110).get_value().unwrap();
println!("{:?}", tick_value);
// Output (prettified):
// TickInfoValue {
//     liquidityGross:                 398290794261,
//     liquidityNet:                   398290794261,
//     feeGrowthOutside0X128:          0x0000000000000000000000000000000000000b73d798604f1b0cd4f1d544c646_U256,
//     feeGrowthOutside1X128:          0x000000000000000000000000000000f2a960acbe8891e526c025b819077f15ae_U256,
//     tickCumulativeOutside:          622572156443,
//     secondsPerLiquidityOutsideX128: 0x0000000000000000000000000000000000000001e576ee66a9d9f002e36fad4c_U256,
//     secondsOutside:                 1623419923,
//     initialized:                    true
// }

生成的结构体

生成的绑定结构体将类似于以下内容

pub struct UniswapV3Pool {
    __slot: U256,
    __slots_getter: Option<Arc<dyn SlotsGetter>>,
    pub slot0: UniswapV3PoolSlot0,
    pub feeGrowthGlobal0X128: Primitive<32, U256>,
    pub feeGrowthGlobal1X128: Primitive<32, U256>,
    pub protocolFees: UniswapV3PoolProtocolFees,
    pub liquidity: Primitive<16, u128>,
    pub ticks: Mapping<i32, TickInfo>,
    pub tickBitmap: Mapping<i16, Primitive<32, U256>>,
    pub positions: Mapping<U256, PositionInfo>,
    pub observations: StaticArray<2097120, OracleObservation>,
}

安装

cargo install rustsol

设置和使用

1. 获取合约存储布局

要为合约生成存储绑定,您首先需要合约的存储布局JSON格式。对于Solidity合约,可以使用solc编译器生成。 rustsol提供了一个简单的Python脚本来协助此过程。请参阅原始仓库中的说明。

2. 生成绑定

要生成绑定,请使用以下命令

rustsol generate_storage_bindings your_solc_output.json contract_path contract_name generated_contract.rs

要了解contract_pathcontract_name的含义,让我们看看一个示例存储布局JSON

{
  "contracts": {
    "UniswapV3Pool.sol": {
      "UniswapV3Pool": {
        "storageLayout": {
          ...
        }
      }
    }
  }
}

在这里,UniswapV3Pool.sol是合约路径,UniswapV3Pool是合约名称。

对于提供的示例,将是

rustsol generate_storage_bindings example/solc_output_uniswap3pool.json UniswapV3Pool.sol UniswapV3Pool example/src/generated_contract_uniswap3pool.rs

运行以上命令后,生成的结构体将在generated_contract.rs文件中。请参阅原始仓库中的示例。

类型映射

以太坊智能合约语言(Solidity)与Rust语言的映射

Solidity中的变量类型被映射到Rust的绑定类型。这种映射在下面的表格中展示。在这里,value_type对应于(可能嵌套的)rustsol绑定类型,例如PrimitiveMapping。而native_type是将实际槽位值转换成的类型,例如u64boolU256。请注意,Mappings的键也是原生类型。

Solidity类型 生成的Rust类型
所有整数类型,布尔值,枚举,
地址,合约,小字节1..32
原始类型<字节大小,原生类型>
字符串,字节 Bytes<String>Bytes<Vec<u8>>
静态数组 StaticArray<字节大小,值类型>
动态数组 DynamicArray<值类型>
映射 Mapping<键原生类型,值类型>
结构体 CustomNamedStructWithCorrespondingFields

请注意,所有枚举都映射到Primitive<byte_size, U256>。使用原生Rust枚举作为native_type可能更好,但这需要更深入的对Solidity合约的分析,因为枚举字段名称的信息无法从存储布局中获得。

值类型映射

使用get_value()获得的变量值根据下面的表格转换为原生类型。

rustsol类型 生成的Rust类型
原始类型<_,原生类型> 原生类型
Bytes<String> String
Bytes<Vec<u8>> Vec<u8>
StaticArray<值类型> Vec<value_type的递归原生类型>
DynamicArray Vec<value_type的递归原生类型>
Mapping Mapping<key_native_type, value_type>获取器
SomeStruct SomeStructValue

请注意,Mapping类型实际上映射到相同的Mapping。这是因为无法获取Solidity映射的所有元素。因此,我们返回一个值获取器而不是具体值。

许可证

本项目受MIT许可证许可。

依赖项

~8MB
~139K SLoC