diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f69296b0f..eab7d4661 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: toolchain: ${{ matrix.toolchain }} default: true target: wasm32-unknown-unknown - - name: downgrade `anstyle`,`anstyle-parse`,`anstyle-query`,`clap`,`clap_lex` crates to support older Rust toolchain + - name: downgrade `anstyle`,`anstyle-parse`,`anstyle-query`,`clap`,`clap_lex`, `home` crates to support older Rust toolchain if: matrix.toolchain == '1.69.0' run: | cargo update -p anstyle --precise 1.0.2 @@ -31,6 +31,7 @@ jobs: cargo update -p anstyle-parse --precise 0.2.1 cargo update -p clap --precise 4.3.24 cargo update -p clap_lex --precise 0.5.0 + cargo update -p home --precise 0.5.5 - uses: Swatinem/rust-cache@v1 - name: Test run: cargo test --all --features unstable,legacy diff --git a/near-contract-standards/src/fungible_token/mod.rs b/near-contract-standards/src/fungible_token/mod.rs index e81d68a20..eb0698fca 100644 --- a/near-contract-standards/src/fungible_token/mod.rs +++ b/near-contract-standards/src/fungible_token/mod.rs @@ -15,5 +15,4 @@ pub mod storage_impl; pub use crate::fungible_token::core::FungibleTokenCore; pub use core_impl::{Balance, FungibleToken}; -pub use macros::*; pub use resolver::FungibleTokenResolver; diff --git a/near-contract-standards/src/non_fungible_token/approval/mod.rs b/near-contract-standards/src/non_fungible_token/approval/mod.rs index e9648e86e..3bd2198a8 100644 --- a/near-contract-standards/src/non_fungible_token/approval/mod.rs +++ b/near-contract-standards/src/non_fungible_token/approval/mod.rs @@ -1,7 +1,6 @@ mod approval_impl; mod approval_receiver; -pub use approval_impl::*; pub use approval_receiver::*; use crate::non_fungible_token::token::TokenId; diff --git a/near-contract-standards/src/non_fungible_token/mod.rs b/near-contract-standards/src/non_fungible_token/mod.rs index 155cc5022..cc1014d92 100644 --- a/near-contract-standards/src/non_fungible_token/mod.rs +++ b/near-contract-standards/src/non_fungible_token/mod.rs @@ -23,8 +23,6 @@ pub use self::token::{Token, TokenId}; mod utils; pub use utils::*; -pub use macros::*; - pub use self::approval::NonFungibleTokenApproval; pub use self::core::NonFungibleToken; pub use self::core::NonFungibleTokenResolver; diff --git a/near-sdk-macros/src/core_impl/abi/abi_generator.rs b/near-sdk-macros/src/core_impl/abi/abi_generator.rs index ed065861f..4089863ce 100644 --- a/near-sdk-macros/src/core_impl/abi/abi_generator.rs +++ b/near-sdk-macros/src/core_impl/abi/abi_generator.rs @@ -22,7 +22,7 @@ pub fn generate(i: &ItemImplInfo) -> TokenStream2 { pub extern "C" fn #near_abi_symbol() -> (*const u8, usize) { use ::std::string::String; - let mut gen = ::near_sdk::__private::schemars::gen::SchemaGenerator::default(); + let mut gen = ::near_sdk::schemars::gen::SchemaGenerator::default(); let functions = vec![#(#functions),*]; let mut data = ::std::mem::ManuallyDrop::new( ::near_sdk::serde_json::to_vec(&::near_sdk::__private::ChunkedAbiEntry::new( diff --git a/near-sdk-macros/src/core_impl/code_generator/attr_sig_info.rs b/near-sdk-macros/src/core_impl/code_generator/attr_sig_info.rs index 974408dd3..c6bbf4215 100644 --- a/near-sdk-macros/src/core_impl/code_generator/attr_sig_info.rs +++ b/near-sdk-macros/src/core_impl/code_generator/attr_sig_info.rs @@ -307,7 +307,7 @@ impl AttrSigInfo { } } -pub fn deserialize_data(ty: &SerializerType) -> TokenStream2 { +fn deserialize_data(ty: &SerializerType) -> TokenStream2 { match ty { SerializerType::JSON => quote! { ::near_sdk::serde_json::from_slice(&data).expect("Failed to deserialize callback using JSON") diff --git a/near-sdk-macros/src/core_impl/code_generator/metadata.rs b/near-sdk-macros/src/core_impl/code_generator/metadata.rs new file mode 100644 index 000000000..a42703a1e --- /dev/null +++ b/near-sdk-macros/src/core_impl/code_generator/metadata.rs @@ -0,0 +1,17 @@ +use proc_macro2::Ident; +use quote::quote; +use syn::Generics; + +/// Generates a view method to retrieve the source metadata. +pub(crate) fn generate_contract_metadata_method( + ident: &Ident, + generics: &Generics, +) -> proc_macro2::TokenStream { + quote! { + impl #generics #ident #generics { + pub fn contract_source_metadata() { + near_sdk::env::value_return(CONTRACT_SOURCE_METADATA.as_bytes()) + } + } + } +} diff --git a/near-sdk-macros/src/core_impl/code_generator/mod.rs b/near-sdk-macros/src/core_impl/code_generator/mod.rs index 1e461c2c1..94429cd1e 100644 --- a/near-sdk-macros/src/core_impl/code_generator/mod.rs +++ b/near-sdk-macros/src/core_impl/code_generator/mod.rs @@ -1,15 +1,12 @@ mod attr_sig_info; -pub use attr_sig_info::*; mod impl_item_method_info; -pub use impl_item_method_info::*; mod item_trait_info; -pub use item_trait_info::*; mod item_impl_info; -pub use item_impl_info::*; pub(crate) mod ext; +pub(crate) mod metadata; pub(crate) mod serializer; diff --git a/near-sdk-macros/src/lib.rs b/near-sdk-macros/src/lib.rs index 4cc86a97b..d6039ea45 100644 --- a/near-sdk-macros/src/lib.rs +++ b/near-sdk-macros/src/lib.rs @@ -3,11 +3,12 @@ extern crate proc_macro; mod core_impl; -use core_impl::ext::generate_ext_structs; +use core_impl::{ext::generate_ext_structs, metadata::generate_contract_metadata_method}; + use proc_macro::TokenStream; use self::core_impl::*; -use proc_macro2::Span; +use proc_macro2::{Ident, Span}; use quote::{quote, ToTokens}; use syn::{parse_quote, ImplItem, ItemEnum, ItemImpl, ItemStruct, ItemTrait, WhereClause}; @@ -114,8 +115,25 @@ pub fn near_bindgen(attr: TokenStream, item: TokenStream) -> TokenStream { return core_impl::near_events(attr, item); } + let generate_metadata = |ident: &Ident, + generics: &syn::Generics| + -> Result { + let metadata_impl_gen = generate_contract_metadata_method(ident, generics).into(); + let metadata_impl_gen = syn::parse::(metadata_impl_gen) + .expect("failed to generate contract metadata"); + process_impl_block(metadata_impl_gen) + }; + if let Ok(input) = syn::parse::(item.clone()) { let metadata = core_impl::contract_source_metadata_const(attr); + + let metadata_impl_gen = generate_metadata(&input.ident, &input.generics); + + let metadata_impl_gen = match metadata_impl_gen { + Ok(metadata) => metadata, + Err(err) => return err.into(), + }; + let ext_gen = generate_ext_structs(&input.ident, Some(&input.generics)); #[cfg(feature = "__abi-embed-checked")] let abi_embedded = abi::embed(); @@ -126,9 +144,17 @@ pub fn near_bindgen(attr: TokenStream, item: TokenStream) -> TokenStream { #ext_gen #abi_embedded #metadata + #metadata_impl_gen }) } else if let Ok(input) = syn::parse::(item.clone()) { let metadata = core_impl::contract_source_metadata_const(attr); + let metadata_impl_gen = generate_metadata(&input.ident, &input.generics); + + let metadata_impl_gen = match metadata_impl_gen { + Ok(metadata) => metadata, + Err(err) => return err.into(), + }; + let ext_gen = generate_ext_structs(&input.ident, Some(&input.generics)); #[cfg(feature = "__abi-embed-checked")] let abi_embedded = abi::embed(); @@ -139,8 +165,9 @@ pub fn near_bindgen(attr: TokenStream, item: TokenStream) -> TokenStream { #ext_gen #abi_embedded #metadata + #metadata_impl_gen }) - } else if let Ok(mut input) = syn::parse::(item) { + } else if let Ok(input) = syn::parse::(item) { for method in &input.items { if let ImplItem::Fn(m) = method { let ident = &m.sig.ident; @@ -155,46 +182,11 @@ pub fn near_bindgen(attr: TokenStream, item: TokenStream) -> TokenStream { } } } - - if input.trait_.is_none() { - let contract_source_metadata = quote! { - pub fn contract_source_metadata() { - near_sdk::env::value_return(CONTRACT_SOURCE_METADATA.as_bytes()) - } - }; - - match syn::parse2::(contract_source_metadata) { - Ok(x) => { - input.items.push(x); - } - Err(err) => { - return err.to_compile_error().into(); - } - } + match process_impl_block(input) { + Ok(output) => output, + Err(output) => output, } - - let item_impl_info = match ItemImplInfo::new(&mut input) { - Ok(x) => x, - Err(err) => { - return err.to_compile_error().into(); - } - }; - - #[cfg(not(feature = "__abi-generate"))] - let abi_generated = quote! {}; - #[cfg(feature = "__abi-generate")] - let abi_generated = abi::generate(&item_impl_info); - - let generated_code = item_impl_info.wrapper_code(); - - // Add wrapper methods for ext call API - let ext_generated_code = item_impl_info.generate_ext_wrapper_code(); - TokenStream::from(quote! { - #ext_generated_code - #input - #generated_code - #abi_generated - }) + .into() } else { TokenStream::from( syn::Error::new( @@ -206,6 +198,39 @@ pub fn near_bindgen(attr: TokenStream, item: TokenStream) -> TokenStream { } } +// This function deals with impl block processing, generating wrappers and ABI. +// +// # Arguments +// * input - impl block to process. +// +// The Result has a TokenStream error type, because those need to be propagated to the compiler. +fn process_impl_block( + mut input: ItemImpl, +) -> Result { + let item_impl_info = match ItemImplInfo::new(&mut input) { + Ok(x) => x, + Err(err) => return Err(err.to_compile_error()), + }; + + #[cfg(not(feature = "__abi-generate"))] + let abi_generated = quote! {}; + #[cfg(feature = "__abi-generate")] + let abi_generated = abi::generate(&item_impl_info); + + let generated_code = item_impl_info.wrapper_code(); + + // Add wrapper methods for ext call API + let ext_generated_code = item_impl_info.generate_ext_wrapper_code(); + + Ok(TokenStream::from(quote! { + #ext_generated_code + #input + #generated_code + #abi_generated + }) + .into()) +} + /// `ext_contract` takes a Rust Trait and converts it to a module with static methods. /// Each of these static methods takes positional arguments defined by the Trait, /// then the receiver_id, the attached deposit and the amount of gas and returns a new Promise. diff --git a/near-sdk/compilation_tests/all.rs b/near-sdk/compilation_tests/all.rs index e893c8eba..e78f316e2 100644 --- a/near-sdk/compilation_tests/all.rs +++ b/near-sdk/compilation_tests/all.rs @@ -35,4 +35,5 @@ fn compilation_tests() { t.pass("compilation_tests/handle_result_alias.rs"); t.pass("compilation_tests/contract_metadata.rs"); t.compile_fail("compilation_tests/contract_metadata_fn_name.rs"); + t.pass("compilation_tests/contract_metadata_bindgen.rs"); } diff --git a/near-sdk/compilation_tests/contract_metadata_bindgen.rs b/near-sdk/compilation_tests/contract_metadata_bindgen.rs new file mode 100644 index 000000000..02d9ab5c3 --- /dev/null +++ b/near-sdk/compilation_tests/contract_metadata_bindgen.rs @@ -0,0 +1,20 @@ +use near_account_id::AccountIdRef; +use near_sdk::near_bindgen; + +#[near_bindgen] +struct Contract {} + +#[near_bindgen] +impl Contract { + pub fn anything() {} +} + +#[near_bindgen] +impl Contract { + pub fn anything_else() {} +} + +fn main() { + let ext = Contract::ext(AccountIdRef::new_or_panic("0000").into()); + ext.contract_source_metadata(); +} diff --git a/near-sdk/compilation_tests/impl_generic.rs b/near-sdk/compilation_tests/impl_generic.rs index 4348cdbf9..11f2ec5d7 100644 --- a/near-sdk/compilation_tests/impl_generic.rs +++ b/near-sdk/compilation_tests/impl_generic.rs @@ -2,6 +2,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use near_sdk::near_bindgen; +#[allow(unused_imports)] use std::marker::PhantomData; #[near_bindgen] diff --git a/near-sdk/compilation_tests/impl_generic.stderr b/near-sdk/compilation_tests/impl_generic.stderr index 866318f58..b4850777b 100644 --- a/near-sdk/compilation_tests/impl_generic.stderr +++ b/near-sdk/compilation_tests/impl_generic.stderr @@ -1,5 +1,11 @@ error: Impl type parameters are not supported for smart contracts. - --> $DIR/impl_generic.rs:15:6 + --> compilation_tests/impl_generic.rs:10:20 | -15 | impl<'a, T: 'a + std::fmt::Display> Incrementer { +10 | struct Incrementer { + | ^ + +error: Impl type parameters are not supported for smart contracts. + --> compilation_tests/impl_generic.rs:16:6 + | +16 | impl<'a, T: 'a + std::fmt::Display> Incrementer { | ^^ diff --git a/near-sdk/src/private/mod.rs b/near-sdk/src/private/mod.rs index 631d82dff..c74520618 100644 --- a/near-sdk/src/private/mod.rs +++ b/near-sdk/src/private/mod.rs @@ -5,6 +5,11 @@ pub use near_abi::{ AbiBorshParameter, AbiFunction, AbiFunctionKind, AbiFunctionModifier, AbiJsonParameter, AbiParameters, AbiType, }; +#[cfg(feature = "abi")] +mod result_type_ext; + +#[cfg(feature = "abi")] +pub use result_type_ext::ResultTypeExt; use crate::IntoStorageKey; use borsh::{to_vec, BorshSerialize}; diff --git a/near-sdk/src/types/public_key.rs b/near-sdk/src/types/public_key.rs index 6eeb5c361..3266fe667 100644 --- a/near-sdk/src/types/public_key.rs +++ b/near-sdk/src/types/public_key.rs @@ -268,7 +268,7 @@ mod tests { #[test] fn test_public_key_to_string() { let key: PublicKey = expected_key(); - let actual: String = String::try_from(&key).unwrap(); + let actual: String = String::from(&key); assert_eq!(actual, "ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp"); }