Skip to content

Commit

Permalink
Add updateV2 which allows adding/removing an asset from collection (#…
Browse files Browse the repository at this point in the history
…142)

* Add ability to add/remove an asset from a collection

* Regenerate clients

* Add back check for V1 removing from collection

* Validate permission to add to new collection

* Update comments

* Simplify condition

* Kinobi default for updateV2 and initial tests

* Add test changing collection using delegate

* Add wrong collection tests and collection size checks

* Additional change collection tests

* More checks

* Update JS SDK V1 to use updateV2

* Update updateV2 test to use SDK

* Use SDK test helpers

* Only increment num_minted on create

* Add negative test cases

* Reorder tests

* Add more update delegate tests, rename tests, add asserts

* Separate increment into two methods
  • Loading branch information
danenbm authored Jun 18, 2024
1 parent 5a04e42 commit 433a2dd
Show file tree
Hide file tree
Showing 17 changed files with 2,386 additions and 62 deletions.
1 change: 1 addition & 0 deletions clients/js/src/generated/instructions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ export * from './updateCollectionV1';
export * from './updateExternalPluginAdapterV1';
export * from './updatePluginV1';
export * from './updateV1';
export * from './updateV2';
export * from './writeCollectionExternalPluginAdapterDataV1';
export * from './writeExternalPluginAdapterDataV1';
190 changes: 190 additions & 0 deletions clients/js/src/generated/instructions/updateV2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/**
* This code was AUTOGENERATED using the kinobi library.
* Please DO NOT EDIT THIS FILE, instead use visitors
* to add features, then rerun kinobi to update it.
*
* @see https://github.com/metaplex-foundation/kinobi
*/

import {
Context,
Option,
OptionOrNullable,
Pda,
PublicKey,
Signer,
TransactionBuilder,
none,
transactionBuilder,
} from '@metaplex-foundation/umi';
import {
Serializer,
mapSerializer,
option,
string,
struct,
u8,
} from '@metaplex-foundation/umi/serializers';
import {
ResolvedAccount,
ResolvedAccountsWithIndices,
getAccountMetasAndSigners,
} from '../shared';
import {
BaseUpdateAuthority,
BaseUpdateAuthorityArgs,
getBaseUpdateAuthoritySerializer,
} from '../types';

// Accounts.
export type UpdateV2InstructionAccounts = {
/** The address of the asset */
asset: PublicKey | Pda;
/** The collection to which the asset belongs */
collection?: PublicKey | Pda;
/** The account paying for the storage fees */
payer?: Signer;
/** The update authority or update authority delegate of the asset */
authority?: Signer;
/** A new collection to which to move the asset */
newCollection?: PublicKey | Pda;
/** The system program */
systemProgram?: PublicKey | Pda;
/** The SPL Noop Program */
logWrapper?: PublicKey | Pda;
};

// Data.
export type UpdateV2InstructionData = {
discriminator: number;
newName: Option<string>;
newUri: Option<string>;
newUpdateAuthority: Option<BaseUpdateAuthority>;
};

export type UpdateV2InstructionDataArgs = {
newName?: OptionOrNullable<string>;
newUri?: OptionOrNullable<string>;
newUpdateAuthority?: OptionOrNullable<BaseUpdateAuthorityArgs>;
};

export function getUpdateV2InstructionDataSerializer(): Serializer<
UpdateV2InstructionDataArgs,
UpdateV2InstructionData
> {
return mapSerializer<
UpdateV2InstructionDataArgs,
any,
UpdateV2InstructionData
>(
struct<UpdateV2InstructionData>(
[
['discriminator', u8()],
['newName', option(string())],
['newUri', option(string())],
['newUpdateAuthority', option(getBaseUpdateAuthoritySerializer())],
],
{ description: 'UpdateV2InstructionData' }
),
(value) => ({
...value,
discriminator: 30,
newName: value.newName ?? none(),
newUri: value.newUri ?? none(),
newUpdateAuthority: value.newUpdateAuthority ?? none(),
})
) as Serializer<UpdateV2InstructionDataArgs, UpdateV2InstructionData>;
}

// Args.
export type UpdateV2InstructionArgs = UpdateV2InstructionDataArgs;

