1use cosmwasm_schema::cw_serde;
2use cw_utils::{must_pay, PaymentError};
3use thiserror::Error;
4
5use cosmwasm_std::{
6 to_json_binary, Addr, BankMsg, Coin, CosmosMsg, Deps, MessageInfo, StdResult, Uint128, WasmMsg,
7};
8use cw20::{Denom, UncheckedDenom};
9
10#[cw_serde]
12pub struct DepositInfo {
13 pub amount: Uint128,
15 pub denom: Denom,
17 pub refund_failed_proposals: bool,
19}
20
21#[cw_serde]
25pub struct UncheckedDepositInfo {
26 pub amount: Uint128,
28 pub denom: UncheckedDenom,
30 pub refund_failed_proposals: bool,
32}
33
34#[derive(Error, Debug, PartialEq, Eq)]
35pub enum DepositError {
36 #[error("Invalid zero deposit. Set the deposit to None to have no deposit.")]
37 ZeroDeposit {},
38
39 #[error("Invalid cw20")]
40 InvalidCw20 {},
41
42 #[error("{0}")]
43 Payment(#[from] PaymentError),
44
45 #[error("Invalid native deposit amount")]
46 InvalidDeposit {},
47}
48
49impl UncheckedDepositInfo {
50 pub fn into_checked(self, deps: Deps) -> Result<DepositInfo, DepositError> {
52 if self.amount.is_zero() {
53 Err(DepositError::ZeroDeposit {})
54 } else {
55 Ok(DepositInfo {
56 amount: self.amount,
57 denom: self
58 .denom
59 .into_checked(deps)
60 .map_err(|_| DepositError::InvalidCw20 {})?,
61 refund_failed_proposals: self.refund_failed_proposals,
62 })
63 }
64 }
65}
66
67impl DepositInfo {
68 pub fn check_native_deposit_paid(&self, info: &MessageInfo) -> Result<(), DepositError> {
69 if let Self {
70 amount,
71 denom: Denom::Native(denom),
72 ..
73 } = self
74 {
75 let paid = must_pay(info, denom)?;
76 if paid != *amount {
77 Err(DepositError::InvalidDeposit {})
78 } else {
79 Ok(())
80 }
81 } else {
82 Ok(())
83 }
84 }
85
86 pub fn get_take_deposit_messages(
87 &self,
88 depositor: &Addr,
89 contract: &Addr,
90 ) -> StdResult<Vec<CosmosMsg>> {
91 let take_deposit_msg: Vec<CosmosMsg> = if let DepositInfo {
92 amount,
93 denom: Denom::Cw20(address),
94 ..
95 } = self
96 {
97 if amount.is_zero() {
100 vec![]
101 } else {
102 vec![WasmMsg::Execute {
103 contract_addr: address.to_string(),
104 funds: vec![],
105 msg: to_json_binary(&cw20::Cw20ExecuteMsg::TransferFrom {
106 owner: depositor.to_string(),
107 recipient: contract.to_string(),
108 amount: *amount,
109 })?,
110 }
111 .into()]
112 }
113 } else {
114 vec![]
115 };
116 Ok(take_deposit_msg)
117 }
118
119 pub fn get_return_deposit_message(&self, depositor: &Addr) -> StdResult<CosmosMsg> {
120 let message = match &self.denom {
121 Denom::Native(denom) => BankMsg::Send {
122 to_address: depositor.to_string(),
123 amount: vec![Coin {
124 amount: self.amount,
125 denom: denom.to_string(),
126 }],
127 }
128 .into(),
129 Denom::Cw20(address) => WasmMsg::Execute {
130 contract_addr: address.to_string(),
131 msg: to_json_binary(&cw20::Cw20ExecuteMsg::Transfer {
132 recipient: depositor.to_string(),
133 amount: self.amount,
134 })?,
135 funds: vec![],
136 }
137 .into(),
138 };
139 Ok(message)
140 }
141}