provwasm_stdv1/
msg.rs

1use cosmwasm_std::{
2    coin, to_binary, Addr, Binary, Coin, CosmosMsg, CustomMsg, StdError, StdResult,
3};
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7use crate::common::{validate_address, validate_string};
8use crate::types::{AttributeValueType, MarkerAccess, MarkerType, NameBinding, ProvenanceRoute};
9use crate::Scope;
10
11// The data format version to pass into provenance for message encoding
12static MSG_DATAFMT_VERSION: &str = "2.0.0";
13
14/// Represents a request to encode custom provenance messages.
15#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
16#[serde(rename_all = "snake_case")]
17pub struct ProvenanceMsg {
18    pub route: ProvenanceRoute,      // The module router key
19    pub params: ProvenanceMsgParams, // The module-specific encoder params
20    pub version: String,             // The data format version
21}
22
23impl CustomMsg for ProvenanceMsg {}
24
25/// Input params for custom provenance message encoders.
26#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
27pub enum ProvenanceMsgParams {
28    Name(NameMsgParams),
29    Attribute(AttributeMsgParams),
30    Marker(MarkerMsgParams),
31    Metadata(MetadataMsgParams),
32    MsgFees(MsgFeesMsgParams),
33}
34
35/// Input params for creating name module messages.
36#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
37#[serde(rename_all = "snake_case")]
38pub enum NameMsgParams {
39    BindName {
40        name: String,
41        address: Addr,
42        restrict: bool,
43    },
44    DeleteName {
45        name: String,
46    },
47}
48
49// Create a custom cosmos message using name module params.
50fn create_name_msg(params: NameMsgParams) -> CosmosMsg<ProvenanceMsg> {
51    CosmosMsg::Custom(ProvenanceMsg {
52        route: ProvenanceRoute::Name,
53        params: ProvenanceMsgParams::Name(params),
54        version: String::from(MSG_DATAFMT_VERSION),
55    })
56}
57
58/// Create a message that will bind a name to an address.
59///
60/// ### Example
61///
62/// ```rust
63/// // Imports required
64/// use cosmwasm_std::{Addr, Response, StdResult};
65/// use provwasm_std::{bind_name, NameBinding, ProvenanceMsg};
66///
67/// // Bind a name to an address.
68/// fn exec_bind_name(
69///     name: String,
70///     address: Addr,
71/// ) -> StdResult<Response<ProvenanceMsg>> {
72///    let msg = bind_name(&name, address, NameBinding::Restricted)?;
73///    let mut res = Response::new().add_message(msg);
74///    Ok(res)
75/// }
76/// ```
77pub fn bind_name<S: Into<String>, H: Into<Addr>>(
78    name: S,
79    address: H,
80    binding: NameBinding,
81) -> StdResult<CosmosMsg<ProvenanceMsg>> {
82    Ok(create_name_msg(NameMsgParams::BindName {
83        name: validate_string(name, "name")?,
84        address: validate_address(address)?,
85        restrict: matches!(binding, NameBinding::Restricted),
86    }))
87}
88
89/// Create a message that will un-bind a name from an address.
90///
91/// ### Example
92///
93/// ```rust
94/// // Imports required
95/// use cosmwasm_std::{Response, StdResult};
96/// use provwasm_std::{unbind_name, ProvenanceMsg};
97///
98/// // Unbind a name
99/// fn exec_unbind_name(name: String) -> StdResult<Response<ProvenanceMsg>> {
100///     let msg = unbind_name(&name)?;
101///     let mut res = Response::new().add_message(msg);
102///     Ok(res)
103/// }
104/// ```
105pub fn unbind_name<S: Into<String>>(name: S) -> StdResult<CosmosMsg<ProvenanceMsg>> {
106    Ok(create_name_msg(NameMsgParams::DeleteName {
107        name: validate_string(name, "name")?,
108    }))
109}
110
111/// Input params for creating attribute module messages.
112#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
113#[serde(rename_all = "snake_case")]
114pub enum AttributeMsgParams {
115    AddAttribute {
116        address: Addr,
117        name: String,
118        value: Binary,
119        value_type: AttributeValueType,
120    },
121    DeleteAttribute {
122        address: Addr,
123        name: String,
124    },
125    DeleteDistinctAttribute {
126        address: Addr,
127        name: String,
128        value: Binary,
129    },
130    UpdateAttribute {
131        address: Addr,
132        name: String,
133        original_value: Binary,
134        original_value_type: AttributeValueType,
135        update_value: Binary,
136        update_value_type: AttributeValueType,
137    },
138}
139
140// Create a custom cosmos message using attribute module params.
141fn create_attribute_msg(params: AttributeMsgParams) -> CosmosMsg<ProvenanceMsg> {
142    CosmosMsg::Custom(ProvenanceMsg {
143        route: ProvenanceRoute::Attribute,
144        params: ProvenanceMsgParams::Attribute(params),
145        version: String::from(MSG_DATAFMT_VERSION),
146    })
147}
148
149/// Create a message that will add an attribute (a typed key-value pair) to an account.
150///
151/// ### Example
152///
153/// ```rust
154/// // Imports required
155/// use cosmwasm_std::{Binary, Env, Addr, Response, StdResult};
156/// use provwasm_std::{add_attribute, AttributeValueType, ProvenanceMsg};
157///
158/// // Add a greeting attribute to an account.
159/// // NOTE: The name below must resolve to the contract address.
160/// fn exec_add_greeting(
161///     env: Env,
162///     address: Addr,
163///     text: String,
164/// ) -> StdResult<Response<ProvenanceMsg>> {
165///     let attr_name = String::from("greeting.my-contract.sc.pb");
166///     let greeting = String::from("hello");
167///     let msg = add_attribute(
168///         address,
169///         &attr_name,
170///         Binary::from(greeting.as_bytes()),
171///         AttributeValueType::String,
172///     )?;
173///     let mut res = Response::new().add_message(msg);
174///     Ok(res)
175/// }
176/// ```
177pub fn add_attribute<H: Into<Addr>, S: Into<String>, B: Into<Binary>>(
178    address: H,
179    name: S,
180    value: B,
181    value_type: AttributeValueType,
182) -> StdResult<CosmosMsg<ProvenanceMsg>> {
183    if value_type == AttributeValueType::Unspecified {
184        return Err(StdError::generic_err(
185            "cannot add attribute with unspecified value type",
186        ));
187    }
188    Ok(create_attribute_msg(AttributeMsgParams::AddAttribute {
189        address: validate_address(address)?,
190        name: validate_string(name, "name")?,
191        value: value.into(),
192        value_type,
193    }))
194}
195
196/// Create a message that will add a JSON attribute to an account. Serializable types can be passed
197/// into this function, but it's up to the user to handle StdResult error case.
198///
199/// ### Example
200///
201/// ```rust
202/// // Imports required
203/// use cosmwasm_std::{Env, Addr, Response, StdResult};
204/// use provwasm_std::{add_json_attribute, ProvenanceMsg};
205/// use schemars::JsonSchema;
206/// use serde::{Deserialize, Serialize};
207///
208/// // Add a label attribute. NOTE: The name below must resolve to the contract address.
209/// fn exec_add_label(
210///     env: Env,
211///     address: Addr,
212///     text: String,
213/// ) -> StdResult<Response<ProvenanceMsg>> {
214///     let attr_name = String::from("label.my-contract.sc.pb");
215///     let timestamp = env.block.time.nanos();
216///     let label = Label { text, timestamp };
217///     let msg = add_json_attribute(address, &attr_name, &label)?;
218///     let mut res = Response::new().add_message(msg);
219///     Ok(res)
220/// }
221///
222/// // Text with a timestamp.
223/// #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
224/// #[serde(rename_all = "snake_case")]
225/// pub struct Label {
226///     pub text: String,
227///     pub timestamp: u64,
228/// }
229///
230/// ```
231pub fn add_json_attribute<H: Into<Addr>, S: Into<String>, T: Serialize + ?Sized>(
232    address: H,
233    name: S,
234    data: &T,
235) -> StdResult<CosmosMsg<ProvenanceMsg>> {
236    // Serialize the value, bailing on error
237    let value = to_binary(data)?;
238    // Create and return json typed message
239    add_attribute(address, name, value, AttributeValueType::Json)
240}
241
242/// Create a message that will remove all attributes with the given name from an account.
243///
244/// ### Example
245///
246/// ```rust
247/// // Imports required
248/// use cosmwasm_std::{Addr, Response, StdResult};
249/// use provwasm_std::{delete_attributes, ProvenanceMsg};
250///
251/// // Delete all label attributes. NOTE: The name below must resolve to the contract address.
252/// fn exec_delete_labels(
253///     address: Addr,
254/// ) -> StdResult<Response<ProvenanceMsg>> {
255///     let attr_name = String::from("label.my-contract.sc.pb");
256///     let msg = delete_attributes(address, &attr_name)?;
257///     let mut res = Response::new().add_message(msg);
258///     Ok(res)
259/// }
260/// ```
261pub fn delete_attributes<H: Into<Addr>, S: Into<String>>(
262    address: H,
263    name: S,
264) -> StdResult<CosmosMsg<ProvenanceMsg>> {
265    Ok(create_attribute_msg(AttributeMsgParams::DeleteAttribute {
266        address: validate_address(address)?,
267        name: validate_string(name, "name")?,
268    }))
269}
270
271/// Create a message that will delete a distinct attribute with the given name and value from an account.
272///
273/// ### Example
274///
275/// ```rust
276/// // Imports required
277/// use cosmwasm_std::{Addr, Response, StdResult, to_binary};
278/// use provwasm_std::{delete_distinct_attribute, ProvenanceMsg};
279///
280/// // Delete the distinct label attribute. NOTE: The name below must resolve to the contract address.
281/// fn try_delete_distinct_label(
282///     address: Addr,
283/// ) -> StdResult<Response<ProvenanceMsg>> {
284///     let attr_name = String::from("label.my-contract.sc.pb");
285///     let attr_value = String::from("hello");
286///     let msg = delete_distinct_attribute(address, &attr_name, to_binary(&attr_value)?)?;
287///     let mut res = Response::new().add_message(msg);
288///     Ok(res)
289/// }
290/// ```
291pub fn delete_distinct_attribute<H: Into<Addr>, S: Into<String>, B: Into<Binary>>(
292    address: H,
293    name: S,
294    value: B,
295) -> StdResult<CosmosMsg<ProvenanceMsg>> {
296    Ok(create_attribute_msg(
297        AttributeMsgParams::DeleteDistinctAttribute {
298            address: validate_address(address)?,
299            name: validate_string(name, "name")?,
300            value: value.into(),
301        },
302    ))
303}
304
305/// Create a message that will update an attribute (a typed key-value pair) on an account.
306///
307/// ### Example
308///
309/// ```rust
310/// // Imports required
311/// use cosmwasm_std::{Binary, Env, Addr, Response, StdResult};
312/// use provwasm_std::{update_attribute, AttributeValueType, ProvenanceMsg};
313///
314/// // Update an attribute on an account.
315/// // NOTE: The name below must resolve to the contract address.
316/// fn try_update_attribute(
317///     env: Env,
318///     address: Addr,
319///     text: String,
320/// ) -> StdResult<Response<ProvenanceMsg>> {
321///     let attr_name = String::from("attribute.my-contract.sc.pb");
322///     let original_attribute_value = String::from("hello");
323///     let updated_attribute_value = String::from("goodbye");
324///     let msg = update_attribute(
325///         address,
326///         &attr_name,
327///         Binary::from(original_attribute_value.as_bytes()),
328///         AttributeValueType::String,
329///         Binary::from(original_attribute_value.as_bytes()),
330///         AttributeValueType::String,
331///     )?;
332///     let mut res = Response::new().add_message(msg);
333///     Ok(res)
334/// }
335/// ```
336pub fn update_attribute<H: Into<Addr>, S: Into<String>, B: Into<Binary>>(
337    address: H,
338    name: S,
339    original_value: B,
340    original_value_type: AttributeValueType,
341    update_value: B,
342    update_value_type: AttributeValueType,
343) -> StdResult<CosmosMsg<ProvenanceMsg>> {
344    if original_value_type == AttributeValueType::Unspecified {
345        return Err(StdError::generic_err(
346            "cannot update attribute with unspecified original value type",
347        ));
348    }
349    if update_value_type == AttributeValueType::Unspecified {
350        return Err(StdError::generic_err(
351            "cannot update attribute with unspecified update value type",
352        ));
353    }
354    Ok(create_attribute_msg(AttributeMsgParams::UpdateAttribute {
355        address: validate_address(address)?,
356        name: validate_string(name, "name")?,
357        original_value: original_value.into(),
358        original_value_type,
359        update_value: update_value.into(),
360        update_value_type,
361    }))
362}
363
364/// Input params for creating marker module messages.
365#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
366#[serde(rename_all = "snake_case")]
367pub enum MarkerMsgParams {
368    CreateMarker {
369        coin: Coin,
370        marker_type: MarkerType,
371    },
372    GrantMarkerAccess {
373        denom: String,
374        address: Addr,
375        permissions: Vec<MarkerAccess>,
376    },
377    RevokeMarkerAccess {
378        denom: String,
379        address: Addr,
380    },
381    FinalizeMarker {
382        denom: String,
383    },
384    ActivateMarker {
385        denom: String,
386    },
387    CancelMarker {
388        denom: String,
389    },
390    DestroyMarker {
391        denom: String,
392    },
393    MintMarkerSupply {
394        coin: Coin,
395    },
396    BurnMarkerSupply {
397        coin: Coin,
398    },
399    WithdrawCoins {
400        marker_denom: String,
401        coin: Coin,
402        recipient: Addr,
403    },
404    TransferMarkerCoins {
405        coin: Coin,
406        to: Addr,
407        from: Addr,
408    },
409}
410
411// Create a custom cosmos message using marker module params.
412fn create_marker_msg(params: MarkerMsgParams) -> CosmosMsg<ProvenanceMsg> {
413    CosmosMsg::Custom(ProvenanceMsg {
414        route: ProvenanceRoute::Marker,
415        params: ProvenanceMsgParams::Marker(params),
416        version: String::from(MSG_DATAFMT_VERSION),
417    })
418}
419
420/// Create a message that will propose a new marker with a given type.
421///
422/// ### Example
423///
424/// ```rust
425/// // Imports required
426/// use cosmwasm_std::{Response, StdResult};
427/// use provwasm_std::{create_marker, MarkerType, ProvenanceMsg};
428///
429/// // Create and dispatch a message that will propose a new unrestricted marker.
430/// fn try_create_marker(
431///     amount: u128,
432///     denom: String,
433/// ) -> StdResult<Response<ProvenanceMsg>> {
434///     let msg = create_marker(amount, &denom, MarkerType::Coin)?;
435///     let mut res = Response::new().add_message(msg);
436///     Ok(res)
437/// }
438/// ```
439pub fn create_marker<S: Into<String>>(
440    amount: u128,
441    denom: S,
442    marker_type: MarkerType,
443) -> StdResult<CosmosMsg<ProvenanceMsg>> {
444    let coin = coin(amount, validate_string(denom, "denom")?);
445    Ok(create_marker_msg(MarkerMsgParams::CreateMarker {
446        coin,
447        marker_type,
448    }))
449}
450
451/// Create a message that will grant permissions on a marker.
452///
453/// ### Example
454///
455/// ```rust
456/// // Imports required
457/// use cosmwasm_std::{Addr, Response, StdResult};
458/// use provwasm_std::{grant_marker_access, MarkerAccess, ProvenanceMsg};
459///
460/// // Create and dispatch a message that will grant specific permissions to a marker for an address.
461/// fn try_grant_marker_access(
462///     denom: String,
463///     address: Addr,
464/// ) -> StdResult<Response<ProvenanceMsg>> {
465///     let permissions = vec![MarkerAccess::Burn, MarkerAccess::Mint];
466///     let msg = grant_marker_access(&denom, address, permissions)?;
467///     let mut res = Response::new().add_message(msg);
468///     Ok(res)
469/// }
470/// ```
471pub fn grant_marker_access<S: Into<String>, H: Into<Addr>>(
472    denom: S,
473    address: H,
474    permissions: Vec<MarkerAccess>,
475) -> StdResult<CosmosMsg<ProvenanceMsg>> {
476    Ok(create_marker_msg(MarkerMsgParams::GrantMarkerAccess {
477        denom: validate_string(denom, "denom")?,
478        address: validate_address(address)?,
479        permissions,
480    }))
481}
482
483/// Create a message that will revoke marker permissions.
484///
485/// ### Example
486///
487/// ```rust
488/// // Imports required
489/// use cosmwasm_std::{Addr, Response, StdResult};
490/// use provwasm_std::{revoke_marker_access, ProvenanceMsg};
491///
492/// // Create and dispatch a message that will revoke all permissions from a marker for an address.
493/// fn try_revoke_marker_access(
494///     denom: String,
495///     address: Addr,
496/// ) -> StdResult<Response<ProvenanceMsg>> {
497///     let msg = revoke_marker_access(&denom, address)?;
498///     let mut res = Response::new().add_message(msg);
499///     Ok(res)
500/// }
501/// ```
502pub fn revoke_marker_access<S: Into<String>, H: Into<Addr>>(
503    denom: S,
504    address: H,
505) -> StdResult<CosmosMsg<ProvenanceMsg>> {
506    Ok(create_marker_msg(MarkerMsgParams::RevokeMarkerAccess {
507        denom: validate_string(denom, "denom")?,
508        address: validate_address(address)?,
509    }))
510}
511
512/// Create a message that will finalize a proposed marker.
513///
514/// ### Example
515///
516/// ```rust
517/// // Imports required
518/// use cosmwasm_std::{Response, StdResult};
519/// use provwasm_std::{finalize_marker, ProvenanceMsg};
520///
521/// // Create and dispatch a message that will finalize a proposed marker.
522/// fn try_finalize_marker(denom: String) -> StdResult<Response<ProvenanceMsg>> {
523///     let msg = finalize_marker(&denom)?;
524///     let mut res = Response::new().add_message(msg);
525///     Ok(res)
526/// }
527/// ```
528pub fn finalize_marker<S: Into<String>>(denom: S) -> StdResult<CosmosMsg<ProvenanceMsg>> {
529    Ok(create_marker_msg(MarkerMsgParams::FinalizeMarker {
530        denom: validate_string(denom, "denom")?,
531    }))
532}
533
534/// Create a message that will activate a finalized marker.
535///
536/// ### Example
537///
538/// ```rust
539/// // Imports required
540/// use cosmwasm_std::{Response, StdResult};
541/// use provwasm_std::{activate_marker, ProvenanceMsg};
542///
543/// // Create and dispatch a message that will activate a finalized marker.
544/// fn try_activate_marker(denom: String) -> StdResult<Response<ProvenanceMsg>> {
545///     let msg = activate_marker(&denom)?;
546///     let mut res = Response::new().add_message(msg);
547///     Ok(res)
548/// }
549/// ```
550pub fn activate_marker<S: Into<String>>(denom: S) -> StdResult<CosmosMsg<ProvenanceMsg>> {
551    Ok(create_marker_msg(MarkerMsgParams::ActivateMarker {
552        denom: validate_string(denom, "denom")?,
553    }))
554}
555
556/// Create a message that will cancel a marker.
557///
558/// ### Example
559///
560/// ```rust
561/// // Imports required
562/// use cosmwasm_std::{Response, StdResult};
563/// use provwasm_std::{cancel_marker, ProvenanceMsg};
564///
565/// // Create and dispatch a message that will cancel a marker.
566/// fn try_cancel_marker(denom: String) -> StdResult<Response<ProvenanceMsg>> {
567///     let msg = cancel_marker(&denom)?;
568///     let mut res = Response::new().add_message(msg);
569///     Ok(res)
570/// }
571/// ```
572pub fn cancel_marker<S: Into<String>>(denom: S) -> StdResult<CosmosMsg<ProvenanceMsg>> {
573    Ok(create_marker_msg(MarkerMsgParams::CancelMarker {
574        denom: validate_string(denom, "denom")?,
575    }))
576}
577
578/// Create a message that will destroy a marker.
579///
580/// ### Example
581///
582/// ```rust
583/// // Imports required
584/// use cosmwasm_std::{Response, StdResult};
585/// use provwasm_std::{destroy_marker, ProvenanceMsg};
586///
587/// // Create and dispatch a message that will destroy a marker.
588/// fn try_destroy_marker(denom: String) -> StdResult<Response<ProvenanceMsg>> {
589///     let msg = destroy_marker(&denom)?;
590///     let mut res = Response::new().add_message(msg);
591///     Ok(res)
592/// }
593/// ```
594pub fn destroy_marker<S: Into<String>>(denom: S) -> StdResult<CosmosMsg<ProvenanceMsg>> {
595    Ok(create_marker_msg(MarkerMsgParams::DestroyMarker {
596        denom: validate_string(denom, "denom")?,
597    }))
598}
599
600/// Create a message that will mint marker coins.
601///
602/// ### Example
603///
604/// ```rust
605/// // Imports required
606/// use cosmwasm_std::{Response, StdResult};
607/// use provwasm_std::{mint_marker_supply, ProvenanceMsg};
608///
609/// // Create and dispatch a message that will mint marker supply.
610/// fn try_mint_marker(amount: u128, denom: String) -> StdResult<Response<ProvenanceMsg>> {
611///     let msg = mint_marker_supply(amount, &denom)?;
612///     let mut res = Response::new().add_message(msg);
613///     Ok(res)
614/// }
615/// ```
616pub fn mint_marker_supply<S: Into<String>>(
617    amount: u128,
618    denom: S,
619) -> StdResult<CosmosMsg<ProvenanceMsg>> {
620    if amount == 0 {
621        return Err(StdError::generic_err("mint amount must be > 0"));
622    }
623    let coin = coin(amount, validate_string(denom, "denom")?);
624    Ok(create_marker_msg(MarkerMsgParams::MintMarkerSupply {
625        coin,
626    }))
627}
628
629/// Create a message that will burn marker coins.
630///
631/// ### Example
632///
633/// ```rust
634/// // Imports required
635/// use cosmwasm_std::{Response, StdResult};
636/// use provwasm_std::{burn_marker_supply, ProvenanceMsg};
637///
638/// // Create and dispatch a message that will burn marker supply.
639/// fn try_burn_marker(amount: u128, denom: String) -> StdResult<Response<ProvenanceMsg>> {
640///     let msg = burn_marker_supply(amount, &denom)?;
641///     let mut res = Response::new().add_message(msg);
642///     Ok(res)
643/// }
644/// ```
645pub fn burn_marker_supply<S: Into<String>>(
646    amount: u128,
647    denom: S,
648) -> StdResult<CosmosMsg<ProvenanceMsg>> {
649    if amount == 0 {
650        return Err(StdError::generic_err("burn amount must be > 0"));
651    }
652    let coin = coin(amount, validate_string(denom, "denom")?);
653    Ok(create_marker_msg(MarkerMsgParams::BurnMarkerSupply {
654        coin,
655    }))
656}
657
658/// Create a message that will withdraw coins from a marker account to a recipient account.
659///
660/// ### Example
661///
662/// ```rust
663/// // Imports required
664/// use cosmwasm_std::{Addr, Response, StdResult};
665/// use provwasm_std::{withdraw_coins, ProvenanceMsg};
666///
667/// // Create and dispatch a message that will withdraw coins from a marker.
668/// fn try_withdraw_coins(
669///     marker_denom: String,
670///     amount: u128,
671///     denom: String,
672///     recipient: Addr,
673/// ) -> StdResult<Response<ProvenanceMsg>> {
674///     let msg = withdraw_coins(&marker_denom, amount, &denom, recipient)?;
675///     let mut res = Response::new().add_message(msg);
676///     Ok(res)
677/// }
678/// ```
679pub fn withdraw_coins<S: Into<String>, H: Into<Addr>>(
680    marker_denom: S,
681    amount: u128,
682    denom: S,
683    recipient: H,
684) -> StdResult<CosmosMsg<ProvenanceMsg>> {
685    if amount == 0 {
686        return Err(StdError::generic_err("withdraw amount must be > 0"));
687    }
688    let coin = coin(amount, validate_string(denom, "denom")?);
689    Ok(create_marker_msg(MarkerMsgParams::WithdrawCoins {
690        marker_denom: validate_string(marker_denom, "marker_denom")?,
691        coin,
692        recipient: validate_address(recipient)?,
693    }))
694}
695
696/// Create a message that will transfer a marker amount from one account to another.
697///
698/// ### Example
699///
700/// ```rust
701/// // Imports required
702/// use cosmwasm_std::{Addr, Response, StdResult};
703/// use provwasm_std::{transfer_marker_coins, ProvenanceMsg};
704///
705/// // Create and dispatch a message that will transfer marker coins from one account to another.
706/// // NOTE: Transfer is only enabled for restricted markers.
707/// fn try_transfer_marker_coins(
708///     amount: u128,
709///     denom: String,
710///     to: Addr,
711///     from: Addr,
712/// ) -> StdResult<Response<ProvenanceMsg>> {
713///     let msg = transfer_marker_coins(amount, &denom, to, from)?;
714///     let mut res = Response::new().add_message(msg);
715///     Ok(res)
716/// }
717/// ```
718pub fn transfer_marker_coins<S: Into<String>, H: Into<Addr>>(
719    amount: u128,
720    denom: S,
721    to: H,
722    from: H,
723) -> StdResult<CosmosMsg<ProvenanceMsg>> {
724    if amount == 0 {
725        return Err(StdError::generic_err("transfer amount must be > 0"));
726    }
727    let coin = coin(amount, validate_string(denom, "denom")?);
728    let msg = create_marker_msg(MarkerMsgParams::TransferMarkerCoins {
729        coin,
730        to: validate_address(to)?,
731        from: validate_address(from)?,
732    });
733    Ok(msg)
734}
735
736/// Input params for creating marker module messages.
737#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
738#[serde(rename_all = "snake_case")]
739pub enum MetadataMsgParams {
740    WriteScope { scope: Scope, signers: Vec<Addr> },
741}
742
743// Create a custom cosmos message using metadata module params.
744fn create_metadata_msg(params: MetadataMsgParams) -> CosmosMsg<ProvenanceMsg> {
745    CosmosMsg::Custom(ProvenanceMsg {
746        route: ProvenanceRoute::Metadata,
747        params: ProvenanceMsgParams::Metadata(params),
748        version: String::from(MSG_DATAFMT_VERSION),
749    })
750}
751
752/// Create a message that will create, or update, a scope.
753///
754/// ### Example
755///
756/// ```rust
757/// // Imports required
758/// use cosmwasm_std::{Addr, Response, StdError};
759/// use provwasm_std::{ProvenanceMsg, Scope, write_scope};
760///
761/// // Create and dispatch a message that will create, or update, a scope.
762/// fn try_write_scope(scope: Scope, signers: Vec<Addr>) -> Result<Response<ProvenanceMsg>, StdError> {
763///     let msg = write_scope(scope, signers)?;
764///     let mut res = Response::new().add_message(msg);
765///     Ok(res)
766/// }
767/// ```
768pub fn write_scope<S: Into<Scope>, H: Into<Addr>>(
769    scope: S,
770    signers: Vec<H>,
771) -> Result<CosmosMsg<ProvenanceMsg>, StdError> {
772    Ok(create_metadata_msg(MetadataMsgParams::WriteScope {
773        scope: scope.into(),
774        signers: signers
775            .into_iter()
776            .map(validate_address)
777            .collect::<Result<Vec<Addr>, _>>()?,
778    }))
779}
780
781/// Input params for creating msgfee module messages.
782#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
783#[serde(rename_all = "snake_case")]
784pub enum MsgFeesMsgParams {
785    AssessCustomFee {
786        amount: Coin,
787        from: Addr,
788        name: Option<String>,
789        recipient: Option<Addr>,
790    },
791}
792
793// Create a custom cosmos message using msgfees module params.
794fn create_msgfees_msg(params: MsgFeesMsgParams) -> CosmosMsg<ProvenanceMsg> {
795    CosmosMsg::Custom(ProvenanceMsg {
796        route: ProvenanceRoute::Msgfees,
797        params: ProvenanceMsgParams::MsgFees(params),
798        version: String::from(MSG_DATAFMT_VERSION),
799    })
800}
801
802/// Create a message that will assess a custom fee
803/// ### Example
804///
805/// ```rust
806/// use cosmwasm_std::{Addr, Coin, Response, StdError};
807/// use provwasm_std::{assess_custom_fee, MsgFeesMsgParams, ProvenanceMsg};
808///
809/// fn try_assess_custom_fee(amount: Coin, name: Option<String>, from: Addr, recipient: Option<Addr>) -> Result<Response<ProvenanceMsg>, StdError>{
810///     let msg = assess_custom_fee(amount, name, from, recipient)?;
811///     let res = Response::new().add_message(msg);
812///     Ok(res)
813/// }
814/// ```
815pub fn assess_custom_fee<S: Into<String>>(
816    amount: Coin,
817    name: Option<S>,
818    from: Addr,
819    recipient: Option<Addr>,
820) -> Result<CosmosMsg<ProvenanceMsg>, StdError> {
821    Ok(create_msgfees_msg(MsgFeesMsgParams::AssessCustomFee {
822        amount,
823        name: name.map(|name| name.into()),
824        from,
825        recipient,
826    }))
827}