Skip to content

Commit

Permalink
Add Jupiter adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
emersonliuuu committed Dec 27, 2022
1 parent 7f4b5ab commit f854422
Show file tree
Hide file tree
Showing 6 changed files with 573 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Cargo.lock

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

23 changes: 23 additions & 0 deletions programs/adapter-jupiter/Cargo.toml
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"
2 changes: 2 additions & 0 deletions programs/adapter-jupiter/Xargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []
266 changes: 266 additions & 0 deletions programs/adapter-jupiter/src/lib.rs
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
// }
// }
Loading

0 comments on commit f854422

Please sign in to comment.