Skip to content

Commit

Permalink
[mmm] T22 extension MMM support (#87)
Browse files Browse the repository at this point in the history
* [mmm] initial commit

* [mmm] deposit sell for T22 extension

* fmt

* add metadata check

* remove mut

* add entrypoints

* merge check fn

* add integration test

* integration test fixes

* add multiple unit tests

* add fulfill sell + buy and integration tests

* fmt

* minor refactor

* add ext_withdraw_sell

* withdraw from m2 first

* address comment

* add test for shared escrow to trigger pool close/remain_open

* fix test fn import

* address comments

* update
test

* add todo

* change name

* fix test

* add comment for lp_fee_bp
  • Loading branch information
solonk8 authored Mar 19, 2024
1 parent e8c5662 commit 5fd1531
Show file tree
Hide file tree
Showing 26 changed files with 4,123 additions and 384 deletions.
4 changes: 4 additions & 0 deletions Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ address = "ocp4vWUzA2z2XMYJ3QhM9vWdyoyoQwAFJhRdVTbvo9E" # ocp: open_creator_prot
[[test.validator.clone]]
address = "6Huqrb4xxmmNA4NufYdgpmspoLmjXFd3qEfteCddLgSz" # ocp: policy (allow all)

[[test.genesis]]
address = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
program = "./tests/deps/spl_token_2022.so"

[programs.localnet]
mmm = "mmm3XBJg5gk8XJxEKBvdgptZz6SgK4tXvn36sodowMc"

Expand Down
2 changes: 2 additions & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"@metaplex-foundation/umi-bundle-tests": "^0.8.2",
"@metaplex-foundation/umi-web3js-adapters": "^0.8.2",
"@project-serum/anchor": "^0.26.0",
"@solana/spl-token": "^0.3.5",
"@solana/spl-token": "^0.4.1",
"@solana/spl-token-group": "^0.0.1",
"@solana/web3.js": "^1.65.0",
"borsh": "^0.7.0",
"old-mpl-token-metadata": "npm:@metaplex-foundation/[email protected]"
Expand Down
79 changes: 75 additions & 4 deletions pnpm-lock.yaml

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

2 changes: 2 additions & 0 deletions programs/mmm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ community-managed-token = { version = "0.3.1", features = ["no-entrypoint"] }
mpl-token-metadata = { version = "4.0.0" }
open_creator_protocol = { version = "0.4.2", features = ["cpi"] }
solana-program = "~1.17"
spl-token-group-interface = "0.1.0"
spl-token-metadata-interface = "0.2.0"
spl-token = { version = "4.0.0", features = ["no-entrypoint"] }
spl-associated-token-account = { version = "2.2.0", features = [
"no-entrypoint",
Expand Down
4 changes: 4 additions & 0 deletions programs/mmm/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,8 @@ pub enum MMMErrorCode {
UnexpectedMetadataUri, // 0x178c
#[msg("Invalid remaining accounts")]
InvalidRemainingAccounts, // 0x178d
#[msg("Invalid token metadata extensions")]
InvalidTokenMetadataExtension, // 0x178e
#[msg("Invalid token member extensions")]
InvalidTokenMemberExtension, // 0x178f
}
134 changes: 134 additions & 0 deletions programs/mmm/src/instructions/ext_vanilla/ext_deposit_sell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use anchor_lang::{prelude::*, AnchorDeserialize};
use anchor_spl::{
associated_token::AssociatedToken,
token_interface::{Mint, TokenAccount, TokenInterface},
};
use solana_program::program::invoke;
use spl_token_2022::onchain::invoke_transfer_checked;

use crate::{
constants::*,
errors::MMMErrorCode,
state::{Pool, SellState},
util::{check_allowlists_for_mint_ext, log_pool},
DepositSellArgs,
};

#[derive(Accounts)]
#[instruction(args: DepositSellArgs)]
pub struct ExtDepositeSell<'info> {
#[account(mut)]
pub owner: Signer<'info>,
pub cosigner: Signer<'info>,
#[account(
mut,
seeds = [POOL_PREFIX.as_bytes(), owner.key().as_ref(), pool.uuid.as_ref()],
has_one = owner @ MMMErrorCode::InvalidOwner,
has_one = cosigner @ MMMErrorCode::InvalidCosigner,
bump
)]
pub pool: Box<Account<'info, Pool>>,
#[account(
mint::token_program = token_program,
constraint = asset_mint.supply == 1 && asset_mint.decimals == 0 @ MMMErrorCode::InvalidTokenMint,
)]
pub asset_mint: Box<InterfaceAccount<'info, Mint>>,
#[account(
mut,
associated_token::mint = asset_mint,
associated_token::authority = owner,
associated_token::token_program = token_program,
)]
pub asset_token_account: Box<InterfaceAccount<'info, TokenAccount>>,
#[account(
init_if_needed,
payer = owner,
associated_token::mint = asset_mint,
associated_token::authority = pool,
associated_token::token_program = token_program,
)]
pub sellside_escrow_token_account: Box<InterfaceAccount<'info, TokenAccount>>,
#[account(
init_if_needed,
payer = owner,
seeds = [
SELL_STATE_PREFIX.as_bytes(),
pool.key().as_ref(),
asset_mint.key().as_ref(),
],
space = SellState::LEN,
bump
)]
pub sell_state: Account<'info, SellState>,
pub system_program: Program<'info, System>,
pub token_program: Interface<'info, TokenInterface>,
pub associated_token_program: Program<'info, AssociatedToken>,
}

pub fn handler<'info>(
ctx: Context<'_, '_, '_, 'info, ExtDepositeSell<'info>>,
args: DepositSellArgs,
) -> Result<()> {
let owner = &ctx.accounts.owner;
let asset_token_account = &ctx.accounts.asset_token_account;
let asset_mint = &ctx.accounts.asset_mint;
let sellside_escrow_token_account = &ctx.accounts.sellside_escrow_token_account;
let token_program = &ctx.accounts.token_program;
let pool = &mut ctx.accounts.pool;
let sell_state = &mut ctx.accounts.sell_state;

if pool.using_shared_escrow() {
return Err(MMMErrorCode::InvalidAccountState.into());
}

check_allowlists_for_mint_ext(
&pool.allowlists,
&asset_mint.to_account_info(),
args.allowlist_aux,
)?;

invoke_transfer_checked(
token_program.key,
asset_token_account.to_account_info(),
asset_mint.to_account_info(),
sellside_escrow_token_account.to_account_info(),
owner.to_account_info(),
ctx.remaining_accounts,
args.asset_amount,
0,
&[],
)?;

if asset_token_account.amount == args.asset_amount {
invoke(
&spl_token_2022::instruction::close_account(
token_program.key,
&asset_token_account.key(),
&owner.key(),
&owner.key(),
&[],
)?,
&[
asset_token_account.to_account_info(),
owner.to_account_info(),
],
)?;
}

pool.sellside_asset_amount = pool
.sellside_asset_amount
.checked_add(args.asset_amount)
.ok_or(MMMErrorCode::NumericOverflow)?;

sell_state.pool = pool.key();
sell_state.pool_owner = owner.key();
sell_state.asset_mint = asset_mint.key();
sell_state.cosigner_annotation = pool.cosigner_annotation;
sell_state.asset_amount = sell_state
.asset_amount
.checked_add(args.asset_amount)
.ok_or(MMMErrorCode::NumericOverflow)?;
log_pool("post_ext_deposit_sell", pool)?;

Ok(())
}
Loading

0 comments on commit 5fd1531

Please sign in to comment.