Skip to content

Commit

Permalink
Clean up Solana state by minimizing account space for TM. (#148)
Browse files Browse the repository at this point in the history
* Adding resizing of metadata and edition accounts.

* Integrating close of ownerless accounts.

* Adding auth to fungibles.

* Updating based on first round of feedback.

* Minor tweaks and adding more thorough tests.

* Finishing resize tests.

* Fix formatting.

* Fixing bad test function.

* Minor fixes.

* Adding ignores.

* TS Ignore

* Ignoring DeadlineExceeded tests.

* Updating based on audit.

* Update clients.

* Add couple last tests

---------

Co-authored-by: Michael Danenberg <56533526+danenbm@users.noreply.github.com>
  • Loading branch information
blockiosaurus and danenbm authored Oct 23, 2024
1 parent d580a0b commit 7c95f99
Show file tree
Hide file tree
Showing 34 changed files with 5,398 additions and 43 deletions.
29 changes: 29 additions & 0 deletions clients/js/src/generated/errors/mplTokenMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2955,6 +2955,35 @@ nameToErrorMap.set(
InvalidEditionAccountLengthError
);

/** AccountAlreadyResized: Account has already been resized */
export class AccountAlreadyResizedError extends ProgramError {
override readonly name: string = 'AccountAlreadyResized';

readonly code: number = 0xc9; // 201

constructor(program: Program, cause?: Error) {
super('Account has already been resized', program, cause);
}
}
codeToErrorMap.set(0xc9, AccountAlreadyResizedError);
nameToErrorMap.set('AccountAlreadyResized', AccountAlreadyResizedError);

/** ConditionsForClosingNotMet: Conditions for closing not met */
export class ConditionsForClosingNotMetError extends ProgramError {
override readonly name: string = 'ConditionsForClosingNotMet';

readonly code: number = 0xca; // 202

constructor(program: Program, cause?: Error) {
super('Conditions for closing not met', program, cause);
}
}
codeToErrorMap.set(0xca, ConditionsForClosingNotMetError);
nameToErrorMap.set(
'ConditionsForClosingNotMet',
ConditionsForClosingNotMetError
);

/**
* Attempts to resolve a custom program error from the provided error code.
* @category Errors
Expand Down
141 changes: 141 additions & 0 deletions clients/js/src/generated/instructions/closeAccounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/**
* 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,
Pda,
PublicKey,
Signer,
TransactionBuilder,
transactionBuilder,
} from '@metaplex-foundation/umi';
import {
Serializer,
mapSerializer,
struct,
u8,
} from '@metaplex-foundation/umi/serializers';
import { findMasterEditionPda, findMetadataPda } from '../accounts';
import {
ResolvedAccount,
ResolvedAccountsWithIndices,
expectPublicKey,
getAccountMetasAndSigners,
} from '../shared';

// Accounts.
export type CloseAccountsInstructionAccounts = {
/** Metadata (pda of ['metadata', program id, mint id]) */
metadata?: PublicKey | Pda;
/** Edition of the asset */
edition?: PublicKey | Pda;
/** Mint of token asset */
mint: PublicKey | Pda;
/** Authority to close ownerless accounts */
authority?: Signer;
/** The destination account that will receive the rent. */
destination: PublicKey | Pda;
};

// Data.
export type CloseAccountsInstructionData = { discriminator: number };

export type CloseAccountsInstructionDataArgs = {};

export function getCloseAccountsInstructionDataSerializer(): Serializer<
CloseAccountsInstructionDataArgs,
CloseAccountsInstructionData
> {
return mapSerializer<
CloseAccountsInstructionDataArgs,
any,
CloseAccountsInstructionData
>(
struct<CloseAccountsInstructionData>([['discriminator', u8()]], {
description: 'CloseAccountsInstructionData',
}),
(value) => ({ ...value, discriminator: 57 })
) as Serializer<
CloseAccountsInstructionDataArgs,
CloseAccountsInstructionData
>;
}

