diff --git a/Cargo.lock b/Cargo.lock
index 0402d439..b8f170a3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -764,6 +764,7 @@ dependencies = [
"fvm_shared 2.6.0",
"fvm_shared 3.6.0",
"fvm_shared 4.0.0",
+ "integer-encoding",
"lazy_static",
"multihash",
"num",
diff --git a/actors/multisig/src/v12/state.rs b/actors/multisig/src/v12/state.rs
index f5d38a77..4421eaf9 100644
--- a/actors/multisig/src/v12/state.rs
+++ b/actors/multisig/src/v12/state.rs
@@ -5,11 +5,11 @@ use cid::Cid;
use fil_actors_shared::v12::{ActorError, Config, Map2, DEFAULT_HAMT_CONFIG};
use fvm_ipld_blockstore::Blockstore;
use fvm_ipld_encoding::tuple::*;
-use fvm_shared::address::Address;
-use fvm_shared::bigint::BigInt;
-use fvm_shared::bigint::Integer;
-use fvm_shared::clock::ChainEpoch;
-use fvm_shared::econ::TokenAmount;
+use fvm_shared4::address::Address;
+use fvm_shared4::bigint::BigInt;
+use fvm_shared4::bigint::Integer;
+use fvm_shared4::clock::ChainEpoch;
+use fvm_shared4::econ::TokenAmount;
use indexmap::IndexMap;
use num_traits::Zero;
diff --git a/actors/multisig/src/v12/types.rs b/actors/multisig/src/v12/types.rs
index 151dbbeb..c3689902 100644
--- a/actors/multisig/src/v12/types.rs
+++ b/actors/multisig/src/v12/types.rs
@@ -5,11 +5,11 @@ use std::fmt::Display;
use fvm_ipld_encoding::tuple::*;
use fvm_ipld_encoding::{strict_bytes, RawBytes};
-use fvm_shared::address::Address;
-use fvm_shared::clock::ChainEpoch;
-use fvm_shared::econ::TokenAmount;
-use fvm_shared::error::ExitCode;
-use fvm_shared::MethodNum;
+use fvm_shared4::address::Address;
+use fvm_shared4::clock::ChainEpoch;
+use fvm_shared4::econ::TokenAmount;
+use fvm_shared4::error::ExitCode;
+use fvm_shared4::MethodNum;
use serde::{Deserialize, Serialize};
use fil_actors_shared::v12::MapKey;
diff --git a/fil_actor_interface/Cargo.toml b/fil_actor_interface/Cargo.toml
index 4d0fb071..82ed2a9b 100644
--- a/fil_actor_interface/Cargo.toml
+++ b/fil_actor_interface/Cargo.toml
@@ -30,6 +30,7 @@ fvm_ipld_encoding.workspace = true
fvm_shared = { workspace = true }
fvm_shared3 = { workspace = true }
fvm_shared4 = { workspace = true }
+integer-encoding.workspace = true
lazy_static.workspace = true
multihash = { workspace = true, features = ["identity"] }
num.workspace = true
diff --git a/fil_actor_interface/src/builtin/multisig/mod.rs b/fil_actor_interface/src/builtin/multisig/mod.rs
index 6434fee2..f4372787 100644
--- a/fil_actor_interface/src/builtin/multisig/mod.rs
+++ b/fil_actor_interface/src/builtin/multisig/mod.rs
@@ -1,12 +1,15 @@
// Copyright 2019-2023 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT
-use crate::convert::from_token_v3_to_v2;
+use crate::convert::{
+ from_address_v3_to_v2, from_address_v4_to_v2, from_token_v3_to_v2, from_token_v4_to_v2,
+};
use anyhow::Context;
use cid::Cid;
use fvm_ipld_blockstore::Blockstore;
-use fvm_shared::{clock::ChainEpoch, econ::TokenAmount};
-use serde::Serialize;
+use fvm_ipld_encoding::RawBytes;
+use fvm_shared::{address::Address, clock::ChainEpoch, econ::TokenAmount, MethodNum};
+use serde::{Deserialize, Serialize};
use crate::io::get_obj;
@@ -21,7 +24,18 @@ pub enum State {
V9(fil_actor_multisig_state::v9::State),
V10(fil_actor_multisig_state::v10::State),
V11(fil_actor_multisig_state::v11::State),
- V12(fil_actor_multisig_state::v11::State),
+ V12(fil_actor_multisig_state::v12::State),
+}
+
+/// Transaction type used in multisig actor
+#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
+pub struct Transaction {
+ pub id: i64,
+ pub to: Address,
+ pub value: TokenAmount,
+ pub method: MethodNum,
+ pub params: RawBytes,
+ pub approved: Vec
,
}
pub fn is_v8_multisig_cid(cid: &Cid) -> bool {
@@ -84,7 +98,57 @@ impl State {
State::V9(st) => st.amount_locked(height),
State::V10(st) => from_token_v3_to_v2(st.amount_locked(height)),
State::V11(st) => from_token_v3_to_v2(st.amount_locked(height)),
- State::V12(st) => from_token_v3_to_v2(st.amount_locked(height)),
+ State::V12(st) => from_token_v4_to_v2(st.amount_locked(height)),
})
}
+
+ /// Returns pending transactions for the given multisig wallet
+ pub fn get_pending_txn(&self, store: &BS) -> anyhow::Result> {
+ let mut res = Vec::new();
+ match self {
+ State::V8(st) => {
+ let txns = fil_actors_shared::v8::make_map_with_root::<
+ BS,
+ fil_actor_multisig_state::v8::Transaction,
+ >(&st.pending_txs, store)?;
+ crate::parse_pending_transactions!(res, txns);
+ Ok(res)
+ }
+ State::V9(st) => {
+ let txns = fil_actors_shared::v9::make_map_with_root::<
+ BS,
+ fil_actor_multisig_state::v9::Transaction,
+ >(&st.pending_txs, store)?;
+ crate::parse_pending_transactions!(res, txns);
+ Ok(res)
+ }
+ State::V10(st) => {
+ let txns = fil_actors_shared::v10::make_map_with_root::<
+ BS,
+ fil_actor_multisig_state::v10::Transaction,
+ >(&st.pending_txs, store)?;
+ crate::parse_pending_transactions_v3!(res, txns);
+ Ok(res)
+ }
+ State::V11(st) => {
+ let txns = fil_actors_shared::v11::make_map_with_root::<
+ BS,
+ fil_actor_multisig_state::v11::Transaction,
+ >(&st.pending_txs, store)?;
+ crate::parse_pending_transactions_v3!(res, txns);
+ Ok(res)
+ }
+ State::V12(st) => {
+ let txns = fil_actor_multisig_state::v12::PendingTxnMap::load(
+ store,
+ &st.pending_txs,
+ fil_actor_multisig_state::v12::PENDING_TXN_CONFIG,
+ "pending txns",
+ )
+ .expect("Could not load pending transactions");
+ crate::parse_pending_transactions_v4!(res, txns);
+ Ok(res)
+ }
+ }
+ }
}
diff --git a/fil_actor_interface/src/lib.rs b/fil_actor_interface/src/lib.rs
index 3211df19..136b742f 100644
--- a/fil_actor_interface/src/lib.rs
+++ b/fil_actor_interface/src/lib.rs
@@ -4,6 +4,7 @@
mod builtin;
mod convert;
mod io;
+mod macros;
mod r#mod;
pub use self::builtin::*;
diff --git a/fil_actor_interface/src/macros.rs b/fil_actor_interface/src/macros.rs
new file mode 100644
index 00000000..628dc4d9
--- /dev/null
+++ b/fil_actor_interface/src/macros.rs
@@ -0,0 +1,90 @@
+// Copyright 2019-2022 ChainSafe Systems
+// SPDX-License-Identifier: Apache-2.0, MIT
+
+/// This macro iterates over each transaction, decodes the transaction key using variable-length integer encoding,
+/// and constructs a Transaction object with the decoded data.
+///
+/// Parameters:
+/// - `$res`: A mutable reference to a collection where the parsed transactions will be stored.
+/// - `$txns`: A collection of transaction data to be parsed.
+#[macro_export]
+macro_rules! parse_pending_transactions {
+ ($res:ident, $txns:expr) => {
+ $txns.for_each(|tx_key, txn| {
+ match integer_encoding::VarInt::decode_var(&tx_key) {
+ Some((tx_id, _)) => {
+ $res.push(Transaction {
+ id: tx_id,
+ to: txn.to,
+ value: txn.value.clone(),
+ method: txn.method,
+ params: txn.params.clone(),
+ approved: txn.approved.clone(),
+ });
+ }
+ None => anyhow::bail!("Error decoding varint"),
+ }
+ Ok(())
+ })?;
+ };
+}
+
+/// This macro iterates over each transaction, decodes the transaction key, and constructs a Transaction object
+/// with additional processing for address and token formats using `from_address_v3_to_v2` and `from_token_v3_to_v2`.
+///
+/// Parameters:
+/// - `$res`: A mutable reference to a collection where the parsed transactions will be stored.
+/// - `$txns`: A collection of transaction data to be parsed.
+#[macro_export]
+macro_rules! parse_pending_transactions_v3 {
+ ($res:ident, $txns:expr) => {
+ $txns.for_each(|tx_key, txn| {
+ match integer_encoding::VarInt::decode_var(&tx_key) {
+ Some((tx_id, _)) => {
+ $res.push(Transaction {
+ id: tx_id,
+ to: from_address_v3_to_v2(txn.to),
+ value: from_token_v3_to_v2(txn.value.clone()),
+ method: txn.method,
+ params: txn.params.clone(),
+ approved: txn
+ .approved
+ .iter()
+ .map(|&addr| from_address_v3_to_v2(addr))
+ .collect(),
+ });
+ }
+ None => anyhow::bail!("Error decoding varint"),
+ }
+ Ok(())
+ })?;
+ };
+}
+
+/// This macro iterates over each transaction, assumes that transaction id's are directly available and not encoded.
+/// It constructs Transaction objects with transformations for address and token data from version 4 to version 2
+/// using `from_address_v4_to_v2` and `from_token_v4_to_v2`.
+///
+/// Parameters:
+/// - `$res`: A mutable reference to a collection where the parsed transactions will be stored.
+/// - `$txns`: A collection of transaction data to be parsed.
+#[macro_export]
+macro_rules! parse_pending_transactions_v4 {
+ ($res:ident, $txns:expr) => {
+ $txns.for_each(|tx_id, txn| {
+ $res.push(Transaction {
+ id: tx_id.0,
+ to: from_address_v4_to_v2(txn.to),
+ value: from_token_v4_to_v2(txn.value.clone()),
+ method: txn.method,
+ params: txn.params.clone(),
+ approved: txn
+ .approved
+ .iter()
+ .map(|&addr| from_address_v4_to_v2(addr))
+ .collect(),
+ });
+ Ok(())
+ })?;
+ };
+}