Compute edges from safes.

This commit is contained in:
chriseth 2022-12-12 23:03:57 +01:00
parent a7e9aefd40
commit 5969204a1f
3 changed files with 129 additions and 5 deletions

View file

@ -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)] #[derive(Default, Debug)]
pub struct DB { pub struct DB {
safes: BTreeMap<Address, Safe>, safes: BTreeMap<Address, Safe>,
token_owner: BTreeMap<Address, Address>, token_owner: BTreeMap<Address, Address>,
edges: EdgeDB,
} }
impl DB { impl DB {
pub fn new(safes: BTreeMap<Address, Safe>, token_owner: BTreeMap<Address, Address>) -> DB { pub fn new(safes: BTreeMap<Address, Safe>, token_owner: BTreeMap<Address, Address>) -> DB {
println!("{} safes, {} tokens", safes.len(), token_owner.len()); 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)
} }
} }

View file

@ -1,4 +1,4 @@
use std::collections::BTreeMap; use std::{cmp::min, collections::BTreeMap};
use super::{Address, U256}; use super::{Address, U256};
@ -10,3 +10,26 @@ pub struct Safe {
pub limit_percentage: BTreeMap<Address, u8>, pub limit_percentage: BTreeMap<Address, u8>,
pub organization: bool, 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))
}
}
}
}

View file

@ -1,6 +1,8 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::fmt::Display; use std::fmt::Display;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::ops::Div;
use std::ops::Mul;
use std::ops::{Add, AddAssign, Neg, Sub, SubAssign}; use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
use num_bigint::BigUint; use num_bigint::BigUint;
@ -13,12 +15,22 @@ impl U256 {
U256([high, low]) U256([high, low])
} }
pub const MAX: U256 = U256::new(u128::MAX, u128::MAX); 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 { pub fn to_decimal(self) -> String {
let value = BigUint::from(self.0[0]) << 128 | BigUint::from(self.0[1]); let value = BigUint::from(self.0[0]) << 128 | BigUint::from(self.0[1]);
format!("{value}") format!("{value}")
} }
pub fn to_decimal_fraction(self) -> String { 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}"); let formatted = format!("{value}");
match formatted.len() { match formatted.len() {
18.. => { 18.. => {
@ -85,6 +97,12 @@ impl From<&str> for U256 {
} }
} }
impl From<U256> for BigUint {
fn from(value: U256) -> Self {
BigUint::from(value.0[0]) << 128 | BigUint::from(value.0[1])
}
}
impl Add for U256 { impl Add for U256 {
type Output = Self; type Output = Self;
fn add(self, rhs: Self) -> 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 { impl SubAssign for U256 {
fn sub_assign(&mut self, rhs: Self) { fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs; *self = *self - rhs;
@ -222,4 +260,23 @@ mod test {
"340282366920938463463374607431768211456" "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")
);
}
} }