Sylvia 1.0.0

Jan Woźniak
Confio
Published in
4 min readMar 29, 2024

We are happy to introduce two releases of Sylvia: 0.10.0 and the first major release, 1.0.0, distinct from the 0.10.0 with support for the CosmWasm 2.0.0.

As always, we recommend checking the Sylvia-book and the documentation to learn how to use Sylvia.

Major features

We worked on expanding some features we already established and providing new ones for this release.

Associated types

In 0.9.0, we provided support for generics in interfaces. Since 0.10.0 we removed this support in favor of using the associated types. This is the more idiomatic way to approach generic types in Rust since Sylvia interfaces can be implemented only a single time per contract.

Associated type in the interface

With these changes, we also delivered the promised functionality to link generics from the contracts to interfaces implementing them.

Link contract generics with interface

Note the lack of #[contract] macro call. More on that later.

Sudo support

Sylvia now supports the sudo message on both contract and interface macros. You can define them the same way as you would query and execute.

Minor features and improvements

With those changes, we introduced some other minor ones.

Improved errors

We worked on improving the errors in Sylvia to make it as verbose as possible and intuitive to use. There is still a lot to do in upcoming releases, but we hope to improve the user experience with this release.

Querier implemented on App

Querier is now directly implemented on the App. Now, instead of calling wrap on underlying cw_multi_test::App to create QuerierWrapper, you can call a new querier method.

- app.app().wrap()
+ app.querier()

This change is a part of our goal for App to mimic cw_multi_test::App .

Interface proxy trait implemented on contract Proxy

In previous versions, interfaces generated their Proxy types to allow calling messages in Multitest.

Now, no such thing is being generated; instead, you can directly call interface messages on Proxy.

 let resp = contract
- .cw20_allowances_proxy()
.all_allowances(owner.to_string(), None, None)
.unwrap();

Other API changes

Since Sylvia was in the development phase, we constantly shaped the API to provide the best experience for the users and adapt to numerous new features. Here are some major changes present in 0.10.0 and 1.0.0.

Sylvia attributes

If you are a Sylvia user, you might notice that we now use sv prefix before the msg attribute. This applies to every attribute in Sylvia. We don’t want to get in the way of any other attributes the user might use, and we want to distinguish our attributes

#[sylvia::contract]
- #[messages(...)]
+ #[sv::messages(...)]
- #[custom(...)]
+ #[sv::custom(...)]
// and so on..

Optional "as InterfaceName"

messages attribute on contract macro always expects the user to pass the path to the interface and its name. In most cases, though, the interface name is just a camel case of the module name in which it’s defined. Because of that, we made the interface name an optional value. If you keep your interface in the differently named module, you can still use the old syntax.

#[sylvia::contract]
#[sv::messages(path::to::interface as Interface)] // This works
#[sv::messages(path::to::interface)] // This also works

Generated code in modules

Sylvia grew and now generates a lot of code. Because of that, we decided to introduce a new sv module in which all of this code will be generated so as not to populate the scope.

We also unified the multitest modules names. Previously we used names like trait_utils multitest_utils and test_utils. This was supposed to allow users to call different macros in the same scope. As we already generate the sv module, the one macro per module rule becomes mandatory, and we could change the naming of these modules to simple mt.

use contract::sv::ExecMsg;
#[cfg(test)]
use contract::sv::mt::CodeId;

Interface implementation on Contract

In previous versions, Sylvia required using #[contract] macro call on impl Interface for Contract block. This is not needed anymore, and from now on, you can enjoy the simpler API of Sylvia.

- #[sylvia::contract]
impl Interface for Contract {
- #[sv::msg(exec)]
fn some_exec(...) -> ... {
}
}

Less generated code

The last change in the Sylvia 1.0.0 we want to mention is a move of some code that was originally generated to modules in Sylvia.

Types like Remote and BoundQuerier were always generated the same way, and the only difference came from the traits that were implemented on them. This led us to move them to sylvia::types modules and tweak them to be generic over contract type.

let remote = sylvia::types::Remote::<super::CounterContract<'_>>::new(remote_addr.clone());

Summary

There are many more changes that mentioning would make this article inconveniently long to read, and the only one we will mention here is improved code documentation.

Please check the Sylvia-book, the documentation, and examples in Sylvia to learn about the new API of Sylvia.

--

--