Skip to content

Commit

Permalink
MET-96: Add Inscription support for Token22 (#11)
Browse files Browse the repository at this point in the history
* fixed typo in the command that launches tests for the js client

* Added support for SPL Token program 2022

* Updated clients tests accordingly to added Token22 support
  • Loading branch information
kstepanovdev authored Mar 18, 2024
1 parent 7838d40 commit ff08a1d
Show file tree
Hide file tree
Showing 8 changed files with 402 additions and 35 deletions.
6 changes: 5 additions & 1 deletion clients/js/test/_setup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable import/no-extraneous-dependencies */
import { createUmi as basecreateUmi } from '@metaplex-foundation/umi-bundle-tests';
import { Umi } from '@metaplex-foundation/umi';
import { PublicKey, Umi, publicKey } from '@metaplex-foundation/umi';
import pMap from 'p-map';
import {
mplInscription,
Expand All @@ -9,6 +9,10 @@ import {
safeFetchInscriptionShard,
} from '../src';

export const SPL_TOKEN_2022_PROGRAM_ID: PublicKey = publicKey(
'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'
);

export const createUmi = async () => {
const umi = (await basecreateUmi()).use(mplInscription());

Expand Down
105 changes: 97 additions & 8 deletions clients/js/test/initializeFromMint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
mintV1,
mplTokenMetadata,
} from '@metaplex-foundation/mpl-token-metadata';
import { publicKey as publicKeySerializer } from '@metaplex-foundation/umi/serializers';
import { SPL_ASSOCIATED_TOKEN_PROGRAM_ID } from '@metaplex-foundation/mpl-toolbox';
import {
AssociatedInscription,
DataType,
Expand All @@ -19,7 +21,7 @@ import {
findMintInscriptionPda,
initializeFromMint,
} from '../src';
import { createUmi } from './_setup';
import { SPL_TOKEN_2022_PROGRAM_ID, createUmi } from './_setup';

test('it can initialize a Mint Inscription account', async (t) => {
// Given a Umi instance and a new signer.
Expand All @@ -40,14 +42,101 @@ test('it can initialize a Mint Inscription account', async (t) => {
tokenStandard: TokenStandard.NonFungible,
}).sendAndConfirm(umi);

const inscriptionAccount = await findMintInscriptionPda(umi, {
const inscriptionAccount = findMintInscriptionPda(umi, {
mint: mint.publicKey,
});
const inscriptionMetadataAccount = await findInscriptionMetadataPda(umi, {
const inscriptionMetadataAccount = findInscriptionMetadataPda(umi, {
inscriptionAccount: inscriptionAccount[0],
});

const inscriptionShardAccount = await findInscriptionShardPda(umi, {
const inscriptionShardAccount = findInscriptionShardPda(umi, {
shardNumber: 0,
});
const shardDataBefore = await fetchInscriptionShard(
umi,
inscriptionShardAccount
);

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

// When we create a new account.
await initializeFromMint(umi, {
mintAccount: mint.publicKey,
inscriptionShardAccount,
}).sendAndConfirm(umi);

// Then an account was created with the correct data.
const inscriptionMetadata = await fetchInscriptionMetadata(
umi,
inscriptionMetadataAccount
);

const shardDataAfter = await fetchInscriptionShard(
umi,
inscriptionShardAccount
);
t.is(shardDataBefore.count + BigInt(1), shardDataAfter.count);

t.like(inscriptionMetadata, <InscriptionMetadata>{
key: Key.MintInscriptionMetadataAccount,
inscriptionAccount: inscriptionAccount[0],
bump: inscriptionMetadataAccount[1],
dataType: DataType.Uninitialized,
inscriptionRank:
shardDataBefore.count * BigInt(32) + BigInt(shardDataBefore.shardNumber),
updateAuthorities: [umi.identity.publicKey],
associatedInscriptions: [] as AssociatedInscription[],
mint: some(mint.publicKey),
});

const jsonData = await umi.rpc.getAccount(inscriptionAccount[0]);
if (jsonData.exists) {
t.like(jsonData, {
owner: MPL_INSCRIPTION_PROGRAM_ID,
data: Uint8Array.from([]),
});
}
});

test('it can initialize a Mint Inscription account from SPL Token 2022', async (t) => {
// Given a Umi instance and a new signer.
const umi = await createUmi();
umi.use(mplTokenMetadata());

const mint = generateSigner(umi);
await createV1(umi, {
mint,
name: 'My Programmable NFT',
uri: 'https://arweave.net/LcjCf-NDr5bhCJ0YMKGlc8m8qT_J6TDWtIuW8lbu0-A',
sellerFeeBasisPoints: percentAmount(5.5),
splTokenProgram: SPL_TOKEN_2022_PROGRAM_ID,
tokenStandard: TokenStandard.NonFungible,
}).sendAndConfirm(umi);

// And we derive the associated token account from SPL Token 2022.
const [token] = umi.eddsa.findPda(SPL_ASSOCIATED_TOKEN_PROGRAM_ID, [
publicKeySerializer().serialize(umi.identity.publicKey),
publicKeySerializer().serialize(SPL_TOKEN_2022_PROGRAM_ID),
publicKeySerializer().serialize(mint.publicKey),
]);

// When we mint one token.
await mintV1(umi, {
mint: mint.publicKey,
token,
tokenOwner: umi.identity.publicKey,
splTokenProgram: SPL_TOKEN_2022_PROGRAM_ID,
tokenStandard: TokenStandard.NonFungible,
}).sendAndConfirm(umi);

const inscriptionAccount = findMintInscriptionPda(umi, {
mint: mint.publicKey,
});
const inscriptionMetadataAccount = findInscriptionMetadataPda(umi, {
inscriptionAccount: inscriptionAccount[0],
});

const inscriptionShardAccount = findInscriptionShardPda(umi, {
shardNumber: 0,
});
const shardDataBefore = await fetchInscriptionShard(
Expand Down Expand Up @@ -116,7 +205,7 @@ test('it cannot initialize a Mint Inscription account if it is not the update au
tokenStandard: TokenStandard.NonFungible,
}).sendAndConfirm(umi);

const inscriptionShardAccount = await findInscriptionShardPda(umi, {
const inscriptionShardAccount = findInscriptionShardPda(umi, {
shardNumber: 0,
});
const shardDataBefore = await fetchInscriptionShard(
Expand Down Expand Up @@ -160,7 +249,7 @@ test('it can initialize a Mint Inscription account with separate authority', asy
creators: [{ address: authority.publicKey, verified: false, share: 100 }],
}).sendAndConfirm(umi);

const inscriptionShardAccount = await findInscriptionShardPda(umi, {
const inscriptionShardAccount = findInscriptionShardPda(umi, {
shardNumber: 0,
});
const shardDataBefore = await fetchInscriptionShard(
Expand All @@ -174,10 +263,10 @@ test('it can initialize a Mint Inscription account with separate authority', asy
authority,
}).sendAndConfirm(umi);

const inscriptionAccount = await findMintInscriptionPda(umi, {
const inscriptionAccount = findMintInscriptionPda(umi, {
mint: mint.publicKey,
});
const inscriptionMetadataAccount = await findInscriptionMetadataPda(umi, {
const inscriptionMetadataAccount = findInscriptionMetadataPda(umi, {
inscriptionAccount: inscriptionAccount[0],
});

Expand Down
89 changes: 83 additions & 6 deletions clients/js/test/setMint.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
mintV1,
mplTokenMetadata,
} from '@metaplex-foundation/mpl-token-metadata';
import { SPL_ASSOCIATED_TOKEN_PROGRAM_ID } from '@metaplex-foundation/mpl-toolbox';
import { publicKey as publicKeySerializer } from '@metaplex-foundation/umi/serializers';
import {
AssociatedInscription,
DataType,
Expand All @@ -23,7 +25,7 @@ import {
initializeFromMint,
setMint,
} from '../src';
import { createUmi } from './_setup';
import { createUmi, SPL_TOKEN_2022_PROGRAM_ID } from './_setup';

test('it can set the mint on a Mint Inscription account', async (t) => {
// Given a Umi instance and a new signer.
Expand All @@ -44,10 +46,10 @@ test('it can set the mint on a Mint Inscription account', async (t) => {
tokenStandard: TokenStandard.NonFungible,
}).sendAndConfirm(umi);

const inscriptionAccount = await findMintInscriptionPda(umi, {
const inscriptionAccount = findMintInscriptionPda(umi, {
mint: mint.publicKey,
});
const inscriptionMetadataAccount = await findInscriptionMetadataPda(umi, {
const inscriptionMetadataAccount = findInscriptionMetadataPda(umi, {
inscriptionAccount: inscriptionAccount[0],
});

Expand Down Expand Up @@ -110,7 +112,7 @@ test('it cannot set the mint on an Inscription account that is not derived from
// We are creating an inscription account that is not derived from a mint and is not a PDA.
const inscriptionAccount = generateSigner(umi);

const inscriptionMetadataAccount = await findInscriptionMetadataPda(umi, {
const inscriptionMetadataAccount = findInscriptionMetadataPda(umi, {
inscriptionAccount: inscriptionAccount.publicKey,
});

Expand Down Expand Up @@ -171,10 +173,10 @@ test('it cannot set the wrong mint on a Mint Inscription account', async (t) =>
tokenStandard: TokenStandard.NonFungible,
}).sendAndConfirm(umi);

const inscriptionAccount = await findMintInscriptionPda(umi, {
const inscriptionAccount = findMintInscriptionPda(umi, {
mint: mint.publicKey,
});
const inscriptionMetadataAccount = await findInscriptionMetadataPda(umi, {
const inscriptionMetadataAccount = findInscriptionMetadataPda(umi, {
inscriptionAccount: inscriptionAccount[0],
});

Expand All @@ -201,3 +203,78 @@ test('it cannot set the wrong mint on a Mint Inscription account', async (t) =>
// And it fails because the derivation from the wrong mint is invalid.
await t.throwsAsync(promise, { name: 'DerivedKeyInvalid' });
});

test('it can mint from SPL Token 2022', async (t) => {
// Given a created NonFungible.
const umi = await createUmi();
umi.use(mplTokenMetadata());
const mint = generateSigner(umi);

await createV1(umi, {
mint,
name: 'My Programmable NFT',
uri: 'https://arweave.net/LcjCf-NDr5bhCJ0YMKGlc8m8qT_J6TDWtIuW8lbu0-A',
sellerFeeBasisPoints: percentAmount(5.5),
splTokenProgram: SPL_TOKEN_2022_PROGRAM_ID,
tokenStandard: TokenStandard.NonFungible,
}).sendAndConfirm(umi);

// And we derive the associated token account from SPL Token 2022.
const [token] = umi.eddsa.findPda(SPL_ASSOCIATED_TOKEN_PROGRAM_ID, [
publicKeySerializer().serialize(umi.identity.publicKey),
publicKeySerializer().serialize(SPL_TOKEN_2022_PROGRAM_ID),
publicKeySerializer().serialize(mint.publicKey),
]);

// When we mint one token.
await mintV1(umi, {
mint: mint.publicKey,
token,
tokenOwner: umi.identity.publicKey,
splTokenProgram: SPL_TOKEN_2022_PROGRAM_ID,
tokenStandard: TokenStandard.NonFungible,
}).sendAndConfirm(umi);

const inscriptionAccount = findMintInscriptionPda(umi, {
mint: mint.publicKey,
});
const inscriptionMetadataAccount = findInscriptionMetadataPda(umi, {
inscriptionAccount: inscriptionAccount[0],
});

let builder = new TransactionBuilder();

// When we create a new account.
builder = builder.append(
initializeFromMint(umi, {
mintAccount: mint.publicKey,
})
);

// Set the mint on the account.
builder = builder.append(
setMint(umi, {
mintInscriptionAccount: inscriptionAccount,
inscriptionMetadataAccount,
mintAccount: mint.publicKey,
})
);

await builder.sendAndConfirm(umi);

// Then an account was created with the correct data.
const inscriptionMetadata = await fetchInscriptionMetadata(
umi,
inscriptionMetadataAccount
);

t.like(inscriptionMetadata, <InscriptionMetadata>{
key: Key.MintInscriptionMetadataAccount,
inscriptionAccount: inscriptionAccount[0],
bump: inscriptionMetadataAccount[1],
dataType: DataType.Uninitialized,
updateAuthorities: [umi.identity.publicKey],
associatedInscriptions: [] as AssociatedInscription[],
mint: some(mint.publicKey),
});
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"programs:debug": "./configs/scripts/program/test.sh",
"programs:clean": "./configs/scripts/program/clean.sh",
"clients:rust:test": "./configs/scripts/client/test-rust.sh",
"clients:js:test": "./configs/sripts/client/test-js.sh",
"clients:js:test": "./configs/scripts/client/test-js.sh",
"generate": "pnpm generate:idls && pnpm generate:clients",
"generate:idls": "node ./configs/shank.cjs",
"generate:clients": "node ./configs/kinobi.cjs",
Expand Down
Loading

0 comments on commit ff08a1d

Please sign in to comment.