transfer_admin
Transfer admin ownership of a Settings account
Transfers admin ownership of a Settings account to a new pubkey. Only the current admin can call this instruction.
Signature
Section titled “Signature”pub fn transfer_admin( ctx: Context<TransferAdmin>, new_admin: Pubkey,) -> Result<()>Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
new_admin | Pubkey | Public key of the new admin |
Accounts
Section titled “Accounts”| Account | Type | Description |
|---|---|---|
admin | Signer | Current admin of the Settings account |
settings | Account<Settings> | Settings PDA to transfer |
TypeScript
Section titled “TypeScript”import { buildTransferAdminInstruction } from './codama-ts-range-custom';
const instruction = await buildTransferAdminInstruction({ admin: currentAdminPublicKey, newAdmin: newAdminPublicKey,});
// Sign with current admin and sendconst transaction = new Transaction().add(instruction);await sendTransaction(transaction);Anchor
Section titled “Anchor”await program.methods .transferAdmin(newAdminPublicKey) .accounts({ admin: currentAdmin.publicKey, settings: settingsPda, }) .rpc();Behavior
Section titled “Behavior”- Verifies caller is the current admin
- Updates the
adminfield tonew_admin - Current admin immediately loses all control
- PDA address remains unchanged
Errors
Section titled “Errors”| Error | Cause |
|---|---|
| Constraint violation | Caller is not the current admin |
| Account not found | Settings account doesn’t exist |
Use Cases
Section titled “Use Cases”Organizational Handoff
Section titled “Organizational Handoff”Transferring control when changing team ownership:
// Current admin transfers to new team leadconst instruction = await buildTransferAdminInstruction({ admin: currentTeamLead.publicKey, newAdmin: newTeamLead.publicKey,});Multi-sig Migration
Section titled “Multi-sig Migration”Transferring to a multi-sig wallet for enhanced security:
// Transfer to a Squads multi-sigconst instruction = await buildTransferAdminInstruction({ admin: singleSignerAdmin.publicKey, newAdmin: squadsMultisigPda,});Emergency Recovery
Section titled “Emergency Recovery”Setting up a recovery pubkey before deployment:
// Create backup admin keypair, store securely offlineconst backupAdmin = Keypair.generate();console.log('Backup admin:', backupAdmin.publicKey.toBase58());console.log('Store this keypair securely offline!');
// Later, if primary admin is compromised:const instruction = await buildTransferAdminInstruction({ admin: primaryAdmin.publicKey, newAdmin: backupAdmin.publicKey,});Important Notes
Section titled “Important Notes”PDA Remains Unchanged
Section titled “PDA Remains Unchanged”The Settings PDA is derived from the original admin pubkey. After transfer:
// PDA derivation uses original adminconst [settingsPda] = PublicKey.findProgramAddressSync( [Buffer.from("settings"), originalAdmin.toBuffer()], // Original admin! RANGE_PROGRAM_ID);
// But the new admin controls it// settings.admin === newAdminPublicKeyThis means existing integrations that reference the PDA continue to work.
Two-Step Secure Transfer
Section titled “Two-Step Secure Transfer”For high-value transfers, consider a two-step process:
// Step 1: Transfer to intermediate (verify new admin has access)await buildTransferAdminInstruction({ admin: currentAdmin.publicKey, newAdmin: intermediateAdmin.publicKey, // New admin's hot wallet});
// Step 2: New admin transfers to their secure walletawait buildTransferAdminInstruction({ admin: intermediateAdmin.publicKey, newAdmin: secureMultisig.publicKey,});See Also
Section titled “See Also”- Settings Account - Understanding Settings
- update_settings - Modifying settings
- Security - Security best practices