forest/rpc/methods/
msig.rs1use crate::rpc::error::ServerError;
5use crate::rpc::types::ApiTipsetKey;
6use crate::rpc::types::*;
7use crate::rpc::{ApiPaths, Ctx, Permission, RpcMethod};
8use crate::shim::actors::MultisigActorStateLoad as _;
9use crate::shim::actors::multisig;
10use crate::shim::{address::Address, econ::TokenAmount};
11use enumflags2::BitFlags;
12use fvm_ipld_blockstore::Blockstore;
13use num_bigint::BigInt;
14
15pub enum MsigGetAvailableBalance {}
16
17impl RpcMethod<2> for MsigGetAvailableBalance {
18 const NAME: &'static str = "Filecoin.MsigGetAvailableBalance";
19 const PARAM_NAMES: [&'static str; 2] = ["address", "tipset_key"];
20 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
21 const PERMISSION: Permission = Permission::Read;
22
23 type Params = (Address, ApiTipsetKey);
24 type Ok = TokenAmount;
25
26 async fn handle(
27 ctx: Ctx<impl Blockstore>,
28 (address, ApiTipsetKey(tsk)): Self::Params,
29 _: &http::Extensions,
30 ) -> Result<Self::Ok, ServerError> {
31 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
32 let height = ts.epoch();
33 let actor = ctx
34 .state_manager
35 .get_required_actor(&address, *ts.parent_state())?;
36 let actor_balance = TokenAmount::from(&actor.balance);
37 let ms = multisig::State::load(ctx.store(), actor.code, actor.state)?;
38 let locked_balance = ms.locked_balance(height)?;
39 let avail_balance = &actor_balance - locked_balance;
40 Ok(avail_balance)
41 }
42}
43
44pub enum MsigGetPending {}
45
46impl RpcMethod<2> for MsigGetPending {
47 const NAME: &'static str = "Filecoin.MsigGetPending";
48 const PARAM_NAMES: [&'static str; 2] = ["address", "tipset_key"];
49 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
50 const PERMISSION: Permission = Permission::Read;
51
52 type Params = (Address, ApiTipsetKey);
53 type Ok = Vec<Transaction>;
54
55 async fn handle(
56 ctx: Ctx<impl Blockstore>,
57 (address, ApiTipsetKey(tsk)): Self::Params,
58 _: &http::Extensions,
59 ) -> Result<Self::Ok, ServerError> {
60 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
61 let ms: multisig::State = ctx
62 .state_manager
63 .get_actor_state_from_address(&ts, &address)?;
64 let txns = ms
65 .get_pending_txn(ctx.store())?
66 .into_iter()
67 .map(|txn| Transaction {
68 id: txn.id,
69 to: txn.to,
70 value: txn.value,
71 method: txn.method,
72 params: txn.params,
73 approved: txn.approved,
74 })
75 .collect();
76 Ok(txns)
77 }
78}
79
80pub enum MsigGetVested {}
81impl RpcMethod<3> for MsigGetVested {
82 const NAME: &'static str = "Filecoin.MsigGetVested";
83 const PARAM_NAMES: [&'static str; 3] = ["address", "start_tsk", "end_tsk"];
84 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
85 const PERMISSION: Permission = Permission::Read;
86
87 type Params = (Address, ApiTipsetKey, ApiTipsetKey);
88 type Ok = BigInt;
89
90 async fn handle(
91 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
92 (addr, ApiTipsetKey(start_tsk), ApiTipsetKey(end_tsk)): Self::Params,
93 _: &http::Extensions,
94 ) -> Result<Self::Ok, ServerError> {
95 let start_ts = ctx
96 .chain_store()
97 .load_required_tipset_or_heaviest(&start_tsk)?;
98 let end_ts = ctx
99 .chain_store()
100 .load_required_tipset_or_heaviest(&end_tsk)?;
101
102 match start_ts.epoch().cmp(&end_ts.epoch()) {
103 std::cmp::Ordering::Greater => Err(ServerError::internal_error(
104 "start tipset is after end tipset",
105 None,
106 )),
107 std::cmp::Ordering::Equal => Ok(BigInt::from(0)),
108 std::cmp::Ordering::Less => {
109 let ms: multisig::State = ctx
110 .state_manager
111 .get_actor_state_from_address(&end_ts, &addr)?;
112 let start_lb = ms.locked_balance(start_ts.epoch())?;
113 let end_lb = ms.locked_balance(end_ts.epoch())?;
114 Ok(start_lb.atto() - end_lb.atto())
115 }
116 }
117 }
118}
119
120pub enum MsigGetVestingSchedule {}
121impl RpcMethod<2> for MsigGetVestingSchedule {
122 const NAME: &'static str = "Filecoin.MsigGetVestingSchedule";
123 const PARAM_NAMES: [&'static str; 2] = ["address", "tsk"];
124 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
125 const PERMISSION: Permission = Permission::Read;
126
127 type Params = (Address, ApiTipsetKey);
128 type Ok = MsigVesting;
129
130 async fn handle(
131 ctx: Ctx<impl Blockstore + Send + Sync + 'static>,
132 (addr, ApiTipsetKey(tsk)): Self::Params,
133 _: &http::Extensions,
134 ) -> Result<Self::Ok, ServerError> {
135 let ts = ctx.chain_store().load_required_tipset_or_heaviest(&tsk)?;
136 let ms: multisig::State = ctx.state_manager.get_actor_state_from_address(&ts, &addr)?;
137 Ok(ms.get_vesting_schedule()?)
138 }
139}