1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
use std::{
fmt::{Debug, Display},
path::PathBuf,
str::FromStr,
};
use crate::error::DeployError;
use serde::Serialize;
use strum::{IntoEnumIterator, ParseError};
pub trait Msg: Debug + Send + Sync + erased_serde::Serialize {}
impl<T> Msg for T where T: Debug + Serialize + Send + Sync {}
impl Serialize for dyn Msg {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
erased_serde::serialize(self, serializer)
}
}
/// This trait represents a contract that can be deployed.
pub trait Deploy: ContractInteractive {
/// This method gets the preprogrammed instantiate msg for the contract.
fn instantiate_msg(&self) -> Option<Box<dyn Msg>> {
println!("No instantiate msg for {}", self.name());
println!("Defaulting to interactive instantiate");
self.instantiate().ok()
}
/// This method gets the preprogrammed migrate msg for the contract.
fn migrate_msg(&self) -> Option<Box<dyn Msg>> {
None
}
/// This method gets the preprogrammed set config msg for the contract.
fn set_config_msg(&self) -> Option<Box<dyn Msg>> {
None
}
/// This method gets the preprogrammed set up for the contract.
fn set_up_msgs(&self) -> Vec<Box<dyn Msg>> {
vec![]
}
/// This method will instantiate an external contract via code_id alongside a local contract.
fn external_instantiate_msgs(&self) -> Vec<ExternalInstantiate<Box<dyn Msg>>> {
vec![]
}
}
pub trait ContractInteractive:
Send + Sync + Debug + Display + FromStr<Err = ParseError> + IntoEnumIterator + 'static
{
/// This is the name of the contract and represents
/// how it will appear in the cli.
fn name(&self) -> String {
self.to_string()
}
/// This is the name of the generated binary.
/// It defaults to the contract name.
/// If you have multiple contracts that share the same code
/// then you can use this, in conjunction with the path method.
fn bin_name(&self) -> String {
self.name()
}
/// This method allows for customizing the path to the contract.
/// This should be the path relative to the project root.
fn path(&self) -> PathBuf {
PathBuf::from(format!("contracts/{}", self.name()))
}
/// This is the address of the contract admin.
/// It is required when instantiating.
fn admin(&self) -> String;
/// This method allows instantiating a contract interactively.
/// interactive-parse should be used to generate the msg.
fn instantiate(&self) -> anyhow::Result<Box<dyn Msg>> {
Err(DeployError::TraitNotImplemented.into())
}
/// This method allows executing a contract interactively.
/// interactive-parse should be used to generate the msg.
fn execute(&self) -> anyhow::Result<Box<dyn Msg>> {
Err(DeployError::TraitNotImplemented.into())
}
/// This method allows querying a contract interactively.
/// interactive-parse should be used to generate the msg.
fn query(&self) -> anyhow::Result<Box<dyn Msg>> {
Err(DeployError::TraitNotImplemented.into())
}
/// This method allows migrating a contract interactively.
/// interactive-parse should be used to generate the msg.
fn migrate(&self) -> anyhow::Result<Box<dyn Msg>> {
Err(DeployError::TraitNotImplemented.into())
}
/// This method allows sending a cw20 token with an attached message to a contract interactively.
/// interactive-parse should be used to generate the msg.
fn cw20_send(&self) -> anyhow::Result<Box<dyn Msg>> {
Err(DeployError::TraitNotImplemented.into())
}
}
#[derive(Debug, Clone)]
pub struct ExternalInstantiate<T> {
pub msg: T,
pub code_id: u64,
pub name: String,
}
impl<T> From<ExternalInstantiate<T>> for ExternalInstantiate<Box<dyn Msg>>
where
T: Msg + Clone + 'static,
{
fn from(msg: ExternalInstantiate<T>) -> Self {
ExternalInstantiate {
msg: Box::new(msg.msg),
code_id: msg.code_id,
name: msg.name,
}
}
}