From 0875a7f34f5e332dc91cc1ba58414e9e8a8e0230 Mon Sep 17 00:00:00 2001 From: Doug Chimento Date: Sun, 5 May 2024 14:41:54 +0300 Subject: [PATCH 1/2] Adding hooks endpoint --- src/api/hooks.rs | 34 ++++++++++++++++++++++++++++++++++ src/types/hooks.rs | 7 +++++++ 2 files changed, 41 insertions(+) create mode 100644 src/api/hooks.rs create mode 100644 src/types/hooks.rs diff --git a/src/api/hooks.rs b/src/api/hooks.rs new file mode 100644 index 0000000..997b7c5 --- /dev/null +++ b/src/api/hooks.rs @@ -0,0 +1,34 @@ +use crate::api::Success; +use crate::types::hooks::HookResponse; +use crate::Client; +use crate::Result; +use serde_derive::{Deserialize, Serialize}; + +impl Client { + /// Resends all failed webhook notifications. + /// + /// See + /// * [resendWebhooks](https://docs.fireblocks.com/api/swagger-ui/#/Webhooks/resendWebhooks) + #[tracing::instrument(level = "debug", skip(self))] + pub async fn hooks_resend(&self) -> Result { + let u = self.build_url("webhooks/resend")?.0; + self.post::(u, None).await + } + + /// Resend a specific transaction by txId + /// + /// See + /// * [resendTransactionWebhooks](https://docs.fireblocks.com/api/swagger-ui/#/Webhooks/resendTransactionWebhooks) + #[tracing::instrument(level = "debug", skip(self))] + pub async fn hooks_resend_tx(&self, tx_id: &str, created: bool, updated: bool) -> Result { + #[derive(Debug, Deserialize, Serialize, Default)] + #[serde(rename_all = "camelCase")] + struct HookTransaction { + resend_created: bool, + resend_status_updated: bool, + } + let request = HookTransaction { resend_created: created, resend_status_updated: updated }; + let u = self.build_url(format!("webhooks/resend/{tx_id}"))?.0; + self.post::(u, Some(request).as_ref()).await + } +} diff --git a/src/types/hooks.rs b/src/types/hooks.rs new file mode 100644 index 0000000..d63e4c4 --- /dev/null +++ b/src/types/hooks.rs @@ -0,0 +1,7 @@ +use serde_derive::Deserialize; + +#[derive(Debug, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct HookResponse { + pub message_count: u32, +} From 7a75187727827d335833db84a6604231985b1e75 Mon Sep 17 00:00:00 2001 From: Doug Chimento Date: Sun, 5 May 2024 14:51:09 +0300 Subject: [PATCH 2/2] Refactor: Adding Serialize and Clone. Removed deadcode warning --- Cargo.toml | 4 +-- src/api/mod.rs | 8 ++++- src/api/vaults.rs | 8 ++--- src/lib.rs | 52 ++++++++++++++++++++++++------ src/types/address.rs | 3 -- src/types/asset.rs | 3 -- src/types/connect.rs | 8 ----- src/types/fee.rs | 2 -- src/types/mod.rs | 2 +- src/types/page.rs | 1 - src/types/transaction.rs | 69 ++++++++++++++++++++-------------------- src/types/vault.rs | 4 --- src/types/wallet.rs | 3 -- 13 files changed, 89 insertions(+), 78 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d9cd7e2..f2a7416 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "fireblocks-sdk" resolver = "2" -version = "0.3.0" +version = "0.3.1" authors = ["Doug Chimento "] description = "Rust implementation of the Fireblocks SDK" readme = "README.md" @@ -20,7 +20,7 @@ crate-type = ["cdylib", "rlib"] [lints.rust] unsafe_code = "forbid" -dead_code = "allow" + [lints.clippy] enum_glob_use = "deny" diff --git a/src/api/mod.rs b/src/api/mod.rs index 8d3ad8e..0d4b486 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,7 +1,8 @@ -use serde_derive::Serialize; +use serde_derive::{Deserialize, Serialize}; mod contracts; mod external_wallets; +mod hooks; mod internal_wallets; mod staking; mod transactions; @@ -19,3 +20,8 @@ pub struct WalletCreateAsset { pub address: String, pub tag: String, } + +#[derive(Debug, Deserialize, Default)] +pub struct Success { + pub success: bool, +} diff --git a/src/api/vaults.rs b/src/api/vaults.rs index 6f0e0b3..3e634a9 100644 --- a/src/api/vaults.rs +++ b/src/api/vaults.rs @@ -1,18 +1,14 @@ +use crate::api::Success; use crate::types::{ Account, Address, AddressContainer, CreateAccount, CreateAddressResponse, PaginatedAssetWallet, VaultAccounts, VaultRenameResponse, }; use crate::Client; use crate::Result; -use serde_derive::{Deserialize, Serialize}; +use serde_derive::Serialize; use std::borrow::Borrow; use std::fmt::{Debug, Display}; -#[derive(Debug, Deserialize, Default)] -struct Success { - success: bool, -} - impl Client { /// Create an asset (address) for a vault account /// diff --git a/src/lib.rs b/src/lib.rs index 5734ef6..76d0d87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -314,20 +314,19 @@ mod tests { if !config.is_ok() { return Ok(()); } + let c = config.client(); let name = format!("c-{}", vault_name()); - let (contract_response, id) = config.client().contract_create(&name).await?; + let (contract_response, id) = c.contract_create(&name).await?; assert!(!id.is_empty()); assert_eq!(contract_response.name, name); assert!(!contract_response.id.is_empty()); - let (addr_response, _) = config - .client() - .contract_asset(&contract_response.id, ASSET_ETH_TEST, "0x9bb4d44e6963260a1850926e8f6beb8d5803836f") - .await?; + let (addr_response, _) = + c.contract_asset(&contract_response.id, ASSET_ETH_TEST, "0x9bb4d44e6963260a1850926e8f6beb8d5803836f").await?; assert_eq!(addr_response.id, ASSET_ETH_TEST); - - config.client().contract_delete(&name).await?; - config.client().contracts().await?; + c.contract(&contract_response.id).await?; + c.contract_delete(&name).await?; + c.contracts().await?; Ok(()) } @@ -423,7 +422,15 @@ mod tests { if !config.is_ok() { return Ok(()); } - config.client().wallet_connections().await?; + let c = config.client(); + c.wallet_connections().await?; + if let Err(e) = c.wallet_connection_delete("wallet-connect-id").await { + assert!(e.to_string().contains("wallet-connect-id not found")); + } + + if let Err(e) = c.wallet_connection_approve("wallet-connect-id", true).await { + assert!(e.to_string().contains("wallet-connect-id not found")); + } Ok(()) } @@ -496,6 +503,33 @@ mod tests { Ok(()) } + #[rstest::rstest] + #[tokio::test] + async fn test_hooks(config: Config) -> color_eyre::Result<()> { + if !config.is_ok() { + return Ok(()); + } + let c = config.client(); + match c.hooks_resend().await { + Ok(result) => { + assert!(result.0.message_count > 0); + }, + Err(e) => { + assert!(e.to_string().contains("Internal Fireblocks Error")); + }, + }; + + match c.hooks_resend_tx("e01b1c68-2d26-45dc-bb02-4cc9152295e1", true, true).await { + Err(e) => { + assert!(e.to_string().contains("Internal Fireblocks Error")); + }, + Ok(result) => { + assert!(result.0.success); + }, + } + Ok(()) + } + #[rstest::rstest] #[tokio::test] async fn test_paged_transactions(config: Config) -> color_eyre::Result<()> { diff --git a/src/types/address.rs b/src/types/address.rs index 7475764..c112e76 100644 --- a/src/types/address.rs +++ b/src/types/address.rs @@ -31,7 +31,6 @@ where #[derive(Debug, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct AddressContainer { pub addresses: Vec
, pub paging: Option, @@ -39,7 +38,6 @@ pub struct AddressContainer { #[derive(Debug, Serialize, Deserialize, Clone, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct CreateAddressResponse { pub id: String, pub address: String, @@ -47,7 +45,6 @@ pub struct CreateAddressResponse { #[derive(Debug, Serialize, Deserialize, Clone, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct Address { pub asset_id: Asset, pub address: String, diff --git a/src/types/asset.rs b/src/types/asset.rs index b960117..78cb9c2 100644 --- a/src/types/asset.rs +++ b/src/types/asset.rs @@ -5,7 +5,6 @@ use serde_derive::{Deserialize, Serialize}; #[derive(Debug, Serialize, Deserialize, Clone, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct SupportedAsset { pub id: Asset, pub name: String, @@ -18,7 +17,6 @@ pub struct SupportedAsset { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct AssetResponse { #[serde(deserialize_with = "deserialize_str_u64", default)] pub vault_id: u64, @@ -34,7 +32,6 @@ pub struct AssetResponse { #[derive(Debug, Serialize, Deserialize, Default, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct AccountAsset { pub id: String, pub total: BigDecimal, diff --git a/src/types/connect.rs b/src/types/connect.rs index ce84558..95e67de 100644 --- a/src/types/connect.rs +++ b/src/types/connect.rs @@ -3,7 +3,6 @@ use serde_derive::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct Metadata { pub app_url: String, pub app_name: String, @@ -14,7 +13,6 @@ pub struct Metadata { #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct WalletConnection { pub id: String, #[serde(rename = "userId")] @@ -33,14 +31,12 @@ pub struct WalletConnection { #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct NextPage { pub next: String, } #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct PagedWalletConnectResponse { pub data: Vec, pub page: Option, @@ -48,7 +44,6 @@ pub struct PagedWalletConnectResponse { #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -#[allow(dead_code)] pub enum FeeLevel { #[default] Medium, @@ -56,7 +51,6 @@ pub enum FeeLevel { #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct WalletConnectRequest { pub fee_level: FeeLevel, pub vault_account_id: i32, @@ -66,14 +60,12 @@ pub struct WalletConnectRequest { #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct WalletConnectResponse { pub id: String, } #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct WalletApprove { pub approve: bool, } diff --git a/src/types/fee.rs b/src/types/fee.rs index 3ba2099..1b734d6 100644 --- a/src/types/fee.rs +++ b/src/types/fee.rs @@ -3,7 +3,6 @@ use serde::Deserialize; #[derive(Debug, Deserialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct Fee { pub network_fee: Option, pub gas_price: Option, @@ -14,7 +13,6 @@ pub struct Fee { #[derive(Debug, Deserialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct EstimateFee { pub low: Fee, pub medium: Fee, diff --git a/src/types/mod.rs b/src/types/mod.rs index ad03dae..a7caff5 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -8,6 +8,7 @@ pub mod address; pub mod asset; pub mod connect; pub mod fee; +pub mod hooks; mod page; pub mod staking; pub mod transaction; @@ -66,7 +67,6 @@ where #[derive(Debug, Deserialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct PaginatedAssetWallet { pub asset_wallets: Vec, pub paging: Paging, diff --git a/src/types/page.rs b/src/types/page.rs index 3bd0a76..c675394 100644 --- a/src/types/page.rs +++ b/src/types/page.rs @@ -4,7 +4,6 @@ use serde_derive::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct Paging { pub before: Option, pub after: Option, diff --git a/src/types/transaction.rs b/src/types/transaction.rs index 94b4524..5e34d72 100644 --- a/src/types/transaction.rs +++ b/src/types/transaction.rs @@ -33,7 +33,6 @@ pub enum PeerType { #[allow(non_camel_case_types)] #[derive(Debug, Deserialize, Serialize, Clone, Default)] #[allow(clippy::upper_case_acronyms)] -#[allow(dead_code)] #[cfg_attr(feature = "sql", derive(sqlx::Type))] #[cfg_attr(feature = "sql", sqlx(type_name = "transaction_operation_type", rename_all = "lowercase"))] pub enum TransactionOperation { @@ -127,11 +126,11 @@ impl TransactionListBuilder { self } - pub(crate) fn before(&mut self, t: &Epoch) -> &mut Self { + pub fn before(&mut self, t: &Epoch) -> &mut Self { self.add_instant("before", t) } - pub(crate) fn after(&mut self, t: &Epoch) -> &mut Self { + pub fn after(&mut self, t: &Epoch) -> &mut Self { self.add_instant("after", t) } @@ -139,6 +138,7 @@ impl TransactionListBuilder { self.params.push((param.to_owned(), Self::epoch(t))); self } + fn epoch(before: &Epoch) -> String { format!("{}", before.timestamp_millis()) } @@ -161,9 +161,8 @@ pub enum VirtualType { OEC_FEE_BANK, } -#[derive(Debug, Deserialize, Serialize, Default)] +#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct TransferPeerPath { #[serde(deserialize_with = "deserialize_option_empty_object", default)] pub id: Option, @@ -181,9 +180,8 @@ pub struct TransferPeerPath { pub wallet_id: Option, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct AmountInfo { amount: Option, requested_amount: Option, @@ -192,9 +190,8 @@ pub struct AmountInfo { amount_usd: Option, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct BlockInfo { pub block_hash: Option, //#[serde(deserialize_with = "deserialize_str_u64_opt")] @@ -202,45 +199,40 @@ pub struct BlockInfo { pub block_height: Option, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct FeeInfo { - network_fee: Option, - service_fee: Option, - gas_price: Option, + pub network_fee: Option, + pub service_fee: Option, + pub gas_price: Option, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct RewardInfo { src_rewards: Option, dest_rewards: Option, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct FeePayerInfo { fee_payer_account_id: Option, } -#[derive(Debug, Deserialize)] -#[allow(dead_code)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub enum Logic { OR, AND, } -#[derive(Debug, Deserialize)] + +#[derive(Debug, Deserialize, Serialize, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct AuthorizationInfo { allow_operator_as_authorizer: bool, logic: Logic, } -#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Default)] -#[allow(dead_code)] +#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, Clone, Default)] #[allow(non_camel_case_types)] #[cfg_attr(feature = "sql", derive(sqlx::Type))] #[cfg_attr(feature = "sql", sqlx(type_name = "signing_algorithm", rename_all = "lowercase"))] @@ -251,16 +243,14 @@ pub enum SigningAlgorithm { MPC_EDDSA_ED25519, } -#[derive(Debug, Deserialize, Default)] +#[derive(Debug, Deserialize, Serialize, Clone, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct Signature { pub full_sig: Option, } -#[derive(Debug, Deserialize, Default)] +#[derive(Debug, Deserialize, Serialize, Clone, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct SignedMessage { pub derivation_path: Vec, pub algorithm: SigningAlgorithm, @@ -270,7 +260,6 @@ pub struct SignedMessage { #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct OneTimeAddress { pub address: String, #[serde(skip_serializing_if = "Option::is_none")] @@ -279,7 +268,6 @@ pub struct OneTimeAddress { #[derive(Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct DestinationTransferPeerPath { #[serde(rename = "type")] pub peer_type: PeerType, @@ -294,16 +282,14 @@ pub struct DestinationTransferPeerPath { pub one_time_address: Option, } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct TransactionDestination { amount: BigDecimal, } -#[derive(Debug, Deserialize, Default)] +#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct Transaction { pub id: String, pub asset_id: Asset, @@ -413,8 +399,21 @@ pub struct UnsignedMessage { #[derive(Debug, Deserialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct CreateTransactionResponse { pub id: String, pub status: TransactionStatus, } + +#[cfg(test)] +mod test { + use crate::types::TransactionListBuilder; + use chrono::Utc; + + #[test] + fn transaction_builder() -> color_eyre::Result<()> { + let request = TransactionListBuilder::new().sort_desc().order_last_updated().before(&Utc::now()).build()?; + let found = request.into_iter().find(|v| v.0 == "before"); + assert!(found.is_some()); + Ok(()) + } +} diff --git a/src/types/vault.rs b/src/types/vault.rs index e30cca3..f9004c1 100644 --- a/src/types/vault.rs +++ b/src/types/vault.rs @@ -4,7 +4,6 @@ use crate::types::{asset::AccountAsset, deserialize_str_i32, Paging}; #[derive(Debug, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct VaultAccounts { pub accounts: Vec, pub paging: Paging, @@ -14,7 +13,6 @@ pub struct VaultAccounts { #[derive(Debug, Serialize, Deserialize, Clone, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct Account { #[serde(deserialize_with = "deserialize_str_i32")] pub id: i32, @@ -28,7 +26,6 @@ pub struct Account { #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct CreateAccount { pub name: String, #[serde(rename = "hiddenOnUI")] @@ -39,7 +36,6 @@ pub struct CreateAccount { #[derive(Debug, Default, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct VaultRenameResponse { pub name: String, #[serde(deserialize_with = "deserialize_str_i32")] diff --git a/src/types/wallet.rs b/src/types/wallet.rs index 23fe3ab..f17d354 100644 --- a/src/types/wallet.rs +++ b/src/types/wallet.rs @@ -3,7 +3,6 @@ use serde_derive::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize, Default)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct WalletContainer { pub id: String, pub name: String, @@ -13,7 +12,6 @@ pub struct WalletContainer { #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] -#[allow(dead_code)] pub struct ExternalWalletAsset { pub id: String, pub status: String, @@ -23,7 +21,6 @@ pub struct ExternalWalletAsset { } #[derive(Debug, Deserialize, Serialize, Default)] -#[allow(dead_code)] pub struct WalletCreateAssetResponse { pub id: Asset, }