diff --git a/apps/daemon/src/pusher/pusher.rs b/apps/daemon/src/pusher/pusher.rs index 2bdb07d72..b96bc4f6e 100644 --- a/apps/daemon/src/pusher/pusher.rs +++ b/apps/daemon/src/pusher/pusher.rs @@ -111,7 +111,7 @@ impl Pusher { let message = format!("Closed perpetual position for {value} at {to_address}"); Ok(Message { title, message: Some(message) }) } - TransactionType::AssetActivation | TransactionType::PerpetualModifyPosition => todo!(), + TransactionType::AssetActivation | TransactionType::PerpetualModifyPosition | TransactionType::EarnDeposit | TransactionType::EarnWithdraw => todo!(), TransactionType::StakeFreeze => Ok(Message { title: localizer.notification_freeze_title(self.get_value(amount, asset.symbol.clone()).as_str()), message: None, diff --git a/crates/gem_aptos/src/provider/staking_mapper.rs b/crates/gem_aptos/src/provider/staking_mapper.rs index b086579a9..af7aefbb4 100644 --- a/crates/gem_aptos/src/provider/staking_mapper.rs +++ b/crates/gem_aptos/src/provider/staking_mapper.rs @@ -1,6 +1,6 @@ use chrono::{DateTime, Utc}; use num_bigint::BigUint; -use primitives::{Chain, DelegationBase, DelegationState, DelegationValidator}; +use primitives::{Chain, DelegationBase, DelegationState, DelegationValidator, EarnProviderType}; use crate::models::{DelegationPoolStake, StakingConfig, ValidatorInfo, ValidatorSet}; @@ -21,6 +21,7 @@ pub fn map_validator(validator: &ValidatorInfo, apy: f64, commission: f64, is_ac is_active, commission, apr: apy, + provider_type: EarnProviderType::Stake, } } diff --git a/crates/gem_aptos/src/rpc/client.rs b/crates/gem_aptos/src/rpc/client.rs index 30282aac0..0bc6afb83 100644 --- a/crates/gem_aptos/src/rpc/client.rs +++ b/crates/gem_aptos/src/rpc/client.rs @@ -108,7 +108,7 @@ impl AptosClient { } } TransactionInputType::Swap(_, _, _) | TransactionInputType::Stake(_, _) | TransactionInputType::TokenApprove(_, _) | TransactionInputType::Generic(_, _, _) => Ok(1500), - TransactionInputType::Perpetual(_, _) => unimplemented!(), + TransactionInputType::Perpetual(_, _) | TransactionInputType::Earn(_, _, _) => unimplemented!(), } } diff --git a/crates/gem_cosmos/src/provider/preload_mapper.rs b/crates/gem_cosmos/src/provider/preload_mapper.rs index 3a9913803..d4c503e72 100644 --- a/crates/gem_cosmos/src/provider/preload_mapper.rs +++ b/crates/gem_cosmos/src/provider/preload_mapper.rs @@ -11,7 +11,8 @@ fn get_fee(chain: CosmosChain, input_type: &TransactionInputType) -> BigInt { | TransactionInputType::Account(_, _) | TransactionInputType::TokenApprove(_, _) | TransactionInputType::Generic(_, _, _) - | TransactionInputType::Perpetual(_, _) => BigInt::from(3_000u64), + | TransactionInputType::Perpetual(_, _) + | TransactionInputType::Earn(_, _, _) => BigInt::from(3_000u64), TransactionInputType::Swap(_, _, _) => BigInt::from(3_000u64), TransactionInputType::Stake(_, _) => BigInt::from(25_000u64), }, @@ -22,7 +23,8 @@ fn get_fee(chain: CosmosChain, input_type: &TransactionInputType) -> BigInt { | TransactionInputType::Account(_, _) | TransactionInputType::TokenApprove(_, _) | TransactionInputType::Generic(_, _, _) - | TransactionInputType::Perpetual(_, _) => BigInt::from(10_000u64), + | TransactionInputType::Perpetual(_, _) + | TransactionInputType::Earn(_, _, _) => BigInt::from(10_000u64), TransactionInputType::Swap(_, _, _) => BigInt::from(10_000u64), TransactionInputType::Stake(_, _) => BigInt::from(100_000u64), }, @@ -33,7 +35,8 @@ fn get_fee(chain: CosmosChain, input_type: &TransactionInputType) -> BigInt { | TransactionInputType::Account(_, _) | TransactionInputType::TokenApprove(_, _) | TransactionInputType::Generic(_, _, _) - | TransactionInputType::Perpetual(_, _) => BigInt::from(3_000u64), + | TransactionInputType::Perpetual(_, _) + | TransactionInputType::Earn(_, _, _) => BigInt::from(3_000u64), TransactionInputType::Swap(_, _, _) => BigInt::from(3_000u64), TransactionInputType::Stake(_, _) => BigInt::from(10_000u64), }, @@ -44,7 +47,8 @@ fn get_fee(chain: CosmosChain, input_type: &TransactionInputType) -> BigInt { | TransactionInputType::Account(_, _) | TransactionInputType::TokenApprove(_, _) | TransactionInputType::Generic(_, _, _) - | TransactionInputType::Perpetual(_, _) => BigInt::from(100_000u64), + | TransactionInputType::Perpetual(_, _) + | TransactionInputType::Earn(_, _, _) => BigInt::from(100_000u64), TransactionInputType::Swap(_, _, _) => BigInt::from(100_000u64), TransactionInputType::Stake(_, _) => BigInt::from(200_000u64), }, @@ -55,7 +59,8 @@ fn get_fee(chain: CosmosChain, input_type: &TransactionInputType) -> BigInt { | TransactionInputType::Account(_, _) | TransactionInputType::TokenApprove(_, _) | TransactionInputType::Generic(_, _, _) - | TransactionInputType::Perpetual(_, _) => BigInt::from(100_000_000_000_000u64), + | TransactionInputType::Perpetual(_, _) + | TransactionInputType::Earn(_, _, _) => BigInt::from(100_000_000_000_000u64), TransactionInputType::Swap(_, _, _) => BigInt::from(100_000_000_000_000u64), TransactionInputType::Stake(_, _) => BigInt::from(1_000_000_000_000_000u64), }, @@ -71,7 +76,8 @@ fn get_gas_limit(input_type: &TransactionInputType, _chain: CosmosChain) -> u64 | TransactionInputType::Account(_, _) | TransactionInputType::TokenApprove(_, _) | TransactionInputType::Generic(_, _, _) - | TransactionInputType::Perpetual(_, _) => 200_000, + | TransactionInputType::Perpetual(_, _) + | TransactionInputType::Earn(_, _, _) => 200_000, TransactionInputType::Swap(_, _, _) => 200_000, TransactionInputType::Stake(_, operation) => match operation { StakeType::Stake(_) | StakeType::Unstake(_) => 1_000_000, diff --git a/crates/gem_cosmos/src/provider/staking_mapper.rs b/crates/gem_cosmos/src/provider/staking_mapper.rs index fa378eaca..8f5c153c4 100644 --- a/crates/gem_cosmos/src/provider/staking_mapper.rs +++ b/crates/gem_cosmos/src/provider/staking_mapper.rs @@ -11,7 +11,7 @@ use crate::models::{OsmosisDistributionProportions, OsmosisMintParams}; use number_formatter::BigNumberFormatter; use primitives::chain_cosmos::CosmosChain; -use primitives::{DelegationBase, DelegationState, DelegationValidator}; +use primitives::{DelegationBase, DelegationState, DelegationValidator, EarnProviderType}; use std::collections::HashMap; const BOND_STATUS_BONDED: &str = "BOND_STATUS_BONDED"; @@ -68,6 +68,7 @@ pub fn map_staking_validators(validators: Vec, chain: CosmosChain, ap is_active, commission: commission_rate * 100.0, apr: validator_apr, + provider_type: EarnProviderType::Stake, } }) .collect() diff --git a/crates/gem_evm/src/provider/preload_mapper.rs b/crates/gem_evm/src/provider/preload_mapper.rs index 17d167e3c..446ef2226 100644 --- a/crates/gem_evm/src/provider/preload_mapper.rs +++ b/crates/gem_evm/src/provider/preload_mapper.rs @@ -145,6 +145,13 @@ pub fn get_transaction_params(chain: EVMChain, input: &TransactionLoadInput) -> } _ => Err("Unsupported chain for staking".into()), }, + TransactionInputType::Earn(_, _, earn_data) => { + if let Some(approval) = &earn_data.approval { + Ok(TransactionParams::new(approval.token.clone(), encode_erc20_approve(&approval.spender)?, BigInt::from(0))) + } else { + Ok(TransactionParams::new(earn_data.contract_address.clone(), hex::decode(&earn_data.call_data)?, value)) + } + } _ => Err("Unsupported transfer type".into()), } } @@ -183,6 +190,14 @@ pub fn get_extra_fee_gas_limit(input: &TransactionLoadInput) -> Result { + if earn_data.approval.is_some() { + if let Some(gas_limit) = &earn_data.gas_limit { + return Ok(BigInt::from_str_radix(gas_limit, 10)?); + } + } + Ok(BigInt::from(0)) + } _ => Ok(BigInt::from(0)), } } @@ -284,7 +299,7 @@ mod tests { use super::*; use crate::everstake::{EVERSTAKE_POOL_ADDRESS, IAccounting}; use num_bigint::BigUint; - use primitives::{Delegation, DelegationBase, DelegationState, DelegationValidator, RedelegateData}; + use primitives::{Delegation, DelegationBase, DelegationState, DelegationValidator, EarnProviderType, RedelegateData}; fn everstake_validator() -> DelegationValidator { DelegationValidator { @@ -294,6 +309,7 @@ mod tests { is_active: true, commission: 10.0, apr: 4.2, + provider_type: EarnProviderType::Stake, } } @@ -428,6 +444,7 @@ mod tests { is_active: true, commission: 5.0, apr: 10.0, + provider_type: EarnProviderType::Stake, }; let stake_type = StakeType::Stake(validator); @@ -464,6 +481,7 @@ mod tests { is_active: true, commission: 5.0, apr: 10.0, + provider_type: EarnProviderType::Stake, }, price: None, }; @@ -501,6 +519,7 @@ mod tests { is_active: true, commission: 5.0, apr: 10.0, + provider_type: EarnProviderType::Stake, }, price: None, }; @@ -512,6 +531,7 @@ mod tests { is_active: true, commission: 3.0, apr: 12.0, + provider_type: EarnProviderType::Stake, }; let redelegate_data = RedelegateData { delegation, to_validator }; @@ -549,6 +569,7 @@ mod tests { is_active: true, commission: 5.0, apr: 10.0, + provider_type: EarnProviderType::Stake, }, price: None, }; diff --git a/crates/gem_evm/src/provider/staking_ethereum.rs b/crates/gem_evm/src/provider/staking_ethereum.rs index 6111a1646..77110dcc6 100644 --- a/crates/gem_evm/src/provider/staking_ethereum.rs +++ b/crates/gem_evm/src/provider/staking_ethereum.rs @@ -1,7 +1,7 @@ use gem_client::Client; use num_bigint::BigUint; use num_traits::Zero; -use primitives::{AssetBalance, AssetId, Balance, Chain, DelegationBase, DelegationState, DelegationValidator}; +use primitives::{AssetBalance, AssetId, Balance, Chain, DelegationBase, DelegationState, DelegationValidator, EarnProviderType}; use std::error::Error; use crate::everstake::{EVERSTAKE_POOL_ADDRESS, get_everstake_account_state, map_balance_to_delegation, map_withdraw_request_to_delegations}; @@ -32,6 +32,7 @@ impl EthereumClient { is_active: true, commission: 0.1, apr: apy, + provider_type: EarnProviderType::Stake, }]) } diff --git a/crates/gem_evm/src/provider/staking_monad.rs b/crates/gem_evm/src/provider/staking_monad.rs index 8a7e622ed..4fa6bb661 100644 --- a/crates/gem_evm/src/provider/staking_monad.rs +++ b/crates/gem_evm/src/provider/staking_monad.rs @@ -6,7 +6,7 @@ use chrono::{DateTime, Utc}; use gem_client::Client; use num_bigint::BigUint; use num_traits::{ToPrimitive, Zero}; -use primitives::{AssetBalance, AssetId, Chain, DelegationBase, DelegationState, DelegationValidator}; +use primitives::{AssetBalance, AssetId, Chain, DelegationBase, DelegationState, DelegationValidator, EarnProviderType}; use crate::monad::{ IMonadStakingLens, MONAD_SCALE, MonadLensBalance, MonadLensDelegation, MonadLensValidatorInfo, STAKING_LENS_CONTRACT, decode_get_lens_apys, decode_get_lens_balance, @@ -124,6 +124,7 @@ impl EthereumClient { is_active: validator.is_active, commission: Self::lens_commission_rate(&validator.commission), apr: if validator.apy_bps > 0 { validator.apy_bps as f64 / 100.0 } else { network_apy }, + provider_type: EarnProviderType::Stake, } } diff --git a/crates/gem_evm/src/provider/staking_smartchain.rs b/crates/gem_evm/src/provider/staking_smartchain.rs index 66f6a4b9a..4f5921f66 100644 --- a/crates/gem_evm/src/provider/staking_smartchain.rs +++ b/crates/gem_evm/src/provider/staking_smartchain.rs @@ -7,7 +7,7 @@ use gem_bsc::stake_hub::{ }; use gem_client::Client; use num_bigint::BigUint; -use primitives::{AssetId, Chain, DelegationBase, DelegationState, DelegationValidator}; +use primitives::{AssetId, Chain, DelegationBase, DelegationState, DelegationValidator, EarnProviderType}; use std::{error::Error, str::FromStr}; #[cfg(feature = "rpc")] @@ -37,6 +37,7 @@ impl EthereumClient { is_active: !v.jailed, commission: v.commission as f64 / 10000.0, apr: v.apy as f64 / 100.0, + provider_type: EarnProviderType::Stake, }) .collect()) } diff --git a/crates/gem_hypercore/src/provider/staking_mapper.rs b/crates/gem_hypercore/src/provider/staking_mapper.rs index 41fca6c59..92a53a4b1 100644 --- a/crates/gem_hypercore/src/provider/staking_mapper.rs +++ b/crates/gem_hypercore/src/provider/staking_mapper.rs @@ -1,7 +1,7 @@ use crate::models::balance::{DelegationBalance, Validator}; use num_bigint::BigUint; use number_formatter::BigNumberFormatter; -use primitives::{Asset, Chain, DelegationBase, DelegationState, DelegationValidator}; +use primitives::{Asset, Chain, DelegationBase, DelegationState, DelegationValidator, EarnProviderType}; use std::str::FromStr; pub fn map_staking_validators(validators: Vec, chain: Chain, apy: Option) -> Vec { @@ -15,6 +15,7 @@ pub fn map_staking_validators(validators: Vec, chain: Chain, apy: Opt is_active: x.is_active, commission: x.commission, apr: calculated_apy, + provider_type: EarnProviderType::Stake, }) .collect() } diff --git a/crates/gem_hypercore/src/signer/core_signer.rs b/crates/gem_hypercore/src/signer/core_signer.rs index 32ecacf33..6c6607533 100644 --- a/crates/gem_hypercore/src/signer/core_signer.rs +++ b/crates/gem_hypercore/src/signer/core_signer.rs @@ -428,7 +428,7 @@ mod tests { use crate::core::actions::Grouping; use num_bigint::{BigInt, BigUint}; use primitives::{ - Asset, Chain, Delegation, DelegationBase, DelegationState, DelegationValidator, GasPriceType, StakeType, TransactionInputType, TransactionLoadInput, + Asset, Chain, Delegation, DelegationBase, DelegationState, DelegationValidator, EarnProviderType, GasPriceType, StakeType, TransactionInputType, TransactionLoadInput, TransactionLoadMetadata, }; @@ -443,6 +443,7 @@ mod tests { is_active: true, commission: 0.0, apr: 0.0, + provider_type: EarnProviderType::Stake, }; let input = TransactionLoadInput { input_type: TransactionInputType::Stake(asset.clone(), StakeType::Stake(validator)), @@ -497,6 +498,7 @@ mod tests { is_active: true, commission: 0.0, apr: 0.0, + provider_type: EarnProviderType::Stake, }, price: None, }; diff --git a/crates/gem_solana/src/provider/preload_mapper.rs b/crates/gem_solana/src/provider/preload_mapper.rs index e2e1c0080..93ac30421 100644 --- a/crates/gem_solana/src/provider/preload_mapper.rs +++ b/crates/gem_solana/src/provider/preload_mapper.rs @@ -40,7 +40,8 @@ fn get_gas_limit(input_type: &TransactionInputType) -> BigInt { | TransactionInputType::Account(_, _) | TransactionInputType::TokenApprove(_, _) | TransactionInputType::Generic(_, _, _) - | TransactionInputType::Perpetual(_, _) => BigInt::from(100_000), + | TransactionInputType::Perpetual(_, _) + | TransactionInputType::Earn(_, _, _) => BigInt::from(100_000), TransactionInputType::Swap(_, _, _) => BigInt::from(420_000), TransactionInputType::Stake(_, _) => BigInt::from(100_000), } @@ -54,7 +55,8 @@ fn get_multiple_of(input_type: &TransactionInputType) -> i64 { | TransactionInputType::Account(asset, _) | TransactionInputType::TokenApprove(asset, _) | TransactionInputType::Generic(asset, _, _) - | TransactionInputType::Perpetual(asset, _) => match &asset.id.token_subtype() { + | TransactionInputType::Perpetual(asset, _) + | TransactionInputType::Earn(asset, _, _) => match &asset.id.token_subtype() { AssetSubtype::NATIVE => 25_000, AssetSubtype::TOKEN => 50_000, }, diff --git a/crates/gem_solana/src/provider/staking_mapper.rs b/crates/gem_solana/src/provider/staking_mapper.rs index 2ee98538b..20d2ea5e8 100644 --- a/crates/gem_solana/src/provider/staking_mapper.rs +++ b/crates/gem_solana/src/provider/staking_mapper.rs @@ -1,7 +1,7 @@ use crate::models::{EpochInfo, TokenAccountInfo, VoteAccount}; use chrono::Utc; use num_bigint::BigUint; -use primitives::{AssetId, Chain, DelegationBase, DelegationState, DelegationValidator}; +use primitives::{AssetId, Chain, DelegationBase, DelegationState, DelegationValidator, EarnProviderType}; pub fn map_staking_validators(vote_accounts: Vec, chain: Chain, network_apy: f64) -> Vec { vote_accounts @@ -18,6 +18,7 @@ pub fn map_staking_validators(vote_accounts: Vec, chain: Chain, net is_active, commission: validator.commission as f64, apr: validator_apr, + provider_type: EarnProviderType::Stake, } }) .collect() diff --git a/crates/gem_sui/src/provider/preload_mapper.rs b/crates/gem_sui/src/provider/preload_mapper.rs index a4263a7b9..e397570c9 100644 --- a/crates/gem_sui/src/provider/preload_mapper.rs +++ b/crates/gem_sui/src/provider/preload_mapper.rs @@ -36,7 +36,8 @@ fn get_gas_limit(input_type: &TransactionInputType) -> u64 { | TransactionInputType::Deposit(_) | TransactionInputType::TokenApprove(_, _) | TransactionInputType::Generic(_, _, _) - | TransactionInputType::Perpetual(_, _) => GAS_BUDGET, + | TransactionInputType::Perpetual(_, _) + | TransactionInputType::Earn(_, _, _) => GAS_BUDGET, TransactionInputType::Swap(_, _, _) => 50_000_000, TransactionInputType::Stake(_, _) => GAS_BUDGET, } diff --git a/crates/gem_sui/src/provider/staking_mapper.rs b/crates/gem_sui/src/provider/staking_mapper.rs index e16d3dfee..908cf030c 100644 --- a/crates/gem_sui/src/provider/staking_mapper.rs +++ b/crates/gem_sui/src/provider/staking_mapper.rs @@ -2,7 +2,7 @@ use crate::models::RpcSuiSystemState; use crate::models::staking::{SuiStakeDelegation, SuiSystemState, SuiValidators}; use chrono::{DateTime, Utc}; use num_bigint::BigUint; -use primitives::{Chain, DelegationBase, DelegationState, DelegationValidator, StakeValidator}; +use primitives::{Chain, DelegationBase, DelegationState, DelegationValidator, EarnProviderType, StakeValidator}; pub fn map_validators(validators: SuiValidators, default_apy: f64) -> Vec { validators @@ -15,6 +15,7 @@ pub fn map_validators(validators: SuiValidators, default_apy: f64) -> Vec ChainParameter { @@ -277,6 +278,7 @@ mod tests { is_active: true, commission: 0.0, apr: 0.0, + provider_type: EarnProviderType::Stake, }); let with_bandwidth = account_usage(DEFAULT_BANDWIDTH_BYTES, 0, 0); diff --git a/crates/gem_tron/src/provider/staking_mapper.rs b/crates/gem_tron/src/provider/staking_mapper.rs index 6b582fa35..b6fbaf9c3 100644 --- a/crates/gem_tron/src/provider/staking_mapper.rs +++ b/crates/gem_tron/src/provider/staking_mapper.rs @@ -1,6 +1,6 @@ use crate::address::TronAddress; use crate::models::WitnessesList; -use primitives::{Chain, DelegationValidator, StakeValidator}; +use primitives::{Chain, DelegationValidator, EarnProviderType, StakeValidator}; const SYSTEM_UNSTAKING_VALIDATOR_ID: &str = "system"; const SYSTEM_UNSTAKING_VALIDATOR_NAME: &str = "Unstaking"; @@ -22,6 +22,7 @@ pub fn map_staking_validators(witnesses: WitnessesList, apy: Option) -> Vec is_active: witness.is_jobs.unwrap_or(false), commission: 0.0, apr: default_apy, + provider_type: EarnProviderType::Stake, }) }) .collect(); @@ -33,6 +34,7 @@ pub fn map_staking_validators(witnesses: WitnessesList, apy: Option) -> Vec is_active: true, commission: 0.0, apr: default_apy, + provider_type: EarnProviderType::Stake, }); validators diff --git a/crates/primitives/src/asset_balance.rs b/crates/primitives/src/asset_balance.rs index 0fc871d62..613b5aa4a 100644 --- a/crates/primitives/src/asset_balance.rs +++ b/crates/primitives/src/asset_balance.rs @@ -51,6 +51,17 @@ impl AssetBalance { is_active: true, } } + pub fn new_earn(asset_id: AssetId, earn: BigUint) -> Self { + Self { + asset_id, + balance: Balance { + earn, + ..Balance::coin_balance(BigUint::from(0u32)) + }, + is_active: true, + } + } + pub fn new_staking_with_metadata(asset_id: AssetId, staked: BigUint, pending: BigUint, rewards: BigUint, metadata: BalanceMetadata) -> Self { Self { asset_id, @@ -71,6 +82,7 @@ pub struct Balance { pub pending_unconfirmed: BigUint, pub rewards: BigUint, pub reserved: BigUint, + pub earn: BigUint, pub withdrawable: BigUint, pub metadata: Option, } @@ -97,6 +109,7 @@ impl Balance { pending_unconfirmed: BigUint::from(0u32), rewards: BigUint::from(0u32), reserved: BigUint::from(0u32), + earn: BigUint::from(0u32), withdrawable: BigUint::from(0u32), metadata: None, } @@ -112,6 +125,7 @@ impl Balance { pending: BigUint::from(0u32), rewards: BigUint::from(0u32), reserved: BigUint::from(0u32), + earn: BigUint::from(0u32), withdrawable: BigUint::from(0u32), metadata: None, } @@ -127,6 +141,7 @@ impl Balance { pending: BigUint::from(0u32), pending_unconfirmed: BigUint::from(0u32), rewards: BigUint::from(0u32), + earn: BigUint::from(0u32), withdrawable: BigUint::from(0u32), metadata: None, } @@ -146,8 +161,10 @@ impl Balance { pending_unconfirmed: BigUint::from(0u32), rewards: rewards.unwrap_or(BigUint::from(0u32)), reserved: BigUint::from(0u32), + earn: BigUint::from(0u32), withdrawable: BigUint::from(0u32), metadata, } } + } diff --git a/crates/primitives/src/asset_metadata.rs b/crates/primitives/src/asset_metadata.rs index fcc63b3f9..4c90de872 100644 --- a/crates/primitives/src/asset_metadata.rs +++ b/crates/primitives/src/asset_metadata.rs @@ -12,12 +12,16 @@ struct AssetMetaData { is_swap_enabled: bool, #[serde(rename = "isStakeEnabled")] is_stake_enabled: bool, + #[serde(rename = "isEarnEnabled")] + is_earn_enabled: bool, #[serde(rename = "isPinned")] is_pinned: bool, #[serde(rename = "isActive")] is_active: bool, #[serde(rename = "stakingApr")] staking_apr: Option, + #[serde(rename = "earnApr")] + earn_apr: Option, #[serde(rename = "rankScore")] rank_score: i32, } diff --git a/crates/primitives/src/balance_type.rs b/crates/primitives/src/balance_type.rs index f3d501896..e45394766 100644 --- a/crates/primitives/src/balance_type.rs +++ b/crates/primitives/src/balance_type.rs @@ -8,4 +8,5 @@ pub enum BalanceType { pendingUnconfirmed, rewards, reserved, + earn, } diff --git a/crates/primitives/src/delegation.rs b/crates/primitives/src/delegation.rs index e6a3c2357..57031144a 100644 --- a/crates/primitives/src/delegation.rs +++ b/crates/primitives/src/delegation.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use strum::{AsRefStr, Display, EnumString}; use typeshare::typeshare; +use crate::earn_provider_type::EarnProviderType; use crate::{AssetId, Chain, Price, StakeValidator}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -45,6 +46,7 @@ pub struct DelegationValidator { pub is_active: bool, pub commission: f64, pub apr: f64, + pub provider_type: EarnProviderType, } #[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, AsRefStr, EnumString, PartialEq)] diff --git a/crates/primitives/src/earn_data.rs b/crates/primitives/src/earn_data.rs new file mode 100644 index 000000000..ed64e5d24 --- /dev/null +++ b/crates/primitives/src/earn_data.rs @@ -0,0 +1,14 @@ +use serde::{Deserialize, Serialize}; +use typeshare::typeshare; + +use crate::swap::ApprovalData; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[typeshare(swift = "Equatable, Hashable, Sendable")] +#[serde(rename_all = "camelCase")] +pub struct EarnData { + pub contract_address: String, + pub call_data: String, + pub approval: Option, + pub gas_limit: Option, +} diff --git a/crates/primitives/src/earn_provider_type.rs b/crates/primitives/src/earn_provider_type.rs new file mode 100644 index 000000000..c89f1191f --- /dev/null +++ b/crates/primitives/src/earn_provider_type.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; +use strum::{AsRefStr, Display, EnumString}; +use typeshare::typeshare; + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, AsRefStr, EnumString, PartialEq, Eq)] +#[typeshare(swift = "Equatable, CaseIterable, Sendable")] +#[serde(rename_all = "lowercase")] +#[strum(serialize_all = "lowercase")] +pub enum EarnProviderType { + Stake, + Earn, +} diff --git a/crates/primitives/src/earn_transaction.rs b/crates/primitives/src/earn_transaction.rs new file mode 100644 index 000000000..2047bb164 --- /dev/null +++ b/crates/primitives/src/earn_transaction.rs @@ -0,0 +1,16 @@ +use serde::{Deserialize, Serialize}; +use typeshare::typeshare; + +use crate::{Chain, swap::ApprovalData}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[typeshare(swift = "Sendable")] +#[serde(rename_all = "camelCase")] +pub struct EarnTransaction { + pub chain: Chain, + pub from: String, + pub to: String, + pub data: String, + pub value: Option, + pub approval: Option, +} diff --git a/crates/primitives/src/earn_type.rs b/crates/primitives/src/earn_type.rs new file mode 100644 index 000000000..538bc0952 --- /dev/null +++ b/crates/primitives/src/earn_type.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; +use typeshare::typeshare; + +use crate::{Delegation, DelegationValidator}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", content = "content")] +#[typeshare(swift = "Equatable, Hashable, Sendable")] +pub enum EarnType { + Deposit(DelegationValidator), + Withdraw(Delegation), +} diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index c9225725d..f149beec3 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -220,14 +220,24 @@ pub mod chart; pub use self::chart::{ChartCandleStick, ChartDateValue}; pub mod delegation; pub use self::delegation::{Delegation, DelegationBase, DelegationState, DelegationValidator}; +pub mod stake_type; +pub use self::stake_type::{RedelegateData, Resource, StakeData, StakeType, TronStakeData, TronUnfreeze, TronVote}; +pub mod earn_provider_type; +pub use self::earn_provider_type::EarnProviderType; +pub mod yield_provider; +pub use self::yield_provider::YieldProvider; +pub mod earn_type; +pub use self::earn_type::EarnType; +pub mod earn_transaction; +pub use self::earn_transaction::EarnTransaction; +pub mod earn_data; +pub use self::earn_data::EarnData; pub mod transaction_update; pub use self::transaction_update::{TransactionChange, TransactionMetadata, TransactionStateRequest, TransactionUpdate}; pub mod transaction_preload_input; pub use self::transaction_preload_input::TransactionPreloadInput; pub mod transaction_fee; pub use self::transaction_fee::{FeeOption, TransactionFee}; -pub mod stake_type; -pub use self::stake_type::{RedelegateData, Resource, StakeData, StakeType, TronStakeData, TronUnfreeze, TronVote}; pub mod transaction_load_metadata; pub use self::transaction_load_metadata::{HyperliquidOrder, TransactionLoadMetadata}; pub mod transaction_input_type; diff --git a/crates/primitives/src/testkit/delegation_mock.rs b/crates/primitives/src/testkit/delegation_mock.rs index 263a59666..98d63e126 100644 --- a/crates/primitives/src/testkit/delegation_mock.rs +++ b/crates/primitives/src/testkit/delegation_mock.rs @@ -1,4 +1,4 @@ -use crate::{AssetId, Chain, Delegation, DelegationBase, DelegationState, DelegationValidator}; +use crate::{AssetId, Chain, Delegation, DelegationBase, DelegationState, DelegationValidator, EarnProviderType}; use num_bigint::BigUint; impl Delegation { @@ -56,6 +56,7 @@ impl DelegationValidator { is_active: true, commission: 0.05, apr: 0.08, + provider_type: EarnProviderType::Stake, } } } diff --git a/crates/primitives/src/transaction.rs b/crates/primitives/src/transaction.rs index fbdcb572b..e7d9cacc2 100644 --- a/crates/primitives/src/transaction.rs +++ b/crates/primitives/src/transaction.rs @@ -260,7 +260,9 @@ impl Transaction { | TransactionType::SmartContractCall | TransactionType::PerpetualOpenPosition | TransactionType::PerpetualClosePosition - | TransactionType::PerpetualModifyPosition => vec![self.asset_id.clone(), self.fee_asset_id.clone()], + | TransactionType::PerpetualModifyPosition + | TransactionType::EarnDeposit + | TransactionType::EarnWithdraw => vec![self.asset_id.clone(), self.fee_asset_id.clone()], TransactionType::Swap => self .metadata .clone() @@ -295,7 +297,9 @@ impl Transaction { | TransactionType::SmartContractCall | TransactionType::PerpetualOpenPosition | TransactionType::PerpetualClosePosition - | TransactionType::PerpetualModifyPosition => vec![AssetAddress::new(self.asset_id.clone(), self.to.clone(), None)], + | TransactionType::PerpetualModifyPosition + | TransactionType::EarnDeposit + | TransactionType::EarnWithdraw => vec![AssetAddress::new(self.asset_id.clone(), self.to.clone(), None)], TransactionType::Swap => self .metadata .clone() diff --git a/crates/primitives/src/transaction_input_type.rs b/crates/primitives/src/transaction_input_type.rs index b519a4d0d..6badd9e2a 100644 --- a/crates/primitives/src/transaction_input_type.rs +++ b/crates/primitives/src/transaction_input_type.rs @@ -1,3 +1,5 @@ +use crate::earn_data::EarnData; +use crate::earn_type::EarnType; use crate::stake_type::StakeType; use crate::swap::{ApprovalData, SwapData}; use crate::transaction_fee::TransactionFee; @@ -21,6 +23,7 @@ pub enum TransactionInputType { TransferNft(Asset, NFTAsset), Account(Asset, AccountDataType), Perpetual(Asset, PerpetualType), + Earn(Asset, EarnType, EarnData), } impl TransactionInputType { @@ -35,6 +38,7 @@ impl TransactionInputType { TransactionInputType::TransferNft(asset, _) => asset, TransactionInputType::Account(asset, _) => asset, TransactionInputType::Perpetual(asset, _) => asset, + TransactionInputType::Earn(asset, _, _) => asset, } } @@ -63,6 +67,7 @@ impl TransactionInputType { TransactionInputType::TransferNft(asset, _) => asset, TransactionInputType::Account(asset, _) => asset, TransactionInputType::Perpetual(asset, _) => asset, + TransactionInputType::Earn(asset, _, _) => asset, } } @@ -87,6 +92,10 @@ impl TransactionInputType { PerpetualType::Close(_) | PerpetualType::Reduce(_) => TransactionType::PerpetualClosePosition, PerpetualType::Modify(_) => TransactionType::PerpetualModifyPosition, }, + TransactionInputType::Earn(_, earn_type, _) => match earn_type { + EarnType::Deposit(_) => TransactionType::EarnDeposit, + EarnType::Withdraw(_) => TransactionType::EarnWithdraw, + }, } } } diff --git a/crates/primitives/src/transaction_type.rs b/crates/primitives/src/transaction_type.rs index 025d0e20f..0eefd012f 100644 --- a/crates/primitives/src/transaction_type.rs +++ b/crates/primitives/src/transaction_type.rs @@ -27,6 +27,8 @@ pub enum TransactionType { PerpetualOpenPosition, PerpetualClosePosition, PerpetualModifyPosition, + EarnDeposit, + EarnWithdraw, } impl TransactionType { diff --git a/crates/primitives/src/yield_provider.rs b/crates/primitives/src/yield_provider.rs new file mode 100644 index 000000000..b9dab7b30 --- /dev/null +++ b/crates/primitives/src/yield_provider.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; +use strum::{AsRefStr, Display, EnumString}; +use typeshare::typeshare; + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, Display, AsRefStr, EnumString, PartialEq, Eq)] +#[typeshare(swift = "Equatable, CaseIterable, Sendable")] +#[serde(rename_all = "lowercase")] +#[strum(serialize_all = "lowercase")] +pub enum YieldProvider { + Yo, +} diff --git a/gemstone/src/gateway/mod.rs b/gemstone/src/gateway/mod.rs index f4a02e518..7f506bc5f 100644 --- a/gemstone/src/gateway/mod.rs +++ b/gemstone/src/gateway/mod.rs @@ -299,6 +299,20 @@ impl GemGateway { Ok(self.provider(chain).await?.get_is_token_address(&token_id)) } + pub async fn get_earn_data(&self, _chain: Chain, _asset_id: String, _address: String, _value: String, _earn_type: GemEarnType) -> Result { + Err(GatewayError::NetworkError { + msg: "Earn provider not available".to_string(), + }) + } + + pub async fn get_earn_providers(&self, _asset_id: String) -> Result, GatewayError> { + Ok(vec![]) + } + + pub async fn get_earn_positions(&self, _chain: Chain, _address: String) -> Result, GatewayError> { + Ok(vec![]) + } + pub async fn get_node_status(&self, chain: Chain, url: &str) -> Result { let start_time = std::time::Instant::now(); let provider = self.provider_with_url(chain, url.to_string()).await?; diff --git a/gemstone/src/models/balance.rs b/gemstone/src/models/balance.rs index 9c3588e4f..0af403cc3 100644 --- a/gemstone/src/models/balance.rs +++ b/gemstone/src/models/balance.rs @@ -22,6 +22,7 @@ pub struct GemBalance { pub pending_unconfirmed: GemBigUint, pub rewards: GemBigUint, pub reserved: GemBigUint, + pub earn: GemBigUint, pub withdrawable: GemBigUint, pub metadata: Option, } diff --git a/gemstone/src/models/stake.rs b/gemstone/src/models/stake.rs index 641b98bd9..cc5d158d6 100644 --- a/gemstone/src/models/stake.rs +++ b/gemstone/src/models/stake.rs @@ -1,6 +1,6 @@ use crate::models::custom_types::{DateTimeUtc, GemBigUint}; use primitives::stake_type::{FreezeType, Resource}; -use primitives::{AssetId, Chain, Delegation, DelegationBase, DelegationState, DelegationValidator, Price, StakeChain}; +use primitives::{AssetId, Chain, Delegation, DelegationBase, DelegationState, DelegationValidator, EarnProviderType, Price, StakeChain}; pub type GemFreezeType = FreezeType; pub type GemResource = Resource; @@ -8,6 +8,7 @@ pub type GemDelegation = Delegation; pub type GemDelegationBase = DelegationBase; pub type GemDelegationValidator = DelegationValidator; pub type GemDelegationState = DelegationState; +pub type GemEarnProviderType = EarnProviderType; pub type GemPrice = Price; pub type GemStakeChain = StakeChain; @@ -50,6 +51,12 @@ pub enum GemDelegationState { AwaitingWithdrawal, } +#[uniffi::remote(Enum)] +pub enum GemEarnProviderType { + Stake, + Earn, +} + #[uniffi::remote(Record)] pub struct GemDelegationValidator { pub chain: Chain, @@ -58,6 +65,7 @@ pub struct GemDelegationValidator { pub is_active: bool, pub commission: f64, pub apr: f64, + pub provider_type: GemEarnProviderType, } #[uniffi::remote(Record)] diff --git a/gemstone/src/models/transaction.rs b/gemstone/src/models/transaction.rs index 40fb4f9c9..05752e1fd 100644 --- a/gemstone/src/models/transaction.rs +++ b/gemstone/src/models/transaction.rs @@ -2,10 +2,10 @@ use crate::models::*; use num_bigint::BigInt; use primitives::stake_type::{FreezeData, StakeData}; use primitives::{ - AccountDataType, Asset, FeeOption, GasPriceType, HyperliquidOrder, PerpetualConfirmData, PerpetualDirection, PerpetualProvider, PerpetualType, Resource, StakeType, - TransactionChange, TransactionFee, TransactionInputType, TransactionLoadInput, TransactionLoadMetadata, TransactionMetadata, TransactionPerpetualMetadata, TransactionState, - TransactionStateRequest, TransactionType, TransactionUpdate, TransferDataExtra, TransferDataOutputAction, TransferDataOutputType, TronStakeData, TronUnfreeze, TronVote, - UInt64, WalletConnectionSessionAppMetadata, + AccountDataType, Asset, EarnData, EarnType, FeeOption, GasPriceType, HyperliquidOrder, PerpetualConfirmData, PerpetualDirection, PerpetualProvider, PerpetualType, Resource, + StakeType, TransactionChange, TransactionFee, TransactionInputType, TransactionLoadInput, TransactionLoadMetadata, TransactionMetadata, TransactionPerpetualMetadata, + TransactionState, TransactionStateRequest, TransactionType, TransactionUpdate, TransferDataExtra, TransferDataOutputAction, TransferDataOutputType, TronStakeData, + TronUnfreeze, TronVote, UInt64, WalletConnectionSessionAppMetadata, perpetual::{CancelOrderData, PerpetualModifyConfirmData, PerpetualModifyPositionType, PerpetualReduceData, TPSLOrderData}, }; use std::collections::HashMap; @@ -127,6 +127,8 @@ pub enum TransactionType { PerpetualOpenPosition, PerpetualClosePosition, PerpetualModifyPosition, + EarnDeposit, + EarnWithdraw, } pub type GemAccountDataType = AccountDataType; @@ -180,6 +182,24 @@ pub struct GemFreezeData { pub resource: GemResource, } +pub type GemEarnData = EarnData; + +#[uniffi::remote(Record)] +pub struct GemEarnData { + pub contract_address: String, + pub call_data: String, + pub approval: Option, + pub gas_limit: Option, +} + +pub type GemEarnType = EarnType; + +#[uniffi::remote(Enum)] +pub enum GemEarnType { + Deposit(GemDelegationValidator), + Withdraw(GemDelegation), +} + pub type GemWalletConnectionSessionAppMetadata = WalletConnectionSessionAppMetadata; #[uniffi::remote(Record)] @@ -302,6 +322,11 @@ pub enum GemTransactionInputType { asset: GemAsset, perpetual_type: GemPerpetualType, }, + Earn { + asset: GemAsset, + earn_type: GemEarnType, + earn_data: GemEarnData, + }, } impl GemTransactionInputType { @@ -314,7 +339,8 @@ impl GemTransactionInputType { | Self::Generic { asset, .. } | Self::TransferNft { asset, .. } | Self::Account { asset, .. } - | Self::Perpetual { asset, .. } => asset, + | Self::Perpetual { asset, .. } + | Self::Earn { asset, .. } => asset, Self::Swap { from_asset, .. } => from_asset, } } @@ -326,6 +352,13 @@ impl GemTransactionInputType { } } + pub fn earn_data(&self) -> Result<&GemEarnData, String> { + match self { + Self::Earn { earn_data, .. } => Ok(earn_data), + _ => Err("Expected Earn".to_string()), + } + } + pub fn stake_type(&self) -> Result<&GemStakeType, String> { match self { Self::Stake { stake_type, .. } => Ok(stake_type), @@ -680,6 +713,7 @@ impl From for GemTransactionInputType { TransactionInputType::TransferNft(asset, nft_asset) => GemTransactionInputType::TransferNft { asset, nft_asset }, TransactionInputType::Account(asset, account_type) => GemTransactionInputType::Account { asset, account_type }, TransactionInputType::Perpetual(asset, perpetual_type) => GemTransactionInputType::Perpetual { asset, perpetual_type }, + TransactionInputType::Earn(asset, earn_type, earn_data) => GemTransactionInputType::Earn { asset, earn_type, earn_data }, } } } @@ -831,6 +865,7 @@ impl From for TransactionInputType { GemTransactionInputType::TransferNft { asset, nft_asset } => TransactionInputType::TransferNft(asset, nft_asset), GemTransactionInputType::Account { asset, account_type } => TransactionInputType::Account(asset, account_type), GemTransactionInputType::Perpetual { asset, perpetual_type } => TransactionInputType::Perpetual(asset, perpetual_type), + GemTransactionInputType::Earn { asset, earn_type, earn_data } => TransactionInputType::Earn(asset, earn_type, earn_data), } } }