diff --git a/src/pages/sylvia/basics/contract-structure.mdx b/src/pages/sylvia/basics/contract-structure.mdx
index 7149b2fc..31f930ef 100644
--- a/src/pages/sylvia/basics/contract-structure.mdx
+++ b/src/pages/sylvia/basics/contract-structure.mdx
@@ -2,25 +2,109 @@
tags: ["sylvia"]
---
+import { Callout, Tabs } from "nextra/components";
+
# Contract structure
Sylvia contracts are designed using the actor model. An actor is a contract struct that can store a
state and define a behavior.
+
+
+
+```rust
+use cw_storey::containers::Item;
+
+pub struct CounterContract { pub count: Item, }
+```
+
+
+
+
```rust
use sylvia::cw_storage_plus::Item;
-pub struct CounterContract {
- pub count: Item,
-}
+pub struct CounterContract { pub count: Item, }
```
+
+
+
In Sylvia we keep the state accessors as part of the contract definition. The accessors are
-[`cw_storage_plus`](../../cw-storage-plus) primitives.
+[`storey`](../../storey) or [`cw_storage_plus`](../../cw-storage-plus) primitives.
Let's take a look at the behavior implementation.
+
+
+
+```rust
+use cosmwasm_schema::cw_serde;
+use cw_storey::CwStorage;
+use sylvia::contract;
+use sylvia::cw_std::{Response, StdError, StdResult};
+use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx};
+
+#[cw_serde]
+pub struct CountResponse {
+ pub count: u64,
+}
+
+#[cfg_attr(not(feature = "library"), sylvia::entry_points)]
+#[contract]
+impl CounterContract {
+ pub const fn new() -> Self {
+ Self {
+ count: Item::new(0),
+ }
+ }
+
+ #[sv::msg(instantiate)]
+ fn instantiate(&self, ctx: InstantiateCtx) -> StdResult {
+ self.count
+ .access(&mut CwStorage(ctx.deps.storage))
+ .set(&0)?;
+ Ok(Response::new())
+ }
+
+ #[sv::msg(exec)]
+ fn increment(&self, ctx: ExecCtx) -> StdResult {
+ let mut storage = CwStorage(ctx.deps.storage);
+ let mut accessor = self.count.access(&mut storage);
+ let count = accessor
+ .get()?
+ .ok_or_else(|| StdError::generic_err("Count not instantiated yet"))?;
+ accessor.set(&(count + 1))?;
+
+ Ok(Response::new())
+ }
+
+ #[sv::msg(query)]
+ fn count(&self, ctx: QueryCtx) -> StdResult {
+ let count = self
+ .count
+ .access(&CwStorage(ctx.deps.storage))
+ .get()?
+ .ok_or_else(|| StdError::generic_err("Count not instantiated yet"))?;
+ Ok(CountResponse { count })
+ }
+}
+```
+
+
+
+
```rust
+use cosmwasm_schema::cw_serde;
+use sylvia::contract;
+use sylvia::cw_std::{Response, StdError, StdResult};
+use sylvia::types::{ExecCtx, InstantiateCtx, QueryCtx};
+
+#[cw_serde]
+pub struct CountResponse {
+ pub count: u64,
+}
+
#[cfg_attr(not(feature = "library"), sylvia::entry_points)]
#[contract]
impl CounterContract {
@@ -53,12 +137,14 @@ impl CounterContract {
}
```
+
+
+
In the first two lines, we see the usage of two macros:
-- [`entry_points`](https://docs.rs/sylvia/latest/sylvia/attr.entry_points.html) - Generates entry
- points of the contract. By default it will generate `instantiate`, `execute` and `query` entry
- points. The other ones, `migrate`, `reply`, and `sudo`, are generated if a behavior related to
- them is defined in the `impl` block.
+- [`entry_points`](../macros/entry-points) - Generates entry points of the contract. By default it
+ will generate `instantiate`, `execute` and `query` entry points. The other ones, `migrate`,
+ `reply`, and `sudo`, are generated if a behavior related to them is defined in the `impl` block.
This macro is wrapped in `cfg_attr` statement to be compiled only if `library` feature flag is not
enabled. This way, other users who might want to use this contract in theirs won't get an entry
@@ -92,7 +178,7 @@ queries should never mutate the state. This is not the case for the
[`ExecCtx`](https://docs.rs/sylvia/latest/sylvia/types/struct.ExecCtx.html) and `InstantiateCtx`
which exposes the [`DepsMut`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.DepsMut.html).
-Fell free expanding the macro now and seeing what Sylvia generates. It might be overwhelming, as
+Feel free expanding the macro now and seeing what Sylvia generates. It might be overwhelming, as
there will be a lot of things generated that seem not relevant to our code, so for the bare minimum,
check the `InstantiateMsg` and its `impl` block.
diff --git a/src/pages/sylvia/basics/interoperability.mdx b/src/pages/sylvia/basics/interoperability.mdx
index 0b55c7be..17c1cd10 100644
--- a/src/pages/sylvia/basics/interoperability.mdx
+++ b/src/pages/sylvia/basics/interoperability.mdx
@@ -25,7 +25,30 @@ call the
or
[`add_messages`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Response.html#method.add_messages).
-```rust
+
+
+
+```rust {3, 8, 13}
+#[sv::msg(exec)]
+fn external_increment(&self, ctx: ExecCtx) -> StdResult {
+ let remote = self
+ .remote
+ .access(&CwStorage(ctx.deps.storage))
+ .get()?
+ .ok_or_else(|| StdError::generic_err("Remote not instantiated"))?;
+ let msg = WasmMsg::Execute {
+ contract_addr: remote.to_string(),
+ msg: to_json_binary(&ExternalExecMsg::Increment {})?,
+ funds: vec![],
+ };
+ Ok(Response::new().add_message(msg))
+}
+```
+
+
+
+
+```rust {3-4, 9}
#[sv::msg(exec)]
fn external_increment(&self, ctx: ExecCtx) -> StdResult {
let remote = self.remote.load(ctx.deps.storage)?;
@@ -38,13 +61,75 @@ fn external_increment(&self, ctx: ExecCtx) -> StdResult {
}
```
+
+
+
We can also use the generated
[`WasmMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/enum.WasmMsg.html) to construct the
[`SubMsg`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.SubMsg.html) and expect reply.
Learn more about replies [here](../../core/entrypoints/reply).
-```rust {1, 24-33, 36-45}
+
+
+
+```rust {1, 18-20, 26-36, 42-48}
+const SUBMSG_ID: u64 = 1;
+
+pub struct ReplyContract {
+ remote: Item>,
+}
+
+#[entry_points]
+#[contract]
+impl ReplyContract {
+ pub fn new() -> Self {
+ Self {
+ remote: Item::new(0),
+ }
+ }
+
+ #[sv::msg(instantiate)]
+ fn instantiate(&self, ctx: InstantiateCtx, remote_addr: Addr) -> StdResult {
+ self.remote
+ .access(&mut CwStorage(ctx.deps.storage))
+ .set(&Remote::new(remote_addr))?;
+ Ok(Response::new())
+ }
+
+ #[sv::msg(exec)]
+ fn exec(&self, ctx: ExecCtx) -> StdResult {
+ let msg = self
+ .remote
+ .access(&mut CwStorage(ctx.deps.storage))
+ .get()?
+ .ok_or_else(|| StdError::generic_err("Remote not instantiated"))?
+ .executor()
+ .contract_exec()?
+ .build();
+
+ let sub_msg = SubMsg::reply_on_success(msg, SUBMSG_ID);
+ let resp = Response::new().add_submessage(sub_msg);
+ Ok(resp)
+ }
+
+ #[sv::msg(reply)]
+ fn reply(&self, ctx: ReplyCtx, reply: Reply) -> StdResult {
+ match reply.id {
+ SUBMSG_ID => {
+ // Your logic here
+ Ok(Response::new())
+ }
+ _ => Err(StdError::generic_err("Invalid reply id")),
+ }
+ }
+}
+```
+
+
+
+
+```rust {1, 18-20, 25-34, 39-45}
const SUBMSG_ID: u64 = 1;
pub struct ReplyContract {
@@ -94,12 +179,36 @@ impl ReplyContract {
}
```
+
+
+
Query messages can also be sent through the
[`query_wasm_smart`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.QuerierWrapper.html#method.query_wasm_smart)
method. We can access the
[`Deps`](https://docs.rs/cosmwasm-std/latest/cosmwasm_std/struct.Deps.html) through the
[`QueryCtx`](../types/context).
+
+
+
+```rust {5-7}
+#[sv::msg(query)]
+fn external_count(&self, ctx: QueryCtx) -> StdResult {
+ let remote = self
+ .remote
+ .access(&CwStorage(ctx.deps.storage))
+ .get()?
+ .ok_or_else(|| StdError::generic_err("Remote not instantiated"))?;
+
+ ctx.deps
+ .querier
+ .query_wasm_smart(remote, &ExternalQueryMsg::Count {})
+}
+```
+
+
+
+
```rust {5-7}
#[sv::msg(query)]
fn external_count(&self, ctx: QueryCtx) -> StdResult {
@@ -111,6 +220,9 @@ fn external_count(&self, ctx: QueryCtx) -> StdResult {
}
```
+
+
+
As you see, we can send messages from the Sylvia contract as we would in case of a CosmWasm
contract. You can check generated messages [here](../macros/generated-types/message-types).