Skip to content
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8aed042
added oracle limit support
santy311 Jun 9, 2025
805c8a1
WIP: fixed test case for oracle limit
santy311 Jun 9, 2025
bd533b4
added passthrough action support
santy311 Jun 10, 2025
2fe58f0
WIP: added oracle data reader
santy311 Jun 11, 2025
1046066
modified OracleTokenLimit
santy311 Jun 11, 2025
25a6436
added sol oracle limit
santy311 Jun 11, 2025
50d61ba
fixed oracle token transfer test case
santy311 Jun 13, 2025
19f4cd7
added CU count logs
santy311 Jun 13, 2025
57bee0e
added more oracle mints support
santy311 Jun 13, 2025
18d01c0
read directly from pyth oracle data
santy311 Jun 15, 2025
02d2d9c
removed complex feed id fetch logic
santy311 Jun 15, 2025
449af9c
fix stupid comments
santy311 Jun 15, 2025
9cd1b87
Merge remote-tracking branch 'origin/main' into santhosh/oracle-limit
santy311 Jun 27, 2025
d462321
changed error code after merge conflict
santy311 Jun 27, 2025
848edaf
changed error code number for oracle limit
santy311 Jun 27, 2025
0a4aa49
scope support added
santy311 Jul 5, 2025
2680569
Merge remote-tracking branch 'origin/main' into santhosh/oracle-limit…
santy311 Jul 5, 2025
0c77ff0
fixed merge conflict issues
santy311 Jul 5, 2025
a47b68c
removed long mapping
santy311 Jul 16, 2025
61e98d9
Merge remote-tracking branch 'origin/main' into santhosh/oracle-limit…
santy311 Jul 16, 2025
19ab2d0
oracle test added for new scope mapping states
santy311 Jul 16, 2025
d543931
imported oracle mapper states from mapper repo
santy311 Jul 25, 2025
6345368
added display support for test debugging
santy311 Jul 25, 2025
f4268fe
removed pyth as scope is derived from pyth
santy311 Aug 1, 2025
211367c
fixed merge conflict
santy311 Aug 4, 2025
c113c68
added stale check for oracle prices
santy311 Aug 4, 2025
ca69b03
changed oracle mapper branch to main
santy311 Aug 4, 2025
15a6569
oracle reccuring limit
santy311 Aug 10, 2025
95a29e1
fixed formatting
santy311 Aug 10, 2025
1b5954e
Merge remote-tracking branch 'origin/main' into santhosh/oracle-limit…
santy311 Aug 11, 2025
d4613bd
oracle fixes
santy311 Aug 11, 2025
5bac70d
added EUR support
santy311 Aug 12, 2025
ca1d940
oracle_recurring_limit_window_reset debug
santy311 Aug 12, 2025
c3ac2cd
fixed CU limit for program scope test
santy311 Aug 12, 2025
6dabac6
Merge remote-tracking branch 'origin/main' into santhosh/oracle-limit…
santy311 Aug 13, 2025
c410d78
Merge remote-tracking branch 'origin/main' into santhosh/oracle-limit…
santy311 Sep 22, 2025
a4d532f
WIP: oracle refactor
santy311 Sep 23, 2025
94281b2
Merge remote-tracking branch 'origin/main' into santhosh/oracle-limit…
santy311 Oct 7, 2025
bb0afdc
removed duplicate role fetch helper
santy311 Oct 7, 2025
a6053b1
fixed oracle test cases for sign v2.
santy311 Oct 7, 2025
958ae3f
sdk and CLI support
santy311 Oct 14, 2025
81fda70
replaced owner check with address check
santy311 Oct 14, 2025
e96b774
replaced key with owner
santy311 Oct 14, 2025
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
76 changes: 69 additions & 7 deletions Cargo.lock

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

