diff --git a/Cargo.lock b/Cargo.lock index 5349229..0b07693 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -404,7 +404,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -471,7 +471,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -609,7 +609,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -944,7 +944,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -984,7 +984,7 @@ dependencies = [ "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -1078,9 +1078,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -1096,9 +1096,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] @@ -1282,7 +1282,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -1487,7 +1487,7 @@ dependencies = [ "curve25519-dalek", "solana-define-syscall", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -1561,7 +1561,7 @@ dependencies = [ "solana-pubkey", "solana-sdk-ids", "solana-system-interface", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -1872,7 +1872,7 @@ dependencies = [ "solana-sysvar", "solana-sysvar-id", "solana-vote-interface", - "thiserror 2.0.17", + "thiserror 2.0.18", "wasm-bindgen", ] @@ -1991,7 +1991,7 @@ dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2002,7 +2002,7 @@ checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" dependencies = [ "libsecp256k1", "solana-define-syscall", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2277,7 +2277,7 @@ dependencies = [ "solana-signature", "solana-signer", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "wasm-bindgen", "zeroize", ] @@ -2295,7 +2295,7 @@ dependencies = [ "spl-associated-token-account-client", "spl-token", "spl-token-2022", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2328,7 +2328,7 @@ checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2340,7 +2340,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.9", - "syn 2.0.106", + "syn 2.0.117", "thiserror 1.0.69", ] @@ -2398,7 +2398,7 @@ dependencies = [ "solana-program-option", "solana-pubkey", "solana-zk-sdk", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2413,7 +2413,7 @@ dependencies = [ "solana-msg", "solana-program-error", "spl-program-error-derive", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2425,7 +2425,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.9", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2447,7 +2447,7 @@ dependencies = [ "spl-pod", "spl-program-error", "spl-type-length-value", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2475,7 +2475,7 @@ dependencies = [ "solana-rent", "solana-sdk-ids", "solana-sysvar", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2519,7 +2519,7 @@ dependencies = [ "spl-token-metadata-interface", "spl-transfer-hook-interface", "spl-type-length-value", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2551,7 +2551,7 @@ dependencies = [ "solana-sdk-ids", "solana-zk-sdk", "spl-pod", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2562,7 +2562,7 @@ checksum = "fa27b9174bea869a7ebf31e0be6890bce90b1a4288bc2bbf24bd413f80ae3fde" dependencies = [ "curve25519-dalek", "solana-zk-sdk", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2581,7 +2581,7 @@ dependencies = [ "solana-pubkey", "spl-discriminator", "spl-pod", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2602,7 +2602,7 @@ dependencies = [ "spl-discriminator", "spl-pod", "spl-type-length-value", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2627,7 +2627,7 @@ dependencies = [ "spl-program-error", "spl-tlv-account-resolution", "spl-type-length-value", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2645,7 +2645,7 @@ dependencies = [ "solana-program-error", "spl-discriminator", "spl-pod", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2667,9 +2667,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -2687,11 +2687,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -2702,18 +2702,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2890,7 +2890,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -2912,7 +2912,7 @@ checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2968,7 +2968,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2988,5 +2988,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] diff --git a/programs/metlev-engine/src/errors.rs b/programs/metlev-engine/src/errors.rs index 1dd9abe..1f890f7 100644 --- a/programs/metlev-engine/src/errors.rs +++ b/programs/metlev-engine/src/errors.rs @@ -29,6 +29,9 @@ pub enum ProtocolError { #[msg("Lending vault has insufficient liquidity")] InsufficientLiquidity, + #[msg("Error in provided Pubkeys")] + PubkeyMismatch, + #[msg("Oracle price is stale or invalid")] OracleStale, diff --git a/programs/metlev-engine/src/instructions/close_position.rs b/programs/metlev-engine/src/instructions/close_position.rs index f118f43..c16088d 100644 --- a/programs/metlev-engine/src/instructions/close_position.rs +++ b/programs/metlev-engine/src/instructions/close_position.rs @@ -25,7 +25,7 @@ pub struct ClosePosition<'info> { #[account( mut, seeds = [LendingVault::SEED_PREFIX], - bump = lending_vault.bump, + bump = lending_vault.vault_bump, )] pub lending_vault: Account<'info, LendingVault>, diff --git a/programs/metlev-engine/src/instructions/initialize_lending_vault.rs b/programs/metlev-engine/src/instructions/initialize_lending_vault.rs index 3d897ee..81c5fb1 100644 --- a/programs/metlev-engine/src/instructions/initialize_lending_vault.rs +++ b/programs/metlev-engine/src/instructions/initialize_lending_vault.rs @@ -1,4 +1,5 @@ -use anchor_lang::{prelude::*, system_program::{Transfer, transfer}}; +use anchor_lang::prelude::*; +use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; use crate::state::LendingVault; use crate::state::Config; use crate::errors::ProtocolError; @@ -25,39 +26,32 @@ pub struct InitializeLendingVault<'info>{ pub lending_vault: Account<'info, LendingVault>, #[account( - mut, - seeds = [b"sol_vault", lending_vault.key().as_ref()], - bump, + init, + payer = authority, + token::mint = mint_x, + token::authority = lending_vault, + token::token_program = token_program, + seeds = [b"token_vault"], + bump )] - pub sol_vault: SystemAccount<'info>, + pub token_vault: InterfaceAccount<'info, TokenAccount>, + // mint_x = NATIVE_MINT for WSOL + pub mint_x: InterfaceAccount<'info, Mint>, + pub token_program: Interface<'info, TokenInterface>, pub system_program: Program<'info, System>, } impl<'info> InitializeLendingVault<'info> { pub fn initialize_lending_vault(&mut self, bumps: &InitializeLendingVaultBumps) -> Result<()> { - let rent_exempt = Rent::get()?.minimum_balance( - self.sol_vault.to_account_info().data_len() - ); - let accounts = Transfer { - from: self.authority.to_account_info(), - to: self.sol_vault.to_account_info(), - }; - - let ctx = CpiContext::new( - self.system_program.to_account_info(), - accounts, - ); - transfer(ctx, rent_exempt)?; - self.lending_vault.set_inner(LendingVault { authority: self.authority.key(), total_supplied: 0, total_borrowed: 0, interest_rate_bps: 30, // Let's update that later to be dynamic last_update: Clock::get()?.unix_timestamp, - bump: bumps.lending_vault, - vault_bump: bumps.sol_vault, + vault_bump: bumps.lending_vault, + token_vault_bump: bumps.token_vault, }); Ok(()) } diff --git a/programs/metlev-engine/src/instructions/liquidate.rs b/programs/metlev-engine/src/instructions/liquidate.rs index 91316f1..252e966 100644 --- a/programs/metlev-engine/src/instructions/liquidate.rs +++ b/programs/metlev-engine/src/instructions/liquidate.rs @@ -24,7 +24,7 @@ pub struct Liquidate<'info> { #[account( mut, seeds = [LendingVault::SEED_PREFIX], - bump = lending_vault.bump, + bump = lending_vault.vault_bump, )] pub lending_vault: Account<'info, LendingVault>, diff --git a/programs/metlev-engine/src/instructions/mod.rs b/programs/metlev-engine/src/instructions/mod.rs index 0ffe92b..5909047 100644 --- a/programs/metlev-engine/src/instructions/mod.rs +++ b/programs/metlev-engine/src/instructions/mod.rs @@ -7,8 +7,8 @@ pub mod open_position; pub mod close_position; pub mod liquidate; pub mod update_config; -pub mod supply; -pub mod withdraw; +pub mod supply_vault_lp; +pub mod withdraw_vault_lp; pub use initialize::*; pub use initialize_lending_vault::*; @@ -19,5 +19,5 @@ pub use open_position::*; pub use close_position::*; pub use liquidate::*; pub use update_config::*; -pub use supply::*; -pub use withdraw::*; +pub use supply_vault_lp::*; +pub use withdraw_vault_lp::*; diff --git a/programs/metlev-engine/src/instructions/open_position.rs b/programs/metlev-engine/src/instructions/open_position.rs index 7b00ee9..4dda473 100644 --- a/programs/metlev-engine/src/instructions/open_position.rs +++ b/programs/metlev-engine/src/instructions/open_position.rs @@ -25,7 +25,7 @@ pub struct OpenPosition<'info> { #[account( mut, seeds = [LendingVault::SEED_PREFIX], - bump = lending_vault.bump, + bump = lending_vault.vault_bump, )] pub lending_vault: Account<'info, LendingVault>, diff --git a/programs/metlev-engine/src/instructions/supply.rs b/programs/metlev-engine/src/instructions/supply.rs deleted file mode 100644 index 1ea33ee..0000000 --- a/programs/metlev-engine/src/instructions/supply.rs +++ /dev/null @@ -1,78 +0,0 @@ -use anchor_lang::{ - prelude::*, - system_program::{ - transfer, - Transfer - } -}; -use crate::state::{LendingVault}; -use crate::state::LpPosition; -use crate::errors::ProtocolError; - -#[derive(Accounts)] -pub struct Supply<'info> { - #[account(mut)] - pub signer: Signer<'info>, - - #[account( - mut, - seeds = [LendingVault::SEED_PREFIX], - bump = lending_vault.bump - )] - pub lending_vault: Account<'info, LendingVault>, - - #[account( - mut, - seeds = [b"sol_vault", lending_vault.key().as_ref()], - bump = lending_vault.vault_bump - )] - pub sol_vault: SystemAccount<'info>, - - #[account( - init_if_needed, - payer = signer, - space = LpPosition::DISCRIMINATOR.len() + LpPosition::INIT_SPACE, - seeds = [b"lp_position", signer.key().as_ref()], - bump, - )] - pub lp_position: Account<'info, LpPosition>, - - pub system_program: Program<'info, System>, -} - -impl<'info> Supply<'info> { - pub fn supply(&mut self, bumps: &SupplyBumps, amount: u64) -> Result<()> { - let current_time = Clock::get()?.unix_timestamp; - - if self.lp_position.lp == Pubkey::default() { - self.lp_position.lp = self.signer.key(); - self.lp_position.last_update = current_time; - self.lp_position.bump = bumps.lp_position; - } else { - self.lp_position.accrue_interest( - self.lending_vault.interest_rate_bps, - current_time, - ); - } - - self.lp_position.supplied_amount = self.lp_position.supplied_amount - .checked_add(amount) - .ok_or(ProtocolError::MathOverflow)?; - - self.lending_vault.total_supplied = self.lending_vault.total_supplied - .checked_add(amount) - .ok_or(ProtocolError::MathOverflow)?; - - let accounts = Transfer { - from: self.signer.to_account_info(), - to: self.sol_vault.to_account_info() - }; - - let ctx = CpiContext::new( - self.system_program.to_account_info(), - accounts, - ); - - transfer(ctx, amount) - } -} \ No newline at end of file diff --git a/programs/metlev-engine/src/instructions/supply_vault_lp.rs b/programs/metlev-engine/src/instructions/supply_vault_lp.rs new file mode 100644 index 0000000..65121bf --- /dev/null +++ b/programs/metlev-engine/src/instructions/supply_vault_lp.rs @@ -0,0 +1,125 @@ +use anchor_lang::prelude::*; +use anchor_lang::system_program::{Transfer, transfer}; +use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface, TransferChecked, transfer_checked, sync_native, SyncNative}; +use crate::state::{LendingVault}; +use crate::state::LpPosition; +use crate::errors::ProtocolError; +use crate::utils::constants::*; + +#[derive(Accounts)] +pub struct Supply<'info> { + #[account(mut)] + pub signer: Signer<'info>, + + #[account( + mut, + seeds = [LendingVault::SEED_PREFIX], + bump = lending_vault.vault_bump + )] + pub lending_vault: Account<'info, LendingVault>, + + #[account( + mut, + token::mint = mint_x, + token::authority = lending_vault, + token::token_program = token_program, + seeds = [b"token_x_vault"], + bump + )] + pub token_vault: InterfaceAccount<'info, TokenAccount>, + + #[account( + init_if_needed, + payer = signer, + space = LpPosition::DISCRIMINATOR.len() + LpPosition::INIT_SPACE, + seeds = [b"lp_position", signer.key().as_ref()], + bump, + )] + pub lp_position: Account<'info, LpPosition>, + // mint_x = NATIVE_MINT for WSOL + pub mint_x: InterfaceAccount<'info, Mint>, + ///Check: SPL token interface will check this + pub user_x_ata: UncheckedAccount<'info>, + pub token_program: Interface<'info, TokenInterface>, + pub system_program: Program<'info, System>, +} + +impl<'info> Supply<'info> { + pub fn supply(&mut self, bumps: &SupplyBumps, amount: u64) -> Result<()> { + let current_time = Clock::get()?.unix_timestamp; + + require_neq!(self.mint_x.key(), Pubkey::default(), ProtocolError::PubkeyMismatch); + + if self.lp_position.lp == Pubkey::default() { + self.lp_position.lp = self.signer.key(); + self.lp_position.last_update = current_time; + self.lp_position.bump = bumps.lp_position; + } else { + self.lp_position.accrue_interest( + self.lending_vault.interest_rate_bps, + current_time, + ); + } + + self.lp_position.supplied_amount = self.lp_position.supplied_amount + .checked_add(amount) + .ok_or(ProtocolError::MathOverflow)?; + + self.lending_vault.total_supplied = self.lending_vault.total_supplied + .checked_add(amount_x) + .ok_or(ProtocolError::MathOverflow)?; + + let is_native = self.mint_x.key() == NATIVE_MINT_ID; + + // Transfer Logic for X + self.handle_transfer( + is_native, + amount, + &self.user_x_ata.to_account_info(), + &self.token_vault.to_account_info(), + &self.mint_x + )?; + + Ok(()) + } + + //Helper Function For Handling Native & SPL transfers + fn handle_transfer( + &self, + is_native:bool, + amount: u64, + user_token_info: &AccountInfo<'info>, + vault_info: &AccountInfo<'info>, + mint: &InterfaceAccount<'info, Mint> + ) -> Result<()> { + if amount == 0 { + return Ok(()) + }; + if is_native { + //Transfer Raw SOL to Vault token account + let native_transfer_accounts = Transfer { + from: self.signer.to_account_info(), + to: vault_info.clone() + }; + let native_transfer_ctx = CpiContext::new(self.system_program.to_account_info(), native_transfer_accounts); + transfer(native_transfer_ctx, amount)?; + // 2. Sync Native to wrap it instantly inside the Vault + let sync_native_ctx = CpiContext::new(self.token_program.to_account_info(), SyncNative { + account: vault_info.clone() + }); + sync_native(sync_native_ctx)?; + + } else { + let spl_transfer_accounts = TransferChecked { + from: user_token_info.clone(), + to: vault_info.clone(), + mint: mint.to_account_info(), + authority: self.signer.to_account_info() + }; + let spl_transfer_ctx = CpiContext::new(self.token_program.to_account_info(), spl_transfer_accounts); + transfer_checked(spl_transfer_ctx, amount, mint.decimals)?; + } + Ok(()) + } + +} diff --git a/programs/metlev-engine/src/instructions/withdraw.rs b/programs/metlev-engine/src/instructions/withdraw_vault_lp.rs similarity index 67% rename from programs/metlev-engine/src/instructions/withdraw.rs rename to programs/metlev-engine/src/instructions/withdraw_vault_lp.rs index ad808ed..5971db9 100644 --- a/programs/metlev-engine/src/instructions/withdraw.rs +++ b/programs/metlev-engine/src/instructions/withdraw_vault_lp.rs @@ -1,5 +1,5 @@ use anchor_lang::{prelude::*, system_program::{Transfer, transfer}}; - +use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; use crate::state::{LpPosition, LendingVault}; use crate::errors::ProtocolError; @@ -20,17 +20,23 @@ pub struct Withdraw<'info> { #[account( mut, seeds = [LendingVault::SEED_PREFIX], - bump = lending_vault.bump, + bump = lending_vault.vault_bump, )] pub lending_vault: Account<'info, LendingVault>, #[account( mut, - seeds = [b"sol_vault", lending_vault.key().as_ref()], - bump = lending_vault.vault_bump, + token::mint = mint_x, + token::authority = lending_vault, + token::token_program = token_program, + seeds = [b"token_vault"], + bump )] - pub sol_vault: SystemAccount<'info>, - + pub token_vault: InterfaceAccount<'info, TokenAccount>, + + // mint_x = NATIVE_MINT for WSOL + pub mint_x: InterfaceAccount<'info, Mint>, + pub token_program: Interface<'info, TokenInterface>, pub system_program: Program<'info, System>, } @@ -47,24 +53,26 @@ impl<'info> Withdraw<'info> { let amount = self.lp_position.claimable(); - let rent_exempt = Rent::get()?.minimum_balance(0); + // let rent_exempt = Rent::get()?.minimum_balance(0); + //not sure whether it is safer to treat the WSOL as a token account and use token_vault.amount here + // as we have used the sync_native to sync the balances require!( - self.sol_vault.get_lamports() >= amount + rent_exempt, + // self.sol_vault.get_lamports() >= amount + rent_exempt, + self.token_vault.amount >= amount, ProtocolError::InsufficientLiquidity - ); + ); self.lending_vault.total_supplied = self.lending_vault.total_supplied .checked_sub(self.lp_position.supplied_amount) .ok_or(ProtocolError::MathUnderflow)?; let accounts = Transfer{ - from: self.sol_vault.to_account_info(), + from: self.token_vault.to_account_info(), to: self.signer.to_account_info() }; - let lending_vault_key = self.lending_vault.key(); + let signer_seeds: &[&[&[u8]]] = &[&[ - b"sol_vault", - lending_vault_key.as_ref(), + b"token_vault", &[self.lending_vault.vault_bump], ] ]; diff --git a/programs/metlev-engine/src/state/lending_vault.rs b/programs/metlev-engine/src/state/lending_vault.rs index 427d242..2b2a4bd 100644 --- a/programs/metlev-engine/src/state/lending_vault.rs +++ b/programs/metlev-engine/src/state/lending_vault.rs @@ -12,8 +12,8 @@ pub struct LendingVault { pub interest_rate_bps: u16, /// Last time interest was accrued pub last_update: i64, - pub bump: u8, pub vault_bump: u8, + pub token_vault_bump: u8, } impl LendingVault { @@ -30,15 +30,22 @@ impl LendingVault { } pub fn borrow(&mut self, amount: u64) -> Result<()> { - require!(self.can_borrow(amount), crate::errors::ProtocolError::InsufficientLiquidity); - self.total_borrowed = self.total_borrowed.checked_add(amount) + require!( + self.can_borrow(amount), + crate::errors::ProtocolError::InsufficientLiquidity + ); + self.total_borrowed = self + .total_borrowed + .checked_add(amount) .ok_or(crate::errors::ProtocolError::MathOverflow)?; Ok(()) } /// Record debt repayment pub fn repay(&mut self, amount: u64) -> Result<()> { - self.total_borrowed = self.total_borrowed.checked_sub(amount) + self.total_borrowed = self + .total_borrowed + .checked_sub(amount) .ok_or(crate::errors::ProtocolError::MathOverflow)?; Ok(()) } diff --git a/programs/metlev-engine/src/state/lp_position.rs b/programs/metlev-engine/src/state/lp_position.rs index 8448b9f..5172909 100644 --- a/programs/metlev-engine/src/state/lp_position.rs +++ b/programs/metlev-engine/src/state/lp_position.rs @@ -6,7 +6,7 @@ pub struct LpPosition { /// LP provider wallet pub lp: Pubkey, - /// Total SOL supplied (in lamports) + /// Total SOL/TOKEN supplied (in lamports) pub supplied_amount: u64, /// Accumulated interest earned so far (in lamports) @@ -24,6 +24,7 @@ impl LpPosition { /// Accrue simple annual interest based on elapsed time and update state. /// interest = principal * rate_bps * elapsed_seconds / (365 * 24 * 3600 * 10000) + /// Interest Rate Same for Token_x and Token_Y pub fn accrue_interest(&mut self, interest_rate_bps: u16, current_time: i64) { let elapsed = (current_time - self.last_update).max(0) as u128; let interest = (self.supplied_amount as u128) diff --git a/programs/metlev-engine/src/utils/constants.rs b/programs/metlev-engine/src/utils/constants.rs new file mode 100644 index 0000000..1ab590b --- /dev/null +++ b/programs/metlev-engine/src/utils/constants.rs @@ -0,0 +1,4 @@ +use anchor_lang::prelude::*; + + +pub const NATIVE_MINT_ID:Pubkey = pubkey!("So11111111111111111111111111111111111111112"); \ No newline at end of file diff --git a/programs/metlev-engine/src/utils/mod.rs b/programs/metlev-engine/src/utils/mod.rs index 5c53e78..bbd6a64 100644 --- a/programs/metlev-engine/src/utils/mod.rs +++ b/programs/metlev-engine/src/utils/mod.rs @@ -1,5 +1,7 @@ pub mod health; pub mod oracle; +pub mod constants; pub use health::*; pub use oracle::*; +pub use constants::*; diff --git a/tests/lending_vault.ts b/tests/lending_vault.ts index e3cad36..6012c4a 100644 --- a/tests/lending_vault.ts +++ b/tests/lending_vault.ts @@ -1,7 +1,14 @@ import * as anchor from "@coral-xyz/anchor"; import { Program } from "@coral-xyz/anchor"; import { MetlevEngine } from "../target/types/metlev_engine"; -import { PublicKey, Keypair, SystemProgram, LAMPORTS_PER_SOL } from "@solana/web3.js"; +import { PublicKey, Keypair, SystemProgram, LAMPORTS_PER_SOL, } from "@solana/web3.js"; +import { + TOKEN_PROGRAM_ID, + createMint, + createAccount, + mintTo, + getAccount, +} from "@solana/spl-token"; import { expect } from "chai"; describe("Lending Vault", () => { @@ -16,7 +23,12 @@ describe("Lending Vault", () => { let configPda: PublicKey; let lendingVaultPda: PublicKey; - let solVaultPda: PublicKey; + let tokenXVaultPda: PublicKey; + let tokenYVaultPda: PublicKey; + + const SOL_MINT = new PublicKey("So11111111111111111111111111111111111111112"); + let USDC_MINT: PublicKey; + before(async () => { [configPda] = PublicKey.findProgramAddressSync( @@ -29,11 +41,23 @@ describe("Lending Vault", () => { program.programId ); - [solVaultPda] = PublicKey.findProgramAddressSync( - [Buffer.from("sol_vault"), lendingVaultPda.toBuffer()], + [tokenXVaultPda] = PublicKey.findProgramAddressSync( + [Buffer.from("token_x_vault")], + program.programId + ); + [tokenYVaultPda] = PublicKey.findProgramAddressSync( + [Buffer.from("token_y_vault")], program.programId ); + USDC_MINT = await createMint( + provider.connection, + provider.wallet.payer, + authority, + null, + 6 + ); + for (const user of [lp, lp2]) { const sig = await provider.connection.requestAirdrop( user.publicKey, @@ -66,7 +90,11 @@ describe("Lending Vault", () => { authority, config: configPda, lendingVault: lendingVaultPda, - solVault: solVaultPda, + tokenXVault: tokenXVaultPda, + tokenYVault: tokenYVaultPda, + mintX: SOL_MINT, + mintY: USDC_MINT, + tokenProgram: TOKEN_PROGRAM_ID, systemProgram: SystemProgram.programId, }) .rpc(); @@ -75,7 +103,8 @@ describe("Lending Vault", () => { console.log("\n=== Setup Complete ==="); console.log("Lending Vault PDA:", lendingVaultPda.toBase58()); - console.log("SOL Vault PDA:", solVaultPda.toBase58()); + console.log("WSOL Vault PDA:", tokenXVaultPda.toBase58()); + console.log("USDC Vault PDA:", tokenYVaultPda.toBase58()); }); describe("Initialize Lending Vault", () => { @@ -86,11 +115,7 @@ describe("Lending Vault", () => { expect(vault.totalSupplied.toNumber()).to.equal(0); expect(vault.totalBorrowed.toNumber()).to.equal(0); - const solVaultBalance = await provider.connection.getBalance(solVaultPda); - expect(solVaultBalance).to.be.greaterThan(0); - console.log("Vault authority:", vault.authority.toBase58()); - console.log("SOL vault balance (rent):", solVaultBalance, "lamports"); }); });