Skip to content

Commit

Permalink
Update asset interface (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
febo authored Apr 10, 2024
1 parent ec4a3dd commit c21dadc
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 45 deletions.
11 changes: 10 additions & 1 deletion idls/nifty_asset_interface.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.1.0",
"version": "0.2.1",
"name": "nifty_asset_interface",
"instructions": [
{
Expand Down Expand Up @@ -109,6 +109,15 @@
"Asset account of the group"
]
},
{
"name": "groupAuthority",
"isMut": false,
"isSigner": true,
"isOptional": true,
"docs": [
"The delegate authority for minting assets into a group"
]
},
{
"name": "payer",
"isMut": true,
Expand Down
74 changes: 67 additions & 7 deletions programs/asset/interface/src/generated/instructions/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ pub struct Create {
pub owner: solana_program::pubkey::Pubkey,
/// Asset account of the group
pub group: Option<solana_program::pubkey::Pubkey>,
/// The delegate authority for minting assets into a group
pub group_authority: Option<solana_program::pubkey::Pubkey>,
/// The account paying for the storage fees
pub payer: Option<solana_program::pubkey::Pubkey>,
/// The system program
Expand All @@ -39,7 +41,7 @@ impl Create {
args: CreateInstructionArgs,
remaining_accounts: &[solana_program::instruction::AccountMeta],
) -> solana_program::instruction::Instruction {
let mut accounts = Vec::with_capacity(6 + remaining_accounts.len());
let mut accounts = Vec::with_capacity(7 + remaining_accounts.len());
accounts.push(solana_program::instruction::AccountMeta::new(
self.asset, true,
));
Expand All @@ -58,6 +60,17 @@ impl Create {
false,
));
}
if let Some(group_authority) = self.group_authority {
accounts.push(solana_program::instruction::AccountMeta::new_readonly(
group_authority,
true,
));
} else {
accounts.push(solana_program::instruction::AccountMeta::new_readonly(
crate::INTERFACE_ID,
false,
));
}
if let Some(payer) = self.payer {
accounts.push(solana_program::instruction::AccountMeta::new(payer, true));
} else {
Expand Down Expand Up @@ -118,14 +131,16 @@ pub struct CreateInstructionArgs {
/// 1. `[signer]` authority
/// 2. `[]` owner
/// 3. `[writable, optional]` group
/// 4. `[writable, signer, optional]` payer
/// 5. `[optional]` system_program
/// 4. `[signer, optional]` group_authority
/// 5. `[writable, signer, optional]` payer
/// 6. `[optional]` system_program
#[derive(Default)]
pub struct CreateBuilder {
asset: Option<solana_program::pubkey::Pubkey>,
authority: Option<(solana_program::pubkey::Pubkey, bool)>,
owner: Option<solana_program::pubkey::Pubkey>,
group: Option<solana_program::pubkey::Pubkey>,
group_authority: Option<solana_program::pubkey::Pubkey>,
payer: Option<solana_program::pubkey::Pubkey>,
system_program: Option<solana_program::pubkey::Pubkey>,
name: Option<String>,
Expand Down Expand Up @@ -169,6 +184,16 @@ impl CreateBuilder {
self
}
/// `[optional account]`
/// The delegate authority for minting assets into a group
#[inline(always)]
pub fn group_authority(
&mut self,
group_authority: Option<solana_program::pubkey::Pubkey>,
) -> &mut Self {
self.group_authority = group_authority;
self
}
/// `[optional account]`
/// The account paying for the storage fees
#[inline(always)]
pub fn payer(&mut self, payer: Option<solana_program::pubkey::Pubkey>) -> &mut Self {
Expand Down Expand Up @@ -233,6 +258,7 @@ impl CreateBuilder {
authority: self.authority.expect("authority is not set"),
owner: self.owner.expect("owner is not set"),
group: self.group,
group_authority: self.group_authority,
payer: self.payer,
system_program: self.system_program,
};
Expand All @@ -257,6 +283,8 @@ pub struct CreateCpiAccounts<'a, 'b> {
pub owner: &'b solana_program::account_info::AccountInfo<'a>,
/// Asset account of the group
pub group: Option<&'b solana_program::account_info::AccountInfo<'a>>,
/// The delegate authority for minting assets into a group
pub group_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>,
/// The account paying for the storage fees
pub payer: Option<&'b solana_program::account_info::AccountInfo<'a>>,
/// The system program
Expand All @@ -275,6 +303,8 @@ pub struct CreateCpi<'a, 'b> {
pub owner: &'b solana_program::account_info::AccountInfo<'a>,
/// Asset account of the group
pub group: Option<&'b solana_program::account_info::AccountInfo<'a>>,
/// The delegate authority for minting assets into a group
pub group_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>,
/// The account paying for the storage fees
pub payer: Option<&'b solana_program::account_info::AccountInfo<'a>>,
/// The system program
Expand All @@ -295,6 +325,7 @@ impl<'a, 'b> CreateCpi<'a, 'b> {
authority: accounts.authority,
owner: accounts.owner,
group: accounts.group,
group_authority: accounts.group_authority,
payer: accounts.payer,
system_program: accounts.system_program,
__args: args,
Expand Down Expand Up @@ -333,7 +364,7 @@ impl<'a, 'b> CreateCpi<'a, 'b> {
bool,
)],
) -> solana_program::entrypoint::ProgramResult {
let mut accounts = Vec::with_capacity(6 + remaining_accounts.len());
let mut accounts = Vec::with_capacity(7 + remaining_accounts.len());
accounts.push(solana_program::instruction::AccountMeta::new(
*self.asset.key,
true,
Expand All @@ -356,6 +387,17 @@ impl<'a, 'b> CreateCpi<'a, 'b> {
false,
));
}
if let Some(group_authority) = self.group_authority {
accounts.push(solana_program::instruction::AccountMeta::new_readonly(
*group_authority.key,
true,
));
} else {
accounts.push(solana_program::instruction::AccountMeta::new_readonly(
crate::INTERFACE_ID,
false,
));
}
if let Some(payer) = self.payer {
accounts.push(solana_program::instruction::AccountMeta::new(
*payer.key, true,
Expand Down Expand Up @@ -393,14 +435,17 @@ impl<'a, 'b> CreateCpi<'a, 'b> {
accounts,
data,
};
let mut account_infos = Vec::with_capacity(6 + 1 + remaining_accounts.len());
let mut account_infos = Vec::with_capacity(7 + 1 + remaining_accounts.len());
account_infos.push(self.__program.clone());
account_infos.push(self.asset.clone());
account_infos.push(self.authority.0.clone());
account_infos.push(self.owner.clone());
if let Some(group) = self.group {
account_infos.push(group.clone());
}
if let Some(group_authority) = self.group_authority {
account_infos.push(group_authority.clone());
}
if let Some(payer) = self.payer {
account_infos.push(payer.clone());
}
Expand All @@ -427,8 +472,9 @@ impl<'a, 'b> CreateCpi<'a, 'b> {
/// 1. `[signer]` authority
/// 2. `[]` owner
/// 3. `[writable, optional]` group
/// 4. `[writable, signer, optional]` payer
/// 5. `[optional]` system_program
/// 4. `[signer, optional]` group_authority
/// 5. `[writable, signer, optional]` payer
/// 6. `[optional]` system_program
pub struct CreateCpiBuilder<'a, 'b> {
instruction: Box<CreateCpiBuilderInstruction<'a, 'b>>,
}
Expand All @@ -441,6 +487,7 @@ impl<'a, 'b> CreateCpiBuilder<'a, 'b> {
authority: None,
owner: None,
group: None,
group_authority: None,
payer: None,
system_program: None,
name: None,
Expand Down Expand Up @@ -484,6 +531,16 @@ impl<'a, 'b> CreateCpiBuilder<'a, 'b> {
self
}
/// `[optional account]`
/// The delegate authority for minting assets into a group
#[inline(always)]
pub fn group_authority(
&mut self,
group_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>,
) -> &mut Self {
self.instruction.group_authority = group_authority;
self
}
/// `[optional account]`
/// The account paying for the storage fees
#[inline(always)]
pub fn payer(
Expand Down Expand Up @@ -588,6 +645,8 @@ impl<'a, 'b> CreateCpiBuilder<'a, 'b> {

group: self.instruction.group,

group_authority: self.instruction.group_authority,

payer: self.instruction.payer,

system_program: self.instruction.system_program,
Expand All @@ -606,6 +665,7 @@ struct CreateCpiBuilderInstruction<'a, 'b> {
authority: Option<(&'b solana_program::account_info::AccountInfo<'a>, bool)>,
owner: Option<&'b solana_program::account_info::AccountInfo<'a>>,
group: Option<&'b solana_program::account_info::AccountInfo<'a>>,
group_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>,
payer: Option<&'b solana_program::account_info::AccountInfo<'a>>,
system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>,
name: Option<String>,
Expand Down
3 changes: 3 additions & 0 deletions programs/asset/interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ pub struct MetadataInput {

/// Indicates whether the asset is mutable or not.
pub mutable: bool,

/// Extensions to be added to the asset.
pub extensions: Option<Vec<ExtensionInput>>,
}

#[repr(C)]
Expand Down
16 changes: 8 additions & 8 deletions programs/asset/program/src/processor/group.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use nifty_asset_types::{
extensions::GroupingMut,
extensions::{Extension, GroupingMut},
podded::{pod::PodOption, ZeroCopy},
state::{Asset, Discriminator},
};
Expand Down Expand Up @@ -64,8 +64,8 @@ pub fn process_group(program_id: &Pubkey, ctx: Context<GroupAccounts>) -> Progra
"asset"
);

let group = Asset::load_mut(&mut group_data);
let group_authority = group.authority;
let (group, extensions) = group_data.split_at_mut(Asset::LEN);
let group = Asset::load_mut(group);

// authority of the group must match the asset
require!(
Expand All @@ -74,7 +74,7 @@ pub fn process_group(program_id: &Pubkey, ctx: Context<GroupAccounts>) -> Progra
"Group and asset authority mismatch"
);

let grouping = if let Some(grouping) = Asset::get_mut::<GroupingMut>(&mut group_data) {
let grouping = if let Some(grouping) = Extension::get_mut::<GroupingMut>(extensions) {
grouping
} else {
return err!(
Expand All @@ -84,18 +84,18 @@ pub fn process_group(program_id: &Pubkey, ctx: Context<GroupAccounts>) -> Progra
};

// if the signing authority doesn't match the group authority
if *ctx.accounts.authority.key != group_authority {
if *ctx.accounts.authority.key != group.authority {
// then the authority must match the grouping delegate
if let Some(delegate) = grouping.delegate.value() {
require!(
*delegate == ctx.accounts.authority.key.into(),
**delegate == *ctx.accounts.authority.key,
AssetError::InvalidAuthority,
"group authority delegate mismatch"
"Group authority or delegate mismatch"
);
} else {
return err!(
AssetError::InvalidAuthority,
"missing group authority delegate"
"Invalid group authority delegate"
);
};
}
Expand Down
17 changes: 9 additions & 8 deletions programs/asset/program/src/processor/ungroup.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use nifty_asset_types::{
extensions::GroupingMut,
extensions::{Extension, GroupingMut},
podded::{pod::PodOption, ZeroCopy},
state::{Asset, Discriminator},
};
Expand Down Expand Up @@ -56,9 +56,10 @@ pub fn process_ungroup(program_id: &Pubkey, ctx: Context<UngroupAccounts>) -> Pr
"asset"
);

let group = Asset::load_mut(&mut group_data);
let asset = Asset::load_mut(&mut asset_data);
let group_authority = group.authority;

let (group, extensions) = group_data.split_at_mut(Asset::LEN);
let group = Asset::load_mut(group);

// asset must be in the group
require!(
Expand All @@ -67,7 +68,7 @@ pub fn process_ungroup(program_id: &Pubkey, ctx: Context<UngroupAccounts>) -> Pr
"asset group mismatch"
);

let grouping = if let Some(grouping) = Asset::get_mut::<GroupingMut>(&mut group_data) {
let grouping = if let Some(grouping) = Extension::get_mut::<GroupingMut>(extensions) {
grouping
} else {
return err!(
Expand All @@ -77,18 +78,18 @@ pub fn process_ungroup(program_id: &Pubkey, ctx: Context<UngroupAccounts>) -> Pr
};

// if the signing authority doesn't match the group authority
if *ctx.accounts.authority.key != group_authority {
if *ctx.accounts.authority.key != group.authority {
// then the authority must match the grouping delegate
if let Some(delegate) = grouping.delegate.value() {
require!(
*delegate == ctx.accounts.authority.key.into(),
**delegate == *ctx.accounts.authority.key,
AssetError::InvalidAuthority,
"group authority delegate mismatch"
"Group authority or delegate mismatch"
);
} else {
return err!(
AssetError::InvalidAuthority,
"missing group authority delegate"
"Invalid group authority delegate"
);
};
}
Expand Down
Loading

0 comments on commit c21dadc

Please sign in to comment.