Skip to content
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

Making new permissions system. #8

Merged
merged 4 commits into from
Mar 7, 2024
Merged
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
17 changes: 12 additions & 5 deletions clients/js/src/generated/instructions/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import {
export type UpdateInstructionAccounts = {
/** The address of the asset */
asset: PublicKey | Pda;
/** The collection to which the asset belongs */
collection?: PublicKey | Pda;
/** The update authority or update authority delegate of the asset */
authority?: Signer;
/** The account paying for the storage fees */
Expand Down Expand Up @@ -96,28 +98,33 @@ export function update(
isWritable: true as boolean,
value: input.asset ?? null,
},
authority: {
collection: {
index: 1,
isWritable: false as boolean,
value: input.collection ?? null,
},
authority: {
index: 2,
isWritable: false as boolean,
value: input.authority ?? null,
},
payer: {
index: 2,
index: 3,
isWritable: true as boolean,
value: input.payer ?? null,
},
newUpdateAuthority: {
index: 3,
index: 4,
isWritable: false as boolean,
value: input.newUpdateAuthority ?? null,
},
systemProgram: {
index: 4,
index: 5,
isWritable: false as boolean,
value: input.systemProgram ?? null,
},
logWrapper: {
index: 5,
index: 6,
isWritable: false as boolean,
value: input.logWrapper ?? null,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import {
burn,
Key,
updateAuthority,
} from '../../../src';
import { createUmi } from '../../_setup';
plugin,
} from '../src';
import { createUmi } from './_setup';

test('it can burn an asset as the owner', async (t) => {
// Given a Umi instance and a new signer.
Expand Down Expand Up @@ -99,3 +100,50 @@ test('it cannot burn an asset if not the owner', async (t) => {
uri: 'https://example.com/bread',
});
});

test('it cannot burn an asset if it is frozen', async (t) => {
// Given a Umi instance and a new signer.
const umi = await createUmi();
const assetAddress = generateSigner(umi);
const attacker = generateSigner(umi);

// When we create a new account.
await create(umi, {
dataState: DataState.AccountState,
asset: assetAddress,
name: 'Test Bread',
uri: 'https://example.com/bread',
plugins: [
plugin('Freeze', [{ frozen: true }]),
],
}).sendAndConfirm(umi);

// Then an account was created with the correct data.
const beforeAsset = await fetchAsset(umi, assetAddress.publicKey);
// console.log("Account State:", beforeAsset);
t.like(beforeAsset, <Asset>{
publicKey: assetAddress.publicKey,
updateAuthority: updateAuthority('Address', [umi.identity.publicKey]),
owner: umi.identity.publicKey,
name: 'Test Bread',
uri: 'https://example.com/bread',
});

const result = burn(umi, {
asset: assetAddress.publicKey,
compressionProof: null,
authority: attacker,
}).sendAndConfirm(umi);

await t.throwsAsync(result, { name: 'InvalidAuthority' });

const afterAsset = await fetchAsset(umi, assetAddress.publicKey);
// console.log("Account State:", afterAsset);
t.like(afterAsset, <Asset>{
publicKey: assetAddress.publicKey,
updateAuthority: updateAuthority('Address', [umi.identity.publicKey]),
owner: umi.identity.publicKey,
name: 'Test Bread',
uri: 'https://example.com/bread',
});
});
82 changes: 69 additions & 13 deletions clients/rust/src/generated/instructions/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use borsh::BorshSerialize;
pub struct Update {
/// The address of the asset
pub asset: solana_program::pubkey::Pubkey,
/// The collection to which the asset belongs
pub collection: Option<solana_program::pubkey::Pubkey>,
/// The update authority or update authority delegate of the asset
pub authority: solana_program::pubkey::Pubkey,
/// The account paying for the storage fees
Expand All @@ -37,10 +39,20 @@ impl Update {
args: UpdateInstructionArgs,
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, false,
));
if let Some(collection) = self.collection {
accounts.push(solana_program::instruction::AccountMeta::new_readonly(
collection, false,
));
} else {
accounts.push(solana_program::instruction::AccountMeta::new_readonly(
crate::MPL_CORE_ID,
false,
));
}
accounts.push(solana_program::instruction::AccountMeta::new_readonly(
self.authority,
true,
Expand Down Expand Up @@ -115,14 +127,16 @@ pub struct UpdateInstructionArgs {
/// ### Accounts:
///
/// 0. `[writable]` asset
/// 1. `[signer]` authority
/// 2. `[writable, signer, optional]` payer
/// 3. `[optional]` new_update_authority
/// 4. `[optional]` system_program (default to `11111111111111111111111111111111`)
/// 5. `[optional]` log_wrapper
/// 1. `[optional]` collection
/// 2. `[signer]` authority
/// 3. `[writable, signer, optional]` payer
/// 4. `[optional]` new_update_authority
/// 5. `[optional]` system_program (default to `11111111111111111111111111111111`)
/// 6. `[optional]` log_wrapper
#[derive(Default)]
pub struct UpdateBuilder {
asset: Option<solana_program::pubkey::Pubkey>,
collection: Option<solana_program::pubkey::Pubkey>,
authority: Option<solana_program::pubkey::Pubkey>,
payer: Option<solana_program::pubkey::Pubkey>,
new_update_authority: Option<solana_program::pubkey::Pubkey>,
Expand All @@ -143,6 +157,13 @@ impl UpdateBuilder {
self.asset = Some(asset);
self
}
/// `[optional account]`
/// The collection to which the asset belongs
#[inline(always)]
pub fn collection(&mut self, collection: Option<solana_program::pubkey::Pubkey>) -> &mut Self {
self.collection = collection;
self
}
/// The update authority or update authority delegate of the asset
#[inline(always)]
pub fn authority(&mut self, authority: solana_program::pubkey::Pubkey) -> &mut Self {
Expand Down Expand Up @@ -217,6 +238,7 @@ impl UpdateBuilder {
pub fn instruction(&self) -> solana_program::instruction::Instruction {
let accounts = Update {
asset: self.asset.expect("asset is not set"),
collection: self.collection,
authority: self.authority.expect("authority is not set"),
payer: self.payer,
new_update_authority: self.new_update_authority,
Expand All @@ -238,6 +260,8 @@ impl UpdateBuilder {
pub struct UpdateCpiAccounts<'a, 'b> {
/// The address of the asset
pub asset: &'b solana_program::account_info::AccountInfo<'a>,
/// The collection to which the asset belongs
pub collection: Option<&'b solana_program::account_info::AccountInfo<'a>>,
/// The update authority or update authority delegate of the asset
pub authority: &'b solana_program::account_info::AccountInfo<'a>,
/// The account paying for the storage fees
Expand All @@ -256,6 +280,8 @@ pub struct UpdateCpi<'a, 'b> {
pub __program: &'b solana_program::account_info::AccountInfo<'a>,
/// The address of the asset
pub asset: &'b solana_program::account_info::AccountInfo<'a>,
/// The collection to which the asset belongs
pub collection: Option<&'b solana_program::account_info::AccountInfo<'a>>,
/// The update authority or update authority delegate of the asset
pub authority: &'b solana_program::account_info::AccountInfo<'a>,
/// The account paying for the storage fees
Expand All @@ -279,6 +305,7 @@ impl<'a, 'b> UpdateCpi<'a, 'b> {
Self {
__program: program,
asset: accounts.asset,
collection: accounts.collection,
authority: accounts.authority,
payer: accounts.payer,
new_update_authority: accounts.new_update_authority,
Expand Down Expand Up @@ -320,11 +347,22 @@ impl<'a, 'b> UpdateCpi<'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,
false,
));
if let Some(collection) = self.collection {
accounts.push(solana_program::instruction::AccountMeta::new_readonly(
*collection.key,
false,
));
} else {
accounts.push(solana_program::instruction::AccountMeta::new_readonly(
crate::MPL_CORE_ID,
false,
));
}
accounts.push(solana_program::instruction::AccountMeta::new_readonly(
*self.authority.key,
true,
Expand Down Expand Up @@ -381,9 +419,12 @@ impl<'a, 'b> UpdateCpi<'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());
if let Some(collection) = self.collection {
account_infos.push(collection.clone());
}
account_infos.push(self.authority.clone());
if let Some(payer) = self.payer {
account_infos.push(payer.clone());
Expand Down Expand Up @@ -412,11 +453,12 @@ impl<'a, 'b> UpdateCpi<'a, 'b> {
/// ### Accounts:
///
/// 0. `[writable]` asset
/// 1. `[signer]` authority
/// 2. `[writable, signer, optional]` payer
/// 3. `[optional]` new_update_authority
/// 4. `[]` system_program
/// 5. `[optional]` log_wrapper
/// 1. `[optional]` collection
/// 2. `[signer]` authority
/// 3. `[writable, signer, optional]` payer
/// 4. `[optional]` new_update_authority
/// 5. `[]` system_program
/// 6. `[optional]` log_wrapper
pub struct UpdateCpiBuilder<'a, 'b> {
instruction: Box<UpdateCpiBuilderInstruction<'a, 'b>>,
}
Expand All @@ -426,6 +468,7 @@ impl<'a, 'b> UpdateCpiBuilder<'a, 'b> {
let instruction = Box::new(UpdateCpiBuilderInstruction {
__program: program,
asset: None,
collection: None,
authority: None,
payer: None,
new_update_authority: None,
Expand All @@ -443,6 +486,16 @@ impl<'a, 'b> UpdateCpiBuilder<'a, 'b> {
self.instruction.asset = Some(asset);
self
}
/// `[optional account]`
/// The collection to which the asset belongs
#[inline(always)]
pub fn collection(
&mut self,
collection: Option<&'b solana_program::account_info::AccountInfo<'a>>,
) -> &mut Self {
self.instruction.collection = collection;
self
}
/// The update authority or update authority delegate of the asset
#[inline(always)]
pub fn authority(
Expand Down Expand Up @@ -553,6 +606,8 @@ impl<'a, 'b> UpdateCpiBuilder<'a, 'b> {

asset: self.instruction.asset.expect("asset is not set"),

collection: self.instruction.collection,

authority: self.instruction.authority.expect("authority is not set"),

payer: self.instruction.payer,
Expand All @@ -577,6 +632,7 @@ impl<'a, 'b> UpdateCpiBuilder<'a, 'b> {
struct UpdateCpiBuilderInstruction<'a, 'b> {
__program: &'b solana_program::account_info::AccountInfo<'a>,
asset: Option<&'b solana_program::account_info::AccountInfo<'a>>,
collection: Option<&'b solana_program::account_info::AccountInfo<'a>>,
authority: Option<&'b solana_program::account_info::AccountInfo<'a>>,
payer: Option<&'b solana_program::account_info::AccountInfo<'a>>,
new_update_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>,
Expand Down
9 changes: 9 additions & 0 deletions idls/mpl_core.json
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,15 @@
"The address of the asset"
]
},
{
"name": "collection",
"isMut": false,
"isSigner": false,
"isOptional": true,
"docs": [
"The collection to which the asset belongs"
]
},
{
"name": "authority",
"isMut": false,
Expand Down
11 changes: 6 additions & 5 deletions programs/mpl-core/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,12 @@ pub(crate) enum MplAssetInstruction {

/// Update an mpl-core.
#[account(0, writable, name="asset", desc = "The address of the asset")]
#[account(1, signer, name="authority", desc = "The update authority or update authority delegate of the asset")]
#[account(2, optional, writable, signer, name="payer", desc = "The account paying for the storage fees")]
#[account(3, optional, name="new_update_authority", desc = "The new update authority of the asset")]
#[account(4, name="system_program", desc = "The system program")]
#[account(5, optional, name="log_wrapper", desc = "The SPL Noop Program")]
#[account(1, optional, name="collection", desc = "The collection to which the asset belongs")]
#[account(2, signer, name="authority", desc = "The update authority or update authority delegate of the asset")]
#[account(3, optional, writable, signer, name="payer", desc = "The account paying for the storage fees")]
#[account(4, optional, name="new_update_authority", desc = "The new update authority of the asset")]
#[account(5, name="system_program", desc = "The system program")]
#[account(6, optional, name="log_wrapper", desc = "The SPL Noop Program")]
Update(UpdateArgs),

/// Update an mpl-core.
Expand Down
3 changes: 1 addition & 2 deletions programs/mpl-core/src/plugins/burn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{account_info::AccountInfo, program_error::ProgramError};

use crate::{
processor::{CompressArgs, CreateArgs, DecompressArgs, TransferArgs},
processor::{CompressArgs, CreateArgs, DecompressArgs},
state::{Authority, DataBlob},
};

Expand Down Expand Up @@ -73,7 +73,6 @@ impl PluginValidation for Burn {
&self,
_authority: &AccountInfo,
_new_owner: &AccountInfo,
_args: &TransferArgs,
_authorities: &[Authority],
) -> Result<super::ValidationResult, ProgramError> {
Ok(ValidationResult::Pass)
Expand Down
3 changes: 1 addition & 2 deletions programs/mpl-core/src/plugins/freeze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{account_info::AccountInfo, program_error::ProgramError};

use crate::{
processor::{CompressArgs, CreateArgs, DecompressArgs, TransferArgs},
processor::{CompressArgs, CreateArgs, DecompressArgs},
state::{Asset, Authority, DataBlob},
};

Expand Down Expand Up @@ -98,7 +98,6 @@ impl PluginValidation for Freeze {
&self,
_authority: &AccountInfo,
_new_owner: &AccountInfo,
_args: &TransferArgs,
_authorities: &[Authority],
) -> Result<super::ValidationResult, ProgramError> {
if self.frozen {
Expand Down
Loading
Loading