Beginner
Smart contract modules
Smart contracts are the backbone of decentralized applications (dApps) and are an essential component of blockchain technology. They allow for secure, autonomous, and transparent transactions without the need for intermediaries. In this tutorial, we will delve into the world of smart contract modules and how they can be used to build complex and scalable dApps on MultiversX.
Smart contract modules are a way of breaking down complex smart contracts into smaller, reusable components. By using modules, we can reduce the amount of duplicated code, improve maintainability, and increase the overall efficiency of our smart contracts.
In this tutorial, we will walk through the process of creating and using smart contract modules on MultiversX. We will cover the basic syntax and show you how to import and use modules in your smart contracts. By the end of this tutorial, you will have a solid understanding of smart contract modules and how to implement them in your own dApp projects on MultiversX.
Smart contract modules are a handy way of dividing a contract into smaller components. Modules also reduce code duplication, since they can be reused across multiple contracts.
Declaration
Modules can be defined both in the same crate as the main contract or even in their own standalone crate. The latter is used when you want to use the same module in multiple contracts.
A module is a trait declared with the #[multiversx_sc::module]
macro. Inside the trait, you can write any code you would usually write in a smart contract, even endpoints, events, storage mappers, etc.
For example, let’s say you want to have your storage mappers in a separate module. The implementation would look like this:
#[multiversx_sc::module] pub trait StorageModule { #[view(getQuorum)] #[storage_mapper("firstStorage")] fn first_storage(&self) -> SingleValueMapper<usize>; #[view] #[storage_mapper("secondStorage")] fn second_storage(&self) -> SingleValueMapper<u64>; }
Then, in your main file (usually named lib.rs
), you have to define the module. If the file for the above module is named storage.rs
, then in the main file you’d declare it like this:
pub mod storage;
Importing a module
A module can be imported both by other modules and contracts:
pub trait SetupModule: crate::storage::StorageModule + crate::util::UtilModule { }
#[multiversx_sc::contract] pub trait MainContract: setup::SetupModule + storage::StorageModule + util::UtilModule { }
Keep in mind your main contract has to implement all modules that any sub-module might use. In this example, even if the MainContract
does not use anything from the UtilModule
, it still has to implement it if it wants to use SetupModule
.