// Instruction.
export function updateV2(
context: Pick<Context, 'payer' | 'programs'>,
input: UpdateV2InstructionAccounts & UpdateV2InstructionArgs
): TransactionBuilder {
// Program ID.
const programId = context.programs.getPublicKey(
'mplCore',
'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d'
);

// Accounts.
const resolvedAccounts = {
asset: {
index: 0,
isWritable: true as boolean,
value: input.asset ?? null,
},
collection: {
index: 1,
isWritable: true as boolean,
value: input.collection ?? null,
},
payer: {
index: 2,
isWritable: true as boolean,
value: input.payer ?? null,
},
authority: {
index: 3,
isWritable: false as boolean,
value: input.authority ?? null,
},
newCollection: {
index: 4,
isWritable: true as boolean,
value: input.newCollection ?? null,
},
systemProgram: {
index: 5,
isWritable: false as boolean,
value: input.systemProgram ?? null,
},
logWrapper: {
index: 6,
isWritable: false as boolean,
value: input.logWrapper ?? null,
},
} satisfies ResolvedAccountsWithIndices;

// Arguments.
const resolvedArgs: UpdateV2InstructionArgs = { ...input };

// Default values.
if (!resolvedAccounts.payer.value) {
resolvedAccounts.payer.value = context.payer;
}
if (!resolvedAccounts.systemProgram.value) {
resolvedAccounts.systemProgram.value = context.programs.getPublicKey(
'splSystem',
'11111111111111111111111111111111'
);
resolvedAccounts.systemProgram.isWritable = false;
}

// Accounts in order.
const orderedAccounts: ResolvedAccount[] = Object.values(
resolvedAccounts
).sort((a, b) => a.index - b.index);

// Keys and Signers.
const [keys, signers] = getAccountMetasAndSigners(
orderedAccounts,
'programId',
programId
);

// Data.
const data = getUpdateV2InstructionDataSerializer().serialize(
resolvedArgs as UpdateV2InstructionDataArgs
);

// Bytes Created On Chain.
const bytesCreatedOnChain = 0;

return transactionBuilder([
{ instruction: { keys, programId, data }, signers, bytesCreatedOnChain },
]);
}
12 changes: 6 additions & 6 deletions clients/js/src/instructions/update.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { Context } from '@metaplex-foundation/umi';
import {
CollectionV1,
updateV1,
AssetV1,
UpdateV1InstructionDataArgs,
UpdateV2InstructionDataArgs,
updateV2,
} from '../generated';
import { findExtraAccounts } from '../plugins';
import { deriveExternalPluginAdapters } from '../helpers';

export type UpdateArgs = Omit<
Parameters<typeof updateV1>[1],
Parameters<typeof updateV2>[1],
'asset' | 'collection' | 'newName' | 'newUri'
> & {
asset: Pick<AssetV1, 'publicKey' | 'owner' | 'oracles' | 'lifecycleHooks'>;
collection?: Pick<CollectionV1, 'publicKey' | 'oracles' | 'lifecycleHooks'>;
name?: UpdateV1InstructionDataArgs['newName'];
uri?: UpdateV1InstructionDataArgs['newUri'];
name?: UpdateV2InstructionDataArgs['newName'];
uri?: UpdateV2InstructionDataArgs['newUri'];
};

export const update = (
Expand All @@ -38,7 +38,7 @@ export const update = (
}
);

return updateV1(context, {
return updateV2(context, {
...args,
asset: asset.publicKey,
collection: collection?.publicKey,
Expand Down
4 changes: 2 additions & 2 deletions clients/js/test/update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ test('it can update an asset update authority', async (t) => {
});
});

test('it cannot update an asset update authority to be part of a collection (right now)', async (t) => {
test('it cannot update an asset update authority to be part of a collection using updateV1', async (t) => {
// Given a Umi instance and a new signer.
const umi = await createUmi();
const asset = await createAsset(umi);
Expand All @@ -199,7 +199,7 @@ test('it cannot update an asset update authority to be part of a collection (rig
await t.throwsAsync(result, { name: 'NotAvailable' });
});

test('it cannot remove an asset from a collection (right now)', async (t) => {
test('it cannot remove an asset from a collection using updateV1', async (t) => {
// Given a Umi instance and a new signer.
const umi = await createUmi();
const { asset, collection } = await createAssetWithCollection(umi, {}, {});
Expand Down
Loading

0 comments on commit 433a2dd

Please sign in to comment.