Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

token-cli: add command for updating metadata address #4810

Merged
merged 11 commits into from
Jul 21, 2023
141 changes: 141 additions & 0 deletions token/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ pub enum CommandName {
EnableCpiGuard,
DisableCpiGuard,
UpdateDefaultAccountState,
UpdateMetadataAddress,
WithdrawWithheldTokens,
SetTransferFee,
WithdrawExcessLamports,
Expand Down Expand Up @@ -2302,6 +2303,33 @@ async fn command_cpi_guard(
})
}

async fn command_update_metadata_pointer_address(
config: &Config<'_>,
token_pubkey: Pubkey,
authority: Pubkey,
new_metadata_address: Option<Pubkey>,
bulk_signers: BulkSigners,
) -> CommandResult {
if config.sign_only {
panic!("Config can not be sign-only for updating metadata pointer address.");
}

let token = token_client_from_config(config, &token_pubkey, None)?;
let res = token
.update_metadata_address(&authority, new_metadata_address, &bulk_signers)
.await?;

let tx_return = finish_tx(config, &res, false).await?;
Ok(match tx_return {
TransactionReturnData::CliSignature(signature) => {
config.output_format.formatted_string(&signature)
}
TransactionReturnData::CliSignOnlyData(sign_only_data) => {
config.output_format.formatted_string(&sign_only_data)
}
})
}

async fn command_update_default_account_state(
config: &Config<'_>,
token_pubkey: Pubkey,
Expand Down Expand Up @@ -3624,6 +3652,48 @@ fn app<'a, 'b>(
.nonce_args(true)
.offline_args(),
)
.subcommand(
SubCommand::with_name(CommandName::UpdateMetadataAddress.into())
.about("Updates metadata pointer address for the mint. Requires the metadata pointer extension.")
.arg(
Arg::with_name("token")
.validator(is_valid_pubkey)
.value_name("TOKEN_MINT_ADDRESS")
.takes_value(true)
.index(1)
.required(true)
.help("The address of the token mint to update the metadata pointer address"),
)
.arg(
Arg::with_name("metadata_address")
.index(2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add .validator(is_valid_pubkey) for this arg too? Otherwise, if someone inputs an invalid pubkey, it'll disable the metadata pointer address!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yupp, Done! and also sorry about this many commits. :)

.value_name("METADATA_ADDRESS")
.takes_value(true)
.required_unless("disable")
joncinque marked this conversation as resolved.
Show resolved Hide resolved
.help("Specify address that stores token's metadata-pointer"),
)
.arg(
Arg::with_name("disable")
.long("disable")
.takes_value(false)
.conflicts_with("metadata_address")
.help("Unset metadata pointer address.")
)
.arg(
Arg::with_name("authority")
.long("authority")
.value_name("KEYPAIR")
.validator(is_valid_signer)
.takes_value(true)
.help(
"Specify the token's metadata-pointer authority. \
This may be a keypair file or the ASK keyword. \
Defaults to the client keypair.",
),
)
.arg(multisig_signer_arg())
.nonce_args(true)
)
.subcommand(
SubCommand::with_name(CommandName::WithdrawWithheldTokens.into())
.about("Withdraw withheld transfer fee tokens from mint and / or account(s)")
Expand Down Expand Up @@ -4387,6 +4457,28 @@ async fn process_command<'a>(
)
.await
}
(CommandName::UpdateMetadataAddress, arg_matches) => {
// Since account is required argument it will always be present
let token = pubkey_of_signer(arg_matches, "token", &mut wallet_manager)
.unwrap()
.unwrap();

let (authority_signer, authority) =
config.signer_or_default(arg_matches, "authority", &mut wallet_manager);
if config.multisigner_pubkeys.is_empty() {
push_signer_with_dedup(authority_signer, &mut bulk_signers);
}
let metadata_address = value_t!(arg_matches, "metadata_address", Pubkey).ok();

command_update_metadata_pointer_address(
config,
token,
authority,
metadata_address,
bulk_signers,
)
.await
}
(CommandName::WithdrawWithheldTokens, arg_matches) => {
let (authority_signer, authority) = config.signer_or_default(
arg_matches,
Expand Down Expand Up @@ -7489,5 +7581,54 @@ mod tests {
extension.metadata_address,
Some(metadata_address).try_into().unwrap()
);

let new_metadata_address = Pubkey::new_unique();

let _new_result = process_test_command(
&config,
&payer,
&[
"spl-token",
CommandName::UpdateMetadataAddress.into(),
&mint.to_string(),
&new_metadata_address.to_string(),
],
)
.await;

let new_account = config.rpc_client.get_account(&mint).await.unwrap();
let new_mint_state = StateWithExtensionsOwned::<Mint>::unpack(new_account.data).unwrap();

let new_extension = new_mint_state.get_extension::<MetadataPointer>().unwrap();

assert_eq!(
new_extension.metadata_address,
Some(new_metadata_address).try_into().unwrap()
);

let _result_with_disable = process_test_command(
&config,
&payer,
&[
"spl-token",
CommandName::UpdateMetadataAddress.into(),
&mint.to_string(),
"--disable",
],
)
.await;

let new_account_disbale = config.rpc_client.get_account(&mint).await.unwrap();
let new_mint_state_disable =
StateWithExtensionsOwned::<Mint>::unpack(new_account_disbale.data).unwrap();

let new_extension_disable = new_mint_state_disable
.get_extension::<MetadataPointer>()
.unwrap();

assert_eq!(
new_extension_disable.metadata_address,
None.try_into().unwrap()
);
}
}