Skip to content

Commit

Permalink
Fixing unpacking for T22 Mints (#153)
Browse files Browse the repository at this point in the history
* Fixing to correct unpack for T22 mints.

* Fix linting and skip tests.

* Fixing feedback.
  • Loading branch information
blockiosaurus authored Nov 5, 2024
1 parent 76ea371 commit 7c1c905
Show file tree
Hide file tree
Showing 5 changed files with 415 additions and 11 deletions.
103 changes: 103 additions & 0 deletions clients/js/test/_setup.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/* eslint-disable import/no-extraneous-dependencies */
import {
Context,
generateSigner,
percentAmount,
publicKey,
PublicKey,
Signer,
TransactionBuilder,
transactionBuilder,
Umi,
} from '@metaplex-foundation/umi';
Expand All @@ -17,6 +19,19 @@ import {
TokenStandard,
verifyCreatorV1,
} from '../src';
import {
BurnTokenInstructionAccounts,
BurnTokenInstructionArgs,
BurnTokenInstructionDataArgs,
getAccountMetasAndSigners,
getBurnTokenInstructionDataSerializer,
getSetAuthorityInstructionDataSerializer,
ResolvedAccount,
ResolvedAccountsWithIndices,
SetAuthorityInstructionAccounts,
SetAuthorityInstructionArgs,
SetAuthorityInstructionDataArgs,
} from '@metaplex-foundation/mpl-toolbox';

export type TokenStandardKeys = keyof typeof TokenStandard;

Expand Down Expand Up @@ -142,3 +157,91 @@ export const createDigitalAssetWithVerifiedCreators = async (

return mint;
};

export function burnToken22(
context: Pick<Context, 'identity' | 'programs'>,
input: BurnTokenInstructionAccounts & BurnTokenInstructionArgs
): TransactionBuilder {
// Program ID.
const programId = SPL_TOKEN_2022_PROGRAM_ID;

// Accounts.
const resolvedAccounts: ResolvedAccountsWithIndices = {
account: { index: 0, isWritable: true, value: input.account ?? null },
mint: { index: 1, isWritable: true, value: input.mint ?? null },
authority: { index: 2, isWritable: false, value: input.authority ?? null },
};

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

// Default values.
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 = getBurnTokenInstructionDataSerializer().serialize(
resolvedArgs as BurnTokenInstructionDataArgs
);

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

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

export function setAuthority22(
context: Pick<Context, 'programs'>,
input: SetAuthorityInstructionAccounts & SetAuthorityInstructionArgs
): TransactionBuilder {
// Program ID.
const programId = SPL_TOKEN_2022_PROGRAM_ID;

// Accounts.
const resolvedAccounts: ResolvedAccountsWithIndices = {
owned: { index: 0, isWritable: true, value: input.owned ?? null },
owner: { index: 1, isWritable: false, value: input.owner ?? null },
};

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

// 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 = getSetAuthorityInstructionDataSerializer().serialize(
resolvedArgs as SetAuthorityInstructionDataArgs
);

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

return transactionBuilder([
{ instruction: { keys, programId, data }, signers, bytesCreatedOnChain },
]);
}
97 changes: 96 additions & 1 deletion clients/js/test/close/fungible.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,31 @@ import {
generateSigner,
lamports,
MaybeRpcAccount,
percentAmount,
publicKey,
subtractAmounts,
} from '@metaplex-foundation/umi';
import { readFileSync } from 'fs';
import {
AuthorityType,
burnToken,
findAssociatedTokenPda,
setAuthority,
SPL_SYSTEM_PROGRAM_ID,
} from '@metaplex-foundation/mpl-toolbox';
import { createDigitalAssetWithToken, createUmi } from '../_setup';
import {
burnToken22,
createDigitalAssetWithToken,
createUmi,
setAuthority22,
SPL_TOKEN_2022_PROGRAM_ID,
} from '../_setup';
import {
closeAccounts,
createV1,
fetchDigitalAsset,
fetchDigitalAssetWithAssociatedToken,
mintV1,
TokenStandard,
} from '../../src';

Expand Down Expand Up @@ -87,6 +98,90 @@ test.skip('it can close ownerless metadata for a fungible with zero supply and n
t.deepEqual(subtractAmounts(lamportsAfter, lamportsBefore), metadataLamports);
});

test.skip('it can close ownerless metadata for a t22 fungible with zero supply and no mint authority', async (t) => {
const umi = await createUmi();
const mint = generateSigner(umi);
const closeAuthority = createSignerFromKeypair(
umi,
umi.eddsa.createKeypairFromSecretKey(
new Uint8Array(
JSON.parse(
readFileSync(
'/Users/kelliott/Metaplex/keys/C1oseLQExhuEzeBhsVbLtseSpVgvpHDbBj3PTevBCEBh.json'
).toString()
)
)
)
);

// const mint = await createDigitalAssetWithToken(umi, {
// name: 'Fungible',
// symbol: 'FUN',
// uri: 'https://example.com/nft.json',
// tokenStandard: TokenStandard.Fungible,
// amount: 1,
// });
await createV1(umi, {
mint,
name: 'Fungible',
symbol: 'FUN',
uri: 'https://example.com/nft.json',
sellerFeeBasisPoints: percentAmount(0),
splTokenProgram: SPL_TOKEN_2022_PROGRAM_ID,
tokenStandard: TokenStandard.Fungible,
}).sendAndConfirm(umi);

// And we derive the associated token account from SPL Token 2022.
const token = findAssociatedTokenPda(umi, {
mint: mint.publicKey,
owner: umi.identity.publicKey,
tokenProgramId: SPL_TOKEN_2022_PROGRAM_ID,
});

await mintV1(umi, {
mint: mint.publicKey,
token,
tokenOwner: umi.identity.publicKey,
amount: 1,
tokenStandard: TokenStandard.Fungible,
splTokenProgram: SPL_TOKEN_2022_PROGRAM_ID,
}).sendAndConfirm(umi);

const asset = await fetchDigitalAsset(umi, mint.publicKey);

await burnToken22(umi, {
account: token,
mint: mint.publicKey,
amount: 1,
}).sendAndConfirm(umi);

await setAuthority22(umi, {
owned: mint.publicKey,
owner: umi.identity,
authorityType: AuthorityType.MintTokens,
newAuthority: null,
}).sendAndConfirm(umi);

const metadataLamports = await umi.rpc.getBalance(asset.metadata.publicKey);
const lamportsBefore = await umi.rpc.getBalance(closeDestination);
await closeAccounts(umi, {
mint: mint.publicKey,
authority: closeAuthority,
destination: closeDestination,
}).sendAndConfirm(umi);

t.deepEqual(await umi.rpc.getAccount(asset.metadata.publicKey), <
MaybeRpcAccount
>{
publicKey: asset.metadata.publicKey,
exists: false,
});
t.deepEqual(await umi.rpc.getBalance(asset.metadata.publicKey), lamports(0));

const lamportsAfter = await umi.rpc.getBalance(closeDestination);
t.deepEqual(subtractAmounts(lamportsAfter, lamportsBefore), metadataLamports);
});

test.skip('it can close ownerless metadata for a fungible with zero supply and mint authority set to the system program', async (t) => {
const umi = await createUmi();
const closeAuthority = createSignerFromKeypair(
Expand Down
Loading

0 comments on commit 7c1c905

Please sign in to comment.