Skip to content

Commit

Permalink
docs: Update book to sylvia 1.1.0 (#13)
Browse files Browse the repository at this point in the history
* docs: Add `sudo` and `Executor`. Improve URLs
* chore: Update sylvia-book's examples
* docs: Update generics module
* docs: Update after review
  • Loading branch information
kulikthebird authored Jul 12, 2024
1 parent 568e6e4 commit f2084d7
Show file tree
Hide file tree
Showing 17 changed files with 275 additions and 219 deletions.
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();

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.

```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

0 comments on commit f2084d7

Please sign in to comment.