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-2022: Add Pausable extension #7562

Merged
merged 3 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 51 additions & 2 deletions token/client/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ use {
ConfidentialTransferFeeConfig,
},
cpi_guard, default_account_state, group_member_pointer, group_pointer,
interest_bearing_mint, memo_transfer, metadata_pointer, scaled_ui_amount, transfer_fee,
transfer_hook, BaseStateWithExtensions, Extension, ExtensionType,
interest_bearing_mint, memo_transfer, metadata_pointer, pausable, scaled_ui_amount,
transfer_fee, transfer_hook, BaseStateWithExtensions, Extension, ExtensionType,
StateWithExtensionsOwned,
},
instruction, offchain,
Expand Down Expand Up @@ -193,6 +193,9 @@ pub enum ExtensionInitializationParams {
authority: Option<Pubkey>,
multiplier: f64,
},
PausableConfig {
authority: Pubkey,
},
}
impl ExtensionInitializationParams {
/// Get the extension type associated with the init params
Expand All @@ -213,6 +216,7 @@ impl ExtensionInitializationParams {
Self::GroupPointer { .. } => ExtensionType::GroupPointer,
Self::GroupMemberPointer { .. } => ExtensionType::GroupMemberPointer,
Self::ScaledUiAmountConfig { .. } => ExtensionType::ScaledUiAmount,
Self::PausableConfig { .. } => ExtensionType::Pausable,
}
}
/// Generate an appropriate initialization instruction for the given mint
Expand Down Expand Up @@ -331,6 +335,9 @@ impl ExtensionInitializationParams {
authority,
multiplier,
),
Self::PausableConfig { authority } => {
pausable::instruction::initialize(token_program_id, mint, &authority)
}
}
}
}
Expand Down Expand Up @@ -1753,6 +1760,48 @@ where
.await
}

/// Pause transferring, minting, and burning on the mint
pub async fn pause<S: Signers>(
&self,
authority: &Pubkey,
signing_keypairs: &S,
) -> TokenResult<T::Output> {
let signing_pubkeys = signing_keypairs.pubkeys();
let multisig_signers = self.get_multisig_signers(authority, &signing_pubkeys);

self.process_ixs(
&[pausable::instruction::pause(
&self.program_id,
self.get_address(),
authority,
&multisig_signers,
)?],
signing_keypairs,
)
.await
}

/// Resume transferring, minting, and burning on the mint
pub async fn resume<S: Signers>(
&self,
authority: &Pubkey,
signing_keypairs: &S,
) -> TokenResult<T::Output> {
let signing_pubkeys = signing_keypairs.pubkeys();
let multisig_signers = self.get_multisig_signers(authority, &signing_pubkeys);

self.process_ixs(
&[pausable::instruction::resume(
&self.program_id,
self.get_address(),
authority,
&multisig_signers,
)?],
signing_keypairs,
)
.await
}

/// Prevent unsafe usage of token account through CPI
pub async fn enable_cpi_guard<S: Signers>(
&self,
Expand Down
181 changes: 181 additions & 0 deletions token/program-2022-test/tests/confidential_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1617,6 +1617,86 @@ async fn confidential_transfer_transfer() {
.await;
}

#[cfg(feature = "zk-ops")]
#[tokio::test]
async fn pause_confidential_transfer() {
samkim-crypto marked this conversation as resolved.
Show resolved Hide resolved
let authority = Keypair::new();
let pausable_authority = Keypair::new();
let auto_approve_new_accounts = true;
let auditor_elgamal_keypair = ElGamalKeypair::new_rand();
let auditor_elgamal_pubkey = (*auditor_elgamal_keypair.pubkey()).into();

let mut context = TestContext::new().await;
context
.init_token_with_mint(vec![
ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(authority.pubkey()),
auto_approve_new_accounts,
auditor_elgamal_pubkey: Some(auditor_elgamal_pubkey),
},
ExtensionInitializationParams::PausableConfig {
authority: pausable_authority.pubkey(),
},
])
.await
.unwrap();

let TokenContext {
token,
alice,
bob,
mint_authority,
decimals,
..
} = context.token_context.unwrap();

let alice_meta = ConfidentialTokenAccountMeta::new_with_tokens(
&token,
&alice,
None,
false,
false,
&mint_authority,
42,
decimals,
)
.await;

let bob_meta = ConfidentialTokenAccountMeta::new(&token, &bob, Some(2), false, false).await;

// pause it
token
.pause(&pausable_authority.pubkey(), &[&pausable_authority])
.await
.unwrap();
let error = confidential_transfer_with_option(
&token,
&alice_meta.token_account,
&bob_meta.token_account,
&alice.pubkey(),
10,
&alice_meta.elgamal_keypair,
&alice_meta.aes_key,
bob_meta.elgamal_keypair.pubkey(),
Some(auditor_elgamal_keypair.pubkey()),
None,
&[&alice],
ConfidentialTransferOption::InstructionData,
)
.await
.unwrap_err();

assert_eq!(
error,
TokenClientError::Client(Box::new(TransportError::TransactionError(
TransactionError::InstructionError(
0,
InstructionError::Custom(TokenError::MintPaused as u32)
)
)))
);
}

