Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: document callback_unwrap attribute #1313

Merged
merged 9 commits into from
Feb 25, 2025
37 changes: 0 additions & 37 deletions near-sdk-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,43 +374,6 @@ pub fn ext_contract(attr: TokenStream, item: TokenStream) -> TokenStream {
}
}

// The below attributes a marker-attributes and therefore they are no-op.

/// `callback` is a marker attribute it does not generate code by itself.
#[proc_macro_attribute]
#[deprecated(since = "4.0.0", note = "Case is handled internally by macro, no need to import")]
pub fn callback(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}

/// `callback_args_vec` is a marker attribute it does not generate code by itself.
#[deprecated(since = "4.0.0", note = "Case is handled internally by macro, no need to import")]
#[proc_macro_attribute]
pub fn callback_vec(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}

/// `serializer` is a marker attribute it does not generate code by itself.
#[deprecated(since = "4.0.0", note = "Case is handled internally by macro, no need to import")]
#[proc_macro_attribute]
pub fn serializer(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}

/// `result_serializer` is a marker attribute it does not generate code by itself.
#[deprecated(since = "4.0.0", note = "Case is handled internally by macro, no need to import")]
#[proc_macro_attribute]
pub fn result_serializer(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}

/// `init` is a marker attribute it does not generate code by itself.
#[deprecated(since = "4.0.0", note = "Case is handled internally by macro, no need to import")]
#[proc_macro_attribute]
pub fn init(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}

