Skip to content
This repository was archived by the owner on May 29, 2024. It is now read-only.
Open
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
23 changes: 11 additions & 12 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
{
"cSpell.words": [
"bocchi",
"Hitori",
"Ikuyo",
"Jimii",
"lamports",
"soundwork"
],
"rust-analyzer.linkedProjects": [
"programs/soundwork-list/Cargo.toml",
]
}
"cSpell.words": [
"bocchi",
"Delist",
"Hitori",
"Ikuyo",
"Jimii",
"lamports",
"soundwork"
],
"rust-analyzer.linkedProjects": ["programs/soundwork-list/Cargo.toml"]
}
24 changes: 24 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"dependencies": {
"@coral-xyz/anchor": "^0.28.0",
"@metaplex-foundation/mpl-token-metadata": "^3.1.0",
"@solana/spl-account-compression": "^0.2.0",
"@solana/spl-token": "^0.3.8"
},
"devDependencies": {
Expand Down
2 changes: 2 additions & 0 deletions programs/soundwork-bid/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use anchor_lang::prelude::*;
#[cfg(not(feature = "no-entrypoint"))]
use solana_security_txt::security_txt;

pub mod instructions;
pub mod state;
Expand Down
1 change: 1 addition & 0 deletions programs/soundwork-list/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ default = []
[dependencies]
anchor-lang = { version = "0.29.0", features = ["init-if-needed"] }
anchor-spl = { version = "0.29.0", features = ["metadata"] }
mpl-bubblegum = "1.2.0"
mpl-token-metadata = "4.0.0"
serde = { version = "1.0", optional = true }
solana-security-txt = "1.1"
45 changes: 24 additions & 21 deletions programs/soundwork-list/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
use anchor_lang::{
prelude::{Account, AccountInfo, CpiContext, Program, Result},
solana_program::pubkey::Pubkey,
system_program::{self, System, Transfer as SolanaTransfer},
ToAccountInfo,
};
use anchor_spl::token::{
self, ApproveChecked, Mint, Token, TransferChecked as TokenTransferChecked,
};
use anchor_spl::token::{self, Mint, Token, TransferChecked as TokenTransferChecked};

/// delegate authority over NFT to asset manager
pub fn delegate_nft<'a>(
authority: AccountInfo<'a>,
delegate: AccountInfo<'a>,
to: AccountInfo<'a>,
mint: Account<'a, Mint>,
token_program: Program<'a, Token>,
) -> Result<()> {
let cpi_accounts = ApproveChecked {
to,
mint: mint.to_account_info(),
delegate,
authority,
};
let cpi_program = token_program.to_account_info();
let cpi_context = CpiContext::new(cpi_program, cpi_accounts);
#[derive(Clone)]
pub struct MplBubblegum;

token::approve_checked(cpi_context, 1, 0)?;
impl anchor_lang::Id for MplBubblegum {
fn id() -> Pubkey {
mpl_bubblegum::ID
}
}

Ok(())
#[derive(Clone)]
pub struct Noop;

impl anchor_lang::Id for Noop {
fn id() -> Pubkey {
mpl_bubblegum::programs::SPL_NOOP_ID
}
}

pub struct SplAccountCompression;

impl anchor_lang::Id for SplAccountCompression {
fn id() -> Pubkey {
mpl_bubblegum::programs::SPL_ACCOUNT_COMPRESSION_ID
}
}

// todo (Jimii) use references for the accounts
Expand Down
95 changes: 95 additions & 0 deletions programs/soundwork-list/src/instructions/delist_compressed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use anchor_lang::prelude::*;
use mpl_bubblegum::instructions::TransferCpiBuilder;

use crate::{
helpers::{MplBubblegum, Noop, SplAccountCompression},
state::listing::{AssetManagerV1, ListingDataCompressed},
};

#[derive(Accounts)]
#[instruction(params: DelistCompressedParams)]
pub struct DelistCompressed<'info> {
#[account(mut)]
pub authority: Signer<'info>,

/// CHECK: not really an account but the asset id
pub asset_id: UncheckedAccount<'info>, //,

/// CHECK: okay
pub tree_config: AccountInfo<'info>,

/// CHECK: okay
pub merkle_tree: AccountInfo<'info>,

// expecting this to already be initialized
#[account(mut)]
pub asset_manager: Account<'info, AssetManagerV1>,

#[account(
init,
payer = authority,
space = ListingDataCompressed::LEN,
seeds = [asset_id.key().as_ref(), "ryo".as_bytes()],
bump
)]
pub listing_data: Account<'info, ListingDataCompressed>,

pub bubblegum_program: Program<'info, MplBubblegum>,
pub compression_program: Program<'info, SplAccountCompression>,
pub log_wrapper: Program<'info, Noop>,
pub system_program: Program<'info, System>,
}

#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct DelistCompressedParams {
root: [u8; 32],
data_hash: [u8; 32],
creator_hash: [u8; 32],
nonce: u64,
index: u32,
}

