Skip to content

Commit

Permalink
funds-manager: Reorganize api types and helpers ahead of execution impl
Browse files Browse the repository at this point in the history
  • Loading branch information
joeykraut committed Aug 9, 2024
1 parent bcb7a24 commit cf43283
Show file tree
Hide file tree
Showing 16 changed files with 649 additions and 475 deletions.
6 changes: 6 additions & 0 deletions funds-manager/funds-manager-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ edition = "2021"
[dependencies]

renegade-api = { package = "external-api", workspace = true }

ethers = "2"
hex = "0.4.3"
hmac = "0.12.1"
http = "0.2.12"
itertools = "0.13.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sha2 = "0.10.7"
uuid = "1.7.1"

[dev-dependencies]
rand = "0.8.5"
202 changes: 3 additions & 199 deletions funds-manager/funds-manager-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,202 +3,6 @@
#![deny(clippy::missing_docs_in_private_items)]

pub mod auth;

use renegade_api::types::ApiWallet;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

// --------------
// | Api Routes |
// --------------

/// The ping route
pub const PING_ROUTE: &str = "ping";
/// The route through which a client may start the fee indexing process
pub const INDEX_FEES_ROUTE: &str = "index-fees";
/// The route through which a client may start the fee redemption process
pub const REDEEM_FEES_ROUTE: &str = "redeem-fees";

/// The route to retrieve the address to deposit custody funds to
pub const GET_DEPOSIT_ADDRESS_ROUTE: &str = "deposit-address";
/// The route to withdraw funds from custody
pub const WITHDRAW_CUSTODY_ROUTE: &str = "withdraw";

/// The route to withdraw gas from custody
pub const WITHDRAW_GAS_ROUTE: &str = "withdraw-gas";
/// The route to refill gas for all active wallets
pub const REFILL_GAS_ROUTE: &str = "refill-gas";
/// The route to register a gas wallet for a peer
pub const REGISTER_GAS_WALLET_ROUTE: &str = "register-gas-wallet";
/// The route to report active peers
pub const REPORT_ACTIVE_PEERS_ROUTE: &str = "report-active-peers";

/// The route to get fee wallets
pub const GET_FEE_WALLETS_ROUTE: &str = "get-fee-wallets";
/// The route to withdraw a fee balance
pub const WITHDRAW_FEE_BALANCE_ROUTE: &str = "withdraw-fee-balance";

/// The route to transfer funds from a hot wallet to its backing vault
pub const TRANSFER_TO_VAULT_ROUTE: &str = "transfer-to-vault";
/// The route to withdraw funds from a hot wallet to Fireblocks
pub const WITHDRAW_TO_HOT_WALLET_ROUTE: &str = "withdraw-to-hot-wallet";

// -------------
// | Api Types |
// -------------

// --- Fee Indexing & Management --- //

/// The response containing fee wallets
#[derive(Debug, Serialize, Deserialize)]
pub struct FeeWalletsResponse {
/// The wallets managed by the funds manager
pub wallets: Vec<ApiWallet>,
}

/// The request body for withdrawing a fee balance
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WithdrawFeeBalanceRequest {
/// The ID of the wallet to withdraw from
pub wallet_id: Uuid,
/// The mint of the asset to withdraw
pub mint: String,
}

// --- Quoters --- //

/// A response containing the deposit address
#[derive(Debug, Serialize, Deserialize)]
pub struct DepositAddressResponse {
/// The deposit address
pub address: String,
}

/// The request body for withdrawing funds from custody
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WithdrawFundsRequest {
/// The mint of the asset to withdraw
pub mint: String,
/// The amount of funds to withdraw
pub amount: f64,
/// The address to withdraw to
pub address: String,
}

// --- Gas --- //

/// The request body for withdrawing gas from custody
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WithdrawGasRequest {
/// The amount of gas to withdraw
pub amount: f64,
/// The address to withdraw to
pub destination_address: String,
}

/// The request body for refilling gas for all active wallets
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RefillGasRequest {
/// The amount of gas to top up each wallet to
pub amount: f64,
}

/// The response containing the gas wallet's address
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateGasWalletResponse {
/// The address of the gas wallet
pub address: String,
}

/// A request to allocate a gas wallet for a peer
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisterGasWalletRequest {
/// The peer ID of the peer to allocate a gas wallet for
pub peer_id: String,
}

/// The response containing an newly active gas wallet's key
///
/// Clients will hit the corresponding endpoint to register a gas wallet with
/// the funds manager when they spin up
#[derive(Debug, Serialize, Deserialize)]
pub struct RegisterGasWalletResponse {
/// The key of the active gas wallet
pub key: String,
}

/// A request reporting active peers in the network
///
/// The funds manager uses such a request to mark gas wallets as active or
/// inactive
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ReportActivePeersRequest {
/// The list of active peers
pub peers: Vec<String>,
}

// --- Hot Wallets --- //

/// The request body for creating a hot wallet
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CreateHotWalletRequest {
/// The name of the vault backing the hot wallet
pub vault: String,
/// The internal wallet ID to associate with the hot wallet
pub internal_wallet_id: Uuid,
}

/// The response containing the hot wallet's address
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateHotWalletResponse {
/// The address of the hot wallet
pub address: String,
}

/// The response containing hot wallet balances
#[derive(Debug, Serialize, Deserialize)]
pub struct HotWalletBalancesResponse {
/// The list of hot wallets with their balances
pub wallets: Vec<WalletWithBalances>,
}

