Compute edges from safes.
This commit is contained in:
parent
a7e9aefd40
commit
5969204a1f
3 changed files with 129 additions and 5 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue