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#[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 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 #[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#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
55#[serde(untagged)]
56pub enum NewCallJsonArgs {
57 V1(NewCallArgsV4),
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
62pub struct LegacyNewCallArgs {
63 pub chain_id: RawU256,
65 pub owner_id: AccountId,
68 pub bridge_prover_id: AccountId,
71 pub upgrade_delay_blocks: u64,
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
76pub struct NewCallArgsV2 {
77 pub chain_id: RawU256,
79 pub owner_id: AccountId,
82 pub upgrade_delay_blocks: u64,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
87pub struct NewCallArgsV3 {
88 pub chain_id: RawU256,
90 pub owner_id: AccountId,
93 pub upgrade_delay_blocks: u64,
95 pub key_manager: AccountId,
97}
98
99#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
100pub struct NewCallArgsV4 {
101 #[serde(with = "chain_id_deserialize")]
103 pub chain_id: RawU256,
104 pub owner_id: AccountId,
107 pub upgrade_delay_blocks: u64,
109 pub key_manager: AccountId,
111 pub initial_hashchain: Option<RawH256>,
114}
115
116#[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#[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#[derive(Default, Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
132pub struct SubmitArgs {
133 pub tx_data: Vec<u8>,
135 pub max_gas_price: Option<u128>,
137 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#[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#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
184#[cfg_attr(feature = "impl-serde", derive(Serialize, Deserialize))]
185pub enum TransactionStatus {
186 Succeed(Vec<u8>),
188 Revert(Vec<u8>),
190 OutOfGas,
192 OutOfFund,
194 OutOfOffset,
196 CallTooDeep,
198 StackUnderflow,
200 StackOverflow,
202 InvalidJump,
204 InvalidRange,
206 DesignatedInvalid,
208 CreateCollision,
210 CreateContractLimit,
212 InvalidCode(u8),
214 #[allow(clippy::upper_case_acronyms)]
216 PCUnderflow,
217 CreateEmpty,
219 MaxNonce,
221 UsizeOverflow,
223 Other(crate::Cow<'static, str>),
225 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#[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 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#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone)]
305pub struct FunctionCallArgsV2 {
306 pub contract: Address,
307 pub value: WeiU256,
309 pub input: Vec<u8>,
310}
311
312#[derive(BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Clone)]
314pub struct FunctionCallArgsV1 {
315 pub contract: Address,
316 pub input: Vec<u8>,
317}
318
319#[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#[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#[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#[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#[derive(Debug, Clone, Eq, PartialEq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
382pub struct RelayerKeyManagerArgs {
383 pub key_manager: Option<AccountId>,
384}
385
386#[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#[derive(Debug, Clone, Eq, PartialEq, BorshSerialize, BorshDeserialize)]
396pub struct UpgradeParams {
397 pub code: Vec<u8>,
399 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 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 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 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 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 let bytes = borsh::to_vec(&nep141).unwrap();
597
598 let actual = DeployErc20TokenArgs::deserialize(&bytes).unwrap();
599 assert_eq!(actual, expected);
600
601 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}