1use std::convert::TryFrom;
2
3use serde::{Deserialize, Serialize};
4
5use fvm_ipld_encoding::RawBytes;
6use fvm_shared::message::Message;
7
8use extras::init::ExecParamsAPI;
9use extras::{
10 message::MessageAPI, miner, multisig, paych, signed_message::ref_fvm::SignedMessage,
11 signed_message::SignedMessageAPI,
12};
13
14use crate::error::SignerError;
15
16#[derive(Deserialize, Serialize)]
17#[serde(untagged)]
18#[allow(clippy::large_enum_variant)]
19pub enum MessageParams {
20 MessageParamsSerialized(String),
21 #[serde(with = "ExecParamsAPI")]
22 ExecParams(fil_actor_init::ExecParams),
23 #[serde(with = "multisig::ConstructorParamsAPI")]
24 MultisigConstructorParams(fil_actor_multisig::ConstructorParams),
25 #[serde(with = "multisig::ProposeParamsAPI")]
26 ProposeParams(fil_actor_multisig::ProposeParams),
27 #[serde(with = "multisig::TxnIDParamsAPI")]
28 TxnIDParams(fil_actor_multisig::TxnIDParams),
29 #[serde(with = "multisig::AddSignerParamsAPI")]
30 AddSignerParams(fil_actor_multisig::AddSignerParams),
31 #[serde(with = "multisig::RemoveSignerParamsAPI")]
32 RemoveSignerParams(fil_actor_multisig::RemoveSignerParams),
33 #[serde(with = "multisig::SwapSignerParamsAPI")]
34 SwapSignerParams(fil_actor_multisig::SwapSignerParams),
35 #[serde(with = "multisig::ChangeNumApprovalsThresholdParamsAPI")]
36 ChangeNumApprovalsThresholdParams(fil_actor_multisig::ChangeNumApprovalsThresholdParams),
37 #[serde(with = "multisig::LockBalanceParamsAPI")]
38 LockBalanceParams(fil_actor_multisig::LockBalanceParams),
39 #[serde(with = "paych::ConstructorParamsAPI")]
40 PaychConstructorParams(fil_actor_paych::ConstructorParams),
41 #[serde(with = "paych::UpdateChannelStateParamsAPI")]
42 UpdateChannelStateParams(fil_actor_paych::UpdateChannelStateParams),
43 #[serde(with = "miner::ChangeOwnerAddressParamsAPI")]
46 ChangeOwnerAddressParamsAPI(fil_actor_miner::ChangeOwnerAddressParams),
47 #[serde(with = "miner::ChangeWorkerAddressParamsAPI")]
48 ChangeWorkerAddressParams(fil_actor_miner::ChangeWorkerAddressParams),
49 #[serde(with = "miner::ChangePeerIDParamsAPI")]
50 ChangePeerIDParams(fil_actor_miner::ChangePeerIDParams),
51 #[serde(with = "miner::WithdrawBalanceParamsAPI")]
66 WithdrawBalanceParams(fil_actor_miner::WithdrawBalanceParams),
67 #[serde(with = "miner::ApplyRewardParamsAPI")]
69 ApplyRewardParams(fil_actor_miner::ApplyRewardParams),
70 }
74
75impl MessageParams {
76 pub fn serialize(self) -> Result<RawBytes, SignerError> {
77 let params_serialized = match self {
78 MessageParams::MessageParamsSerialized(params_string) => {
79 let params_bytes = base64::decode(¶ms_string)
80 .map_err(|err| SignerError::GenericString(err.to_string()))?;
81 RawBytes::from(params_bytes)
82 }
83 MessageParams::ExecParams(params) => RawBytes::serialize(¶ms)
84 .map_err(|err| SignerError::GenericString(err.to_string()))?,
85 MessageParams::MultisigConstructorParams(params) => RawBytes::serialize(¶ms)
86 .map_err(|err| SignerError::GenericString(err.to_string()))?,
87 MessageParams::ProposeParams(params) => RawBytes::serialize(¶ms)
88 .map_err(|err| SignerError::GenericString(err.to_string()))?,
89 MessageParams::TxnIDParams(params) => RawBytes::serialize(¶ms)
90 .map_err(|err| SignerError::GenericString(err.to_string()))?,
91 MessageParams::AddSignerParams(params) => RawBytes::serialize(¶ms)
92 .map_err(|err| SignerError::GenericString(err.to_string()))?,
93 MessageParams::RemoveSignerParams(params) => RawBytes::serialize(¶ms)
94 .map_err(|err| SignerError::GenericString(err.to_string()))?,
95 MessageParams::SwapSignerParams(params) => RawBytes::serialize(¶ms)
96 .map_err(|err| SignerError::GenericString(err.to_string()))?,
97 MessageParams::ChangeNumApprovalsThresholdParams(params) => {
98 RawBytes::serialize(¶ms)
99 .map_err(|err| SignerError::GenericString(err.to_string()))?
100 }
101 MessageParams::LockBalanceParams(params) => RawBytes::serialize(¶ms)
102 .map_err(|err| SignerError::GenericString(err.to_string()))?,
103 MessageParams::PaychConstructorParams(params) => RawBytes::serialize(¶ms)
104 .map_err(|err| SignerError::GenericString(err.to_string()))?,
105 MessageParams::UpdateChannelStateParams(params) => RawBytes::serialize(¶ms)
106 .map_err(|err| SignerError::GenericString(err.to_string()))?,
107 MessageParams::ChangeOwnerAddressParamsAPI(params) => RawBytes::serialize(¶ms)
110 .map_err(|err| SignerError::GenericString(err.to_string()))?,
111 MessageParams::ChangeWorkerAddressParams(params) => RawBytes::serialize(¶ms)
112 .map_err(|err| SignerError::GenericString(err.to_string()))?,
113 MessageParams::ChangePeerIDParams(params) => RawBytes::serialize(¶ms)
114 .map_err(|err| SignerError::GenericString(err.to_string()))?,
115 MessageParams::WithdrawBalanceParams(params) => RawBytes::serialize(¶ms)
118 .map_err(|err| SignerError::GenericString(err.to_string()))?,
119 MessageParams::ApplyRewardParams(params) => RawBytes::serialize(¶ms)
120 .map_err(|err| SignerError::GenericString(err.to_string()))?,
121 };
122
123 Ok(params_serialized)
124 }
125}
126
127#[derive(Deserialize, Serialize, Debug)]
129#[serde(untagged)]
130pub enum MessageTxAPI {
131 #[serde(with = "MessageAPI")]
132 Message(Message),
133 #[serde(with = "SignedMessageAPI")]
134 SignedMessage(SignedMessage),
135}
136
137#[derive(Deserialize, Serialize)]
138#[serde(untagged)]
139pub enum MessageTx {
140 Message(Message),
141 SignedMessage(SignedMessage),
142}
143
144impl From<MessageTx> for MessageTxAPI {
145 fn from(message_tx: MessageTx) -> MessageTxAPI {
146 match message_tx {
147 MessageTx::Message(msg) => MessageTxAPI::Message(msg),
148 MessageTx::SignedMessage(smsg) => MessageTxAPI::SignedMessage(smsg),
149 }
150 }
151}
152
153#[cfg_attr(feature = "with-arbitrary", derive(arbitrary::Arbitrary))]
155#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
156pub struct CreateMultisigMessageAPI {
157 #[serde(alias = "From")]
158 pub from: String,
159 #[serde(alias = "Nonce")]
160 pub nonce: u64,
161 #[serde(alias = "Value")]
162 pub value: String,
163
164 #[serde(rename = "gaslimit")]
165 #[serde(alias = "gasLimit")]
166 #[serde(alias = "gas_limit")]
167 #[serde(alias = "GasLimit")]
168 pub gas_limit: i64,
169
170 #[serde(rename = "gasfeecap")]
171 #[serde(alias = "gasFeeCap")]
172 #[serde(alias = "gas_fee_cap")]
173 #[serde(alias = "GasFeeCap")]
174 pub gas_fee_cap: String,
175
176 #[serde(rename = "gaspremium")]
177 #[serde(alias = "gasPremium")]
178 #[serde(alias = "gas_premium")]
179 #[serde(alias = "GasPremium")]
180 pub gas_premium: String,
181
182 #[serde(alias = "Signers")]
183 #[serde(alias = "signers")]
184 pub signers: Vec<String>,
185
186 #[serde(alias = "Threshold")]
187 #[serde(alias = "threshold")]
188 pub threshold: i64,
189
190 #[serde(alias = "UnlockDuration")]
191 #[serde(alias = "unlock_duration")]
192 pub unlock_duration: i64,
193
194 #[serde(alias = "StartEpoch")]
195 #[serde(alias = "start_epoch")]
196 pub start_epoch: i64,
197}
198
199#[cfg_attr(feature = "with-arbitrary", derive(arbitrary::Arbitrary))]
201#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
202pub struct ProposalMessageParamsAPI {
203 #[serde(alias = "Requester")]
204 pub requester: String,
205
206 #[serde(alias = "To")]
207 pub to: String,
208
209 #[serde(alias = "Value")]
210 pub value: String,
211
212 #[serde(alias = "Method")]
213 pub method: u64,
214
215 #[serde(alias = "Params")]
216 pub params: String,
217}
218
219impl MessageTxAPI {
220 pub fn get_message(&self) -> Message {
221 match self {
222 MessageTxAPI::Message(message) => message.to_owned(),
223 MessageTxAPI::SignedMessage(signed_message) => signed_message.message.to_owned(),
224 }
225 }
226}
227
228pub struct MessageTxNetwork {
231 pub message_tx: MessageTxAPI,
232 pub testnet: bool,
233}
234
235impl TryFrom<MessageTxNetwork> for MessageTxAPI {
236 type Error = SignerError;
237
238 fn try_from(message_tx_network: MessageTxNetwork) -> Result<MessageTxAPI, Self::Error> {
239 match message_tx_network.message_tx {
240 MessageTxAPI::Message(message_tx) => {
241 let to_address: fvm_shared::address::Address = message_tx.to.to_owned();
242
243 let from_address: fvm_shared::address::Address = message_tx.from.to_owned();
244
245 let message_with_network = Message {
246 to: to_address,
247 from: from_address,
248 ..message_tx
249 };
250
251 Ok(MessageTxAPI::Message(message_with_network))
252 }
253 MessageTxAPI::SignedMessage(message_tx) => {
254 let to_address: fvm_shared::address::Address = message_tx.message.to.to_owned();
255
256 let from_address: fvm_shared::address::Address = message_tx.message.from.to_owned();
257
258 let tmp = message_tx.message.clone();
259
260 let message_with_network = Message {
261 to: to_address,
262 from: from_address,
263 ..tmp
264 };
265
266 let signed_message = SignedMessage {
267 message: message_with_network,
268 signature: message_tx.signature,
269 };
270
271 Ok(MessageTxAPI::SignedMessage(signed_message))
272 }
273 }
274 }
275}
276
277#[cfg(test)]
278mod tests {
279 use fvm_ipld_encoding::{from_slice, to_vec};
280 use hex::{decode, encode};
281
282 use crate::api::MessageTxAPI;
283
284 const EXAMPLE_UNSIGNED_MESSAGE: &str = r#"
285 {
286 "To": "f17uoq6tp427uzv7fztkbsnn64iwotfrristwpryy",
287 "From": "f1xcbgdhkgkwht3hrrnui3jdopeejsoas2rujnkdi",
288 "Nonce": 1,
289 "Value": "100000",
290 "GasFeeCap": "1",
291 "GasPremium": "1",
292 "GasLimit": 25000,
293 "Method": 0,
294 "Params": ""
295 }"#;
296
297 const EXAMPLE_CBOR_DATA: &str =
298 "8a005501fd1d0f4dfcd7e99afcb99a8326b7dc459d32c6285501b882619d46558f3d9e316d11b48dcf211327025a0144000186a01961a84200014200010040";
299
300 #[test]
303 fn json_to_cbor() {
304 let message_api: MessageTxAPI =
305 serde_json::from_str(EXAMPLE_UNSIGNED_MESSAGE).expect("FIXME");
306
307 let message = match message_api {
308 MessageTxAPI::Message(msg) => msg,
309 _ => panic!("Shouldn't be SignedMessage"),
310 };
311
312 let message_cbor: Vec<u8> = to_vec(&message).expect("Cbor serialization failed");
313 let message_cbor_hex = encode(message_cbor);
314
315 assert_eq!(EXAMPLE_CBOR_DATA, message_cbor_hex)
316 }
317
318 #[test]
319 fn cbor_to_json() {
320 let cbor_buffer = decode(EXAMPLE_CBOR_DATA).expect("FIXME");
321
322 let message =
323 MessageTxAPI::Message(from_slice(&cbor_buffer).expect("could not decode cbor"));
324
325 let message_json =
326 serde_json::to_string_pretty(&message).expect("could not serialize as JSON");
327
328 const EXPECTED_MESSAGE_JSON: &str = r#"{
329 "From": "f1xcbgdhkgkwht3hrrnui3jdopeejsoas2rujnkdi",
330 "To": "f17uoq6tp427uzv7fztkbsnn64iwotfrristwpryy",
331 "Nonce": 1,
332 "Value": "100000",
333 "Method": 0,
334 "Params": "",
335 "GasLimit": 25000,
336 "GasFeeCap": "1",
337 "GasPremium": "1"
338}"#;
339
340 assert_eq!(EXPECTED_MESSAGE_JSON, message_json)
341 }
342
343 #[test]
344 fn conversion_signed_messages() {
345 const EXAMPLE_SIGNED_MESSAGE: &str = r#"{
346 "Message": {
347 "From": "f1iuj7atowet37tsmeehwxfvyjv2pqhsnyvb6niay",
348 "To": "f14ole2akjiw5qizembmw6r2e6yvj5ygmxgczervy",
349 "Nonce": 37,
350 "Value": "1000000000000000",
351 "Method": 0,
352 "Params": "",
353 "GasLimit": 2101318,
354 "GasFeeCap": "1890700000",
355 "GasPremium": "150000"
356 },
357 "Signature": {
358 "Type": 1,
359 "Data": "f3w5IcXFvWpWEAFp9LOAzixIsPjkgVaFx5XwynXx2sgZJ57yLIHLJi8CepHwoYeaWfZTRRUucHPARhi6iE2qqgA="
360 }
361}"#;
362
363 let message_api: MessageTxAPI =
364 serde_json::from_str(EXAMPLE_SIGNED_MESSAGE).expect("FIXME");
365
366 let signed_message_json =
367 serde_json::to_string_pretty(&message_api).expect("could not serialize as JSON");
368
369 assert_eq!(EXAMPLE_SIGNED_MESSAGE, signed_message_json);
370 }
371}