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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ List of supported programs:
- [x] BisonFi
- [x] HumidiFi
- [x] Obric
- [x] Scorch
- [x] SolFi
- [x] Tessera
- [x] ZeroFi
Expand All @@ -52,6 +53,7 @@ CU benchmarks between Mona, Jupiter and direct (non-router) program hit:
| goonfi | — | — | 87,703 |
| humidifi | 41,194 | 47,342 | 52,723 |
| obric | 54,406 | 56,813 | 61,111 |
| scorch | TODO | TODO | TODO |
| solfi | 82,616 | 90,086 | 99,717 |
| tessera | — | 63,198 | 79,376 |
| zerofi | 34,734 | 37,238 | 41,910 |
Expand Down
1 change: 1 addition & 0 deletions src/adapters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod aquifer_v1;
pub mod bisonfi_v1;
pub mod humidifi_v1;
pub mod obric_v2;
pub mod scorch_v1;
pub mod solfi_v2;
pub mod tessera_v1;
pub mod zerofi_v1;
105 changes: 105 additions & 0 deletions src/adapters/scorch_v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::cons::scorch::{ACCS_LEN, ARGS_LEN, SWAP_SELECTOR};
use pinocchio::cpi::{invoke_unchecked, CpiAccount};
use pinocchio::instruction::{InstructionAccount, InstructionView};
use pinocchio::AccountView;

// Scorch V1 swap args: selector(1) + param(17) + amount_in(8) + min_out(8) = 34 bytes.
#[repr(C, packed)]
pub struct SwapArgs {
pub selector: [u8; 1],
pub scorch_param: [u8; 17],
pub amount_in: [u8; 8],
pub min_out: [u8; 8],
}

impl SwapArgs {
pub fn new(amount_in: u64) -> Self {
Self {
selector: *SWAP_SELECTOR,
scorch_param: [0u8; 17], // patched by caller from scorch_param key
amount_in: amount_in.to_le_bytes(),
min_out: 1u64.to_le_bytes(),
}
}

pub fn as_bytes(&self) -> &[u8; ARGS_LEN] {
unsafe { &*(self as *const Self as *const [u8; ARGS_LEN]) }
}
}

/// Remaining layout (18 accounts):
/// 0 program (readonly)
/// 1 market (readonly)
/// 2 user_ata_a (writable)
/// 3 user_ata_b (writable)
/// 4 market_ta_a (writable)
/// 5 market_ta_b (writable)
/// 6 mint_a (readonly)
/// 7 mint_b (readonly)
/// 8 token_prog (readonly)
/// 9 token_prog (readonly)
/// 10 memo_prog (readonly)
/// 11 core_prog (readonly)
/// 12 acc1 (readonly)
/// 13 state_a (writable)
/// 14 state_b (writable)
/// 15 state_c (writable)
/// 16 sysvar_ixs (readonly)
/// 17 scorch_param (readonly) - encoded in first 16 bytes of key
///
/// CPI to Scorch (18 accounts): payer injected at position 1.
pub fn swap_v1(payer: &AccountView, rem: &[AccountView], amount_in: u64, _a_to_b: bool) {
let mut args = SwapArgs::new(amount_in);

// extract params from the scorch_param account key (first 17 bytes)
args.scorch_param
.copy_from_slice(&rem[17].address().as_ref()[..17]);

let ix_accs = [
InstructionAccount::readonly(rem[1].address()), // market
InstructionAccount::writable_signer(payer.address()), // payer
InstructionAccount::writable(rem[2].address()), // user_ata_a
InstructionAccount::writable(rem[3].address()), // user_ata_b
InstructionAccount::writable(rem[4].address()), // market_ta_a
InstructionAccount::writable(rem[5].address()), // market_ta_b
InstructionAccount::readonly(rem[6].address()), // mint_a
InstructionAccount::readonly(rem[7].address()), // mint_b
InstructionAccount::readonly(rem[8].address()), // token_prog
InstructionAccount::readonly(rem[9].address()), // token_prog
InstructionAccount::readonly(rem[10].address()), // memo_prog
InstructionAccount::readonly(rem[11].address()), // core_prog
InstructionAccount::readonly(rem[12].address()), // acc1
InstructionAccount::writable(rem[13].address()), // state_a
InstructionAccount::writable(rem[14].address()), // state_b
InstructionAccount::writable(rem[15].address()), // state_c
InstructionAccount::readonly(rem[16].address()), // sysvar_ixs
];

let ix = InstructionView {
program_id: rem[0].address(),
data: args.as_bytes(),
accounts: &ix_accs,
};

let cpi: [CpiAccount; ACCS_LEN - 1] = [
CpiAccount::from(&rem[1]),
CpiAccount::from(payer),
CpiAccount::from(&rem[2]),
CpiAccount::from(&rem[3]),
CpiAccount::from(&rem[4]),
CpiAccount::from(&rem[5]),
CpiAccount::from(&rem[6]),
CpiAccount::from(&rem[7]),
CpiAccount::from(&rem[8]),
CpiAccount::from(&rem[9]),
CpiAccount::from(&rem[10]),
CpiAccount::from(&rem[11]),
CpiAccount::from(&rem[12]),
CpiAccount::from(&rem[13]),
CpiAccount::from(&rem[14]),
CpiAccount::from(&rem[15]),
CpiAccount::from(&rem[16]),
];

unsafe { invoke_unchecked(&ix, &cpi) }
}
45 changes: 34 additions & 11 deletions src/cons.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ use five8_const::decode_32_const as d;

