use std::collections::BTreeMap;
use std::str::FromStr;
use crate::AccountId;
use base64::Engine;
use base64::prelude::BASE64_STANDARD;
use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Serialize};
use serde_with::{base64::Base64, serde_as};
use crate::errors::DataConversionError;
use crate::json::U64;
use crate::transaction::delegate_action::SignedDelegateAction;
use crate::utils::near_gas_as_u64;
use crate::{CryptoHash, NearGas, NearToken, PublicKey, Signature};
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub enum Action {
CreateAccount(CreateAccountAction),
DeployContract(DeployContractAction),
FunctionCall(Box<FunctionCallAction>),
Transfer(TransferAction),
Stake(Box<StakeAction>),
AddKey(Box<AddKeyAction>),
DeleteKey(Box<DeleteKeyAction>),
DeleteAccount(DeleteAccountAction),
Delegate(Box<SignedDelegateAction>),
DeployGlobalContract(DeployGlobalContractAction),
UseGlobalContract(Box<UseGlobalContractAction>),
DeterministicStateInit(Box<DeterministicStateInitAction>),
AddGasKey(Box<AddGasKeyAction>),
DeleteGasKey(Box<DeleteGasKeyAction>),
TransferToGasKey(Box<TransferToGasKeyAction>),
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct DeterministicStateInitAction {
pub state_init: DeterministicAccountStateInit,
pub deposit: NearToken,
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
#[borsh(use_discriminant = true)]
#[repr(u8)]
pub enum DeterministicAccountStateInit {
V1(DeterministicAccountStateInitV1),
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct DeterministicAccountStateInitV1 {
pub code: GlobalContractIdentifier,
#[serde_as(as = "BTreeMap<Base64, Base64>")]
pub data: BTreeMap<Vec<u8>, Vec<u8>>,
}
impl TryFrom<near_openapi_types::DeterministicStateInitAction> for DeterministicStateInitAction {
type Error = DataConversionError;
fn try_from(
val: near_openapi_types::DeterministicStateInitAction,
) -> Result<Self, Self::Error> {
let near_openapi_types::DeterministicStateInitAction {
state_init,
deposit,
} = val;
match state_init {
near_openapi_types::DeterministicAccountStateInit::V1(v1) => Ok(Self {
state_init: DeterministicAccountStateInit::V1(DeterministicAccountStateInitV1 {
code: v1.code.into(),
data: v1
.data
.into_iter()
.map(|(k, v)| {
Ok::<(Vec<u8>, Vec<u8>), DataConversionError>((
BASE64_STANDARD.decode(k)?,
BASE64_STANDARD.decode(v)?,
))
})
.collect::<Result<BTreeMap<Vec<u8>, Vec<u8>>, _>>()?,
}),
deposit,
}),
}
}
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct DeployGlobalContractAction {
#[serde_as(as = "Base64")]
pub code: Vec<u8>,
pub deploy_mode: GlobalContractDeployMode,
}
impl TryFrom<near_openapi_types::DeployGlobalContractAction> for DeployGlobalContractAction {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::DeployGlobalContractAction) -> Result<Self, Self::Error> {
let near_openapi_types::DeployGlobalContractAction { code, deploy_mode } = val;
Ok(Self {
code: BASE64_STANDARD.decode(code)?,
deploy_mode: deploy_mode.into(),
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct UseGlobalContractAction {
pub contract_identifier: GlobalContractIdentifier,
}
impl From<near_openapi_types::UseGlobalContractAction> for UseGlobalContractAction {
fn from(val: near_openapi_types::UseGlobalContractAction) -> Self {
let near_openapi_types::UseGlobalContractAction {
contract_identifier,
} = val;
Self {
contract_identifier: contract_identifier.into(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct CreateAccountAction {}
impl From<near_openapi_types::CreateAccountAction> for CreateAccountAction {
fn from(_: near_openapi_types::CreateAccountAction) -> Self {
Self {}
}
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct DeployContractAction {
#[serde_as(as = "Base64")]
pub code: Vec<u8>,
}
impl TryFrom<near_openapi_types::DeployContractAction> for DeployContractAction {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::DeployContractAction) -> Result<Self, Self::Error> {
let near_openapi_types::DeployContractAction { code } = val;
Ok(Self {
code: BASE64_STANDARD.decode(code)?,
})
}
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct FunctionCallAction {
pub method_name: String,
#[serde_as(as = "Base64")]
pub args: Vec<u8>,
#[serde(serialize_with = "near_gas_as_u64::serialize")]
pub gas: NearGas,
pub deposit: NearToken,
}
impl TryFrom<near_openapi_types::FunctionCallAction> for FunctionCallAction {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::FunctionCallAction) -> Result<Self, Self::Error> {
let near_openapi_types::FunctionCallAction {
method_name,
args,
gas,
deposit,
} = val;
Ok(Self {
method_name,
args: BASE64_STANDARD.decode(args)?,
gas,
deposit,
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct TransferAction {
pub deposit: NearToken,
}
impl TryFrom<near_openapi_types::TransferAction> for TransferAction {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::TransferAction) -> Result<Self, Self::Error> {
let near_openapi_types::TransferAction { deposit } = val;
Ok(Self { deposit })
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct StakeAction {
pub stake: NearToken,
pub public_key: PublicKey,
}
impl TryFrom<near_openapi_types::StakeAction> for StakeAction {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::StakeAction) -> Result<Self, Self::Error> {
let near_openapi_types::StakeAction { public_key, stake } = val;
Ok(Self {
public_key: public_key.try_into()?,
stake,
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct AddGasKeyAction {
pub public_key: PublicKey,
pub num_nonces: u32,
pub permission: AccessKeyPermission,
}
impl TryFrom<near_openapi_types::AddGasKeyAction> for AddGasKeyAction {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::AddGasKeyAction) -> Result<Self, Self::Error> {
let near_openapi_types::AddGasKeyAction {
public_key,
num_nonces,
permission,
} = val;
Ok(Self {
public_key: public_key.try_into()?,
num_nonces,
permission: permission.try_into()?,
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct DeleteGasKeyAction {
pub public_key: PublicKey,
}
impl TryFrom<near_openapi_types::DeleteGasKeyAction> for DeleteGasKeyAction {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::DeleteGasKeyAction) -> Result<Self, Self::Error> {
let near_openapi_types::DeleteGasKeyAction { public_key } = val;
Ok(Self {
public_key: public_key.try_into()?,
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct TransferToGasKeyAction {
pub public_key: PublicKey,
pub deposit: NearToken,
}
impl TryFrom<near_openapi_types::TransferToGasKeyAction> for TransferToGasKeyAction {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::TransferToGasKeyAction) -> Result<Self, Self::Error> {
let near_openapi_types::TransferToGasKeyAction {
public_key,
deposit,
} = val;
Ok(Self {
public_key: public_key.try_into()?,
deposit,
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct AddKeyAction {
pub public_key: PublicKey,
pub access_key: AccessKey,
}
impl TryFrom<near_openapi_types::AddKeyAction> for AddKeyAction {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::AddKeyAction) -> Result<Self, Self::Error> {
let near_openapi_types::AddKeyAction {
public_key,
access_key,
} = val;
Ok(Self {
public_key: public_key.try_into()?,
access_key: access_key.try_into()?,
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct AccessKey {
pub nonce: U64,
pub permission: AccessKeyPermission,
}
impl TryFrom<near_openapi_types::AccessKeyView> for AccessKey {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::AccessKeyView) -> Result<Self, Self::Error> {
let near_openapi_types::AccessKeyView { nonce, permission } = val;
Ok(Self {
nonce: U64(nonce),
permission: permission.try_into()?,
})
}
}
impl TryFrom<near_openapi_types::AccessKey> for AccessKey {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::AccessKey) -> Result<Self, Self::Error> {
let near_openapi_types::AccessKey { nonce, permission } = val;
Ok(Self {
nonce: U64(nonce),
permission: permission.try_into()?,
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub enum AccessKeyPermission {
FunctionCall(FunctionCallPermission),
FullAccess,
}
impl TryFrom<near_openapi_types::AccessKeyPermissionView> for AccessKeyPermission {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::AccessKeyPermissionView) -> Result<Self, Self::Error> {
match val {
near_openapi_types::AccessKeyPermissionView::FunctionCall {
allowance,
method_names,
receiver_id,
} => Ok(Self::FunctionCall(FunctionCallPermission {
allowance,
receiver_id,
method_names,
})),
near_openapi_types::AccessKeyPermissionView::FullAccess => Ok(Self::FullAccess),
}
}
}
impl TryFrom<near_openapi_types::AccessKeyPermission> for AccessKeyPermission {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::AccessKeyPermission) -> Result<Self, Self::Error> {
match val {
near_openapi_types::AccessKeyPermission::FunctionCall(function_call_permission) => {
Ok(Self::FunctionCall(function_call_permission.try_into()?))
}
near_openapi_types::AccessKeyPermission::FullAccess => Ok(Self::FullAccess),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct FunctionCallPermission {
pub allowance: Option<NearToken>,
pub receiver_id: String,
pub method_names: Vec<String>,
}
impl TryFrom<near_openapi_types::FunctionCallPermission> for FunctionCallPermission {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::FunctionCallPermission) -> Result<Self, Self::Error> {
let near_openapi_types::FunctionCallPermission {
allowance,
receiver_id,
method_names,
} = val;
Ok(Self {
allowance,
receiver_id,
method_names,
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct DeleteKeyAction {
pub public_key: PublicKey,
}
impl TryFrom<near_openapi_types::DeleteKeyAction> for DeleteKeyAction {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::DeleteKeyAction) -> Result<Self, Self::Error> {
let near_openapi_types::DeleteKeyAction { public_key } = val;
Ok(Self {
public_key: public_key.try_into()?,
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct DeleteAccountAction {
pub beneficiary_id: AccountId,
}
impl From<near_openapi_types::DeleteAccountAction> for DeleteAccountAction {
fn from(val: near_openapi_types::DeleteAccountAction) -> Self {
let near_openapi_types::DeleteAccountAction { beneficiary_id } = val;
Self { beneficiary_id }
}
}
#[derive(
BorshSerialize,
BorshDeserialize,
serde::Serialize,
serde::Deserialize,
PartialEq,
Eq,
Clone,
Debug,
)]
#[repr(u8)]
pub enum GlobalContractDeployMode {
CodeHash,
AccountId,
}
impl From<near_openapi_types::GlobalContractDeployMode> for GlobalContractDeployMode {
fn from(val: near_openapi_types::GlobalContractDeployMode) -> Self {
match val {
near_openapi_types::GlobalContractDeployMode::CodeHash => Self::CodeHash,
near_openapi_types::GlobalContractDeployMode::AccountId => Self::AccountId,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub enum GlobalContractIdentifier {
CodeHash(CryptoHash),
AccountId(AccountId),
}
impl From<near_openapi_types::GlobalContractIdentifier> for GlobalContractIdentifier {
fn from(val: near_openapi_types::GlobalContractIdentifier) -> Self {
match val {
near_openapi_types::GlobalContractIdentifier::CodeHash(code_hash) => {
Self::CodeHash(code_hash.into())
}
near_openapi_types::GlobalContractIdentifier::AccountId(account_id) => {
Self::AccountId(account_id)
}
}
}
}
impl From<near_openapi_types::GlobalContractIdentifierView> for GlobalContractIdentifier {
fn from(val: near_openapi_types::GlobalContractIdentifierView) -> Self {
match val {
near_openapi_types::GlobalContractIdentifierView::CryptoHash(code_hash) => {
Self::CodeHash(code_hash.into())
}
near_openapi_types::GlobalContractIdentifierView::AccountId(account_id) => {
Self::AccountId(account_id)
}
}
}
}
impl TryFrom<near_openapi_types::ActionView> for Action {
type Error = DataConversionError;
fn try_from(val: near_openapi_types::ActionView) -> Result<Self, Self::Error> {
match val {
near_openapi_types::ActionView::DeterministicStateInit {
code,
data,
deposit,
} => Ok(Self::DeterministicStateInit(Box::new(
DeterministicStateInitAction {
state_init: DeterministicAccountStateInit::V1(
DeterministicAccountStateInitV1 {
code: code.into(),
data: data
.into_iter()
.map(|(k, v)| {
Ok::<(Vec<u8>, Vec<u8>), DataConversionError>((
BASE64_STANDARD.decode(k)?,
BASE64_STANDARD.decode(v)?,
))
})
.collect::<Result<BTreeMap<Vec<u8>, Vec<u8>>, _>>()?,
},
),
deposit,
},
))),
near_openapi_types::ActionView::CreateAccount => {
Ok(Self::CreateAccount(CreateAccountAction {}))
}
near_openapi_types::ActionView::DeployContract { code } => {
Ok(Self::DeployContract(DeployContractAction {
code: BASE64_STANDARD.decode(code)?,
}))
}
near_openapi_types::ActionView::FunctionCall {
method_name,
args,
gas,
deposit,
} => Ok(Self::FunctionCall(Box::new(FunctionCallAction {
method_name,
args: BASE64_STANDARD.decode(args.0)?,
gas,
deposit,
}))),
near_openapi_types::ActionView::Transfer { deposit } => {
Ok(Self::Transfer(TransferAction { deposit }))
}
near_openapi_types::ActionView::Stake { public_key, stake } => {
Ok(Self::Stake(Box::new(StakeAction {
public_key: public_key.try_into()?,
stake,
})))
}
near_openapi_types::ActionView::AddKey {
access_key,
public_key,
} => Ok(Self::AddKey(Box::new(AddKeyAction {
public_key: public_key.try_into()?,
access_key: access_key.try_into()?,
}))),
near_openapi_types::ActionView::DeleteKey { public_key } => {
Ok(Self::DeleteKey(Box::new(DeleteKeyAction {
public_key: public_key.try_into()?,
})))
}
near_openapi_types::ActionView::DeleteAccount { beneficiary_id } => {
Ok(Self::DeleteAccount(DeleteAccountAction { beneficiary_id }))
}
near_openapi_types::ActionView::Delegate {
delegate_action,
signature,
} => Ok(Self::Delegate(Box::new(SignedDelegateAction {
delegate_action: delegate_action.try_into()?,
signature: Signature::from_str(&signature)?,
}))),
near_openapi_types::ActionView::DeployGlobalContract { code } => {
Ok(Self::DeployGlobalContract(DeployGlobalContractAction {
code: BASE64_STANDARD.decode(code)?,
deploy_mode: GlobalContractDeployMode::CodeHash,
}))
}
near_openapi_types::ActionView::DeployGlobalContractByAccountId { code } => {
Ok(Self::DeployGlobalContract(DeployGlobalContractAction {
code: BASE64_STANDARD.decode(code)?,
deploy_mode: GlobalContractDeployMode::AccountId,
}))
}
near_openapi_types::ActionView::UseGlobalContract { code_hash } => {
Ok(Self::UseGlobalContract(Box::new(UseGlobalContractAction {
contract_identifier: GlobalContractIdentifier::CodeHash(code_hash.into()),
})))
}
near_openapi_types::ActionView::UseGlobalContractByAccountId { account_id } => {
Ok(Self::UseGlobalContract(Box::new(UseGlobalContractAction {
contract_identifier: GlobalContractIdentifier::AccountId(account_id),
})))
}
near_openapi_types::ActionView::AddGasKey {
num_nonces,
permission,
public_key,
} => Ok(Self::AddGasKey(Box::new(AddGasKeyAction {
public_key: public_key.try_into()?,
num_nonces,
permission: permission.try_into()?,
}))),
near_openapi_types::ActionView::DeleteGasKey { public_key } => {
Ok(Self::DeleteGasKey(Box::new(DeleteGasKeyAction {
public_key: public_key.try_into()?,
})))
}
near_openapi_types::ActionView::TransferToGasKey {
amount: deposit,
public_key,
} => Ok(Self::TransferToGasKey(Box::new(TransferToGasKeyAction {
public_key: public_key.try_into()?,
deposit,
}))),
}
}
}
#[cfg(test)]
mod tests {
use std::collections::BTreeMap;
use std::sync::Arc;
use super::*;
use crate::crypto::{ED25519_PUBLIC_KEY_LENGTH, public_key::ED25519PublicKey};
use crate::transaction::delegate_action::{DelegateAction, NonDelegateAction};
use near_primitives::action as npa;
use near_primitives::deterministic_account_id::{
DeterministicAccountStateInit as npaDeterministicAccountStateInit,
DeterministicAccountStateInitV1 as npaDeterministicAccountStateInitV1,
};
use near_primitives::gas::Gas;
use near_primitives::global_contract::GlobalContractIdentifier as npaGlobalContractIdentifier;
use serde_json;
fn get_actions() -> (Vec<Action>, Vec<npa::Action>) {
let btreemap = BTreeMap::from([(b"key".to_vec(), b"value".to_vec())]);
let local_actions = vec![
Action::CreateAccount(CreateAccountAction {}),
Action::DeployContract(DeployContractAction {
code: vec![1, 2, 3],
}),
Action::FunctionCall(Box::new(FunctionCallAction {
method_name: "test".to_string(),
args: vec![4, 5, 6],
gas: NearGas::from_gas(1000000),
deposit: NearToken::from_yoctonear(0),
})),
Action::Transfer(TransferAction {
deposit: NearToken::from_yoctonear(1000000000),
}),
Action::Stake(Box::new(StakeAction {
stake: NearToken::from_yoctonear(100000000),
public_key: PublicKey::ED25519(ED25519PublicKey([0; ED25519_PUBLIC_KEY_LENGTH])),
})),
Action::AddKey(Box::new(AddKeyAction {
public_key: PublicKey::ED25519(ED25519PublicKey([0; ED25519_PUBLIC_KEY_LENGTH])),
access_key: AccessKey {
nonce: U64(0),
permission: AccessKeyPermission::FullAccess,
},
})),
Action::DeleteKey(Box::new(DeleteKeyAction {
public_key: PublicKey::ED25519(ED25519PublicKey([0; ED25519_PUBLIC_KEY_LENGTH])),
})),
Action::DeleteAccount(DeleteAccountAction {
beneficiary_id: "alice.near".parse().unwrap(),
}),
Action::DeployGlobalContract(DeployGlobalContractAction {
code: vec![7, 8, 9],
deploy_mode: GlobalContractDeployMode::CodeHash,
}),
Action::UseGlobalContract(Box::new(UseGlobalContractAction {
contract_identifier: GlobalContractIdentifier::AccountId(
"global.near".parse().unwrap(),
),
})),
Action::Delegate(Box::new(SignedDelegateAction {
delegate_action: DelegateAction {
sender_id: "sender.near".parse().unwrap(),
receiver_id: "receiver.near".parse().unwrap(),
actions: vec![
NonDelegateAction::try_from(Action::Transfer(TransferAction {
deposit: NearToken::from_yoctonear(1000),
}))
.unwrap(),
],
nonce: 1,
max_block_height: 1000,
public_key: PublicKey::ED25519(ED25519PublicKey(
[0; ED25519_PUBLIC_KEY_LENGTH],
)),
},
signature: Signature::from_parts(crate::crypto::KeyType::ED25519, &[0u8; 64])
.unwrap(),
})),
Action::DeterministicStateInit(Box::new(DeterministicStateInitAction {
state_init: DeterministicAccountStateInit::V1(DeterministicAccountStateInitV1 {
code: GlobalContractIdentifier::AccountId("init.near".parse().unwrap()),
data: btreemap.clone(),
}),
deposit: NearToken::from_yoctonear(5000000000),
})),
];
let near_primitives_actions = vec![
npa::Action::CreateAccount(npa::CreateAccountAction {}),
npa::Action::DeployContract(npa::DeployContractAction {
code: vec![1, 2, 3],
}),
npa::Action::FunctionCall(Box::new(npa::FunctionCallAction {
method_name: "test".to_string(),
args: vec![4, 5, 6],
gas: Gas::from_gas(1000000),
deposit: NearToken::ZERO,
})),
npa::Action::Transfer(npa::TransferAction {
deposit: NearToken::from_yoctonear(1000000000),
}),
npa::Action::Stake(Box::new(npa::StakeAction {
stake: NearToken::from_yoctonear(100000000),
public_key: near_crypto::PublicKey::empty(near_crypto::KeyType::ED25519),
})),
npa::Action::AddKey(Box::new(npa::AddKeyAction {
public_key: near_crypto::PublicKey::empty(near_crypto::KeyType::ED25519),
access_key: near_primitives::account::AccessKey {
nonce: 0,
permission: near_primitives::account::AccessKeyPermission::FullAccess,
},
})),
npa::Action::DeleteKey(Box::new(npa::DeleteKeyAction {
public_key: near_crypto::PublicKey::empty(near_crypto::KeyType::ED25519),
})),
npa::Action::DeleteAccount(npa::DeleteAccountAction {
beneficiary_id: "alice.near".parse().unwrap(),
}),
npa::Action::DeployGlobalContract(npa::DeployGlobalContractAction {
code: Arc::new([7, 8, 9]),
deploy_mode: npa::GlobalContractDeployMode::CodeHash,
}),
npa::Action::UseGlobalContract(Box::new(npa::UseGlobalContractAction {
contract_identifier: npa::GlobalContractIdentifier::AccountId(
"global.near".parse().unwrap(),
),
})),
npa::Action::Delegate(Box::new(npa::delegate::SignedDelegateAction {
delegate_action: npa::delegate::DelegateAction {
sender_id: "sender.near".parse().unwrap(),
receiver_id: "receiver.near".parse().unwrap(),
actions: vec![
npa::delegate::NonDelegateAction::try_from(npa::Action::Transfer(
npa::TransferAction {
deposit: NearToken::from_yoctonear(1000),
},
))
.unwrap(),
],
nonce: 1,
max_block_height: 1000,
public_key: near_crypto::PublicKey::empty(near_crypto::KeyType::ED25519),
},
signature: near_crypto::Signature::from_parts(
near_crypto::KeyType::ED25519,
&[0u8; 64],
)
.unwrap(),
})),
npa::Action::DeterministicStateInit(Box::new(npa::DeterministicStateInitAction {
state_init: npaDeterministicAccountStateInit::V1(
npaDeterministicAccountStateInitV1 {
code: npaGlobalContractIdentifier::AccountId("init.near".parse().unwrap()),
data: btreemap,
},
),
deposit: NearToken::from_yoctonear(5000000000),
})),
];
(local_actions, near_primitives_actions)
}
#[test]
fn test_action_serialization() {
let (local_actions, _) = get_actions();
for action in local_actions {
let serialized =
serde_json::to_string(&action).expect("Failed to serialize action to JSON");
let deserialized: Action =
serde_json::from_str(&serialized).expect("Failed to deserialize action from JSON");
assert_eq!(
action, deserialized,
"Serialization/Deserialization mismatch: original action: {action:?}, deserialized action: {deserialized:?}"
);
}
}
#[test]
fn test_action_borsh_serialization() {
let (local_actions, _) = get_actions();
for action in local_actions {
let serialized = borsh::to_vec(&action).expect("Failed to serialize action to borsh");
let deserialized: Action = Action::try_from_slice(&serialized)
.expect("Failed to deserialize action from borsh");
assert_eq!(
action, deserialized,
"Serialization/Deserialization mismatch: original action: {action:?}, deserialized action: {deserialized:?}"
);
}
}
#[test]
fn serialization_comparison_with_near_primitives() {
let (local_actions, near_primitives_actions) = get_actions();
assert_eq!(
local_actions.len(),
near_primitives_actions.len(),
"Action lists should have the same length"
);
for (local_action, np_action) in local_actions.iter().zip(near_primitives_actions.iter()) {
let local_borsh =
borsh::to_vec(local_action).expect("Failed to serialize local action to borsh");
let np_borsh = borsh::to_vec(np_action)
.expect("Failed to serialize near_primitives action to borsh");
assert_eq!(local_borsh, np_borsh, "Borsh serialization mismatch");
}
}
}