From 0148128ef09d2a31be67aa549a77dc84c9d198bf Mon Sep 17 00:00:00 2001 From: ara <226676426+ara-stock@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:51:26 +0900 Subject: [PATCH] js: Use UTF-8 byte length for metadata string prefixes Co-Authored-By: Claude Opus 5.5 --- clients/js-legacy/tests/transactions.test.ts | 36 ++++++++++++++++++++ clients/js/src/instructions.ts | 15 ++++---- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/clients/js-legacy/tests/transactions.test.ts b/clients/js-legacy/tests/transactions.test.ts index 437309a5..a05ffa7f 100644 --- a/clients/js-legacy/tests/transactions.test.ts +++ b/clients/js-legacy/tests/transactions.test.ts @@ -432,6 +432,42 @@ test('update metadata', async (t) => { ); }); +test('update metadata with non-ascii name', async (t) => { + const authorizedWithdrawer = new Keypair(); + + const context = await startWithContext(authorizedWithdrawer.publicKey); + const svm = context.svm; + const payer = context.payer; + const connection = new LiteConnection(svm, payer); + + const voteAccountAddress = new PublicKey(voteAccount.pubkey); + const poolAddress = await findPoolAddress(SinglePoolProgram.programId, voteAccountAddress); + const poolMintAddress = await findPoolMintAddress(SinglePoolProgram.programId, poolAddress); + const poolMetadataAddress = findMplMetadataAddress(poolMintAddress); + + let transaction = await SinglePoolProgram.initialize( + connection, + voteAccountAddress, + payer.publicKey, + ); + await processTransaction(context, transaction); + + const newName = 'Café Staking ☀'; + const newSymbol = 'stkÉ'; + transaction = await SinglePoolProgram.updateTokenMetadata( + voteAccountAddress, + authorizedWithdrawer.publicKey, + newName, + newSymbol, + ); + await processTransaction(context, transaction, [authorizedWithdrawer]); + + const metadataAccount = svm.getAccount(poolMetadataAddress); + const metadata = new TextDecoder().decode(metadataAccount.data); + t.true(metadata.indexOf(newName) > -1, 'metadata name has been updated'); + t.true(metadata.indexOf(newSymbol) > -1, 'metadata symbol has been updated'); +}); + test('get vote account address', async (t) => { const context = await startWithContext(); const svm = context.svm; diff --git a/clients/js/src/instructions.ts b/clients/js/src/instructions.ts index 7b81349d..f88b48a0 100644 --- a/clients/js/src/instructions.ts +++ b/clients/js/src/instructions.ts @@ -407,14 +407,17 @@ export async function updateTokenMetadataInstruction( const mplMetadata = await findMplMetadataAddress(mint); const text = new TextEncoder(); + const nameBytes = text.encode(tokenName); + const symbolBytes = text.encode(tokenSymbol); + const uriBytes = text.encode(tokenUri); const data = new Uint8Array([ SinglePoolInstructionType.UpdateTokenMetadata, - ...getU32Encoder().encode(tokenName.length), - ...text.encode(tokenName), - ...getU32Encoder().encode(tokenSymbol.length), - ...text.encode(tokenSymbol), - ...getU32Encoder().encode(tokenUri.length), - ...text.encode(tokenUri), + ...getU32Encoder().encode(nameBytes.length), + ...nameBytes, + ...getU32Encoder().encode(symbolBytes.length), + ...symbolBytes, + ...getU32Encoder().encode(uriBytes.length), + ...uriBytes, ]); return {