pub const MAX_HOPS: usize = 30;

const OBF_CPI_KEY_SEED: [u8; 32] =
[58, 255, 47, 255, 226, 186, 235, 195, 123, 131, 245, 8, 11, 233, 132, 219, 225, 40, 79, 119, 169, 121, 169, 58, 197, 1, 122, 9, 216, 164, 149, 97];
const OBF_CPI_KEY_SEED: [u8; 32] = [
58, 255, 47, 255, 226, 186, 235, 195, 123, 131, 245, 8, 11, 233, 132, 219, 225, 40, 79, 119,
169, 121, 169, 58, 197, 1, 122, 9, 216, 164, 149, 97,
];
pub const OBF_CPI_KEY: u64 = u64::from_le_bytes([
OBF_CPI_KEY_SEED[0],
OBF_CPI_KEY_SEED[1],
Expand Down Expand Up @@ -74,6 +76,13 @@ pub mod alphaq {
pub const ARGS_LEN: usize = 18;
}

pub mod scorch {
pub const ID: [u8; 32] = super::d("SCoRcH8c2dpjvcJD6FiPbCSQyQgu3PcUAWj2Xxx3mqn");
pub const SWAP_SELECTOR: &[u8; 1] = &[0x02];
pub const ACCS_LEN: usize = 18;
pub const ARGS_LEN: usize = 34;
}

/// DEX discriminant;
/// each variant maps to a specific adapter.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
Expand All @@ -85,13 +94,25 @@ pub enum Dex {
HumidifiV2 = 3,
HumidifiV3 = 4,
Obric = 5,
Solfi = 6,
Tessera = 7,
Zerofi = 8,
Scorch = 6,
Solfi = 7,
Tessera = 8,
Zerofi = 9,
}

impl Dex {
pub const ALL: [Dex; 9] = [Dex::Alphaq, Dex::Aquifer, Dex::Bisonfi, Dex::HumidifiV2, Dex::HumidifiV3, Dex::Obric, Dex::Solfi, Dex::Tessera, Dex::Zerofi];
pub const ALL: [Dex; 10] = [
Dex::Alphaq,
Dex::Aquifer,
Dex::Bisonfi,
Dex::HumidifiV2,
Dex::HumidifiV3,
Dex::Obric,
Dex::Scorch,
Dex::Solfi,
Dex::Tessera,
Dex::Zerofi,
];

/// Number of remaining accounts per hop for swap_v1 (excludes shared payer).
#[inline(always)]
Expand All @@ -108,6 +129,7 @@ impl Dex {
Dex::Bisonfi => if a_to_b { 5 } else { 4 },
Dex::HumidifiV2 | Dex::HumidifiV3 => if a_to_b { 5 } else { 4 },
Dex::Obric => if a_to_b { 7 } else { 6 },
Dex::Scorch => 3,
Dex::Solfi => if a_to_b { 7 } else { 6 },
Dex::Tessera => if a_to_b { 6 } else { 5 },
Dex::Zerofi => 7,
Expand All @@ -117,22 +139,23 @@ impl Dex {
/// Map byte to Dex variant.
#[inline(always)]
pub fn from_u8(v: u8) -> Option<Self> {
if v <= 8 {
if v <= 9 {
Some(Self::ALL[v as usize])
} else {
None
}
}
}

const REM_ACCS_LEN_V1: [usize; 9] = [
const REM_ACCS_LEN_V1: [usize; 10] = [
alphaq::ACCS_LEN, // 0 Alphaq
aquifer::ACCS_LEN, // 1 Aquifer
bisonfi::ACCS_LEN, // 2 Bisonfi
humidifi::ACCS_LEN_V2V3, // 3 HumidifiV2
humidifi::ACCS_LEN_V2V3, // 4 HumidifiV3
obric::ACCS_LEN, // 5 Obric
solfi::ACCS_LEN, // 6 Solfi
tessera::ACCS_LEN, // 7 Tessera
zerofi::ACCS_LEN, // 8 Zerofi
scorch::ACCS_LEN, // 6 Scorch
solfi::ACCS_LEN, // 7 Solfi
tessera::ACCS_LEN, // 8 Tessera
zerofi::ACCS_LEN, // 9 Zerofi
];
1 change: 1 addition & 0 deletions src/ixs/swap_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ fn dispatch(payer: &AccountView, rem: &[AccountView], amount_in: u64, a_to_b: bo
Dex::Bisonfi => adapters::bisonfi_v1::swap_v1,
Dex::HumidifiV2 | Dex::HumidifiV3 => adapters::humidifi_v1::swap_v3,
Dex::Obric => adapters::obric_v2::swap_v1,
Dex::Scorch => adapters::scorch_v1::swap_v1,
Dex::Solfi => adapters::solfi_v2::swap_v1,
Dex::Tessera => adapters::tessera_v1::swap_v1,
Dex::Zerofi => adapters::zerofi_v1::swap_v1,
Expand Down
Loading