Skip to content

Commit

Permalink
Merge branch 'main' into danenbm/merge-in-main
Browse files Browse the repository at this point in the history
  • Loading branch information
danenbm committed Jul 11, 2024
2 parents f079d9a + 3bb6c9b commit 0fee59c
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 61 deletions.
33 changes: 23 additions & 10 deletions clients/js/src/generated/errors/mplCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -604,56 +604,69 @@ export class InvalidPluginOperationError extends ProgramError {
codeToErrorMap.set(0x29, InvalidPluginOperationError);
nameToErrorMap.set('InvalidPluginOperation', InvalidPluginOperationError);

/** CollectionMustBeEmpty: Collection must be empty to be burned */
export class CollectionMustBeEmptyError extends ProgramError {
override readonly name: string = 'CollectionMustBeEmpty';

readonly code: number = 0x2a; // 42

constructor(program: Program, cause?: Error) {
super('Collection must be empty to be burned', program, cause);
}
}
codeToErrorMap.set(0x2a, CollectionMustBeEmptyError);
nameToErrorMap.set('CollectionMustBeEmpty', CollectionMustBeEmptyError);

/** TwoDataSources: Two data sources provided, only one is allowed */
export class TwoDataSourcesError extends ProgramError {
override readonly name: string = 'TwoDataSources';

readonly code: number = 0x2a; // 42
readonly code: number = 0x2b; // 43

constructor(program: Program, cause?: Error) {
super('Two data sources provided, only one is allowed', program, cause);
}
}
codeToErrorMap.set(0x2a, TwoDataSourcesError);
codeToErrorMap.set(0x2b, TwoDataSourcesError);
nameToErrorMap.set('TwoDataSources', TwoDataSourcesError);

/** UnsupportedOperation: External Plugin does not support this operation */
export class UnsupportedOperationError extends ProgramError {
override readonly name: string = 'UnsupportedOperation';

readonly code: number = 0x2b; // 43
readonly code: number = 0x2c; // 44

constructor(program: Program, cause?: Error) {
super('External Plugin does not support this operation', program, cause);
}
}
codeToErrorMap.set(0x2b, UnsupportedOperationError);
codeToErrorMap.set(0x2c, UnsupportedOperationError);
nameToErrorMap.set('UnsupportedOperation', UnsupportedOperationError);

/** NoDataSources: No data sources provided, one is required */
export class NoDataSourcesError extends ProgramError {
override readonly name: string = 'NoDataSources';

readonly code: number = 0x2c; // 44
readonly code: number = 0x2d; // 45

constructor(program: Program, cause?: Error) {
super('No data sources provided, one is required', program, cause);
}
}
codeToErrorMap.set(0x2c, NoDataSourcesError);
codeToErrorMap.set(0x2d, NoDataSourcesError);
nameToErrorMap.set('NoDataSources', NoDataSourcesError);

/** InvalidPluginAdapterTarget: This plugin adapter cannot be added to an Asset */
export class InvalidPluginAdapterTargetError extends ProgramError {
override readonly name: string = 'InvalidPluginAdapterTarget';

readonly code: number = 0x2d; // 45
readonly code: number = 0x2e; // 46

constructor(program: Program, cause?: Error) {
super('This plugin adapter cannot be added to an Asset', program, cause);
}
}
codeToErrorMap.set(0x2d, InvalidPluginAdapterTargetError);
codeToErrorMap.set(0x2e, InvalidPluginAdapterTargetError);
nameToErrorMap.set(
'InvalidPluginAdapterTarget',
InvalidPluginAdapterTargetError
Expand All @@ -663,7 +676,7 @@ nameToErrorMap.set(
export class CannotAddDataSectionError extends ProgramError {
override readonly name: string = 'CannotAddDataSection';

readonly code: number = 0x2e; // 46
readonly code: number = 0x2f; // 47

constructor(program: Program, cause?: Error) {
super(
Expand All @@ -673,7 +686,7 @@ export class CannotAddDataSectionError extends ProgramError {
);
}
}
codeToErrorMap.set(0x2e, CannotAddDataSectionError);
codeToErrorMap.set(0x2f, CannotAddDataSectionError);
nameToErrorMap.set('CannotAddDataSection', CannotAddDataSectionError);

/**
Expand Down
47 changes: 27 additions & 20 deletions clients/js/test/burn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { generateSigner, sol } from '@metaplex-foundation/umi';
import test from 'ava';

import { generateSignerWithSol } from '@metaplex-foundation/umi-bundle-tests';
import { burnCollectionV1, burnV1, pluginAuthorityPair } from '../src';
import { burnV1, pluginAuthorityPair } from '../src';
import {
DEFAULT_ASSET,
DEFAULT_COLLECTION,
Expand Down Expand Up @@ -60,6 +60,32 @@ test('it cannot burn an asset if not the owner', async (t) => {
});
});

test('it cannot burn an asset as the authority', async (t) => {
const umi = await createUmi();
const authority = generateSigner(umi);

const asset = await createAsset(umi, { updateAuthority: authority });
await assertAsset(t, umi, {
...DEFAULT_ASSET,
asset: asset.publicKey,
owner: umi.identity.publicKey,
updateAuthority: { type: 'Address', address: authority.publicKey },
});

const result = burnV1(umi, {
asset: asset.publicKey,
authority,
}).sendAndConfirm(umi);

await t.throwsAsync(result, { name: 'NoApprovals' });
await assertAsset(t, umi, {
...DEFAULT_ASSET,
asset: asset.publicKey,
owner: umi.identity.publicKey,
updateAuthority: { type: 'Address', address: authority.publicKey },
});
});

test('it cannot burn an asset if it is frozen', async (t) => {
const umi = await createUmi();

Expand Down Expand Up @@ -208,25 +234,6 @@ test('it cannot use an invalid noop program for assets', async (t) => {
await t.throwsAsync(result, { name: 'InvalidLogWrapperProgram' });
});

test('it cannot use an invalid noop program for collections', async (t) => {
const umi = await createUmi();
const collection = await createCollection(umi);
const fakeLogWrapper = generateSigner(umi);
await assertCollection(t, umi, {
...DEFAULT_COLLECTION,
collection: collection.publicKey,
updateAuthority: umi.identity.publicKey,
});

const result = burnCollectionV1(umi, {
collection: collection.publicKey,
logWrapper: fakeLogWrapper.publicKey,
compressionProof: null,
}).sendAndConfirm(umi);

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

test('it can burn using owner authority', async (t) => {
const umi = await createUmi();
const owner = await generateSignerWithSol(umi);
Expand Down
130 changes: 130 additions & 0 deletions clients/js/test/burnCollection.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { generateSigner, sol } from '@metaplex-foundation/umi';
import test from 'ava';

import { generateSignerWithSol } from '@metaplex-foundation/umi-bundle-tests';
import { burnCollection } from '../src';
import {
DEFAULT_COLLECTION,
assertBurned,
assertCollection,
createAssetWithCollection,
createCollection,
createUmi,
} from './_setupRaw';

test('it can burn a collection as the authority', async (t) => {
const umi = await createUmi();
const collection = await createCollection(umi);
await assertCollection(t, umi, {
...DEFAULT_COLLECTION,
collection: collection.publicKey,
updateAuthority: umi.identity.publicKey,
});

await burnCollection(umi, {
collection: collection.publicKey,
compressionProof: null,
}).sendAndConfirm(umi);

// And the asset address still exists but was resized to 1.
const afterCollection = await assertBurned(t, umi, collection.publicKey);
t.deepEqual(afterCollection.lamports, sol(0.00089784));
});

test('it cannot burn a collection if not the authority', async (t) => {
const umi = await createUmi();
const attacker = generateSigner(umi);

const collection = await createCollection(umi);
await assertCollection(t, umi, {
...DEFAULT_COLLECTION,
collection: collection.publicKey,
updateAuthority: umi.identity.publicKey,
});

const result = burnCollection(umi, {
collection: collection.publicKey,
authority: attacker,
compressionProof: null,
}).sendAndConfirm(umi);

await t.throwsAsync(result, { name: 'InvalidAuthority' });
await assertCollection(t, umi, {
...DEFAULT_COLLECTION,
collection: collection.publicKey,
updateAuthority: umi.identity.publicKey,
});
});

test('it cannot burn a collection if it has Assets in it', async (t) => {
const umi = await createUmi();

const { collection } = await createAssetWithCollection(umi, {});

await assertCollection(t, umi, {
...DEFAULT_COLLECTION,
collection: collection.publicKey,
updateAuthority: umi.identity.publicKey,
});

const result = burnCollection(umi, {
collection: collection.publicKey,
compressionProof: null,
}).sendAndConfirm(umi);

await t.throwsAsync(result, { name: 'CollectionMustBeEmpty' });
await assertCollection(t, umi, {
...DEFAULT_COLLECTION,
collection: collection.publicKey,
updateAuthority: umi.identity.publicKey,
});
});

test('it can burn asset with different payer', async (t) => {
const umi = await createUmi();
const authority = await generateSignerWithSol(umi);
const collection = await createCollection(umi, {
updateAuthority: authority.publicKey,
});
await assertCollection(t, umi, {
...DEFAULT_COLLECTION,
collection: collection.publicKey,
updateAuthority: authority.publicKey,
});

const lamportsBefore = await umi.rpc.getBalance(umi.identity.publicKey);

await burnCollection(umi, {
collection: collection.publicKey,
payer: umi.identity,
authority,
compressionProof: null,
}).sendAndConfirm(umi);

// And the asset address still exists but was resized to 1.
const afterCollection = await assertBurned(t, umi, collection.publicKey);
t.deepEqual(afterCollection.lamports, sol(0.00089784));

const lamportsAfter = await umi.rpc.getBalance(umi.identity.publicKey);

t.true(lamportsAfter.basisPoints > lamportsBefore.basisPoints);
});

test('it cannot use an invalid noop program for collections', async (t) => {
const umi = await createUmi();
const collection = await createCollection(umi);
const fakeLogWrapper = generateSigner(umi);
await assertCollection(t, umi, {
...DEFAULT_COLLECTION,
collection: collection.publicKey,
updateAuthority: umi.identity.publicKey,
});

const result = burnCollection(umi, {
collection: collection.publicKey,
logWrapper: fakeLogWrapper.publicKey,
compressionProof: null,
}).sendAndConfirm(umi);

await t.throwsAsync(result, { name: 'InvalidLogWrapperProgram' });
});
13 changes: 8 additions & 5 deletions clients/rust/src/generated/errors/mpl_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,19 +136,22 @@ pub enum MplCoreError {
/// 41 (0x29) - Invalid plugin operation
#[error("Invalid plugin operation")]
InvalidPluginOperation,
/// 42 (0x2A) - Two data sources provided, only one is allowed
/// 42 (0x2A) - Collection must be empty to be burned
#[error("Collection must be empty to be burned")]
CollectionMustBeEmpty,
/// 43 (0x2B) - Two data sources provided, only one is allowed
#[error("Two data sources provided, only one is allowed")]
TwoDataSources,
/// 43 (0x2B) - External Plugin does not support this operation
/// 44 (0x2C) - External Plugin does not support this operation
#[error("External Plugin does not support this operation")]
UnsupportedOperation,
/// 44 (0x2C) - No data sources provided, one is required
/// 45 (0x2D) - No data sources provided, one is required
#[error("No data sources provided, one is required")]
NoDataSources,
/// 45 (0x2D) - This plugin adapter cannot be added to an Asset
/// 46 (0x2E) - This plugin adapter cannot be added to an Asset
#[error("This plugin adapter cannot be added to an Asset")]
InvalidPluginAdapterTarget,
/// 46 (0x2E) - Cannot add a Data Section without a linked external plugin
/// 47 (0x2F) - Cannot add a Data Section without a linked external plugin
#[error("Cannot add a Data Section without a linked external plugin")]
CannotAddDataSection,
}
Expand Down
13 changes: 9 additions & 4 deletions idls/mpl_core.json
Original file line number Diff line number Diff line change
Expand Up @@ -4825,26 +4825,31 @@
},
{
"code": 42,
"name": "CollectionMustBeEmpty",
"msg": "Collection must be empty to be burned"
},
{
"code": 43,
"name": "TwoDataSources",
"msg": "Two data sources provided, only one is allowed"
},
{
"code": 43,
"code": 44,
"name": "UnsupportedOperation",
"msg": "External Plugin does not support this operation"
},
{
"code": 44,
"code": 45,
"name": "NoDataSources",
"msg": "No data sources provided, one is required"
},
{
"code": 45,
"code": 46,
"name": "InvalidPluginAdapterTarget",
"msg": "This plugin adapter cannot be added to an Asset"
},
{
"code": 46,
"code": 47,
"name": "CannotAddDataSection",
"msg": "Cannot add a Data Section without a linked external plugin"
}
Expand Down
14 changes: 9 additions & 5 deletions programs/mpl-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,23 +177,27 @@ pub enum MplCoreError {
#[error("Invalid plugin operation")]
InvalidPluginOperation,

/// 42 - Two data sources provided, only one is allowed
/// 42 - Collection must be empty to be burned
#[error("Collection must be empty to be burned")]
CollectionMustBeEmpty,

/// 43 - Two data sources provided, only one is allowed
#[error("Two data sources provided, only one is allowed")]
TwoDataSources,

/// 43 - External Plugin does not support this operation
/// 44 - External Plugin does not support this operation
#[error("External Plugin does not support this operation")]
UnsupportedOperation,

/// 44 - No data sources provided, one is required
/// 45 - No data sources provided, one is required
#[error("No data sources provided, one is required")]
NoDataSources,

/// 45 - This plugin adapter cannot be added to an Asset
/// 46 - This plugin adapter cannot be added to an Asset
#[error("This plugin adapter cannot be added to an Asset")]
InvalidPluginAdapterTarget,

/// 46 - Cannot add a Data Section without a linked external plugin
/// 47 - Cannot add a Data Section without a linked external plugin
#[error("Cannot add a Data Section without a linked external plugin")]
CannotAddDataSection,
}
Expand Down
Loading

0 comments on commit 0fee59c

Please sign in to comment.