Skip to content

Commit 7a04da5

Browse files
committed
More generic, simple-price and converter pass tests
1 parent d8b13f4 commit 7a04da5

File tree

10 files changed

+189
-104
lines changed

10 files changed

+189
-104
lines changed

contracts/consumer/converter/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ backtraces = ["cosmwasm-std/backtraces"]
1717
library = []
1818
# enables generation of mt utilities
1919
mt = ["library", "sylvia/mt"]
20+
# enable this for multi-tests where you need custom messages for compatibility with virtual staking
21+
fake-custom = [ "mesh-simple-price-feed/fake-custom" ]
2022

2123
[dependencies]
2224
mesh-apis = { workspace = true }

contracts/consumer/converter/src/contract.rs

+63-48
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,18 @@ pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
2424

2525
const REPLY_ID_INSTANTIATE: u64 = 1;
2626

27-
#[cfg(not(any(test, feature = "mt")))]
28-
pub type ConverterCustomMsg = cosmwasm_std::Empty;
29-
#[cfg(any(test, feature = "mt"))]
30-
pub type ConverterCustomMsg = mesh_bindings::VirtualStakeCustomMsg;
31-
32-
#[cfg(not(any(test, feature = "mt")))]
33-
pub type ConverterCustomQuery = cosmwasm_std::Empty;
34-
#[cfg(any(test, feature = "mt"))]
35-
pub type ConverterCustomQuery = mesh_bindings::VirtualStakeCustomQuery;
27+
#[cfg(not(feature = "fake-custom"))]
28+
pub mod custom {
29+
pub type ConverterMsg = cosmwasm_std::Empty;
30+
pub type ConverterQuery = cosmwasm_std::Empty;
31+
pub type Response = cosmwasm_std::Response<cosmwasm_std::Empty>;
32+
}
33+
#[cfg(feature = "fake-custom")]
34+
pub mod custom {
35+
pub type ConverterMsg = mesh_bindings::VirtualStakeCustomMsg;
36+
pub type ConverterQuery = mesh_bindings::VirtualStakeCustomQuery;
37+
pub type Response = cosmwasm_std::Response<ConverterMsg>;
38+
}
3639

