//! 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 higher-level API available
//! through [`crate::Promise`], and [`crate::PromiseOrValue<T>`].
use std::convert::TryFrom;
use std::convert::TryInto;
use std::mem::{size_of, size_of_val};
use std::panic as std_panic;
#[cfg(all(not(target_arch = "wasm32"), feature = "unit-testing"))]
use crate::mock::MockedBlockchain;
use crate::promise::Allowance;
use crate::types::AccountIdRef;
use crate::types::{
AccountId, BlockHeight, Gas, NearToken, PromiseIndex, PromiseResult, PublicKey, StorageUsage,
};
use crate::{CryptoHash, GasWeight, PromiseError};
#[cfg(feature = "deterministic-account-ids")]
use crate::{AccountContract, ActionIndex, GlobalContractId};
use near_sys as sys;
const REGISTER_EXPECTED_ERR: &str =
"Register was expected to have data because we just wrote it into it.";
/// Register used internally for atomic operations. This register is safe to use by the user,
/// since it only needs to be untouched while methods of `Environment` execute, which is guaranteed
/// guest code is not parallel.
const ATOMIC_OP_REGISTER: u64 = u64::MAX - 2;
/// Register used to record evicted values from the storage.
const EVICTED_REGISTER: u64 = u64::MAX - 1;
/// Key used to store the state of the contract.
const STATE_KEY: &[u8] = b"STATE";
/// The minimum length of a valid account ID.
const MIN_ACCOUNT_ID_LEN: u64 = 2;
/// The maximum length of a valid account ID.
const MAX_ACCOUNT_ID_LEN: u64 = 64;
#[inline]
#[track_caller]
fn expect_register<T>(option: Option<T>) -> T {
option.unwrap_or_else(|| panic_str(REGISTER_EXPECTED_ERR))
}
/// A simple helper to read blob value coming from host's method.
#[inline]
fn try_method_into_register(method: unsafe extern "C" fn(u64)) -> Option<Vec<u8>> {
unsafe { method(ATOMIC_OP_REGISTER) };
read_register(ATOMIC_OP_REGISTER)
}
/// Same as `try_method_into_register` but expects the data.
#[inline]
#[track_caller]
fn method_into_register(method: unsafe extern "C" fn(u64)) -> Vec<u8> {
expect_register(try_method_into_register(method))
}
#[inline]
pub(crate) unsafe fn read_register_fixed<const N: usize>(register_id: u64) -> [u8; N] {
let mut buf = [0; N];
unsafe { sys::read_register(register_id, buf.as_mut_ptr() as _) };
buf
}
/// Replaces the current low-level blockchain interface accessible through `env::*` with another
/// low-level blockchain interface with builtin functions of the NEAR runtime. In most cases you
/// want to use `testing_env!` macro to set it.
///
/// ```
/// # let context = near_sdk::test_utils::VMContextBuilder::new().build();
/// # let vm_config = near_sdk::test_vm_config();
/// # let fees_config = near_sdk::RuntimeFeesConfig::test();
/// # let storage = Default::default();
/// # let validators = Default::default();
/// let mocked_blockchain = near_sdk::MockedBlockchain::new(
/// context,
/// vm_config,
/// fees_config,
/// vec![],
/// storage,
/// validators,
/// None,
/// );
/// near_sdk::env::set_blockchain_interface(mocked_blockchain);
/// ```
#[cfg(all(not(target_arch = "wasm32"), feature = "unit-testing"))]
pub fn set_blockchain_interface(blockchain_interface: MockedBlockchain) {
crate::mock::with_mocked_blockchain(|b| {
*b = blockchain_interface;
})
}
/// Implements panic hook that converts `PanicInfo` into a string and provides it through the
/// blockchain interface.
fn panic_hook_impl(info: &std_panic::PanicHookInfo) {
panic_str(info.to_string().as_str());
}
/// Setups panic hook to expose error info to the blockchain.
pub fn setup_panic_hook() {
std_panic::set_hook(Box::new(panic_hook_impl));
}
/// Reads the content of the `register_id`. If register is not used returns `None`.
pub fn read_register(register_id: u64) -> Option<Vec<u8>> {
read_register_bounded(register_id, usize::MAX).map(|r| {
r
// vector can't be longer than usize::MAX
.unwrap_or_else(|_| unreachable!())
})
}
/// Same as [`read_register`] but bounded: if data in the register is
/// longer than `max_len`, then `Some(Err(len))` is returned.
pub fn read_register_bounded(register_id: u64, max_len: usize) -> Option<Result<Vec<u8>, usize>> {
// Get register length and convert to a usize. The max register size in config is much less
// than the u32 max so the abort should never be hit, but is there for safety because there
// would be undefined behaviour during `read_register` if the buffer length is truncated.
let len: usize = register_len(register_id)?.try_into().unwrap_or_else(|_| abort());
if len > max_len {
return Some(Err(len));
}
// Initialize buffer with capacity.
let mut buffer = Vec::with_capacity(len);
// Read register into buffer.
//* SAFETY: This is safe because the buffer is initialized with the exact capacity of the
//* register that is being read from.
unsafe {
sys::read_register(register_id, buffer.as_mut_ptr() as u64);
// Set updated length after writing to buffer.
buffer.set_len(len);
}
Some(Ok(buffer))
}
/// Returns the size of the register. If register is not used returns `None`.
pub fn register_len(register_id: u64) -> Option<u64> {
let len = unsafe { sys::register_len(register_id) };
if len == u64::MAX { None } else { Some(len) }
}
macro_rules! maybe_cached {
($t:ty: $v:block) => {{
#[cfg(not(feature = "unit-testing"))]
{
static CACHED: ::std::sync::LazyLock<$t> = ::std::sync::LazyLock::new(|| $v);
CACHED.clone()
}
#[cfg(feature = "unit-testing")]
$v
}};
}
// ###############
// # 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(), "alice.near".parse::<AccountId>().unwrap());
/// ```
pub fn current_account_id() -> AccountId {
maybe_cached!(AccountId: {
assert_valid_account_id(method_into_register(sys::current_account_id))
})
}
/// The code of the current contract.
///
/// # Examples
/// ```no_run
/// use near_sdk::env::current_contract_code;
/// use near_sdk::AccountContract;
///
/// assert!(matches!(current_contract_code(), AccountContract::Local(_)));
/// ```
#[cfg(feature = "deterministic-account-ids")]
pub fn current_contract_code() -> AccountContract {
maybe_cached!(AccountContract: {
let mode = unsafe { sys::current_contract_code(ATOMIC_OP_REGISTER) };
match mode {
0 => AccountContract::None,
1 => AccountContract::Local(unsafe { read_register_fixed(ATOMIC_OP_REGISTER) }.into()),
2 => AccountContract::Global(unsafe { read_register_fixed(ATOMIC_OP_REGISTER) }.into()),
3 => AccountContract::GlobalByAccount(assert_valid_account_id(method_into_register(
sys::current_account_id,
))),
_ => panic!("Invalid contract mode"),
}
})
}
/// Returns global contract identifier of the contract's code currently being
/// executed. Otherwise, returns `None` if the current contract is not using
/// globally deployed code.
///
/// # Examples
/// ```no_run
/// use near_sdk::env::current_global_contract_id;
/// use near_sdk::GlobalContractId;
///
/// assert!(matches!(current_global_contract_id(), Some(GlobalContractId::CodeHash(_))));
/// ```
#[cfg(feature = "deterministic-account-ids")]
pub fn current_global_contract_id() -> Option<GlobalContractId> {
Some(match current_contract_code() {
AccountContract::Global(hash) => GlobalContractId::CodeHash(hash),
AccountContract::GlobalByAccount(account_id) => GlobalContractId::AccountId(account_id),
_ => return None,
})
}
/// The account id that will receive the refund if the contract panics.
///
/// # Examples
/// ```
/// use near_sdk::env::refund_to_account_id;
///
/// assert_eq!(refund_to_account_id(), "bob.near".parse::<near_sdk::AccountId>().unwrap());
/// ```
#[cfg(feature = "deterministic-account-ids")]
pub fn refund_to_account_id() -> AccountId {
maybe_cached!(AccountId: {
assert_valid_account_id(method_into_register(sys::refund_to_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(), "bob.near".parse::<AccountId>().unwrap());
/// ```
pub fn signer_account_id() -> AccountId {
maybe_cached!(AccountId: {
assert_valid_account_id(method_into_register(sys::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 {
maybe_cached!(PublicKey: {
PublicKey::try_from(method_into_register(sys::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(), "bob.near".parse::<AccountId>().unwrap());
/// ```
pub fn predecessor_account_id() -> AccountId {
maybe_cached!(AccountId: { assert_valid_account_id(method_into_register(sys::predecessor_account_id)) })
}
/// Helper function to convert and check the account ID from bytes from the runtime.
fn assert_valid_account_id(bytes: Vec<u8>) -> AccountId {
String::from_utf8(bytes)
.ok()
.and_then(|s| AccountId::try_from(s).ok())
.unwrap_or_else(|| abort())
}
/// 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()));
/// ```
/// See an example here [here](https://github.com/near-examples/update-migrate-rust/blob/a1a326de73c152831f93fbf6d90932e13a08b89f/self-updates/update/src/update.rs#L19)
pub fn input() -> Option<Vec<u8>> {
try_method_into_register(sys::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 {
maybe_cached!(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 {
maybe_cached!(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 {
maybe_cached!(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() }
}
// #################
// # Economics API #
// #################
/// 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 mut data = [0u8; size_of::<NearToken>()];
unsafe { sys::account_balance(data.as_mut_ptr() as u64) };
NearToken::from_yoctonear(u128::from_le_bytes(data))
}
/// 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 mut data = [0u8; size_of::<NearToken>()];
unsafe { sys::account_locked_balance(data.as_mut_ptr() as u64) };
NearToken::from_yoctonear(u128::from_le_bytes(data))
}
/// 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 {
maybe_cached!(NearToken: {
let mut data = [0u8; size_of::<NearToken>()];
unsafe { sys::attached_deposit(data.as_mut_ptr() as u64) };
NearToken::from_yoctonear(u128::from_le_bytes(data))
})
}
/// 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 {
maybe_cached!(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() })
}
// ############
// # Math API #
// ############
/// 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<u8> {
random_seed_array().to_vec()
}
/// 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.
/// Example of usage:
/// ```rust
/// use rand::{Rng, SeedableRng};
/// use rand_chacha::ChaCha20Rng;
/// use near_sdk::near;
/// use near_sdk::env;
/// #[near(contract_state)]
/// struct RngExample {
/// val: i32,
/// }
/// #[near]
/// impl RngExample {
/// pub fn increment(&mut self) {
/// let mut rng = ChaCha20Rng::from_seed(env::random_seed_array());
/// let value = rng.gen_range(0..1011);
/// self.val += value;
/// }
/// pub fn get_value(&mut self) -> i32 {
/// self.val
/// }
/// }
/// ```
///
/// Example of usage with [near-rng](https://lib.rs/crates/near-rng) which allows to decrease size of contract binary:
///
/// ```rust
/// use near_rng::Rng;
/// use near_sdk::near;
/// use near_sdk::env;
/// #[near(contract_state)]
/// struct NearRngExample {
/// val: i32,
/// }
/// #[near]
/// impl NearRngExample {
/// pub fn increment(&mut self) {
/// let mut rng = Rng::new(&env::random_seed());
/// let value = rng.rand_range_i32(0, 20);
/// self.val += value;
/// }
/// pub fn get_value(&mut self) -> i32 {
/// self.val
/// }
/// }
/// ```
/// More info in [documentation](https://docs.near.org/develop/contracts/security/random)
pub fn random_seed_array() -> [u8; 32] {
maybe_cached!([u8; 32]: {
//* SAFETY: random_seed 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
//* because all bytes are filled. This assumes a valid random_seed implementation.
unsafe {
sys::random_seed(ATOMIC_OP_REGISTER);
read_register_fixed(ATOMIC_OP_REGISTER)
}
})
}
/// Hashes the random sequence of bytes using sha256.
///
/// # Examples
/// ```
/// use near_sdk::env::sha256;
/// use hex;
///
/// assert_eq!(
/// sha256(b"The phrase that will be hashed"),
/// hex::decode("7fc38bc74a0d0e592d2b8381839adc2649007d5bca11f92eeddef78681b4e3a3").expect("Decoding failed")
/// );
/// ```
pub fn sha256(value: impl AsRef<[u8]>) -> Vec<u8> {
sha256_array(value.as_ref()).to_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: impl AsRef<[u8]>) -> Vec<u8> {
keccak256_array(value.as_ref()).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: impl AsRef<[u8]>) -> Vec<u8> {
keccak512_array(value.as_ref()).to_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;
///
/// assert_eq!(
/// &sha256_array(b"The phrase that will be hashed"),
/// hex::decode("7fc38bc74a0d0e592d2b8381839adc2649007d5bca11f92eeddef78681b4e3a3")
/// .expect("Decoding failed")
/// .as_slice()
/// );
/// ```
pub fn sha256_array(value: impl AsRef<[u8]>) -> CryptoHash {
#[cfg(any(
target_arch = "wasm32",
not(feature = "non-contract-usage"),
all(feature = "unit-testing", not(test)),
))]
{
let value = value.as_ref();
//* SAFETY: sha256 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
//* because all bytes are filled. This assumes a valid sha256 implementation.
unsafe {
sys::sha256(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
read_register_fixed(ATOMIC_OP_REGISTER)
}
}
#[cfg(all(
not(target_arch = "wasm32"),
feature = "non-contract-usage",
any(not(feature = "unit-testing"), test),
))]
{
use sha2::Digest;
sha2::Sha256::digest(value).into()
}
}
/// 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: impl AsRef<[u8]>) -> CryptoHash {
#[cfg(any(
target_arch = "wasm32",
not(feature = "non-contract-usage"),
all(feature = "unit-testing", not(test)),
))]
{
let value = value.as_ref();
//* 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
//* because all bytes are filled. This assumes a valid keccak256 implementation.
unsafe {
sys::keccak256(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
read_register_fixed(ATOMIC_OP_REGISTER)
}
}
#[cfg(all(
not(target_arch = "wasm32"),
feature = "non-contract-usage",
any(not(feature = "unit-testing"), test),
))]
{
use sha3::Digest;
sha3::Keccak256::digest(value).into()
}
}
/// 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: impl AsRef<[u8]>) -> [u8; 64] {
#[cfg(any(
target_arch = "wasm32",
not(feature = "non-contract-usage"),
all(feature = "unit-testing", not(test)),
))]
{
let value = value.as_ref();
//* 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
//* because all bytes are filled. This assumes a valid keccak512 implementation.
unsafe {
sys::keccak512(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
read_register_fixed(ATOMIC_OP_REGISTER)
}
}
#[cfg(all(
not(target_arch = "wasm32"),
feature = "non-contract-usage",
any(not(feature = "unit-testing"), test),
))]
{
use sha3::Digest;
sha3::Keccak512::digest(value).into()
}
}
/// 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: impl AsRef<[u8]>) -> [u8; 20] {
#[cfg(any(
target_arch = "wasm32",
not(feature = "non-contract-usage"),
all(feature = "unit-testing", not(test)),
))]
{
let value = value.as_ref();
//* 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
//* because all bytes are filled. This assumes a valid ripemd160 implementation.
unsafe {
sys::ripemd160(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
read_register_fixed(ATOMIC_OP_REGISTER)
}
}
#[cfg(all(
not(target_arch = "wasm32"),
feature = "non-contract-usage",
any(not(feature = "unit-testing"), test),
))]
{
use sha2::Digest;
ripemd::Ripemd160::digest(value).into()
}
}
/// Recovers an ECDSA signer address from a 32-byte message `hash` and a corresponding `signature`
/// along with `v` recovery byte.
///
/// Takes in an additional flag to check for malleability of the signature
/// which is generally only ideal for transactions.
///
/// Returns 64 bytes representing the public key if the recovery was successful.
#[cfg(feature = "unstable")]
pub fn ecrecover(
hash: &[u8],
signature: &[u8],
v: u8,
malleability_flag: bool,
) -> Option<[u8; 64]> {
#[cfg(any(
target_arch = "wasm32",
not(feature = "non-contract-usage"),
all(feature = "unit-testing", not(test)),
))]
{
unsafe {
let return_code = sys::ecrecover(
hash.len() as _,
hash.as_ptr() as _,
signature.len() as _,
signature.as_ptr() as _,
v as u64,
malleability_flag as u64,
ATOMIC_OP_REGISTER,
);
if return_code == 0 { None } else { Some(read_register_fixed(ATOMIC_OP_REGISTER)) }
}
}
#[cfg(all(
not(target_arch = "wasm32"),
feature = "non-contract-usage",
any(not(feature = "unit-testing"), test),
))]
{
use near_crypto::Secp256K1Signature;
let signature = Secp256K1Signature::from({
let mut buf = [0u8; 65];
buf[0..64].copy_from_slice(signature);
buf[64] = v;
buf
});
let hash: [u8; 32] = hash.try_into().ok()?;
if !signature.check_signature_values(malleability_flag) {
return None;
}
signature.recover(hash).ok()?.as_ref().try_into().ok()
}
}
/// 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: impl AsRef<[u8]>,
public_key: &[u8; 32],
) -> bool {
let message = message.as_ref();
#[cfg(any(
target_arch = "wasm32",
not(feature = "non-contract-usage"),
all(feature = "unit-testing", not(test)),
))]
{
unsafe {
sys::ed25519_verify(
signature.len() as _,
signature.as_ptr() as _,
message.len() as _,
message.as_ptr() as _,
public_key.len() as _,
public_key.as_ptr() as _,
) == 1
}
}
#[cfg(all(
not(target_arch = "wasm32"),
feature = "non-contract-usage",
any(not(feature = "unit-testing"), test),
))]
{
use ed25519_dalek::{Signature, Verifier, VerifyingKey};
let Ok(verifying_key) = VerifyingKey::from_bytes(public_key) else {
return false;
};
let signature = Signature::from_bytes(signature);
verifying_key.verify(message, &signature).is_ok()
}
}
/// Compute alt_bn128 g1 multiexp.
///
/// `alt_bn128` is a specific curve from the Barreto-Naehrig(BN) family. It is particularly
/// well-suited for ZK proofs.
///
/// See also: [EIP-196](https://eips.ethereum.org/EIPS/eip-196)
pub fn alt_bn128_g1_multiexp(value: impl AsRef<[u8]>) -> Vec<u8> {
let value = value.as_ref();
unsafe {
sys::alt_bn128_g1_multiexp(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
match read_register(ATOMIC_OP_REGISTER) {
Some(result) => result,
None => panic_str(REGISTER_EXPECTED_ERR),
}
}
/// Compute alt_bn128 g1 sum.
///
/// `alt_bn128` is a specific curve from the Barreto-Naehrig(BN) family. It is particularly
/// well-suited for ZK proofs.
///
/// See also: [EIP-196](https://eips.ethereum.org/EIPS/eip-196)
pub fn alt_bn128_g1_sum(value: impl AsRef<[u8]>) -> Vec<u8> {
let value = value.as_ref();
unsafe {
sys::alt_bn128_g1_sum(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
match read_register(ATOMIC_OP_REGISTER) {
Some(result) => result,
None => panic_str(REGISTER_EXPECTED_ERR),
}
}
/// Compute pairing check
///
/// `alt_bn128` is a specific curve from the Barreto-Naehrig(BN) family. It is particularly
/// well-suited for ZK proofs.
///
/// See also: [EIP-197](https://eips.ethereum.org/EIPS/eip-197)
pub fn alt_bn128_pairing_check(value: impl AsRef<[u8]>) -> bool {
let value = value.as_ref();
unsafe { sys::alt_bn128_pairing_check(value.len() as _, value.as_ptr() as _) == 1 }
}
// #############
// # BLS12-381 #
// #############
/// Compute BLS12-381 G1 sum.
///
/// See also: [IETF draft-irtf-cfrg-pairing-friendly-curves](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves)
pub fn bls12381_p1_sum(value: impl AsRef<[u8]>) -> Vec<u8> {
let value = value.as_ref();
unsafe {
sys::bls12381_p1_sum(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
match read_register(ATOMIC_OP_REGISTER) {
Some(result) => result,
None => panic_str(REGISTER_EXPECTED_ERR),
}
}
/// Compute BLS12-381 G2 sum.
pub fn bls12381_p2_sum(value: impl AsRef<[u8]>) -> Vec<u8> {
let value = value.as_ref();
unsafe {
sys::bls12381_p2_sum(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
match read_register(ATOMIC_OP_REGISTER) {
Some(result) => result,
None => panic_str(REGISTER_EXPECTED_ERR),
}
}
/// Compute BLS12-381 G1 multiexponentiation.
pub fn bls12381_g1_multiexp(value: impl AsRef<[u8]>) -> Vec<u8> {
let value = value.as_ref();
unsafe {
sys::bls12381_g1_multiexp(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
match read_register(ATOMIC_OP_REGISTER) {
Some(result) => result,
None => panic_str(REGISTER_EXPECTED_ERR),
}
}
/// Compute BLS12-381 G2 multiexponentiation.
pub fn bls12381_g2_multiexp(value: impl AsRef<[u8]>) -> Vec<u8> {
let value = value.as_ref();
unsafe {
sys::bls12381_g2_multiexp(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
match read_register(ATOMIC_OP_REGISTER) {
Some(result) => result,
None => panic_str(REGISTER_EXPECTED_ERR),
}
}
/// Map an Fp element to a BLS12-381 G1 point.
pub fn bls12381_map_fp_to_g1(value: impl AsRef<[u8]>) -> Vec<u8> {
let value = value.as_ref();
unsafe {
sys::bls12381_map_fp_to_g1(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
match read_register(ATOMIC_OP_REGISTER) {
Some(result) => result,
None => panic_str(REGISTER_EXPECTED_ERR),
}
}
/// Map an Fp2 element to a BLS12-381 G2 point.
pub fn bls12381_map_fp2_to_g2(value: impl AsRef<[u8]>) -> Vec<u8> {
let value = value.as_ref();
unsafe {
sys::bls12381_map_fp2_to_g2(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
match read_register(ATOMIC_OP_REGISTER) {
Some(result) => result,
None => panic_str(REGISTER_EXPECTED_ERR),
}
}
/// Perform BLS12-381 pairing check. Returns true if the pairing check passes.
pub fn bls12381_pairing_check(value: impl AsRef<[u8]>) -> bool {
let value = value.as_ref();
unsafe { sys::bls12381_pairing_check(value.len() as _, value.as_ptr() as _) == 0 }
}
/// Decompress a BLS12-381 G1 point.
pub fn bls12381_p1_decompress(value: impl AsRef<[u8]>) -> Vec<u8> {
let value = value.as_ref();
unsafe {
sys::bls12381_p1_decompress(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
match read_register(ATOMIC_OP_REGISTER) {
Some(result) => result,
None => panic_str(REGISTER_EXPECTED_ERR),
}
}
/// Decompress a BLS12-381 G2 point.
pub fn bls12381_p2_decompress(value: impl AsRef<[u8]>) -> Vec<u8> {
let value = value.as_ref();
unsafe {
sys::bls12381_p2_decompress(value.len() as _, value.as_ptr() as _, ATOMIC_OP_REGISTER);
};
match read_register(ATOMIC_OP_REGISTER) {
Some(result) => result,
None => panic_str(REGISTER_EXPECTED_ERR),
}
}
// ################
// # Promises API #
// ################
/// 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(
/// "counter.near".parse::<AccountId>().unwrap(),
/// "increment",
/// serde_json::json!({
/// "value": 5
/// }).to_string(),
/// NearToken::from_yoctonear(0),
/// Gas::from_tgas(30)
/// );
/// ```
///
/// 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/blob/c2a2d36b2a83ad8fe110c3b21046064f581dc458/examples/factory-contract/low-level/src/lib.rs?plain=1#L28> and <https://github.com/near/near-sdk-rs/blob/c2a2d36b2a83ad8fe110c3b21046064f581dc458/examples/cross-contract-calls/low-level/src/lib.rs?plain=1#L23>
///
pub fn promise_create(
account_id: AccountId,
function_name: &str,
arguments: impl AsRef<[u8]>,
amount: NearToken,
gas: Gas,
) -> PromiseIndex {
let account_id = account_id.as_bytes();
let arguments = arguments.as_ref();
unsafe {
PromiseIndex(sys::promise_create(
account_id.len() as _,
account_id.as_ptr() as _,
function_name.len() as _,
function_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount.as_yoctonear() as *const u128 as _,
gas.as_gas(),
))
}
}
/// Attaches the callback (which is a [`near_primitives::action::FunctionCallAction`]) 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(
/// "counter.near".parse().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,
/// "greetings.near".parse().unwrap(),
/// "set_greeting",
/// serde_json::json!({
/// "text": "Hello World"
/// }).to_string().into_bytes().as_slice(),
/// NearToken::from_yoctonear(4000000000000),
/// Gas::from_tgas(30)
/// );
/// ```
/// 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/blob/c2a2d36b2a83ad8fe110c3b21046064f581dc458/examples/factory-contract/low-level/src/lib.rs?plain=1#L49> and <https://github.com/near/near-sdk-rs/blob/c2a2d36b2a83ad8fe110c3b21046064f581dc458/examples/cross-contract-calls/low-level/src/lib.rs?plain=1#L30>
pub fn promise_then(
promise_idx: PromiseIndex,
account_id: AccountId,
function_name: &str,
arguments: impl AsRef<[u8]>,
amount: NearToken,
gas: Gas,
) -> PromiseIndex {
let account_id = account_id.as_bytes();
let arguments = arguments.as_ref();
unsafe {
PromiseIndex(sys::promise_then(
promise_idx.0,
account_id.len() as _,
account_id.as_ptr() as _,
function_name.len() as _,
function_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount.as_yoctonear() as *const u128 as _,
gas.as_gas(),
))
}
}
/// 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(
/// "counter.near".parse().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(
/// "greetings.near".parse().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]);
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_and`]
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() {
data[i * size_of::<PromiseIndex>()..(i + 1) * size_of::<PromiseIndex>()]
.copy_from_slice(&promise_indices[i].0.to_le_bytes());
}
unsafe { PromiseIndex(sys::promise_and(data.as_ptr() as _, promise_indices.len() as _)) }
}
/// # Examples
/// ```no_run
///
/// use near_sdk::env;
/// use near_sdk::AccountId;
/// use std::str::FromStr;
///
/// let promise = env::promise_batch_create(
/// &"receiver.near".parse().unwrap()
/// );
/// ```
/// Create a NEAR promise which will have multiple promise actions inside.
///
/// Example:
/// ```no_run
/// use near_sdk::{env, NearToken, Gas, AccountId};
///
/// let promise_index = env::promise_batch_create(
/// &"example.near".parse().unwrap()
/// );
///
/// // Adding actions to the promise
/// env::promise_batch_action_transfer(promise_index, NearToken::from_near(10u128)); // Transfer 10 NEAR
/// env::promise_batch_action_function_call(
/// promise_index,
/// "method_name", // Target method
/// b"{}", // Arguments
/// NearToken::from_near(0), // Attached deposit
/// Gas::from_tgas(5) // Gas for execution
/// );
/// ```
/// All actions in a batch are executed in the order they were added.
/// Batched actions act as a unit: they execute in the same receipt, and if any fails, then they all get reverted.
/// More information about batching actions can be found in [NEAR documentation](https://docs.near.org/build/smart-contracts/anatomy/actions)
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_create`]
/// See example of usage [here](https://github.com/near/near-sdk-rs/blob/master/examples/factory-contract/low-level/src/lib.rs)
pub fn promise_batch_create(account_id: &AccountId) -> PromiseIndex {
let account_id: &str = account_id.as_ref();
unsafe {
PromiseIndex(sys::promise_batch_create(account_id.len() as _, account_id.as_ptr() as _))
}
}
/// # 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(
/// "counter.near".parse().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,
/// &"receiver.near".parse().unwrap()
/// );
/// ```
/// Attach a callback NEAR promise to a batch of NEAR promise actions.
///
/// More info about batching [here](crate::env::promise_batch_create)
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_then`]
pub fn promise_batch_then(promise_index: PromiseIndex, account_id: &AccountId) -> PromiseIndex {
let account_id: &str = account_id.as_ref();
unsafe {
PromiseIndex(sys::promise_batch_then(
promise_index.0,
account_id.len() as _,
account_id.as_ptr() as _,
))
}
}
/// Set the account id that will receive the refund if the promise panics.
/// Uses low-level [`crate::sys::promise_set_refund_to`]
///
/// # Examples
/// ```
/// use near_sdk::env::{promise_set_refund_to, promise_create};
/// use near_sdk::{AccountId, Gas, NearToken};
/// use std::str::FromStr;
///
/// let promise = promise_create(
/// "account.near".parse().unwrap(),
/// "method",
/// [],
/// NearToken::from_millinear(1),
/// Gas::from_tgas(1),
/// );
/// promise_set_refund_to(promise, &"refund.near".parse().unwrap());
/// ```
#[cfg(feature = "deterministic-account-ids")]
pub fn promise_set_refund_to(promise_index: PromiseIndex, account_id: &AccountId) {
let account_id: &str = account_id.as_ref();
unsafe {
sys::promise_set_refund_to(promise_index.0, account_id.len() as _, account_id.as_ptr() as _)
}
}
/// Appends `DeterministicStateInit` action to the batch of actions for the given promise
/// pointed by `promise_index`.
/// Uses low-level [`crate::sys::promise_batch_action_state_init`]
///
/// # Examples
/// ```
/// use near_sdk::env::{promise_batch_action_state_init, promise_create};
/// use near_sdk::{AccountId, CryptoHash, Gas, NearToken};
/// use std::str::FromStr;
///
/// let promise = promise_create(
/// "account.near".parse().unwrap(),
/// "method",
/// [],
/// NearToken::from_millinear(1),
/// Gas::from_tgas(1),
/// );
/// promise_batch_action_state_init(promise, [0; 32], NearToken::from_millinear(1));
/// ```
#[cfg(feature = "deterministic-account-ids")]
pub fn promise_batch_action_state_init(
promise_index: PromiseIndex,
code: CryptoHash,
amount: NearToken,
) -> ActionIndex {
unsafe {
sys::promise_batch_action_state_init(
promise_index.0,
code.len() as _,
code.as_ptr() as _,
&amount.as_yoctonear() as *const u128 as _,
)
}
}
/// Appends `DeterministicStateInit` action to the batch of actions for the given promise
/// pointed by `promise_index`.
/// Uses low-level [`crate::sys::promise_batch_action_state_init_by_account_id`]
///
/// # Examples
/// ```
/// use near_sdk::env::{promise_batch_action_state_init_by_account_id, promise_create};
/// use near_sdk::{AccountId, Gas, NearToken};
///
/// let account_id: AccountId = "account.near".parse().unwrap();
/// let promise = promise_create(
/// account_id.clone(),
/// "method",
/// [],
/// NearToken::from_millinear(1),
/// Gas::from_tgas(1),
/// );
/// promise_batch_action_state_init_by_account_id(promise, &account_id, NearToken::from_millinear(1));
/// ```
#[cfg(feature = "deterministic-account-ids")]
pub fn promise_batch_action_state_init_by_account_id(
promise_index: PromiseIndex,
account_id: impl AsRef<AccountIdRef>,
amount: NearToken,
) -> ActionIndex {
let account_id: &str = account_id.as_ref().as_str();
unsafe {
sys::promise_batch_action_state_init_by_account_id(
promise_index.0,
account_id.len() as _,
account_id.as_ptr() as _,
&amount.as_yoctonear() as *const u128 as _,
)
}
}
/// Appends a data entry to an existing `DeterministicStateInit` action.
/// Uses low-level [`crate::sys::set_state_init_data_entry`]
///
/// # Examples
/// ```
/// use near_sdk::env::{set_state_init_data_entry, promise_batch_action_state_init_by_account_id, promise_create};
/// use near_sdk::{AccountId, Gas, NearToken};
/// use std::str::FromStr;
///
/// let account_id: AccountId = "account.near".parse().unwrap();
/// let promise = promise_create(
/// account_id.clone(),
/// "method",
/// [],
/// NearToken::from_millinear(1),
/// Gas::from_tgas(1),
/// );
/// let action_index = promise_batch_action_state_init_by_account_id(promise, &account_id, NearToken::from_millinear(1));
/// set_state_init_data_entry(promise, action_index, b"key", b"value");
/// ```
#[cfg(feature = "deterministic-account-ids")]
pub fn set_state_init_data_entry(
promise_index: PromiseIndex,
action_index: ActionIndex,
key: &[u8],
value: &[u8],
) {
unsafe {
sys::set_state_init_data_entry(
promise_index.0,
action_index,
key.len() as _,
key.as_ptr() as _,
value.len() as _,
value.as_ptr() as _,
)
}
}
/// Attach a create account promise action to the NEAR promise index with the provided promise index.
///
/// More info about batching [here](crate::env::promise_batch_create)
///
/// # 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);
/// ```
///
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_action_create_account`]
/// See example of usage [here](https://github.com/near/near-sdk-rs/blob/master/examples/factory-contract/low-level/src/lib.rs)
pub fn promise_batch_action_create_account(promise_index: PromiseIndex) {
unsafe { sys::promise_batch_action_create_account(promise_index.0) }
}
/// Attach a deploy contract promise action to the NEAR promise index with the provided promise index.
///
/// More info about batching [here](crate::env::promise_batch_create)
/// # 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);
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_action_deploy_contract`]
/// See example of usage [here](https://github.com/near/near-sdk-rs/blob/master/examples/factory-contract/low-level/src/lib.rs)
pub fn promise_batch_action_deploy_contract(promise_index: PromiseIndex, code: &[u8]) {
unsafe {
sys::promise_batch_action_deploy_contract(
promise_index.0,
code.len() as _,
code.as_ptr() as _,
)
}
}
/// Attach a function call promise action to the NEAR promise index with the provided promise index.
///
/// More info about batching [here](crate::env::promise_batch_create)
/// # 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)
/// );
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_action_function_call`]
pub fn promise_batch_action_function_call(
promise_index: PromiseIndex,
function_name: &str,
arguments: &[u8],
amount: NearToken,
gas: Gas,
) {
unsafe {
sys::promise_batch_action_function_call(
promise_index.0,
function_name.len() as _,
function_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount.as_yoctonear() as *const u128 as _,
gas.as_gas(),
)
}
}
/// Attach a function call with specific gas weight promise action to the NEAR promise index with the provided promise index.
///
/// More info about batching [here](crate::env::promise_batch_create)
/// # 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)
/// );
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_action_function_call_weight`]
pub fn promise_batch_action_function_call_weight(
promise_index: PromiseIndex,
function_name: &str,
arguments: &[u8],
amount: NearToken,
gas: Gas,
weight: GasWeight,
) {
unsafe {
sys::promise_batch_action_function_call_weight(
promise_index.0,
function_name.len() as _,
function_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
&amount.as_yoctonear() as *const u128 as _,
gas.as_gas(),
weight.0,
)
}
}
/// Attach a transfer promise action to the NEAR promise index with the provided promise index.
///
/// More info about batching [here](crate::env::promise_batch_create)
/// # 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),
/// );
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_action_transfer`]
/// See example of usage [here](https://github.com/near/near-sdk-rs/blob/master/examples/factory-contract/low-level/src/lib.rs)
pub fn promise_batch_action_transfer(promise_index: PromiseIndex, amount: NearToken) {
unsafe {
sys::promise_batch_action_transfer(
promise_index.0,
&amount.as_yoctonear() as *const u128 as _,
)
}
}
/// Attach a stake promise action to the NEAR promise index with the provided promise index.
///
/// More info about batching [here](crate::env::promise_batch_create)
/// # 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
/// );
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_action_stake`]
pub fn promise_batch_action_stake(
promise_index: PromiseIndex,
amount: NearToken,
public_key: &PublicKey,
) {
unsafe {
sys::promise_batch_action_stake(
promise_index.0,
&amount.as_yoctonear() as *const u128 as _,
public_key.as_bytes().len() as _,
public_key.as_bytes().as_ptr() as _,
)
}
}
/// Attach promise action that adds a full access key to the NEAR promise index with the provided promise index.
///
/// More info about batching [here](crate::env::promise_batch_create)
/// # 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
/// );
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_action_add_key_with_full_access`]
/// See example of usage [here](https://github.com/near/near-sdk-rs/blob/master/examples/factory-contract/low-level/src/lib.rs)
pub fn promise_batch_action_add_key_with_full_access(
promise_index: PromiseIndex,
public_key: &PublicKey,
nonce: u64,
) {
unsafe {
sys::promise_batch_action_add_key_with_full_access(
promise_index.0,
public_key.as_bytes().len() as _,
public_key.as_bytes().as_ptr() as _,
nonce,
)
}
}
/// This is a short lived function while we migrate between the Balance and the allowance type
///
/// More info about batching [here](crate::env::promise_batch_create)
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,
public_key: &PublicKey,
nonce: u64,
allowance: NearToken,
receiver_id: &AccountId,
function_names: &str,
) {
let allowance = migrate_to_allowance(allowance);
promise_batch_action_add_key_allowance_with_function_call(
promise_index,
public_key,
nonce,
allowance,
receiver_id,
function_names,
)
}
/// Attach promise action that adds a key with function call with specifi allowance to the NEAR promise index with the provided promise index.
///
/// More info about batching [here](crate::env::promise_batch_create)
/// # 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,
nonce: u64,
allowance: Allowance,
receiver_id: &AccountId,
function_names: &str,
) {
let receiver_id: &str = receiver_id.as_ref();
let allowance = match allowance {
Allowance::Limited(x) => x.get(),
Allowance::Unlimited => 0,
};
unsafe {
sys::promise_batch_action_add_key_with_function_call(
promise_index.0,
public_key.as_bytes().len() as _,
public_key.as_bytes().as_ptr() as _,
nonce,
&allowance as *const u128 as _,
receiver_id.len() as _,
receiver_id.as_ptr() as _,
function_names.len() as _,
function_names.as_ptr() as _,
)
}
}
/// Attach promise action that deletes the key to the NEAR promise index with the provided promise index.
///
/// More info about batching [here](crate::env::promise_batch_create)
/// # 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
/// );
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_action_delete_key`]
pub fn promise_batch_action_delete_key(promise_index: PromiseIndex, public_key: &PublicKey) {
unsafe {
sys::promise_batch_action_delete_key(
promise_index.0,
public_key.as_bytes().len() as _,
public_key.as_bytes().as_ptr() as _,
)
}
}
/// Attach promise action that deletes the account to the NEAR promise index with the provided promise index.
///
/// More info about batching [here](crate::env::promise_batch_create)
/// # 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()
/// );
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_batch_action_delete_account`]
pub fn promise_batch_action_delete_account(
promise_index: PromiseIndex,
beneficiary_id: &AccountId,
) {
let beneficiary_id: &str = beneficiary_id.as_ref();
unsafe {
sys::promise_batch_action_delete_account(
promise_index.0,
beneficiary_id.len() as _,
beneficiary_id.as_ptr() as _,
)
}
}
/// Deploys a global contract using the provided contract code.
///
/// # Arguments
/// * `promise_index` - Promise batch index
/// * `code` - Contract bytecode to deploy as a global contract
///
/// # Examples
/// ```no_run
/// use near_sdk::{env, PromiseIndex};
///
/// let promise = env::promise_batch_create(&"alice.near".parse().unwrap());
/// let code = vec![0u8; 100]; // Contract bytecode
/// env::promise_batch_action_deploy_global_contract(promise, &code);
/// ```
pub fn promise_batch_action_deploy_global_contract(promise_index: PromiseIndex, code: &[u8]) {
unsafe {
sys::promise_batch_action_deploy_global_contract(
promise_index.0,
code.len() as _,
code.as_ptr() as _,
)
}
}
/// Deploys a global contract by referencing another account's deployed code.
///
/// # Arguments
/// * `promise_index` - Promise batch index
/// * `code` - Contract bytecode to deploy as a global contract
///
/// # Examples
/// ```no_run
/// use near_sdk::{env, PromiseIndex};
///
/// let promise = env::promise_batch_create(&"alice.near".parse().unwrap());
/// let code = vec![0u8; 100]; // Contract bytecode
/// env::promise_batch_action_deploy_global_contract_by_account_id(promise, &code);
/// ```
pub fn promise_batch_action_deploy_global_contract_by_account_id(
promise_index: PromiseIndex,
code: &[u8],
) {
unsafe {
sys::promise_batch_action_deploy_global_contract_by_account_id(
promise_index.0,
code.len() as _,
code.as_ptr() as _,
)
}
}
/// Uses an existing global contract by code hash.
///
/// # Arguments
/// * `promise_index` - Promise batch index
/// * `code_hash` - Hash of the global contract code to use
///
/// # Examples
/// ```no_run
/// use near_sdk::{env, PromiseIndex};
///
/// let promise = env::promise_batch_create(&"alice.near".parse().unwrap());
/// let code_hash = [0u8; 32]; // 32-byte hash (CryptoHash)
/// env::promise_batch_action_use_global_contract(promise, &code_hash);
/// ```
pub fn promise_batch_action_use_global_contract(
promise_index: PromiseIndex,
code_hash: &CryptoHash,
) {
unsafe {
sys::promise_batch_action_use_global_contract(
promise_index.0,
code_hash.len() as _,
code_hash.as_ptr() as _,
)
}
}
/// Uses an existing global contract by referencing the account that deployed it.
///
/// # Arguments
/// * `promise_index` - Promise batch index
/// * `account_id` - Account ID that deployed the global contract
///
/// # Examples
/// ```no_run
/// use near_sdk::{env, PromiseIndex, AccountId};
/// use std::str::FromStr;
///
/// let promise = env::promise_batch_create(&"alice.near".parse().unwrap());
/// env::promise_batch_action_use_global_contract_by_account_id(
/// promise,
/// &AccountId::from_str("deployer.near").unwrap()
/// );
/// ```
pub fn promise_batch_action_use_global_contract_by_account_id(
promise_index: PromiseIndex,
account_id: impl AsRef<AccountIdRef>,
) {
let account_id: &str = account_id.as_ref().as_str();
unsafe {
sys::promise_batch_action_use_global_contract_by_account_id(
promise_index.0,
account_id.len() as _,
account_id.as_ptr() as _,
)
}
}
/// 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);
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_results_count`]
///
/// See example of usage [here](https://github.com/near/near-sdk-rs/blob/master/examples/cross-contract-calls/low-level/src/lib.rs)
pub fn promise_results_count() -> u64 {
maybe_cached!(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<u8>: {:?}", data).as_str());
/// }
/// PromiseResult::Failed => {
/// log_str("Promise failed!");
/// }
/// };
/// ```
///
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_result`]
///
/// Example usages:
/// - [near-contract-standards/src/fungible_token](https://github.com/near/near-sdk-rs/blob/189897180649bce47aefa4e5af03664ee525508d/near-contract-standards/src/fungible_token/core_impl.rs#L178)
/// - [near-contract-standards/src/non_fungible_token](https://github.com/near/near-sdk-rs/blob/189897180649bce47aefa4e5af03664ee525508d/near-contract-standards/src/non_fungible_token/core/core_impl.rs#L433)
/// - [examples/factory-contract/low-level](https://github.com/near/near-sdk-rs/blob/189897180649bce47aefa4e5af03664ee525508d/examples/factory-contract/low-level/src/lib.rs#L61)
/// - [examples/cross-contract-calls/low-level](https://github.com/near/near-sdk-rs/blob/189897180649bce47aefa4e5af03664ee525508d/examples/cross-contract-calls/low-level/src/lib.rs#L46)
#[deprecated = "use `promise_result_checked` to prevent out-of-gas errors"]
pub fn promise_result(result_idx: u64) -> PromiseResult {
match promise_result_checked(result_idx, usize::MAX) {
Ok(data) => PromiseResult::Successful(data),
Err(err) => match err {
PromiseError::Failed => PromiseResult::Failed,
// vector can't be longer than usize::MAX
PromiseError::TooLong(_len) => unreachable!(),
},
}
}
/// Same as [`promise_result`] but bounded: if the result is longer than
/// `max_len`, then `Err(PromiseResultError::TooLong(len))` is returned.
///
/// This should be preferred when reading promise results from unknown
/// contracts to prevent out-of-gas errors.
///
/// # Examples
/// ```no_run
/// use near_sdk::env::{promise_result_checked, promise_results_count, log_str, panic_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 data = promise_result_checked(promise_index, 100)
/// .unwrap_or_else(|_| panic_str("Promise failed or returned result is too long!"));
/// log_str(format!("Result as Vec<u8>: {:?}", data).as_str());
/// assert!(data.len() <= 100);
/// ```
pub fn promise_result_checked(result_idx: u64, max_len: usize) -> Result<Vec<u8>, PromiseError> {
promise_result_internal(result_idx)?;
expect_register(read_register_bounded(ATOMIC_OP_REGISTER, max_len))
.map_err(PromiseError::TooLong)
}
pub(crate) fn promise_result_internal(result_idx: u64) -> Result<(), PromiseError> {
match unsafe { sys::promise_result(result_idx, ATOMIC_OP_REGISTER) } {
1 => Ok(()),
2 => Err(PromiseError::Failed),
_ => 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);
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_return`]
///
/// Example usages: [one](https://github.com/near/near-sdk-rs/blob/c2a2d36b2a83ad8fe110c3b21046064f581dc458/examples/cross-contract-calls/low-level/src/lib.rs?plain=1#L38), [two](https://github.com/near/near-sdk-rs/blob/c2a2d36b2a83ad8fe110c3b21046064f581dc458/examples/factory-contract/low-level/src/lib.rs?plain=1#L57)
pub fn promise_return(promise_idx: PromiseIndex) {
unsafe { sys::promise_return(promise_idx.0) }
}
/// Creates a promise that will execute a method on the current account with given arguments.
/// Writes a resumption token (data id) to the specified register. The callback method will execute
/// after promise_yield_resume is called with the data id OR enough blocks have passed. The timeout
/// length is specified as a protocol-level parameter yield_timeout_length_in_blocks = 200.
///
/// The callback method will execute with a single promise input. Input will either be a payload
/// provided by the user when calling promise_yield_resume, or a PromiseError in case of timeout.
///
/// 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()
/// );
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_yield_create`]
/// See example of usage [here](https://github.com/near/mpc/blob/79ec50759146221e7ad8bb04520f13333b75ca07/chain-signatures/contract/src/lib.rs#L689) and [here](https://github.com/near/near-sdk-rs/blob/master/examples/mpc-contract/src/lib.rs#L45)
pub fn promise_yield_create(
function_name: &str,
arguments: impl AsRef<[u8]>,
gas: Gas,
weight: GasWeight,
register_id: u64,
) -> PromiseIndex {
let arguments = arguments.as_ref();
unsafe {
PromiseIndex(sys::promise_yield_create(
function_name.len() as _,
function_name.as_ptr() as _,
arguments.len() as _,
arguments.as_ptr() as _,
gas.as_gas(),
weight.0,
register_id as _,
))
}
}
/// Helper function that creates a yield promise and returns both the promise index and the yield ID.
///
/// This is a convenience wrapper around [`promise_yield_create`] that automatically reads the
/// yield ID from the register and returns it as a [`crate::YieldId`].
pub fn promise_yield_create_id(
function_name: &str,
arguments: impl AsRef<[u8]>,
gas: Gas,
weight: GasWeight,
) -> (PromiseIndex, crate::YieldId) {
let promise_index =
promise_yield_create(function_name, arguments, gas, weight, ATOMIC_OP_REGISTER);
// SAFETY: promise_yield_create writes a 32-byte yield ID to the register
let yield_id = crate::YieldId(unsafe { read_register_fixed(ATOMIC_OP_REGISTER) });
(promise_index, yield_id)
}
/// Accepts a resumption token `data_id` created by promise_yield_create on the local account.
/// `data` is a payload to be passed to the callback method as a promise input. Returns false if
/// no promise yield with the specified `data_id` is found. Returns true otherwise, guaranteeing
/// that the callback method will be executed with a user-provided payload.
///
/// 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()
/// );
/// ```
/// More low-level info here: [`near_vm_runner::logic::VMLogic::promise_yield_resume`]
/// See example of usage [here](https://github.com/near/mpc/blob/79ec50759146221e7ad8bb04520f13333b75ca07/chain-signatures/contract/src/lib.rs#L288) and [here](https://github.com/near/near-sdk-rs/blob/master/examples/mpc-contract/src/lib.rs#L84)
pub fn promise_yield_resume(data_id: &CryptoHash, data: impl AsRef<[u8]>) -> bool {
let data = data.as_ref();
unsafe {
sys::promise_yield_resume(
data_id.len() as _,
data_id.as_ptr() as _,
data.len() as _,
data.as_ptr() as _,
) != 0
}
}
// ###############
// # Validator API #
// ###############
/// 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 mut data = [0u8; size_of::<NearToken>()];
unsafe {
sys::validator_stake(
account_id.len() as _,
account_id.as_ptr() as _,
data.as_mut_ptr() as u64,
)
};
NearToken::from_yoctonear(u128::from_le_bytes(data))
}
/// 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 mut data = [0u8; size_of::<NearToken>()];
unsafe { sys::validator_total_stake(data.as_mut_ptr() as u64) };
NearToken::from_yoctonear(u128::from_le_bytes(data))
}
// #####################
// # 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()
/// );
/// ```
/// Example of usage [here](https://github.com/near/near-sdk-rs/blob/189897180649bce47aefa4e5af03664ee525508d/examples/cross-contract-calls/low-level/src/lib.rs#L18)
pub fn value_return(value: impl AsRef<[u8]>) {
let value = value.as_ref();
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")]
//* This was stabilized recently (~ >1.51), so ignore warnings but don't enforce higher msrv
#[allow(unused_unsafe)]
unsafe {
core::arch::wasm32::unreachable()
}
#[cfg(not(target_arch = "wasm32"))]
unsafe {
sys::panic()
}
}
/// 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());
/// ```
/// Example of usage [here](https://github.com/near/near-sdk-rs/blob/189897180649bce47aefa4e5af03664ee525508d/near-contract-standards/src/event.rs#L29)
pub fn log_str(message: &str) {
#[cfg(all(debug_assertions, not(target_arch = "wasm32")))]
eprintln!("{message}");
unsafe { sys::log_utf8(message.len() as _, message.as_ptr() as _) }
}
/// 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")))]
eprintln!("{}", String::from_utf8_lossy(message));
unsafe { sys::log_utf8(message.len() as _, message.as_ptr() as _) }
}
// ###############
// # Storage API #
// ###############
/// Writes key-value into storage.
/// If another key-value existed in the storage with the same key it 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_read};
///
/// assert!(!storage_write(b"key", b"value"));
/// assert!(storage_write(b"key", b"another_value"));
/// assert_eq!(storage_read(b"key").unwrap(), b"another_value");
/// ```
/// Example of usage [here](https://github.com/near/near-sdk-rs/blob/189897180649bce47aefa4e5af03664ee525508d/near-contract-standards/src/upgrade/mod.rs#L63)
pub fn storage_write(key: &[u8], value: &[u8]) -> bool {
match unsafe {
sys::storage_write(
key.len() as _,
key.as_ptr() as _,
value.len() as _,
value.as_ptr() as _,
EVICTED_REGISTER,
)
} {
0 => false,
1 => true,
_ => abort(),
}
}
/// Reads the value stored under the given key.
///
/// # 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 [`near-examples/update-migrate-rust` repo](https://github.com/near-examples/update-migrate-rust).
///
/// # Examples
/// ```
/// use near_sdk::env::{storage_write, storage_read};
///
/// assert!(storage_read(b"key").is_none());
/// storage_write(b"key", b"value");
/// assert_eq!(storage_read(b"key").unwrap(), b"value");
/// ```
///
/// Another example:
/// - [near-contract-standards/src/upgrade](https://github.com/near/near-sdk-rs/blob/746e4280a7e25b2036bd4e2f2c186cd76e1a7cde/near-contract-standards/src/upgrade/mod.rs?plain=1#L77)
pub fn storage_read(key: &[u8]) -> Option<Vec<u8>> {
match unsafe { sys::storage_read(key.len() as _, key.as_ptr() as _, ATOMIC_OP_REGISTER) } {
0 => None,
1 => Some(expect_register(read_register(ATOMIC_OP_REGISTER))),
_ => abort(),
}
}
/// 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);
/// ```
/// Example of usage [here](https://github.com/near/near-sdk-rs/blob/189897180649bce47aefa4e5af03664ee525508d/near-contract-standards/src/upgrade/mod.rs#L79)
pub fn storage_remove(key: &[u8]) -> bool {
match unsafe { sys::storage_remove(key.len() as _, key.as_ptr() as _, EVICTED_REGISTER) } {
0 => false,
1 => true,
_ => abort(),
}
}
/// 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<Vec<u8>> {
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,
1 => true,
_ => abort(),
}
}
// ############################################
// # Saving and loading of the contract state #
// ############################################
/// Load the state of the given object.
pub fn state_read<T: borsh::BorshDeserialize>() -> Option<T> {
storage_read(STATE_KEY).map(|data| {
T::try_from_slice(&data)
.unwrap_or_else(|_| panic_str("Cannot deserialize the contract state."))
})
}
/// Writes the specified state to storage.
pub fn state_write<T: borsh::BorshSerialize>(state: &T) {
let data = match borsh::to_vec(state) {
Ok(serialized) => serialized,
Err(_) => panic_str("Cannot serialize the contract state."),
};
storage_write(STATE_KEY, &data);
}
/// Returns `true` if the contract state exists and `false` otherwise.
pub fn state_exists() -> bool {
storage_has_key(STATE_KEY)
}
// #####################################
// # Parameters exposed by the runtime #
// #####################################
/// 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));
/// ```
/// Example of usage [here](https://github.com/near/near-sdk-rs/blob/189897180649bce47aefa4e5af03664ee525508d/near-contract-standards/src/fungible_token/storage_impl.rs#L105), [here](https://github.com/near/near-sdk-rs/blob/master/near-contract-standards/src/non_fungible_token/utils.rs) and [here](https://github.com/near/near-sdk-rs/blob/master/examples/fungible-token/tests/workspaces.rs)
pub fn storage_byte_cost() -> NearToken {
NearToken::from_yoctonear(10_000_000_000_000_000_000u128)
}
// ##################
// # Helper methods #
// ##################
/// 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
{
return false;
}
// NOTE: We don't want to use Regex here, because it requires extra time to compile it.
// The valid account ID regex is /^(([a-z\d]+[-_])*[a-z\d]+\.)*([a-z\d]+[-_])*[a-z\d]+$/
// Instead the implementation is based on the previous character checks.
// We can safely assume that last char was a separator.
let mut last_char_is_separator = true;
for c in account_id {
let current_char_is_separator = match *c {
b'a'..=b'z' | b'0'..=b'9' => false,
b'-' | b'_' | b'.' => true,
_ => return false,
};
if current_char_is_separator && last_char_is_separator {
return false;
}
last_char_is_separator = current_char_is_separator;
}
// The account can't end as separator.
!last_char_is_separator
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_valid_account_id_strings() {
// Valid
for account_id in &[
"aa",
"a-a",
"a-aa",
"100",
"0o",
"com",
"near",
"bowen",
"b-o_w_e-n",
"b.owen",
"bro.wen",
"a.ha",
"a.b-a.ra",
"system",
"over.9000",
"google.com",
"illia.cheapaccounts.near",
"0o0ooo00oo00o",
"alex-skidanov",
"10-4.8-2",
"b-o_w_e-n",
"no_lols",
"0123456789012345678901234567890123456789012345678901234567890123",
// Valid, but can't be created
"near.a",
"a.a",
] {
assert!(
is_valid_account_id(account_id.as_ref()),
"Valid account id {:?} marked invalid",
account_id
);
}
// Invalid
for account_id in &[
"",
"a",
"A",
"Abc",
"-near",
"near-",
"-near-",
"near.",
".near",
"near@",
"@near",
"неар",
"@@@@@",
"0__0",
"0_-_0",
"0_-_0",
"..",
"a..near",
"nEar",
"_bowen",
"hello world",
"abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz.abcdefghijklmnopqrstuvwxyz",
"01234567890123456789012345678901234567890123456789012345678901234",
// `@` separators are banned now
"some-complex-address@gmail.com",
"sub.buy_d1gitz@atata@b0-rg.c_0_m",
] {
assert!(
!is_valid_account_id(account_id.as_ref()),
"Invalid account id {:?} marked valid",
account_id
);
}
}
#[test]
fn test_is_valid_account_id_binary() {
assert!(!is_valid_account_id(&[]));
assert!(!is_valid_account_id(&[0]));
assert!(!is_valid_account_id(&[0, 1]));
assert!(!is_valid_account_id(&[0, 1, 2]));
assert!(is_valid_account_id(b"near"));
}
#[test]
fn hash_smoke_tests() {
assert_eq!(
&super::sha256_array(b"some value"),
hex::decode("ab3d07f3169ccbd0ed6c4b45de21519f9f938c72d24124998aab949ce83bb51b")
.unwrap()
.as_slice()
);
assert_eq!(
&super::keccak256_array(b"some value"),
hex::decode("f928dfb5fc72b3bbfb9a5ccb0ee9843b27b4ac1ebc25a6f6f783e23ebd47ef1f")
.unwrap()
.as_slice()
);
assert_eq!(
&super::keccak512_array(b"some value"),
hex::decode("3e38d140a85123374ee63ec208973aa39b87349d17ccac948a2493e18b18b5913220cd174b4f511aa97977009e16be485fc94f5e2743cb9bb0579d35ab410583")
.unwrap()
.as_slice()
);
assert_eq!(
&super::ripemd160_array(b"some value"),
hex::decode("09f025fed704e1ecac8f88b2bda3e56876da03ac").unwrap().as_slice()
);
}
#[test]
fn random_seed_smoke_test() {
crate::testing_env!(
crate::test_utils::VMContextBuilder::new().random_seed([8; 32]).build()
);
assert_eq!(super::random_seed(), [8; 32]);
}
#[cfg(not(target_arch = "wasm32"))]
#[cfg(feature = "unstable")]
#[test]
fn test_ecrecover() {
use crate::test_utils::test_env;
use hex::FromHex;
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use serde_json::from_slice;
use std::fmt::Display;
#[derive(Deserialize)]
struct EcrecoverTest {
#[serde(with = "hex::serde")]
m: [u8; 32],
v: u8,
#[serde(with = "hex::serde")]
sig: [u8; 64],
mc: bool,
#[serde(deserialize_with = "deserialize_option_hex")]
res: Option<[u8; 64]>,
}
fn deserialize_option_hex<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
T: FromHex,
<T as FromHex>::Error: Display,
{
Deserialize::deserialize(deserializer)
.map(|v: Option<&str>| v.map(FromHex::from_hex).transpose().map_err(Error::custom))
.and_then(|v| v)
}
test_env::setup_free();
for EcrecoverTest { m, v, sig, mc, res } in
from_slice::<'_, Vec<_>>(include_bytes!("../../tests/ecrecover-tests.json")).unwrap()
{
assert_eq!(super::ecrecover(&m, &sig, v, mc), res);
}
}
#[test]
fn signer_public_key() {
let key: PublicKey =
"ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp".parse().unwrap();
crate::testing_env!(
crate::test_utils::VMContextBuilder::new().signer_account_pk(key.clone()).build()
);
assert_eq!(super::signer_account_pk(), key);
}
#[test]
fn ed25519_verify() {
const SIGNATURE: [u8; 64] = [
145, 193, 203, 18, 114, 227, 14, 117, 33, 213, 121, 66, 130, 14, 25, 4, 36, 120, 46,
142, 226, 215, 7, 66, 122, 112, 97, 30, 249, 135, 61, 165, 221, 249, 252, 23, 105, 40,
56, 70, 31, 152, 236, 141, 154, 122, 207, 20, 75, 118, 79, 90, 168, 6, 221, 122, 213,
29, 126, 196, 216, 104, 191, 6,
];
const BAD_SIGNATURE: [u8; 64] = [1; 64];
// create a forged signature with the `s` scalar not properly reduced
// https://docs.rs/ed25519/latest/src/ed25519/lib.rs.html#302
const FORGED_SIGNATURE: [u8; 64] = {
let mut sig = SIGNATURE;
sig[63] = 0b1110_0001;
sig
};
const PUBLIC_KEY: [u8; 32] = [
32, 122, 6, 120, 146, 130, 30, 37, 215, 112, 241, 251, 160, 196, 124, 17, 255, 75, 129,
62, 84, 22, 46, 206, 158, 184, 57, 224, 118, 35, 26, 182,
];
// create a forged public key to force a PointDecompressionError
// https://docs.rs/ed25519-dalek/latest/src/ed25519_dalek/public.rs.html#142
const FORGED_PUBLIC_KEY: [u8; 32] = {
let mut key = PUBLIC_KEY;
key[31] = 0b1110_0001;
key
};
// 32 bytes message
const MESSAGE: [u8; 32] = [
107, 97, 106, 100, 108, 102, 107, 106, 97, 108, 107, 102, 106, 97, 107, 108, 102, 106,
100, 107, 108, 97, 100, 106, 102, 107, 108, 106, 97, 100, 115, 107,
];
assert!(super::ed25519_verify(&SIGNATURE, MESSAGE, &PUBLIC_KEY));
assert!(!super::ed25519_verify(&BAD_SIGNATURE, MESSAGE, &FORGED_PUBLIC_KEY));
assert!(!super::ed25519_verify(&SIGNATURE, MESSAGE, &FORGED_PUBLIC_KEY));
assert!(!super::ed25519_verify(&FORGED_SIGNATURE, MESSAGE, &PUBLIC_KEY));
}
#[test]
pub fn alt_bn128_g1_multiexp() {
// Originated from https://github.com/near/nearcore/blob/8cd095ffc98a6507ed2d2a8982a6a3e42ebc1b62/runtime/near-test-contracts/estimator-contract/src/lib.rs#L557-L720
let buffer = [
16, 238, 91, 161, 241, 22, 172, 158, 138, 252, 202, 212, 136, 37, 110, 231, 118, 220,
8, 45, 14, 153, 125, 217, 227, 87, 238, 238, 31, 138, 226, 8, 238, 185, 12, 155, 93,
126, 144, 248, 200, 177, 46, 245, 40, 162, 169, 80, 150, 211, 157, 13, 10, 36, 44, 232,
173, 32, 32, 115, 123, 2, 9, 47, 190, 148, 181, 91, 69, 6, 83, 40, 65, 222, 251, 70,
81, 73, 60, 142, 130, 217, 176, 20, 69, 75, 40, 167, 41, 180, 244, 5, 142, 215, 135,
35,
];
assert_eq!(
super::alt_bn128_g1_multiexp(buffer),
vec![
150, 94, 159, 52, 239, 226, 181, 150, 77, 86, 90, 186, 102, 219, 243, 204, 36, 128,
164, 209, 106, 6, 62, 124, 235, 104, 223, 195, 30, 204, 42, 20, 13, 158, 14, 197,
133, 73, 43, 171, 28, 68, 82, 116, 244, 164, 36, 251, 244, 8, 234, 40, 118, 55,
216, 187, 242, 39, 213, 160, 192, 184, 28, 23
]
);
}
#[test]
pub fn alt_bn128_g1_sum() {
// Originated from https://github.com/near/nearcore/blob/8cd095ffc98a6507ed2d2a8982a6a3e42ebc1b62/runtime/near-test-contracts/estimator-contract/src/lib.rs#L557-L720
let buffer = [
0, 11, 49, 94, 29, 152, 111, 116, 138, 248, 2, 184, 8, 159, 80, 169, 45, 149, 48, 32,
49, 37, 6, 133, 105, 171, 194, 120, 44, 195, 17, 180, 35, 137, 154, 4, 192, 211, 244,
93, 200, 2, 44, 0, 64, 26, 108, 139, 147, 88, 235, 242, 23, 253, 52, 110, 236, 67, 99,
176, 2, 186, 198, 228, 25,
];
assert_eq!(
super::alt_bn128_g1_sum(buffer),
vec![
11, 49, 94, 29, 152, 111, 116, 138, 248, 2, 184, 8, 159, 80, 169, 45, 149, 48, 32,
49, 37, 6, 133, 105, 171, 194, 120, 44, 195, 17, 180, 35, 137, 154, 4, 192, 211,
244, 93, 200, 2, 44, 0, 64, 26, 108, 139, 147, 88, 235, 242, 23, 253, 52, 110, 236,
67, 99, 176, 2, 186, 198, 228, 25
]
);
}
#[test]
pub fn alt_bn128_pairing_check() {
// Taken from https://github.com/near/nearcore/blob/8cd095ffc98a6507ed2d2a8982a6a3e42ebc1b62/runtime/near-vm-runner/src/logic/tests/alt_bn128.rs#L239-L250
let valid_pair = [
117, 10, 217, 99, 113, 78, 234, 67, 183, 90, 26, 58, 200, 86, 195, 123, 42, 184, 213,
88, 224, 248, 18, 200, 108, 6, 181, 6, 28, 17, 99, 7, 36, 134, 53, 115, 192, 180, 3,
113, 76, 227, 174, 147, 50, 174, 79, 74, 151, 195, 172, 10, 211, 210, 26, 92, 117, 246,
65, 237, 168, 104, 16, 4, 1, 26, 3, 219, 6, 13, 193, 115, 77, 230, 27, 13, 242, 214,
195, 9, 213, 99, 135, 12, 160, 202, 114, 135, 175, 42, 116, 172, 79, 234, 26, 41, 212,
111, 192, 129, 124, 112, 57, 107, 38, 244, 230, 222, 240, 36, 65, 238, 133, 188, 19,
43, 148, 59, 205, 40, 161, 179, 173, 228, 88, 169, 231, 29, 17, 67, 163, 51, 165, 187,
101, 44, 250, 24, 68, 101, 92, 128, 203, 190, 51, 85, 9, 43, 58, 136, 68, 180, 92, 110,
185, 168, 107, 129, 45, 30, 187, 22, 100, 17, 75, 93, 216, 125, 23, 212, 11, 186, 199,
204, 1, 140, 133, 11, 82, 44, 65, 222, 20, 26, 48, 26, 132, 220, 25, 213, 93, 25, 79,
176, 4, 149, 151, 243, 11, 131, 253, 233, 121, 38, 222, 15, 118, 117, 200, 214, 175,
233, 130, 181, 193, 167, 255, 153, 169, 240, 207, 235, 28, 31, 83, 74, 69, 179, 6, 150,
72, 67, 74, 166, 130, 83, 82, 115, 123, 111, 208, 221, 64, 43, 237, 213, 186, 235, 7,
56, 251, 179, 95, 233, 159, 23, 109, 173, 85, 103, 8, 165, 235, 226, 218, 79, 72, 120,
172, 251, 20, 83, 121, 201, 140, 98, 170, 246, 121, 218, 19, 115, 42, 135, 60, 239, 30,
32, 49, 170, 171, 204, 196, 197, 160, 158, 168, 47, 23, 110, 139, 123, 222, 222, 245,
98, 125, 208, 70, 39, 110, 186, 146, 254, 66, 185, 118, 3, 78, 32, 47, 179, 197, 93,
79, 240, 204, 78, 236, 133, 213, 173, 117, 94, 63, 154, 68, 89, 236, 138, 0, 247, 242,
212, 245, 33, 249, 0, 35, 246, 233, 0, 124, 86, 198, 162, 201, 54, 19, 26, 196, 75,
254, 71, 70, 238, 51, 2, 23, 185, 152, 139, 134, 65, 107, 129, 114, 244, 47, 251, 240,
80, 193, 23,
];
assert!(super::alt_bn128_pairing_check(valid_pair));
// Taken from https://github.com/near/nearcore/blob/8cd095ffc98a6507ed2d2a8982a6a3e42ebc1b62/runtime/near-vm-runner/src/logic/tests/alt_bn128.rs#L254-L265
let invalid_pair = [
117, 10, 217, 99, 113, 78, 234, 67, 183, 90, 26, 58, 200, 86, 195, 123, 42, 184, 213,
88, 224, 248, 18, 200, 108, 6, 181, 6, 28, 17, 99, 7, 36, 134, 53, 115, 192, 180, 3,
113, 76, 227, 174, 147, 50, 174, 79, 74, 151, 195, 172, 10, 211, 210, 26, 92, 117, 246,
65, 237, 168, 104, 16, 4, 1, 26, 3, 219, 6, 13, 193, 115, 77, 230, 27, 13, 242, 214,
195, 9, 213, 99, 135, 12, 160, 202, 114, 135, 175, 42, 116, 172, 79, 234, 26, 41, 212,
111, 192, 129, 124, 112, 57, 107, 38, 244, 230, 222, 240, 36, 65, 238, 133, 188, 19,
43, 148, 59, 205, 40, 161, 179, 173, 228, 88, 169, 231, 29, 17, 67, 163, 51, 165, 187,
101, 44, 250, 24, 68, 101, 92, 128, 203, 190, 51, 85, 9, 43, 58, 136, 68, 180, 92, 110,
185, 168, 107, 129, 45, 30, 187, 22, 100, 17, 75, 93, 216, 125, 23, 212, 11, 186, 199,
204, 1, 140, 133, 11, 82, 44, 65, 222, 20, 26, 48, 26, 132, 220, 25, 213, 93, 25, 117,
10, 217, 99, 113, 78, 234, 67, 183, 90, 26, 58, 200, 86, 195, 123, 42, 184, 213, 88,
224, 248, 18, 200, 108, 6, 181, 6, 28, 17, 99, 7, 36, 134, 53, 115, 192, 180, 3, 113,
76, 227, 174, 147, 50, 174, 79, 74, 151, 195, 172, 10, 211, 210, 26, 92, 117, 246, 65,
237, 168, 104, 16, 4, 109, 173, 85, 103, 8, 165, 235, 226, 218, 79, 72, 120, 172, 251,
20, 83, 121, 201, 140, 98, 170, 246, 121, 218, 19, 115, 42, 135, 60, 239, 30, 32, 49,
170, 171, 204, 196, 197, 160, 158, 168, 47, 23, 110, 139, 123, 222, 222, 245, 98, 125,
208, 70, 39, 110, 186, 146, 254, 66, 185, 118, 3, 78, 32, 47, 179, 197, 93, 79, 240,
204, 78, 236, 133, 213, 173, 117, 94, 63, 154, 68, 89, 236, 138, 0, 247, 242, 212, 245,
33, 249, 0, 35, 246, 233, 0, 124, 86, 198, 162, 201, 54, 19, 26, 196, 75, 254, 71, 70,
238, 51, 2, 23, 185, 152, 139, 134, 65, 107, 129, 114, 244, 47, 251, 240, 80, 193, 23,
];
assert!(!super::alt_bn128_pairing_check(invalid_pair));
}
#[test]
fn bls12381_p1_sum_0_100() {
let buffer: [u8; 0] = [];
for _ in 0..100 {
let result = super::bls12381_p1_sum(buffer);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_p1_sum");
}
}
#[test]
fn bls12381_p1_sum_50_100() {
let buffer: [[u8; 2 * 97]; 25] = [[
0, 18, 25, 108, 90, 67, 214, 146, 36, 216, 113, 51, 137, 40, 95, 38, 185, 143, 134,
238, 145, 10, 179, 221, 102, 142, 65, 55, 56, 40, 32, 3, 204, 91, 115, 87, 175, 154,
122, 245, 75, 183, 19, 214, 34, 85, 232, 15, 86, 6, 186, 129, 2, 191, 190, 234, 68, 22,
183, 16, 199, 62, 140, 206, 48, 50, 195, 28, 98, 105, 196, 73, 6, 248, 172, 79, 120,
116, 206, 153, 251, 23, 85, 153, 146, 72, 101, 40, 150, 56, 132, 206, 66, 154, 153, 47,
238, 0, 0, 1, 16, 16, 152, 245, 195, 152, 147, 118, 87, 102, 175, 69, 18, 160, 199, 78,
27, 184, 155, 199, 230, 253, 241, 78, 62, 115, 55, 210, 87, 204, 15, 148, 101, 129,
121, 216, 51, 32, 185, 159, 49, 255, 148, 205, 43, 172, 3, 225, 169, 249, 244, 76, 162,
205, 171, 79, 67, 161, 163, 238, 52, 112, 253, 249, 11, 47, 194, 40, 235, 59, 112, 159,
205, 114, 240, 20, 131, 138, 200, 42, 109, 121, 122, 238, 254, 217, 160, 128, 75, 34,
237, 28, 232, 247,
]; 25];
let flat: Vec<u8> = buffer.iter().flat_map(|x| x.iter()).copied().collect();
for _ in 0..100 {
let result = super::bls12381_p1_sum(&flat);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_p1_sum");
}
}
#[test]
fn bls12381_p2_sum_0_100() {
let buffer: [u8; 0] = [];
for _ in 0..100 {
let result = super::bls12381_p2_sum(buffer);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_p2_sum");
}
}
#[test]
fn bls12381_p2_sum_50_100() {
let buffer: [[u8; 2 * 193]; 25] = [[
0, 12, 199, 10, 88, 127, 70, 82, 3, 157, 129, 23, 182, 16, 56, 88, 173, 205, 151, 40,
246, 174, 190, 35, 5, 120, 56, 154, 98, 218, 0, 66, 183, 98, 59, 28, 4, 54, 115, 79,
70, 60, 253, 209, 135, 210, 9, 3, 36, 24, 192, 173, 166, 53, 27, 112, 102, 31, 5, 51,
101, 222, 174, 86, 145, 7, 152, 189, 42, 206, 110, 43, 246, 186, 65, 146, 209, 162, 41,
150, 127, 106, 246, 202, 28, 154, 138, 17, 235, 192, 162, 50, 52, 78, 224, 246, 214, 7,
155, 165, 13, 37, 17, 99, 27, 32, 182, 214, 243, 132, 30, 97, 110, 157, 17, 182, 142,
195, 54, 140, 214, 1, 41, 217, 212, 120, 122, 181, 108, 78, 145, 69, 163, 137, 39, 229,
28, 156, 214, 39, 29, 73, 61, 147, 136, 9, 245, 11, 215, 190, 237, 178, 51, 40, 129,
143, 159, 253, 175, 219, 109, 166, 164, 221, 128, 197, 169, 4, 138, 184, 177, 84, 223,
60, 173, 147, 140, 206, 222, 130, 159, 17, 86, 247, 105, 217, 225, 73, 121, 30, 142,
12, 217, 0, 9, 174, 177, 12, 55, 43, 94, 241, 1, 6, 117, 198, 164, 118, 47, 218, 51,
99, 100, 137, 194, 59, 88, 28, 117, 34, 5, 137, 175, 188, 12, 196, 98, 73, 249, 33,
238, 160, 45, 209, 183, 97, 224, 54, 255, 219, 174, 34, 25, 47, 165, 216, 115, 47, 249,
243, 142, 11, 28, 241, 46, 173, 253, 38, 8, 240, 199, 163, 154, 206, 215, 116, 104, 55,
131, 58, 226, 83, 187, 87, 239, 156, 13, 152, 164, 182, 158, 235, 41, 80, 144, 25, 23,
233, 157, 30, 23, 72, 130, 205, 211, 85, 30, 12, 230, 23, 136, 97, 255, 131, 225, 149,
254, 203, 207, 253, 83, 166, 123, 111, 16, 180, 67, 30, 66, 62, 40, 164, 128, 50, 127,
235, 231, 2, 118, 3, 111, 96, 187, 156, 153, 207, 118, 51, 2, 210, 37, 68, 118, 0, 212,
159, 147, 43, 157, 211, 202, 30, 105, 89, 105, 122, 166, 3, 231, 77, 134, 102, 104, 26,
45, 202, 129, 96, 195, 133, 118, 104, 174, 7, 68, 64, 54, 102, 25, 235, 137, 32, 37,
108, 78, 74,
]; 25];
let flat: Vec<u8> = buffer.iter().flat_map(|x| x.iter()).copied().collect();
let result = super::bls12381_p2_sum(&flat);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_p2_sum");
}
#[test]
fn bls12381_g1_multiexp_0_100() {
let buffer: [u8; 0] = [];
let result = super::bls12381_g1_multiexp(buffer);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_g1_multiexp");
}
#[test]
fn bls12381_g1_multiexp_50_100() {
let buffer: [[u8; 96 + 32]; 50] = [[
23, 241, 211, 167, 49, 151, 215, 148, 38, 149, 99, 140, 79, 169, 172, 15, 195, 104,
140, 79, 151, 116, 185, 5, 161, 78, 58, 63, 23, 27, 172, 88, 108, 85, 232, 63, 249,
122, 26, 239, 251, 58, 240, 10, 219, 34, 198, 187, 8, 179, 244, 129, 227, 170, 160,
241, 160, 158, 48, 237, 116, 29, 138, 228, 252, 245, 224, 149, 213, 208, 10, 246, 0,
219, 24, 203, 44, 4, 179, 237, 208, 60, 199, 68, 162, 136, 138, 228, 12, 170, 35, 41,
70, 197, 231, 225, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255,
]; 50];
let flat: Vec<u8> = buffer.iter().flat_map(|x| x.iter()).copied().collect();
let result = super::bls12381_g1_multiexp(&flat);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_g1_multiexp");
}
#[test]
fn bls12381_g2_multiexp_0_100() {
let buffer: [u8; 0] = [];
let result = super::bls12381_g2_multiexp(buffer);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_g2_multiexp");
}
#[test]
fn bls12381_g2_multiexp_50_100() {
let buffer: [[u8; 192 + 32]; 50] = [[
19, 224, 43, 96, 82, 113, 159, 96, 125, 172, 211, 160, 136, 39, 79, 101, 89, 107, 208,
208, 153, 32, 182, 26, 181, 218, 97, 187, 220, 127, 80, 73, 51, 76, 241, 18, 19, 148,
93, 87, 229, 172, 125, 5, 93, 4, 43, 126, 2, 74, 162, 178, 240, 143, 10, 145, 38, 8, 5,
39, 45, 197, 16, 81, 198, 228, 122, 212, 250, 64, 59, 2, 180, 81, 11, 100, 122, 227,
209, 119, 11, 172, 3, 38, 168, 5, 187, 239, 212, 128, 86, 200, 193, 33, 189, 184, 6, 6,
196, 160, 46, 167, 52, 204, 50, 172, 210, 176, 43, 194, 139, 153, 203, 62, 40, 126,
133, 167, 99, 175, 38, 116, 146, 171, 87, 46, 153, 171, 63, 55, 13, 39, 92, 236, 29,
161, 170, 169, 7, 95, 240, 95, 121, 190, 12, 229, 213, 39, 114, 125, 110, 17, 140, 201,
205, 198, 218, 46, 53, 26, 173, 253, 155, 170, 140, 189, 211, 167, 109, 66, 154, 105,
81, 96, 209, 44, 146, 58, 201, 204, 59, 172, 162, 137, 225, 147, 84, 134, 8, 184, 40,
1, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
]; 50];
let flat: Vec<u8> = buffer.iter().flat_map(|x| x.iter()).copied().collect();
let result = super::bls12381_g2_multiexp(&flat);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_g2_multiexp");
}
#[test]
fn bls12381_map_fp_to_g1_0_100() {
let buffer: [u8; 0] = [];
let result = super::bls12381_map_fp_to_g1(buffer);
assert!(result.is_empty(), "Expected an empty result from bls12381_map_fp_to_g1");
}
#[test]
fn bls12381_map_fp_to_g1_50_100() {
let buffer: [[u8; 48]; 50] = [[
20, 64, 110, 91, 251, 146, 9, 37, 106, 56, 32, 135, 154, 41, 172, 47, 98, 214, 172,
168, 35, 36, 191, 58, 226, 170, 125, 60, 84, 121, 32, 67, 189, 140, 121, 31, 204, 219,
8, 12, 26, 82, 220, 104, 184, 182, 147, 80,
]; 50];
let flat: Vec<u8> = buffer.iter().flat_map(|x| x.iter()).copied().collect();
let result = super::bls12381_map_fp_to_g1(&flat);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_map_fp_to_g1");
}
#[test]
fn bls12381_map_fp2_to_g2_0_100() {
let buffer: [u8; 0] = [];
let result = super::bls12381_map_fp2_to_g2(buffer);
assert!(result.is_empty(), "Expected an empty result from bls12381_map_fp2_to_g2");
}
#[test]
fn bls12381_map_fp2_to_g2_10_100() {
let buffer: [[u8; 96]; 10] = [[
14, 136, 91, 179, 57, 150, 225, 47, 7, 218, 105, 7, 62, 44, 12, 200, 128, 188, 142,
255, 38, 210, 167, 36, 41, 158, 177, 45, 84, 244, 188, 242, 111, 71, 72, 187, 2, 14,
128, 167, 227, 121, 74, 123, 14, 71, 166, 65, 20, 64, 110, 91, 251, 146, 9, 37, 106,
56, 32, 135, 154, 41, 172, 47, 98, 214, 172, 168, 35, 36, 191, 58, 226, 170, 125, 60,
84, 121, 32, 67, 189, 140, 121, 31, 204, 219, 8, 12, 26, 82, 220, 104, 184, 182, 147,
80,
]; 10];
let flat: Vec<u8> = buffer.iter().flat_map(|x| x.iter()).copied().collect();
let result = super::bls12381_map_fp2_to_g2(&flat);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_map_fp2_to_g2");
}
#[test]
fn bls12381_pairing_0_100() {
let buffer: [u8; 0] = [];
let result = super::bls12381_pairing_check(buffer);
assert!(result, "Expected result to be true");
}
#[test]
fn bls12381_pairing_valid_check() {
// Valid test vector (should return true)
let valid_input = hex::decode("085fad8696122c8a421033164e6a71d9adb3882933beba2c14dcad9bfd4badb30b49306c59a7a7837b72e02993f5a4ad025871da31a9be44cd3a46365038ef6f3658fc65ff3064e348083b2de4d983c7436f486f6e9de272fa0db7dfa543656811f7dbc8c5b084e2daf685536a2d155d69c7683b811c840e4167a5c966bad4eebfdb757ef9caa63ffde16727fa5c15ac0b15a2802624e85d6987eb53a69714401adfd5ca5e6151a8e9c0790dfc4494ea77ad32b66e95da7f615ee2fe7b6594f00493deb2392b4159afc07b69000f9b097ecca94bf5a46cb13f95dabdd9a40a2e207c077059c821caa29a40930b4b757f11404dcfe5e92c69acdbf3667651d5adf6856956805693fb945d83c5cf158371536814442ff31d6ad1b834a4ab13ad9917f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb114d1d6855d545a8aa7d76c8cf2e21f267816aef1db507c96655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca0f968bd243908ff3e5fa1ab3f31e078197e58ace562bbe8b5a271d5fba50237da0c8fe65e7b5771cc0a86fd57f32347e15a26d1f5d56c472d019eea2539e58db00c49aa5d0a9663838903fddbe436b5b157e83b35d1a4e5f89f78127f35dacf005a2854c7f36818c137070d1342bba362b5d0c7daed605fcc739df577c33bd6ab6e07ab4a97beee81aa57c8d41f447440eeaf1f595b7b57457d7792b4bc14be74d0038f7ac3767a9c61fecaa02c3d07982c02995f22f66c05b8eb3b9facd5571").unwrap();
let result = super::bls12381_pairing_check(&valid_input);
assert!(result, "Expected valid pairing check to return true");
}
#[test]
fn bls12381_pairing_5_100() {
let buffer: [[u8; 288]; 5] = [[
23, 241, 211, 167, 49, 151, 215, 148, 38, 149, 99, 140, 79, 169, 172, 15, 195, 104,
140, 79, 151, 116, 185, 5, 161, 78, 58, 63, 23, 27, 172, 88, 108, 85, 232, 63, 249,
122, 26, 239, 251, 58, 240, 10, 219, 34, 198, 187, 8, 179, 244, 129, 227, 170, 160,
241, 160, 158, 48, 237, 116, 29, 138, 228, 252, 245, 224, 149, 213, 208, 10, 246, 0,
219, 24, 203, 44, 4, 179, 237, 208, 60, 199, 68, 162, 136, 138, 228, 12, 170, 35, 41,
70, 197, 231, 225, 19, 224, 43, 96, 82, 113, 159, 96, 125, 172, 211, 160, 136, 39, 79,
101, 89, 107, 208, 208, 153, 32, 182, 26, 181, 218, 97, 187, 220, 127, 80, 73, 51, 76,
241, 18, 19, 148, 93, 87, 229, 172, 125, 5, 93, 4, 43, 126, 2, 74, 162, 178, 240, 143,
10, 145, 38, 8, 5, 39, 45, 197, 16, 81, 198, 228, 122, 212, 250, 64, 59, 2, 180, 81,
11, 100, 122, 227, 209, 119, 11, 172, 3, 38, 168, 5, 187, 239, 212, 128, 86, 200, 193,
33, 189, 184, 6, 6, 196, 160, 46, 167, 52, 204, 50, 172, 210, 176, 43, 194, 139, 153,
203, 62, 40, 126, 133, 167, 99, 175, 38, 116, 146, 171, 87, 46, 153, 171, 63, 55, 13,
39, 92, 236, 29, 161, 170, 169, 7, 95, 240, 95, 121, 190, 12, 229, 213, 39, 114, 125,
110, 17, 140, 201, 205, 198, 218, 46, 53, 26, 173, 253, 155, 170, 140, 189, 211, 167,
109, 66, 154, 105, 81, 96, 209, 44, 146, 58, 201, 204, 59, 172, 162, 137, 225, 147, 84,
134, 8, 184, 40, 1,
]; 5];
let flat: Vec<u8> = buffer.iter().flat_map(|x| x.iter()).copied().collect();
let result = super::bls12381_pairing_check(&flat);
assert!(!result, "Expected result to be false");
}
#[test]
fn bls12381_p1_decompress_0_100() {
let buffer: [u8; 0] = [];
let result = super::bls12381_p1_decompress(buffer);
assert!(result.is_empty(), "Expected an empty result from bls12381_p1_decompress");
}
#[test]
fn bls12381_p1_decompress_50_100() {
let buffer: [[u8; 48]; 50] = [[
185, 110, 35, 139, 110, 142, 126, 177, 120, 97, 234, 41, 91, 204, 20, 203, 207, 103,
224, 112, 176, 18, 102, 59, 68, 107, 137, 231, 10, 71, 183, 63, 198, 228, 242, 206,
195, 124, 70, 91, 53, 182, 222, 158, 19, 104, 106, 15,
]; 50];
let flat: Vec<u8> = buffer.iter().flat_map(|x| x.iter()).copied().collect();
let result = super::bls12381_p1_decompress(&flat);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_p1_decompress");
}
#[test]
fn bls12381_p2_decompress_0_100() {
let buffer: [u8; 0] = [];
let result = super::bls12381_p2_decompress(buffer);
assert!(result.is_empty(), "Expected an empty result from bls12381_p2_decompress");
}
#[test]
fn bls12381_p2_decompress_50_100() {
let buffer: [[u8; 96]; 50] = [[
143, 150, 139, 210, 67, 144, 143, 243, 229, 250, 26, 179, 243, 30, 7, 129, 151, 229,
138, 206, 86, 43, 190, 139, 90, 39, 29, 95, 186, 80, 35, 125, 160, 200, 254, 101, 231,
181, 119, 28, 192, 168, 111, 213, 127, 50, 52, 126, 21, 162, 109, 31, 93, 86, 196, 114,
208, 25, 238, 162, 83, 158, 88, 219, 0, 196, 154, 165, 208, 169, 102, 56, 56, 144, 63,
221, 190, 67, 107, 91, 21, 126, 131, 179, 93, 26, 78, 95, 137, 247, 129, 39, 243, 93,
172, 240,
]; 50];
let flat: Vec<u8> = buffer.iter().flat_map(|x| x.iter()).copied().collect();
let result = super::bls12381_p2_decompress(&flat);
assert!(!result.is_empty(), "Expected a non-empty result from bls12381_p2_decompress");
}
#[test]
fn test_global_contract_functions() {
// Test the global contract promise batch action functions
// These tests verify the functions can be called without panicking
let promise_index = super::promise_batch_create(&"alice.near".parse().unwrap());
let code = vec![0u8; 100]; // Mock contract bytecode
let code_hash = [0u8; 32]; // Mock 32-byte hash (CryptoHash)
let account_id = crate::AccountIdRef::new_or_panic("deployer.near");
// Test deploy_global_contract
super::promise_batch_action_deploy_global_contract(promise_index, &code);
// Test deploy_global_contract_by_account_id
super::promise_batch_action_deploy_global_contract_by_account_id(promise_index, &code);
// Test use_global_contract
super::promise_batch_action_use_global_contract(promise_index, &code_hash);
// Test use_global_contract_by_account_id
super::promise_batch_action_use_global_contract_by_account_id(promise_index, account_id);
}
#[test]
fn test_global_contract_edge_cases() {
// Test with minimal valid inputs
let promise_index = super::promise_batch_create(&"alice.near".parse().unwrap());
// Test with single byte code (minimal size)
super::promise_batch_action_deploy_global_contract(promise_index, &[0]);
super::promise_batch_action_deploy_global_contract_by_account_id(promise_index, &[0]);
// Test with 32-byte hash (standard size for CryptoHash)
let valid_hash = [0u8; 32];
super::promise_batch_action_use_global_contract(promise_index, &valid_hash);
}
}