/// A hot wallet with its balances
#[derive(Debug, Serialize, Deserialize)]
pub struct WalletWithBalances {
/// The address of the hot wallet
pub address: String,
/// The balances of various tokens
pub balances: Vec<TokenBalance>,
}

/// A balance for a specific token
#[derive(Debug, Serialize, Deserialize)]
pub struct TokenBalance {
/// The mint address of the token
pub mint: String,
/// The balance amount
pub amount: u128,
}

/// The request body for transferring funds from a hot wallet to its backing
/// vault
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TransferToVaultRequest {
/// The address of the hot wallet
pub hot_wallet_address: String,
/// The mint of the asset to transfer
pub mint: String,
/// The amount to transfer
pub amount: f64,
}

/// The request body for transferring from Fireblocks to a hot wallet
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WithdrawToHotWalletRequest {
/// The name of the vault to withdraw from
pub vault: String,
/// The mint of the asset to transfer
pub mint: String,
/// The amount to transfer
pub amount: f64,
}
mod serialization;
mod types;
pub use types::*;
96 changes: 96 additions & 0 deletions funds-manager/funds-manager-api/src/serialization.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//! Serialization helpers for the funds manager API

/// A module for serializing and deserializing addresses as strings
pub(crate) mod address_string_serialization {
use std::str::FromStr;

use ethers::types::Address;
use serde::{de::Error, Deserialize, Deserializer, Serializer};

/// Serialize an address to a string
pub fn serialize<S: Serializer>(address: &Address, s: S) -> Result<S::Ok, S::Error> {
s.serialize_str(&address.to_string())
}

/// Deserialize a string to an address
pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Address, D::Error> {
let s = String::deserialize(d)?;
Address::from_str(&s).map_err(|_| D::Error::custom("Invalid address"))
}
}

/// A module for serializing and deserializing U256 as strings
pub(crate) mod u256_string_serialization {
use ethers::types::U256;
use serde::{de::Error, Deserialize, Deserializer, Serializer};

/// Serialize a U256 to a string
pub fn serialize<S: Serializer>(value: &U256, s: S) -> Result<S::Ok, S::Error> {
s.serialize_str(&value.to_string())
}

/// Deserialize a string to a U256
pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<U256, D::Error> {
let s = String::deserialize(d)?;
U256::from_dec_str(&s).map_err(|_| D::Error::custom("Invalid U256 value"))
}
}

/// A module for serializing and deserializing bytes from a hex string
pub(crate) mod bytes_string_serialization {
use ethers::types::Bytes;
use hex::FromHex;
use serde::{de::Error, Deserialize, Deserializer, Serializer};

/// Serialize bytes to a hex string
pub fn serialize<S: Serializer>(value: &Bytes, s: S) -> Result<S::Ok, S::Error> {
let hex = format!("{value:#x}");
s.serialize_str(&hex)
}

/// Deserialize a hex string to bytes
pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Bytes, D::Error> {
let s = String::deserialize(d)?;
Bytes::from_hex(s).map_err(|_| D::Error::custom("Invalid bytes value"))
}
}

#[cfg(test)]
mod tests {
use ethers::types::{Address, Bytes, U256};
use rand::{thread_rng, Rng};

/// Test serialization and deserialization of an address
#[test]
fn test_address_serialization() {
let addr = Address::random();
let serialized = serde_json::to_string(&addr).unwrap();
let deserialized: Address = serde_json::from_str(&serialized).unwrap();
assert_eq!(addr, deserialized);
}

/// Test serialization and deserialization of a U256
#[test]
fn test_u256_serialization() {
let mut rng = thread_rng();
let mut bytes = [0u8; 32];
rng.fill(&mut bytes);
let value = U256::from(bytes);

let serialized = serde_json::to_string(&value).unwrap();
let deserialized: U256 = serde_json::from_str(&serialized).unwrap();
assert_eq!(value, deserialized);
}

/// Test serialization and deserialization of bytes
#[test]
fn test_bytes_serialization() {
const N: usize = 32;
let mut rng = thread_rng();
let bytes: Bytes = (0..N).map(|_| rng.gen_range(0..=u8::MAX)).collect();

let serialized = serde_json::to_string(&bytes).unwrap();
let deserialized: Bytes = serde_json::from_str(&serialized).unwrap();
assert_eq!(bytes, deserialized);
}
}
38 changes: 38 additions & 0 deletions funds-manager/funds-manager-api/src/types/fees.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! API types for managing and redeeming fees

use renegade_api::types::ApiWallet;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

// --------------
// | Api Routes |
// --------------

/// The route through which a client may start the fee indexing process
pub const INDEX_FEES_ROUTE: &str = "index-fees";
/// The route through which a client may start the fee redemption process
pub const REDEEM_FEES_ROUTE: &str = "redeem-fees";
/// The route to get fee wallets
pub const GET_FEE_WALLETS_ROUTE: &str = "get-fee-wallets";
/// The route to withdraw a fee balance
pub const WITHDRAW_FEE_BALANCE_ROUTE: &str = "withdraw-fee-balance";

// -------------
// | Api Types |
// -------------

/// The response containing fee wallets
#[derive(Debug, Serialize, Deserialize)]
pub struct FeeWalletsResponse {
/// The wallets managed by the funds manager
pub wallets: Vec<ApiWallet>,
}

/// The request body for withdrawing a fee balance
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct WithdrawFeeBalanceRequest {
/// The ID of the wallet to withdraw from
pub wallet_id: Uuid,
/// The mint of the asset to withdraw
pub mint: String,
}
Loading

0 comments on commit cf43283

Please sign in to comment.