mpl-token-metadata
mpl-token-metadata copied to clipboard
Cannot update "Update Authority" on SPL token created with Metaplex
I create an SPL token using metaplex with specific metadata using the following code. In the process I also revoke Mint and Freeze authority.
const createToken = async () => {
if (!userPublicKey) {
console.error('User public key not found');
return;
}
try {
const metadata = {
name: "RNG Gaming",
symbol: "RNG",
uri: "https://ensagent.mypinata.cloud/ipfs/Qm..."
};
const mint = generateSigner(umi);
const initialSupply = 1000000000000000;
console.log('Creating token: ', metadata.name)
await createAndMint(umi, {
mint,
authority: umi.identity,
name: metadata.name,
symbol: metadata.symbol,
uri: metadata.uri,
sellerFeeBasisPoints: percentAmount(0),
decimals: 7,
amount: initialSupply,
tokenOwner: userPublicKey,
tokenStandard: TokenStandard.Fungible,
}).sendAndConfirm(umi);
const token_mint_pub_key = new PublicKey(mint.publicKey)
await setToken(token_mint_pub_key);
// Revoke the mint & freeze authority
const transaction = new Transaction().add(
createSetAuthorityInstruction(
token_mint_pub_key,
userPublicKey,
AuthorityType.MintTokens,
null,
[],
TOKEN_PROGRAM_ID
),
createSetAuthorityInstruction(
token_mint_pub_key,
userPublicKey,
AuthorityType.FreezeAccount,
null,
[],
TOKEN_PROGRAM_ID
)
);
const { blockhash } = await connection.getRecentBlockhash();
transaction.recentBlockhash = blockhash;
transaction.feePayer = userPublicKey;
const signature = await sendTransaction(transaction, connection);
console.log('Transaction signature:', signature);
} catch (error) {
...
...
}
};
This successfully creates the appropriate token
Now, what I am attempting but failing at is revoking the Update Authority.
This is my code to revoke Update Authority
const revokeUpdate = async () => {
try {
const mintAddress = publicKey(MAINNET_RNG_TOKEN_MINT);
const initialMetadata = await fetchMetadataFromSeeds(umi, { mint: mintAddress });
console.log("Initial metadata:", initialMetadata);
const updateInstruction = updateV1(umi, {
mint: mintAddress,
authority: metadata_wallet_signer,
data: {
...initialMetadata,
},
newUpdateAuthority: null,
isMutable: false,
});
const result = await updateInstruction.sendAndConfirm(umi);
const newMetadata = await fetchMetadataFromSeeds(umi, { mint: mintAddress });
console.log("new metadata:", newMetadata);
} catch (error) {
console.error("Error in revokeAuthorities:", error);
if (error.stack) {
console.error("Stack trace:", error.stack);
}
}
};
Please note the relevant console logs
Initial metadata: {
name : "RNG Gaming",
symbol: "RNG",
isMutable: true,
updateAuthority: "DQ3...",
uri : "https://ensagent.mypinata.cloud/ipfs/Qm..."
....
....
}
AND
new metadata: {
name : "RNG Gaming",
symbol: "RNG",
isMutable: false,
updateAuthority: "DQ3...",
uri : "https://ensagent.mypinata.cloud/ipfs/Qm..."
....
....
}
Please note that the ONLY thing that changes is the isMutable field. The updateAuthority field remains unchanged. This behavior is true even if I send two separate updateInstruction, the first ONLY changing the updateAuthority and the second ONLY changing the isMutable fields.
I should note, the account I am using to sign/send the transactions is the same account which has the Update Authority on the token.
What is happening, what am I doing wrong? And how can I fix it!
Hey,
To remove the update authority account key you probably need to pass in none() instead of null.
In general this should not be required though. As soon as the metadata is set to isMutable: false the update authority cannot be used for anything either way.
Thank you for your feedback.
Unfortunetly your provided solution does not work...
import { none } from '@metaplex-foundation/umi'
const revokUpdateAuthority = async () => {
try {
const mintAddress = publicKey(MAINNET_RNG_TOKEN_MINT);
const initialMetadata = await fetchMetadataFromSeeds(umi, { mint: mintAddress });
console.log("Initial metadata:", initialMetadata);
const updateInstruction = updateV1(umi, {
mint: mintAddress,
authority: metadata_wallet_signer,
data: {
...initialMetadata,
},
newUpdateAuthority: none(),
isMutable: false,
});
const result = await updateInstruction.sendAndConfirm(umi);
const newMetadata = await fetchMetadataFromSeeds(umi, { mint: mintAddress });
console.log("new metadata:", newMetadata);
} catch (error) {
...
...
}
}
};
This produces the exact same Initial metadata & new metadata as before.
Please open this ticket, as there has been no working solution provided.
Let’s start over. What is it that’s not working? You can not update metadata after isMutable was set to false, as mentioned before. So what do you want to achieve in addition with removing your address?
I need to ensure that a token successfully has its Update Authority set to None/null.
Right now, every SPL token I create with metaplex has its Update Authority as the minter of the token. I can successfully revoke Mint & Freeze Authority, meaning those two authorities are set to null.
So when a wallet checks those Authorities, the wallets correctly show the user that this token has renounced those Authorities and that the token is safe from those attacks.
Several popular wallets, including Phantom, show the user if the token has renounced its Update Authority. Even though I can set isMutable: false,, the wallets and rug checking websites show that the token metadata is mutable because an Update Authority is set.
So from a users perspective, they are buying into a token that can change its picture and other metadata.
That is highly problematic for me. All I need to do is set the Update Authority to null just as I have for Freeze & Mint Authorities.
Does that make sense friend? I am struggling with setting the Update Authority to None/null and I have a feeling that metaplex is at fault here. This should be a trivial matter to do, yet it is not.
I want to create the safest token possible for users, and I want that token to be presented accurately to users... meaning that all relevant Authorities are revoked and set to None/null. This will present the token in the best possible light in wallets and rug checking websites.
The fact I can set the token to isMutable: false does nothing for how the token is presented and I should be able to change the update authority if I want to. But right now I cannot and ive tried for several days now, that is why I am here asking for help.
I appreciate your response but I need a viable replicable solution and I still do not have one after days of trying. This is very bad for me.
hi @0xlucyy can u give me a clue on how to revoke the Mint & Freeze? Because when i use Token Metadata Program to mint NFT, it auto set the PDA as mint & freeze key, when i try to unlock/thaw, it need the mint & freeze authority signer and they are derived key and i don't know how to sign with it.
Hey, To remove the update authority account key you probably need to pass in
none()instead ofnull. In general this should not be required though. As soon as the metadata is set toisMutable: falsethe update authority cannot be used for anything either way.
Passing none() as newUpdateAuthority does not work as you said.
import { none } from "@metaplex-foundation/umi";
import { updateAsUpdateAuthorityV2 } from "@metaplex-foundation/mpl-token-metadata";
const newOnChainMetadata = {/*...*/}
const txBuilder = updateAsUpdateAuthorityV2(umi, {
mint: fromWeb3JsPublicKey(mint),
data: newOnChainMetadata,
newUpdateAuthority: none(),
})
Upon executing this, updateAuthority will not be changed and explorer.solana.com will show the same authority as it was.
Also having this issue. Either passing null or none() does not change the metadata's update authority address.
Did this ever get fixed, if so, how?
Any news on this?
I am experiencing the same issue. As a temporary workaround, I assigned the update authority to the system program. By doing this, the update authority is essentially prevented from being updated.
const newAuthority = publicKey("11111111111111111111111111111111");
updateV1(umi, {
isMutable: false,
mint: mint.publicKey,
authority: authority,
newUpdateAuthority: newAuthority
})
serializedData Uint8Array(11) [
50, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0
]
Here is the instruction data returned when the updateV1 function is called with mint and authority, while updateAuthority is set to none() or null. When deserialized, it produces the following result:
deserializedData [
{
discriminator: 50,
updateV1Discriminator: 0,
newUpdateAuthority: { __option: 'None' },
data: { __option: 'None' },
primarySaleHappened: { __option: 'None' },
isMutable: { __option: 'None' },
collection: { __kind: 'None' },
collectionDetails: { __kind: 'None' },
uses: { __kind: 'None' },
ruleSet: { __kind: 'None' },
authorizationData: { __option: 'None' }
},
11
]
When a valid address is provided, the updateAuthority is transferred correctly. However, an exceptional bug occurs when none or null is used.
Hey guys, looking at the Metaplex Token Metadata program source code,
the update_authority must be a Pubkey
pub struct Metadata {
/// Account discriminator.
pub key: Key,
/// Address of the update authority.
#[cfg_attr(feature = "serde-feature", serde(with = "As::<DisplayFromStr>"))]
pub update_authority: Pubkey,
and there are no state variables to keep track of whether a Metadata account's authority is renounced.
Hence, the way to renounce the update authority is to set it to the System Program address like what @Resister-boy has done above.
I also confirmed this with @blockiosaurus