Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: retry handle message #72

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6b969be
add cap as storage service to eth_proxy
Sep 9, 2022
b609899
add cap storage service for claimable message on dip20_proxy
Sep 20, 2022
05942ac
upgrade cap_cdk and use insert_sync on eth_proxy
Sep 21, 2022
0d16aac
upgrade cap_cdk and use insert_sync on dip20_proxy
Sep 21, 2022
d618c7d
rename trait ToEvent to ToCapEvent
Sep 21, 2022
d769dba
remove claimable_assets candid methods from dip20_proxy
Sep 21, 2022
f9450c4
use archive() fn on upgrade
Sep 23, 2022
db17315
use archive() fn on upgrade eth_proxy
Sep 23, 2022
c19a962
eth_proxy: add caller to claimable message
Oct 18, 2022
69c0b08
dip20_proxy: add caller to claimable message
Oct 18, 2022
f6cc64c
add eth_contract_address to withdraw payload
Sep 22, 2022
bb5b837
add claimable_asset in withdraw for dip20_proxy
Sep 22, 2022
3281179
add claimable_asset in withdraw for eth_proxy
Sep 22, 2022
cebc5e8
use eth address as principal to keep balance
Sep 23, 2022
230b663
return Ok(balance) on eth_proxy.withdraw
Sep 23, 2022
b7fa4ce
add withdrawable struct to eth_proxy
Sep 27, 2022
b56a20c
add withdrawable struct to dip20_proxy
Sep 27, 2022
9f82039
remove token_id from withdrawable balance on eth_proxy
Sep 27, 2022
eca1bfa
Fix typo TokendId -> TokenId
Sep 28, 2022
5af4f7e
dip20_proxy: replace Vec for hashmap to store usertx
Sep 29, 2022
a810f52
eth_proxy: replace Vec for hashmap to store usertx
Sep 29, 2022
1889726
dip20_proxy: add operation failure on burn and withdraw
Oct 6, 2022
c933397
eth_proxy: add operation failure on burn and withdraw
Oct 6, 2022
ec846e3
dip20_proxy: refactor pending balance logic
Oct 12, 2022
c312ecf
eth_proxy: refactor pending balance logic
Oct 12, 2022
44d66f9
add caller to claimable message on withdraw
Oct 18, 2022
8f32e39
chore: out going message store (#38)
fcavazzoli Oct 18, 2022
0f3e67e
add account contract (#68)
fcavazzoli Oct 31, 2022
a2d95dc
starknet: increase max fee (#70)
fcavazzoli Nov 3, 2022
8342d37
core: add nonce_exist candid method
Nov 4, 2022
f674f32
dip20_proxy: add message_exist candid method query
Nov 4, 2022
756fbf7
dip20_proxy: update candid file
Nov 4, 2022
0b896dd
solve master conflicts
Nov 10, 2022
91b35b8
fix upgrade with Option<>
Nov 10, 2022
fbc0b7f
resolve merge conflict
Nov 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
dip20_proxy: refactor pending balance logic
  • Loading branch information
Federico authored and Federico committed Oct 18, 2022
commit ec846e36f18df7955f092c9cbbb3a5e66ac1feaa
2 changes: 1 addition & 1 deletion magic_bridge/ic/src/dip20_proxy/dip20_proxy.did
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@ service : {
authorized : () -> (vec principal) query;
burn : (principal, principal, nat) -> (Result);
get_all_token_balance : () -> (Result_1);
get_balance : (principal, principal) -> (opt nat);
get_balance : (principal, principal, nat) -> (opt nat);
handle_message : (principal, nat, vec nat) -> (Result_2);
mint : (principal, nat, vec nat) -> (Result_2);
perform_handshake : () -> (Result_3);
10 changes: 2 additions & 8 deletions magic_bridge/ic/src/dip20_proxy/src/api/burn.rs
Original file line number Diff line number Diff line change
@@ -81,17 +81,11 @@ async fn burn(
match send_message {
Ok(outgoing_message) => {
STATE.with(|s| {
// there could be an underflow here
// like negative balance
let current_balance = s
.get_balance(caller, eth_contract_as_principal, eth_addr)
.unwrap_or(Nat::from(0));

s.update_balance(
s.remove_balance(
caller,
eth_addr,
eth_contract_as_principal,
current_balance - amount.clone(),
amount.clone(),
);

s.remove_user_flag(caller, token_id)
4 changes: 2 additions & 2 deletions magic_bridge/ic/src/dip20_proxy/src/api/get_balance.rs
Original file line number Diff line number Diff line change
@@ -11,9 +11,9 @@ use crate::{

#[update(name = "get_balance")]
#[candid_method(update, rename = "get_balance")]
pub async fn get_balance(token_id: TokenId, eth_address: EthereumAddr) -> Option<Nat> {
pub async fn get_balance(token_id: TokenId, eth_address: EthereumAddr, amount: Nat) -> Option<Nat> {
let caller = ic::caller();
STATE.with(|s| s.get_balance(caller, token_id, eth_address))
STATE.with(|s| s.get_balance(caller, token_id, eth_address, amount))
}

#[update(name = "get_all_token_balance")]
8 changes: 4 additions & 4 deletions magic_bridge/ic/src/dip20_proxy/src/api/withdraw.rs
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ use crate::{
pub async fn withdraw(
eth_contract_as_principal: TokenId,
eth_addr: EthereumAddr,
_amount: Nat,
amount: Nat,
) -> Result<Nat, OperationFailure> {
let caller = ic::caller();
let tera_id = Principal::from_text(TERA_ADDRESS).unwrap();
@@ -59,7 +59,8 @@ pub async fn withdraw(
let erc20_addr_hex = ERC20_ADDRESS_ETH.trim_start_matches("0x");
let erc20_addr_pid = Principal::from_slice(&hex::decode(erc20_addr_hex).unwrap());

let get_balance = STATE.with(|s| s.get_balance(caller, eth_contract_as_principal, eth_addr));
let get_balance =
STATE.with(|s| s.get_balance(caller, eth_contract_as_principal, eth_addr, amount.clone()));
if let Some(balance) = get_balance {
let payload = [
eth_contract_as_principal.to_nat(),
@@ -70,9 +71,8 @@ pub async fn withdraw(

match tera_id.send_message(erc20_addr_pid, payload).await {
Ok(outgoing_message) => {
let zero = Nat::from(0_u32);
STATE.with(|s| {
s.update_balance(caller, eth_addr, eth_contract_as_principal, zero);
s.remove_balance(caller, eth_addr, eth_contract_as_principal, amount);
s.remove_user_flag(caller, token_id);
});

4 changes: 2 additions & 2 deletions magic_bridge/ic/src/dip20_proxy/src/common/types.rs
Original file line number Diff line number Diff line change
@@ -82,7 +82,7 @@ pub struct ProxyState {
/// store incoming messages against status locks
pub incoming_messages: RefCell<HashMap<MessageHash, MessageStatus>>,
/// user balances
pub balances: RefCell<HashMap<Principal, HashMap<TokenId, HashMap<EthereumAddr, Nat>>>>,
pub balances: RefCell<HashMap<Principal, HashMap<TokenId, Vec<(EthereumAddr, Nat)>>>>,
/// authorized principals
pub controllers: RefCell<Vec<Principal>>,
// store outgoing massages waiting to be claimed
@@ -96,7 +96,7 @@ pub struct StableProxyState {
/// store incoming messages against status locks
pub incoming_messages: HashMap<MessageHash, MessageStatus>,
/// user balances
pub balances: Option<HashMap<Principal, HashMap<TokenId, HashMap<EthereumAddr, Nat>>>>,
pub balances: Option<HashMap<Principal, HashMap<TokenId, Vec<(EthereumAddr, Nat)>>>>,
/// authorized principals
pub controllers: Vec<Principal>,
// store outgoing massages waiting to be claimed
131 changes: 77 additions & 54 deletions magic_bridge/ic/src/dip20_proxy/src/proxy.rs
Original file line number Diff line number Diff line change
@@ -44,62 +44,68 @@ impl ProxyState {
caller: Principal,
token_id: TokenId,
eth_address: EthereumAddr,
amount: Nat,
) -> Option<Nat> {
self.balances
if let Some(balance) = self
.balances
.borrow()
.get(&caller)
.unwrap_or(&HashMap::new())
.get(&token_id)
.unwrap_or(&HashMap::new())
.get(&eth_address)
.cloned()
.unwrap_or(&Vec::new())
.into_iter()
.find(|m| m.0 == eth_address && m.1 == amount)
{
return Some(balance.1.clone());
} else {
return None;
}
}

pub fn get_all_balances(&self, caller: Principal) -> Result<WithdrawableBalance, String> {
let token_balances = self.balances.borrow().get(&caller).cloned();
let token_balances: Option<HashMap<TokenId, Vec<(EthereumAddr, Nat)>>> =
self.balances.borrow().get(&caller).cloned();

if let Some(balances) = token_balances {
let mut destination = Vec::default();
for tokens in balances {
for tx in tokens.1 {
destination.push((tokens.0.to_string(), tx.0.to_string(), tx.1))
}
let mut transactions: Vec<(String, String, Nat)> = Vec::new();
for txs in balances {
let token_tx: Vec<(String, String, Nat)> = txs
.1
.into_iter()
.map(|tx| (txs.0.to_string(), tx.0.to_string(), tx.1))
.collect();
transactions.extend(token_tx);
}
return Ok(WithdrawableBalance(destination));
return Ok(WithdrawableBalance(transactions));
}
Err(format!("User {} has no token balances!", &caller))
}

pub fn add_balance(&self, caller: Principal, to: Principal, token_id: TokenId, amount: Nat) {
let mut binding = self.balances.borrow_mut();
let caller_txs: HashMap<TokenId, HashMap<Principal, Nat>> = HashMap::new();
let token_txs: HashMap<Principal, Nat> = HashMap::new();
let user_tx = binding
let caller_txs: HashMap<TokenId, Vec<(Principal, Nat)>> = HashMap::new();
let token_txs: Vec<(Principal, Nat)> = Vec::new();
binding
.entry(caller)
.or_insert(caller_txs)
.entry(token_id)
.or_insert(token_txs);
match user_tx.get_mut(&to) {
Some(balance) => *balance += amount,
None => {
user_tx.insert(to, amount);
}
}
.or_insert(token_txs)
.push((to, amount));
}

// Panics if theres no balance for the user/token_id or destination
pub fn update_balance(&self, caller: Principal, to: Principal, token_id: TokenId, amount: Nat) {
/// Panics if theres no balance for the user/token_id or destination
pub fn remove_balance(&self, caller: Principal, to: Principal, token_id: TokenId, amount: Nat) {
let mut binding = self.balances.borrow_mut();
let tx = binding
let txs = binding
.get_mut(&caller)
.unwrap()
.get_mut(&token_id)
.unwrap();
if amount == 0 {
tx.remove_entry(&to);
return;
}
tx.get_mut(&to).and_then(|v| Some(*v = amount));
let index = txs
.into_iter()
.position(|tx| tx.0 == to && tx.1 == amount)
.unwrap();
txs.remove(index);
}

pub fn set_user_flag(
@@ -366,8 +372,8 @@ mod tests {
#[test]
fn test_add_balance() {
let amount_1 = Nat::from(100_u32);
let amount_2 = Nat::from(100_u32);
let amount_3 = Nat::from(100_u32);
let amount_2 = Nat::from(200_u32);
let amount_3 = Nat::from(300_u32);
let caller = Principal::from_str("fle2e-ltcun-tpi5w-25chp-byb56-dfl72-f664t-slvy").unwrap();
let eth_address_1 = mock_principals::bob();
let eth_address_2 = mock_principals::john();
@@ -382,7 +388,8 @@ mod tests {
amount_1.clone(),
)
});
let current_balance_1 = STATE.with(|s| s.get_balance(caller, token_id, eth_address_1));
let current_balance_1 =
STATE.with(|s| s.get_balance(caller, token_id, eth_address_1, amount_1.clone()));
assert_eq!(current_balance_1.unwrap(), amount_1.clone());

// add amount_2 for token_1 and eth_address_2
@@ -398,7 +405,7 @@ mod tests {
});
assert_eq!(withdraw_address_count, 2);

// add amount_3 for token_1 and eth_address_1 (100 + 100)
// add amount_3 for token_1 and eth_address_1 (100 , 100)
STATE.with(|s| {
s.add_balance(
caller,
@@ -407,8 +414,9 @@ mod tests {
amount_3.clone(),
)
});
let current_balance_1 = STATE.with(|s| s.get_balance(caller, token_id, eth_address_1));
assert_eq!(current_balance_1.unwrap(), amount_3 + amount_1);
let current_balance_1 =
STATE.with(|s| s.get_balance(caller, token_id, eth_address_1, amount_3.clone()));
assert_eq!(current_balance_1.unwrap(), amount_3);
}

#[test]
@@ -429,7 +437,8 @@ mod tests {
eth_address_2=0
}
token_id_2: {
eth_address_1=300+100
eth_address_1=300
eth_address_1=100
eth_address_2=200
}
}
@@ -472,6 +481,12 @@ mod tests {

let all_balances = balances.unwrap().0;

let w = (
token_id_2.clone().to_string(),
eth_address_1.clone().to_string(),
Nat::from(100),
);

let x = (
token_id_2.clone().to_string(),
eth_address_2.clone().to_string(),
@@ -480,14 +495,15 @@ mod tests {
let y = (
token_id_2.clone().to_string(),
eth_address_1.clone().to_string(),
Nat::from(400),
Nat::from(300),
);
let z = (
token_id_1.clone().to_string(),
eth_address_1.clone().to_string(),
Nat::from(100),
);

assert!(all_balances.clone().into_iter().any(|e| e == w));
assert!(all_balances.clone().into_iter().any(|e| e == x));
assert!(all_balances.clone().into_iter().any(|e| e == y));
assert!(all_balances.into_iter().any(|e| e == z));
@@ -497,7 +513,6 @@ mod tests {
fn test_update_balance() {
let amount_1 = Nat::from(100_u32);
let amount_2 = Nat::from(200_u32);
let amount_3 = Nat::from(300_u32);
let caller = mock_principals::bob();
let eth_address_1 = mock_principals::alice();
let eth_address_2 = mock_principals::john();
@@ -528,53 +543,61 @@ mod tests {
)
});

let all_balances = STATE.with(|s| s.get_all_balances(caller.clone()));
assert_eq!(all_balances.unwrap().0.len(), 2);

/*
---- AFTER UPDATE ---
caller: {
token_id_1 : {
eth_address_1=300 <- THIS IS UPDATED 300 INTEAD OF 100
eth_address_2=200
}
}
*/
STATE.with(|s| {
s.update_balance(
s.remove_balance(
caller,
eth_address_1.clone(),
token_id_1.clone(),
amount_3.clone(),
amount_1.clone(),
)
});

let current_balance = STATE
.with(|s| s.get_balance(caller, token_id_1.clone(), eth_address_1.clone()))
.with(|s| {
s.get_balance(
caller,
token_id_1.clone(),
eth_address_2.clone(),
amount_2.clone(),
)
})
.unwrap();

assert_eq!(current_balance, amount_3);
assert_eq!(current_balance, amount_2);

let removed_balance = STATE
.with(|s| s.get_balance(caller, token_id_1.clone(), eth_address_1.clone(), amount_1));

assert!(removed_balance.is_none());

let balances = STATE.with(|s| s.get_all_balances(caller)).unwrap();
// there are 2 eth addess
assert!(balances.0.len() == 2);
// there is 1 eth addess
assert!(balances.0.len() == 1);

/*
---- AFTER UPDATE ---
caller: {
token_id_1 : {
eth_address_1=300
eth_address_2=0 <- Because its zero, it should be removed
}
}
*/
STATE.with(|s| {
s.update_balance(
caller,
eth_address_2.clone(),
token_id_1.clone(),
Nat::from(0),
)
s.remove_balance(caller, eth_address_2.clone(), token_id_1.clone(), amount_2)
});

let balances_final = STATE.with(|s| s.get_all_balances(caller)).unwrap();
assert!(balances_final.0.len() == 1);
assert!(balances_final.0.len() == 0);
}

#[test]