Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 12 additions & 67 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

92 changes: 45 additions & 47 deletions bun.lock

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ export namespace Decimals {
}

export namespace ProgramId {
export const TOKEN_2022 = TOKEN_2022_PROGRAM_ID;
export const TOKEN_METADATA = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
export const CHAINLINK_PROGRAM = new PublicKey("HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny");
export const CHAINLINK_SOL_USD_FEED = new PublicKey("99B2bTijsU6f1GCT73HmdR7HCFFjGMBcPZY6jZ96ynrR");
export const TOKEN = TOKEN_PROGRAM_ID;
export const TOKEN_METADATA = new PublicKey("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s");
export const TOKEN_2022 = TOKEN_2022_PROGRAM_ID;
}
1 change: 1 addition & 0 deletions programs/lockup/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
anchor-lang = { version = "0.31.1", features = ["init-if-needed"] }
anchor-spl = { version = "0.31.1", features = ["metadata"] }
mpl-token-metadata = "5.1.0"
chainlink_solana = { git = "https://github.com/smartcontractkit/chainlink-solana", branch = "solana-2.1" }
8 changes: 4 additions & 4 deletions programs/lockup/src/instructions/create_with_durations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ pub fn handler(
deposit_amount: u64,
cliff_duration: i64,
total_duration: i64,
start_unlock: u64,
cliff_unlock: u64,
start_unlock_amount: u64,
cliff_unlock_amount: u64,
is_cancelable: bool,
) -> Result<()> {
// Declare the start time as the current unix timestamp.
Expand All @@ -35,8 +35,8 @@ pub fn handler(
start_time,
cliff_time,
end_time,
start_unlock,
cliff_unlock,
start_unlock_amount,
cliff_unlock_amount,
is_cancelable,
)
}
10 changes: 5 additions & 5 deletions programs/lockup/src/instructions/create_with_timestamps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,30 +205,30 @@ pub fn handler(
start_time: i64,
cliff_time: i64,
end_time: i64,
start_unlock: u64,
cliff_unlock: u64,
start_unlock_amount: u64,
cliff_unlock_amount: u64,
is_cancelable: bool,
) -> Result<()> {
let deposit_token_mint = &ctx.accounts.deposit_token_mint;
let creator = &ctx.accounts.creator;
let creator_ata = &ctx.accounts.creator_ata;

// Validate parameters
check_create(deposit_amount, start_time, cliff_time, end_time, start_unlock, cliff_unlock)?;
check_create(deposit_amount, start_time, cliff_time, end_time, start_unlock_amount, cliff_unlock_amount)?;

// Effect: create the stream data.
ctx.accounts.stream_data.create(
deposit_token_mint.key(),
ctx.bumps.stream_data,
cliff_time,
cliff_unlock,
cliff_unlock_amount,
deposit_amount,
end_time,
salt,
is_cancelable,
ctx.accounts.sender.key(),
start_time,
start_unlock,
start_unlock_amount,
)?;

// Effect: mint the NFT to the recipient.
Expand Down
9 changes: 7 additions & 2 deletions programs/lockup/src/instructions/initialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,13 @@ pub struct Initialize<'info> {
}

/// See the documentation for [`crate::sablier_lockup::initialize`].
pub fn handler(ctx: Context<Initialize>, fee_collector: Pubkey) -> Result<()> {
ctx.accounts.treasury.initialize(ctx.bumps.treasury, fee_collector)?;
pub fn handler(
ctx: Context<Initialize>,
fee_collector: Pubkey,
chainlink_program: Pubkey,
chainlink_sol_usd_feed: Pubkey,
) -> Result<()> {
ctx.accounts.treasury.initialize(ctx.bumps.treasury, fee_collector, chainlink_program, chainlink_sol_usd_feed)?;
ctx.accounts.nft_collection_data.initialize(ctx.bumps.nft_collection_data)?;

nft::initialize_collection(
Expand Down
2 changes: 2 additions & 0 deletions programs/lockup/src/instructions/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ pub mod status_of;
pub mod stream_view;
pub mod streamed_amount_of;
pub mod withdrawable_amount_of;
pub mod withdrawal_fee_in_lamports;

pub use status_of::*;
pub use stream_view::*;
pub use withdrawal_fee_in_lamports::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use anchor_lang::prelude::*;

use crate::{
state::treasury::Treasury,
utils::{
constants::{seeds::TREASURY, WITHDRAWAL_FEE_USD},
fee_calculation::convert_usd_fee_to_lamports,
},
};

#[derive(Accounts)]
pub struct WithdrawalFeeInLamports<'info> {
/// Read account: the treasury account that receives the withdrawal fee.
#[account(
seeds = [TREASURY],
bump = treasury.bump
)]
pub treasury: Box<Account<'info, Treasury>>,

/// Read account: The Chainlink program used to retrieve on-chain price feeds.
/// CHECK: This is the Chainlink program.
#[account(address = treasury.chainlink_program)]
pub chainlink_program: AccountInfo<'info>,

/// Read account: The account providing the SOL/USD price feed data.
/// CHECK: We're reading data from this Chainlink feed.
#[account(address = treasury.chainlink_sol_usd_feed)]
pub chainlink_sol_usd_feed: AccountInfo<'info>,
}