#[cfg(feature = "abi")]
#[derive(darling::FromDeriveInput, Debug)]
#[darling(attributes(abi), forward_attrs(serde, borsh_skip, schemars, validate))]
Expand Down
2 changes: 1 addition & 1 deletion near-sdk/compilation_tests/schema_derive_invalids.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ error[E0277]: the trait bound `Inner: JsonSchema` is not satisfied
(T0, T1, T2, T3, T4, T5)
and $N others
note: required by a bound in `SchemaGenerator::subschema_for`
--> $CARGO/schemars-0.8.21/src/gen.rs
--> $CARGO/schemars-0.8.22/src/gen.rs
|
| pub fn subschema_for<T: ?Sized + JsonSchema>(&mut self) -> Schema {
| ^^^^^^^^^^ required by this bound in `SchemaGenerator::subschema_for`
14 changes: 11 additions & 3 deletions near-sdk/src/environment/env.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
//! Blockchain-specific methods available to the smart contract that allow to interact with NEAR runtime.
//! This is a wrapper around a low-level [`near_sys`](near_sys). Unless you know what you are doing prefer using `env::*`
//! whenever possible. In case of cross-contract calls prefer using even higher-level API available
//! through `callback_args`, `callback_args_vec`, `ext_contract`, `Promise`, and `PromiseOrValue`.
//! This is a wrapper around a low-level [`near_sys`](near_sys).
//!
//! Unless you know what you are doing prefer using `env::*`
//! whenever possible.
//!
//! In case of cross-contract calls prefer using higher-level API available
//! through [`crate::Promise`], and [`crate::PromiseOrValue<T>`].

use std::convert::TryInto;
use std::mem::{size_of, size_of_val};
Expand Down Expand Up @@ -754,7 +758,9 @@ pub fn alt_bn128_pairing_check(value: &[u8]) -> bool {
/// ```
///
/// More info about promises in [NEAR documentation](https://docs.near.org/build/smart-contracts/anatomy/crosscontract#promises)
///
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_create`]
///
/// Example usages of this low-level api are <https://github.com/near/near-sdk-rs/tree/master/examples/factory-contract/low-level/src/lib.rs> and <https://github.com/near/near-sdk-rs/blob/master/examples/cross-contract-calls/low-level/src/lib.rs>
///
pub fn promise_create(
Expand Down Expand Up @@ -810,6 +816,7 @@ pub fn promise_create(
/// );
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_then`]
///
/// Example usages of this low-level api are <https://github.com/near/near-sdk-rs/tree/master/examples/factory-contract/low-level/src/lib.rs> and <https://github.com/near/near-sdk-rs/blob/master/examples/cross-contract-calls/low-level/src/lib.rs>
pub fn promise_then(
promise_idx: PromiseIndex,
Expand Down Expand Up @@ -1466,6 +1473,7 @@ pub(crate) fn promise_result_internal(result_idx: u64) -> Result<(), PromiseErro
/// promise_return(promise);
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_return`]
///
/// Example usages: [one](https://github.com/near/near-sdk-rs/tree/master/examples/cross-contract-calls/low-level/src/lib.rs), [two](https://github.com/near/near-sdk-rs/tree/master/examples/factory-contract/low-level/src/lib.rs)
pub fn promise_return(promise_idx: PromiseIndex) {
unsafe { sys::promise_return(promise_idx.0) }
Expand Down
88 changes: 88 additions & 0 deletions near-sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,94 @@ extern crate quickcheck;
/// }
/// ```
///
/// ## `#[callback_unwrap]` (annotates function arguments)
///
/// Automatically unwraps the successful result of a callback from a cross-contract call.
/// Used on parameters in callback methods that are invoked as part of a cross-contract call chain.
/// If the promise fails, the method will panic with the error message.
///
/// This attribute is commonly used with [`Promise`] or [`PromiseOrValue<T>`] as the return type of another contract method,
/// whose return value will be passed as argument to `#[callback_unwrap]`-annotated argument
///
/// ### Example with Cross-Contract Factorial:
///
/// In the example:
/// - lower level [`env::promise_create`], [`env::promise_then`] and [`env::promise_return`] are used in
/// `factorial` method to set up a callback of `factorial_mult` with result of factorial for `(n-1)`
/// - [`#[private]`](near#private-annotates-methods-of-a-type-in-its-impl-block) on `factorial_mult` is used to
/// to allow only calling `factorial_mult` from factorial contract method by `CrossContract` itself
/// and disallow for it to be called externally by users
///
/// ```rust
/// use near_sdk::{near, env, log, NearToken, Gas};
///
/// // Prepaid gas for a single (not inclusive of recursion) `factorial` call.
/// const FACTORIAL_CALL_GAS: Gas = Gas::from_tgas(20);
///
/// // Prepaid gas for a single `factorial_mult` call.
/// const FACTORIAL_MULT_CALL_GAS: Gas = Gas::from_tgas(10);
///
/// #[near(contract_state)]
/// #[derive(Default)]
/// pub struct CrossContract {}
///
/// #[near]
/// impl CrossContract {
/// pub fn factorial(&self, n: u32) {
/// if n <= 1 {
/// env::value_return(&serde_json::to_vec(&1u32).unwrap());
/// return;
/// }
/// let account_id = env::current_account_id();
/// let prepaid_gas = env::prepaid_gas().saturating_sub(FACTORIAL_CALL_GAS);
/// let promise0 = env::promise_create(
/// account_id.clone(),
/// "factorial",
/// &serde_json::to_vec(&(n - 1,)).unwrap(),
/// NearToken::from_near(0),
/// prepaid_gas.saturating_sub(FACTORIAL_MULT_CALL_GAS),
/// );
/// let promise1 = env::promise_then(
/// promise0,
/// account_id,
/// "factorial_mult",
/// &serde_json::to_vec(&(n,)).unwrap(),
/// NearToken::from_near(0),
/// FACTORIAL_MULT_CALL_GAS,
/// );
/// env::promise_return(promise1);
/// }
///
/// #[private]
/// pub fn factorial_mult(&self, n: u32, #[callback_unwrap] factorial_n_minus_one_result: u32) -> u32 {
/// log!("Received n: {:?}", n);
/// log!("Received factorial_n_minus_one_result: {:?}", factorial_n_minus_one_result);
///
/// let result = n * factorial_n_minus_one_result;
///
/// log!("Multiplied {:?}", result.clone());
/// result
/// }
/// }
/// ```
/// which has the following lines in a `factorial`'s view call log:
///
/// ```bash,ignore
/// logs: [
/// "Received n: 5",
/// "Received factorial_n_minus_one_result: 24",
/// "Multiplied 120",
/// ],
/// ```
///
/// ### Other examples within repo:
///
/// - `Cross-Contract Factorial` again [examples/cross-contract-calls](https://github.com/near/near-sdk-rs/blob/9596835369467cac6198e8de9a4b72a38deee4a5/examples/cross-contract-calls/high-level/src/lib.rs?plain=1#L26)
/// - same example as [above](near#example-with-cross-contract-factorial), but uses [`Promise::then`] instead of [`env`](mod@env) host functions calls to set up a callback of `factorial_mult`
/// - [examples/adder](https://github.com/near/near-sdk-rs/blob/9596835369467cac6198e8de9a4b72a38deee4a5/examples/adder/src/lib.rs?plain=1#L30)
/// - [examples/adder](https://github.com/near/near-sdk-rs/blob/9596835369467cac6198e8de9a4b72a38deee4a5/examples/adder/src/lib.rs?plain=1#L31)
/// - [examples/callback-results](https://github.com/near/near-sdk-rs/blob/9596835369467cac6198e8de9a4b72a38deee4a5/examples/callback-results/src/lib.rs?plain=1#L51)
///
/// ## `#[near(event_json(...))]` (annotates enums)
///
/// By passing `event_json` as an argument `near` will generate the relevant code to format events
Expand Down
27 changes: 16 additions & 11 deletions near-sdk/src/near_annotations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@
//! This is not a real module; here we document the attributes that [`#[near]`](crate::near)
//! and [`#[near_bindgen]`](crate::near_bindgen) macro use.
//!
//! `near_bindgen` and `near_sdk` shares almost the same attributes:
//! * init
//! * payable
//! * private
//! * handle_result
//! * event_json
//! * contract_metadata
//! * serializer
//! `near_bindgen` and `near_sdk` share most of the attributes:
//! * `init`
//! * `payable`
//! * `private`
//! * `handle_result`
//! * `callback_unwrap`
//! * `event_json`
//! * `contract_metadata`
//! * `serializer`
//! * `result_serializer`
//!
//! These attributes are only part of the `near` macro.
//! * serializers
//! * contract_state
//! Following attributes are only part of the `near` macro:
//! * `serializers`
//! * `contract_state`

/// See [`near_sdk::near #[init]`](crate::near#init-annotates-methods-of-a-type-in-its-impl-block)
pub fn init() {}
Expand All @@ -31,6 +33,9 @@ pub fn result_serializer() {}
/// See [`near_sdk::near #[handle_result]`](crate::near#handle_result-annotates-methods-of-a-type-in-its-impl-block)
pub fn handle_result() {}

/// See [`near_sdk::near #[callback_unwrap]`](crate::near#callback_unwrap-annotates-function-arguments)
pub fn callback_unwrap() {}

/// See [`near_sdk::near #[near(event_json(...))]`](crate::near#nearevent_json-annotates-enums)
pub fn event_json() {}

Expand Down
Loading