A user closes their subscription authority
Source: subscriptions/tests/test_close_subscription_authority.rs L98
- When: the user initializes a subscription authority
- When: the user closes the subscription authority
- Then: Alice closes her own authority ✓
- Then: the authority account is gone or emptied ✓
- Then: Alice’s balance grew ✓
- Then: Alice recovers the rent (less fees) ✓
Result: ✓ success — 1832 CU · claims 4/4 ✓
sequenceDiagram
participant p0 as alice
participant p1 as Subscriptions
p0->>p1: closeSubscriptionAuthority
activate p1
p1-->>p0: ✓ 1832cu
deactivate p1
Authority
flowchart LR
Subscriptions["Subscriptions"]:::program
alice(["alice"]):::signer
SAaliceMint[("SA(alice, Mint)")]:::state
alice -->|signs| Subscriptions
Subscriptions -->|writes| SAaliceMint
classDef program fill:#dae8fc,stroke:#6c8ebf;
classDef signer fill:#d5e8d4,stroke:#82b366;
classDef state fill:#ffe6cc,stroke:#d79b00;
Ownership
flowchart LR
system["system"]:::program
alice[("alice")]:::state
SAaliceMint[("SA(alice, Mint)")]:::state
system -->|owns| alice
system -->|owns| SAaliceMint
classDef program fill:#dae8fc,stroke:#6c8ebf;
classDef signer fill:#d5e8d4,stroke:#82b366;
classDef state fill:#ffe6cc,stroke:#d79b00;
Accounts
| Account | Signer | Writable | Owner |
|---|---|---|---|
| alice | ✓ | ✓ | system |
| SA(alice, Mint) | · | ✓ | system |
Call tree and logs
A user closes their subscription authority
alice (1832cu)
└─ Subscriptions::closeSubscriptionAuthority ✓ 1832cu
Program De1egAFMkMWZSN5rYXRj9CAdheBamobVNubTsi9avR44 invoke [1]
Program De1egAFMkMWZSN5rYXRj9CAdheBamobVNubTsi9avR44 consumed 1832 of 200000 compute units
Program De1egAFMkMWZSN5rYXRj9CAdheBamobVNubTsi9avR44 success
Integration
What an integrator writes: the derivations and the instruction, byte-identical to the transaction this page witnessed. Addresses are this scenario’s; supply your own.
#![allow(unused)]
fn main() {
use solana_instruction::{AccountMeta, Instruction};
use solana_pubkey::{pubkey, Pubkey};
// --- closeSubscriptionAuthority ---
let program_id: Pubkey = pubkey!("De1egAFMkMWZSN5rYXRj9CAdheBamobVNubTsi9avR44");
let user: Pubkey = pubkey!("2rj1EEgg32bupe12mMYnPFaKQCPPyYBhKYmDFZ8cXxpT"); // alice: this scenario's value; supply your own
let subscription_authority: Pubkey = pubkey!("4RDKDQRnKtZC5ti4wunSAayArwxdZida5St595CiKJ7i"); // SA(alice, Mint): this scenario's value; supply your own
let ix = Instruction {
program_id,
accounts: vec![
AccountMeta::new(user, true), // user
AccountMeta::new(subscription_authority, false), // subscriptionAuthority
],
// discriminator ++ borsh()
data: vec![0x06],
};
}
The same call through the Codama-generated TypeScript client (the async builder derives every PDA the resolver derived here, so only the free inputs appear):
import { address } from "@solana/kit";
import { getCloseSubscriptionAuthorityInstructionAsync } from "your-generated-client";
const ix = await getCloseSubscriptionAuthorityInstructionAsync({
user: userSigner, // alice (a TransactionSigner)
subscriptionAuthority: address("4RDKDQRnKtZC5ti4wunSAayArwxdZida5St595CiKJ7i"), // SA(alice, Mint)
});
How this page verifies itself: the test that ran it
The narrative above is this test; the page and the code cannot drift.
#![allow(unused)]
fn main() {
#[test]
fn close_subscription_authority() {
let mut story = Story::load(SO, IDL);
let alice = story.cast("alice");
let mint = story.mint(&alice, MINT_DECIMALS);
story.fund(&alice, &[(mint, 1_000_000)]);
story
.init_subscription_authority(InitAuthorityArgs {
user: &alice,
mint,
sponsor: None,
token_program: None,
})
.expect_success();
let pda = story.subscription_authority_pda(&alice.pubkey(), &mint);
let rent = story
.svm
.get_account(&pda)
.expect("the authority exists before close")
.lamports;
let alice_before = story.svm.get_account(&alice.pubkey()).unwrap().lamports;
let outcome = story.close_subscription_authority(CloseAuthorityArgs {
user: &alice,
mint,
receiver: None,
authority: None,
});
story.then_holds("Alice closes her own authority", outcome.success);
let after = story.svm.get_account(&pda);
story.then_holds(
"the authority account is gone or emptied",
after.is_none() || after.as_ref().map(|a| a.lamports).unwrap_or(0) == 0,
);
let alice_after = story.svm.get_account(&alice.pubkey()).unwrap().lamports;
story.then_holds("Alice's balance grew", alice_after > alice_before);
story.then_holds(
"Alice recovers the rent (less fees)",
alice_after >= alice_before + rent - 10_000,
);
emit_scenario(
&story,
&outcome,
"A user closes their subscription authority",
);
}
}