-
Notifications
You must be signed in to change notification settings - Fork 7
PROTO-409:Just Mint It extension #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ith-harvey
wants to merge
28
commits into
main
Choose a base branch
from
feat/JMI
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
e53c396
chore: sync hive
308b0af
chore: sync hive
8d91f94
initial draft of src changes
2403720
removed hive
d1fa412
split apart wrap into wrap_asset
2855498
fix: remove balance tracking, rename replace -> unwrap_asset
cd647ef
fix: original tests running
e2977e2
depreciating no-yield but still allowing for migration to jmi, tests …
68e4a30
ext_swap wrap n unwrap asset now both have whitelist protection
aab8a56
chore: added tests
9e226ff
Merge branch 'main' into feat/JMI
786ba8a
chore: assert on rounding test to confirm rounding works
6dc06e2
fix: underflow error semantic
ith-harvey 3af8f64
fix: reverted back to replace_asset_with_m to match EVM imp
ith-harvey 86518ff
fix: removed global_account seed requirement from asset_config
ith-harvey 33c941f
chore: added additional check that asset_mint != m_mint in replace_as…
ith-harvey 63c0e3c
fix: undo changes to ext_swap/wrap
ith-harvey a2f7f4f
fix: rename m_amount to m_principal and from_principal to ext_princip…
ith-harvey d2ab707
Update programs/m_ext/src/instructions/jmi/set_asset_cap.rs
ith-harvey 4e20932
chore: moved asset_mint not m_mint validation to accounts section
ith-harvey a06d5d4
fix: used generic tokenInterface combining transfer_tokens_from_progr…
ith-harvey 432404b
fix: removed pause since pause functionality already exists in whitel…
ith-harvey 691b18f
fix: added clearer relationship that JMI always requrires no-yield ye…
ith-harvey b008a84
fix: removed token backing assertion, already reverts with insufficie…
ith-harvey 5789e43
fix: removed unused error
ith-harvey 8f12e00
fix: added additional extension protections to set_cap
ith-harvey ce7c5da
feat: created separate replace_authorities which holds permissions fo…
ith-harvey f7f5dc0
fix: restrict interest bearing tokens as SPL assets
ith-harvey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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
This file contains hidden or 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 |
|---|---|---|
| @@ -1,11 +1,15 @@ | ||
| pub mod initialize; | ||
| pub mod replace_asset_with_m; | ||
| pub mod swap; | ||
| pub mod unwrap; | ||
| pub mod whitelist; | ||
| pub mod wrap; | ||
| pub mod wrap_asset; | ||
|
|
||
| pub use initialize::*; | ||
| pub use replace_asset_with_m::*; | ||
| pub use swap::*; | ||
| pub use unwrap::*; | ||
| pub use whitelist::*; | ||
| pub use wrap::*; | ||
| pub use wrap_asset::*; |
252 changes: 252 additions & 0 deletions
252
programs/ext_swap/src/instructions/replace_asset_with_m.rs
This file contains hidden or 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,252 @@ | ||
| use anchor_lang::prelude::*; | ||
| use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; | ||
| use m_ext::cpi::accounts::{ReplaceAssetWithM as ExtReplaceAssetWithM, Unwrap}; | ||
| use m_ext::state::{EXT_GLOBAL_SEED, MINT_AUTHORITY_SEED, M_VAULT_SEED}; | ||
|
|
||
| use crate::{ | ||
| errors::SwapError, | ||
| state::{SwapGlobal, GLOBAL_SEED, REPLACE_AUTHORITY_SEED}, | ||
| }; | ||
|
|
||
| #[derive(Accounts)] | ||
| pub struct ReplaceAssetWithM<'info> { | ||
| pub signer: Signer<'info>, | ||
|
|
||
| // Required if the fallback_replace_authority is not whitelisted on the extension | ||
| pub replace_authority: Option<Signer<'info>>, | ||
|
|
||
| /// CHECK: PDA used as replace authority for JMI extensions | ||
| #[account( | ||
| seeds = [REPLACE_AUTHORITY_SEED], | ||
| bump, | ||
| )] | ||
| pub fallback_replace_authority: AccountInfo<'info>, | ||
|
|
||
| /* | ||
| * Program globals | ||
| */ | ||
| #[account( | ||
| seeds = [GLOBAL_SEED], | ||
| bump = swap_global.bump, | ||
| )] | ||
| pub swap_global: Box<Account<'info, SwapGlobal>>, | ||
|
|
||
| /// Source extension global (for unwrap) | ||
| #[account( | ||
| mut, | ||
| seeds = [EXT_GLOBAL_SEED], | ||
| seeds::program = from_ext_program.key(), | ||
| bump, | ||
| )] | ||
| /// CHECK: CPI will validate the global account | ||
| pub from_global: AccountInfo<'info>, | ||
|
|
||
| /// JMI extension global (for replace_asset_with_m) | ||
| #[account( | ||
| mut, | ||
| seeds = [EXT_GLOBAL_SEED], | ||
| seeds::program = jmi_ext_program.key(), | ||
| bump, | ||
| )] | ||
| /// CHECK: CPI will validate the global account | ||
| pub jmi_global: AccountInfo<'info>, | ||
|
|
||
| /* | ||
| * Mints | ||
| */ | ||
| #[account(mut)] | ||
| /// Validated by unwrap on the extension program | ||
| pub from_mint: Box<InterfaceAccount<'info, Mint>>, | ||
| #[account(mint::token_program = m_token_program)] | ||
| pub m_mint: Box<InterfaceAccount<'info, Mint>>, | ||
| #[account(mint::token_program = asset_token_program)] | ||
| pub asset_mint: Box<InterfaceAccount<'info, Mint>>, | ||
|
|
||
| /* | ||
| * Asset config for JMI | ||
| */ | ||
| #[account(mut)] | ||
| /// CHECK: CPI will validate the asset config | ||
| pub asset_config: AccountInfo<'info>, | ||
|
|
||
| /* | ||
| * Token Accounts | ||
| */ | ||
| #[account( | ||
| mut, | ||
| token::mint = from_mint, | ||
| token::token_program = from_token_program, | ||
| )] | ||
| pub from_token_account: Box<InterfaceAccount<'info, TokenAccount>>, | ||
| #[account( | ||
| mut, | ||
| token::mint = asset_mint, | ||
| token::token_program = asset_token_program, | ||
| )] | ||
| pub to_asset_token_account: Box<InterfaceAccount<'info, TokenAccount>>, | ||
| #[account( | ||
| mut, | ||
| associated_token::mint = m_mint, | ||
| associated_token::authority = swap_global, | ||
| associated_token::token_program = m_token_program, | ||
| )] | ||
| pub swap_m_account: Box<InterfaceAccount<'info, TokenAccount>>, | ||
|
|
||
| /* | ||
| * Authorities & Vaults for source extension (unwrap) | ||
| */ | ||
| #[account( | ||
| seeds = [M_VAULT_SEED], | ||
| seeds::program = from_ext_program.key(), | ||
| bump, | ||
| )] | ||
| /// CHECK: account does not hold data | ||
| pub from_m_vault_auth: AccountInfo<'info>, | ||
| #[account( | ||
| seeds = [MINT_AUTHORITY_SEED], | ||
| seeds::program = from_ext_program.key(), | ||
| bump, | ||
| )] | ||
| /// CHECK: account does not hold data | ||
| pub from_mint_authority: AccountInfo<'info>, | ||
| #[account( | ||
| mut, | ||
| associated_token::mint = m_mint, | ||
| associated_token::authority = from_m_vault_auth, | ||
| associated_token::token_program = m_token_program, | ||
| )] | ||
| pub from_m_vault: Box<InterfaceAccount<'info, TokenAccount>>, | ||
|
|
||
| /* | ||
| * Vaults for JMI extension (replace_asset_with_m) | ||
| */ | ||
| #[account( | ||
| seeds = [M_VAULT_SEED], | ||
| seeds::program = jmi_ext_program.key(), | ||
| bump, | ||
| )] | ||
| /// CHECK: account does not hold data | ||
| pub jmi_m_vault_auth: AccountInfo<'info>, | ||
| #[account( | ||
| mut, | ||
| associated_token::mint = m_mint, | ||
| associated_token::authority = jmi_m_vault_auth, | ||
| associated_token::token_program = m_token_program, | ||
| )] | ||
| pub jmi_m_vault: Box<InterfaceAccount<'info, TokenAccount>>, | ||
| #[account( | ||
| mut, | ||
| associated_token::mint = asset_mint, | ||
| associated_token::authority = jmi_m_vault_auth, | ||
| associated_token::token_program = asset_token_program, | ||
| )] | ||
| pub jmi_asset_vault: Box<InterfaceAccount<'info, TokenAccount>>, | ||
|
|
||
| /* | ||
| * Token Programs | ||
| */ | ||
| pub from_token_program: Interface<'info, TokenInterface>, | ||
| pub asset_token_program: Interface<'info, TokenInterface>, | ||
| pub m_token_program: Interface<'info, TokenInterface>, | ||
|
|
||
| /* | ||
| * Programs | ||
| */ | ||
| /// CHECK: checked against whitelisted extensions | ||
| pub from_ext_program: UncheckedAccount<'info>, | ||
|
Oighty marked this conversation as resolved.
|
||
| /// CHECK: checked against whitelisted extensions | ||
| pub jmi_ext_program: UncheckedAccount<'info>, | ||
| pub system_program: Program<'info, System>, | ||
| } | ||
|
|
||
| impl<'info> ReplaceAssetWithM<'info> { | ||
| fn validate(&self, ext_principal: u64) -> Result<()> { | ||
| // Validate both extensions are whitelisted | ||
| for ext_program in [&self.from_ext_program, &self.jmi_ext_program] { | ||
| if !self.swap_global.is_extension_whitelisted(ext_program.key) { | ||
| return err!(SwapError::InvalidExtension); | ||
| } | ||
| } | ||
|
|
||
| if ext_principal == 0 { | ||
| return err!(SwapError::InvalidAmount); | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| #[access_control(ctx.accounts.validate(ext_principal))] | ||
| pub fn handler(ctx: Context<'_, '_, '_, 'info, Self>, ext_principal: u64) -> Result<()> { | ||
| let m_pre_balance = ctx.accounts.swap_m_account.amount; | ||
|
|
||
| // Set replace authority as authority if none provided | ||
| let replace_authority = match &ctx.accounts.replace_authority { | ||
| Some(auth) => auth.to_account_info(), | ||
| None => ctx.accounts.fallback_replace_authority.to_account_info(), | ||
| }; | ||
|
|
||
| // 1. Unwrap source extension → M (to swap_m_account) | ||
| m_ext::cpi::unwrap( | ||
| CpiContext::new_with_signer( | ||
| ctx.accounts.from_ext_program.to_account_info(), | ||
| Unwrap { | ||
| token_authority: ctx.accounts.signer.to_account_info(), | ||
| unwrap_authority: Some(replace_authority.clone()), | ||
| m_mint: ctx.accounts.m_mint.to_account_info(), | ||
| ext_mint: ctx.accounts.from_mint.to_account_info(), | ||
| global_account: ctx.accounts.from_global.to_account_info(), | ||
| m_vault: ctx.accounts.from_m_vault_auth.to_account_info(), | ||
| ext_mint_authority: ctx.accounts.from_mint_authority.to_account_info(), | ||
| to_m_token_account: ctx.accounts.swap_m_account.to_account_info(), | ||
| vault_m_token_account: ctx.accounts.from_m_vault.to_account_info(), | ||
| from_ext_token_account: ctx.accounts.from_token_account.to_account_info(), | ||
| m_token_program: ctx.accounts.m_token_program.to_account_info(), | ||
| ext_token_program: ctx.accounts.from_token_program.to_account_info(), | ||
| }, | ||
| &[&[ | ||
| REPLACE_AUTHORITY_SEED, | ||
| &[ctx.bumps.fallback_replace_authority], | ||
| ]], | ||
| ), | ||
| ext_principal, | ||
| )?; | ||
|
|
||
| // 2. Calculate M received | ||
| ctx.accounts.swap_m_account.reload()?; | ||
| let m_principal = ctx.accounts.swap_m_account.amount - m_pre_balance; | ||
|
|
||
| // 3. Call JMI replace_asset_with_m (swap_global signs for token transfer, replace_authority for authorization) | ||
| m_ext::cpi::replace_asset_with_m( | ||
| CpiContext::new_with_signer( | ||
| ctx.accounts.jmi_ext_program.to_account_info(), | ||
| ExtReplaceAssetWithM { | ||
| token_authority: ctx.accounts.swap_global.to_account_info(), | ||
| replace_authority: Some(replace_authority), | ||
| m_mint: ctx.accounts.m_mint.to_account_info(), | ||
| asset_mint: ctx.accounts.asset_mint.to_account_info(), | ||
| global_account: ctx.accounts.jmi_global.to_account_info(), | ||
| asset_config: ctx.accounts.asset_config.to_account_info(), | ||
| m_vault: ctx.accounts.jmi_m_vault_auth.to_account_info(), | ||
| from_m_token_account: ctx.accounts.swap_m_account.to_account_info(), | ||
| vault_m_token_account: ctx.accounts.jmi_m_vault.to_account_info(), | ||
| vault_asset_token_account: ctx.accounts.jmi_asset_vault.to_account_info(), | ||
| to_asset_token_account: ctx.accounts.to_asset_token_account.to_account_info(), | ||
| m_token_program: ctx.accounts.m_token_program.to_account_info(), | ||
| asset_token_program: ctx.accounts.asset_token_program.to_account_info(), | ||
| }, | ||
| &[ | ||
| &[ | ||
| REPLACE_AUTHORITY_SEED, | ||
| &[ctx.bumps.fallback_replace_authority], | ||
| ], | ||
| &[GLOBAL_SEED, &[ctx.accounts.swap_global.bump]], | ||
| ], | ||
| ), | ||
| m_principal, | ||
| )?; | ||
|
|
||
| msg!("{} ext_principal -> {} m_principal -> asset", ext_principal, m_principal); | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.