spl_token_2022/extension/scaled_ui_amount/instruction.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
#[cfg(feature = "serde-traits")]
use serde::{Deserialize, Serialize};
use {
crate::{
check_program_account,
extension::scaled_ui_amount::{PodF64, UnixTimestamp},
instruction::{encode_instruction, TokenInstruction},
},
bytemuck::{Pod, Zeroable},
num_enum::{IntoPrimitive, TryFromPrimitive},
solana_program::{
instruction::{AccountMeta, Instruction},
program_error::ProgramError,
pubkey::Pubkey,
},
spl_pod::optional_keys::OptionalNonZeroPubkey,
std::convert::TryInto,
};
/// Interesting-bearing mint extension instructions
#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
#[derive(Clone, Copy, Debug, PartialEq, IntoPrimitive, TryFromPrimitive)]
#[repr(u8)]
pub enum ScaledUiAmountMintInstruction {
/// Initialize a new mint with scaled UI amounts.
///
/// Fails if the mint has already been initialized, so must be called before
/// `InitializeMint`.
///
/// Fails if the multiplier is less than or equal to 0 or if it's
/// [subnormal](https://en.wikipedia.org/wiki/Subnormal_number).
///
/// The mint must have exactly enough space allocated for the base mint (82
/// bytes), plus 83 bytes of padding, 1 byte reserved for the account type,
/// then space required for this extension, plus any others.
///
/// Accounts expected by this instruction:
///
/// 0. `[writable]` The mint to initialize.
///
/// Data expected by this instruction:
/// `crate::extension::scaled_ui_amount::instruction::InitializeInstructionData`
Initialize,
/// Update the multiplier. Only supported for mints that include the
/// `ScaledUiAmount` extension.
///
/// Fails if the multiplier is less than or equal to 0 or if it's
/// [subnormal](https://en.wikipedia.org/wiki/Subnormal_number).
///
/// The authority provides a new multiplier and a UNIX timestamp on which
/// it should take effect. If the timestamp is before the current time,
/// immediately sets the multiplier.
///
/// Accounts expected by this instruction:
///
/// * Single authority
/// 0. `[writable]` The mint.
/// 1. `[signer]` The multiplier authority.
///
/// * Multisignature authority
/// 0. `[writable]` The mint.
/// 1. `[]` The mint's multisignature multiplier authority.
/// 2. `..2+M` `[signer]` M signer accounts.
///
/// Data expected by this instruction:
/// `crate::extension::scaled_ui_amount::instruction::UpdateMultiplierInstructionData`
UpdateMultiplier,
}
/// Data expected by `ScaledUiAmountMint::Initialize`
#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
#[derive(Clone, Copy, Pod, Zeroable)]
#[repr(C)]
pub struct InitializeInstructionData {
/// The public key for the account that can update the multiplier
pub authority: OptionalNonZeroPubkey,
/// The initial multiplier
pub multiplier: PodF64,
}
/// Data expected by `ScaledUiAmountMint::UpdateMultiplier`
#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
#[derive(Clone, Copy, Pod, Zeroable)]
#[repr(C)]
pub struct UpdateMultiplierInstructionData {
/// The new multiplier
pub multiplier: PodF64,
/// Timestamp at which the new multiplier will take effect
pub effective_timestamp: UnixTimestamp,
}
/// Create an `Initialize` instruction
pub fn initialize(
token_program_id: &Pubkey,
mint: &Pubkey,
authority: Option<Pubkey>,
multiplier: f64,
) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let accounts = vec![AccountMeta::new(*mint, false)];
Ok(encode_instruction(
token_program_id,
accounts,
TokenInstruction::ScaledUiAmountExtension,
ScaledUiAmountMintInstruction::Initialize,
&InitializeInstructionData {
authority: authority.try_into()?,
multiplier: multiplier.into(),
},
))
}
/// Create an `UpdateMultiplier` instruction
pub fn update_multiplier(
token_program_id: &Pubkey,
mint: &Pubkey,
authority: &Pubkey,
signers: &[&Pubkey],
multiplier: f64,
effective_timestamp: i64,
) -> Result<Instruction, ProgramError> {
check_program_account(token_program_id)?;
let mut accounts = vec![
AccountMeta::new(*mint, false),
AccountMeta::new_readonly(*authority, signers.is_empty()),
];
for signer_pubkey in signers.iter() {
accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
}
Ok(encode_instruction(
token_program_id,
accounts,
TokenInstruction::ScaledUiAmountExtension,
ScaledUiAmountMintInstruction::UpdateMultiplier,
&UpdateMultiplierInstructionData {
effective_timestamp: effective_timestamp.into(),
multiplier: multiplier.into(),
},
))
}