Skip to content

Commit

Permalink
token metadata js: update test suites (solana-labs#6015)
Browse files Browse the repository at this point in the history
  • Loading branch information
Joe C authored Dec 20, 2023
1 parent 47a646c commit da94833
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 182 deletions.
230 changes: 110 additions & 120 deletions token-metadata/js/test/instruction.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { PublicKey, TransactionInstruction } from '@solana/web3.js';
import { expect } from 'chai';

import {
Expand All @@ -7,7 +6,29 @@ import {
createRemoveKeyInstruction,
createUpdateAuthorityInstruction,
createUpdateFieldInstruction,
getFieldCodec,
getFieldConfig,
} from '../src';
import type { StructToDecoderTuple } from '@solana/codecs-data-structures';
import { getBooleanDecoder, getBytesDecoder, getDataEnumCodec, getStructDecoder } from '@solana/codecs-data-structures';
import { getStringDecoder } from '@solana/codecs-strings';
import { splDiscriminate } from '@solana/spl-type-length-value';
import { getU64Decoder } from '@solana/codecs-numbers';
import type { Option } from '@solana/options';
import { getOptionDecoder, some } from '@solana/options';
import { PublicKey, type TransactionInstruction } from '@solana/web3.js';

function checkPackUnpack<T extends object>(
instruction: TransactionInstruction,
discriminator: Uint8Array,
layout: StructToDecoderTuple<T>,
values: T
) {
expect(instruction.data.subarray(0, 8)).to.deep.equal(discriminator);
const decoder = getStructDecoder(layout);
const unpacked = decoder.decode(instruction.data.subarray(8));
expect(unpacked).to.deep.equal(values);
}

describe('Token Metadata Instructions', () => {
const programId = new PublicKey('22222222222222222222222222222222222222222222');
Expand All @@ -17,150 +38,119 @@ describe('Token Metadata Instructions', () => {
const mintAuthority = new PublicKey('66666666666666666666666666666666666666666666');

it('Can create Initialize Instruction', () => {
const instruction = createInitializeInstruction({
programId,
metadata,
updateAuthority,
mint,
mintAuthority,
name: 'My test token',
symbol: 'TEST',
uri: 'http://test.test',
});

expect(instruction).to.deep.equal(
new TransactionInstruction({
const name = 'My test token';
const symbol = 'TEST';
const uri = 'http://test.test';
checkPackUnpack(
createInitializeInstruction({
programId,
keys: [
{ isSigner: false, isWritable: true, pubkey: metadata },
{ isSigner: false, isWritable: false, pubkey: updateAuthority },
{ isSigner: false, isWritable: false, pubkey: mint },
{ isSigner: true, isWritable: false, pubkey: mintAuthority },
],
data: Buffer.from([
// Output of rust implementation
210, 225, 30, 162, 88, 184, 77, 141, 13, 0, 0, 0, 77, 121, 32, 116, 101, 115, 116, 32, 116, 111,
107, 101, 110, 4, 0, 0, 0, 84, 69, 83, 84, 16, 0, 0, 0, 104, 116, 116, 112, 58, 47, 47, 116, 101,
115, 116, 46, 116, 101, 115, 116,
]),
})
metadata,
updateAuthority,
mint,
mintAuthority,
name,
symbol,
uri,
}),
splDiscriminate('spl_token_metadata_interface:initialize_account'),
[
['name', getStringDecoder()],
['symbol', getStringDecoder()],
['uri', getStringDecoder()],
],
{ name, symbol, uri }
);
});

it('Can create Update Field Instruction', () => {
const instruction = createUpdateFieldInstruction({
programId,
metadata,
updateAuthority,
field: 'MyTestField',
value: 'http://test.uri',
});

expect(instruction).to.deep.equal(
new TransactionInstruction({
const field = 'MyTestField';
const value = 'http://test.uri';
checkPackUnpack(
createUpdateFieldInstruction({
programId,
keys: [
{ isSigner: false, isWritable: true, pubkey: metadata },
{ isSigner: true, isWritable: false, pubkey: updateAuthority },
],
data: Buffer.from([
// Output of rust implementation
221, 233, 49, 45, 181, 202, 220, 200, 3, 11, 0, 0, 0, 77, 121, 84, 101, 115, 116, 70, 105, 101, 108,
100, 15, 0, 0, 0, 104, 116, 116, 112, 58, 47, 47, 116, 101, 115, 116, 46, 117, 114, 105,
]),
})
metadata,
updateAuthority,
field,
value,
}),
splDiscriminate('spl_token_metadata_interface:updating_field'),
[
['key', getDataEnumCodec(getFieldCodec())],
['value', getStringDecoder()],
],
{ key: getFieldConfig(field), value }
);
});

it('Can create Update Field Instruction with Field Enum', () => {
const instruction = createUpdateFieldInstruction({
programId,
metadata,
updateAuthority,
field: 'Name',
value: 'http://test.uri',
});

expect(instruction).to.deep.equal(
new TransactionInstruction({
const field = 'Name';
const value = 'http://test.uri';
checkPackUnpack(
createUpdateFieldInstruction({
programId,
keys: [
{ isSigner: false, isWritable: true, pubkey: metadata },
{ isSigner: true, isWritable: false, pubkey: updateAuthority },
],
data: Buffer.from([
// Output of rust implementation
221, 233, 49, 45, 181, 202, 220, 200, 0, 15, 0, 0, 0, 104, 116, 116, 112, 58, 47, 47, 116, 101, 115,
116, 46, 117, 114, 105,
]),
})
metadata,
updateAuthority,
field,
value,
}),
splDiscriminate('spl_token_metadata_interface:updating_field'),
[
['key', getDataEnumCodec(getFieldCodec())],
['value', getStringDecoder()],
],
{ key: getFieldConfig(field), value }
);
});

it('Can create Remove Key Instruction', () => {
const instruction = createRemoveKeyInstruction({
programId,
metadata,
updateAuthority: updateAuthority,
key: 'MyTestField',
idempotent: true,
});

expect(instruction).to.deep.equal(
new TransactionInstruction({
checkPackUnpack(
createRemoveKeyInstruction({
programId,
keys: [
{ isSigner: false, isWritable: true, pubkey: metadata },
{ isSigner: true, isWritable: false, pubkey: updateAuthority },
],
data: Buffer.from([
// Output of rust implementation
234, 18, 32, 56, 89, 141, 37, 181, 1, 11, 0, 0, 0, 77, 121, 84, 101, 115, 116, 70, 105, 101, 108,
100,
]),
})
metadata,
updateAuthority: updateAuthority,
key: 'MyTestField',
idempotent: true,
}),
splDiscriminate('spl_token_metadata_interface:remove_key_ix'),
[
['idempotent', getBooleanDecoder()],
['key', getStringDecoder()],
],
{ idempotent: true, key: 'MyTestField' }
);
});

it('Can create Update Authority Instruction', () => {
const instruction = createUpdateAuthorityInstruction({
programId,
metadata,
oldAuthority: updateAuthority,
newAuthority: PublicKey.default,
});

expect(instruction).to.deep.equal(
new TransactionInstruction({
const newAuthority = PublicKey.default;
checkPackUnpack(
createUpdateAuthorityInstruction({
programId,
keys: [
{ isSigner: false, isWritable: true, pubkey: metadata },
{ isSigner: true, isWritable: false, pubkey: updateAuthority },
],
data: Buffer.from([
// Output of rust implementation
215, 228, 166, 228, 84, 100, 86, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
]),
})
metadata,
oldAuthority: updateAuthority,
newAuthority,
}),
splDiscriminate('spl_token_metadata_interface:update_the_authority'),
[['newAuthority', getBytesDecoder({ size: 32 })]],
{ newAuthority: Uint8Array.from(newAuthority.toBuffer()) }
);
});
it('Can create Emit Instruction', () => {
const instruction = createEmitInstruction({
programId,
metadata,
end: BigInt(10),
});

expect(instruction).to.deep.equal(
new TransactionInstruction({
it('Can create Emit Instruction', () => {
const start: Option<bigint> = some(0n);
const end: Option<bigint> = some(10n);
checkPackUnpack(
createEmitInstruction({
programId,
keys: [{ isSigner: false, isWritable: false, pubkey: metadata }],
data: Buffer.from([
// Output of rust implementation
250, 166, 180, 250, 13, 12, 184, 70, 0, 1, 10, 0, 0, 0, 0, 0, 0, 0,
]),
})
metadata,
start: 0n,
end: 10n,
}),
splDiscriminate('spl_token_metadata_interface:emitter'),
[
['start', getOptionDecoder(getU64Decoder())],
['end', getOptionDecoder(getU64Decoder())],
],
{ start, end }
);
});
});
87 changes: 25 additions & 62 deletions token-metadata/js/test/state.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,36 @@ import { expect } from 'chai';
import type { TokenMetadata } from '../src/state';
import { unpack, pack } from '../src';

function checkPackUnpack(tokenMetadata: TokenMetadata) {
const packed = pack(tokenMetadata);
const unpacked = unpack(packed);
expect(unpacked).to.deep.equal(tokenMetadata);
}

describe('Token Metadata State', () => {
it('Can pack and unpack as rust implementation', () => {
const meta = {
it('Can pack and unpack base token metadata', () => {
checkPackUnpack({
mint: PublicKey.default,
name: 'name',
symbol: 'symbol',
uri: 'uri',
additionalMetadata: [],
};

// From rust implementation
const bytes = Buffer.from([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 110, 97,
109, 101, 6, 0, 0, 0, 115, 121, 109, 98, 111, 108, 3, 0, 0, 0, 117, 114, 105, 0, 0, 0, 0,
]);
});
});

expect(pack(meta)).to.deep.equal(bytes);
expect(unpack(bytes)).to.deep.equal(meta);
it('Can pack and unpack with updateAuthority', () => {
checkPackUnpack({
updateAuthority: new PublicKey('44444444444444444444444444444444444444444444'),
mint: new PublicKey('55555555555555555555555555555555555555555555'),
name: 'name',
symbol: 'symbol',
uri: 'uri',
additionalMetadata: [],
});
});

it('Can pack and unpack as rust implementation with additionalMetadata', () => {
const meta: TokenMetadata = {
it('Can pack and unpack with additional metadata', () => {
checkPackUnpack({
mint: PublicKey.default,
name: 'new_name',
symbol: 'new_symbol',
Expand All @@ -35,43 +42,11 @@ describe('Token Metadata State', () => {
['key1', 'value1'],
['key2', 'value2'],
],
};
// From rust implementation
const bytes = Buffer.from([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 110, 101,
119, 95, 110, 97, 109, 101, 10, 0, 0, 0, 110, 101, 119, 95, 115, 121, 109, 98, 111, 108, 7, 0, 0, 0, 110,
101, 119, 95, 117, 114, 105, 2, 0, 0, 0, 4, 0, 0, 0, 107, 101, 121, 49, 6, 0, 0, 0, 118, 97, 108, 117, 101,
49, 4, 0, 0, 0, 107, 101, 121, 50, 6, 0, 0, 0, 118, 97, 108, 117, 101, 50,
]);

expect(pack(meta)).to.deep.equal(bytes);
expect(unpack(bytes)).to.deep.equal(meta);
});

it('Can pack and unpack with mint and updateAuthority', () => {
const meta = {
updateAuthority: new PublicKey('44444444444444444444444444444444444444444444'),
mint: new PublicKey('55555555555555555555555555555555555555555555'),
name: 'name',
symbol: 'symbol',
uri: 'uri',
additionalMetadata: [],
};

const bytes = Buffer.from([
45, 91, 65, 60, 101, 64, 222, 21, 12, 147, 115, 20, 77, 81, 51, 202, 76, 184, 48, 186, 15, 117, 103, 22,
172, 234, 14, 80, 215, 148, 53, 229, 60, 121, 172, 80, 135, 1, 40, 28, 16, 196, 153, 112, 103, 22, 239, 184,
102, 74, 235, 162, 191, 71, 52, 30, 59, 226, 189, 193, 31, 112, 71, 220, 4, 0, 0, 0, 110, 97, 109, 101, 6,
0, 0, 0, 115, 121, 109, 98, 111, 108, 3, 0, 0, 0, 117, 114, 105, 0, 0, 0, 0,
]);

expect(pack(meta)).to.deep.equal(bytes);
expect(unpack(bytes)).to.deep.equal(meta);
});
});

it('Can pack and unpack with mint, updateAuthority and additional metadata', () => {
const meta: TokenMetadata = {
it('Can pack and unpack with updateAuthority and additional metadata', () => {
checkPackUnpack({
updateAuthority: new PublicKey('44444444444444444444444444444444444444444444'),
mint: new PublicKey('55555555555555555555555555555555555555555555'),
name: 'name',
Expand All @@ -81,18 +56,6 @@ describe('Token Metadata State', () => {
['key1', 'value1'],
['key2', 'value2'],
],
};

const bytes = Buffer.from([
45, 91, 65, 60, 101, 64, 222, 21, 12, 147, 115, 20, 77, 81, 51, 202, 76, 184, 48, 186, 15, 117, 103, 22,
172, 234, 14, 80, 215, 148, 53, 229, 60, 121, 172, 80, 135, 1, 40, 28, 16, 196, 153, 112, 103, 22, 239, 184,
102, 74, 235, 162, 191, 71, 52, 30, 59, 226, 189, 193, 31, 112, 71, 220, 4, 0, 0, 0, 110, 97, 109, 101, 6,
0, 0, 0, 115, 121, 109, 98, 111, 108, 3, 0, 0, 0, 117, 114, 105, 2, 0, 0, 0, 4, 0, 0, 0, 107, 101, 121, 49,
6, 0, 0, 0, 118, 97, 108, 117, 101, 49, 4, 0, 0, 0, 107, 101, 121, 50, 6, 0, 0, 0, 118, 97, 108, 117, 101,
50,
]);

expect(pack(meta)).to.deep.equal(bytes);
expect(unpack(bytes)).to.deep.equal(meta);
});
});
});

0 comments on commit da94833

Please sign in to comment.