iota_graphql_rpc/types/
move_function.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use async_graphql::*;
6use iota_package_resolver::FunctionDef;
7
8use crate::{
9    error::Error,
10    types::{
11        iota_address::IotaAddress,
12        move_module::MoveModule,
13        open_move_type::{MoveAbility, MoveVisibility, OpenMoveType, abilities},
14    },
15};
16
17pub(crate) struct MoveFunction {
18    package: IotaAddress,
19    module: String,
20    name: String,
21    visibility: MoveVisibility,
22    is_entry: bool,
23    type_parameters: Vec<MoveFunctionTypeParameter>,
24    parameters: Vec<OpenMoveType>,
25    return_: Vec<OpenMoveType>,
26    checkpoint_viewed_at: u64,
27}
28
29#[derive(SimpleObject)]
30pub(crate) struct MoveFunctionTypeParameter {
31    constraints: Vec<MoveAbility>,
32}
33
34/// Signature of a function, defined in a Move module.
35#[Object]
36impl MoveFunction {
37    /// The module this function was defined in.
38    async fn module(&self, ctx: &Context<'_>) -> Result<MoveModule> {
39        let Some(module) =
40            MoveModule::query(ctx, self.package, &self.module, self.checkpoint_viewed_at)
41                .await
42                .extend()?
43        else {
44            return Err(Error::Internal(format!(
45                "Failed to load module for function: {}::{}::{}",
46                self.package, self.module, self.name,
47            )))
48            .extend();
49        };
50
51        Ok(module)
52    }
53
54    /// The function's (unqualified) name.
55    async fn name(&self) -> &str {
56        &self.name
57    }
58
59    /// The function's visibility: `public`, `public(friend)`, or `private`.
60    async fn visibility(&self) -> Option<&MoveVisibility> {
61        Some(&self.visibility)
62    }
63
64    /// Whether the function has the `entry` modifier or not.
65    async fn is_entry(&self) -> Option<bool> {
66        Some(self.is_entry)
67    }
68
69    /// Constraints on the function's formal type parameters.  Move bytecode
70    /// does not name type parameters, so when they are referenced (e.g. in
71    /// parameter and return types) they are identified by their index in
72    /// this list.
73    async fn type_parameters(&self) -> Option<&Vec<MoveFunctionTypeParameter>> {
74        Some(&self.type_parameters)
75    }
76
77    /// The function's parameter types.  These types can reference type
78    /// parameters introduce by this function (see `typeParameters`).
79    async fn parameters(&self) -> Option<&Vec<OpenMoveType>> {
80        Some(&self.parameters)
81    }
82
83    /// The function's return types.  There can be multiple because functions in
84    /// Move can return multiple values.  These types can reference type
85    /// parameters introduced by this function (see `typeParameters`).
86    #[graphql(name = "return")]
87    async fn return_(&self) -> Option<&Vec<OpenMoveType>> {
88        Some(&self.return_)
89    }
90}
91
92impl MoveFunction {
93    pub(crate) fn new(
94        package: IotaAddress,
95        module: String,
96        name: String,
97        def: FunctionDef,
98        checkpoint_viewed_at: u64,
99    ) -> Self {
100        let type_parameters = def
101            .type_params
102            .into_iter()
103            .map(|constraints| MoveFunctionTypeParameter {
104                constraints: abilities(constraints),
105            })
106            .collect();
107
108        let parameters = def.parameters.into_iter().map(OpenMoveType::from).collect();
109        let return_ = def.return_.into_iter().map(OpenMoveType::from).collect();
110
111        MoveFunction {
112            package,
113            module,
114            name,
115            visibility: def.visibility.into(),
116            is_entry: def.is_entry,
117            type_parameters,
118            parameters,
119            return_,
120            checkpoint_viewed_at,
121        }
122    }
123
124    pub(crate) async fn query(
125        ctx: &Context<'_>,
126        address: IotaAddress,
127        module: &str,
128        function: &str,
129        checkpoint_viewed_at: u64,
130    ) -> Result<Option<Self>, Error> {
131        let Some(module) = MoveModule::query(ctx, address, module, checkpoint_viewed_at).await?
132        else {
133            return Ok(None);
134        };
135
136        module.function_impl(function.to_string())
137    }
138}