3740
pub struct ConverterContract<'a> {
3841
pub config: Item<'a, Config>,
@@ -44,7 +47,7 @@ pub struct ConverterContract<'a> {
4447
#[sv::error(ContractError)]
4548
#[sv::messages(converter_api as ConverterApi)]
4649
/// Workaround for lack of support in communication `Empty` <-> `Custom` Contracts.
47-
#[sv::custom(query=ConverterCustomQuery, msg=ConverterCustomMsg)]
50+
#[sv::custom(query=custom::ConverterQuery, msg=custom::ConverterMsg)]
4851
impl ConverterContract<'_> {
4952
pub const fn new() -> Self {
5053
Self {
@@ -63,13 +66,13 @@ impl ConverterContract<'_> {
6366
#[sv::msg(instantiate)]
6467
pub fn instantiate(
6568
&self,
66-
ctx: InstantiateCtx<ConverterCustomQuery>,
69+
ctx: InstantiateCtx<custom::ConverterQuery>,
6770
price_feed: String,
6871
discount: Decimal,
6972
remote_denom: String,
7073
virtual_staking_code_id: u64,
7174
admin: Option<String>,
72-
) -> Result<Response, ContractError> {
75+
) -> Result<custom::Response, ContractError> {
7376
nonpayable(&ctx.info)?;
7477
// validate args
7578
if discount >= Decimal::one() {
@@ -108,9 +111,9 @@ impl ConverterContract<'_> {
108111
#[sv::msg(reply)]
109112
fn reply(
110113
&self,
111-
ctx: ReplyCtx<ConverterCustomQuery>,
114+
ctx: ReplyCtx<custom::ConverterQuery>,
112115
reply: Reply,
113-
) -> Result<Response, ContractError> {
116+
) -> Result<custom::Response, ContractError> {
114117
match reply.id {
115118
REPLY_ID_INSTANTIATE => self.reply_init_callback(ctx.deps, reply.result.unwrap()),
116119
_ => Err(ContractError::InvalidReplyId(reply.id)),
@@ -120,9 +123,9 @@ impl ConverterContract<'_> {
120123
/// Store virtual staking address
121124
fn reply_init_callback(
122125
&self,
123-
deps: DepsMut<ConverterCustomQuery>,
126+
deps: DepsMut<custom::ConverterQuery>,
124127
reply: SubMsgResponse,
125-
) -> Result<Response, ContractError> {
128+
) -> Result<custom::Response, ContractError> {
126129
let init_data = parse_instantiate_response_data(&reply.data.unwrap())?;
127130
let virtual_staking = Addr::unchecked(init_data.contract_address);
128131
self.virtual_stake.save(deps.storage, &virtual_staking)?;
@@ -134,10 +137,10 @@ impl ConverterContract<'_> {
134137
#[sv::msg(exec)]
135138
fn test_stake(
136139
&self,
137-
ctx: ExecCtx<ConverterCustomQuery>,
140+
ctx: ExecCtx<custom::ConverterQuery>,
138141
validator: String,
139142
stake: Coin,
140-
) -> Result<Response, ContractError> {
143+
) -> Result<custom::Response, ContractError> {
141144
#[cfg(any(test, feature = "mt"))]
142145
{
143146
// This can only ever be called in tests
@@ -155,10 +158,10 @@ impl ConverterContract<'_> {
155158
#[sv::msg(exec)]
156159
fn test_unstake(
157160
&self,
158-
ctx: ExecCtx<ConverterCustomQuery>,
161+
ctx: ExecCtx<custom::ConverterQuery>,
159162
validator: String,
160163
unstake: Coin,
161-
) -> Result<Response, ContractError> {
164+
) -> Result<custom::Response, ContractError> {
162165
#[cfg(any(test, feature = "mt"))]
163166
{
164167
// This can only ever be called in tests
@@ -176,10 +179,10 @@ impl ConverterContract<'_> {
176179
#[sv::msg(exec)]
177180
fn test_burn(
178181
&self,
179-
ctx: ExecCtx<ConverterCustomQuery>,
182+
ctx: ExecCtx<custom::ConverterQuery>,
180183
validators: Vec<String>,
181184
burn: Coin,
182-
) -> Result<Response, ContractError> {
185+
) -> Result<custom::Response, ContractError> {
183186
#[cfg(any(test, feature = "mt"))]
184187
{
185188
// This can only ever be called in tests
@@ -193,7 +196,10 @@ impl ConverterContract<'_> {
193196
}
194197

195198
#[sv::msg(query)]
196-
fn config(&self, ctx: QueryCtx<ConverterCustomQuery>) -> Result<ConfigResponse, ContractError> {
199+
fn config(
200+
&self,
201+
ctx: QueryCtx<custom::ConverterQuery>,
202+
) -> Result<ConfigResponse, ContractError> {
197203
let config = self.config.load(ctx.deps.storage)?;
198204
let virtual_staking = self.virtual_stake.load(ctx.deps.storage)?.into_string();
199205
Ok(ConfigResponse {
@@ -207,10 +213,10 @@ impl ConverterContract<'_> {
207213
/// It is pulled out into a method, so it can also be called by test_stake for testing
208214
pub(crate) fn stake(
209215
&self,
210-
deps: DepsMut<ConverterCustomQuery>,
216+
deps: DepsMut<custom::ConverterQuery>,
211217
validator: String,
212218
stake: Coin,
213-
) -> Result<Response, ContractError> {
219+
) -> Result<custom::Response, ContractError> {
214220
let amount = self.normalize_price(deps.as_ref(), stake)?;
215221

216222
let event = Event::new("mesh-bond")
@@ -231,10 +237,10 @@ impl ConverterContract<'_> {
231237
/// It is pulled out into a method, so it can also be called by test_unstake for testing
232238
pub(crate) fn unstake(
233239
&self,
234-
deps: DepsMut<ConverterCustomQuery>,
240+
deps: DepsMut<custom::ConverterQuery>,
235241
validator: String,
236242
unstake: Coin,
237-
) -> Result<Response, ContractError> {
243+
) -> Result<custom::Response, ContractError> {
238244
let amount = self.normalize_price(deps.as_ref(), unstake)?;
239245

240246
let event = Event::new("mesh-unbond")
@@ -255,10 +261,10 @@ impl ConverterContract<'_> {
255261
/// It is pulled out into a method, so it can also be called by test_burn for testing
256262
pub(crate) fn burn(
257263
&self,
258-
deps: DepsMut<ConverterCustomQuery>,
264+
deps: DepsMut<custom::ConverterQuery>,
259265
validators: &[String],
260266
burn: Coin,
261-
) -> Result<Response, ContractError> {
267+
) -> Result<custom::Response, ContractError> {
262268
let amount = self.normalize_price(deps.as_ref(), burn)?;
263269

264270
let event = Event::new("mesh-burn")
@@ -280,7 +286,7 @@ impl ConverterContract<'_> {
280286

281287
fn normalize_price(
282288
&self,
283-
deps: Deps<ConverterCustomQuery>,
289+
deps: Deps<custom::ConverterQuery>,
284290
amount: Coin,
285291
) -> Result<Coin, ContractError> {
286292
let config = self.config.load(deps.storage)?;
@@ -298,10 +304,13 @@ impl ConverterContract<'_> {
298304
// also see https://github.com/CosmWasm/sylvia/issues/181 to just store Remote in state
299305
use price_feed_api::sv::Querier;
300306
use sylvia::types::Remote;
301-
// NOTE: Jan, this feels hacky... I'm not sure if this is the right way to do it
302-
// Also, I am sticking in a random error type here, not what I will get (which is unknown)
303-
let remote =
304-
Remote::<&dyn price_feed_api::PriceFeedApi<Error = StdError>>::new(config.price_feed);
307+
let remote = Remote::<
308+
dyn price_feed_api::PriceFeedApi<
309+
Error = StdError,
310+
ExecC = custom::ConverterMsg,
311+
QueryC = custom::ConverterQuery,
312+
>,
313+
>::new(config.price_feed);
305314
let price = remote.querier(&deps.querier).price()?.native_per_foreign;
306315
let converted = (amount.amount * price) * config.price_adjustment;
307316

@@ -313,7 +322,7 @@ impl ConverterContract<'_> {
313322

314323
fn invert_price(
315324
&self,
316-
deps: Deps<ConverterCustomQuery>,
325+
deps: Deps<custom::ConverterQuery>,
317326
amount: Coin,
318327
) -> Result<Coin, ContractError> {
319328
let config = self.config.load(deps.storage)?;
@@ -330,10 +339,14 @@ impl ConverterContract<'_> {
330339
// also see https://github.com/CosmWasm/sylvia/issues/181 to just store Remote in state
331340
use price_feed_api::sv::Querier;
332341
use sylvia::types::Remote;
333-
// NOTE: Jan, this feels hacky... I'm not sure if this is the right way to do it
334-
// Also, I am sticking in a random error type here, not what I will get (which is unknown)
335-
let remote =
336-
Remote::<&dyn price_feed_api::PriceFeedApi<Error = StdError>>::new(config.price_feed);
342+
// Note: it doesn't seem to matter which error type goes here...
343+
let remote = Remote::<
344+
dyn price_feed_api::PriceFeedApi<
345+
Error = StdError,
346+
ExecC = custom::ConverterMsg,
347+
QueryC = custom::ConverterQuery,
348+
>,
349+
>::new(config.price_feed);
337350
let price = remote.querier(&deps.querier).price()?.native_per_foreign;
338351
let converted = (amount.amount * price.inv().ok_or(ContractError::InvalidPrice {})?)
339352
* config
@@ -349,10 +362,10 @@ impl ConverterContract<'_> {
349362

350363
pub(crate) fn transfer_rewards(
351364
&self,
352-
deps: Deps<ConverterCustomQuery>,
365+
deps: Deps<custom::ConverterQuery>,
353366
recipient: String,
354367
rewards: Coin,
355-
) -> Result<CosmosMsg, ContractError> {
368+
) -> Result<CosmosMsg<custom::ConverterMsg>, ContractError> {
356369
// ensure the address is proper
357370
let recipient = deps.api.addr_validate(&recipient)?;
358371

@@ -377,7 +390,7 @@ impl ConverterContract<'_> {
377390

378391
fn ensure_authorized(
379392
&self,
380-
deps: &DepsMut<ConverterCustomQuery>,
393+
deps: &DepsMut<custom::ConverterQuery>,
381394
info: &MessageInfo,
382395
) -> Result<(), ContractError> {
383396
let virtual_stake = self.virtual_stake.load(deps.storage)?;
@@ -389,14 +402,16 @@ impl ConverterContract<'_> {
389402

390403
impl ConverterApi for ConverterContract<'_> {
391404
type Error = ContractError;
405+
type ExecC = custom::ConverterMsg;
406+
type QueryC = custom::ConverterQuery;
392407

393408
/// Rewards tokens (in native staking denom) are sent alongside the message, and should be distributed to all
394409
/// stakers who staked on this validator. This is tracked on the provider, so we send an IBC packet there.
395410
fn distribute_reward(
396411
&self,
397-
mut ctx: ExecCtx<ConverterCustomQuery>,
412+
mut ctx: ExecCtx<custom::ConverterQuery>,
398413
validator: String,
399-
) -> Result<Response, Self::Error> {
414+
) -> Result<custom::Response, Self::Error> {
400415
self.ensure_authorized(&ctx.deps, &ctx.info)?;
401416

402417
let config = self.config.load(ctx.deps.storage)?;
@@ -419,9 +434,9 @@ impl ConverterApi for ConverterContract<'_> {
419434
/// in the native staking denom.
420435
fn distribute_rewards(
421436
&self,
422-
mut ctx: ExecCtx<ConverterCustomQuery>,
437+
mut ctx: ExecCtx<custom::ConverterQuery>,
423438
payments: Vec<RewardInfo>,
424-
) -> Result<Response, Self::Error> {
439+
) -> Result<custom::Response, Self::Error> {
425440
self.ensure_authorized(&ctx.deps, &ctx.info)?;
426441

427442
let config = self.config.load(ctx.deps.storage)?;
@@ -459,15 +474,15 @@ impl ConverterApi for ConverterContract<'_> {
459474
#[allow(clippy::too_many_arguments)]
460475
fn valset_update(
461476
&self,
462-
ctx: ExecCtx<ConverterCustomQuery>,
477+
ctx: ExecCtx<custom::ConverterQuery>,
463478
additions: Vec<Validator>,
464479
removals: Vec<String>,
465480
updated: Vec<Validator>,
466481
jailed: Vec<String>,
467482
unjailed: Vec<String>,
468483
tombstoned: Vec<String>,
469484
mut slashed: Vec<ValidatorSlashInfo>,
470-
) -> Result<Response, Self::Error> {
485+
) -> Result<custom::Response, Self::Error> {
471486
self.ensure_authorized(&ctx.deps, &ctx.info)?;
472487

473488
// Send over IBC to the Consumer

contracts/consumer/converter/src/ibc.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ use mesh_apis::ibc::{
1616
};
1717
use sylvia::types::ExecCtx;
1818

19-
use crate::{contract::ConverterContract, error::ContractError};
19+
use crate::{
20+
contract::{custom, ConverterContract},
21+
error::ContractError,
22+
};
2023

2124
/// This is the maximum version of the Mesh Security protocol that we support
2225
const SUPPORTED_IBC_PROTOCOL_VERSION: &str = "0.11.0";
@@ -184,10 +187,10 @@ pub fn ibc_channel_close(
184187
/// We cannot return any meaningful response value as we do not know the response value
185188
/// of execution. We just return ok if we dispatched, error if we failed to dispatch
186189
pub fn ibc_packet_receive(
187-
deps: DepsMut,
190+
deps: DepsMut<custom::ConverterQuery>,
188191
_env: Env,
189192
msg: IbcPacketReceiveMsg,
190-
) -> Result<IbcReceiveResponse, ContractError> {
193+
) -> Result<IbcReceiveResponse<custom::ConverterMsg>, ContractError> {
191194
let packet: ProviderPacket = from_json(msg.packet.data)?;
192195
let contract = ConverterContract::new();
193196
let res = match packet {
@@ -280,7 +283,7 @@ pub fn ibc_packet_timeout(
280283
}
281284

282285
pub(crate) fn make_ibc_packet(
283-
ctx: &mut ExecCtx,
286+
ctx: &mut ExecCtx<custom::ConverterQuery>,
284287
packet: ConsumerPacket,
285288
) -> Result<IbcMsg, ContractError> {
286289
let channel = IBC_CHANNEL.load(ctx.deps.storage)?;

0 commit comments

Comments
 (0)