pub fn handler(ctx: Context<WithdrawalFeeInLamports>) -> Result<u64> {
let fee_in_lamports = convert_usd_fee_to_lamports(
WITHDRAWAL_FEE_USD,
ctx.accounts.chainlink_program.to_account_info(),
ctx.accounts.chainlink_sol_usd_feed.to_account_info(),
);

Ok(fee_in_lamports)
}
51 changes: 43 additions & 8 deletions programs/lockup/src/instructions/withdraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ use anchor_spl::{
use crate::{
state::{lockup::StreamData, treasury::Treasury},
utils::{
constants::seeds::*, events::WithdrawFromLockupStream, lockup_math::get_withdrawable_amount,
transfer_helper::transfer_tokens, validations::check_withdraw,
constants::{seeds::*, WITHDRAWAL_FEE_USD},
events::WithdrawFromLockupStream,
fee_calculation::convert_usd_fee_to_lamports,
lockup_math::get_withdrawable_amount,
transfer_helper::transfer_tokens,
validations::check_withdraw,
},
};

const WITHDRAWAL_FEE: u64 = 10_000_000; // The fee for withdrawing from the stream, in lamports.

#[derive(Accounts)]
pub struct Withdraw<'info> {
// -------------------------------------------------------------------------- //
Expand Down Expand Up @@ -108,6 +110,16 @@ pub struct Withdraw<'info> {
/// Program account: the Associated Token program.
pub associated_token_program: Program<'info, AssociatedToken>,

/// Read account: The Chainlink program used to retrieve on-chain price feeds.
/// CHECK: This is the Chainlink program.
#[account(address = treasury.chainlink_program)]
pub chainlink_program: AccountInfo<'info>,

/// Read account: The account providing the SOL/USD price feed data.
/// CHECK: We're reading data from this Chainlink feed.
#[account(address = treasury.chainlink_sol_usd_feed)]
pub chainlink_sol_usd_feed: AccountInfo<'info>,

/// Program account: the Token program of the deposited token.
pub deposited_token_program: Interface<'info, TokenInterface>,

Expand All @@ -133,9 +145,13 @@ pub fn handler(ctx: Context<Withdraw>, amount: u64) -> Result<()> {
// Effect: update the stream data state.
ctx.accounts.stream_data.withdraw(amount)?;

// Interaction: transfer the fee from the signer to the treasury.
let fee_collection_ix = transfer(&ctx.accounts.signer.key(), &ctx.accounts.treasury.key(), WITHDRAWAL_FEE);
invoke(&fee_collection_ix, &[ctx.accounts.signer.to_account_info(), ctx.accounts.treasury.to_account_info()])?;
// Interaction: charge the withdrawal fee.
let fee_in_lamports = charge_withdrawal_fee(
ctx.accounts.chainlink_program.to_account_info(),
ctx.accounts.chainlink_sol_usd_feed.to_account_info(),
ctx.accounts.signer.to_account_info(),
ctx.accounts.treasury.to_account_info(),
)?;

// Interaction: transfer the tokens from the stream ATA to the recipient.
transfer_tokens(
Expand All @@ -152,10 +168,29 @@ pub fn handler(ctx: Context<Withdraw>, amount: u64) -> Result<()> {
// Log the withdrawal.
emit!(WithdrawFromLockupStream {
deposited_token_mint: ctx.accounts.deposited_token_mint.key(),
fee_in_lamports,
stream_data: ctx.accounts.stream_data.key(),
stream_nft_mint: ctx.accounts.stream_nft_mint.key(),
withdrawn_amount: amount
withdrawn_amount: amount,
});

Ok(())
}

/// Charges the withdrawal fee in lamports.
fn charge_withdrawal_fee<'info>(
chainlink_program: AccountInfo<'info>,
chainlink_sol_usd_feed: AccountInfo<'info>,
tx_signer: AccountInfo<'info>,
treasury: AccountInfo<'info>,
) -> Result<u64> {
// Calculate the fee in lamports.
let fee_in_lamports: u64 =
convert_usd_fee_to_lamports(WITHDRAWAL_FEE_USD, chainlink_program, chainlink_sol_usd_feed);

// Interaction: transfer the fee from the signer to the treasury.
let fee_charging_ix = transfer(&tx_signer.key(), &treasury.key(), fee_in_lamports);
invoke(&fee_charging_ix, &[tx_signer, treasury])?;

Ok(fee_in_lamports)
}
Loading
Loading