// Instruction.
export function closeAccounts(
context: Pick<Context, 'eddsa' | 'identity' | 'programs'>,
input: CloseAccountsInstructionAccounts
): TransactionBuilder {
// Program ID.
const programId = context.programs.getPublicKey(
'mplTokenMetadata',
'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'
);

// Accounts.
const resolvedAccounts = {
metadata: {
index: 0,
isWritable: true as boolean,
value: input.metadata ?? null,
},
edition: {
index: 1,
isWritable: true as boolean,
value: input.edition ?? null,
},
mint: { index: 2, isWritable: true as boolean, value: input.mint ?? null },
authority: {
index: 3,
isWritable: false as boolean,
value: input.authority ?? null,
},
destination: {
index: 4,
isWritable: true as boolean,
value: input.destination ?? null,
},
} satisfies ResolvedAccountsWithIndices;

// Default values.
if (!resolvedAccounts.metadata.value) {
resolvedAccounts.metadata.value = findMetadataPda(context, {
mint: expectPublicKey(resolvedAccounts.mint.value),
});
}
if (!resolvedAccounts.edition.value) {
resolvedAccounts.edition.value = findMasterEditionPda(context, {
mint: expectPublicKey(resolvedAccounts.mint.value),
});
}
if (!resolvedAccounts.authority.value) {
resolvedAccounts.authority.value = context.identity;
}

// 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 = getCloseAccountsInstructionDataSerializer().serialize({});

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

return transactionBuilder([
{ instruction: { keys, programId, data }, signers, bytesCreatedOnChain },
]);
}
2 changes: 2 additions & 0 deletions clients/js/src/generated/instructions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export * from './bubblegumSetCollectionSize';
export * from './burnEditionNft';
export * from './burnNft';
export * from './burnV1';
export * from './closeAccounts';
export * from './closeEscrowAccount';
export * from './collect';
export * from './convertMasterEditionV1ToV2';
Expand Down Expand Up @@ -44,6 +45,7 @@ export * from './printV1';
export * from './printV2';
export * from './puffMetadata';
export * from './removeCreatorVerification';
export * from './resize';
export * from './revokeAuthorityItemV1';
export * from './revokeCollectionAuthority';
export * from './revokeCollectionItemV1';
Expand Down
155 changes: 155 additions & 0 deletions clients/js/src/generated/instructions/resize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/**
* 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,
Pda,
PublicKey,
Signer,
TransactionBuilder,
transactionBuilder,
} from '@metaplex-foundation/umi';
import {
Serializer,
mapSerializer,
struct,
u8,
} from '@metaplex-foundation/umi/serializers';
import { findMasterEditionPda, findMetadataPda } from '../accounts';
import {
ResolvedAccount,
ResolvedAccountsWithIndices,
expectPublicKey,
getAccountMetasAndSigners,
} from '../shared';

// Accounts.
export type ResizeInstructionAccounts = {
/** The metadata account of the digital asset */
metadata?: PublicKey | Pda;
/** The master edition or edition account of the digital asset, an uninitialized account for fungible assets */
edition?: PublicKey | Pda;
/** Mint of token asset */
mint: PublicKey | Pda;
/** The recipient of the excess rent and authority if the authority account is not present */
payer?: PublicKey | Pda | Signer;
/** Owner of the asset for (p)NFTs, or mint authority for fungible assets, if different from the payer */
authority?: Signer;
/** Token or Associated Token account */
token?: PublicKey | Pda;
/** System program */
systemProgram?: PublicKey | Pda;
};

// Data.
export type ResizeInstructionData = { discriminator: number };

export type ResizeInstructionDataArgs = {};

export function getResizeInstructionDataSerializer(): Serializer<
ResizeInstructionDataArgs,
ResizeInstructionData
> {
return mapSerializer<ResizeInstructionDataArgs, any, ResizeInstructionData>(
struct<ResizeInstructionData>([['discriminator', u8()]], {
description: 'ResizeInstructionData',
}),
(value) => ({ ...value, discriminator: 56 })
) as Serializer<ResizeInstructionDataArgs, ResizeInstructionData>;
}

// Instruction.
export function resize(
context: Pick<Context, 'eddsa' | 'payer' | 'programs'>,
input: ResizeInstructionAccounts
): TransactionBuilder {
// Program ID.
const programId = context.programs.getPublicKey(
'mplTokenMetadata',
'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'
);

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

// Default values.
if (!resolvedAccounts.metadata.value) {
resolvedAccounts.metadata.value = findMetadataPda(context, {
mint: expectPublicKey(resolvedAccounts.mint.value),
});
}
if (!resolvedAccounts.edition.value) {
resolvedAccounts.edition.value = findMasterEditionPda(context, {
mint: expectPublicKey(resolvedAccounts.mint.value),
});
}
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 = getResizeInstructionDataSerializer().serialize({});

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

return transactionBuilder([
{ instruction: { keys, programId, data }, signers, bytesCreatedOnChain },
]);
}
Loading

0 comments on commit 7c95f99

Please sign in to comment.