Skip to content
🎉 Welcome to the new Aptos Docs! Click here to submit feedback!
BuildSDKsGo SDKTransactionsSponsoring Transactions

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

Build the transaction with the parameter FeePayer().

sponsor.go
  rawTxn, err := client.BuildTransactionMultiAgent(
  alice.Address,
  aptos.TransactionPayload{
  Payload: transferPayload,
  },
  aptos.FeePayer(&sponsor.Address),
  )

The FeePayer() function is used to specify the account that will pay the gas fees for the transaction. You can use AccountZero to indicate that the fee payer is not known ahead of time.

Sign the transaction with BOTH the sender and the feePayer.

  1. Sign with the sender account using rawTxn.Sign().
  2. Sign with the sponsor account using rawTxn.Sign().
sponsor.go
  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())
  }

Submit the transaction by combining both signatures.

sponsor.go
  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())
  }

Wait for the transaction to execute.

sponsor.go
  // Wait for the transaction
  _, err = client.WaitForTransaction(txnHash)

Go Sponsored Transaction Code Sample

sponsor.go
// 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_000
const TransferAmount = 1_000
 
// example This example shows you how to make an APT transfer transaction in the simplest possible way
func 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)
}