Skip to content
This repository has been archived by the owner on May 16, 2024. It is now read-only.

[WIP]: Source code is upgraded to ink! 4.1.0; Upgradable storage by the OpenBrush is integrated to the contract #67

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 13 additions & 27 deletions bucket/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,55 +7,41 @@ description = "DDC v2 Smart Contracts -- Orchestrate the network around clusters
license = "Apache-2.0"

[dependencies]
scale = { package = "parity-scale-codec", version = "2.1", default-features = false, features = ["derive"] }
scale-info = { version = "0.6.0", default-features = false, features = ["derive"], optional = true }

ink_primitives = { version = "=3.0.0-rc4", default-features = false }
ink_metadata = { version = "=3.0.0-rc4", default-features = false, features = ["derive"], optional = true }
ink_env = { version = "=3.0.0-rc4", default-features = false }
ink_storage = { version = "=3.0.0-rc4", default-features = false }
ink_lang = { version = "=3.0.0-rc4", default-features = false }
ink_prelude = { version = "=3.0.0-rc4", default-features = false }

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

ink = { version = "4.1.0", default-features = false }
ink_primitives = { version = "4.1.0", default-features = false }
ink_metadata = { version = "4.1.0", default-features = false, features = ["derive"], optional = true }
ink_env = { version = "4.1.0", default-features = false }
ink_storage = { version = "4.1.0", default-features = false }
ink_prelude = { version = "4.1.0", default-features = false }
# Transitive dependencies necessary to fix the version.
ink_allocator = { version = "=3.0.0-rc4", default-features = false, optional = true }
ink_lang_codegen = { version = "=3.0.0-rc4", default-features = false, optional = true }
ink_storage_derive = { version = "=3.0.0-rc4", default-features = false, optional = true }
ink_lang_ir = { version = "=3.0.0-rc4", default-features = false, optional = true }
ink_lang_macro = { version = "=3.0.0-rc4", default-features = false, optional = true }
#ink_eth_compatibility = { version = "=3.0.0-rc4", default-features = false, optional = true }
ink_allocator = { version = "4.1.0", default-features = false, optional = true }

serde = { version = "1.0.136", optional = true }
serde_json = { version = "1.0.79", optional = true }
more-asserts = { version = "0.3.0" }

openbrush = { git = "https://github.com/727-Ventures/openbrush-contracts", version = "~3.0.0", default-features = false }

[lib]
name = "ddc_bucket"
path = "lib.rs"
crate-type = [
# Used for normal contract Wasm blobs.
"cdylib",
# Used for ABI generation.
"rlib",
]

