{"id":13566122,"url":"https://github.com/CosmWasm/sylvia","last_synced_at":"2025-04-03T23:31:07.597Z","repository":{"id":39590910,"uuid":"495431586","full_name":"CosmWasm/sylvia","owner":"CosmWasm","description":"CosmWasm smart contract framework","archived":false,"fork":false,"pushed_at":"2024-04-23T06:30:06.000Z","size":1345,"stargazers_count":81,"open_issues_count":29,"forks_count":14,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-04-23T10:53:03.211Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CosmWasm.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2022-05-23T13:51:53.000Z","updated_at":"2024-04-24T13:59:43.818Z","dependencies_parsed_at":"2023-12-20T13:16:12.893Z","dependency_job_id":"ae208d2c-4a4e-49b4-bdd5-facce63d8872","html_url":"https://github.com/CosmWasm/sylvia","commit_stats":{"total_commits":300,"total_committers":4,"mean_commits":75.0,"dds":0.08333333333333337,"last_synced_commit":"401888b3e1d410bb69dd3c9ffc755b545b8dbd9f"},"previous_names":[],"tags_count":52,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CosmWasm%2Fsylvia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CosmWasm%2Fsylvia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CosmWasm%2Fsylvia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CosmWasm%2Fsylvia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CosmWasm","download_url":"https://codeload.github.com/CosmWasm/sylvia/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247097668,"owners_count":20883122,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T13:02:02.563Z","updated_at":"2025-04-03T23:31:05.031Z","avatar_url":"https://github.com/CosmWasm.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# Sylvia Framework\n\nSylvia is the old name meaning Spirit of The Wood.\n\nSylvia is the Roman goddess of the forest.\n\nSylvia is also a framework created to give you the abstraction-focused and\nscalable solution for building your CosmWasm Smart Contracts. Find your way\ninto the forest of Cosmos ecosystem. We provide you with the toolset, so instead\nof focusing on the raw structure of your contract, you can create it in proper\nand idiomatic Rust and then just let cargo make sure that they are sound.\n\nLearn more about `sylvia` in [the book](https://cosmwasm.github.io/sylvia-book/index.html)\n\n## Sylvia contract template\n\nThe Sylvia template streamlines the development of CosmWasm smart contracts by providing a project scaffold that adheres to best practices and leverages the Sylvia framework's powerful features. It's designed to help developers focus more on their contract's business logic rather than boilerplate code.\n\nLearn more here: [Sylvia Template on GitHub](https://github.com/CosmWasm/sylvia-template)\n\n## The approach\n\n[CosmWasm](https://cosmwasm.com/) ecosystem core provides the base building\nblocks for smart contracts - the\n[cosmwasm-std](https://crates.io/crates/cosmwasm-std) for basic CW bindings, the\n[cw-storage-plus](https://crates.io/crates/cw-storage-plus) for easier state management,\nand the [cw-multi-test](https://crates.io/crates/cw-multi-test) for testing them.\nSylvia framework is built on top of them, so for creating contracts, you don't\nhave to think about message structure, how their API is (de)serialized, or how\nto handle message dispatching. Instead, the API of your contract is a set of\ntraits you implement on your contract type. The framework generates things like entry\npoint structures, functions dispatching the messages, or even helpers for multitest.\nIt allows for better control of interfaces, including validating their completeness\nin compile time.\n\n## Code generation\n\nSylvia macros generate code in the `sv` module. This means that every `contract` and\n`interface` macro call must be made in a separate module to avoid collisions between\nthe generated modules.\n\n## Contract type\n\nIn Sylvia, we define our contracts as structures:\n\n```rust\nuse cw_storage_plus::Item;\nuse cosmwasm_schema::cw_serde;\nuse sylvia::types::QueryCtx;\nuse sylvia::cw_std::ensure;\n\n\n/// Our new contract type.\n///\nstruct MyContract\u003c'a\u003e {\n    pub counter: Item\u003c'a, u64\u003e,\n}\n\n\n/// Response type returned by the\n/// query method.\n/// \n#[cw_serde]\npub struct CounterResp {\n    pub counter: u64,\n}\n\n#[entry_points]\n#[contract]\n#[sv::error(ContractError)]\nimpl MyContract\u003c'_\u003e {\n    pub fn new() -\u003e Self {\n        Self {\n            counter: Item::new(\"counter\")\n        }\n    }\n\n    #[sv::msg(instantiate)]\n    pub fn instantiate(\u0026self, ctx: InstantiateCtx, counter: u64) -\u003e StdResult\u003cResponse\u003e {\n        self.counter.save(ctx.deps.storage, \u0026counter)?;\n        Ok(Response::new())\n    }\n\n    #[sv::msg(exec)]\n    pub fn increment(\u0026self, ctx: ExecCtx) -\u003e Result\u003cResponse, ContractError\u003e {\n        let counter = self.counter.load(ctx.deps.storage)?;\n        ensure!(counter \u003c 10, ContractError::LimitReached);\n        self.counter.save(ctx.deps.storage, \u0026(counter + 1))?;\n        Ok(Response::new())\n    }\n\n    #[sv::msg(query)]\n    pub fn counter(\u0026self, ctx: QueryCtx) -\u003e StdResult\u003cCounterResp\u003e {\n        self\n            .counter\n            .load(ctx.deps.storage)\n            .map(|counter| CounterResp { counter })\n    }\n}\n```\n\nSylvia will generate the following new structures:\n\n```rust\npub mod sv {\n    use super::*;\n\n    struct InstantiateMsg {\n        counter: u64,\n    }\n\n    enum ExecMsg {\n        Increment {}\n    }\n\n    enum ContractExecMsg {\n        MyContract(ExecMsg)\n    }\n\n    enum QueryMsg {\n        Counter {}\n    }\n\n    enum ContractQueryMsg {\n        MyContract(QueryMsg)\n    }\n\n    // [...]\n}\n\npub mod entry_points {\n    use super::*;\n\n    #[sylvia::cw_std::entry_point]\n    pub fn instantiate(\n        deps: sylvia::cw_std::DepsMut,\n        env: sylvia::cw_std::Env,\n        info: sylvia::cw_std::MessageInfo,\n        msg: InstantiateMsg,\n    ) -\u003e Result\u003csylvia::cw_std::Response, StdError\u003e {\n        msg.dispatch(\u0026MyContract::new(), (deps, env, info))\n            .map_err(Into::into)\n    }\n\n    // [...]\n}\n```\n\n`entry_points` macro generates `instantiate`, `execute`, `query` and `sudo` entry points.\nAll those methods call `dispatch` on the msg received and run proper logic defined for the sent\nvariant of the message.\n\nWhat is essential - the field in the `InstantiateMsg` (and other messages) gets the same name as the\nfunction argument.\n\nThe `ExecMsg` is the primary one you may use to send messages to the contract.\nThe `ContractExecMsg` is only an additional abstraction layer that would matter\nlater when we define traits for our contract.\nThanks to the `entry_point` macro it is already being used in the generated entry point and we don't\nhave to do it manually.\n\nWhat you might notice - we can still use `StdResult` (so `StdError`) if we don't\nneed `ContractError` in a particular function. What is important is that the returned\nresult type has to implement `Into\u003cContractError\u003e`, where `ContractError` is a contract\nerror type - it will all be commonized in the generated dispatching function (so\nentry points have to return `ContractError` as its error variant).\n\n\n## Interfaces\n\nOne of the fundamental ideas of the Sylvia framework is the interface, allowing the\ngrouping of messages into their semantical groups. Let's define a Sylvia interface:\n\n```rust\npub mod group {\n    use super::*;\n    use sylvia::interface;\n    use sylvia::types::ExecCtx;\n    use sylvia::cw_std::StdError;\n\n    #[cw_serde]\n    pub struct IsMemberResp {\n        pub is_member: bool,\n    }\n\n    #[interface]\n    pub trait Group {\n        type Error: From\u003cStdError\u003e;\n\n        #[sv::msg(exec)]\n        fn add_member(\u0026self, ctx: ExecCtx, member: String) -\u003e Result\u003cResponse, Self::Error\u003e;\n\n        #[sv::msg(query)]\n        fn is_member(\u0026self, ctx: QueryCtx, member: String) -\u003e Result\u003cIsMemberResp, Self::Error\u003e;\n    }\n}\n```\n\nThen we need to implement the trait on the contract type:\n\n```rust\nuse sylvia::cw_std::{Empty, Addr};\nuse cw_storage_plus::{Map, Item};\n\npub struct MyContract\u003c'a\u003e {\n    counter: Item\u003c'a, u64\u003e,\n    // New field added - remember to initialize it in `new`\n    members: Map\u003c'a, \u0026'a Addr, Empty\u003e,\n}\n\nimpl group::Group for MyContract\u003c'_\u003e {\n    type Error = ContractError;\n\n    fn add_member(\u0026self, ctx: ExecCtx, member: String) -\u003e Result\u003cResponse, ContractError\u003e {\n        let member = ctx.deps.api.addr_validate(\u0026member)?;\n        self.members.save(ctx.deps.storage, \u0026member, \u0026Empty {})?;\n        Ok(Response::new())\n    }\n\n    fn is_member(\u0026self, ctx: QueryCtx, member: String) -\u003e Result\u003cgroup::IsMemberResp, ContractError\u003e {\n        let is_member = self.members.has(ctx.deps.storage, \u0026Addr::unchecked(\u0026member));\n        let resp = group::IsMemberResp {\n            is_member,\n        };\n\n        Ok(resp)\n    }\n}\n\n#[contract]\n#[sv::messages(group as Group)]\nimpl MyContract\u003c'_\u003e {\n    // Nothing changed here\n}\n```\n\nFirst, note that I defined the interface trait in its separate module with a name\nmatching the trait name, but written \"snake_case\" instead of CamelCase. Here I have the\n`group` module for the `Group` trait, but the `CrossStaking` trait should be placed\nin its own `cross_staking` module (note the underscore). This is a requirement right\nnow - Sylvia generates all the messages and boilerplate in this module and will try\nto access them through this module. If the interface's name is a camel-case\nversion of the last module path's segment, the `as InterfaceName` can be omitted.\nF.e. `#[sv::messages(cw1 as Cw1)]` can be reduced to `#[sv::messages(cw1)]`\n\nThen there is the `Error` type embedded in the trait - it is also needed there,\nand the trait bound here has to be at least `From\u003cStdError\u003e`, as Sylvia might\ngenerate code returning the `StdError` in deserialization/dispatching implementation.\nThe trait can be more strict - this is the minimum.\n\nFinally, the implementation block has an additional\n`#[sv::messages(module as Identifier)]` attribute. Sylvia needs it to generate the dispatching\nproperly - there is the limitation that every macro has access only to its local\nscope. In particular - we cannot see all traits implemented by a type and their\nimplementation from the `#[contract]` crate.\n\nTo solve this issue, we put this `#[sv::messages(...)]` attribute pointing to Sylvia\nwhat is the module name where the interface is defined, and giving a unique name\nfor this interface (it would be used in generated code to provide proper enum variant).\n\n## Macro attributes\n\n```rust\nstruct MyMsg;\nimpl CustomMsg for MyMsg {}\n\nstruct MyQuery;\nimpl CustomQuery for MyMsg {}\n\n#[entry_point]\n#[contract]\n#[sv::error(ContractError)]\n#[sv::messages(interface as Interface)]\n#[sv::messages(interface as InterfaceWithCustomType: custom(msg, query))]\n#[sv::custom(msg=MyMsg, query=MyQuery)]\n#[sv::msg_attr(exec, PartialOrd)]\n#[sv::override_entry_point(sudo=crate::entry_points::sudo(crate::SudoMsg))]\nimpl MyContract {\n    // ...\n    #[sv::msg(query)]\n    #[sv::attr(serde(rename(serialize = \"CustomQueryMsg\")))]\n    fn query_msg(\u0026self, _ctx: QueryCtx) -\u003e StdResult\u003cResponse\u003e {\n        // ...\n    }\n}\n```\n\n * `sv::error` is used by both `contract` and `entry_point` macros. It is necessary in case a custom\n   error is being used by your contract. If omitted generated code will use `StdError`.\n\n * `sv::messages` is the attribute for the `contract` macro. Its purpose is to inform Sylvia\n   about interfaces implemented for the contract. If the implemented interface does not use a\n   default `Empty` message response for query and/or exec then the `: custom(query)`,\n   `: custom(msg)` or `: custom(msg, query)` should be indicated.\n\n * `sv::override_entry_point` - refer to the `Overriding entry points` section.\n\n * `sv::custom` allows to define CustomMsg and CustomQuery for the contract. By default generated code\n    will return `Response\u003cEmpty\u003e` and will use `Deps\u003cEmpty\u003e` and `DepsMut\u003cEmpty\u003e`.\n\n * `sv::msg_attr` forwards any attribute to the message's type.\n\n * `sv::attr` forwards any attribute to the enum's variant.\n\n\n## Usage in external crates\n\nWhat is important is the possibility of using generated code in the external code.\nFirst, let's start with generating the documentation of the crate:\n\n```sh\ncargo doc --document-private-items --open\n```\n\nThis generates and opens documentation of the crate, including all generated structures.\n`--document-private-item` is optional, but it will generate documentation of non-public\nmodules which is sometimes useful.\n\nGoing through the doc, you will see that all messages are generated in their structs/traits\nmodules. To send messages to the contract, we can just use them:\n\n```rust\nuse sylvia::cw_std::{WasmMsg, to_json_binary};\n\nfn some_handler(my_contract_addr: String) -\u003e StdResult\u003cResponse\u003e {\n    let msg = my_contract_crate::sv::ExecMsg::Increment {};\n    let msg = WasmMsg::ExecMsg {\n        contract_addr: my_contract_addr,\n        msg: to_json_binary(\u0026msg)?,\n        funds: vec![],\n    }\n\n    let resp = Response::new()\n        .add_message(msg);\n    Ok(resp)\n}\n```\n\nWe can use messages from traits in a similar way:\n\n```rust\nlet msg = my_contract_crate::group::QueryMsg::IsMember {\n    member: addr,\n};\n\nlet is_member: my_contract_crate::group::IsMemberResp =\n    deps.querier.query_wasm_smart(my_contract_addr, \u0026msg)?;\n```\n\nIt is important not to confuse the generated `ContractExecMsg/ContractQueryMsg`\nwith `ExecMsg/QueryMsg` - the former is generated only for contract, not for interfaces,\nand is not meant to be used to send messages to the contract - their purpose is for proper\nmessages dispatching only, and should not be used besides the entry points.\n\n\n## Query helpers\n\nTo make querying more user-friendly `Sylvia` provides users with `sylvia::types::BoundQuerier` and \n`sylvia::types::Remote` helpers. The latter is meant to store the address of some remote contract.\nFor each query method in the contract, Sylvia will add a method in a generated `sv::Querier` trait.\nThe `sv::Querier` is then implemented for `sylvia::types::BoundQuerier` so the user can call the method.\n\nLet's modify the query from the previous paragraph. Currently, it will look as follows:\n\n```rust\nlet is_member = Remote::\u003cOtherContractType\u003e::new(remote_addr)\n    .querier(\u0026ctx.deps.querier)\n    .is_member(addr)?;\n```\n\nYour contract might communicate with some other contract regularly.\nIn such a case you might want to store it as a field in your Contract:\n\n```rust\npub struct MyContract\u003c'a\u003e {\n    counter: Item\u003c'a, u64\u003e,\n    members: Map\u003c'a, \u0026'a Addr, Empty\u003e,\n    remote: Item\u003c'a, Remote\u003c'static, OtherContractType\u003e\u003e,\n}\n\n#[sv::msg(exec)]\npub fn evaluate_member(\u0026self, ctx: ExecCtx, ...) -\u003e StdResult\u003cResponse\u003e {\n    let is_member = self\n        .remote\n        .load(ctx.deps.storage)?\n        .querier(\u0026ctx.deps.querier)\n        .is_member(addr)?;\n}\n```\n\n\n## Executor message builder\n\nSylvia defines the\n[`ExecutorBuilder`](https://docs.rs/sylvia/latest/sylvia/types/struct.ExecutorBuilder.html)\ntype, which can be accessed through\n[`Remote::executor`](https://docs.rs/sylvia/latest/sylvia/types/struct.Remote.html#method.executor).\nIt's generic over the contract type and exposes execute methods from the\ncontract and every interface implemented on it through an auto-generated `Executor` traits.\nExecute messages of other contracts can be built with `Remote` as well by\ncalling `executor` method. It returns a message builder that implements\nauto-generated `Executor` traits of all Sylvia contracts.\nMethods defined in the `Executor` traits constructs an execute message,\nwhich variant corresponds to the method name.\nThe message is then wrapped in the `WasmMsg`, and returned once\n[`ExecutorBuilder::build()`](https://docs.rs/sylvia/latest/sylvia/types/struct.ExecutorBuilder.html#method.build)\nmethod is called.\n\n```rust\nuse sylvia::types::Remote;\nuse other_contract::contract::OtherContract;\nuse other_contract::contract::sv::Executor;\n\nlet some_exec_msg: WasmMsg = Remote::\u003cOtherContract\u003e::new(remote_addr)\n    .executor()\n    .some_exec_method()?\n    .build();\n```\n\n## Using unsupported entry points\n\nIf there's a need for an entry point that is not implemented in Sylvia, you can implement\nit manually using the `#[entry_point]` macro. As an example, let's see how to implement\nreplies for messages:\n\n```rust\nuse sylvia::cw_std::{DepsMut, Env, Reply, Response};\n\n#[contract]\n#[entry_point]\n#[sv::error(ContractError)]\n#[sv::messages(group as Group)]\nimpl MyContract\u003c'_\u003e {\n    fn reply(\u0026self, deps: DepsMut, env: Env, reply: Reply) -\u003e Result\u003cResponse, ContractError\u003e {\n        todo!()\n    }\n    // [...]\n}\n\n#[entry_point]\nfn reply(deps: DepsMut, env: Env, reply: Reply) -\u003e Result\u003cResponse, ContractError\u003e {\n    \u0026MyContract::new().reply(deps, env, reply)\n}\n```\n\nIt is important to create an entry function in the contract type - this way, it\ngains access to all the state accessors defined on the type.\n\n## Overriding entry points\n\nThere is a way to override an entry point or to add a custom-defined one.\nLet's consider the following code:\n\n```rust\n#[cw_serde]\npub enum UserExecMsg {\n    IncreaseByOne {},\n}\n\npub fn increase_by_one(ctx: ExecCtx) -\u003e StdResult\u003cResponse\u003e {\n    crate::COUNTER.update(ctx.deps.storage, |count| -\u003e Result\u003cu32, StdError\u003e {\n        Ok(count + 1)\n    })?;\n    Ok(Response::new())\n}\n\n#[cw_serde]\npub enum CustomExecMsg {\n    ContractExec(crate::ContractExecMsg),\n    CustomExec(UserExecMsg),\n}\n\nimpl CustomExecMsg {\n    pub fn dispatch(self, ctx: (DepsMut, Env, MessageInfo)) -\u003e StdResult\u003cResponse\u003e {\n        match self {\n            CustomExecMsg::ContractExec(msg) =\u003e {\n                msg.dispatch(\u0026crate::contract::Contract::new(), ctx)\n            }\n            CustomExecMsg::CustomExec(_) =\u003e increase_by_one(ctx.into()),\n        }\n    }\n}\n\n#[entry_point]\npub fn execute(\n    deps: DepsMut,\n    env: Env,\n    info: MessageInfo,\n    msg: CustomExecMsg,\n) -\u003e StdResult\u003cResponse\u003e {\n    msg.dispatch((deps, env, info))\n}\n```\n\nIt is possible to define a custom `exec` message that will dispatch over one generated\nby your contract and one defined by you. To use this custom entry point with `contract` macro\nyou can add the `sv::override_entry_point(...)` attribute.\n\n```rust    \n#[contract]\n#[sv::override_entry_point(exec=crate::entry_points::execute(crate::exec::CustomExecMsg))]\n#[sv::override_entry_point(sudo=crate::entry_points::sudo(crate::SudoMsg))]\nimpl Contract {\n    // ...\n}\n```\n\nIt is possible to override all message types like that. Next to the entry point path, you will\nalso have to provide the type of your custom message. It is required to deserialize the message\nin the `multitest helpers`.\n\n## Multitest\n\nSylvia also generates some helpers for testing contracts - it is hidden behind the\n`mt` feature flag, which has to be enabled.\n\nIt is important to ensure no `mt` flag is set when the contract is built in `wasm`\ntarget because of some dependencies it uses, which are not buildable on Wasm. The\nrecommendation is to add an extra `sylvia` entry with `mt` enabled in the\n`dev-dependencies`, and also add the `mt` feature on your contract, which enables\nmt utilities in other contract tests. An example `Cargo.toml`:\n\n```toml\n[package]\nname = \"my-contract\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[lib]\ncrate-type = [\"cdylib\", \"rlib\"]\n\n[features]\nlibrary = []\nmt = [\"sylvia/mt\"]\n\n[dependencies]\nsylvia = \"0.10.0\"\n\n# [...]\n\n[dev-dependencies]\nsylvia = { version = \"0.10.0\", features = [\"mt\"] }\n```\n\nAnd the example code:\n\n```rust\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use sylvia::multitest::App;\n\n    #[test]\n    fn counter_test() {\n        let app = App::default();\n\n        let owner = \"owner\";\n\n        let code_id = contract::CodeId::store_code(\u0026app);\n\n        let contract = code_id.instantiate(3)\n            .with_label(\"My contract\")\n            .call(\u0026owner)\n            .unwrap();\n\n        let counter = contract.counter().unwrap();\n        assert_eq!(counter, contract::CounterResp { counter: 3});\n\n        contract.increment().call(\u0026owner).unwrap();\n\n        let counter = contract.counter().unwrap();\n        assert_eq!(counter, contract::CounterResp { counter: 4});\n    }\n}\n```\n\nNote the `contract` module I am using here - it is a slight change\nthat doesn't match the previous code - I assume here that all the contract code\nsits in the `contract` module to make sure it is clear where the used type lies.\nSo if I use `contract::something`, it is `something` in the module of the original\ncontract (most probably Sylvia-generated).\n\nFirst of all - we do not use `cw-multi-test` app directly. Instead, we use the `sylvia`\nwrapper over it. It contains the original multi-test App internally, but it does\nit in an internally mutable manner which makes it possible to avoid passing it\neverywhere around. It adds some overhead, but it should not matter for testing code.\n\nWe are first using the `CodeId` type generated for every single Sylvia contract\nseparately. Its purpose is to abstract storing the contract in the blockchain. It\nmakes sure to create the contract object and pass it to the multitest.\n\nA contract's `CodeId` type has one particularly interesting function - the `instantiate`,\nwhich calls an instantiation function. It takes the same arguments as an instantiation\nfunction in the contract, except for the context that Sylvia's utilities would provide.\n\nThe function doesn't instantiate contract immediately - instead, it returns what\nis called `InstantiationProxy`. We decided that we don't want to force users to set\nall the metadata - admin, label, and funds to send with every instantiation call,\nas in the vast majority of cases, they are irrelevant. Instead, the\n`InstantiationProxy` provides `with_label`, `with_funds`, and `with_amin` functions,\nwhich set those meta fields in the builder pattern style.\n\nWhen the instantiation is ready, we call the `call` function, passing the message\nsender - we could add another `with_sender` function, but we decided that as the\nsender has to be passed every single time, we can save some keystrokes on that.\n\nThe thing is similar when it comes to execution messages. The biggest difference\nis that we don't call it on the `CodeId`, but on instantiated contracts instead.\nWe also have fewer fields to set on that - the proxy for execution provides only\nthe `with_funds` function.\n\nAll the instantiation and execution functions return the\n`Result\u003ccw_multi_test::AppResponse, ContractError\u003e` type, where `ContractError`\nis an error type of the contract.\n\n\n## Interface items in multitest\n\nTrait declaring all the interface methods is directly implemented on\nthe contracts Proxy type.\n\n```rust\nuse contract::mt::Group;\n\n#[test]\nfn member_test() {\n    let app = App::default();\n\n    let owner = \"owner\";\n    let member = \"john\";\n\n    let code_id = contract::mt::CodeId::store_code(\u0026app);\n\n    let contract = code_id.instantiate(0)\n        .with_label(\"My contract\")\n        .call(\u0026owner);\n\n    contract\n        .add_member(member.to_owned())\n        .call(\u0026owner);\n\n    let resp = contract\n        .is_member(member.to_owned())\n\n    assert_eq!(resp, group::IsMemberResp { is_member: true });\n}\n```\n\n## Generics\n\n### Interface\n\nDefining associated types on an interface is as simple as defining them on a regular trait.\n\n```rust\n#[interface]\npub trait Generic {\n    type Error: From\u003cStdError\u003e;\n    type ExecParam: CustomMsg;\n    type QueryParam: CustomMsg;\n    type RetType: CustomMsg;\n\n    #[sv::msg(exec)]\n    fn generic_exec(\n        \u0026self,\n        ctx: ExecCtx,\n        msgs: Vec\u003cCosmosMsg\u003cSelf::ExecParam\u003e\u003e,\n    ) -\u003e Result\u003cResponse, Self::Error\u003e;\n\n    #[sv::msg(query)]\n    fn generic_query(\u0026self, ctx: QueryCtx, param: Self::QueryParam) -\u003e Result\u003cSelf::RetType, Self::Error\u003e;\n}\n```\n\n### Generic contract\n\nGenerics in a contract might be either used as generic field types or as generic parameters of return\ntypes in the messages. When Sylvia generates the messages' enums, only generics used in respective methods\nwill be part of a given generated message type.\n\n\nExample of usage:\n```rust\npub struct GenericContract\u003c\n    InstantiateParam,\n    ExecParam,\n    FieldType,\n\u003e {\n    _field: Item\u003c'static, FieldType\u003e,\n    _phantom: std::marker::PhantomData\u003c(\n        InstantiateParam,\n        ExecParam,\n    )\u003e,\n}\n\n#[contract]\nimpl\u003cInstantiateParam, ExecParam, FieldType\u003e\n    GenericContract\u003cInstantiateParam, ExecParam, FieldType\u003e\nwhere\n    for\u003c'msg_de\u003e InstantiateParam: CustomMsg + Deserialize\u003c'msg_de\u003e + 'msg_de,\n    ExecParam: CustomMsg + DeserializeOwned + 'static,\n    FieldType: 'static,\n{\n    pub const fn new() -\u003e Self {\n        Self {\n            _field: Item::new(\"field\"),\n            _phantom: std::marker::PhantomData,\n        }\n    }\n\n    #[sv::msg(instantiate)]\n    pub fn instantiate(\n        \u0026self,\n        _ctx: InstantiateCtx,\n        _msg: InstantiateParam,\n    ) -\u003e StdResult\u003cResponse\u003e {\n        Ok(Response::new())\n    }\n\n    #[sv::msg(exec)]\n    pub fn contract_execute(\n        \u0026self,\n        _ctx: ExecCtx,\n        _msg: ExecParam,\n    ) -\u003e StdResult\u003cResponse\u003e {\n        Ok(Response::new())\n    }\n}\n```\n\n### Generics in entry_points\n\nEntry points have to be generated with concrete types. Using the `entry_points` macro\non the generic contract we have to specify the types that have to be used.\nWe do that with `entry_points(generics\u003c..\u003e)`:\n\n```rust\n#[cfg_attr(not(feature = \"library\"), entry_points(generics\u003cSvCustomMsg, SvCustomMsg, SvCustomMsg\u003e))]\n#[contract]\nimpl\u003cInstantiateParam, ExecParam, FieldType\u003e\n    GenericContract\u003cInstantiateParam, ExecParam, FieldType\u003e\nwhere\n    for\u003c'msg_de\u003e InstantiateParam: CustomMsg + Deserialize\u003c'msg_de\u003e + 'msg_de,\n    ExecParam: CustomMsg + DeserializeOwned + 'static,\n    FieldType: 'static,\n{\n    ...\n}\n```\n\nThe contract might define a generic type in place of a custom message and query.\nIn such case we have to inform `entry_points` macro using `custom`:\n\n```rust\n#[cfg_attr(not(feature = \"library\"), entry_points(generics\u003cSvCustomMsg, SvCustomMsg, SvCustomMsg\u003e, custom(msg=SvCustomMsg, query=SvCustomQuery))]\n#[contract]\n#[sv::custom(msg=MsgT, query=QueryT)]\nimpl\u003cInstantiateParam, ExecParam, FieldType, MsgT, QueryT\u003e\n    GenericContract\u003cInstantiateParam, ExecParam, FieldType, MsgT, QueryT\u003e\nwhere\n    for\u003c'msg_de\u003e InstantiateParam: CustomMsg + Deserialize\u003c'msg_de\u003e + 'msg_de,\n    ExecParam: CustomMsg + DeserializeOwned + 'static,\n    FieldType: 'static,\n{\n    ...\n}\n```\n\n\n## Generating schema\n\nSylvia is designed to generate all the code that `cosmwasm-schema` relies on - this\nmakes it very easy to generate schema for the contract. Just add a `bin/schema.rs`\nmodule, which would be recognized as a binary, and add a simple main function there:\n\n```rust\nuse cosmwasm_schema::write_api;\n\nuse my_contract_crate::contract::{ContractExecMsg, ContractQueryMsg, InstantiateMsg};\n\nfn main() {\n    write_api! {\n        instantiate: InstantiateMsg,\n        execute: ContractExecMsg,\n        query: ContractQueryMsg,\n    }\n}\n```\n\n## Road map\n\nSylvia is in the adoption stage right now, but we are still working on more and more\nfeatures for you. Here is a rough roadmap for the coming months:\n\n- Replies - Sylvia still needs support for essential CosmWasm messages, which are\n  replies. We want to make them smart, so expressing the correlation between the sent\n  message and the executed handler is more direct and not hidden in the reply dispatcher.\n- Migrations - Another important message we don't support, but the reason is similar\n  to replies - we want them to be smart. We want to give you a nice way to provide\n  upgrading Api for your contract, which would take care of its versioning.\n- IBC - we want to give you a nice IBC Api too! However, expect it to be a\n  while - we must first understand the best patterns here.\n- Better tooling support - The biggest Sylvia issue is that the code it generates\n  is not trivial, and not all the tooling handles it well. We are working on improving\n  user experience in that regard.\n\n## Troubleshooting\n\nFor more descriptive error messages, consider using the nightly toolchain (add `+nightly`\nargument for cargo)\n\n- Missing messages from an interface on your contract - You may be missing the\n  `#[sv::messages(interface as Interface)]` attribute.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCosmWasm%2Fsylvia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FCosmWasm%2Fsylvia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCosmWasm%2Fsylvia/lists"}