赞助交易
通常情况下,执行交易的账户需要支付 gas 费用。通过赞助(费用支付者)交易,一个单独的账户可以代替发送者承担 gas 费用。这对于引导尚未持有 APT 的新用户、为您的应用用户补贴交易成本或从中央金库管理 gas 费用非常有用。
如何赞助交易
Section titled “如何赞助交易”-
构建入口函数负载。
为发送者要执行的交易创建负载。
use aptos_sdk::types::EntryFunctionPayload;let payload = EntryFunctionPayload::new("0x1::aptos_account::transfer".parse()?,vec![],vec![bob.address().into(), 10_000_000u64.into()],); -
使用
TransactionBuilder构建原始交易。从发送者账户构造原始交易。
use aptos_sdk::transaction_builder::TransactionBuilder;let raw_txn = TransactionBuilder::new(payload, aptos.get_chain_id().await?).sender(alice.address()).sequence_number(aptos.get_sequence_number(alice.address()).await?).max_gas_amount(10_000).gas_unit_price(100).expiration_timestamp_secs(aptos.get_latest_ledger_info().await?.timestamp() + 60,).build(); -
创建指定赞助者的
FeePayerRawTransaction。用费用支付者的地址包装原始交易。当没有额外的次要签名者时使用
new_simple。use aptos_sdk::types::FeePayerRawTransaction;let fee_payer_txn = FeePayerRawTransaction::new_simple(raw_txn,sponsor.address(),); -
让发送者和赞助者同时签署交易。
使用
sign_fee_payer_transaction生成已签名交易。第二个参数是发送者,第三个是空切片(用于多代理赞助交易中的次要签名者),第四个是费用支付者。let signed_txn = aptos.sign_fee_payer_transaction(&fee_payer_txn,&alice, // Sender&[], // Secondary signers (empty for simple transactions)&sponsor, // Fee payer)?; -
提交交易并等待确认。
let result = aptos.submit_and_wait(signed_txn).await?;let success = result.data.get("success").and_then(|v| v.as_bool()).unwrap_or(false);println!("Transaction success: {}", success);
赞助的多代理交易
Section titled “赞助的多代理交易”您可以将费用支付者赞助与多代理交易结合使用。在这种情况下,在构造 FeePayerRawTransaction 和签名时提供次要签名者。
use aptos_sdk::types::FeePayerRawTransaction;
// Create fee payer transaction with secondary signerslet fee_payer_txn = FeePayerRawTransaction::new( raw_txn, vec![bob.address()], // Secondary signer addresses sponsor.address(), // Fee payer address);
// Sign with all partieslet signed_txn = aptos.sign_fee_payer_transaction( &fee_payer_txn, &alice, // Primary sender &[&bob as &dyn Account], // Secondary signers &sponsor, // Fee payer)?;INSUFFICIENT_BALANCE_FOR_TRANSACTION_FEE— 赞助者账户没有足够的 APT 来支付最大可能的 gas 费用。赞助者必须至少持有max_gas_amount * gas_unit_priceoctas。您可以先模拟交易以获得更精确的 gas 估算,然后相应地设置max_gas_amount。详见模拟交易。INVALID_AUTH_KEY—FeePayerRawTransaction中指定的费用支付者地址与签名为费用支付者的账户不匹配。请验证您在构造函数和签名函数中传递的是正确的赞助者账户。
完整工作示例
Section titled “完整工作示例”/// This example demonstrates a sponsored transaction where a separate/// account (sponsor) pays the gas fees for Alice's transfer to Bob.use aptos_sdk::{Aptos, AptosConfig};use aptos_sdk::account::Ed25519Account;use aptos_sdk::types::{EntryFunctionPayload, FeePayerRawTransaction};use aptos_sdk::transaction_builder::TransactionBuilder;
#[tokio::main]async fn main() -> anyhow::Result<()> { // Connect to testnet let aptos = Aptos::new(AptosConfig::testnet())?;
// Generate accounts let alice = Ed25519Account::generate(); let bob = Ed25519Account::generate(); let sponsor = Ed25519Account::generate();
// Fund accounts -- note that Alice only needs a small amount for the // transfer itself, while the sponsor needs enough to cover gas. aptos.fund_account(alice.address(), 100_000_000).await?; aptos.fund_account(bob.address(), 100_000_000).await?; aptos.fund_account(sponsor.address(), 100_000_000).await?;
println!("Alice: {}", alice.address()); println!("Bob: {}", bob.address()); println!("Sponsor: {}", sponsor.address());
// Check initial balances let alice_balance = aptos.get_balance(alice.address()).await?; let sponsor_balance = aptos.get_balance(sponsor.address()).await?; println!("\n=== Initial Balances ==="); println!("Alice: {} octas", alice_balance); println!("Sponsor: {} octas", sponsor_balance);
// 1. Build the payload let payload = EntryFunctionPayload::new( "0x1::aptos_account::transfer".parse()?, vec![], vec![bob.address().into(), 10_000_000u64.into()], );
// 2. Build the raw transaction let raw_txn = TransactionBuilder::new(payload, aptos.get_chain_id().await?) .sender(alice.address()) .sequence_number(aptos.get_sequence_number(alice.address()).await?) .max_gas_amount(10_000) .gas_unit_price(100) .expiration_timestamp_secs( aptos.get_latest_ledger_info().await?.timestamp() + 60, ) .build();
// 3. Create the fee payer transaction let fee_payer_txn = FeePayerRawTransaction::new_simple( raw_txn, sponsor.address(), );
// 4. Sign with both the sender and the sponsor let signed_txn = aptos.sign_fee_payer_transaction( &fee_payer_txn, &alice, &[], &sponsor, )?;
// 5. Submit and wait let result = aptos.submit_and_wait(signed_txn).await?; let success = result .data .get("success") .and_then(|v| v.as_bool()) .unwrap_or(false); println!("\nTransaction success: {}", success);
// Verify that the sponsor paid the gas, not Alice let new_alice_balance = aptos.get_balance(alice.address()).await?; let new_sponsor_balance = aptos.get_balance(sponsor.address()).await?; println!("\n=== Balances After Transfer ==="); println!("Alice: {} octas (paid only the transfer amount)", new_alice_balance); println!("Sponsor: {} octas (paid the gas fee)", new_sponsor_balance);
Ok(())}