#![allow(unused)]
use std::collections::HashMap;
use anyhow::anyhow;
use borderless_id_types::BorderlessId;
use serde::{Deserialize, Serialize};
use crate::__private::{read_field, storage_keys::BASE_KEY_MASK_LEDGER, write_field};
use super::TxCtx;
#[repr(u32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Currency {
ALL = 8,
AZN = 944,
BYN = 933,
BAM = 977,
GBP = 826,
BGN = 975,
CZK = 203,
DKK = 208,
EUR = 978,
HUF = 348,
ISK = 352,
NOK = 578,
PLN = 985,
RON = 946,
RUB = 643,
RSD = 941,
CHF = 756,
TRY = 949,
UAH = 980,
USD = 840,
}
impl Currency {
pub fn currency_name(&self) -> &'static str {
match self {
Currency::ALL => "Albanian Lek",
Currency::AZN => "Azerbaijani Manat",
Currency::BYN => "Belarusian Ruble",
Currency::BAM => "Bosnian Convertible Mark",
Currency::GBP => "British Pound Sterling",
Currency::BGN => "Bulgarian Lev",
Currency::CZK => "Czech Koruna",
Currency::DKK => "Danish Krone",
Currency::EUR => "Euro",
Currency::HUF => "Hungarian Forint",
Currency::ISK => "Icelandic Krona",
Currency::NOK => "Norwegian Krone",
Currency::PLN => "Polish Zloty",
Currency::RON => "Romanian Leu",
Currency::RUB => "Russian Ruble",
Currency::RSD => "Serbian Dinar",
Currency::CHF => "Swiss Franc",
Currency::TRY => "Turkish Lira",
Currency::UAH => "Ukrainian Hryvnia",
Currency::USD => "US Dollar",
}
}
pub const fn symbol(&self) -> &'static str {
match self {
Currency::ALL => "Lek",
Currency::AZN => "₼",
Currency::BYN => "Br",
Currency::BAM => "KM",
Currency::GBP => "£",
Currency::BGN => "лв",
Currency::CZK => "Kč",
Currency::DKK => "kr",
Currency::EUR => "€",
Currency::HUF => "Ft",
Currency::ISK => "kr",
Currency::NOK => "kr",
Currency::PLN => "zł",
Currency::RON => "lei",
Currency::RUB => "₽",
Currency::RSD => "Дин.",
Currency::CHF => "CHF",
Currency::TRY => "₺",
Currency::UAH => "₴",
Currency::USD => "$",
}
}
}
pub trait Account: Copy {
fn settle_debt(&self, debitor: Self) -> TransferBuilder<Self> {
TransferBuilder {
party_a: *self,
party_b: debitor,
}
}
fn transfer(&self, other: Self) -> TransferBuilder<Self> {
TransferBuilder {
party_a: other,
party_b: *self,
}
}
}
impl Account for BorderlessId {
fn settle_debt(&self, debitor: Self) -> TransferBuilder<Self> {
TransferBuilder {
party_a: *self,
party_b: debitor,
}
}
fn transfer(&self, other: Self) -> TransferBuilder<Self> {
TransferBuilder {
party_a: other,
party_b: *self,
}
}
}
pub struct TransferBuilder<A: Account> {
party_a: A,
party_b: A,
}
impl TransferBuilder<BorderlessId> {
pub fn amount(self, amount: i64, currency: Currency) -> crate::Result<()> {
Ledger::open(self.party_a, self.party_b).push(amount, currency)
}
}
pub struct Ledger {
party_a: BorderlessId,
party_b: BorderlessId,
base_key: u64,
}
const SUB_KEY_STATE: u64 = 0;
const SUB_KEY_LEN: u64 = u64::MAX;
impl Ledger {
pub fn open(party_a: BorderlessId, party_b: BorderlessId) -> Self {
let base_key = party_a.merge_compact(&party_b) & BASE_KEY_MASK_LEDGER;
Ledger {
party_a,
party_b,
base_key,
}
}
pub fn state(&self) -> LedgerState {
if let Some(state) = read_field(self.base_key, SUB_KEY_STATE) {
state
} else {
LedgerState {
party_a: self.party_a,
party_b: self.party_b,
currency: Currency::EUR,
balance: 0,
}
}
}
pub fn len(&self) -> u64 {
read_field(self.base_key, SUB_KEY_LEN).unwrap_or_default()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn push(&mut self, amount: i64, currency: Currency) -> crate::Result<()> {
let prev = self.state();
if prev.currency != currency {
return Err(anyhow!("ledger currency mismatch"));
}
let new_state = LedgerState {
party_a: prev.party_a,
party_b: prev.party_b,
currency,
balance: prev.balance + amount,
};
write_field(self.base_key, SUB_KEY_STATE, &new_state);
let transfer = LedgerStateMeta {
transfer: LedgerState {
party_a: prev.party_a,
party_b: prev.party_b,
currency,
balance: amount,
},
tx_ctx: super::env::tx_ctx(),
block_ts: super::env::block_timestamp(),
};
let sub_key = self.len() + 1;
write_field(self.base_key, sub_key, &transfer);
write_field(self.base_key, SUB_KEY_LEN, &sub_key);
Ok(())
}
pub fn get_transfer(&self, idx: usize) -> Option<LedgerStateMeta> {
todo!()
}
}
#[derive(Serialize, Deserialize)]
pub struct LedgerState {
party_a: BorderlessId,
party_b: BorderlessId,
currency: Currency,
balance: i64,
}
#[derive(Serialize, Deserialize)]
pub struct LedgerStateMeta {
transfer: LedgerState,
tx_ctx: TxCtx,
block_ts: u64,
}