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