16 changes: 11 additions & 5 deletions interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ use swig::actions::{
pub use swig_compact_instructions::*;
use swig_state::{
action::{
all::All, manage_authority::ManageAuthority, program::Program, program_all::ProgramAll,
program_curated::ProgramCurated, program_scope::ProgramScope, sol_limit::SolLimit,
sol_recurring_limit::SolRecurringLimit, stake_all::StakeAll, stake_limit::StakeLimit,
stake_recurring_limit::StakeRecurringLimit, sub_account::SubAccount,
token_limit::TokenLimit, token_recurring_limit::TokenRecurringLimit, Action, Permission,
all::All, manage_authority::ManageAuthority, oracle_limits::OracleTokenLimit,
program::Program, program_all::ProgramAll, program_curated::ProgramCurated,
program_scope::ProgramScope, sol_limit::SolLimit, sol_recurring_limit::SolRecurringLimit,
stake_all::StakeAll, stake_limit::StakeLimit, stake_recurring_limit::StakeRecurringLimit,
sub_account::SubAccount, token_limit::TokenLimit,
token_recurring_limit::TokenRecurringLimit, Action, Permission,
},
authority::{
secp256k1::{hex_encode, AccountsPayload},
Expand All @@ -50,6 +51,7 @@ pub enum ClientAction {
StakeLimit(StakeLimit),
StakeRecurringLimit(StakeRecurringLimit),
StakeAll(StakeAll),
OracleTokenLimit(OracleTokenLimit),
}

impl ClientAction {
Expand All @@ -75,6 +77,9 @@ impl ClientAction {
(Permission::StakeRecurringLimit, StakeRecurringLimit::LEN)
},
ClientAction::StakeAll(_) => (Permission::StakeAll, StakeAll::LEN),
ClientAction::OracleTokenLimit(_) => {
(Permission::OracleTokenLimit, OracleTokenLimit::LEN)
},
};
let offset = data.len() as u32;
let header = Action::new(
Expand All @@ -101,6 +106,7 @@ impl ClientAction {
ClientAction::StakeLimit(action) => action.into_bytes(),
ClientAction::StakeRecurringLimit(action) => action.into_bytes(),
ClientAction::StakeAll(action) => action.into_bytes(),
ClientAction::OracleTokenLimit(action) => action.into_bytes(),
};
data.extend_from_slice(
bytes_res.map_err(|e| anyhow::anyhow!("Failed to serialize action {:?}", e))?,
Expand Down
3 changes: 3 additions & 0 deletions program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ bytemuck = { version = "1.13.1", features = ["derive"] }
no-padding = { path = "../no-padding" }
solana-security-txt = "=1.1.1"
default-env = "=0.1.1"
oracle-mapping-state = { git = "https://github.com/anagrambuild/scope-oracle-mapper", branch = "santhosh/state-crate" }


[dev-dependencies]
solana-sdk = "2"
Expand All @@ -47,6 +49,7 @@ solana-client = "=2.2.4"
solana-program = "=2.2.1"
once_cell = "1.21.3"
spl-memo = "=6.0.0"
base64 = "0.22.1"
solana-secp256r1-program = "2.2.1"
openssl = { version = "0.10.72", features = ["vendored"] }
hex = "0.4.3"
Expand Down
93 changes: 91 additions & 2 deletions program/src/actions/sign_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ use pinocchio::{
sysvars::{clock::Clock, Sysvar},
ProgramResult,
};
use pinocchio_pubkey::from_str;
use pinocchio_pubkey::{from_str, pubkey};
use swig_assertions::*;
use swig_compact_instructions::InstructionIterator;
use swig_state::{
action::{
all::All,
oracle_limits::OracleTokenLimit,
program::Program,
program_all::ProgramAll,
program_curated::ProgramCurated,
Expand All @@ -43,7 +44,7 @@ use crate::{
accounts::{Context, SignV1Accounts},
SwigInstruction,
},
util::{build_restricted_keys, hash_except},
util::{build_restricted_keys, calculate_token_value, get_price_data, hash_except},
AccountClassification,
};
// use swig_instructions::InstructionIterator;
Expand Down Expand Up @@ -361,7 +362,56 @@ pub fn sign_v1(
}
if lamports > &current_lamports {
let amount_diff = lamports - current_lamports;
{
if let Some(action) =
RoleMut::get_action_mut::<OracleTokenLimit>(actions, &[0u8])?
{
let scope_data = unsafe {
let scope_account =
&all_accounts.get_unchecked(all_accounts.len() - 1);
// also check if owner matches
if scope_account.owner().as_ref()
!= &pubkey!("HFn8GnPADiny6XqUoWE8uRPPxb29ikn4yTuPa9MF2fWJ")
{
return Err(SwigError::WrongOracleProgramAccount.into());
}
scope_account.borrow_data_unchecked()
};

let mapping_registry = unsafe {
let mapping_account =
&all_accounts.get_unchecked(all_accounts.len() - 2);
if mapping_account.owner().as_ref()
!= &pubkey!("HFn8GnPADiny6XqUoWE8uRPPxb29ikn4yTuPa9MF2fWJ")
{
return Err(SwigError::WrongOracleMappingAccount.into());
}
mapping_account.borrow_data_unchecked()
};

let (price, exp, mint_decimal) = get_price_data(
mapping_registry,
scope_data,
&pubkey!("So11111111111111111111111111111111111111112"),
&clock,
)?;

let token_value_in_base = calculate_token_value(
price,
exp,
action.get_base_asset_decimals(),
amount_diff,
mint_decimal,
action.get_base_asset_decimals(),
)?;

action.run_for_sol(token_value_in_base)?;

if !action.passthrough_check {
continue;
}
};
}
{
if let Some(action) = RoleMut::get_action_mut::<SolLimit>(actions, &[])?
{
Expand Down Expand Up @@ -421,6 +471,45 @@ pub fn sign_v1(

if balance > &current_token_balance {
let diff = balance - current_token_balance;
// Check oracle token limit
{
if let Some(action) =
RoleMut::get_action_mut::<OracleTokenLimit>(actions, &[0u8])?
{
let scope_data = unsafe {
&all_accounts
.get_unchecked(all_accounts.len() - 1)
.borrow_data_unchecked()
};

let mapping_data = unsafe {
&all_accounts
.get_unchecked(all_accounts.len() - 2)
.borrow_data_unchecked()
};

let mint_bytes =
mint.try_into().map_err(|_| SwigError::OracleMintNotFound)?;

let (price, exp, mint_decimal) =
get_price_data(mapping_data, scope_data, &mint_bytes, &clock)?;

let token_value_in_base = calculate_token_value(
price,
exp,
action.get_base_asset_decimals(),
diff,
mint_decimal,
action.get_base_asset_decimals(),
)?;

action.run_for_token(token_value_in_base)?;

if !action.passthrough_check {
continue;
}
};
}
{
if let Some(action) =
RoleMut::get_action_mut::<TokenRecurringLimit>(actions, mint)?
Expand Down
36 changes: 36 additions & 0 deletions program/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,42 @@ pub enum SwigError {
AccountDataModifiedUnexpectedly,
/// Cannot update root authority (ID 0)
PermissionDeniedCannotUpdateRootAuthority,
/// Oracle account required for token limit check was not found
PermissionDeniedMissingOracleAccount,
/// Failed to read oracle price data
InvalidOraclePriceData,
/// Failed to verify the oracle level to FULL
OracleVerficationLevelFailed,
/// Failed to fetch latest oracle price
OraclePriceTooOld,
/// Wrong oracle program account
WrongOracleProgramAccount,
/// Wrong oracle mapping account
WrongOracleMappingAccount,
/// Oracle mint not found
OracleMintNotFound,
/// Oracle value overflow during calculation
OracleValueOverflow,
/// Oracle invalid price chain configuration
OracleInvalidPriceChain,
/// Oracle data bounds error
OracleDataBoundsError,
/// Oracle empty price chain
OracleEmptyPriceChain,
/// Oracle multiplication overflow
OracleMultiplicationOverflow,
/// Oracle addition overflow
OracleAdditionOverflow,
/// Oracle subtraction overflow
OracleSubtractionOverflow,
/// Oracle exponent mismatch between price sources
OracleExponentMismatch,
/// Oracle price difference exceeds threshold
OraclePriceDifferenceExceedsThreshold,
/// Oracle mapping registry is not initialized
OracleMappingRegistryNotInitialized,
/// Oracle price chain empty
OraclePriceChainEmpty,
}

/// Implements conversion from SwigError to ProgramError.
Expand Down
Loading