Утвердить делегата

Как утвердить делегата

Инструкция ApproveChecked предоставляет другому аккаунту (делегату) разрешение на перевод определённого количества токенов с вашего токен-аккаунта. Делегат может переводить токены в пределах утверждённой суммы, но не может её превышать. Только владелец токен-аккаунта может утвердить делегата, и у каждого токен-аккаунта может быть только один делегат одновременно. Любое новое утверждение заменяет предыдущее.

Программа токенов и Программа расширений токенов имеют схожие реализации для достижения одинаковой функциональности.

Typescript

import {
airdropFactory,
appendTransactionMessageInstructions,
createSolanaRpc,
createSolanaRpcSubscriptions,
createTransactionMessage,
generateKeyPairSigner,
getSignatureFromTransaction,
lamports,
pipe,
sendAndConfirmTransactionFactory,
setTransactionMessageFeePayerSigner,
setTransactionMessageLifetimeUsingBlockhash,
signTransactionMessageWithSigners
} from "@solana/kit";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
getCreateAssociatedTokenInstructionAsync,
getInitializeMintInstruction,
getMintSize,
TOKEN_PROGRAM_ADDRESS,
findAssociatedTokenPda,
getMintToInstruction,
getApproveCheckedInstruction
} from "@solana-program/token";
// Create Connection, local validator in this example
const rpc = createSolanaRpc("http://localhost:8899");
const rpcSubscriptions = createSolanaRpcSubscriptions("ws://localhost:8900");
// Generate keypairs for fee payer and delegate
const feePayer = await generateKeyPairSigner();
const delegate = await generateKeyPairSigner();
// Fund fee payer
await airdropFactory({ rpc, rpcSubscriptions })({
recipientAddress: feePayer.address,
lamports: lamports(1_000_000_000n),
commitment: "confirmed"
});
// Generate keypair to use as address of mint
const mint = await generateKeyPairSigner();
// Get default mint account size (in bytes), no extensions enabled
const space = BigInt(getMintSize());
// Get minimum balance for rent exemption
const rent = await rpc.getMinimumBalanceForRentExemption(space).send();
// Get latest blockhash to include in transaction
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
// Instruction to create new account for mint (token program)
// Invokes the system program
const createAccountInstruction = getCreateAccountInstruction({
payer: feePayer,
newAccount: mint,
lamports: rent,
space,
programAddress: TOKEN_PROGRAM_ADDRESS
});
// Instruction to initialize mint account data
// Invokes the token program
const initializeMintInstruction = getInitializeMintInstruction({
mint: mint.address,
decimals: 9,
mintAuthority: feePayer.address
});
// Use findAssociatedTokenPda to derive the ATA address
const [associatedTokenAddress] = await findAssociatedTokenPda({
mint: mint.address,
owner: feePayer.address,
tokenProgram: TOKEN_PROGRAM_ADDRESS
});
// Create instruction to create the associated token account
const createAtaInstruction = await getCreateAssociatedTokenInstructionAsync({
payer: feePayer,
mint: mint.address,
owner: feePayer.address
});
// Create instruction to mint tokens
const mintToInstruction = getMintToInstruction({
mint: mint.address,
token: associatedTokenAddress,
mintAuthority: feePayer.address,
amount: 1000_000_000_000n // 1000.0 tokens with 9 decimals
});
const instructions = [
createAccountInstruction,
initializeMintInstruction,
createAtaInstruction,
mintToInstruction
];
// Create transaction message
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(feePayer, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx),
(tx) => appendTransactionMessageInstructions(instructions, tx)
);
// Sign transaction message with all required signers
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
// Send and confirm transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedTransaction,
{ commitment: "confirmed" }
);
// Get transaction signature
const transactionSignature = getSignatureFromTransaction(signedTransaction);
console.log("Mint Address:", mint.address.toString());
console.log(
"Associated Token Account Address:",
associatedTokenAddress.toString()
);
console.log("Transaction Signature:", transactionSignature);
// Get a fresh blockhash for the approve transaction
const { value: approveBlockhash } = await rpc.getLatestBlockhash().send();
// Create instruction to approve delegate
const approveInstruction = getApproveCheckedInstruction({
source: associatedTokenAddress,
mint: mint.address,
delegate: delegate.address,
owner: feePayer,
amount: 1_000_000_000n, // 1.0 tokens with 9 decimals
decimals: 9
});
// Create transaction message for approval
const approveTxMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(feePayer, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(approveBlockhash, tx),
(tx) => appendTransactionMessageInstructions([approveInstruction], tx)
);
// Sign transaction message with all required signers
const signedApproveTx =
await signTransactionMessageWithSigners(approveTxMessage);
// Send and confirm transaction
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedApproveTx,
{ commitment: "confirmed" }
);
// Get transaction signature
const transactionSignature2 = getSignatureFromTransaction(signedApproveTx);
console.log("\nDelegate Address:", delegate.address.toString());
console.log("Successfully approved delegate to transfer 1.0 tokens");
console.log("Transaction Signature:", transactionSignature2);
Console
Click to execute the code.

