From e0a9b54ba0a6507218be8f00ad7b6a1eaf9f89e6 Mon Sep 17 00:00:00 2001 From: Den <41162202+denbite@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:00:41 +0100 Subject: [PATCH] doc: examples for Near-related host functions (#1259) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: add examples for Near-related host functions * docs: resolve compilation errors in doctests * docs: add use case description to Storage API host functions along with reference to implementation repo example --------- Co-authored-by: dj8yf0μl <26653921+dj8yfo@users.noreply.github.com> --- near-sdk/src/environment/env.rs | 836 +++++++++++++++++++++++++++++++- 1 file changed, 831 insertions(+), 5 deletions(-) diff --git a/near-sdk/src/environment/env.rs b/near-sdk/src/environment/env.rs index e439318d4..462250df9 100644 --- a/near-sdk/src/environment/env.rs +++ b/near-sdk/src/environment/env.rs @@ -152,23 +152,59 @@ pub fn register_len(register_id: u64) -> Option { // # Context API # // ############### /// The id of the account that owns the current contract. +/// +/// # Examples +/// ``` +/// use near_sdk::env::current_account_id; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// assert_eq!(current_account_id(), AccountId::from_str("alice.near").unwrap()); +/// ``` pub fn current_account_id() -> AccountId { assert_valid_account_id(method_into_register!(current_account_id)) } /// The id of the account that either signed the original transaction or issued the initial /// cross-contract call. +/// +/// # Examples +/// ``` +/// use near_sdk::env::signer_account_id; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// assert_eq!(signer_account_id(), AccountId::from_str("bob.near").unwrap()); +/// ``` pub fn signer_account_id() -> AccountId { assert_valid_account_id(method_into_register!(signer_account_id)) } /// The public key of the account that did the signing. +/// +/// # Examples +/// ``` +/// use near_sdk::env::signer_account_pk; +/// use near_sdk::{PublicKey, CurveType}; +/// +/// let pk = PublicKey::from_parts(near_sdk::CurveType::ED25519, vec![0; 32]).unwrap(); +/// assert_eq!(signer_account_pk(), pk); +/// ``` pub fn signer_account_pk() -> PublicKey { PublicKey::try_from(method_into_register!(signer_account_pk)).unwrap_or_else(|_| abort()) } /// The id of the account that was the previous contract in the chain of cross-contract calls. /// If this is the first contract, it is equal to `signer_account_id`. +/// +/// # Examples +/// ``` +/// use near_sdk::env::predecessor_account_id; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// assert_eq!(predecessor_account_id(), AccountId::from_str("bob.near").unwrap()); +/// ``` pub fn predecessor_account_id() -> AccountId { assert_valid_account_id(method_into_register!(predecessor_account_id)) } @@ -182,37 +218,86 @@ fn assert_valid_account_id(bytes: Vec) -> AccountId { } /// The input to the contract call serialized as bytes. If input is not provided returns `None`. +/// +/// # Examples +/// ``` +/// use near_sdk::env::input; +/// +/// assert_eq!(input(), Some(Vec::new())); +/// ``` pub fn input() -> Option> { try_method_into_register!(input) } /// Current block index. +/// +/// # Examples +/// ``` +/// use near_sdk::env::block_index; +/// +/// assert_eq!(block_index(), 0); +/// ``` #[deprecated(since = "4.0.0", note = "Use block_height instead")] pub fn block_index() -> BlockHeight { block_height() } /// Returns the height of the block the transaction is being executed in. +/// +/// # Examples +/// ``` +/// use near_sdk::env::block_height; +/// +/// assert_eq!(block_height(), 0); +/// ``` pub fn block_height() -> BlockHeight { unsafe { sys::block_height() } } /// Current block timestamp, i.e, number of non-leap-nanoseconds since January 1, 1970 0:00:00 UTC. +/// +/// # Examples +/// ``` +/// use near_sdk::env::block_timestamp; +/// +/// assert_eq!(block_timestamp(), 0); +/// ``` pub fn block_timestamp() -> u64 { unsafe { sys::block_timestamp() } } /// Current block timestamp, i.e, number of non-leap-milliseconds since January 1, 1970 0:00:00 UTC. +/// +/// # Examples +/// ``` +/// use near_sdk::env::block_timestamp_ms; +/// +/// assert_eq!(block_timestamp_ms(), 0); +/// ``` pub fn block_timestamp_ms() -> u64 { block_timestamp() / 1_000_000 } /// Current epoch height. +/// +/// # Examples +/// ``` +/// use near_sdk::env::epoch_height; +/// +/// assert_eq!(epoch_height(), 0); +/// ``` pub fn epoch_height() -> u64 { unsafe { sys::epoch_height() } } /// Current total storage usage of this smart contract that this account would be paying for. +/// +/// # Examples +/// ``` +/// use near_sdk::env::storage_usage; +/// +/// assert_eq!(storage_usage(), 307200); +/// ``` pub fn storage_usage() -> StorageUsage { unsafe { sys::storage_usage() } } @@ -222,6 +307,14 @@ pub fn storage_usage() -> StorageUsage { // ################# /// The balance attached to the given account. This includes the attached_deposit that was /// attached to the transaction +/// +/// # Examples +/// ``` +/// use near_sdk::env::account_balance; +/// use near_sdk::NearToken; +/// +/// assert_eq!(account_balance(), NearToken::from_near(100)); +/// ``` pub fn account_balance() -> NearToken { let data = [0u8; size_of::()]; unsafe { sys::account_balance(data.as_ptr() as u64) }; @@ -229,6 +322,14 @@ pub fn account_balance() -> NearToken { } /// The balance locked for potential validator staking. +/// +/// # Examples +/// ``` +/// use near_sdk::env::account_locked_balance; +/// use near_sdk::NearToken; +/// +/// assert_eq!(account_locked_balance(), NearToken::from_yoctonear(0)); +/// ``` pub fn account_locked_balance() -> NearToken { let data = [0u8; size_of::()]; unsafe { sys::account_locked_balance(data.as_ptr() as u64) }; @@ -237,6 +338,14 @@ pub fn account_locked_balance() -> NearToken { /// The balance that was attached to the call that will be immediately deposited before the /// contract execution starts +/// +/// # Examples +/// ``` +/// use near_sdk::env::attached_deposit; +/// use near_sdk::NearToken; +/// +/// assert_eq!(attached_deposit(), NearToken::from_yoctonear(0)); +/// ``` pub fn attached_deposit() -> NearToken { let data = [0u8; size_of::()]; unsafe { sys::attached_deposit(data.as_ptr() as u64) }; @@ -244,11 +353,27 @@ pub fn attached_deposit() -> NearToken { } /// The amount of gas attached to the call that can be used to pay for the gas fees. +/// +/// # Examples +/// ``` +/// use near_sdk::env::prepaid_gas; +/// use near_sdk::Gas; +/// +/// assert_eq!(prepaid_gas(), Gas::from_tgas(300)); +/// ``` pub fn prepaid_gas() -> Gas { Gas::from_gas(unsafe { sys::prepaid_gas() }) } /// The gas that was already burnt during the contract execution (cannot exceed `prepaid_gas`) +/// +/// # Examples +/// ``` +/// use near_sdk::env::used_gas; +/// use near_sdk::Gas; +/// +/// assert_eq!(used_gas(), Gas::from_gas(264768111)); +/// ``` pub fn used_gas() -> Gas { Gas::from_gas(unsafe { sys::used_gas() }) } @@ -260,6 +385,13 @@ pub fn used_gas() -> Gas { /// Returns the random seed from the current block. This 32 byte hash is based on the VRF value from /// the block. This value is not modified in any way each time this function is called within the /// same method/block. +/// +/// # Examples +/// ``` +/// use near_sdk::env::random_seed; +/// +/// assert_eq!(random_seed(), vec![0; 32]); +/// ``` pub fn random_seed() -> Vec { random_seed_array().to_vec() } @@ -326,7 +458,6 @@ pub fn random_seed_array() -> [u8; 32] { /// Hashes the random sequence of bytes using sha256. /// /// # Examples -/// /// ``` /// use near_sdk::env::sha256; /// use hex; @@ -341,11 +472,35 @@ pub fn sha256(value: &[u8]) -> Vec { } /// Hashes the random sequence of bytes using keccak256. +/// +/// # Examples +/// ``` +/// use near_sdk::env::keccak256; +/// use hex; +/// +/// assert_eq!( +/// keccak256(b"The phrase that will be hashed"), +/// hex::decode("b244af9dd4aada2eda59130bbcff112f29b427d924b654aaeb5a0384fa9afed4") +/// .expect("Decoding failed") +/// ); +/// ``` pub fn keccak256(value: &[u8]) -> Vec { keccak256_array(value).to_vec() } /// Hashes the random sequence of bytes using keccak512. +/// +/// # Examples +/// ``` +/// use near_sdk::env::keccak512; +/// use hex; +/// +/// assert_eq!( +/// keccak512(b"The phrase that will be hashed"), +/// hex::decode("29a7df7b889a443fdfbd769adb57ef7e98e6159187b582baba778c06e8b41a75f61367257e8c525a95b3f13ddf432f115d1df128a910c8fc93221db136d92b31") +/// .expect("Decoding failed") +/// ); +/// ``` pub fn keccak512(value: &[u8]) -> Vec { keccak512_array(value).to_vec() } @@ -353,7 +508,6 @@ pub fn keccak512(value: &[u8]) -> Vec { /// Hashes the bytes using the SHA-256 hash function. This returns a 32 byte hash. /// /// # Examples -/// /// ``` /// use near_sdk::env::sha256_array; /// use hex; @@ -376,6 +530,19 @@ pub fn sha256_array(value: &[u8]) -> [u8; 32] { } /// Hashes the bytes using the Keccak-256 hash function. This returns a 32 byte hash. +/// +/// # Examples +/// ``` +/// use near_sdk::env::keccak256_array; +/// use hex; +/// +/// assert_eq!( +/// &keccak256_array(b"The phrase that will be hashed"), +/// hex::decode("b244af9dd4aada2eda59130bbcff112f29b427d924b654aaeb5a0384fa9afed4") +/// .expect("Decoding failed") +/// .as_slice() +/// ); +/// ``` pub fn keccak256_array(value: &[u8]) -> [u8; 32] { //* SAFETY: keccak256 syscall will always generate 32 bytes inside of the atomic op register //* so the read will have a sufficient buffer of 32, and can transmute from uninit @@ -387,6 +554,19 @@ pub fn keccak256_array(value: &[u8]) -> [u8; 32] { } /// Hashes the bytes using the Keccak-512 hash function. This returns a 64 byte hash. +/// +/// # Examples +/// ``` +/// use near_sdk::env::keccak512_array; +/// use hex; +/// +/// assert_eq!( +/// &keccak512_array(b"The phrase that will be hashed"), +/// hex::decode("29a7df7b889a443fdfbd769adb57ef7e98e6159187b582baba778c06e8b41a75f61367257e8c525a95b3f13ddf432f115d1df128a910c8fc93221db136d92b31") +/// .expect("Decoding failed") +/// .as_slice() +/// ); +/// ``` pub fn keccak512_array(value: &[u8]) -> [u8; 64] { //* SAFETY: keccak512 syscall will always generate 64 bytes inside of the atomic op register //* so the read will have a sufficient buffer of 64, and can transmute from uninit @@ -398,6 +578,19 @@ pub fn keccak512_array(value: &[u8]) -> [u8; 64] { } /// Hashes the bytes using the RIPEMD-160 hash function. This returns a 20 byte hash. +/// +/// # Examples +/// ``` +/// use near_sdk::env::ripemd160_array; +/// use hex; +/// +/// assert_eq!( +/// &ripemd160_array(b"The phrase that will be hashed"), +/// hex::decode("9a48b9195fcb14cfe6051c0a1be7882efcadaed8") +/// .expect("Decoding failed") +/// .as_slice() +/// ); +/// ``` pub fn ripemd160_array(value: &[u8]) -> [u8; 20] { //* SAFETY: ripemd160 syscall will always generate 20 bytes inside of the atomic op register //* so the read will have a sufficient buffer of 20, and can transmute from uninit @@ -441,6 +634,46 @@ pub fn ecrecover( } /// Verifies signature of message using provided ED25519 Public Key +/// +/// # Examples +/// ``` +/// use near_sdk::env::ed25519_verify; +/// use hex; +/// +/// assert_eq!( +/// ed25519_verify( +/// hex::decode("41C44494DAB13009BE73D2CCBD3A49677DDC1F26AD2823CE72833CE4B9603F77CA70A9E179272D92D28E8B2AE7006747C87AB1890362A50347EFF553F5EC4008") +/// .expect("Decoding failed") +/// .as_slice() +/// .try_into() +/// .unwrap(), +/// b"Hello world!", +/// hex::decode("9C16937BF04CCE709FED52344C43634F1E7A05FC29DD41F48844C3588C7FE663") +/// .expect("Decoding failed") +/// .as_slice() +/// .try_into() +/// .unwrap(), +/// ), +/// true +/// ); +/// +/// assert_eq!( +/// ed25519_verify( +/// hex::decode("41C44494DAB13009BE73D2CCBD3A49677DDC1F26AD2823CE72833CE4B9603F77CA70A9E179272D92D28E8B2AE7006747C87AB1890362A50347EFF553F5EC4008") +/// .expect("Decoding failed") +/// .as_slice() +/// .try_into() +/// .unwrap(), +/// b"Modified message!", +/// hex::decode("9C16937BF04CCE709FED52344C43634F1E7A05FC29DD41F48844C3588C7FE663") +/// .expect("Decoding failed") +/// .as_slice() +/// .try_into() +/// .unwrap(), +/// ), +/// false +/// ); +/// ``` pub fn ed25519_verify(signature: &[u8; 64], message: &[u8], public_key: &[u8; 32]) -> bool { unsafe { sys::ed25519_verify( @@ -500,6 +733,24 @@ pub fn alt_bn128_pairing_check(value: &[u8]) -> bool { // ################ /// Creates a promise that will execute a method on account with given arguments and attaches /// the given amount and gas. +/// +/// # Examples +/// ``` +/// use near_sdk::env::promise_create; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise = promise_create( +/// AccountId::from_str("counter.near").unwrap(), +/// "increment", +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// ``` pub fn promise_create( account_id: AccountId, function_name: &str, @@ -523,6 +774,35 @@ pub fn promise_create( } /// Attaches the callback that is executed after promise pointed by `promise_idx` is complete. +/// +/// # Examples +/// ``` +/// use near_sdk::env::{promise_create, promise_then}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise = promise_create( +/// AccountId::from_str("counter.near").unwrap(), +/// "increment", +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// +/// let chained_promise = promise_then( +/// promise, +/// AccountId::from_str("greetings.near").unwrap(), +/// "set_greeting", +/// serde_json::json!({ +/// "text": "Hello World" +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(4000000000000), +/// Gas::from_tgas(30) +/// ); +/// ``` pub fn promise_then( promise_idx: PromiseIndex, account_id: AccountId, @@ -548,6 +828,36 @@ pub fn promise_then( } /// Creates a new promise which completes when time all promises passed as arguments complete. +/// +/// # Examples +/// ``` +/// use near_sdk::env::{promise_create, promise_and}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise1 = promise_create( +/// AccountId::from_str("counter.near").unwrap(), +/// "increment", +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// +/// let promise2 = promise_create( +/// AccountId::from_str("greetings.near").unwrap(), +/// "set_greeting", +/// serde_json::json!({ +/// "text": "Hello World" +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(4000000000000), +/// Gas::from_tgas(30) +/// ); +/// +/// let chained_promise = promise_and(&[promise1, promise2]); +/// ``` pub fn promise_and(promise_indices: &[PromiseIndex]) -> PromiseIndex { let mut data = vec![0u8; size_of_val(promise_indices)]; for i in 0..promise_indices.len() { @@ -557,6 +867,16 @@ pub fn promise_and(promise_indices: &[PromiseIndex]) -> PromiseIndex { unsafe { PromiseIndex(sys::promise_and(data.as_ptr() as _, promise_indices.len() as _)) } } +/// # Examples +/// ``` +/// use near_sdk::env::promise_batch_create; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// ``` pub fn promise_batch_create(account_id: &AccountId) -> PromiseIndex { let account_id: &str = account_id.as_ref(); unsafe { @@ -564,6 +884,28 @@ pub fn promise_batch_create(account_id: &AccountId) -> PromiseIndex { } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_then, promise_create}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise = promise_create( +/// AccountId::from_str("counter.near").unwrap(), +/// "increment", +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// +/// let new_promise = promise_batch_then( +/// promise, +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// ``` pub fn promise_batch_then(promise_index: PromiseIndex, account_id: &AccountId) -> PromiseIndex { let account_id: &str = account_id.as_ref(); unsafe { @@ -575,10 +917,35 @@ pub fn promise_batch_then(promise_index: PromiseIndex, account_id: &AccountId) - } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_create_account, promise_batch_create}; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("new_account.near").unwrap() +/// ); +/// +/// promise_batch_action_create_account(promise); +/// ``` pub fn promise_batch_action_create_account(promise_index: PromiseIndex) { unsafe { sys::promise_batch_action_create_account(promise_index.0) } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_deploy_contract, promise_batch_create}; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("contract.near").unwrap() +/// ); +/// +/// let code = [0; 1487]; +/// promise_batch_action_deploy_contract(promise, &code); +/// ``` pub fn promise_batch_action_deploy_contract(promise_index: PromiseIndex, code: &[u8]) { unsafe { sys::promise_batch_action_deploy_contract( @@ -589,6 +956,25 @@ pub fn promise_batch_action_deploy_contract(promise_index: PromiseIndex, code: & } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_function_call, promise_batch_create}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("counter.near").unwrap() +/// ); +/// +/// promise_batch_action_function_call( +/// promise, +/// "increase", +/// serde_json::json!({ "value": 5 }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// ``` pub fn promise_batch_action_function_call( promise_index: PromiseIndex, function_name: &str, @@ -609,6 +995,26 @@ pub fn promise_batch_action_function_call( } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_function_call_weight, promise_batch_create}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas, GasWeight}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("counter.near").unwrap() +/// ); +/// +/// promise_batch_action_function_call_weight( +/// promise, +/// "increase", +/// serde_json::json!({ "value": 5 }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30), +/// GasWeight(1) +/// ); +/// ``` pub fn promise_batch_action_function_call_weight( promise_index: PromiseIndex, function_name: &str, @@ -631,6 +1037,21 @@ pub fn promise_batch_action_function_call_weight( } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_transfer, promise_batch_create}; +/// use near_sdk::{NearToken, AccountId}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// promise_batch_action_transfer( +/// promise, +/// NearToken::from_near(1), +/// ); +/// ``` pub fn promise_batch_action_transfer(promise_index: PromiseIndex, amount: NearToken) { unsafe { sys::promise_batch_action_transfer( @@ -640,6 +1061,23 @@ pub fn promise_batch_action_transfer(promise_index: PromiseIndex, amount: NearTo } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_stake, promise_batch_create}; +/// use near_sdk::{NearToken, PublicKey, AccountId}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// promise_batch_action_stake( +/// promise, +/// NearToken::from_near(1), +/// &pk +/// ); +/// ``` pub fn promise_batch_action_stake( promise_index: PromiseIndex, amount: NearToken, @@ -654,6 +1092,25 @@ pub fn promise_batch_action_stake( ) } } + +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_add_key_with_full_access, promise_batch_create}; +/// use near_sdk::{PublicKey, AccountId}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// let nonce = 55; +/// promise_batch_action_add_key_with_full_access( +/// promise, +/// &pk, +/// nonce +/// ); +/// ``` pub fn promise_batch_action_add_key_with_full_access( promise_index: PromiseIndex, public_key: &PublicKey, @@ -674,6 +1131,27 @@ pub(crate) fn migrate_to_allowance(allowance: NearToken) -> Allowance { Allowance::limited(allowance).unwrap_or(Allowance::Unlimited) } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_add_key_with_function_call, promise_batch_create}; +/// use near_sdk::{PublicKey, AccountId, NearToken}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// let nonce = 55; +/// promise_batch_action_add_key_with_function_call( +/// promise, +/// &pk, +/// nonce, +/// NearToken::from_near(1), +/// &AccountId::from_str("counter.near").unwrap(), +/// "increase,decrease" +/// ); +/// ``` #[deprecated(since = "5.0.0", note = "Use add_access_key_allowance instead")] pub fn promise_batch_action_add_key_with_function_call( promise_index: PromiseIndex, @@ -694,6 +1172,50 @@ pub fn promise_batch_action_add_key_with_function_call( ) } +/// # Examples +/// Unlimited allowance +/// ``` +/// use near_sdk::env::{promise_batch_action_add_key_allowance_with_function_call, promise_batch_create}; +/// use near_sdk::{PublicKey, AccountId, Allowance}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// let nonce = 55; +/// promise_batch_action_add_key_allowance_with_function_call( +/// promise, +/// &pk, +/// nonce, +/// Allowance::unlimited(), +/// &AccountId::from_str("counter.near").unwrap(), +/// "increase,decrease" +/// ); +/// ``` +/// +/// Limited allowance (1 NEAR) +/// ``` +/// use near_sdk::env::{promise_batch_action_add_key_allowance_with_function_call, promise_batch_create}; +/// use near_sdk::{PublicKey, AccountId, Allowance, NearToken}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// let nonce = 55; +/// promise_batch_action_add_key_allowance_with_function_call( +/// promise, +/// &pk, +/// nonce, +/// Allowance::limited(NearToken::from_near(1)).unwrap(), +/// &AccountId::from_str("counter.near").unwrap(), +/// "increase,decrease" +/// ); +/// ``` pub fn promise_batch_action_add_key_allowance_with_function_call( promise_index: PromiseIndex, public_key: &PublicKey, @@ -721,6 +1243,23 @@ pub fn promise_batch_action_add_key_allowance_with_function_call( ) } } + +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_delete_key, promise_batch_create}; +/// use near_sdk::{PublicKey, AccountId}; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// let pk: PublicKey = "secp256k1:qMoRgcoXai4mBPsdbHi1wfyxF9TdbPCF4qSDQTRP3TfescSRoUdSx6nmeQoN3aiwGzwMyGXAb1gUjBTv5AY8DXj".parse().unwrap(); +/// promise_batch_action_delete_key( +/// promise, +/// &pk +/// ); +/// ``` pub fn promise_batch_action_delete_key(promise_index: PromiseIndex, public_key: &PublicKey) { unsafe { sys::promise_batch_action_delete_key( @@ -731,6 +1270,21 @@ pub fn promise_batch_action_delete_key(promise_index: PromiseIndex, public_key: } } +/// # Examples +/// ``` +/// use near_sdk::env::{promise_batch_action_delete_account, promise_batch_create}; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// let promise = promise_batch_create( +/// &AccountId::from_str("receiver.near").unwrap() +/// ); +/// +/// promise_batch_action_delete_account( +/// promise, +/// &AccountId::from_str("beneficiary.near").unwrap() +/// ); +/// ``` pub fn promise_batch_action_delete_account( promise_index: PromiseIndex, beneficiary_id: &AccountId, @@ -748,11 +1302,41 @@ pub fn promise_batch_action_delete_account( /// If the current function is invoked by a callback we can access the execution results of the /// promises that caused the callback. This function returns the number of complete and /// incomplete callbacks. +/// +/// # Examples +/// ``` +/// use near_sdk::env::promise_results_count; +/// +/// assert_eq!(promise_results_count(), 0); +/// ``` pub fn promise_results_count() -> u64 { unsafe { sys::promise_results_count() } } /// If the current function is invoked by a callback we can access the execution results of the /// promises that caused the callback. +/// +/// # Examples +/// ```no_run +/// use near_sdk::env::{promise_result, promise_results_count, log_str}; +/// use near_sdk::PromiseResult; +/// +/// assert!(promise_results_count() > 0); +/// +/// // The promise_index will be in the range [0, n) +/// // where n is the number of promises triggering this callback, +/// // retrieved from promise_results_count() +/// let promise_index = 0; +/// let result = promise_result(promise_index); +/// +/// match result { +/// PromiseResult::Successful(data) => { +/// log_str(format!("Result as Vec: {:?}", data).as_str()); +/// } +/// PromiseResult::Failed => { +/// log_str("Promise failed!"); +/// } +/// }; +/// ``` pub fn promise_result(result_idx: u64) -> PromiseResult { match promise_result_internal(result_idx) { Ok(()) => { @@ -770,8 +1354,29 @@ pub(crate) fn promise_result_internal(result_idx: u64) -> Result<(), PromiseErro _ => abort(), } } + /// Consider the execution result of promise under `promise_idx` as execution result of this /// function. +/// +/// # Examples +/// ``` +/// use near_sdk::env::{promise_create, promise_return}; +/// use near_sdk::serde_json; +/// use near_sdk::{AccountId, NearToken, Gas}; +/// use std::str::FromStr; +/// +/// let promise = promise_create( +/// AccountId::from_str("counter.near").unwrap(), +/// "increment", +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// NearToken::from_yoctonear(0), +/// Gas::from_tgas(30) +/// ); +/// +/// promise_return(promise); +/// ``` pub fn promise_return(promise_idx: PromiseIndex) { unsafe { sys::promise_return(promise_idx.0) } } @@ -786,6 +1391,42 @@ pub fn promise_return(promise_idx: PromiseIndex) { /// /// Resumption tokens are specific to the local account; promise_yield_resume must be called from /// a method of the same contract. +/// +/// # Examples +/// ```no_run +/// use near_sdk::env::{promise_yield_create, promise_yield_resume, read_register}; +/// use near_sdk::serde_json; +/// use near_sdk::{Gas, GasWeight, CryptoHash}; +/// +/// let DATA_ID_REGISTER = 0; +/// // Create yield promise +/// let promise = promise_yield_create( +/// "increment", +/// // passed as arguments +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// Gas::from_tgas(10), +/// GasWeight(0), +/// DATA_ID_REGISTER +/// ); +/// +/// // Retrieve `data_id` for further resume +/// let data_id: CryptoHash = read_register(DATA_ID_REGISTER) +/// .expect("read_register failed") +/// .try_into() +/// .expect("conversion to CryptoHash failed"); +/// +/// // Resume execution using previously retrieved `data_id` +/// promise_yield_resume( +/// &data_id, +/// // passed as callback_result +/// serde_json::json!({ +/// "key": "value", +/// "description": "some text" +/// }).to_string().into_bytes().as_slice() +/// ); +/// ``` pub fn promise_yield_create( function_name: &str, arguments: &[u8], @@ -814,6 +1455,42 @@ pub fn promise_yield_create( /// If promise_yield_resume is called multiple times with the same `data_id`, it is possible to get /// back multiple 'true' results. The payload from the first successful call is passed to the /// callback. +/// +/// # Examples +/// ```no_run +/// use near_sdk::env::{promise_yield_create, promise_yield_resume, read_register}; +/// use near_sdk::serde_json; +/// use near_sdk::{Gas, GasWeight, CryptoHash}; +/// +/// let DATA_ID_REGISTER = 0; +/// // Create yield promise +/// let promise = promise_yield_create( +/// "increment", +/// // passed as arguments +/// serde_json::json!({ +/// "value": 5 +/// }).to_string().into_bytes().as_slice(), +/// Gas::from_tgas(10), +/// GasWeight(0), +/// DATA_ID_REGISTER +/// ); +/// +/// // Retrieve `data_id` for further resume +/// let data_id: CryptoHash = read_register(DATA_ID_REGISTER) +/// .expect("read_register failed") +/// .try_into() +/// .expect("conversion to CryptoHash failed"); +/// +/// // Resume execution using previously retrieved `data_id` +/// promise_yield_resume( +/// &data_id, +/// // passed as callback_result +/// serde_json::json!({ +/// "key": "value", +/// "description": "some text" +/// }).to_string().into_bytes().as_slice() +/// ); +/// ``` pub fn promise_yield_resume(data_id: &CryptoHash, data: &[u8]) -> bool { unsafe { sys::promise_yield_resume( @@ -830,6 +1507,18 @@ pub fn promise_yield_resume(data_id: &CryptoHash, data: &[u8]) -> bool { // ############### /// For a given account return its current stake. If the account is not a validator, returns 0. +/// +/// # Examples +/// ``` +/// use near_sdk::env::validator_stake; +/// use near_sdk::{AccountId, NearToken}; +/// use std::str::FromStr; +/// +/// assert_eq!( +/// validator_stake(&AccountId::from_str("bob.near").unwrap()), +/// NearToken::from_yoctonear(0) +/// ); +/// ``` pub fn validator_stake(account_id: &AccountId) -> NearToken { let account_id: &str = account_id.as_ref(); let data = [0u8; size_of::()]; @@ -840,6 +1529,17 @@ pub fn validator_stake(account_id: &AccountId) -> NearToken { } /// Returns the total stake of validators in the current epoch. +/// +/// # Examples +/// ``` +/// use near_sdk::env::validator_total_stake; +/// use near_sdk::NearToken; +/// +/// assert_eq!( +/// validator_total_stake(), +/// NearToken::from_yoctonear(0) +/// ); +/// ``` pub fn validator_total_stake() -> NearToken { let data = [0u8; size_of::()]; unsafe { sys::validator_total_stake(data.as_ptr() as u64) }; @@ -850,23 +1550,70 @@ pub fn validator_total_stake() -> NearToken { // # Miscellaneous API # // ##################### /// Sets the blob of data as the return value of the contract. +/// +/// # Examples +/// ``` +/// use near_sdk::env::value_return; +/// +/// value_return(b"String data"); +/// ``` +/// ``` +/// use near_sdk::env::value_return; +/// use near_sdk::serde_json; +/// +/// value_return( +/// serde_json::json!({ +/// "account": "test.near", +/// "value": 5 +/// }).to_string().into_bytes().as_slice() +/// ); +/// ``` pub fn value_return(value: &[u8]) { unsafe { sys::value_return(value.len() as _, value.as_ptr() as _) } } /// Terminates the execution of the program with the UTF-8 encoded message. /// [`panic_str`] should be used as the bytes are required to be UTF-8 +/// +/// # Examples +/// ```should_panic +/// use near_sdk::env::panic; +/// +/// panic(b"Unexpected error"); +/// ``` #[deprecated(since = "4.0.0", note = "Use env::panic_str to panic with a message.")] pub fn panic(message: &[u8]) -> ! { unsafe { sys::panic_utf8(message.len() as _, message.as_ptr() as _) } } /// Terminates the execution of the program with the UTF-8 encoded message. +/// +/// # Examples +/// ```should_panic +/// use near_sdk::env::panic_str; +/// +/// panic_str("Unexpected error"); +/// ``` +/// ```should_panic +/// use near_sdk::env::panic_str; +/// use near_sdk::AccountId; +/// use std::str::FromStr; +/// +/// let account = AccountId::from_str("bob.near").unwrap(); +/// panic_str(format!("Unexpected error happened for account {}", account).as_str()); +/// ``` pub fn panic_str(message: &str) -> ! { unsafe { sys::panic_utf8(message.len() as _, message.as_ptr() as _) } } /// Aborts the current contract execution without a custom message. /// To include a message, use [`panic_str`]. +/// +/// # Examples +/// ```should_panic +/// use near_sdk::env::abort; +/// +/// abort(); +/// ``` pub fn abort() -> ! { // Use wasm32 unreachable call to avoid including the `panic` external function in Wasm. #[cfg(target_arch = "wasm32")] @@ -882,6 +1629,19 @@ pub fn abort() -> ! { } /// Logs the string message message. This message is stored on chain. +/// +/// # Examples +/// ``` +/// use near_sdk::env::log_str; +/// +/// log_str("Some text"); +/// ``` +/// ``` +/// use near_sdk::env::log_str; +/// +/// let number = 5; +/// log_str(format!("Number: {}", number).as_str()); +/// ``` pub fn log_str(message: &str) { #[cfg(all(debug_assertions, not(target_arch = "wasm32")))] eprintln!("{}", message); @@ -890,6 +1650,13 @@ pub fn log_str(message: &str) { } /// Log the UTF-8 encodable message. +/// +/// # Examples +/// ``` +/// use near_sdk::env::log; +/// +/// log(b"Text"); +/// ``` #[deprecated(since = "4.0.0", note = "Use env::log_str for logging messages.")] pub fn log(message: &[u8]) { #[cfg(all(debug_assertions, not(target_arch = "wasm32")))] @@ -904,8 +1671,11 @@ pub fn log(message: &[u8]) { /// Writes key-value into storage. /// If another key-value existed in the storage with the same key it returns `true`, otherwise `false`. /// -/// # Examples +/// # Use cases +/// Storage functions are typically used to upgrade/migrate a contract state, preventing errors like `Cannot deserialize the contract state` after rolling out the breaking changes to the network. +/// For practical examples, see different implementations in [this repository](https://github.com/near-examples/update-migrate-rust). /// +/// # Examples /// ``` /// use near_sdk::env::{storage_write, storage_read}; /// @@ -930,8 +1700,11 @@ pub fn storage_write(key: &[u8], value: &[u8]) -> bool { } /// Reads the value stored under the given key. /// -/// # Examples +/// # Use cases +/// Storage functions are typically used to upgrade/migrate a contract state, preventing errors like `Cannot deserialize the contract state` after rolling out the breaking changes to the network. +/// For practical examples, see different implementations in [this repository](https://github.com/near-examples/update-migrate-rust). /// +/// # Examples /// ``` /// use near_sdk::env::{storage_write, storage_read}; /// @@ -948,6 +1721,19 @@ pub fn storage_read(key: &[u8]) -> Option> { } /// Removes the value stored under the given key. /// If key-value existed returns `true`, otherwise `false`. +/// +/// # Use cases +/// Storage functions are typically used to upgrade/migrate a contract state, preventing errors like `Cannot deserialize the contract state` after rolling out the breaking changes to the network. +/// For practical examples, see different implementations in [this repository](https://github.com/near-examples/update-migrate-rust). +/// +/// # Examples +/// ``` +/// use near_sdk::env::{storage_write, storage_remove}; +/// +/// assert_eq!(storage_remove(b"key"), false); +/// storage_write(b"key", b"value"); +/// assert_eq!(storage_remove(b"key"), true); +/// ``` pub fn storage_remove(key: &[u8]) -> bool { match unsafe { sys::storage_remove(key.len() as _, key.as_ptr() as _, EVICTED_REGISTER) } { 0 => false, @@ -956,10 +1742,34 @@ pub fn storage_remove(key: &[u8]) -> bool { } } /// Reads the most recent value that was evicted with `storage_write` or `storage_remove` command. +/// +/// # Use cases +/// Storage functions are typically used to upgrade/migrate a contract state, preventing errors like `Cannot deserialize the contract state` after rolling out the breaking changes to the network. +/// For practical examples, see different implementations in [this repository](https://github.com/near-examples/update-migrate-rust). +/// +/// # Examples +/// ``` +/// use near_sdk::env::{storage_write, storage_remove, storage_get_evicted}; +/// +/// assert_eq!(storage_get_evicted(), None); +/// ``` pub fn storage_get_evicted() -> Option> { read_register(EVICTED_REGISTER) } /// Checks if there is a key-value in the storage. +/// +/// # Use cases +/// Storage functions are typically used to upgrade/migrate a contract state, preventing errors like `Cannot deserialize the contract state` after rolling out the breaking changes to the network. +/// For practical examples, see different implementations in [this repository](https://github.com/near-examples/update-migrate-rust). +/// +/// # Examples +/// ``` +/// use near_sdk::env::{storage_write, storage_has_key}; +/// +/// assert_eq!(storage_has_key(b"key"), false); +/// storage_write(b"key", b"value"); +/// assert_eq!(storage_has_key(b"key"), true); +/// ``` pub fn storage_has_key(key: &[u8]) -> bool { match unsafe { sys::storage_has_key(key.len() as _, key.as_ptr() as _) } { 0 => false, @@ -996,7 +1806,14 @@ pub fn state_exists() -> bool { /// Price per 1 byte of storage from mainnet genesis config. /// TODO: will be using the host function when it will be available. - +/// +/// # Examples +/// ``` +/// use near_sdk::env::storage_byte_cost; +/// use near_sdk::NearToken; +/// +/// assert_eq!(storage_byte_cost(), NearToken::from_yoctonear(10000000000000000000)); +/// ``` pub fn storage_byte_cost() -> NearToken { NearToken::from_yoctonear(10_000_000_000_000_000_000u128) } @@ -1006,6 +1823,15 @@ pub fn storage_byte_cost() -> NearToken { // ################## /// Returns `true` if the given account ID is valid and `false` otherwise. +/// +/// # Examples +/// +/// ``` +/// use near_sdk::env::is_valid_account_id; +/// +/// assert_eq!(is_valid_account_id(b"test.near"), true); +/// assert_eq!(is_valid_account_id(b"test!.%.near"), false); +/// ``` pub fn is_valid_account_id(account_id: &[u8]) -> bool { if (account_id.len() as u64) < MIN_ACCOUNT_ID_LEN || (account_id.len() as u64) > MAX_ACCOUNT_ID_LEN