From 5969204a1fd9dd83feb0f05a2bf6b84c2f97f8f0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Mon, 12 Dec 2022 23:03:57 +0100 Subject: [PATCH] Compute edges from safes. --- src/safe_db/db.rs | 50 ++++++++++++++++++++++++++++++++++++--- src/types/safe.rs | 25 +++++++++++++++++++- src/types/u256.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 129 insertions(+), 5 deletions(-) diff --git a/src/safe_db/db.rs b/src/safe_db/db.rs index 7fcef0f..f36b62f 100644 --- a/src/safe_db/db.rs +++ b/src/safe_db/db.rs @@ -1,16 +1,60 @@ -use std::collections::BTreeMap; +use std::{collections::BTreeMap, default}; -use crate::types::{Address, Safe}; +use crate::types::{edge::EdgeDB, Address, Edge, Safe, U256}; #[derive(Default, Debug)] pub struct DB { safes: BTreeMap, token_owner: BTreeMap, + edges: EdgeDB, } impl DB { pub fn new(safes: BTreeMap, token_owner: BTreeMap) -> DB { println!("{} safes, {} tokens", safes.len(), token_owner.len()); - DB { safes, token_owner } + let mut db = DB { + safes, + token_owner, + ..Default::default() + }; + db.compute_edges(); + db + } + + fn compute_edges(&mut self) { + let mut edges = vec![]; + for (user, safe) in &self.safes { + // trust connections + for (send_to, percentage) in &safe.limit_percentage { + if *user == *send_to { + continue; + } + if let Some(receiver_safe) = self.safes.get(send_to) { + let limit = safe.trust_transfer_limit(receiver_safe, *percentage); + if limit != U256::from(0) { + edges.push(Edge { + from: *user, + to: *send_to, + token: *user, + capacity: limit, + }) + } + } + } + // send tokens back to owner + for (token, balance) in &safe.balances { + if let Some(owner) = self.token_owner.get(token) { + if *user != *owner { + edges.push(Edge { + from: *user, + to: *owner, + token: *owner, + capacity: *balance, + }) + } + } + } + } + self.edges = EdgeDB::new(edges) } } diff --git a/src/types/safe.rs b/src/types/safe.rs index 4cb82df..295b95d 100644 --- a/src/types/safe.rs +++ b/src/types/safe.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::{cmp::min, collections::BTreeMap}; use super::{Address, U256}; @@ -10,3 +10,26 @@ pub struct Safe { pub limit_percentage: BTreeMap, pub organization: bool, } + +impl Safe { + pub fn balance(&self, token: &Address) -> U256 { + *self.balances.get(token).unwrap_or(&U256::from(0)) + } + /// @returns how much of their own tokens a user can send to receiver. + pub fn trust_transfer_limit(&self, receiver: &Safe, trust_percentage: u8) -> U256 { + if receiver.organization { + // TODO treat this as "return to owner" + self.balance(&self.token_address) + } else { + let receiver_balance = receiver.balance(&self.token_address); + let amount = (receiver.balance(&receiver.token_address) + * U256::from(trust_percentage as u128)) + / U256::from(100); + if amount < receiver_balance { + U256::from(0) + } else { + min(amount - receiver_balance, self.balance(&self.token_address)) + } + } + } +} diff --git a/src/types/u256.rs b/src/types/u256.rs index f731b19..64cf818 100644 --- a/src/types/u256.rs +++ b/src/types/u256.rs @@ -1,6 +1,8 @@ use std::fmt::Debug; use std::fmt::Display; use std::fmt::Formatter; +use std::ops::Div; +use std::ops::Mul; use std::ops::{Add, AddAssign, Neg, Sub, SubAssign}; use num_bigint::BigUint; @@ -13,12 +15,22 @@ impl U256 { U256([high, low]) } pub const MAX: U256 = U256::new(u128::MAX, u128::MAX); + pub fn from_bigint_truncating(input: BigUint) -> U256 { + let digits = input.to_u64_digits(); + U256([ + u128::from(*digits.get(3).unwrap_or(&0)) << 64 + | u128::from(*digits.get(2).unwrap_or(&0)), + u128::from(*digits.get(1).unwrap_or(&0)) << 64 + | u128::from(*digits.first().unwrap_or(&0)), + ]) + } + pub fn to_decimal(self) -> String { let value = BigUint::from(self.0[0]) << 128 | BigUint::from(self.0[1]); format!("{value}") } pub fn to_decimal_fraction(self) -> String { - let value = BigUint::from(self.0[0]) << 128 | BigUint::from(self.0[1]); + let value: BigUint = self.into(); let formatted = format!("{value}"); match formatted.len() { 18.. => { @@ -85,6 +97,12 @@ impl From<&str> for U256 { } } +impl From for BigUint { + fn from(value: U256) -> Self { + BigUint::from(value.0[0]) << 128 | BigUint::from(value.0[1]) + } +} + impl Add for U256 { type Output = Self; fn add(self, rhs: Self) -> Self { @@ -118,6 +136,26 @@ impl Sub for U256 { } } +impl Mul for U256 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + let self_big: BigUint = self.into(); + let rhs_big: BigUint = rhs.into(); + U256::from_bigint_truncating(self_big * rhs_big) + } +} + +impl Div for U256 { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + let self_big: BigUint = self.into(); + let rhs_big: BigUint = rhs.into(); + U256::from_bigint_truncating(self_big / rhs_big) + } +} + impl SubAssign for U256 { fn sub_assign(&mut self, rhs: Self) { *self = *self - rhs; @@ -222,4 +260,23 @@ mod test { "340282366920938463463374607431768211456" ); } + + #[test] + fn to_mul_div() { + let two = U256::from("2"); + let three = U256::from(3); + let large = U256::from("0x100000000000000000000000000000000"); + assert_eq!(two * three, U256::from(6)); + assert_eq!(three / two, U256::from(1)); + assert_eq!((large * two) / two, large); + assert_eq!( + large / three, + U256::from("0x55555555555555555555555555555555") + ); + assert_eq!(large * large, U256::from("0")); + assert_eq!( + (large / two) * large, + U256::from("0x8000000000000000000000000000000000000000000000000000000000000000") + ); + } }