8 个版本
0.4.3 | 2024 年 3 月 27 日 |
---|---|
0.4.2 | 2023 年 8 月 29 日 |
0.3.6 | 2023 年 8 月 14 日 |
0.3.5 | 2023 年 7 月 28 日 |
0.3.3 | 2023 年 2 月 17 日 |
#83 in #solidity
每月 27 次下载
在 evm-coder 中使用
120KB
3.5K SLoC
evm-coder
概述
这是一个库,用于在 Rust 和 Solidity 代码之间无缝调用转换。
通过在 Rust 中编码 Solidity 定义,此库还为以太坊开发者提供生成 Solidity 接口的功能。
用法
要在 Substrate 中创建合约,请使用 solidity_interface
属性。此属性应应用于表示您的合约的结构实现。它提供了各种参数,支持诸如继承、编译时的接口验证和其他功能等功能。
还支持使用属性 #[solidity(rename="funcName")]
进行函数重载。
安装
将以下行添加到您的 Cargo.toml
项目文件中。
[dependencies]
evm-coder = "0.3"
示例
考虑以下示例,我们创建一个支持 ERC721 并带有附加扩展接口的合约。
首先,我们使用以下Rust代码定义我们的合约接口:
struct ContractHandle;
#[solidity_interface(
name = MyContract,
is(
ERC721,
CustomContract,
)
)]
impl ContractHandle{}
上述代码定义了一个名为MyContract的合约,它实现了两个接口,即ERC721和CustomContract。
接下来,我们开始实际实现ERC721接口。
// This docs will be included into the generated `sol` file.
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
#[solidity_interface(
name = ERC721, // Contract name
events(ERC721Events), // Include events
expect_selector = 0x80ac58cd // Expected selector of contract (will be matched at compile time)
)]
impl ContractHandle {
// This docs will be included into the generated `sol` file.
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param owner An address for whom to query the balance
/// @return The number of NFTs owned by `owner`, possibly zero
fn balance_of(&self, owner: Address) -> Result<U256> {
todo!()
}
fn owner_of(&self, token_id: U256) -> Result<Address> {
todo!()
}
#[solidity(rename_selector = "safeTransferFrom")]
fn safe_transfer_from_with_data(&mut self, from: Address, to: Address, token_id: U256, data: Bytes) -> Result<()> {
todo!()
}
fn safe_transfer_from(&mut self, from: Address, to: Address, token_id: U256) -> Result<()> {
todo!()
}
fn transfer_from(&mut self, caller: Caller, from: Address, to: Address, token_id: U256) -> Result<()> {
todo!()
}
fn approve(&mut self, caller: Caller, approved: Address, token_id: U256) -> Result<()> {
todo!()
}
fn set_approval_for_all(&mut self, caller: Caller, operator: Address, approved: bool) -> Result<()> {
todo!()
}
fn get_approved(&self, token_id: U256) -> Result<Address> {
todo!()
}
fn is_approved_for_all(&self, owner: Address, operator: Address) -> Result<bool> {
todo!()
}
}
在这个接口的实现中,我们包含了在相应的调用期间会触发的事件ERC721Events
。为了确保标准接口的无缝实现,solidity_interface
注解中的expect_selector
指令在编译时检查合约选择器,从而防止错误。
现在,让我们继续创建ERC721的事件。
#[derive(ToLog)]
pub enum ERC721Events {
// This docs will be included into the generated `sol` file.
/// @dev This emits when ownership of any NFT changes by any mechanism.
Transfer {
#[indexed] // This field will be indexed
from: Address,
#[indexed]
to: Address,
#[indexed]
token_id: U256,
},
Approval {
#[indexed]
owner: Address,
#[indexed]
approved: Address,
#[indexed]
token_id: U256,
},
ApprovalForAll {
#[indexed]
owner: Address,
#[indexed]
operator: Address,
approved: bool,
},
}
让我们创建我们的扩展。
#[solidity_interface(name = CustomContract)
impl ContractHandle {
#[solidity(rename_selector = "doSome")]
fn do_some_0(&mut self, caller: Caller, param: bool) -> Result<()> {
todo!()
}
#[solidity(rename_selector = "doSome")]
fn do_some_1(&mut self, caller: Caller, param: u8) -> Result<()> {
todo!()
}
#[solidity(hide)]
fn do_another(&mut self, caller: Caller, param: bool) -> Result<()> {
todo!()
}
fn do_magic(&mut self, caller: Caller, param1: Enum, param2: Struct) -> Result<Option<U256>> {
todo!()
}
}
方法do_some_0
和do_some_1
被宏#[solidity(rename_selector = ""doSome"")]
标注。这允许它们在Solidity接口中以一个单一的 overloaded 方法名为doSome呈现。同时,do_another
方法将被包含在.sol
文件中,但会被注释掉。最后,do_magic
方法使用了自定义类型--我们也可以这样做!
让我们让我们的类型在solidity中可用(Option
默认可用)
#[derive(AbiCoder)]
struct Struct {
a: u8,
b: String
}
#[derive(AbiCoder, Default, Clone, Copy)]
#[repr(u8)]
enum Enum {
First,
Second,
#[default]
Third,
}
使用AbiCoder
派生的宏,维护你的类型变得如此简单。
最后,我们将指定sol
文件的生成器。
generate_stubgen!(gen_impl, ContractHandleCall<()>, true);
generate_stubgen!(gen_iface, ContractHandleCall<()>, false);
scripts文件夹包含了一组用于生成接口、sol
存根、json abi
和编译合约的脚本。为此,创建以下make
文件。
MyContract.sol:
PACKAGE=package-name NAME=erc::gen_iface OUTPUT=/path/to/iface/$@ $(PATH_TO_SCRIPTS)/generate_sol.sh
PACKAGE=package-name NAME=erc::gen_impl OUTPUT=/patch/to/stub/$@ $(PATH_TO_SCRIPTS)/generate_sol.sh
MyContract: MyContract.sol
INPUT=/patch/to/stub/$< OUTPUT=/patch/to/compiled/contract/MyContract.raw ./.maintain/scripts/compile_stub.sh
INPUT=/patch/to/stub/$< OUTPUT=/patch/to/abi ./.maintain/scripts/generate_abi.sh
结果,我们得到了以下sol
接口文件。
// SPDX-License-Identifier: OTHER
// This code is automatically generated
pragma solidity >=0.8.0 <0.9.0;
/// @dev common stubs holder
contract Dummy {
}
contract ERC165 is Dummy {
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
struct Struct {
a uint8;
b string;
}
enum Enum {
First,
Second,
Third
}
/// Optional value
struct OptionUint256 {
/// Shows the status of accessibility of value
bool status;
/// Actual value if `status` is true
uint256 value;
}
/// @title A contract that allows you to work with collections.
/// @dev the ERC-165 identifier for this interface is 0x738a0043
contract CustomContract is Dummy, ERC165 {
/// @dev EVM selector for this function is: 0x5465a527,
/// or in textual repr: doSome(bool)
function doSome(bool param) public;
/// @dev EVM selector for this function is: 0x58a93f40,
/// or in textual repr: doSome(uint8)
function doSome(uint8 param) public;
// /// @dev EVM selector for this function is: 0xf41a813e,
// /// or in textual repr: doAnother(bool)
// function doAnother(bool param) public;
/// @dev EVM selector for this function is: 0x8b5c1b1a,
/// or in textual repr: doMagic(uint8,(uint8,string))
function doSome(Enum param1, Struct param2) public returns (OptionUint256);
}
/// @dev inlined interface
contract ERC721Events {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
}
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
/// @dev the ERC-165 identifier for this interface is 0x80ac58cd
contract ERC721 is Dummy, ERC165, ERC721Events {
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param owner An address for whom to query the balance
/// @return The number of NFTs owned by `owner`, possibly zero
/// @dev EVM selector for this function is: 0x70a08231,
/// or in textual repr: balanceOf(address)
function balanceOf(address owner) public view returns (uint256);
/// @dev EVM selector for this function is: 0x6352211e,
/// or in textual repr: ownerOf(uint256)
function ownerOf(uint256 tokenId) public view returns (address);
/// @dev EVM selector for this function is: 0xb88d4fde,
/// or in textual repr: safeTransferFrom(address,address,uint256,bytes)
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory data
) public;
/// @dev EVM selector for this function is: 0x42842e0e,
/// or in textual repr: safeTransferFrom(address,address,uint256)
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public;
/// @dev EVM selector for this function is: 0x23b872dd,
/// or in textual repr: transferFrom(address,address,uint256)
function transferFrom(
address from,
address to,
uint256 tokenId
) public;
/// @dev EVM selector for this function is: 0x095ea7b3,
/// or in textual repr: approve(address,uint256)
function approve(address approved, uint256 tokenId) public;
/// @dev EVM selector for this function is: 0xa22cb465,
/// or in textual repr: setApprovalForAll(address,bool)
function setApprovalForAll(address operator, bool approved) public;
/// @dev EVM selector for this function is: 0x081812fc,
/// or in textual repr: getApproved(uint256)
function getApproved(uint256 tokenId) public view returns (address);
/// @dev EVM selector for this function is: 0xe985e9c5,
/// or in textual repr: isApprovedForAll(address,address)
function isApprovedForAll(address owner, address operator) public view returns (bool);
}
contract MyContract is
Dummy,
ERC165,
ERC721,
CustomContract
{}
许可证
根据您的选择,在以下许可证下授权:Apache License, Version 2.0或MIT许可证。
除非您明确声明,否则您故意提交给evm-coder的任何贡献,根据Apache-2.0许可证的定义,应按上述方式双许可,不附加任何额外条款或条件。
依赖项
~3MB
~48K SLoC