Rust

use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{
commitment_config::CommitmentConfig,
program_pack::Pack,
signature::{Keypair, Signer},
system_instruction::create_account,
transaction::Transaction,
};
use spl_associated_token_account::{
get_associated_token_address_with_program_id, instruction::create_associated_token_account,
};
use spl_token::{
id as token_program_id,
instruction::{initialize_mint, mint_to, approve_checked},
state::Mint,
};
#[tokio::main]
async fn main() -> Result<()> {
// Create connection to local validator
let client = RpcClient::new_with_commitment(
String::from("http://localhost:8899"),
CommitmentConfig::confirmed(),
);
let latestBlockhash = client.get_latest_blockhash().await?;
// Generate a new keypair for the fee payer
let fee_payer = Keypair::new();
// Generate a keypair for the delegate
let delegate = Keypair::new();
// Airdrop 1 SOL to fee payer
let airdrop_signature = client
.request_airdrop(&fee_payer.pubkey(), 1_000_000_000)
.await?;
client.confirm_transaction(&airdrop_signature).await?;
loop {
let confirmed = client.confirm_transaction(&airdrop_signature).await?;
if confirmed {
break;
}
}
// Generate keypair to use as address of mint
let mint = Keypair::new();
// Get default mint account size (in bytes), no extensions enabled
let mint_space = Mint::LEN;
let mint_rent = client
.get_minimum_balance_for_rent_exemption(mint_space)
.await?;
// Instruction to create new account for mint (token program)
let create_account_instruction = create_account(
&fee_payer.pubkey(), // payer
&mint.pubkey(), // new account (mint)
mint_rent, // lamports
mint_space as u64, // space
&token_program_id(), // program id
);
// Instruction to initialize mint account data
let initialize_mint_instruction = initialize_mint(
&token_program_id(),
&mint.pubkey(), // mint
&fee_payer.pubkey(), // mint authority
Some(&fee_payer.pubkey()), // freeze authority
9, // decimals
)?;
// Calculate the associated token account address for fee_payer
let associated_token_address = get_associated_token_address_with_program_id(
&fee_payer.pubkey(), // owner
&mint.pubkey(), // mint
&token_program_id(), // program_id
);
// Instruction to create associated token account
let create_ata_instruction = create_associated_token_account(
&fee_payer.pubkey(), // funding address
&fee_payer.pubkey(), // wallet address
&mint.pubkey(), // mint address
&token_program_id(), // program id
);
// Amount of tokens to mint (1000 tokens with 9 decimals)
let amount = 1000_000_000_000;
// Create mint_to instruction to mint tokens to the associated token account
let mint_to_instruction = mint_to(
&token_program_id(),
&mint.pubkey(), // mint
&associated_token_address, // destination
&fee_payer.pubkey(), // authority
&[&fee_payer.pubkey()], // signer
amount, // amount
)?;
// Create transaction and add instructions
let transaction = Transaction::new_signed_with_payer(
&[
create_account_instruction,
initialize_mint_instruction,
create_ata_instruction,
mint_to_instruction,
],
Some(&fee_payer.pubkey()),
&[&fee_payer, &mint],
latestBlockhash,
);
// Send and confirm transaction
let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
println!("Mint Address: {}", mint.pubkey());
println!(
"Associated Token Account Address: {}",
associated_token_address
);
println!("\nTransaction Signature: {}", transaction_signature);
// Get the latest blockhash for the approve transaction
let latestBlockhash = client.get_latest_blockhash().await?;
// Amount of tokens to approve (1 token with 9 decimals)
let approve_amount = 1_000_000_000;
// Create approve_checked instruction
let approve_instruction = approve_checked(
&token_program_id(), // program id
&associated_token_address, // source token account
&mint.pubkey(), // mint
&delegate.pubkey(), // delegate
&fee_payer.pubkey(), // owner
&[&fee_payer.pubkey()], // signers
approve_amount, // amount
9, // decimals
)?;
// Create transaction for approving delegate
let transaction = Transaction::new_signed_with_payer(
&[approve_instruction],
Some(&fee_payer.pubkey()),
&[&fee_payer],
latestBlockhash,
);
// Send and confirm transaction
let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;
println!("\nDelegate Address: {}", delegate.pubkey());
println!(
"Successfully approved delegate to transfer 1.0 tokens"
);
println!("Transaction Signature: {}", transaction_signature);
Ok(())
}
Console
Click to execute the code.

