Go SDK - Sponsoring Transactions
Normally, the account that is executing a transaction pays for the gas fees. You can allow another account to cover those charges by sponsoring a transaction.
This can be used to help manage fees from a central account when working with complicated smart contracts.
How To Sponsor a Transaction
Section titled “How To Sponsor a Transaction”-
Build the transaction with the parameter FeePayer().
rawTxn, err := client.BuildTransactionMultiAgent(alice.Address,aptos.TransactionPayload{Payload: transferPayload,},aptos.FeePayer(&sponsor.Address),) -
Sign the transaction with BOTH the sender and the feePayer.
- Sign with the sender account using
rawTxn.Sign()
. - Sign with the sponsor account using
rawTxn.Sign()
.
aliceAuth, err := rawTxn.Sign(alice)if err != nil {panic("Failed to sign transaction as sender:" + err.Error())}sponsorAuth, err := rawTxn.Sign(sponsor)if err != nil {panic("Failed to sign transaction as sponsor:" + err.Error())} - Sign with the sender account using
-
Submit the transaction by combining both signatures.
signedFeePayerTxn, ok = rawTxn.ToFeePayerSignedTransaction(aliceAuth,sponsorAuth,[]crypto.AccountAuthenticator{},)if !ok {panic("Failed to build fee payer signed transaction")}// Submit and wait for it to completesubmitResult, err = client.SubmitTransaction(signedFeePayerTxn)if err != nil {panic("Failed to submit transaction:" + err.Error())} -
Wait for the transaction to execute.
// Wait for the transaction_, err = client.WaitForTransaction(txnHash)
Go Sponsored Transaction Code Sample
Section titled “Go Sponsored Transaction Code Sample”// sponsored_transaction is an example of how to make a sponsored transaction in Aptos.package main
import ( "fmt"
"github.com/aptos-labs/aptos-go-sdk" "github.com/aptos-labs/aptos-go-sdk/crypto")
const FundAmount = 100_000_000const TransferAmount = 1_000
// example This example shows you how to make an APT transfer transaction in the simplest possible wayfunc example(networkConfig aptos.NetworkConfig) { // Create a client for Aptos client, err := aptos.NewClient(networkConfig) if err != nil { panic("Failed to create client:" + err.Error()) }
// Create accounts locally for alice and bob alice, err := aptos.NewEd25519Account() if err != nil { panic("Failed to create alice:" + err.Error()) } bob, err := aptos.NewEd25519Account() if err != nil { panic("Failed to create bob:" + err.Error()) } sponsor, err := aptos.NewEd25519Account() if err != nil { panic("Failed to create sponsor:" + err.Error()) }
fmt.Printf("\n=== Addresses ===\n") fmt.Printf("Alice: %s\n", alice.Address.String()) fmt.Printf("Bob:%s\n", bob.Address.String()) fmt.Printf("Sponsor:%s\n", sponsor.Address.String())
// Fund the alice with the faucet to create it on-chain err = client.Fund(alice.Address, FundAmount) if err != nil { panic("Failed to fund alice:" + err.Error()) }
// And the sponsor err = client.Fund(sponsor.Address, FundAmount) if err != nil { panic("Failed to fund sponsor:" + err.Error()) }
aliceBalance, err := client.AccountAPTBalance(alice.Address) if err != nil { panic("Failed to retrieve alice balance:" + err.Error()) } bobBalance, err := client.AccountAPTBalance(bob.Address) if err != nil { panic("Failed to retrieve bob balance:" + err.Error()) } sponsorBalance, err := client.AccountAPTBalance(sponsor.Address) if err != nil { panic("Failed to retrieve sponsor balance:" + err.Error()) } fmt.Printf("\n=== Initial Balances ===\n") fmt.Printf("Alice: %d\n", aliceBalance) fmt.Printf("Bob: %d\n", bobBalance) fmt.Printf("Sponsor: %d\n", sponsorBalance)
// Build transaction transferPayload, err := aptos.CoinTransferPayload(&aptos.AptosCoinTypeTag, bob.Address, TransferAmount) if err != nil { panic("Failed to build transfer payload:" + err.Error()) } rawTxn, err := client.BuildTransactionMultiAgent( alice.Address, aptos.TransactionPayload{ Payload: transferPayload, }, aptos.FeePayer(&sponsor.Address),
) if err != nil { panic("Failed to build transaction:" + err.Error()) }
// Sign transaction aliceAuth, err := rawTxn.Sign(alice) if err != nil { panic("Failed to sign transaction as sender:" + err.Error()) } sponsorAuth, err := rawTxn.Sign(sponsor) if err != nil { panic("Failed to sign transaction as sponsor:" + err.Error()) }
signedFeePayerTxn, ok := rawTxn.ToFeePayerSignedTransaction( aliceAuth, sponsorAuth, []crypto.AccountAuthenticator{}, ) if !ok { panic("Failed to build fee payer signed transaction") }
// Submit and wait for it to complete submitResult, err := client.SubmitTransaction(signedFeePayerTxn) if err != nil { panic("Failed to submit transaction:" + err.Error()) } txnHash := submitResult.Hash println("Submitted transaction hash:", txnHash)
// Wait for the transaction _, err = client.WaitForTransaction(txnHash) if err != nil { panic("Failed to wait for transaction:" + err.Error()) } aliceBalance, err = client.AccountAPTBalance(alice.Address) if err != nil { panic("Failed to retrieve alice balance:" + err.Error()) } bobBalance, err = client.AccountAPTBalance(bob.Address) if err != nil { panic("Failed to retrieve bob balance:" + err.Error()) } sponsorBalance, err = client.AccountAPTBalance(sponsor.Address) if err != nil { panic("Failed to retrieve sponsor balance:" + err.Error()) } fmt.Printf("\n=== Intermediate Balances ===\n") fmt.Printf("Alice: %d\n", aliceBalance) fmt.Printf("Bob: %d\n", bobBalance) fmt.Printf("Sponsor: %d\n", sponsorBalance)
fmt.Printf("\n=== Now do it without knowing the signer ahead of time ===\n")
rawTxn, err = client.BuildTransactionMultiAgent( alice.Address, aptos.TransactionPayload{ Payload: transferPayload, }, aptos.FeePayer(&aptos.AccountZero), // Note that the Address is 0x0, because we don't know the signer ) if err != nil { panic("Failed to build transaction:" + err.Error()) }
// Alice signs the transaction, without knowing the sponsor aliceAuth, err = rawTxn.Sign(alice) if err != nil { panic("Failed to sign transaction as sender:" + err.Error()) }
// The sponsor has to add themselves to the transaction to sign, note that this would likely be on a different // server ok = rawTxn.SetFeePayer(sponsor.Address) if !ok { panic("Failed to set fee payer") }
sponsorAuth, err = rawTxn.Sign(sponsor) if err != nil { panic("Failed to sign transaction as sponsor:" + err.Error()) }
signedFeePayerTxn, ok = rawTxn.ToFeePayerSignedTransaction( aliceAuth, sponsorAuth, []crypto.AccountAuthenticator{}, ) if !ok { panic("Failed to build fee payer signed transaction") }
// Submit and wait for it to complete submitResult, err = client.SubmitTransaction(signedFeePayerTxn) if err != nil { panic("Failed to submit transaction:" + err.Error()) } txnHash = submitResult.Hash println("Submitted transaction hash:", txnHash)
// Wait for the transaction _, err = client.WaitForTransaction(txnHash) if err != nil { panic("Failed to wait for transaction:" + err.Error()) } aliceBalance, err = client.AccountAPTBalance(alice.Address) if err != nil { panic("Failed to retrieve alice balance:" + err.Error()) } bobBalance, err = client.AccountAPTBalance(bob.Address) if err != nil { panic("Failed to retrieve bob balance:" + err.Error()) } sponsorBalance, err = client.AccountAPTBalance(sponsor.Address) if err != nil { panic("Failed to retrieve sponsor balance:" + err.Error()) } fmt.Printf("\n=== Final Balances ===\n") fmt.Printf("Alice: %d\n", aliceBalance) fmt.Printf("Bob: %d\n", bobBalance) fmt.Printf("Sponsor: %d\n", sponsorBalance)}
func main() { example(aptos.DevnetConfig)}