impl DelistCompressed<'_> {
pub fn validate(&self) -> Result<()> {
Ok(())
}

/// creates a listing
#[access_control(ctx.accounts.validate())]
pub fn delist_compressed(
ctx: Context<DelistCompressed>,
params: DelistCompressedParams,
) -> Result<()> {
// signer seeds
let (_, bump) = Pubkey::find_program_address(&[b"soundwork".as_ref()], ctx.program_id);
let asset_manager_seeds = &[b"soundwork".as_ref(), &[bump]];
let asset_manager_signer = &[&asset_manager_seeds[..]];

let DelistCompressedParams {
root,
data_hash,
creator_hash,
nonce,
index,
} = params;

// transfer the compressed NFT back to owner
TransferCpiBuilder::new(&ctx.accounts.bubblegum_program.to_account_info())
.tree_config(&ctx.accounts.tree_config)
.leaf_owner(&ctx.accounts.asset_manager.to_account_info(), true)
// .leaf_delegate(leaf_delegate, as_signer) // skip me
.new_leaf_owner(&ctx.accounts.authority)
.merkle_tree(&ctx.accounts.merkle_tree)
.log_wrapper(&ctx.accounts.log_wrapper)
.compression_program(&ctx.accounts.compression_program)
.system_program(&ctx.accounts.system_program)
.root(root)
.data_hash(data_hash)
.creator_hash(creator_hash)
.nonce(nonce)
.index(index)
.invoke_signed(asset_manager_signer)?;

Ok(())
}
}
101 changes: 101 additions & 0 deletions programs/soundwork-list/src/instructions/list_compressed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use anchor_lang::prelude::*;
use mpl_bubblegum::instructions::TransferCpiBuilder;

use crate::{
helpers::{MplBubblegum, Noop, SplAccountCompression},
state::listing::{AssetManagerV1, ListingDataCompressed},
};

#[derive(Accounts)]
#[instruction(params: ListCompressedParams)]
pub struct ListCompressed<'info> {
#[account(mut)]
pub authority: Signer<'info>,

/// CHECK: not really an account but the asset id
pub asset_id: UncheckedAccount<'info>, //,

/// CHECK: okay
pub tree_config: AccountInfo<'info>,

/// CHECK: okay
pub merkle_tree: AccountInfo<'info>,

// expecting this to already be initialized
#[account(mut)]
pub asset_manager: Account<'info, AssetManagerV1>,

#[account(
init,
payer = authority,
space = ListingDataCompressed::LEN,
seeds = [asset_id.key().as_ref(), "ryo".as_bytes()],
bump
)]
pub listing_data: Account<'info, ListingDataCompressed>,

pub bubblegum_program: Program<'info, MplBubblegum>,
pub compression_program: Program<'info, SplAccountCompression>,
pub log_wrapper: Program<'info, Noop>,
pub system_program: Program<'info, System>,
}

#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct ListCompressedParams {
lamports: u64,
root: [u8; 32],
data_hash: [u8; 32],
creator_hash: [u8; 32],
nonce: u64,
index: u32,
}

impl ListCompressed<'_> {
pub fn validate(&self) -> Result<()> {
Ok(())
}

/// creates a listing
#[access_control(ctx.accounts.validate())]
pub fn list_compressed(
ctx: Context<ListCompressed>,
params: ListCompressedParams,
) -> Result<()> {
// insert data into listing data account
let listing_data_acc = &mut ctx.accounts.listing_data;

let ListCompressedParams {
root,
data_hash,
creator_hash,
nonce,
index,
..
} = params;

**listing_data_acc = ListingDataCompressed::new(
params.lamports,
ctx.accounts.authority.key(),
ctx.accounts.asset_id.key(),
);

// transfer the compressed NFT to our asset manager
TransferCpiBuilder::new(&ctx.accounts.bubblegum_program.to_account_info())
.tree_config(&ctx.accounts.tree_config)
.leaf_owner(&ctx.accounts.authority, true)
// .leaf_delegate(leaf_delegate, as_signer) // skip me
.new_leaf_owner(&ctx.accounts.asset_manager.to_account_info())
.merkle_tree(&ctx.accounts.merkle_tree)
.log_wrapper(&ctx.accounts.log_wrapper)
.compression_program(&ctx.accounts.compression_program)
.system_program(&ctx.accounts.system_program)
.root(root)
.data_hash(data_hash)
.creator_hash(creator_hash)
.nonce(nonce)
.index(index)
.invoke()?;

Ok(())
}
}
4 changes: 4 additions & 0 deletions programs/soundwork-list/src/instructions/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
pub mod buy_listing;
pub mod create_listing;
pub mod delete_listing;
pub mod delist_compressed;
pub mod deposit_sol;
pub mod edit_listing;
pub mod list_compressed;
pub mod withdraw_sol;

pub use buy_listing::*;
pub use create_listing::*;
pub use delete_listing::*;
pub use delist_compressed::*;
pub use deposit_sol::*;
pub use edit_listing::*;
pub use list_compressed::*;
pub use withdraw_sol::*;
Loading