Skip to main content

Lending contract

The main logic of the LendingContract is defined in the impls/lending directory. In this file, we only need to "inherit" it.

Add dependencies

LendingContract instantiates the SharesContract and LoanContract, so we should import them as ink-as-dependency. Also we want to use the AccessControl and Pausable from OpenBrush, so we import them too. We also want to "inherit" the implementation of Lending and LendingPermissioned traits defined in the lending_project crate.

name = "lending_contract"
version= "4.0.0-beta"
authors = ["Brushfam <>"]
edition = "2021"

ink = { version = "4.2.1", default-features = false }
scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] }
scale-info = { version = "2.6", default-features = false, features = ["derive"], optional = true }

# These dependencies
shares_contract = { path = "../shares", default-features = false, features = ["ink-as-dependency"] }
loan_contract = { path = "../loan", default-features = false, features = ["ink-as-dependency"] }
lending_project = { path = "../..", default-features = false }
openbrush = { git = "", branch = "develop", default-features = false, features = ["pausable", "access_control"] }

name = "lending_contract"
path = ""

default = ["std"]
std = [

# These dependencies
ink-as-dependency = []

codegen-units = 16

overflow-checks = false

Define the contract storage

As described earlier, we want our smart contract to be paused by the Manager account. To do that, we need our contract to be Pausable and we need a manager role. We can do this with the AccessControl. Also, we want to use the data from lending that we have declared. So we will declare a struct and derive all the needed traits.

#[derive(Default, Storage)]
pub struct LendingContract {
access: access_control::Data,
pause: pausable::Data,
lending: lending::data::Data,

Implement traits

We need to "inherit" the implementation of AccessControll, Pausable, Lending, LendingPermissioned and lending::Internal.

impl lending::Internal for LendingContract {}

impl LendingImpl for LendingContract {}

impl Lending for LendingContract {
fn total_asset(&self, asset_address: AccountId) -> Result<Balance, LendingError> {
LendingImpl::total_asset(self, asset_address)
// other methods should be implemented here as the one above

impl LendingPermissionedImpl for LendingContract {}

impl LendingPermissioned for LendingContract {
fn deposit(&mut self, asset_address: AccountId, amount: Balance) -> Result<(), LendingError> {
LendingPermissionedImpl::deposit(self, asset_address, amount)
// other methods should be implemented here as the one above

impl lending::Instantiator for LendingContract {
fn _instantiate_shares_contract(&self, contract_name: &str, contract_symbol: &str) -> AccountId {
let code_hash = self.lending.shares_contract_code_hash;

let salt = (<Self as DefaultEnv>::env().block_timestamp(), contract_name).encode();

let hash = xxh32(&salt, 0).to_le_bytes();

let contract =
SharesContractRef::new(Some(String::from(contract_name)), Some(String::from(contract_symbol)))

Now the LendingContract has functionality of all that traits.

Define the constructor

Finally, we will add a constructor, in which we will initiate the admin of the contract, to whom we will also grant the manager role declared before, and we will also instantiate the LoanContract here and store its AccountId in LendingContract.

impl LendingContract {
/// constructor with name and symbol
#[ink(constructor, payable)]
pub fn new(shares_hash: Hash, loan_hash: Hash) -> Self {

let mut instance = Self::default();

let caller = Self::env().caller();
instance.grant_role(MANAGER, caller).expect("Can not set manager role");
instance.lending.shares_contract_code_hash = shares_hash;
// instantiate NFT contract and store its account id
let nft = LoanContractRef::new()
.salt_bytes(&[0xDE, 0xAD, 0xBE, 0xEF])
instance.lending.loan_account = nft.to_account_id();