Python

Python
#!/usr/bin/env python3
import asyncio
from solana.rpc.async_api import AsyncClient
from solders.keypair import Keypair
from solders.transaction import VersionedTransaction
from solders.message import MessageV0
from solders.system_program import create_account, CreateAccountParams
from spl.token.instructions import (
initialize_mint, InitializeMintParams,
create_associated_token_account,
mint_to_checked, MintToCheckedParams,
approve_checked, ApproveCheckedParams,
get_associated_token_address
)
from spl.token.constants import TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID
# Constants
DECIMALS = 9
async def setup(rpc, mint_authority):
"""
The setup function initializes the mint and associated token accounts,
and mints tokens to said associated token account
"""
mint = Keypair()
space = 82 # getMintSize() equivalent for SPL Token
# Get minimum balance for rent exemption
rent = await rpc.get_minimum_balance_for_rent_exemption(space)
# Create & initialize mint account
create_account_instruction = create_account(
CreateAccountParams(
from_pubkey=mint_authority.pubkey(),
to_pubkey=mint.pubkey(),
lamports=rent.value,
space=space,
owner=TOKEN_PROGRAM_ID
)
)
initialize_mint_instruction = initialize_mint(
InitializeMintParams(
program_id=TOKEN_PROGRAM_ID,
mint=mint.pubkey(),
decimals=DECIMALS,
mint_authority=mint_authority.pubkey(),
freeze_authority=None
)
)
# Create associated token account
authority_ata = get_associated_token_address(
owner=mint_authority.pubkey(),
mint=mint.pubkey(),
token_program_id=TOKEN_PROGRAM_ID
)
create_authority_ata_instruction = create_associated_token_account(
payer=mint_authority.pubkey(),
owner=mint_authority.pubkey(),
mint=mint.pubkey()
)
# Mint to token account
mint_to_instruction = mint_to_checked(
MintToCheckedParams(
program_id=TOKEN_PROGRAM_ID,
mint=mint.pubkey(),
dest=authority_ata,
mint_authority=mint_authority.pubkey(),
amount=1_000_000_000_000, # 1000 tokens
decimals=DECIMALS
)
)
instructions = [
create_account_instruction,
initialize_mint_instruction,
create_authority_ata_instruction,
mint_to_instruction
]
# Get latest blockhash
latest_blockhash = await rpc.get_latest_blockhash()
# Create message
transaction_message = MessageV0.try_compile(
payer=mint_authority.pubkey(),
instructions=instructions,
address_lookup_table_accounts=[],
recent_blockhash=latest_blockhash.value.blockhash
)
# Create and sign transaction
signed_transaction = VersionedTransaction(transaction_message, [mint_authority, mint])
print("Setup transaction created successfully")
print(f"Mint: {mint.pubkey()}")
print(f"Authority ATA: {authority_ata}")
return {
"mint": mint.pubkey(),
"authority_ata": authority_ata
}
async def main():
rpc = AsyncClient("http://localhost:8899")
# Constants
mint_authority = Keypair()
delegate = Keypair()
async with rpc:
# Get latest blockhash
latest_blockhash = await rpc.get_latest_blockhash()
# Setup mint and associated token accounts
setup_result = await setup(rpc, mint_authority)
mint = setup_result["mint"]
authority_ata = setup_result["authority_ata"]
# Create delegate instruction
delegate_instruction = approve_checked(
ApproveCheckedParams(
program_id=TOKEN_PROGRAM_ID,
source=authority_ata,
mint=mint,
delegate=delegate.pubkey(),
owner=mint_authority.pubkey(),
amount=1_000_000_000, # 1 token
decimals=DECIMALS
)
)
# Create transaction message
transaction_message = MessageV0.try_compile(
payer=mint_authority.pubkey(),
instructions=[delegate_instruction],
address_lookup_table_accounts=[],
recent_blockhash=latest_blockhash.value.blockhash
)
# Create and sign transaction
signed_transaction = VersionedTransaction(transaction_message, [mint_authority])
print(f"\nDelegate Transaction:")
print(f"Source: {authority_ata}")
print(f"Mint: {mint}")
print(f"Delegate: {delegate.pubkey()}")
print(f"Owner: {mint_authority.pubkey()}")
print(f"Amount: 1_000_000_000 (1 token)")
print(f"Decimals: {DECIMALS}")
print(f"Delegation transaction created successfully")
if __name__ == "__main__":
asyncio.run(main())
Console
Click to execute the code.

Is this page helpful?

Содержание

Редактировать страницу