From 3d14ec560294fdda476f519b33a4d0c6f630e8c1 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Fri, 05 Nov 2021 19:29:57 +0000 Subject: [PATCH] feat: generate solidity documentation --- --- a/crates/evm-coder-macros/src/solidity_interface.rs +++ b/crates/evm-coder-macros/src/solidity_interface.rs @@ -6,7 +6,7 @@ use std::fmt::Write; use syn::{ Expr, FnArg, GenericArgument, Generics, Ident, ImplItem, ImplItemMethod, ItemImpl, Lit, Meta, - NestedMeta, PatType, Path, PathArguments, ReturnType, Type, spanned::Spanned, + MetaNameValue, NestedMeta, PatType, Path, PathArguments, ReturnType, Type, spanned::Spanned, }; use crate::{ @@ -362,19 +362,28 @@ has_normal_args: bool, mutability: Mutability, result: Type, + docs: Vec, } impl Method { fn try_from(value: &ImplItemMethod) -> syn::Result { let mut info = MethodInfo { rename_selector: None, }; + let mut docs = Vec::new(); for attr in &value.attrs { let ident = parse_ident_from_path(&attr.path, false)?; if ident == "solidity" { let args = attr.parse_meta().unwrap(); info = MethodInfo::from_meta(&args).unwrap(); } else if ident == "doc" { - // TODO: Add docs to evm interfaces + let args = attr.parse_meta().unwrap(); + let value = match args { + Meta::NameValue(MetaNameValue { + lit: Lit::Str(str), .. + }) => str.value(), + _ => unreachable!(), + }; + docs.push(value); } } let ident = &value.sig.ident; @@ -457,6 +466,7 @@ has_normal_args, mutability, result: result.clone(), + docs, }) } fn expand_call_def(&self) -> proc_macro2::TokenStream { @@ -570,10 +580,12 @@ .iter() .filter(|a| !a.is_special()) .map(MethodArg::expand_solidity_argument); + let docs = self.docs.iter(); let selector = format!("{} {:0>8x}", self.selector_str, self.selector); quote! { SolidityFunction { + docs: &[#(#docs),*], selector: #selector, name: #camel_name, mutability: #mutability, @@ -704,6 +716,7 @@ use core::fmt::Write; let interface = SolidityInterface { name: #solidity_name, + selector: Self::interface_id(), is: &["Dummy", "ERC165", #( #solidity_is, )* #( --- a/crates/evm-coder-macros/src/to_log.rs +++ b/crates/evm-coder-macros/src/to_log.rs @@ -183,6 +183,7 @@ use evm_coder::solidity::*; use core::fmt::Write; let interface = SolidityInterface { + selector: 0, name: #solidity_name, is: &[], functions: (#( --- a/crates/evm-coder/src/solidity.rs +++ b/crates/evm-coder/src/solidity.rs @@ -84,6 +84,7 @@ solidity_type_name! { uint8 => "uint8" true = "0", uint32 => "uint32" true = "0", + uint64 => "uint64" true = "0", uint128 => "uint128" true = "0", uint256 => "uint256" true = "0", address => "address" true = "0x0000000000000000000000000000000000000000", @@ -376,6 +377,7 @@ Mutable, } pub struct SolidityFunction { + pub docs: &'static [&'static str], pub selector: &'static str, pub name: &'static str, pub args: A, @@ -389,6 +391,12 @@ writer: &mut impl fmt::Write, tc: &TypeCollector, ) -> fmt::Result { + for doc in self.docs { + writeln!(writer, "\t//{}", doc)?; + } + if !self.docs.is_empty() { + writeln!(writer, "\t//")?; + } writeln!(writer, "\t// Selector: {}", self.selector)?; write!(writer, "\tfunction {}(", self.name)?; self.args.solidity_name(writer, tc)?; @@ -449,6 +457,7 @@ } pub struct SolidityInterface { + pub selector: u32, pub name: &'static str, pub is: &'static [&'static str], pub functions: F, @@ -461,6 +470,9 @@ out: &mut impl fmt::Write, tc: &TypeCollector, ) -> fmt::Result { + if self.selector != 0 { + writeln!(out, "// Selector: {:0>8x}", self.selector)?; + } if is_impl { write!(out, "contract ")?; } else { --- a/pallets/fungible/src/stubs/UniqueFungible.sol +++ b/pallets/fungible/src/stubs/UniqueFungible.sol @@ -31,6 +31,7 @@ ); } +// Selector: 942e8b22 contract ERC20 is Dummy, ERC165, ERC20Events { // Selector: name() 06fdde03 function name() public view returns (string memory) { --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -61,6 +61,7 @@ Ok(string::from_utf8_lossy(&self.token_prefix).into()) } + /// Returns token's const_metadata #[solidity(rename_selector = "tokenURI")] fn token_uri(&self, token_id: uint256) -> Result { let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; @@ -79,6 +80,7 @@ Ok(index) } + /// Not implemented fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result { // TODO: Not implemetable Err("not implemented".into()) @@ -103,6 +105,7 @@ .owner .as_eth()) } + /// Not implemented fn safe_transfer_from_with_data( &mut self, _from: address, @@ -114,6 +117,7 @@ // TODO: Not implemetable Err("not implemented".into()) } + /// Not implemented fn safe_transfer_from( &mut self, _from: address, @@ -159,6 +163,7 @@ Ok(()) } + /// Not implemented fn set_approval_for_all( &mut self, _caller: caller, @@ -169,11 +174,13 @@ Err("not implemented".into()) } + /// Not implemented fn get_approved(&self, _token_id: uint256) -> Result
{ // TODO: Not implemetable Err("not implemented".into()) } + /// Not implemented fn is_approved_for_all(&self, _owner: address, _operator: address) -> Result
{ // TODO: Not implemetable Err("not implemented".into()) @@ -197,6 +204,8 @@ Ok(false) } + /// `token_id` should be obtained with `next_token_id` method, + /// unlike standard, you can't specify it manually fn mint(&mut self, caller: caller, to: address, token_id: uint256) -> Result { let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); @@ -223,6 +232,8 @@ Ok(true) } + /// `token_id` should be obtained with `next_token_id` method, + /// unlike standard, you can't specify it manually #[solidity(rename_selector = "mintWithTokenURI")] fn mint_with_token_uri( &mut self, @@ -257,6 +268,7 @@ Ok(true) } + /// Not implemented fn finish_minting(&mut self, _caller: caller) -> Result { Err("not implementable".into()) } --- a/pallets/nonfungible/src/stubs/UniqueNFT.sol +++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol @@ -51,6 +51,17 @@ event MintingFinished(); } +// Selector: 42966c68 +contract ERC721Burnable is Dummy, ERC165 { + // Selector: burn(uint256) 42966c68 + function burn(uint256 tokenId) public { + require(false, stub_error); + tokenId; + dummy = 0; + } +} + +// Selector: 58800161 contract ERC721 is Dummy, ERC165, ERC721Events { // Selector: balanceOf(address) 70a08231 function balanceOf(address owner) public view returns (uint256) { @@ -68,6 +79,8 @@ return 0x0000000000000000000000000000000000000000; } + // Not implemented + // // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672 function safeTransferFromWithData( address from, @@ -83,6 +96,8 @@ dummy = 0; } + // Not implemented + // // Selector: safeTransferFrom(address,address,uint256) 42842e0e function safeTransferFrom( address from, @@ -117,6 +132,8 @@ dummy = 0; } + // Not implemented + // // Selector: setApprovalForAll(address,bool) a22cb465 function setApprovalForAll(address operator, bool approved) public { require(false, stub_error); @@ -125,6 +142,8 @@ dummy = 0; } + // Not implemented + // // Selector: getApproved(uint256) 081812fc function getApproved(uint256 tokenId) public view returns (address) { require(false, stub_error); @@ -133,6 +152,8 @@ return 0x0000000000000000000000000000000000000000; } + // Not implemented + // // Selector: isApprovedForAll(address,address) e985e9c5 function isApprovedForAll(address owner, address operator) public @@ -147,45 +168,7 @@ } } -contract ERC721Burnable is Dummy, ERC165 { - // Selector: burn(uint256) 42966c68 - function burn(uint256 tokenId) public { - require(false, stub_error); - tokenId; - dummy = 0; - } -} - -contract ERC721Enumerable is Dummy, ERC165 { - // Selector: tokenByIndex(uint256) 4f6ccce7 - function tokenByIndex(uint256 index) public view returns (uint256) { - require(false, stub_error); - index; - dummy; - return 0; - } - - // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59 - function tokenOfOwnerByIndex(address owner, uint256 index) - public - view - returns (uint256) - { - require(false, stub_error); - owner; - index; - dummy; - return 0; - } - - // Selector: totalSupply() 18160ddd - function totalSupply() public view returns (uint256) { - require(false, stub_error); - dummy; - return 0; - } -} - +// Selector: 5b5e139f contract ERC721Metadata is Dummy, ERC165 { // Selector: name() 06fdde03 function name() public view returns (string memory) { @@ -201,6 +184,8 @@ return ""; } + // Returns token's const_metadata + // // Selector: tokenURI(uint256) c87b56dd function tokenURI(uint256 tokenId) public view returns (string memory) { require(false, stub_error); @@ -210,6 +195,7 @@ } } +// Selector: 68ccfe89 contract ERC721Mintable is Dummy, ERC165, ERC721MintableEvents { // Selector: mintingFinished() 05d2035b function mintingFinished() public view returns (bool) { @@ -218,6 +204,9 @@ return false; } + // `token_id` should be obtained with `next_token_id` method, + // unlike standard, you can't specify it manually + // // Selector: mint(address,uint256) 40c10f19 function mint(address to, uint256 tokenId) public returns (bool) { require(false, stub_error); @@ -227,6 +216,9 @@ return false; } + // `token_id` should be obtained with `next_token_id` method, + // unlike standard, you can't specify it manually + // // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f function mintWithTokenURI( address to, @@ -241,6 +233,8 @@ return false; } + // Not implemented + // // Selector: finishMinting() 7d64bcb4 function finishMinting() public returns (bool) { require(false, stub_error); @@ -249,6 +243,40 @@ } } +// Selector: 780e9d63 +contract ERC721Enumerable is Dummy, ERC165 { + // Selector: tokenByIndex(uint256) 4f6ccce7 + function tokenByIndex(uint256 index) public view returns (uint256) { + require(false, stub_error); + index; + dummy; + return 0; + } + + // Not implemented + // + // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59 + function tokenOfOwnerByIndex(address owner, uint256 index) + public + view + returns (uint256) + { + require(false, stub_error); + owner; + index; + dummy; + return 0; + } + + // Selector: totalSupply() 18160ddd + function totalSupply() public view returns (uint256) { + require(false, stub_error); + dummy; + return 0; + } +} + +// Selector: e562194d contract ERC721UniqueExtensions is Dummy, ERC165 { // Selector: transfer(address,uint256) a9059cbb function transfer(address to, uint256 tokenId) public { --- a/tests/src/eth/api/ContractHelpers.sol +++ b/tests/src/eth/api/ContractHelpers.sol @@ -12,6 +12,7 @@ function supportsInterface(bytes4 interfaceID) external view returns (bool); } +// Selector: 31acb1fe interface ContractHelpers is Dummy, ERC165 { // Selector: contractOwner(address) 5152b14c function contractOwner(address contractAddress) --- a/tests/src/eth/api/UniqueFungible.sol +++ b/tests/src/eth/api/UniqueFungible.sol @@ -22,6 +22,7 @@ ); } +// Selector: 942e8b22 interface ERC20 is Dummy, ERC165, ERC20Events { // Selector: name() 06fdde03 function name() external view returns (string memory); --- a/tests/src/eth/api/UniqueNFT.sol +++ b/tests/src/eth/api/UniqueNFT.sol @@ -42,6 +42,13 @@ event MintingFinished(); } +// Selector: 42966c68 +interface ERC721Burnable is Dummy, ERC165 { + // Selector: burn(uint256) 42966c68 + function burn(uint256 tokenId) external; +} + +// Selector: 58800161 interface ERC721 is Dummy, ERC165, ERC721Events { // Selector: balanceOf(address) 70a08231 function balanceOf(address owner) external view returns (uint256); @@ -49,6 +56,8 @@ // Selector: ownerOf(uint256) 6352211e function ownerOf(uint256 tokenId) external view returns (address); + // Not implemented + // // Selector: safeTransferFromWithData(address,address,uint256,bytes) 60a11672 function safeTransferFromWithData( address from, @@ -57,6 +66,8 @@ bytes memory data ) external; + // Not implemented + // // Selector: safeTransferFrom(address,address,uint256) 42842e0e function safeTransferFrom( address from, @@ -74,12 +85,18 @@ // Selector: approve(address,uint256) 095ea7b3 function approve(address approved, uint256 tokenId) external; + // Not implemented + // // Selector: setApprovalForAll(address,bool) a22cb465 function setApprovalForAll(address operator, bool approved) external; + // Not implemented + // // Selector: getApproved(uint256) 081812fc function getApproved(uint256 tokenId) external view returns (address); + // Not implemented + // // Selector: isApprovedForAll(address,address) e985e9c5 function isApprovedForAll(address owner, address operator) external @@ -87,25 +104,7 @@ returns (address); } -interface ERC721Burnable is Dummy, ERC165 { - // Selector: burn(uint256) 42966c68 - function burn(uint256 tokenId) external; -} - -interface ERC721Enumerable is Dummy, ERC165 { - // Selector: tokenByIndex(uint256) 4f6ccce7 - function tokenByIndex(uint256 index) external view returns (uint256); - - // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59 - function tokenOfOwnerByIndex(address owner, uint256 index) - external - view - returns (uint256); - - // Selector: totalSupply() 18160ddd - function totalSupply() external view returns (uint256); -} - +// Selector: 5b5e139f interface ERC721Metadata is Dummy, ERC165 { // Selector: name() 06fdde03 function name() external view returns (string memory); @@ -113,17 +112,26 @@ // Selector: symbol() 95d89b41 function symbol() external view returns (string memory); + // Returns token's const_metadata + // // Selector: tokenURI(uint256) c87b56dd function tokenURI(uint256 tokenId) external view returns (string memory); } +// Selector: 68ccfe89 interface ERC721Mintable is Dummy, ERC165, ERC721MintableEvents { // Selector: mintingFinished() 05d2035b function mintingFinished() external view returns (bool); + // `token_id` should be obtained with `next_token_id` method, + // unlike standard, you can't specify it manually + // // Selector: mint(address,uint256) 40c10f19 function mint(address to, uint256 tokenId) external returns (bool); + // `token_id` should be obtained with `next_token_id` method, + // unlike standard, you can't specify it manually + // // Selector: mintWithTokenURI(address,uint256,string) 50bb4e7f function mintWithTokenURI( address to, @@ -131,10 +139,30 @@ string memory tokenUri ) external returns (bool); + // Not implemented + // // Selector: finishMinting() 7d64bcb4 function finishMinting() external returns (bool); } +// Selector: 780e9d63 +interface ERC721Enumerable is Dummy, ERC165 { + // Selector: tokenByIndex(uint256) 4f6ccce7 + function tokenByIndex(uint256 index) external view returns (uint256); + + // Not implemented + // + // Selector: tokenOfOwnerByIndex(address,uint256) 2f745c59 + function tokenOfOwnerByIndex(address owner, uint256 index) + external + view + returns (uint256); + + // Selector: totalSupply() 18160ddd + function totalSupply() external view returns (uint256); +} + +// Selector: e562194d interface ERC721UniqueExtensions is Dummy, ERC165 { // Selector: transfer(address,uint256) a9059cbb function transfer(address to, uint256 tokenId) external; -- gitstuff