Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Update book to sylvia 1.1.0 #13

Merged
merged 4 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@

- [Advanced](advanced.md)
- [Override entry point](advanced/entry_points_overriding.md)
- [Sudo entry point](advanced/sudo.md)
- [Custom messages](advanced/custom.md)
- [Generics](advanced/generics.md)
- [Attributes forwarding](advanced/attributes_forwarding.md)

- [Ibc]()

Expand Down
53 changes: 53 additions & 0 deletions src/advanced/attributes_forwarding.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Attributes forwarding

This feature allows ^sylvia users to forward any attribute to any message
type using `#[sv::msg_attr(msg_type, ...)]` attribute.
For the messages that resolves to enum types it is possible to forward attributes to their specific variants by using `#[sv::attr(...)]` on top of the appropriate method - this works for `exec`, `query`
and `sudo` methods.

## Example

```rust,noplayground
use cosmwasm_std::{Response, StdResult};
use sylvia::types::{InstantiateCtx, ExecCtx};
use sylvia::{contract, entry_points};


pub mod interface {
use cosmwasm_std::{Response, StdResult, StdError};
use sylvia::types::QueryCtx;
use sylvia::interface;

#[interface]
#[sv::msg_attr(query, derive(PartialOrd))]
pub trait Interface {
type Error: From<StdError>;

#[sv::msg(query)]
#[sv::attr(serde(rename(serialize = "QuErY")))]
fn interface_query_msg(&self, _ctx: QueryCtx) -> StdResult<Response>;
}
}

pub struct CounterContract;

#[entry_points]
#[contract]
#[sv::msg_attr(exec, derive(PartialOrd))]
impl CounterContract {
pub const fn new() -> Self {
Self
}

#[sv::msg(instantiate)]
pub fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
Ok(Response::default())
}

#[sv::msg(exec)]
#[sv::attr(serde(rename(serialize = "EXEC_METHOD")))]
pub fn exec_method(&self, _ctx: ExecCtx) -> StdResult<Response> {
Ok(Response::default())
}
}
```
104 changes: 34 additions & 70 deletions src/advanced/custom.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# Custom messages

*Since version 0.8.0.*

Blockchain creators might define chain-specific logic triggered through defined by them messages.
`CosmWasm` provides a way to send such messages through `cosmwasm_std::CosmosMsg::Custom(..)` variant.

Expand Down Expand Up @@ -60,6 +58,23 @@ pub trait SvCustom {
#[sv::msg(query)]
fn sv_custom_query(&self, ctx: QueryCtx<ExternalQuery>) -> Result<String, Self::Error>;
}

use crate::contract::CustomContract;

impl SvCustom for CustomContract {
type Error = StdError;

fn sv_custom_exec(
&self,
_ctx: ExecCtx<ExternalQuery>,
) -> Result<Response<ExternalMsg>, Self::Error> {
Ok(Response::new())
}

fn sv_custom_query(&self, _ctx: QueryCtx<ExternalQuery>) -> Result<String, Self::Error> {
Ok(String::default())
}
}
```

If, however, we would like to give the developers the freedom to choose which chain to support, we can use define
Expand Down Expand Up @@ -129,67 +144,29 @@ Now that we have defined the interfaces, we can implement them on the contract.
cast `Response<Custom>` to `Response<Empty>` or `Deps<Empty>` to `Deps<Custom>`, implementation of the custom interface
on non-custom contracts is not possible. It is possible, however, to implement a non-custom interface on a custom contract.

Implementation of chain-specific custom interfaces is simple. We have to pass the `sv::custom(..)` attribute once again.

`src/sv_custom.rs`
```rust
use super::SvCustom;
use crate::contract::CustomContract;
use crate::messages::{ExternalMsg, ExternalQuery};
use cosmwasm_std::{Response, StdError};
use sylvia::contract;
use sylvia::types::{ExecCtx, QueryCtx};

