pub use crate::{
payment_splitter,
traits::payment_splitter::*,
};
pub use payment_splitter::Internal as _;
use ink::prelude::vec::Vec;
use openbrush::{
storage::Mapping,
traits::{
AccountId,
AccountIdExt,
Balance,
Storage,
ZERO_ADDRESS,
},
};
pub const STORAGE_KEY: u32 = openbrush::storage_unique_key!(Data);
#[derive(Default, Debug)]
#[openbrush::upgradeable_storage(STORAGE_KEY)]
pub struct Data {
pub total_shares: Balance,
pub total_released: Balance,
pub shares: Mapping<AccountId, Balance>,
pub released: Mapping<AccountId, Balance>,
pub payees: Vec<AccountId>,
pub _reserved: Option<()>,
}
impl<T: Storage<Data>> PaymentSplitter for T {
default fn total_shares(&self) -> Balance {
self.data().total_shares.clone()
}
default fn total_released(&self) -> Balance {
self.data().total_released.clone()
}
default fn shares(&self, account: AccountId) -> Balance {
self.data().shares.get(&account).unwrap_or(0)
}
default fn released(&self, account: AccountId) -> Balance {
self.data().released.get(&account).unwrap_or(0)
}
default fn payee(&self, index: u32) -> AccountId {
self.data()
.payees
.get(index as usize)
.cloned()
.unwrap_or(ZERO_ADDRESS.into())
}
default fn receive(&mut self) {
self._emit_payee_added_event(Self::env().caller(), Self::env().transferred_value())
}
default fn release(&mut self, account: AccountId) -> Result<(), PaymentSplitterError> {
if !self.data().shares.get(&account).is_some() {
return Err(PaymentSplitterError::AccountHasNoShares)
}
let balance = Self::env().balance();
let current_balance = balance.checked_sub(Self::env().minimum_balance()).unwrap_or_default();
let total_received = current_balance + self.data().total_released;
let shares = self.data().shares.get(&account).unwrap().clone();
let total_shares = self.data().total_shares;
let released = self.data().released.get(&account).unwrap_or_default();
let payment = total_received * shares / total_shares - released;
if payment == 0 {
return Err(PaymentSplitterError::AccountIsNotDuePayment)
}
self.data().released.insert(&account, &(released + payment));
self.data().total_released += payment;
let transfer_result = Self::env().transfer(account.clone(), payment);
if transfer_result.is_err() {
return Err(PaymentSplitterError::TransferFailed)
}
self._emit_payment_released_event(account, payment);
Ok(())
}
}
pub trait Internal {
fn _emit_payee_added_event(&self, _account: AccountId, _shares: Balance);
fn _emit_payment_received_event(&self, _from: AccountId, _amount: Balance);
fn _emit_payment_released_event(&self, _to: AccountId, _amount: Balance);
fn _init(&mut self, payees_and_shares: Vec<(AccountId, Balance)>) -> Result<(), PaymentSplitterError>;
fn _add_payee(&mut self, payee: AccountId, share: Balance) -> Result<(), PaymentSplitterError>;
fn _release_all(&mut self) -> Result<(), PaymentSplitterError>;
}
impl<T: Storage<Data>> Internal for T {
default fn _emit_payee_added_event(&self, _account: AccountId, _shares: Balance) {}
default fn _emit_payment_received_event(&self, _from: AccountId, _amount: Balance) {}
default fn _emit_payment_released_event(&self, _to: AccountId, _amount: Balance) {}
default fn _init(&mut self, payees_and_shares: Vec<(AccountId, Balance)>) -> Result<(), PaymentSplitterError> {
if payees_and_shares.is_empty() {
return Err(PaymentSplitterError::NoPayees)
}
for (payee, share) in payees_and_shares.into_iter() {
self._add_payee(payee, share)?;
}
Ok(())
}
default fn _add_payee(&mut self, payee: AccountId, share: Balance) -> Result<(), PaymentSplitterError> {
if payee.is_zero() {
return Err(PaymentSplitterError::AccountZeroAddress)
}
if share == 0 {
return Err(PaymentSplitterError::SharesAreZero)
}
if self.data().shares.get(&payee).is_some() {
return Err(PaymentSplitterError::AlreadyHasShares)
}
self.data().payees.push(payee.clone());
self.data().shares.insert(&payee, &share);
self.data().total_shares += share;
self._emit_payee_added_event(payee, share);
Ok(())
}
default fn _release_all(&mut self) -> Result<(), PaymentSplitterError> {
let len = self.data().payees.len();
for i in 0..len {
let account = self.data().payees[i];
self.release(account)?;
}
Ok(())
}
}