-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7f4b5ab
commit f854422
Showing
6 changed files
with
573 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[package] | ||
name = "adapter-jupiter" | ||
version = "0.1.0" | ||
description = "Created with Anchor" | ||
edition = "2021" | ||
|
||
[lib] | ||
crate-type = ["cdylib", "lib"] | ||
name = "adapter_jupiter" | ||
|
||
[features] | ||
no-entrypoint = [] | ||
no-idl = [] | ||
no-log-ix-name = [] | ||
cpi = ["no-entrypoint"] | ||
default = [] | ||
|
||
[profile.release] | ||
overflow-checks = true | ||
|
||
[dependencies] | ||
anchor-lang = "0.24.2" | ||
anchor-spl = "0.24.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[target.bpfel-unknown-unknown.dependencies.std] | ||
features = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
use anchor_lang::prelude::*; | ||
use anchor_lang::solana_program::{ | ||
hash::hash, | ||
instruction::{AccountMeta, Instruction}, | ||
program::invoke, | ||
pubkey::Pubkey, | ||
}; | ||
use anchor_spl::token::TokenAccount; | ||
|
||
declare_id!("ADPT8iF4A7BSUWQ8AsVwmcod2suFzA4bpYpJj7kUWK3E"); | ||
|
||
#[program] | ||
pub mod adapter_jupiter { | ||
use super::*; | ||
|
||
pub fn swap(ctx: Context<Action>, input: Vec<u8>) -> Result<()> { | ||
let discriminator: [u8; 8] = sighash("global", "route"); | ||
|
||
// Use remaining accounts | ||
let mut dest_token_account_and_balance = | ||
load_token_account_and_balance(ctx.remaining_accounts, 2); | ||
|
||
// Get Input | ||
let mut input_bytes: &[u8] = &input[..]; | ||
let input_struct = SwapInputWrapper::deserialize(&mut input_bytes)?; | ||
msg!("Input: {:?}", input_struct); | ||
|
||
let mut last_index: usize = 13; | ||
for index in 0..input_struct.swap_config.len() { | ||
if input_struct.swap_config[index] == 255 { | ||
last_index = index; | ||
} | ||
} | ||
|
||
let swap_accounts = load_remaining_accounts(ctx.remaining_accounts, None); | ||
|
||
let mut swap_data = vec![]; | ||
swap_data.append(&mut discriminator.try_to_vec()?); | ||
swap_data.append(&mut input_struct.swap_config[..last_index].try_to_vec()?); | ||
swap_data.append(&mut input_struct.in_amount.try_to_vec()?); | ||
swap_data.append(&mut input_struct.out_amount.try_to_vec()?); | ||
swap_data.append(&mut input_struct.slippage_bps.try_to_vec()?); | ||
swap_data.append(&mut input_struct.platform_fee_bps.try_to_vec()?); | ||
|
||
let ix = Instruction { | ||
program_id: ctx.accounts.base_program_id.key(), | ||
accounts: swap_accounts, | ||
data: swap_data, | ||
}; | ||
|
||
invoke(&ix, ctx.remaining_accounts)?; | ||
|
||
// Return Result | ||
let swap_result = SwapOutputWrapper { | ||
swap_out_amount: dest_token_account_and_balance.get_balance_change(), | ||
..Default::default() | ||
}; | ||
let mut buffer: Vec<u8> = Vec::new(); | ||
swap_result.serialize(&mut buffer).unwrap(); | ||
|
||
anchor_lang::solana_program::program::set_return_data(&buffer); | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[derive(Accounts)] | ||
pub struct Action<'info> { | ||
pub gateway_authority: Signer<'info>, | ||
/// CHECK: Safe | ||
pub gateway_state_info: AccountInfo<'info>, | ||
/// CHECK: Safe | ||
pub base_program_id: AccountInfo<'info>, | ||
} | ||
|
||
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug, Default)] | ||
pub struct SwapInputWrapper { | ||
pub in_amount: u64, | ||
pub out_amount: u64, | ||
pub slippage_bps: u16, | ||
pub platform_fee_bps: u8, | ||
pub swap_config: [u8; 13], | ||
} | ||
|
||
// OutputWrapper needs to take up all the space of 32 bytes | ||
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug, Default)] | ||
pub struct SwapOutputWrapper { | ||
pub swap_out_amount: u64, | ||
pub dummy_2: u64, | ||
pub dummy_3: u64, | ||
pub dummy_4: u64, | ||
} | ||
|
||
pub type SwapOutputTuple = (u64, u64, u64, u64); | ||
|
||
impl From<SwapOutputWrapper> for SwapOutputTuple { | ||
fn from(result: SwapOutputWrapper) -> SwapOutputTuple { | ||
let SwapOutputWrapper { | ||
swap_out_amount, | ||
dummy_2, | ||
dummy_3, | ||
dummy_4, | ||
} = result; | ||
(swap_out_amount, dummy_2, dummy_3, dummy_4) | ||
} | ||
} | ||
|
||
pub fn sighash(namespace: &str, name: &str) -> [u8; 8] { | ||
let preimage = format!("{}:{}", namespace, name); | ||
let mut sighash = [0u8; 8]; | ||
|
||
sighash.copy_from_slice(&hash(preimage.as_bytes()).to_bytes()[..8]); | ||
sighash | ||
} | ||
|
||
pub fn load_token_account_and_balance<'info>( | ||
remaining_accounts: &[AccountInfo<'info>], | ||
account_index: usize, | ||
) -> TokenAccountAndBalance<'info> { | ||
let token_account_info = &remaining_accounts[account_index]; | ||
let token_account = Account::<TokenAccount>::try_from(token_account_info).unwrap(); | ||
let balance_before = token_account.amount.clone(); | ||
return TokenAccountAndBalance { | ||
token_accout: token_account, | ||
balance_before: balance_before, | ||
}; | ||
} | ||
|
||
pub struct TokenAccountAndBalance<'info> { | ||
token_accout: Account<'info, TokenAccount>, | ||
balance_before: u64, | ||
} | ||
|
||
impl<'info> TokenAccountAndBalance<'info> { | ||
pub fn get_balance_change(&mut self) -> u64 { | ||
self.token_accout.reload().unwrap(); | ||
let balance_before = self.balance_before; | ||
let balance_after = self.token_accout.amount; | ||
if balance_after > balance_before { | ||
balance_after.checked_sub(balance_before).unwrap() | ||
} else if balance_after == balance_before { | ||
0_u64 | ||
} else { | ||
balance_before.checked_sub(balance_after).unwrap() | ||
} | ||
} | ||
} | ||
|
||
pub fn load_remaining_accounts<'info>( | ||
remaining_accounts: &[AccountInfo<'info>], | ||
index_array: Option<Vec<usize>>, | ||
) -> Vec<AccountMeta> { | ||
let mut accounts: Vec<AccountMeta> = vec![]; | ||
match index_array { | ||
Some(index_array) => { | ||
for index in index_array.iter() { | ||
if remaining_accounts[*index].is_writable { | ||
accounts.push(AccountMeta::new( | ||
remaining_accounts[*index].key(), | ||
remaining_accounts[*index].is_signer, | ||
)) | ||
} else { | ||
accounts.push(AccountMeta::new_readonly( | ||
remaining_accounts[*index].key(), | ||
remaining_accounts[*index].is_signer, | ||
)) | ||
} | ||
} | ||
} | ||
None => { | ||
for account in remaining_accounts.iter() { | ||
if account.is_writable { | ||
accounts.push(AccountMeta::new(account.key(), account.is_signer)) | ||
} else { | ||
accounts.push(AccountMeta::new_readonly(account.key(), account.is_signer)) | ||
} | ||
} | ||
} | ||
} | ||
|
||
return accounts; | ||
} | ||
|
||
// pub enum SwapLeg { | ||
// Chain{ | ||
// swap_legs: Vec<SwapLegDeeper> | ||
// }, | ||
// Split{ | ||
// split_legs: Vec<SplitLeg> | ||
// }, | ||
// Swap{ | ||
// swap: Swap | ||
// } | ||
// } | ||
|
||
// pub enum SwapLegDeeper { | ||
// Chain{ | ||
// swap_legs: Vec<SwapLegSwap> | ||
// }, | ||
// Split{ | ||
// split_legs: Vec<SplitLegDeeper> | ||
// }, | ||
// Swap{ | ||
// swap: Swap | ||
// } | ||
// } | ||
|
||
// pub enum SwapLegSwap{ | ||
// PlaceholderOne, | ||
// PlaceholderTwo, | ||
// Swap{ | ||
// swap: Swap | ||
// } | ||
// } | ||
|
||
// pub struct SplitLegDeeper { | ||
// pub percent: u8, | ||
// pub swap_leg: SwapLegSwap | ||
// } | ||
|
||
// pub struct SplitLeg { | ||
// pub percent: u8, | ||
// pub swap_leg: SwapLegDeeper | ||
// } | ||
|
||
// pub enum Side { | ||
// Bid, | ||
// Ask | ||
// } | ||
|
||
// pub enum Swap { | ||
// Saber, | ||
// SaberAddDecimalsDeposit, | ||
// SaberAddDecimalsWithdraw, | ||
// TokenSwap, | ||
// Sencha, | ||
// Step, | ||
// Cropper, | ||
// Raydium, | ||
// Crema, | ||
// Lifinity, | ||
// Mercurial, | ||
// Cykura, | ||
// Serum{ | ||
// side: Side | ||
// }, | ||
// MarinadeDeposit, | ||
// MarinadeUnstake, | ||
// Aldrin{ | ||
// side: Side | ||
// }, | ||
// AldrinV2{ | ||
// side: Side | ||
// }, | ||
// Whirlpool{ | ||
// a_to_b: bool | ||
// }, | ||
// Invariant{ | ||
// x_to_y: bool | ||
// }, | ||
// Meteora, | ||
// GooseFX, | ||
// DeltaFi{ | ||
// stable: bool | ||
// } | ||
// } |
Oops, something went wrong.