#[cfg(feature = "zk-ops")]
async fn confidential_transfer_transfer_with_option(option: ConfidentialTransferOption) {
let authority = Keypair::new();
Expand Down Expand Up @@ -2328,6 +2408,107 @@ async fn confidential_transfer_transfer_with_fee() {
.await;
}

#[cfg(feature = "zk-ops")]
#[tokio::test]
async fn pause_confidential_transfer_with_fee() {
let transfer_fee_authority = Keypair::new();
let withdraw_withheld_authority = Keypair::new();

let pausable_authority = Keypair::new();
let confidential_transfer_authority = Keypair::new();
let auto_approve_new_accounts = true;
let auditor_elgamal_keypair = ElGamalKeypair::new_rand();
let auditor_elgamal_pubkey = (*auditor_elgamal_keypair.pubkey()).into();

let confidential_transfer_fee_authority = Keypair::new();
let withdraw_withheld_authority_elgamal_keypair = ElGamalKeypair::new_rand();
let withdraw_withheld_authority_elgamal_pubkey =
(*withdraw_withheld_authority_elgamal_keypair.pubkey()).into();

let mut context = TestContext::new().await;
context
.init_token_with_mint(vec![
ExtensionInitializationParams::TransferFeeConfig {
transfer_fee_config_authority: Some(transfer_fee_authority.pubkey()),
withdraw_withheld_authority: Some(withdraw_withheld_authority.pubkey()),
transfer_fee_basis_points: TEST_FEE_BASIS_POINTS,
maximum_fee: TEST_MAXIMUM_FEE,
},
ExtensionInitializationParams::ConfidentialTransferMint {
authority: Some(confidential_transfer_authority.pubkey()),
auto_approve_new_accounts,
auditor_elgamal_pubkey: Some(auditor_elgamal_pubkey),
},
ExtensionInitializationParams::ConfidentialTransferFeeConfig {
authority: Some(confidential_transfer_fee_authority.pubkey()),
withdraw_withheld_authority_elgamal_pubkey,
},
ExtensionInitializationParams::PausableConfig {
authority: pausable_authority.pubkey(),
},
])
.await
.unwrap();

let TokenContext {
token,
alice,
bob,
mint_authority,
decimals,
..
} = context.token_context.unwrap();

let alice_meta = ConfidentialTokenAccountMeta::new_with_tokens(
&token,
&alice,
None,
false,
true,
&mint_authority,
100,
decimals,
)
.await;

let bob_meta = ConfidentialTokenAccountMeta::new(&token, &bob, None, false, true).await;

token
.pause(&pausable_authority.pubkey(), &[&pausable_authority])
.await
.unwrap();

let error = confidential_transfer_with_fee_with_option(
&token,
&alice_meta.token_account,
&bob_meta.token_account,
&alice.pubkey(),
10,
&alice_meta.elgamal_keypair,
&alice_meta.aes_key,
bob_meta.elgamal_keypair.pubkey(),
Some(auditor_elgamal_keypair.pubkey()),
withdraw_withheld_authority_elgamal_keypair.pubkey(),
TEST_FEE_BASIS_POINTS,
TEST_MAXIMUM_FEE,
None,
&[&alice],
ConfidentialTransferOption::InstructionData,
)
.await
.unwrap_err();

assert_eq!(
error,
TokenClientError::Client(Box::new(TransportError::TransactionError(
TransactionError::InstructionError(
0,
InstructionError::Custom(TokenError::MintPaused as u32)
)
)))
);
}

#[cfg(feature = "zk-ops")]
async fn confidential_transfer_transfer_with_fee_with_option(option: ConfidentialTransferOption) {
let transfer_fee_authority = Keypair::new();
Expand Down
Loading
Loading