levana_perpswap_cosmos/
response.rs1use std::collections::HashMap;
2
3use anyhow::Result;
4use cosmwasm_std::{
5 from_json, to_json_binary, wasm_execute, CosmosMsg, Empty, Event, IbcBasicResponse,
6 IbcReceiveResponse, Response, SubMsg, WasmMsg,
7};
8use cw2::ContractVersion;
9use serde::de::DeserializeOwned;
10use serde::Serialize;
11
12use crate::ibc::{ack_fail, ack_success};
13
14pub struct ResponseBuilder {
16 resp: Response,
17 event_type: EventType,
18 event_type_count: HashMap<String, u32>,
19}
20
21enum EventType {
22 MuteEvents,
23 EmitEvents {
24 common_attrs: Vec<(&'static str, String)>,
25 },
26}
27
28fn standard_event_attributes(
29 ContractVersion { contract, version }: ContractVersion,
30) -> Vec<(&'static str, String)> {
31 vec![
32 ("levana_protocol", "perps".to_string()),
33 ("contract_version", version),
34 ("contract_name", contract),
35 ]
36}
37
38impl ResponseBuilder {
39 pub fn new(contract_version: ContractVersion) -> Self {
41 ResponseBuilder {
42 resp: Response::new(),
43 event_type: EventType::EmitEvents {
44 common_attrs: standard_event_attributes(contract_version),
45 },
46 event_type_count: HashMap::new(),
47 }
48 }
49
50 pub fn new_mute_events() -> Self {
52 ResponseBuilder {
53 resp: Response::new(),
54 event_type: EventType::MuteEvents,
55 event_type_count: HashMap::new(),
56 }
57 }
58
59 pub fn into_response(self) -> Response {
61 self.resp
62 }
63
64 pub fn add_message(&mut self, msg: impl Into<CosmosMsg<Empty>>) {
66 self.resp.messages.push(SubMsg::new(msg.into()));
67 }
68
69 pub fn add_instantiate_submessage<
71 I: Into<u64>,
72 A: Into<String>,
73 L: Into<String>,
74 T: Serialize,
75 >(
76 &mut self,
77 id: I,
78 admin: A,
79 code_id: u64,
80 label: L,
81 msg: &T,
82 ) -> Result<()> {
83 let payload = to_json_binary(msg)?;
84
85 let msg = WasmMsg::Instantiate {
88 admin: Some(admin.into()),
89 code_id,
90 msg: payload,
91 funds: vec![],
92 label: label.into(),
93 };
94 self.add_raw_submessage(
95 SubMsg::reply_on_success(msg, id.into()),
98 );
99
100 Ok(())
101 }
102
103 pub fn add_execute_submessage_oneshot<C: Into<String>, T: Serialize>(
105 &mut self,
106 contract: C,
107 msg: &T,
108 ) -> Result<()> {
109 self.add_raw_submessage(
110 SubMsg::new(wasm_execute(
113 contract,
114 msg,
115 vec![],
117 )?),
118 );
119
120 Ok(())
121 }
122
123 pub fn add_raw_submessage(&mut self, msg: SubMsg<Empty>) {
125 self.resp.messages.push(msg);
126 }
127
128 pub fn add_event(&mut self, event: impl Into<Event>) {
130 let event: Event = event.into();
131 match &self.event_type {
132 EventType::MuteEvents => (),
133 EventType::EmitEvents { common_attrs } => {
134 let mut event = event.add_attributes(common_attrs.clone());
135
136 let event_type_count = self.event_type_count.entry(event.ty.clone()).or_default();
137
138 if *event_type_count > 0 {
139 event.ty = format!("{}-{}", event.ty, *event_type_count);
140 }
141
142 *event_type_count += 1;
143
144 self.resp.events.push(event)
145 }
146 }
147 }
148
149 pub fn set_data(&mut self, data: &impl Serialize) -> Result<()> {
151 match self.resp.data {
152 None => {
153 let data = to_json_binary(data)?;
154 self.resp.data = Some(data);
155 }
156 Some(_) => anyhow::bail!("data already exists, use update_data instead"),
157 }
158
159 Ok(())
160 }
161
162 pub fn get_data<T: DeserializeOwned>(&self) -> Result<Option<T>> {
164 match &self.resp.data {
165 None => Ok(None),
166 Some(data) => Ok(Some(from_json(data)?)),
167 }
168 }
169
170 pub fn remove_data(&mut self) {
172 self.resp.data = None;
173 }
174
175 pub fn update_data<T: Serialize + DeserializeOwned>(
177 &mut self,
178 f: impl FnOnce(Option<T>) -> T,
179 ) -> Result<()> {
180 let data = self.get_data()?;
181 let updated = f(data);
182 self.resp.data = Some(to_json_binary(&updated)?);
183
184 Ok(())
185 }
186
187 pub fn into_ibc_response(self) -> IbcBasicResponse {
189 let mut resp = IbcBasicResponse::default();
190 resp.messages = self.resp.messages;
191 resp.attributes = self.resp.attributes;
192 resp.events = self.resp.events;
193
194 resp
195 }
196
197 pub fn into_ibc_recv_response_success(self) -> IbcReceiveResponse {
199 let mut resp = IbcReceiveResponse::new(ack_success());
200 resp.messages = self.resp.messages;
201 resp.attributes = self.resp.attributes;
202 resp.events = self.resp.events;
203 resp
204 }
205
206 pub fn into_ibc_recv_response_fail(self, error: anyhow::Error) -> IbcReceiveResponse {
208 let mut resp = IbcReceiveResponse::new(ack_fail(error));
209 resp.messages = self.resp.messages;
210 resp.attributes = self.resp.attributes;
211 resp.events = self.resp.events;
212 resp
213 }
214}