[features]
default = ["std"]
std = [
"scale/std",
"scale-info/std",
"ink/std",
"ink_metadata/std",
"ink_env/std",
"ink_storage/std",
"ink_primitives/std",
"ink_prelude/std",
# Transitive dependencies.
"ink_allocator/std",
"ink_lang_codegen/std",
#"ink_storage_derive/std",
"ink_lang_ir/std",
"ink_lang_macro/std",
#"ink_eth_compatibility/std",

# For tests
"serde",
Expand Down
8 changes: 3 additions & 5 deletions bucket/ddc_bucket/account/entity.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
//! The data structure of Accounts.

use ink_storage::traits::{PackedLayout, SpreadLayout};
use scale::{Decode, Encode};

use crate::ddc_bucket::{
Balance, cash::{Cash, Payable},
Error::*, Result,
schedule::Schedule,
};
use crate::ddc_bucket::currency::{USD, CurrencyConverter};

#[derive(Clone, PartialEq, Encode, Decode, SpreadLayout, PackedLayout)]
#[cfg_attr(feature = "std", derive(Debug, scale_info::TypeInfo))]

#[derive(Encode, Decode, Clone, PartialEq)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo, ink::storage::traits::StorageLayout, Debug))]
pub struct Account {
pub deposit: Cash,
pub bonded: Cash,
Expand Down
85 changes: 48 additions & 37 deletions bucket/ddc_bucket/account/messages.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
//! The public interface of Accounts and deposits.

use ink_prelude::vec::Vec;
use ink_lang::{EmitEvent, StaticEnv};
use ink::codegen::{EmitEvent, StaticEnv};

use crate::ddc_bucket::{AccountId, Balance, Cash, DdcBucket, Deposit, Payable, Result, TOKEN};
use crate::ddc_bucket::Error::InsufficientBalance;
use crate::ddc_bucket::perm::entity::Permission;

impl DdcBucket {

// todo: remove this method as we can not support iterable data structures of arbitrary data size
pub fn message_get_accounts(&self) -> Vec<AccountId> {
self.accounts.0.keys().cloned().collect()
self.accounts.account_ids.iter().cloned().collect()
}

pub fn message_account_deposit(&mut self) -> Result<()> {
Expand All @@ -22,55 +24,60 @@ impl DdcBucket {

Self::env().emit_event(Deposit { account_id, value: cash.peek() });

self.accounts
.get_mut(&account_id)?
.deposit(cash);
let mut account = self.accounts.get(&account_id)?;
account.deposit(cash);
self.accounts.save(&account_id, &account);

Ok(())
}

pub fn message_account_bond(&mut self, bond_amount: Balance) -> Result<()> {
let time_ms = Self::env().block_timestamp();
let account_id = Self::env().caller();
let account = self.accounts.0.get_mut(&account_id)
.ok_or(InsufficientBalance)?;

let conv = &self.accounts.1;

account.bond(time_ms, conv, bond_amount)?;
Ok(())
if let Ok(mut account) = self.accounts.get(&account_id) {
let conv = &self.accounts.curr_converter;
account.bond(time_ms, conv, bond_amount)?;
self.accounts.save(&account_id, &account);
Ok(())
} else {
Err(InsufficientBalance)
}
}

pub fn message_account_unbond(&mut self, amount_to_unbond: Cash) -> Result<()> {
let time_ms = Self::env().block_timestamp();
let account_id = Self::env().caller();

self.accounts
.get_mut(&account_id)?
.unbond(amount_to_unbond, time_ms).unwrap();
let mut account = self.accounts.get(&account_id)?;
account.unbond(amount_to_unbond, time_ms)?;
self.accounts.save(&account_id, &account);

Ok(())
}

pub fn message_account_withdraw_unbonded(&mut self) -> Result<()> {
let time_ms = Self::env().block_timestamp();
let account_id = Self::env().caller();

self.accounts
.get_mut(&account_id)?
.withdraw_unbonded(time_ms).unwrap();
let mut account = self.accounts.get(&account_id)?;
account.withdraw_unbonded(time_ms)?;
self.accounts.save(&account_id, &account);

Ok(())
}

pub fn message_account_get_usd_per_cere(&self) -> Balance {
self.accounts.1.to_usd(1 * TOKEN)
self.accounts.curr_converter.to_usd(1 * TOKEN)
}

pub fn message_account_set_usd_per_cere(&mut self, usd_per_cere: Balance) {
self.only_with_permission(Permission::SetExchangeRate).unwrap();
self.accounts.1.set_usd_per_cere(usd_per_cere)
self.accounts.curr_converter.set_usd_per_cere(usd_per_cere)
}

pub fn receive_cash() -> Cash {
Cash(Self::env().transferred_balance())
Cash(Self::env().transferred_value())
}

pub fn send_cash(destination: AccountId, cash: Cash) -> Result<()> {
Expand All @@ -82,29 +89,33 @@ impl DdcBucket {
}

fn _account_withdraw(&mut self, from: AccountId, payable: Payable) -> Result<()> {
let account = self.accounts.0.get_mut(&from)
.ok_or(InsufficientBalance)?;

let time_ms = Self::env().block_timestamp();
let conv = &self.accounts.1;
account.withdraw(time_ms, conv, payable)?;
Ok(())
if let Ok(mut account) = self.accounts.get(&from) {
let time_ms = Self::env().block_timestamp();
let conv = &self.accounts.curr_converter;
account.withdraw(time_ms, conv, payable)?;
self.accounts.save(&from, &account);
Ok(())
} else {
Err(InsufficientBalance)
}
}

fn _account_withdraw_bonded(&mut self, account_id: AccountId, payable: Payable) -> Result<()> {
let account = self.accounts.0.get_mut(&account_id)
.ok_or(InsufficientBalance)?;

account.withdraw_bonded(payable)?;
Ok(())
if let Ok(mut account) = self.accounts.get(&account_id) {
account.withdraw_bonded(payable)?;
self.accounts.save(&account_id, &account);
Ok(())
} else {
Err(InsufficientBalance)
}
}

fn _account_get_net(&self, from: AccountId) -> Balance {
match self.accounts.0.get(&from) {
match self.accounts.accounts.get(&from) {
None => 0,
Some(account) => {
let time_ms = Self::env().block_timestamp();
let conv = &self.accounts.1;
let conv = &self.accounts.curr_converter;
account.get_withdrawable(time_ms, conv)
}
}
Expand All @@ -117,9 +128,9 @@ impl DdcBucket {
// Create the account, if necessary.
self.accounts.create_if_not_exist(to);

self.accounts
.get_mut(&to)?
.deposit(cash);
let mut account = self.accounts.get(&to)?;
account.deposit(cash);
self.accounts.save(&to, &account);
Ok(())
}
}
56 changes: 31 additions & 25 deletions bucket/ddc_bucket/account/store.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! The store to create and access Accounts.

use ink_storage::{collections::{HashMap, hashmap::Entry::*}, traits, Lazy};
use ink_storage::Mapping;

use crate::ddc_bucket::{
AccountId, Balance, cash::Cash, Error::*,
Expand All @@ -9,43 +9,46 @@ use crate::ddc_bucket::{
};
use crate::ddc_bucket::currency::CurrencyConverter;
use crate::ddc_bucket::flow::Flow;

use ink_prelude::vec::Vec;
use super::entity::Account;

#[derive(traits::SpreadLayout, Default)]
#[cfg_attr(feature = "std", derive(traits::StorageLayout, Debug))]
pub struct AccountStore(
pub HashMap<AccountId, Account>,
pub Lazy<CurrencyConverter>,
);

pub const ACCOUNT_STORE_KEY: u32 = openbrush::storage_unique_key!(AccountStore);
#[openbrush::upgradeable_storage(ACCOUNT_STORE_KEY)]
#[derive(Default)]
#[cfg_attr(feature = "std", derive(Debug))]
pub struct AccountStore {
pub accounts: Mapping<AccountId, Account>,
pub curr_converter: CurrencyConverter,
// todo: remove this vector as it can store an arbitrary number of elements and easily exceed 16KB limit
pub account_ids: Vec<AccountId>,
_reserved: Option<()>
}

impl AccountStore {
/// Create a record for the given account if it does not exist yet.
/// Does not return extra contract storage used, due to blockchain changes.
pub fn create_if_not_exist(&mut self, account_id: AccountId) {
match self.0.entry(account_id) {
Vacant(e) => {
e.insert(Account::new());
()
}
Occupied(_) => (),
}
if !self.accounts.contains(account_id) {
let acc = Account::new();
self.accounts.insert(account_id, &acc);
self.account_ids.push(account_id);
};
}

pub fn balance(&self, account_id: &AccountId) -> Balance {
match self.0.get(account_id) {
match self.accounts.get(account_id) {
None => 0,
Some(account) => account.deposit.peek(),
}
}


pub fn get(&self, account_id: &AccountId) -> Result<&Account> {
self.0.get(account_id).ok_or(AccountDoesNotExist)
pub fn get(&self, account_id: &AccountId) -> Result<Account> {
self.accounts.get(account_id).ok_or(AccountDoesNotExist)
}

pub fn get_mut(&mut self, account_id: &AccountId) -> Result<&mut Account> {
self.0.get_mut(account_id).ok_or(AccountDoesNotExist)
pub fn save(&mut self, account_id: &AccountId, account: &Account) {
self.accounts.insert(account_id, account);
}

/// Increase the rate of the given flow starting from the given time.
Expand All @@ -54,26 +57,29 @@ impl AccountStore {
let extra_schedule = Schedule::new(start_ms, extra_rate);
flow.schedule.add_schedule(extra_schedule.clone());

let from_account = self.get_mut(&flow.from)?;
let mut from_account = self.get(&flow.from)?;
from_account.lock_schedule(extra_schedule);
self.save(&flow.from, &from_account);

Ok(())
}

pub fn settle_flow(&mut self, now_ms: u64, flow: &mut Flow) -> Result<Cash> {
let flowed_usd = flow.schedule.take_value_at_time(now_ms);
let flowed_cere = self.1.to_cere(flowed_usd);
let flowed_cere = self.curr_converter.to_cere(flowed_usd);
let (payable, cash) = Cash::borrow_payable_cash(flowed_cere);

let account = self.get_mut(&flow.from)?;
let mut account = self.get(&flow.from)?;
account.pay_scheduled(payable, flowed_usd)?;
self.save(&flow.from, &account);

Ok(cash)
}

pub fn flow_covered_until(&self, flow: &Flow) -> Result<u64> {
let account = self.get(&flow.from)?;
let deposit_cere = account.deposit.peek();
let deposit_usd = self.1.to_usd(deposit_cere);
let deposit_usd = self.curr_converter.to_usd(deposit_cere);
Ok(account.schedule_covered_until(deposit_usd))
}
}
Loading