#[contract(module=crate::contract)]
#[sv::messages(crate::sv_custom as SvCustom)]
#[sv::custom(msg=ExternalMsg, query=ExternalQuery)]
impl SvCustom for CustomContract {
type Error = StdError;

#[sv::msg(exec)]
fn sv_custom_exec(
&self,
_ctx: ExecCtx<ExternalQuery>,
) -> Result<Response<ExternalMsg>, Self::Error> {
Ok(Response::new())
}

#[sv::msg(query)]
fn sv_custom_query(&self, _ctx: QueryCtx<ExternalQuery>) -> Result<String, Self::Error> {
Ok(String::default())
}
}
```

To implement the interface with the associated type, we have to assign types for them.
Because the type of `ExecC` and `QueryC` is defined by the user, the interface is reusable in the context of
different chains.

`src/associated.rs`
```rust
use super::Associated;
// [...]

use crate::contract::CustomContract;
use crate::messages::{ExternalMsg, ExternalQuery};
use cosmwasm_std::{Response, StdError};
use sylvia::contract;
use sylvia::types::{ExecCtx, QueryCtx};

#[contract(module=crate::contract)]
#[sv::messages(crate::associated as Associated)]
impl Associated for CustomContract {
type Error = StdError;
type ExecC = ExternalMsg;
type QueryC = ExternalQuery;

#[sv::msg(exec)]
fn associated_exec(
&self,
_ctx: ExecCtx<Self::QueryC>,
) -> Result<Response<Self::ExecC>, Self::Error> {
Ok(Response::new())
}

#[sv::msg(query)]
fn associated_query(&self, _ctx: QueryCtx<Self::QueryC>) -> Result<String, Self::Error> {
Ok(String::default())
}
Expand Down Expand Up @@ -251,36 +228,22 @@ pub trait NonCustom {
fn non_custom_query(&self, ctx: QueryCtx) -> Result<String, Self::Error>;
}

pub mod impl_non_custom {
use crate::contract::CustomContract;
use cosmwasm_std::{Response, StdError};
use sylvia::contract;
use sylvia::types::{ExecCtx, QueryCtx};
use crate::contract::CustomContract;

use super::NonCustom;

#[contract(module=crate::contract)]
#[sv::messages(crate::non_custom as NonCustom)]
#[sv::custom(msg=ExternalMsg, query=ExternalQuery)]
impl NonCustom for CustomContract {
type Error = StdError;
impl NonCustom for CustomContract {
type Error = StdError;

#[sv::msg(exec)]
fn non_custom_exec(&self, _ctx: ExecCtx) -> Result<Response, Self::Error> {
Ok(Response::new())
}
fn non_custom_exec(&self, _ctx: ExecCtx) -> Result<Response, Self::Error> {
Ok(Response::new())
}

#[sv::msg(query)]
fn non_custom_query(&self, _ctx: QueryCtx) -> Result<String, Self::Error> {
Ok(String::default())
}
fn non_custom_query(&self, _ctx: QueryCtx) -> Result<String, Self::Error> {
Ok(String::default())
}
}
```

As you can see, although it's non-custom, we still have to inform ^sylvia custom types from the contract.
It's required for the `MultiTest` helpers to be generic over the same types as the contract.

Let's add the last `messages` attribute to the contract. It has to end with `: custom(msg query)`. This way ^sylvia
will know that it has to cast `Response<Custom>` to `Response<Empty>` for `msg` and `Deps<Custom>` to `Deps<Empty>` for `query`.

Expand All @@ -296,7 +259,7 @@ pub struct CustomContract;
#[contract]
#[sv::messages(crate::sv_custom as SvCustomInterface)]
#[sv::messages(crate::associated as AssociatedInterface)]
#[sv::messages(crate::non_custom as NonCustom: custom(msg query))]
#[sv::messages(crate::non_custom as NonCustom: custom(msg, query))]
#[sv::custom(msg=ExternalMsg, query=ExternalQuery)]
impl CustomContract {
pub const fn new() -> Self {
Expand Down Expand Up @@ -336,7 +299,7 @@ pub struct CustomContract;
#[contract]
#[sv::messages(crate::sv_custom as SvCustomInterface)]
#[sv::messages(crate::associated as AssociatedInterface)]
#[sv::messages(crate::non_custom as NonCustom: custom(msg query))]
#[sv::messages(crate::non_custom as NonCustom: custom(msg, query))]
#[sv::custom(msg=ExternalMsg, query=ExternalQuery)]
impl CustomContract {
pub const fn new() -> Self {
Expand Down Expand Up @@ -382,7 +345,7 @@ We are only interested in `execute` and `query` methods in our example. In case
```rust
use cosmwasm_schema::schemars::JsonSchema;
use cosmwasm_std::{
to_binary, Addr, Api, Binary, BlockInfo, CustomQuery, Empty, Querier, StdResult, Storage,
to_json_binary, Addr, Api, Binary, BlockInfo, CustomQuery, Empty, Querier, StdResult, Storage
};
use cw_multi_test::{AppResponse, CosmosRouter, Module};
use cw_storage_plus::Item;
Expand Down Expand Up @@ -459,7 +422,7 @@ impl Module for CustomModule {
match request {
ExternalQuery::IsPoked {} => {
let is_poked = self.is_poked.load(storage)?;
to_binary(&is_poked).map_err(Into::into)
to_json_binary(&is_poked).map_err(Into::into)
}
}
}
Expand All @@ -476,14 +439,15 @@ Running `poke` on our contract will send the `ExternalMsg::Poke`, which `App` wi

`src/multitest/tests.rs`
```rust
use cw_multi_test::IntoBech32;
use sylvia::multitest::App;

use crate::contract::sv::mt::{CodeId, CounterContractProxy};
use crate::contract::sv::mt::{CodeId, CustomContractProxy};
use crate::multitest::custom_module::CustomModule;

#[test]
fn test_custom() {
let owner = "owner".into_addr();
let owner = "owner".into_bech32();
kulikthebird marked this conversation as resolved.
Show resolved Hide resolved

let mt_app = cw_multi_test::BasicAppBuilder::new_custom()
.with_custom(CustomModule::new())
Expand Down
17 changes: 9 additions & 8 deletions src/advanced/entry_points_overriding.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
# Override entry point

^Sylvia is still developing and lacks features like f.e. `sudo` support.
If you need to use a lacking feature of `CosmWasm` or prefer to define some custom
entry point, it is possible to use the `#[sv::override_entry_point(...)]` attribute.
It may happen that for any reason CosmWasm will start support some new
entry point that is not yet implemented in ^sylvia. There is a way to
add it manually using `#[sv::override_entry_point(...)]` attribute.
This feature can be used to override already implemented entry points
like `execute` and `query`.

## Example

To make ^sylvia generate multitest helpers with `sudo` support, you first need to define your
To make ^sylvia generate multitest helpers with `custom_entrypoint` support, you first need to define your
`entry point`.

```rust,noplayground
#[entry_point]
pub fn sudo(deps: DepsMut, _env: Env, _msg: SudoMsg) -> StdResult<Response> {
pub fn custom_entrypoint(deps: DepsMut, _env: Env, _msg: SudoMsg) -> StdResult<Response> {
CounterContract::new().counter.save(deps.storage, &3)?;
Ok(Response::new())
}
```

You have to define the `SudoMsg` yourself, as it is not yet supported.
You have to define the `CustomEntrypointMsg` yourself, as it is not yet supported.
kulikthebird marked this conversation as resolved.
Show resolved Hide resolved

```rust,noplayground
#[cfg_attr(not(feature = "library"), entry_points)]
#[contract]
#[sv::override_entry_point(sudo=crate::entry_points::sudo(crate::messages::SudoMsg))]
#[sv::override_entry_point(exec=crate::entry_points::execute(crate::messages::CustomExecMsg))]
#[sv::override_entry_point(custom=crate::entry_points::custom_entrypoint(crate::messages::CustomEntrypointMsg))]
impl CounterContract {
}
```
Expand Down
Loading
Loading