1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Copyright (c) Mysten Labs, Inc.
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use move_binary_format::{CompiledModule, file_format::SignatureToken};
use move_bytecode_utils::resolve_struct;
use move_core_types::{
    account_address::AccountAddress,
    ident_str,
    identifier::IdentStr,
    language_storage::{StructTag, TypeTag},
};
use serde::{Deserialize, Serialize};

use crate::{
    IOTA_FRAMEWORK_ADDRESS,
    base_types::{ObjectID, SequenceNumber},
    id::ID,
};

const TRANSFER_MODULE_NAME: &IdentStr = ident_str!("transfer");
const RECEIVING_STRUCT_NAME: &IdentStr = ident_str!("Receiving");

pub const RESOLVED_RECEIVING_STRUCT: (&AccountAddress, &IdentStr, &IdentStr) = (
    &IOTA_FRAMEWORK_ADDRESS,
    TRANSFER_MODULE_NAME,
    RECEIVING_STRUCT_NAME,
);

/// Rust version of the Move iota::transfer::Receiving type
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Receiving {
    pub id: ID,
    pub version: SequenceNumber,
}

impl Receiving {
    pub fn new(id: ObjectID, version: SequenceNumber) -> Self {
        Self {
            id: ID::new(id),
            version,
        }
    }

    pub fn to_bcs_bytes(&self) -> Vec<u8> {
        bcs::to_bytes(self).expect("Value representation is owned and should always serialize")
    }

    pub fn struct_tag() -> StructTag {
        StructTag {
            address: IOTA_FRAMEWORK_ADDRESS,
            module: TRANSFER_MODULE_NAME.to_owned(),
            name: RECEIVING_STRUCT_NAME.to_owned(),
            // TODO: this should really include the type parameters eventually when we add type
            // parameters to the other polymorphic types like this.
            type_params: vec![],
        }
    }

    pub fn type_tag() -> TypeTag {
        TypeTag::Struct(Box::new(Self::struct_tag()))
    }

    pub fn is_receiving(view: &CompiledModule, s: &SignatureToken) -> bool {
        use SignatureToken as S;
        match s {
            S::MutableReference(inner) | S::Reference(inner) => Self::is_receiving(view, inner),
            S::DatatypeInstantiation(inst) => {
                let (idx, type_args) = &**inst;
                let struct_tag = resolve_struct(view, *idx);
                struct_tag == RESOLVED_RECEIVING_STRUCT && type_args.len() == 1
            }
            _ => false,
        }
    }
}