diff --git a/clients/runtime/src/rpc.rs b/clients/runtime/src/rpc.rs index 7a0d42ec9..829f1b748 100644 --- a/clients/runtime/src/rpc.rs +++ b/clients/runtime/src/rpc.rs @@ -1109,10 +1109,11 @@ pub trait RedeemPallet { async fn get_redeem_request(&self, redeem_id: H256) -> Result; /// Get all redeem requests requested of the given vault - async fn get_vault_redeem_requests( + async fn get_vault_redeem_requests( &self, account_id: AccountId, - ) -> Result, Error>; + filter: Box Option + Send>, + ) -> Result, Error>; async fn get_redeem_period(&self) -> Result; } @@ -1165,24 +1166,38 @@ impl RedeemPallet for SpacewalkParachain { .await } - async fn get_vault_redeem_requests( + async fn get_vault_redeem_requests( &self, account_id: AccountId, - ) -> Result, Error> { + filter: Box Option + Send>, + ) -> Result, Error> { let head = self.get_finalized_block_hash().await?; let result: Vec = self .api .rpc() .request("redeem_getVaultRedeemRequests", rpc_params![account_id, head]) .await?; - join_all( - result.into_iter().map(|key| async move { - self.get_redeem_request(key).await.map(|value| (key, value)) - }), - ) - .await - .into_iter() - .collect() + + let redeem_requests = join_all(result.into_iter().map(|key| async move { + self.get_redeem_request(key).await.map(|value| (key, value)) + })) + .await; + + let mut some_error: Option = None; + let filtered_results: Vec<_> = redeem_requests + .into_iter() + .filter_map(|item_maybe| match item_maybe { + Ok(item) => filter(item), + Err(e) => { + some_error.get_or_insert(e); + None + }, + }) + .collect(); + match some_error { + Some(err) => Err(err), + None => Ok(filtered_results), + } } async fn get_redeem_period(&self) -> Result { @@ -1256,10 +1271,11 @@ pub trait ReplacePallet { ) -> Result, Error>; /// Get all replace requests made by the given vault - async fn get_old_vault_replace_requests( + async fn get_old_vault_replace_requests( &self, account_id: AccountId, - ) -> Result, Error>; + filter: Box Option + Send>, + ) -> Result, Error>; /// Get the time difference in number of blocks between when a replace /// request is created and required completion time by a vault @@ -1352,22 +1368,39 @@ impl ReplacePallet for SpacewalkParachain { } /// Get all replace requests made by the given vault - async fn get_old_vault_replace_requests( + async fn get_old_vault_replace_requests( &self, account_id: AccountId, - ) -> Result, Error> { + filter: Box Option + Send>, + ) -> Result, Error> { let head = self.get_finalized_block_hash().await?; let result: Vec = self .api .rpc() .request("replace_getOldVaultReplaceRequests", rpc_params![account_id, head]) .await?; - join_all(result.into_iter().map(|key| async move { + + let replace_requests = join_all(result.into_iter().map(|key| async move { self.get_replace_request(key).await.map(|value| (key, value)) })) - .await - .into_iter() - .collect() + .await; + + let mut some_error: Option = None; + let filtered_results: Vec<_> = replace_requests + .into_iter() + .filter_map(|item_maybe| match item_maybe { + Ok(item) => filter(item), + Err(e) => { + some_error.get_or_insert(e); + None + }, + }) + .collect(); + + match some_error { + Some(err) => Err(err), + None => Ok(filtered_results), + } } async fn get_replace_period(&self) -> Result { diff --git a/clients/vault/src/cancellation.rs b/clients/vault/src/cancellation.rs index 3f98fbfa8..f680e11a3 100644 --- a/clients/vault/src/cancellation.rs +++ b/clients/vault/src/cancellation.rs @@ -169,16 +169,16 @@ impl Canceller

for ReplaceCance // verbose drain_filter fn drain_expired(requests: &mut Vec, current_height: u32) -> Vec { let mut expired = Vec::new(); - let has_expired = |request: &ActiveRequest| current_height > request.parachain_deadline_height; - let mut i = 0; - while i != requests.len() { - if has_expired(&requests[i]) { - let req = requests.remove(i); - expired.push(req); + + requests.retain(|req| { + if current_height > req.parachain_deadline_height { + expired.push(*req); + false } else { - i += 1; + true } - } + }); + expired } diff --git a/clients/vault/src/execution.rs b/clients/vault/src/execution.rs index a80b022e9..eaf6b4536 100644 --- a/clients/vault/src/execution.rs +++ b/clients/vault/src/execution.rs @@ -374,29 +374,38 @@ pub async fn execute_open_requests( let parachain_rpc = ¶chain_rpc; let vault_id = parachain_rpc.get_account_id().clone(); - // get all redeem and replace requests - let (redeem_requests, replace_requests) = try_join!( - parachain_rpc.get_vault_redeem_requests(vault_id.clone()), - parachain_rpc.get_old_vault_replace_requests(vault_id.clone()), - )?; - - let open_redeems = redeem_requests - .into_iter() - .filter(|(_, request)| request.status == RedeemRequestStatus::Pending) - .filter_map(|(hash, request)| { + //closure to filter and transform redeem_requests + let filter_redeem_reqs = move |(hash, request): (H256, SpacewalkRedeemRequest)| { + if request.status == RedeemRequestStatus::Pending { Request::from_redeem_request(hash, request, payment_margin).ok() - }); + } else { + None + } + }; - let open_replaces = replace_requests - .into_iter() - .filter(|(_, request)| request.status == ReplaceRequestStatus::Pending) - .filter_map(|(hash, request)| { + //closure to filter and transform replace_requests + let filter_replace_reqs = move |(hash, request): (H256, SpacewalkReplaceRequest)| { + if request.status == ReplaceRequestStatus::Pending { Request::from_replace_request(hash, request, payment_margin).ok() - }); + } else { + None + } + }; + + // get all redeem and replace requests + let (open_redeems, open_replaces) = try_join!( + parachain_rpc + .get_vault_redeem_requests::(vault_id.clone(), Box::new(filter_redeem_reqs)), + parachain_rpc.get_old_vault_replace_requests::( + vault_id.clone(), + Box::new(filter_replace_reqs) + ), + )?; // collect all requests into a hashmap, indexed by their id let mut open_requests = open_redeems - .chain(open_replaces) + .into_iter() + .chain(open_replaces.into_iter()) .map(|x| (derive_shortened_request_id(&x.hash.0), x)) .collect::>(); @@ -461,7 +470,7 @@ pub async fn execute_open_requests( // All requests remaining in the hashmap did not have a Stellar payment yet, so pay // and execute all of these - for (_, request) in open_requests { + for (_, request) in open_requests.into_iter() { // there are potentially a large number of open requests - pay and execute each // in a separate task to ensure that awaiting confirmations does not significantly // delay other requests diff --git a/clients/vault/src/metrics.rs b/clients/vault/src/metrics.rs index e8cffde98..6b12d8c8a 100644 --- a/clients/vault/src/metrics.rs +++ b/clients/vault/src/metrics.rs @@ -15,7 +15,7 @@ use runtime::{ types::currency_id::CurrencyIdExt, AggregateUpdatedEvent, CollateralBalancesPallet, CurrencyId, Error as RuntimeError, FixedU128, IssuePallet, IssueRequestStatus, OracleKey, RedeemPallet, RedeemRequestStatus, SecurityPallet, - SpacewalkParachain, UtilFuncs, VaultId, VaultRegistryPallet, H256, + SpacewalkParachain, SpacewalkRedeemRequest, UtilFuncs, VaultId, VaultRegistryPallet, H256, }; use service::{ warp::{Rejection, Reply}, @@ -469,8 +469,14 @@ pub async fn poll_metrics< loop { publish_native_currency_balance(parachain_rpc).await?; publish_issue_count(parachain_rpc, vault_id_manager).await; + + let pass_all_filter = |item: (H256, SpacewalkRedeemRequest)| Some(item); + if let Ok(redeems) = parachain_rpc - .get_vault_redeem_requests(parachain_rpc.get_account_id().clone()) + .get_vault_redeem_requests::<(H256, SpacewalkRedeemRequest)>( + parachain_rpc.get_account_id().clone(), + Box::new(pass_all_filter), + ) .await { publish_redeem_count(vault_id_manager, &redeems).await; diff --git a/clients/vault/src/oracle/collector/proof_builder.rs b/clients/vault/src/oracle/collector/proof_builder.rs index 58a9eae3a..6218aedbc 100644 --- a/clients/vault/src/oracle/collector/proof_builder.rs +++ b/clients/vault/src/oracle/collector/proof_builder.rs @@ -114,9 +114,7 @@ impl ScpMessageCollector { &self, slot: Slot, sender: &StellarMessageSender, - ) -> UnlimitedVarArray { - let empty = UnlimitedVarArray::new_empty(); - + ) -> Option> { if let Some(envelopes) = self.envelopes_map().get(&slot) { // lacking envelopes if envelopes.len() < get_min_externalized_messages(self.is_public()) { @@ -124,14 +122,14 @@ impl ScpMessageCollector { "Proof Building for slot {slot}: not enough envelopes to build proof " ); } else { - return UnlimitedVarArray::new(envelopes.clone()).unwrap_or(empty) + return UnlimitedVarArray::new(envelopes.clone()).ok() } } // forcefully retrieve envelopes self.fetch_missing_envelopes(slot, sender).await; - empty + return None } /// Returns either a TransactionSet or a ProofStatus saying it failed to retrieve the set. @@ -179,15 +177,15 @@ impl ScpMessageCollector { /// * `slot` - the slot where the txset is to get. /// * `sender` - used to send messages to Stellar Node pub async fn build_proof(&self, slot: Slot, sender: &StellarMessageSender) -> Option { - let envelopes = self.get_envelopes(slot, sender).await; + let envelopes_maybe = self.get_envelopes(slot, sender).await; // return early if we don't have enough envelopes or the tx_set - if envelopes.len() == 0 { - tracing::debug!("Couldn't built proof for slot {slot} due to missing envelopes"); + if let Some(envelopes) = envelopes_maybe { + let tx_set = self.get_txset(slot, sender).await?; + return Some(Proof { slot, envelopes, tx_set }) + } else { + tracing::debug!("Couldn't build proof for slot {slot} due to missing envelopes"); return None } - - let tx_set = self.get_txset(slot, sender).await?; - Some(Proof { slot, envelopes, tx_set }) } /// Insert envelopes fetched from the archive to the map diff --git a/clients/vault/src/replace.rs b/clients/vault/src/replace.rs index 8f98ba2d7..9eb5d3317 100644 --- a/clients/vault/src/replace.rs +++ b/clients/vault/src/replace.rs @@ -248,47 +248,54 @@ mod tests { } mockall::mock! { - Provider {} - - #[async_trait] - pub trait VaultRegistryPallet { - async fn get_vault(&self, vault_id: &VaultId) -> Result; - async fn get_vaults_by_account_id(&self, account_id: &AccountId) -> Result, RuntimeError>; - async fn get_all_vaults(&self) -> Result, RuntimeError>; - async fn register_vault(&self, vault_id: &VaultId, collateral: u128) -> Result<(), RuntimeError>; - async fn deposit_collateral(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>; - async fn withdraw_collateral(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>; - async fn get_public_key(&self) -> Result, RuntimeError>; - async fn register_public_key(&self, public_key: StellarPublicKeyRaw) -> Result<(), RuntimeError>; - async fn get_required_collateral_for_wrapped(&self, amount: u128, wrapped_currency: CurrencyId, collateral_currency: CurrencyId) -> Result; - async fn get_required_collateral_for_vault(&self, vault_id: VaultId) -> Result; - async fn get_vault_total_collateral(&self, vault_id: VaultId) -> Result; - async fn get_collateralization_from_vault(&self, vault_id: VaultId, only_issued: bool) -> Result; - } + Provider {} + + #[async_trait] + pub trait VaultRegistryPallet { + async fn get_vault(&self, vault_id: &VaultId) -> Result; + async fn get_vaults_by_account_id(&self, account_id: &AccountId) -> Result, RuntimeError>; + async fn get_all_vaults(&self) -> Result, RuntimeError>; + async fn register_vault(&self, vault_id: &VaultId, collateral: u128) -> Result<(), RuntimeError>; + async fn deposit_collateral(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>; + async fn withdraw_collateral(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>; + async fn get_public_key(&self) -> Result, RuntimeError>; + async fn register_public_key(&self, public_key: StellarPublicKeyRaw) -> Result<(), RuntimeError>; + async fn get_required_collateral_for_wrapped(&self, amount: u128, wrapped_currency: CurrencyId, collateral_currency: CurrencyId) -> Result; + async fn get_required_collateral_for_vault(&self, vault_id: VaultId) -> Result; + async fn get_vault_total_collateral(&self, vault_id: VaultId) -> Result; + async fn get_collateralization_from_vault(&self, vault_id: VaultId, only_issued: bool) -> Result; + } - #[async_trait] - pub trait ReplacePallet { - async fn request_replace(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>; - async fn withdraw_replace(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>; - async fn accept_replace(&self, new_vault: &VaultId, old_vault: &VaultId, amount: u128, collateral: u128, stellar_address: StellarPublicKeyRaw) -> Result<(), RuntimeError>; - async fn execute_replace(&self, replace_id: H256, tx_env: &[u8], scp_envs: &[u8], tx_set: &[u8]) -> Result<(), RuntimeError>; - async fn cancel_replace(&self, replace_id: H256) -> Result<(), RuntimeError>; - async fn get_new_vault_replace_requests(&self, account_id: AccountId) -> Result, RuntimeError>; - async fn get_old_vault_replace_requests(&self, account_id: AccountId) -> Result, RuntimeError>; - async fn get_replace_period(&self) -> Result; - async fn get_replace_request(&self, replace_id: H256) -> Result; - async fn get_replace_dust_amount(&self) -> Result; - } - #[async_trait] - pub trait CollateralBalancesPallet { - async fn get_free_balance(&self, currency_id: CurrencyId) -> Result; - async fn get_native_balance_for_id(&self, id: &AccountId) -> Result; - async fn get_free_balance_for_id(&self, id: AccountId, currency_id: CurrencyId) -> Result; - async fn get_reserved_balance(&self, currency_id: CurrencyId) -> Result; - async fn get_reserved_balance_for_id(&self, id: AccountId, currency_id: CurrencyId) -> Result; - async fn transfer_to(&self, recipient: &AccountId, amount: u128, currency_id: CurrencyId) -> Result<(), RuntimeError>; } + #[async_trait] + pub trait ReplacePallet { + async fn request_replace(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>; + async fn withdraw_replace(&self, vault_id: &VaultId, amount: u128) -> Result<(), RuntimeError>; + async fn accept_replace(&self, new_vault: &VaultId, old_vault: &VaultId, amount: u128, collateral: u128, stellar_address: StellarPublicKeyRaw) -> Result<(), RuntimeError>; + async fn execute_replace(&self, replace_id: H256, tx_env: &[u8], scp_envs: &[u8], tx_set: &[u8]) -> Result<(), RuntimeError>; + async fn cancel_replace(&self, replace_id: H256) -> Result<(), RuntimeError>; + async fn get_new_vault_replace_requests(&self, account_id: AccountId) -> Result, RuntimeError>; + async fn get_old_vault_replace_requests( + &self, + account_id: AccountId, + filter: Box Option + Send>, + ) -> Result, RuntimeError>; + async fn get_replace_period(&self) -> Result; + async fn get_replace_request(&self, replace_id: H256) -> Result; + async fn get_replace_dust_amount(&self) -> Result; + } + + + #[async_trait] + pub trait CollateralBalancesPallet { + async fn get_free_balance(&self, currency_id: CurrencyId) -> Result; + async fn get_native_balance_for_id(&self, id: &AccountId) -> Result; + async fn get_free_balance_for_id(&self, id: AccountId, currency_id: CurrencyId) -> Result; + async fn get_reserved_balance(&self, currency_id: CurrencyId) -> Result; + async fn get_reserved_balance_for_id(&self, id: AccountId, currency_id: CurrencyId) -> Result; + async fn transfer_to(&self, recipient: &AccountId, amount: u128, currency_id: CurrencyId) -> Result<(), RuntimeError>; + } } impl Clone for MockProvider { diff --git a/clients/vault/src/system.rs b/clients/vault/src/system.rs index b02802f4e..eb04e4817 100644 --- a/clients/vault/src/system.rs +++ b/clients/vault/src/system.rs @@ -403,12 +403,16 @@ impl VaultService { let startup_height = self.await_parachain_block().await?; let account_id = self.spacewalk_parachain.get_account_id().clone(); + let mut amount_is_none: bool = false; let parsed_auto_register = self .config .auto_register .clone() .into_iter() .map(|(collateral, wrapped, amount)| { + if amount.is_none() { + amount_is_none = true; + } Ok(( CurrencyId::try_from_symbol(collateral)?, CurrencyId::try_from_symbol(wrapped)?, @@ -420,9 +424,7 @@ impl VaultService { .map_err(ServiceError::Abort)?; // exit if auto-register uses faucet and faucet url not set - if parsed_auto_register.iter().any(|(_, _, o)| o.is_none()) && - self.config.faucet_url.is_none() - { + if amount_is_none && self.config.faucet_url.is_none() { return Err(ServiceError::Abort(Error::FaucetUrlNotSet)) } diff --git a/clients/wallet/src/horizon/horizon.rs b/clients/wallet/src/horizon/horizon.rs index 8609370ee..8e5593b3f 100644 --- a/clients/wallet/src/horizon/horizon.rs +++ b/clients/wallet/src/horizon/horizon.rs @@ -29,7 +29,7 @@ use crate::{ const POLL_INTERVAL: u64 = 5000; /// See [Stellar doc](https://developers.stellar.org/api/introduction/pagination/page-arguments) -pub const DEFAULT_PAGE_SIZE: i64 = 200; +pub const DEFAULT_PAGE_SIZE: u8 = 200; pub fn horizon_url(is_public_network: bool, is_need_fallback: bool) -> &'static str { if is_public_network { @@ -61,7 +61,7 @@ impl HorizonClient for reqwest::Client { account_id: A, is_public_network: bool, cursor: PagingToken, - limit: i64, + limit: u8, order_ascending: bool, ) -> Result { let account_id_encoded = account_id.as_encoded_string()?; diff --git a/clients/wallet/src/horizon/traits.rs b/clients/wallet/src/horizon/traits.rs index 6dfde62c3..6931ff932 100644 --- a/clients/wallet/src/horizon/traits.rs +++ b/clients/wallet/src/horizon/traits.rs @@ -22,7 +22,7 @@ pub trait HorizonClient { account_id: A, is_public_network: bool, cursor: PagingToken, - limit: i64, + limit: u8, order_ascending: bool, ) -> Result; diff --git a/pallets/issue/src/lib.rs b/pallets/issue/src/lib.rs index 545bed80b..760564c87 100644 --- a/pallets/issue/src/lib.rs +++ b/pallets/issue/src/lib.rs @@ -387,9 +387,9 @@ impl Pallet { Self::check_volume(amount_requested.clone())?; + // ensure that the vault is accepting new issues (vault is active) let vault = ext::vault_registry::get_active_vault_from_id::(&vault_id)?; - // ensure that the vault is accepting new issues ensure!(vault.status == VaultStatus::Active(true), Error::::VaultNotAcceptingNewIssues); // Check that the vault is currently not banned diff --git a/pallets/vault-registry/src/lib.rs b/pallets/vault-registry/src/lib.rs index f888c0c47..7e1199576 100644 --- a/pallets/vault-registry/src/lib.rs +++ b/pallets/vault-registry/src/lib.rs @@ -198,7 +198,6 @@ pub mod pallet { let vault = Self::get_active_rich_vault_from_id(&vault_id)?; let amount = Amount::new(amount, currency_pair.collateral); - Self::try_deposit_collateral(&vault_id, &amount)?; Self::deposit_event(Event::::DepositCollateral { diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs index 8717d2a65..bb486c44f 100644 --- a/primitives/src/lib.rs +++ b/primitives/src/lib.rs @@ -593,11 +593,11 @@ impl TryFrom<(&str, AssetIssuer)> for CurrencyId { if slice.len() <= 4 { let mut code: Bytes4 = [0; 4]; code[..slice.len()].copy_from_slice(slice.as_bytes()); - Ok(CurrencyId::AlphaNum4(code, issuer)) - } else if slice.len() > 4 && slice.len() <= 12 { + return Ok(CurrencyId::AlphaNum4(code, issuer)) + } else if slice.len() <= 12 { let mut code: Bytes12 = [0; 12]; code[..slice.len()].copy_from_slice(slice.as_bytes()); - Ok(CurrencyId::AlphaNum12(code, issuer)) + return Ok(CurrencyId::AlphaNum12(code, issuer)) } else { Err("More than 12 bytes not supported") } @@ -844,6 +844,8 @@ impl TransactionEnvelopeExt for TransactionEnvelope { let recipient_account_muxed = MuxedAccount::KeyTypeEd25519(to); let recipient_account_pk = PublicKey::PublicKeyTypeEd25519(to); + let mut transferred_amount: StellarStroops = 0; + let tx_operations: Vec = match self { TransactionEnvelope::EnvelopeTypeTxV0(env) => env.tx.operations.get_vec().clone(), TransactionEnvelope::EnvelopeTypeTx(env) => env.tx.operations.get_vec().clone(), @@ -851,34 +853,40 @@ impl TransactionEnvelopeExt for TransactionEnvelope { TransactionEnvelope::Default(_) => Vec::new(), }; - let mut transferred_amount: StellarStroops = 0; - for x in tx_operations { - match x.body { + if tx_operations.len() == 0 { + return BalanceConversion::unlookup(transferred_amount) + } + + transferred_amount = tx_operations.iter().fold(0i64, |acc, x| { + match &x.body { OperationBody::Payment(payment) => { if payment.destination.eq(&recipient_account_muxed) && payment.asset == asset { - transferred_amount = transferred_amount.saturating_add(payment.amount); + acc.saturating_add(payment.amount) + } else { + acc } }, OperationBody::CreateClaimableBalance(payment) => { // for security reasons, we only count operations that have the // recipient as a single claimer and unconditional claim predicate if payment.claimants.len() == 1 { - let Claimant::ClaimantTypeV0(claimant) = - payment.claimants.get_vec()[0].clone(); + let Claimant::ClaimantTypeV0(claimant) = &payment.claimants.get_vec()[0]; if claimant.destination.eq(&recipient_account_pk) && payment.asset == asset && claimant.predicate == ClaimPredicate::ClaimPredicateUnconditional { - transferred_amount = transferred_amount.saturating_add(payment.amount); + acc.saturating_add(payment.amount) + } else { + acc } + } else { + acc } }, - _ => { - // ignore other operations - }, + _ => acc, // ignore other operations } - } + }); // `transferred_amount` is in stroops, so we need to convert it BalanceConversion::unlookup(transferred_amount)