diff --git a/contracts/splitter/src/lib.rs b/contracts/splitter/src/lib.rs index ed56786..b2973ad 100644 --- a/contracts/splitter/src/lib.rs +++ b/contracts/splitter/src/lib.rs @@ -115,6 +115,7 @@ enum DataKey { Created(Address), HeldTokens(u64), PendingController(u64), + AccountBalance(Address, Address), } #[contractevent] @@ -644,6 +645,19 @@ impl Splitter { .persistent() .get(&DataKey::PendingController(id)) } + + /// Claims any fallback balances credited to this account due to failed payouts. + pub fn claim(env: Env, account: Address, token: Address) -> Result<(), Error> { + let key = DataKey::AccountBalance(account.clone(), token.clone()); + let held: i128 = env.storage().persistent().get(&key).unwrap_or(0); + if held == 0 { + return Err(Error::InvalidAmount); + } + env.storage().persistent().remove(&key); + let client = token::Client::new(&env, &token); + client.transfer(&env.current_contract_address(), &account, &held); + Ok(()) + } } fn load_created(env: &Env, creator: &Address) -> Vec { @@ -730,7 +744,15 @@ fn payout(env: &Env, split: &Split, from: &Address, token: &Address, amount: i12 continue; } match split.recipients.get_unchecked(i) { - Recipient::Account(addr) => client.transfer(from, &addr, &part), + Recipient::Account(addr) => match client.try_transfer(from, &addr, &part) { + Ok(Ok(())) => {} + _ => { + if from != &vault { + client.transfer(from, &vault, &part); + } + credit_account(env, &addr, token, part); + } + }, Recipient::Split(child) => { if from != &vault { client.transfer(from, &vault, &part); @@ -741,6 +763,15 @@ fn payout(env: &Env, split: &Split, from: &Address, token: &Address, amount: i12 } } +fn credit_account(env: &Env, account: &Address, token: &Address, amount: i128) { + let key = DataKey::AccountBalance(account.clone(), token.clone()); + let held: i128 = env.storage().persistent().get(&key).unwrap_or(0); + env.storage().persistent().set(&key, &(held + amount)); + env.storage() + .persistent() + .extend_ttl(&key, TTL_THRESHOLD, TTL_EXTEND_TO); +} + fn credit(env: &Env, id: u64, token: &Address, amount: i128) { let key = DataKey::Balance(id, token.clone()); let held: i128 = env.storage().persistent().get(&key).unwrap_or(0);