#[near]
Expand description
This attribute macro is used on a struct/enum and its implementations
to generate the necessary code to expose pub
methods from the contract as well
as generating the glue code to be a valid NEAR contract.
The macro is a syntactic sugar for near_bindgen and expands to the near_bindgen macro invocations. Both of them share the same attributes, except for those that are explicitly marked as specific to the near macro. (1, 2)
§Attributes
§#[near(contract_state)]
(annotates structs/enums)
The attribute prepares a struct/enum to be a contract state. Only one contract state is allowed per crate.
A contract type is usually acompanied by an impl
block, annotated with #[near]
.
This attribute is also required to make the #[near(contract_metadata(...))]
attribute work.
contract_state
is specific to the near macro only, not available for near_bindgen.
§Basic example
use near_sdk::near;
#[near(contract_state)]
pub struct Contract {
greeting: String,
}
which usually comes paired with at least one impl block for the contract type,
annotated with a plain #[near]
attribute:
§Using SDK collections for storage
If contract state becomes large, collections from following modules can be used:
§store
module:
use near_sdk::store::IterableMap;
#[near(contract_state)]
pub struct StatusMessage {
records: IterableMap<String, String>,
}
- list of host functions used for
store
implementation - FAQ: mutating state of collections from
store
module is only finally persisted on runningDrop
/flush
§collections
module:
use near_sdk::collections::LookupMap;
#[near(contract_state)]
pub struct StatusMessage {
records: LookupMap<String, String>,
}
- list of host functions used for
collections
implementation
§Reference to Implementation of #[near(contract_state)]
attribute (How does it work?)
§#[near]
(annotates impl blocks)
This macro is used to define the code for view-only and mutating methods for contract types,
annotated by #[near(contract_state)]
.
§Basic example
use near_sdk::{near, log};
#[near]
impl Contract {
// view method
pub fn get_greeting(&self) -> String {
self.greeting.clone()
}
// mutating method
pub fn set_greeting(&mut self, greeting: String) {
log!("Saving greeting: {greeting}");
self.greeting = greeting;
}
}
§Reference to Implementation of #[near]
macro (How does it work?)
§#[near(serializers=[...])
(annotates structs/enums)
The attribute makes the struct or enum serializable with either json or borsh. By default, borsh is used.
serializers
is specific to the near macro only, not available for near_bindgen.
§Make struct/enum serializable with borsh
use near_sdk::near;
#[near(serializers=[borsh])]
pub enum MyEnum {
Variant1,
}
#[near(serializers=[borsh])]
pub struct MyStruct {
pub name: String,
}
// Since [borsh] is the default value, you can simply skip serializers:
#[near]
pub enum MyEnum2 {
Variant1,
}
#[near]
pub struct MyStruct2 {
pub name: String,
}
§Make struct/enum serializable with json
use near_sdk::near;
#[near(serializers=[json])]
pub enum MyEnum {
Variant1,
}
#[near(serializers=[json])]
pub struct MyStruct {
pub name: String,
}
§Make struct/enum serializable with both borsh and json
use near_sdk::near;
#[near(serializers=[borsh, json])]
pub enum MyEnum {
Variant1,
}
#[near(serializers=[borsh, json])]
pub struct MyStruct {
pub name: String,
}
§Customize borsh
serializer
The #[near(serializers = [borsh(...)])]
macro allows you to pass configuration parameters to the borsh
serializer.
This is useful for customizing borsh serialization parameters since, unlike serde, borsh macros do not support repetitive attributes.
use near_sdk::near;
#[near(serializers = [borsh(use_discriminant = true)])]
pub enum MyEnum {
Variant1,
Variant2,
}
§Customize json
serializer
The #[near(serializers = [json])]
macro does not support passing configuration parameters to the json
serializer.
Yet, you can just use #[serde(...)]
attributes as if #[derive(Serialize, Deserialize)]
is added to the struct (which is what actually happens under the hood of #[near(serializers = [json])]
implementation).
use near_sdk::near;
#[near(serializers = [json])]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum MyEnum {
Variant1,
#[serde(alias = "VARIANT_2")]
Variant2,
}
§#[serializer(...)]
(annotates function arguments)
The attribute makes the function argument deserializable from Vec
<u8
> with either json or borsh. By default, json is used.
Please, note that all the arguments of the function should be using the same deserializer.
NOTE: a more correct name for the attribute would be argument_deserializer
, but it’s serializer
for historic reasons.
§Basic example
use near_sdk::near;
#[near]
impl Contract {
pub fn borsh_arguments(&self, #[serializer(borsh)] a: String, #[serializer(borsh)] b: String) {}
}
§Implementation of #[serializer(...)]
attribute and host functions calls used
In a nutshell and if the details of ABI generation layer are put aside,
using the attribute allows to replace default serde_json::from_slice
with borsh::from_slice
.
A bit more thoroughly the effect of the attribute is described in (step 3.1, #[near]
on mutating method).
§#[init]
(annotates methods of a type in its impl
block)
Contract initialization method annotation. More details can be found here
By default, the Default::default()
implementation of a contract will be used to initialize a contract.
There can be a custom initialization function which takes parameters or performs custom logic with the following #[init]
annotation.
You can provide several initialization functions.
§Basic example
use near_sdk::{log, near};
#[near(contract_state)]
#[derive(Default)]
pub struct Counter {
value: u64,
}
#[near]
impl Counter {
#[init]
pub fn new(value: u64) -> Self {
log!("Custom counter initialization!");
Self { value }
}
}
§#[payable]
(annotates methods of a type in its impl
block)
Specifies that the method can accept NEAR tokens. More details can be found here
Methods can be annotated with #[payable]
to allow tokens to be transferred with the method invocation. For more information, see payable methods.
To declare a function as payable, use the #[payable]
annotation as follows:
§Basic example
use near_sdk::near;
#[near(contract_state)]
#[derive(Default)]
pub struct Counter {
val: i8,
}
#[near]
impl Counter {
#[payable]
pub fn my_method(&mut self) {
//...
}
}
§#[private]
(annotates methods of a type in its impl
block)]
The attribute forbids to call the method except from within the contract. This is useful for internal methods that should not be called from outside the contract.
More details can be found here
§Basic example
use near_sdk::near;
#[near(contract_state)]
#[derive(Default)]
pub struct Counter {
val: u64,
}
#[near]
impl Counter {
#[private]
pub fn my_method(&mut self) {
// ...
}
}
§#[deny_unknown_arguments]
(annotates methods of a type in its impl
block)]
Specifies that the method call should error during deserialization if any unknown fields are present in the input. This helps ensure data integrity by rejecting potentially malformed input.
Without this attribute, unknown fields are silently ignored during deserialization.
Implementation uses deny_unknown_fields
serde
’s attribute.
In the following example call of my_method
with
{
"description": "value of description"
}
payload works, but call of my_method
with
{
"description": "value of description",
"unknown_field": "what"
}
payload is declined with a FunctionCallError(ExecutionError("Smart contract panicked: Failed to deserialize input from JSON."))
error.
§Basic example
use near_sdk::near;
#[near(contract_state)]
#[derive(Default)]
pub struct Counter {
val: u64,
}
#[near]
impl Counter {
#[deny_unknown_arguments]
pub fn my_method(&mut self, description: String) {
// ...
}
}
This attribute is not supposed to be used together with #[serializer(borsh)]
arguments’ serializer, and assumes that default json
is used.
If borsh
is used on arguments, usage of deny_unknown_arguments
on method is a no-op.
§#[result_serializer(...)]
(annotates methods of a type in its impl
block)
The attribute defines the serializer for function return serialization.
Only one of borsh
or json
can be specified.
use near_sdk::near;
#[near]
impl MyContract {
#[result_serializer(borsh)]
pub fn borsh_return_value(&self) -> String {
"hello_world".to_string()
}
}
§Implementation of #[result_serializer(...)]
attribute and host functions calls used
In a nutshell and if the details of ABI generation layer are put aside,
using the attribute allows to replace default serde_json::to_vec
with borsh::to_vec
.
A bit more thoroughly the effect of the attribute is described in (step 4.1, #[near] on view method
).
§#[handle_result]
(annotates methods of a type in its impl
block)
Have #[handle_result]
to Support Result types regardless of how they’re referred to
Function marked with #[handle_result]
should return Result<T, E>
(where E implements FunctionError).
If you’re trying to use a type alias for Result
, try #[handle_result(aliased)]
§Basic error handling with Result
use near_sdk::{near, AccountId, Promise, PromiseError};
#[near(contract_state)]
#[derive(Default)]
pub struct Counter {
val: u64,
}
#[near]
impl Counter {
#[handle_result]
pub fn some_function2(
&self,
) -> Result<(), &'static str> {
Err("error")
}
}
§Typed error handling
This example shows how to use error handling in a contract when the error are defined in the contract. This way the contract can utilize result types and panic with the type using its ToString implementation
use near_sdk::{near, FunctionError};
#[derive(FunctionError)]
pub enum MyError {
SomePanicError,
}
impl std::fmt::Display for MyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MyError::SomePanicError => write!(f, "Panic error message that would be displayed to the user"),
}
}
}
#[near]
impl Counter {
#[handle_result]
pub fn some_function(&self) -> Result<(), MyError> {
if self.val == 0 {
return Err(MyError::SomePanicError);
}
Ok(())
}
}
§#[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
andenv::promise_return
are used infactorial
method to set up a callback offactorial_mult
with result of factorial for(n-1)
#[private]
onfactorial_mult
is used to to allow only callingfactorial_mult
from factorial contract method byCrossContract
itself and disallow for it to be called externally by users
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:
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- same example as above, but uses
Promise::then
instead ofenv
host functions calls to set up a callback offactorial_mult
- same example as above, but uses
- examples/callback-results
§Reference to Implementation of #[callback_unwrap]
attribute
§#[near(event_json(...))]
(annotates enums)
By passing event_json
as an argument near
will generate the relevant code to format events
according to NEP-297
For parameter serialization, this macro will generate a wrapper struct to include the NEP-297 standard fields standard
and version
as well as include serialization reformatting to include the event
and data
fields automatically.
The standard
and version
values must be included in the enum and variant declaration (see example below).
By default this will be JSON deserialized with serde
The version is required to allow backward compatibility. The older back-end will use the version field to determine if the event is supported.
§Basic example
use near_sdk::{near, AccountId};
#[near(event_json(standard = "nepXXX"))]
pub enum MyEvents {
#[event_version("1.0.0")]
Swap { token_in: AccountId, token_out: AccountId, amount_in: u128, amount_out: u128 },
#[event_version("2.0.0")]
StringEvent(String),
#[event_version("3.0.0")]
EmptyEvent
}
#[near]
impl Contract {
pub fn some_function(&self) {
MyEvents::StringEvent(
String::from("some_string")
).emit();
}
}
§#[near(contract_metadata(...))]
(annotates structs/enums)
By using contract_metadata
as an argument near
will populate the contract metadata
according to NEP-330
standard. This still applies even when #[near]
is used without
any arguments.
All fields(version, link) are optional and will be populated with defaults from the Cargo.toml file if not specified.
The standard
will be populated with nep330
by default.
Any additional standards can be added and should be specified using the standard
attribute.
The contract_source_metadata()
view function will be added and can be used to retrieve the source metadata.
Also, the source metadata will be stored as a constant, CONTRACT_SOURCE_METADATA
, in the contract code.
Please note that the contract_metadata
will be ignored if #[near(contract_state)]
is not used.
§Basic example
use near_sdk::near;
#[near(contract_state, contract_metadata(
version = "39f2d2646f2f60e18ab53337501370dc02a5661c",
link = "https://github.com/near-examples/nft-tutorial",
standard(standard = "nep171", version = "1.0.0"),
standard(standard = "nep177", version = "2.0.0"),
))]
struct Contract {}
§Implementation of #[near(contract_state)]
attribute and host functions calls used
This heading describes #[near(contract_state)]
.
In a nutshell and if the details of ABI generation layer are put aside,
#[near(contract_state)]
pub struct Contract { /* .. */ }
- Macro adds derived implementations of
borsh::BorshSerialize
/borsh::BorshSerialize
forContract
type - Macro defines a global
CONTRACT_SOURCE_METADATA
variable, which is a string of json serialization ofnear_contract_standards::contract_metadata::ContractSourceMetadata
. - Macro defines
contract_source_metadata
function:which#[no_mangle] pub extern "C" fn contract_source_metadata() { /* .. */ }
- calls
env::setup_panic_hook
host function - calls
env::value_return
host function with bytes ofCONTRACT_SOURCE_METADATA
from step 2.
- calls
§using cargo-expand to view actual macro results
The above is an approximate description of what macro performs.
Running the following in a contract’s crate is a way to introspect more details of its operation:
cargo expand --lib --target wasm32-unknown-unknown
# this has additional code generated for ABI layer
cargo expand --lib --features near-sdk/__abi-generate
§Implementation of #[near]
macro and host functions calls used
This heading describes #[near]
on impl blocks.
In a nutshell and if the details of ABI generation layer are put aside,
#[near]
impl Contract {
pub fn view_method(&self) -> String { todo!("method body") }
pub fn mutating_method(&mut self, argument: String) { /* .. */ }
}
§for above view method #[near]
macro defines the following function:
#[no_mangle]
pub extern "C" fn view_method() { /* .. */ }
which
- calls
env::setup_panic_hook
host function - calls
env::state_read
host function to loadContract
into astate
variableenv::state_read
’s result is unwrapped withOption::unwrap_or_default
PanicOnDefault
may be used to NOT let implementation ofDefault
forContract
value become the outcomeContract
’sstate
, whenenv::state_read
returnsOption::None
- calls original
Contract::view_method(&state)
as defined in#[near]
annotated impl block and saves the returned value into aresult
variable - calls
serde_json::to_vec
on obtainedresult
and saves returned value toserialized_result
variablejson
format can be changed to serializing withborsh::to_vec
by using#[result_serializer(...)]
- if the
serialized_result
is anResult::Err
error, thenenv::panic_str
host function is called to signal result serialization error - otherwise, if the
serialized_result
is aResult::Ok
, thenenv::value_return
host function is called with unwrappedserialized_result
§for above mutating method #[near]
macro defines the following function:
#[no_mangle]
pub extern "C" fn mutating_method() { /* ..*/ }
which
- calls
env::setup_panic_hook
host function - calls
env::input
host function and saves it toinput
variable - deserializes
Contract::mutating_method
arguments by callingserde_json::from_slice
oninput
variable and saves it todeserialized_input
variablejson
format can be changed to deserializing withborsh::from_slice
by using#[serializer(...)]
- if the
deserialized_input
is anResult::Err
error, thenenv::panic_str
host function is called to signal input deserialization error - otherwise, if the
deserialized_input
is aResult::Ok
,deserialized_input
is unwrapped and saved todeserialized_input_success
variable - calls
env::state_read
host function to loadContract
into astate
variableenv::state_read
’s result is unwrapped withOption::unwrap_or_default
PanicOnDefault
may be used to NOT let implementation ofDefault
forContract
value become the outcomeContract
’sstate
, whenenv::state_read
returnsOption::None
- calls original
Contract::mutating_method(&mut state, deserialized_input_success.argument)
as defined in#[near]
annotated impl block - calls
env::state_write
with&state
as argument.
§Implementation of #[callback_unwrap]
attribute and host functions calls used
This heading describes #[callback_unwrap]
.
In a nutshell and if the details of ABI generation layer are put aside,
#[near]
impl Contract {
pub fn method(
&mut self,
regular: String,
#[callback_unwrap] one: String,
#[callback_unwrap] two: String
) { /* .. */ }
}
For above method
using the attribute on arguments, changes the body of function generated in #[near]
on mutating method
#[no_mangle]
pub extern "C" fn method() { /* .. */ }
in the following way:
- arguments, annotated with
#[callback_unwrap]
, are no longer expected to be included intoinput
, deserialized in (step 3,#[near]
on mutating method). - for each argument, annotated with
#[callback_unwrap]
:env::promise_result
host function is called with corresponding index, starting from 0 (0u64
for argumentone
,1u64
for argumenttwo
above), and saved intopromise_result
variable- if the
promise_result
is aPromiseResult::Failed
error, thenenv::panic_str
host function is called to signal callback computation error - otherwise, if the
promise_result
is aPromiseResult::Successful
, it’s unwrapped and saved to adata
variable data
is deserialized similar to that as usual (step 3,#[near]
on mutating method), and saved todeserialized_n_promise
variable
- counterpart of (step 7,
#[near]
on mutating method): original method is calledContract::method(&mut state, deserialized_input_success.regular, deserialized_0_promise, deserialized_1_promise)
, as defined in#[near]
annotated impl block