aurora_engine_types/parameters/
engine.rs

1use crate::{
2    account_id::AccountId,
3    public_key::PublicKey,
4    types::{Address, RawH256, RawU256, WeiU256, Yocto},
5    Vec,
6};
7use borsh::{io, BorshDeserialize, BorshSerialize};
8use serde::{Deserialize, Serialize};
9
10/// Parameters for the `new` function.
11#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
12pub enum NewCallArgs {
13    V1(LegacyNewCallArgs),
14    V2(NewCallArgsV2),
15    V3(NewCallArgsV3),
16    V4(NewCallArgsV4),
17}
18
19impl NewCallArgs {
20    /// Creates a `NewCallArs` from the provided bytes which could be represented
21    /// in JSON or Borsh format. Supporting arguments in JSON format starting from V4.
22    pub fn deserialize(bytes: &[u8]) -> Result<Self, io::Error> {
23        Self::try_from_json(bytes).or_else(|_| {
24            Self::try_from_slice(bytes).map_or_else(
25                |_| LegacyNewCallArgs::try_from_slice(bytes).map(Self::V1),
26                Ok,
27            )
28        })
29    }
30
31    /// Returns a genesis hash of the Hashchain if present.
32    #[must_use]
33    pub const fn initial_hashchain(&self) -> Option<RawH256> {
34        match self {
35            Self::V4(args) => args.initial_hashchain,
36            Self::V1(_) | Self::V2(_) | Self::V3(_) => None,
37        }
38    }
39
40    fn try_from_json(bytes: &[u8]) -> Result<Self, serde_json::Error> {
41        serde_json::from_slice::<NewCallJsonArgs>(bytes).map(Into::into)
42    }
43}
44
45impl From<NewCallJsonArgs> for NewCallArgs {
46    fn from(value: NewCallJsonArgs) -> Self {
47        match value {
48            NewCallJsonArgs::V1(args) => Self::V4(args),
49        }
50    }
51}
52
53/// JSON encoded new parameters.
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(untagged)]
56pub enum NewCallJsonArgs {
57    V1(NewCallArgsV4),
58}
59
60/// Old Borsh-encoded parameters for the `new` function.
61#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
62pub struct LegacyNewCallArgs {
63    /// Chain id, according to the EIP-115 / ethereum-lists spec.
64    pub chain_id: RawU256,
65    /// Account which can upgrade this contract.
66    /// Use empty to disable updatability.
67    pub owner_id: AccountId,
68    /// Account of the bridge prover.
69    /// Use empty to not use base token as bridged asset.
70    pub bridge_prover_id: AccountId,
71    /// How many blocks after staging upgrade can deploy it.
72    pub upgrade_delay_blocks: u64,
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
76pub struct NewCallArgsV2 {
77    /// Chain id, according to the EIP-115 / ethereum-lists spec.
78    pub chain_id: RawU256,
79    /// Account which can upgrade this contract.
80    /// Use empty to disable updatability.
81    pub owner_id: AccountId,
82    /// How many blocks after staging upgrade can deploy it.
83    pub upgrade_delay_blocks: u64,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
87pub struct NewCallArgsV3 {
88    /// Chain id, according to the EIP-115 / ethereum-lists spec.
89    pub chain_id: RawU256,
90    /// Account which can upgrade this contract.
91    /// Use empty to disable updatability.
92    pub owner_id: AccountId,
93    /// How many blocks after staging upgrade can deploy it.
94    pub upgrade_delay_blocks: u64,
95    /// Relayer keys manager.
96    pub key_manager: AccountId,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
100pub struct NewCallArgsV4 {
101    /// Chain id, according to the EIP-115 / ethereum-lists spec.
102    #[serde(with = "chain_id_deserialize")]
103    pub chain_id: RawU256,
104    /// Account which can upgrade this contract.
105    /// Use empty to disable updatability.
106    pub owner_id: AccountId,
107    /// How many blocks after staging upgrade can deploy it.
108    pub upgrade_delay_blocks: u64,
109    /// Relayer keys manager.
110    pub key_manager: AccountId,
111    /// Initial value of the hashchain.
112    /// If none is provided then the hashchain will start disabled.
113    pub initial_hashchain: Option<RawH256>,
114}
115
116/// Borsh-encoded parameters for the `set_owner` function.
117#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
118#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
119pub struct SetOwnerArgs {
120    pub new_owner: AccountId,
121}
122
123/// Borsh-encoded parameters for the `set_upgrade_delay_blocks` function.
124#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
125#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
126pub struct SetUpgradeDelayBlocksArgs {
127    pub upgrade_delay_blocks: u64,
128}
129
130/// Borsh-encoded submit arguments used by the `submit_with_args` function.
131#[derive(Default, Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
132pub struct SubmitArgs {
133    /// Bytes of the transaction.
134    pub tx_data: Vec<u8>,
135    /// Max gas price the user is ready to pay for the transaction.
136    pub max_gas_price: Option<u128>,
137    /// Address of the `ERC20` token the user prefers to pay in.
138    pub gas_token_address: Option<Address>,
139}
140
141#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
142#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
143pub struct StartHashchainArgs {
144    pub block_height: u64,
145    pub block_hashchain: RawH256,
146}
147
148/// Fungible token storage balance
149#[derive(Default, Debug, Serialize, Deserialize)]
150pub struct StorageBalance {
151    pub total: Yocto,
152    pub available: Yocto,
153}
154
155impl StorageBalance {
156    #[must_use]
157    pub fn to_json_bytes(&self) -> Vec<u8> {
158        serde_json::to_vec(self).unwrap_or_default()
159    }
160}
161
162#[derive(BorshSerialize, BorshDeserialize)]
163pub struct RegisterRelayerCallArgs {
164    pub address: Address,
165}
166
167#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
168pub struct PausePrecompilesCallArgs {
169    pub paused_mask: u32,
170}
171
172#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
173#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
174pub struct ResultLog {
175    pub address: Address,
176    pub topics: Vec<RawU256>,
177    pub data: Vec<u8>,
178}
179
180/// The status of a transaction representing EVM error kinds.
181/// !!! THE ORDER OF VARIANTS MUSTN'T BE CHANGED FOR SAVING BACKWARD COMPATIBILITY !!!
182/// !!! NEW VARIANTS SHOULD BE ADDED IN THE END OF THE ENUM ONLY !!!
183#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
184#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
185pub enum TransactionStatus {
186    /// The transaction succeeded.
187    Succeed(Vec<u8>),
188    /// The transaction reverted.
189    Revert(Vec<u8>),
190    /// Execution runs out of gas.
191    OutOfGas,
192    /// Not enough fund to start the execution.
193    OutOfFund,
194    /// An opcode accesses external information, but the request is off offset limit.
195    OutOfOffset,
196    /// Call stack is too deep.
197    CallTooDeep,
198    /// Trying to pop from an empty stack.
199    StackUnderflow,
200    /// Trying to push into a stack over stack limit.
201    StackOverflow,
202    /// Jump destination is invalid.
203    InvalidJump,
204    /// An opcode accesses memory region, but the region is invalid.
205    InvalidRange,
206    /// Encountered the designated invalid opcode.
207    DesignatedInvalid,
208    /// Create opcode encountered collision.
209    CreateCollision,
210    /// Create init code exceeds limit.
211    CreateContractLimit,
212    /// Invalid opcode during execution or starting byte is 0xef. See [EIP-3541](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3541.md).
213    InvalidCode(u8),
214    /// PC underflow (unused).
215    #[allow(clippy::upper_case_acronyms)]
216    PCUnderflow,
217    /// Attempt to create an empty account (unused).
218    CreateEmpty,
219    /// Nonce reached maximum value of 2^64-1
220    MaxNonce,
221    /// `usize` casting overflow
222    UsizeOverflow,
223    /// Other normal errors.
224    Other(crate::Cow<'static, str>),
225    /// Contract contains forbidden opcode 0xEF
226    CreateContractStartingWithEF,
227}
228
229impl TransactionStatus {
230    #[must_use]
231    pub const fn is_ok(&self) -> bool {
232        matches!(*self, Self::Succeed(_))
233    }
234
235    #[must_use]
236    pub const fn is_revert(&self) -> bool {
237        matches!(*self, Self::Revert(_))
238    }
239
240    #[must_use]
241    pub const fn is_fail(&self) -> bool {
242        !matches!(*self, Self::Succeed(_) | Self::Revert(_))
243    }
244}
245
246impl AsRef<[u8]> for TransactionStatus {
247    fn as_ref(&self) -> &[u8] {
248        match self {
249            Self::Succeed(_) => b"SUCCESS",
250            Self::Revert(_) => errors::ERR_REVERT,
251            Self::OutOfFund => errors::ERR_OUT_OF_FUNDS,
252            Self::OutOfGas => errors::ERR_OUT_OF_GAS,
253            Self::OutOfOffset => errors::ERR_OUT_OF_OFFSET,
254            Self::CallTooDeep => errors::ERR_CALL_TOO_DEEP,
255            Self::StackUnderflow => errors::ERR_STACK_UNDERFLOW,
256            Self::StackOverflow => errors::ERR_STACK_OVERFLOW,
257            Self::InvalidJump => errors::ERR_INVALID_JUMP,
258            Self::InvalidRange => errors::ERR_INVALID_RANGE,
259            Self::DesignatedInvalid => errors::ERR_DESIGNATED_INVALID,
260            Self::CreateCollision => errors::ERR_CREATE_COLLISION,
261            Self::CreateContractLimit => errors::ERR_CREATE_CONTRACT_LIMIT,
262            Self::InvalidCode(_) => errors::ERR_INVALID_CODE,
263            Self::PCUnderflow => errors::ERR_PC_UNDERFLOW,
264            Self::CreateEmpty => errors::ERR_CREATE_EMPTY,
265            Self::MaxNonce => errors::ERR_MAX_NONCE,
266            Self::UsizeOverflow => errors::ERR_USIZE_OVERFLOW,
267            Self::CreateContractStartingWithEF => errors::ERR_CREATE_CONTRACT_STARTING_WITH_EF,
268            Self::Other(e) => e.as_bytes(),
269        }
270    }
271}
272
273/// Borsh-encoded parameters for the `call`, `call_with_args`, `deploy_code`,
274/// and `deploy_with_input` methods.
275#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
276#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
277pub struct SubmitResult {
278    version: u8,
279    pub status: TransactionStatus,
280    pub gas_used: u64,
281    pub logs: Vec<ResultLog>,
282}
283
284impl SubmitResult {
285    /// Must be incremented when making breaking changes to the `SubmitResult` ABI.
286    /// The current value of 7 is chosen because previously a `TransactionStatus` object
287    /// was first in the serialization, which is an enum with less than 7 variants.
288    /// Therefore, no previous `SubmitResult` would have begun with a leading 7 byte,
289    /// and this can be used to distinguish the new ABI (with version byte) from the old.
290    const VERSION: u8 = 7;
291
292    #[must_use]
293    pub const fn new(status: TransactionStatus, gas_used: u64, logs: Vec<ResultLog>) -> Self {
294        Self {
295            version: Self::VERSION,
296            status,
297            gas_used,
298            logs,
299        }
300    }
301}
302
303/// Borsh-encoded parameters for the engine `call` function.
304#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone)]
305pub struct FunctionCallArgsV2 {
306    pub contract: Address,
307    /// Wei compatible Borsh-encoded value field to attach an ETH balance to the transaction
308    pub value: WeiU256,
309    pub input: Vec<u8>,
310}
311
312/// Legacy Borsh-encoded parameters for the engine `call` function, to provide backward type compatibility
313#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone)]
314pub struct FunctionCallArgsV1 {
315    pub contract: Address,
316    pub input: Vec<u8>,
317}
318
319/// Deserialized values from bytes to current or legacy Borsh-encoded parameters
320/// for passing to the engine `call` function, and to provide backward type compatibility
321#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone)]
322pub enum CallArgs {
323    V2(FunctionCallArgsV2),
324    V1(FunctionCallArgsV1),
325}
326
327impl CallArgs {
328    #[must_use]
329    pub fn deserialize(bytes: &[u8]) -> Option<Self> {
330        Self::try_from_slice(bytes).map_or_else(
331            |_| {
332                FunctionCallArgsV1::try_from_slice(bytes)
333                    .map_or(None, |value| Some(Self::V1(value)))
334            },
335            Some,
336        )
337    }
338}
339
340/// Borsh-encoded parameters for the `view` function.
341#[derive(BorshSerialize, BorshDeserialize, Debug, Eq, PartialEq)]
342pub struct ViewCallArgs {
343    pub sender: Address,
344    pub address: Address,
345    pub amount: RawU256,
346    pub input: Vec<u8>,
347}
348
349/// Borsh-encoded parameters for `deploy_erc20_token` function.
350#[derive(BorshDeserialize, BorshSerialize, Debug, Eq, PartialEq, Clone)]
351pub enum DeployErc20TokenArgs {
352    Legacy(AccountId),
353    WithMetadata(AccountId),
354}
355
356impl DeployErc20TokenArgs {
357    pub fn deserialize(bytes: &[u8]) -> Result<Self, io::Error> {
358        Self::try_from_slice(bytes).or_else(|_| AccountId::try_from_slice(bytes).map(Self::Legacy))
359    }
360}
361
362/// Borsh-encoded parameters for the `get_storage_at` function.
363#[derive(BorshSerialize, BorshDeserialize)]
364pub struct GetStorageAtArgs {
365    pub address: Address,
366    pub key: RawH256,
367}
368
369#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
370pub struct StorageUnregisterArgs {
371    pub force: bool,
372}
373
374pub fn parse_json_args<'de, T: Deserialize<'de>>(
375    bytes: &'de [u8],
376) -> Result<T, errors::ParseArgsError> {
377    serde_json::from_slice(bytes).map_err(Into::into)
378}
379
380/// Parameters for setting relayer keys manager.
381#[derive(Debug, Clone, Eq, PartialEq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
382pub struct RelayerKeyManagerArgs {
383    pub key_manager: Option<AccountId>,
384}
385
386/// Parameters for adding or removing relayer function all keys.
387#[derive(Debug, Clone, Eq, PartialEq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
388pub struct RelayerKeyArgs {
389    pub public_key: PublicKey,
390}
391
392pub type FullAccessKeyArgs = RelayerKeyArgs;
393
394/// Parameters for upgrading the contract.
395#[derive(Debug, Clone, Eq, PartialEq, BorshSerialize, BorshDeserialize)]
396pub struct UpgradeParams {
397    /// Code for upgrading.
398    pub code: Vec<u8>,
399    /// Amount of gas for the state migration.
400    pub state_migration_gas: Option<u64>,
401}
402
403mod chain_id_deserialize {
404    use crate::types::{u256_to_arr, RawU256};
405    use primitive_types::U256;
406    use serde::{Deserialize, Deserializer, Serializer};
407
408    pub fn deserialize<'de, D>(deserializer: D) -> Result<RawU256, D::Error>
409    where
410        D: Deserializer<'de>,
411    {
412        u64::deserialize(deserializer).map(|v| u256_to_arr(&(v.into())))
413    }
414
415    pub fn serialize<S>(value: &RawU256, serializer: S) -> Result<S::Ok, S::Error>
416    where
417        S: Serializer,
418    {
419        let chain_id = U256::from_big_endian(value.as_slice()).low_u64();
420        serializer.serialize_u64(chain_id)
421    }
422}
423
424pub mod errors {
425    use crate::{account_id::ParseAccountError, String, ToString};
426
427    pub const ERR_REVERT: &[u8] = b"ERR_REVERT";
428    pub const ERR_NOT_ALLOWED: &[u8] = b"ERR_NOT_ALLOWED";
429    pub const ERR_OUT_OF_FUNDS: &[u8] = b"ERR_OUT_OF_FUNDS";
430    pub const ERR_CALL_TOO_DEEP: &[u8] = b"ERR_CALL_TOO_DEEP";
431    pub const ERR_OUT_OF_OFFSET: &[u8] = b"ERR_OUT_OF_OFFSET";
432    pub const ERR_OUT_OF_GAS: &[u8] = b"ERR_OUT_OF_GAS";
433    pub const ERR_STACK_UNDERFLOW: &[u8] = b"STACK_UNDERFLOW";
434    pub const ERR_STACK_OVERFLOW: &[u8] = b"STACK_OVERFLOW";
435    pub const ERR_INVALID_JUMP: &[u8] = b"INVALID_JUMP";
436    pub const ERR_INVALID_RANGE: &[u8] = b"INVALID_RANGE";
437    pub const ERR_DESIGNATED_INVALID: &[u8] = b"DESIGNATED_INVALID";
438    pub const ERR_CREATE_COLLISION: &[u8] = b"CREATE_COLLISION";
439    pub const ERR_CREATE_CONTRACT_LIMIT: &[u8] = b"CREATE_CONTRACT_LIMIT";
440    pub const ERR_INVALID_CODE: &[u8] = b"INVALID_CODE";
441    pub const ERR_PC_UNDERFLOW: &[u8] = b"PC_UNDERFLOW";
442    pub const ERR_CREATE_EMPTY: &[u8] = b"CREATE_EMPTY";
443    pub const ERR_MAX_NONCE: &[u8] = b"MAX_NONCE";
444    pub const ERR_USIZE_OVERFLOW: &[u8] = b"USIZE_OVERFLOW";
445    pub const ERR_CREATE_CONTRACT_STARTING_WITH_EF: &[u8] = b"ERR_CREATE_CONTRACT_STARTING_WITH_EF";
446
447    #[derive(Debug)]
448    pub enum ParseArgsError {
449        Json(String),
450        InvalidAccount(ParseAccountError),
451    }
452
453    impl From<serde_json::Error> for ParseArgsError {
454        fn from(e: serde_json::Error) -> Self {
455            Self::Json(e.to_string())
456        }
457    }
458
459    impl From<ParseAccountError> for ParseArgsError {
460        fn from(e: ParseAccountError) -> Self {
461            Self::InvalidAccount(e)
462        }
463    }
464
465    impl AsRef<[u8]> for ParseArgsError {
466        fn as_ref(&self) -> &[u8] {
467            match self {
468                Self::Json(e) => e.as_bytes(),
469                Self::InvalidAccount(e) => e.as_ref(),
470            }
471        }
472    }
473}
474
475#[cfg(test)]
476mod tests {
477    use super::*;
478
479    #[test]
480    fn test_view_call_fail() {
481        let bytes = [0; 71];
482        let _args = ViewCallArgs::try_from_slice(&bytes).unwrap_err();
483    }
484
485    #[test]
486    fn test_roundtrip_view_call() {
487        let x = ViewCallArgs {
488            sender: Address::from_array([1; 20]),
489            address: Address::from_array([2; 20]),
490            amount: [3; 32],
491            input: vec![1, 2, 3],
492        };
493        let bytes = borsh::to_vec(&x).unwrap();
494        let res = ViewCallArgs::try_from_slice(&bytes).unwrap();
495        assert_eq!(x, res);
496    }
497
498    #[test]
499    fn test_call_args_deserialize() {
500        let new_input = FunctionCallArgsV2 {
501            contract: Address::from_array([0u8; 20]),
502            value: WeiU256::default(),
503            input: Vec::new(),
504        };
505        let legacy_input = FunctionCallArgsV1 {
506            contract: Address::from_array([0u8; 20]),
507            input: Vec::new(),
508        };
509
510        // Parsing bytes in a new input format - data structures (wrapped into call args enum) with new arguments,
511        // made for flexibility and extensibility.
512
513        // Using new input format (wrapped into call args enum) and data structure with new argument (`value` field).
514        let args = CallArgs::V2(new_input.clone());
515        let input_bytes = borsh::to_vec(&args).unwrap();
516        let parsed_data = CallArgs::deserialize(&input_bytes);
517        assert_eq!(parsed_data, Some(args));
518
519        // Using new input format (wrapped into call args enum) and old data structure with legacy arguments,
520        // this is allowed for compatibility reason.
521        let args = CallArgs::V1(legacy_input.clone());
522        let input_bytes = borsh::to_vec(&args).unwrap();
523        let parsed_data = CallArgs::deserialize(&input_bytes);
524        assert_eq!(parsed_data, Some(args));
525
526        // Parsing bytes in an old input format - raw data structure (not wrapped into call args enum) with legacy arguments,
527        // made for backward compatibility.
528
529        // Using old input format (not wrapped into call args enum) - raw data structure with legacy arguments.
530        let input_bytes = borsh::to_vec(&legacy_input).unwrap();
531        let parsed_data = CallArgs::deserialize(&input_bytes);
532        assert_eq!(parsed_data, Some(CallArgs::V1(legacy_input)));
533
534        // Using old input format (not wrapped into call args enum) - raw data structure with new argument (`value` field).
535        // Data structures with new arguments allowed only in new input format for future extensibility reason.
536        // Raw data structure (old input format) allowed only with legacy arguments for backward compatibility reason.
537        // Unrecognized input should be handled and result as an exception in a call site.
538        let input_bytes = borsh::to_vec(&new_input).unwrap();
539        let parsed_data = CallArgs::deserialize(&input_bytes);
540        assert_eq!(parsed_data, None);
541    }
542
543    #[test]
544    fn test_deserialize_relayer_key_args() {
545        let json = r#"{"public_key": "ed25519:DcA2MzgpJbrUATQLLceocVckhhAqrkingax4oJ9kZ847"}"#;
546        let public_key: PublicKey = "ed25519:DcA2MzgpJbrUATQLLceocVckhhAqrkingax4oJ9kZ847"
547            .parse()
548            .unwrap();
549        let args = serde_json::from_str::<RelayerKeyArgs>(json).unwrap();
550
551        assert_eq!(args.public_key, public_key);
552    }
553
554    #[test]
555    fn test_deserialize_new_call_args_json() {
556        let chain_id = 1_313_161_559;
557        let json = serde_json::json!({
558            "chain_id": chain_id,
559            "owner_id": "aurora",
560            "upgrade_delay_blocks": 10,
561            "key_manager": "manager.near",
562            "initial_hashchain": null
563        });
564        let arguments = NewCallArgs::deserialize(&serde_json::to_vec(&json).unwrap());
565        let Ok(NewCallArgs::V4(arguments)) = arguments else {
566            panic!("Wrong type of arguments");
567        };
568        let value = serde_json::to_value(arguments).unwrap();
569        assert_eq!(value.get("chain_id").unwrap().as_u64(), Some(chain_id));
570
571        let outdated = serde_json::json!({
572            "chain_id": chain_id,
573            "owner_id": "aurora",
574            "upgrade_delay_blocks": 19
575        });
576        let arguments = NewCallArgs::deserialize(&serde_json::to_vec(&outdated).unwrap());
577        assert!(arguments.is_err());
578    }
579
580    #[test]
581    fn test_serialization_transaction_status_regression() {
582        let bytes =
583            std::fs::read("../engine-tests/src/tests/res/transaction_status.borsh").unwrap();
584        let actual = Vec::<TransactionStatus>::try_from_slice(&bytes).unwrap();
585        let expected = transaction_status_variants();
586
587        assert_eq!(actual, expected);
588    }
589
590    #[test]
591    fn test_read_deploy_erc20_args() {
592        let nep141: AccountId = "nep141.near".parse().unwrap();
593        let expected = DeployErc20TokenArgs::Legacy(nep141.clone());
594
595        // Legacy args
596        let bytes = borsh::to_vec(&nep141).unwrap();
597
598        let actual = DeployErc20TokenArgs::deserialize(&bytes).unwrap();
599        assert_eq!(actual, expected);
600
601        // Args from just account id
602        let bytes = borsh::to_vec("nep141.near").unwrap();
603
604        let actual = DeployErc20TokenArgs::deserialize(&bytes).unwrap();
605        assert_eq!(actual, expected);
606
607        let bytes = borsh::to_vec(&expected).unwrap();
608        let actual = DeployErc20TokenArgs::deserialize(&bytes).unwrap();
609        assert_eq!(actual, expected);
610
611        let expected = DeployErc20TokenArgs::WithMetadata(nep141);
612        let bytes = borsh::to_vec(&expected).unwrap();
613        let actual = DeployErc20TokenArgs::deserialize(&bytes).unwrap();
614        assert_eq!(actual, expected);
615    }
616
617    #[allow(dead_code)]
618    fn generate_borsh_bytes() {
619        let variants = transaction_status_variants();
620
621        std::fs::write(
622            "../engine-tests/src/tests/res/transaction_status.borsh",
623            borsh::to_vec(&variants).unwrap(),
624        )
625        .unwrap();
626    }
627
628    fn transaction_status_variants() -> Vec<TransactionStatus> {
629        vec![
630            TransactionStatus::Succeed(Vec::new()),
631            TransactionStatus::Revert(Vec::new()),
632            TransactionStatus::OutOfGas,
633            TransactionStatus::OutOfFund,
634            TransactionStatus::OutOfOffset,
635            TransactionStatus::CallTooDeep,
636            TransactionStatus::StackUnderflow,
637            TransactionStatus::StackOverflow,
638            TransactionStatus::InvalidJump,
639            TransactionStatus::InvalidRange,
640            TransactionStatus::DesignatedInvalid,
641            TransactionStatus::CreateCollision,
642            TransactionStatus::CreateContractLimit,
643            TransactionStatus::InvalidCode(0),
644            TransactionStatus::PCUnderflow,
645            TransactionStatus::CreateEmpty,
646            TransactionStatus::MaxNonce,
647            TransactionStatus::UsizeOverflow,
648            TransactionStatus::Other("error".into()),
649            TransactionStatus::CreateContractStartingWithEF,
650        ]
651    }
652}