Modules
Simply put, modules in Odra let you reuse your code between contracts or even projects. Every contract you
write is also a module, thanks to the #[odra::module]
attribute. This means that we can easily rewrite our math
example from the previous article, to use a single contract, but still separate our "math" code:
use crate::features::cross_calls::MathEngine;
use odra::module::SubModule;
use odra::prelude::*;
#[odra::module]
pub struct ModulesContract {
pub math_engine: SubModule<MathEngine>
}
#[odra::module]
impl ModulesContract {
pub fn add_using_module(&self) -> u32 {
self.math_engine.add(3, 5)
}
}
To use a module as a component of another module, you need to use the SubModule
type. This is a special type
that crates a keyspace (read more in Storage Layout) and provide access to its public methods.
Note that we didn't need to rewrite the MathEngine
- we are using the contract from cross calls example as
a module!
To see how modules can be used in a real-world scenario, check out the OwnedToken example in the main Odra repository!
Testing
As we don't need to hold addresses, the test is really simple:
#[cfg(test)]
mod tests {
use super::ModulesContractHostRef;
use odra::host::{Deployer, NoArgs};
#[test]
fn test_modules() {
let test_env = odra_test::env();
let modules_contract = ModulesContractHostRef::deploy(&test_env, NoArgs);
assert_eq!(modules_contract.add_using_module(), 8);
}
}
What's next
We will see how to handle native token transfers.