From 0f6a232503d771b31d620b549920952f32800cc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wo=C5=BAniak?= Date: Fri, 2 Feb 2024 12:36:38 +0100 Subject: [PATCH 1/2] docs: Update MIGRATING.md regarding 0.10.0 --- MIGRATING.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/MIGRATING.md b/MIGRATING.md index a62e540b..b32556b9 100644 --- a/MIGRATING.md +++ b/MIGRATING.md @@ -2,6 +2,28 @@ This guide explains what is needed to upgrade contracts when migrating over major releases of `sylvia`. Note that you can also view the [complete CHANGELOG](https://github.com/CosmWasm/sylvia/blob/main/CHANGELOG.md) to understand the differences. +## 0.9.3 -> 0.10.0 + +## Multitest proxy + +Since `0.10.0` Sylvia won't generate multitest Proxy types for `interface` macro call. Instead all the methods from interfaces are directly implemented on the contract's multitest proxy. +To use methods from a implemented interface like before user has to import the multitest trait from module in which the interface is implemented. + +```diff +-let resp = contract +- .cw1_proxy() +- .can_execute() +- .unwrap(); ++let resp = contract ++ .can_execute() ++ .unwrap(); +``` + +## Associated types in generics + +`Sylvia` interface is meant to be implemented on contract only a single time. Because of that we decided to remove support for generics in interfaces. +Instead migrating from `0.9.3` to `0.10.0` generics have to be changed to associated types. + ## 0.8.1 -> 0.9.0 ### `sv` module From 09ab54c50611f9086599197e6a77e21d1a663622 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Wo=C5=BAniak?= Date: Fri, 2 Feb 2024 16:34:49 +0100 Subject: [PATCH 2/2] docs: Update README --- README.md | 127 +++++++++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index f00b2c44..4af5b9b4 100644 --- a/README.md +++ b/README.md @@ -352,7 +352,7 @@ pub struct MyContract<'a> { #[messages(group as Group)] // Alternatively: // It's not needed to provide the interface's -// name if it's corresponds to the last segment +// name if it corresponds to the last segment // of the module path: // #[messages(group)] impl group::Group for MyContract<'_> { @@ -489,11 +489,8 @@ will return `Response` and will use `Deps` and `DepsMut`. ## Single module per macro -Generated items and namespaces may overlap and it is suggested to split all macro calls -into separate modules. -This could also improve the project readability as it would end up split between semantical parts -and save maintainers from possible adjustment in case of new features being introduced in the -future. +Sylvia macros generate code in the `sv` module. This means that every single macro call +has to be done in a separate module or the generated `sv` modules will overlap. ## Usage in external crates @@ -839,8 +836,11 @@ is an error type of the contract. ## Interface items in multitest -Because of implementation restrictions, calling methods from the contract interface -look slightly different: +Before `0.10.0` user has to call additional `_proxy()` method before calling +interfaces methods. +Since `0.10.0` `interface` macro does not generate it's own Proxy type. +Instead trait declaring all the interface methods is directly implemented on +the contracts Proxy type. ```rust use contract::multitest_utils::Group; @@ -859,22 +859,24 @@ fn member_test() { .call(owner); contract - .group_proxy() .add_member(member.to_owned()) .call(owner); let resp = contract - .group_proxy() .is_member(member.to_owned()) assert_eq!(resp, group::IsMemberResp { is_member: true }); } ``` -Note an additional `group_proxy()` call for executions and queries - it returns an -extra proxy wrapper that would send the messages from a particular interface. I also -had to add trait with group-related methods - it is named in the same way as the -original `Group` trait, but lies in `multitest_utils` module of the contract. +Pre `0.10.0`: + +```diff +contract ++ .cw1_proxy() + .add_member(member.to_owned()) + .call(owner); +``` ## CustomQuery and CustomMsg @@ -936,62 +938,36 @@ will be used to determine `CustomMsg` and/or `CustomQuery`. ## Generics -Since `0.9.0` we can use generics next to the `sylvia` macros. -It is possible to define both generic contract and generic interface. +Since `0.9.0` we can use generics in interfaces and contracts. +Since `0.10.0` support for generics in interfaces was replaced with +support for associated types. This change was made because only a single implementation +of interface is allowed per contract. This is a more idiomatic rust approach. +`0.10.0` introduced also support for generics forwarding. This means that if a contract +defines some generic types, you can assign them to the associated types while implementing +an interface. -### Generic interface +### Interface -Defining generic interface is as simple as defining a generic trait. +Defining associated types on interface is as simple as defining a them on a regular trait. ```rust #[interface] -pub trait Generic -where - for<'msg_de> ExecParam: CustomMsg + Deserialize<'msg_de>, - QueryParam: sylvia::types::CustomMsg, - RetType: CustomMsg + DeserializeOwned, +pub trait Generic { type Error: From; + type ExecParam: CustomMsg; + type QueryParam: CustomMsg; + type RetType: CustomMsg; #[msg(exec)] fn generic_exec( &self, ctx: ExecCtx, - msgs: Vec>, + msgs: Vec>, ) -> Result; #[msg(query)] - fn generic_query(&self, ctx: QueryCtx, param: QueryParam) -> Result; -} -``` - -We can also use generics with `custom`. In such case we have to provide the generic -type name to the `sv::custom(..)` attribute. - -```rust -#[interface] -#[sv::custom(msg=RetType)] -pub trait CustomAndGeneric -where - for<'msg_de> ExecParam: CustomMsg + Deserialize<'msg_de>, - QueryParam: sylvia::types::CustomMsg, - RetType: CustomMsg + DeserializeOwned, -{ - type Error: From; - - #[msg(exec)] - fn custom_generic_execute( - &self, - ctx: ExecCtx, - msgs: Vec>, - ) -> Result, Self::Error>; - - #[msg(query)] - fn custom_generic_query( - &self, - ctx: QueryCtx, - param: QueryParam, - ) -> Result; + fn generic_query(&self, ctx: QueryCtx, param: Self::QueryParam) -> Result; } ``` @@ -1052,15 +1028,15 @@ where ### Implement interface -To implement generic interface we have to provide solid types for the interface -generics. No additional attributes are required. +Rust will force the user to specify the types of the associates during the implementation. +We can either use some concrete types here or forward the generics defined on contract. ```rust #[contract(module = crate::contract)] #[messages(generic as Generic)] #[sv::custom(msg=SvCustomMsg)] impl - Generic + Generic for crate::contract::GenericContract< InstantiateParam, ExecParam, @@ -1068,12 +1044,15 @@ impl > { type Error = StdError; + type ExecParam = ExecParam; + type QueryParam: SvCustomMsg; + type RetType = SvCustomMsg; #[msg(exec)] fn generic_exec( &self, _ctx: ExecCtx, - _msgs: Vec>, + _msgs: Vec>, ) -> StdResult { Ok(Response::new()) } @@ -1082,19 +1061,19 @@ impl fn generic_query( &self, _ctx: QueryCtx, - _msg: sylvia::types::SvCustomMsg, - ) -> StdResult { + _msg: Self::QueryParam, + ) -> StdResult { Ok(SvCustomMsg {}) } } ``` -Then we have to inform `sylvia` about the generics used while implementing +Then we have to inform `sylvia` about the types used while implementing interface in the main `contract` macro call: ```rust #[contract] -#[messages(generic as Generic)] +#[messages(generic as Generic)] impl GenericContract where @@ -1102,6 +1081,7 @@ where ExecParam: CustomMsg + DeserializeOwned + 'static, FieldType: 'static, { + ... } ``` @@ -1109,7 +1089,7 @@ where Entry points has to be generated with solid types. Using the `entry_points` macro on the generic contract we have to specify the types that has to be used. -We do that by via `entry_points(generics<..>)`: +We do that with `entry_points(generics<..>)`: ```rust #[cfg_attr(not(feature = "library"), entry_points(generics))] @@ -1125,6 +1105,25 @@ where } ``` +Also the contract might define generic type in place of custom message and query. +In such case we have to inform `entry_points` macro using `custom`: + +```rust +#[cfg_attr(not(feature = "library"), entry_points(generics, custom(msg=SvCustomMsg, query=SvCustomQuery))] +#[contract] +#[sv::custom(msg=MsgT, query=QueryT)] +impl + GenericContract +where + for<'msg_de> InstantiateParam: CustomMsg + Deserialize<'msg_de> + 'msg_de, + ExecParam: CustomMsg + DeserializeOwned + 'static, + FieldType: 'static, +{ + ... +} +``` + + ## Generating schema Sylvia is designed to generate all the code which cosmwasm-schema relies on - this