What is gas abstraction?
Overview
gasabs (Gas Abstraction Interface) is a Go-based service that abstracts gas handling for CROSS chain network transactions and provides a fee delegation feature. This solution enables gas fee sponsorship (Fee Delegation) for transactions that meet specific conditions.
Key Features
1. Transaction Fee Delegation
The core functionality of gasabs is to pay gas fees on behalf of transactions that meet certain criteria. This process involves the following steps:
- User creates and signs a transaction (DynamicFeeTx EIP1559)
- Transaction is sent to the gasabs API
- gasabs validates the transaction:
- Checks if the target address is an approved contract
- Verifies if the transaction format is eligible for fee delegation
- Validates transaction execution through simulation
- Verifies if the transaction format is eligible for fee delegation
- Checks if the target address is an approved contract
- If validation passes, FeePayer adds its signature and converts it to a FeeDelegatedDynamicFeeTx
- Returns the final transaction
2) Transaction Filtering
gasabs processes only transactions that meet specific filter rules.
Detailed fee delegation policies will be provided on a separate page.
API Specification
gasabs provides its services through RPC API:
1. Fee Delegated Transaction Signing
Item | Description |
---|---|
Method |
|
Parameters | raw transaction of dynamic Fee Tx |
Return Value | Transaction data with fee delegation signature (hexadecimal string) |
Errors | ErrorDisapprovedAddress: Unapproved address ErrorNondelegableTx: Non-delegable transaction ErrorRevertExpected: Error during transaction execution ErrorInvalidTransactionType: Invalid transaction type ErrorNotFoundMethodSig: Missing method signature |
2. Address Approval Check
Item | Description |
---|---|
Method | gasabs_isApproved |
Parameters | Contract address to check |
Return Value | boolean (approval status) |
Client Usage Examples
Example 1: Direct Transaction Submission to Node
package main
import (
"context"
"crypto/ecdsa"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
)
func main() {
// Connect to Ethereum node
client, err := ethclient.Dial("http://localhost:8545")
if err != nil {
log.Fatalf("Failed to connect to Ethereum node: %v", err)
}
// Generate a new private key
privateKey, err := crypto.GenerateKey()
if err != nil {
log.Fatalf("Failed to generate private key: %v", err)
}
// Get the public address from the private key
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("Failed to cast public key to ECDSA")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
fmt.Printf("From address: %s\n", fromAddress.Hex())
// Get chain ID
chainID, err := client.NetworkID(context.Background())
if err != nil {
log.Fatalf("Failed to get chain ID: %v", err)
}
// Get the latest nonce for the from address
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
log.Fatalf("Failed to get nonce: %v", err)
}
// Get gas price estimates
tipCap, err := client.SuggestGasTipCap(context.Background())
if err != nil {
log.Fatalf("Failed to suggest gas tip cap: %v", err)
}
baseFee, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatalf("Failed to suggest gas price: %v", err)
}
maxFeePerGas := new(big.Int).Add(baseFee, big.NewInt(2000000000)) // Base fee + 2 Gwei buffer
// Target contract address
toAddress := common.HexToAddress("0x1234567890123456789012345678901234567890")
// Transaction parameters
value := big.NewInt(0) // 0 ETH
gasLimit := uint64(100000) // Gas limit
data := []byte{0x1, 0x2, 0x3, 0x4} // Method call data (example)
// Create an EIP-1559 transaction
tx := types.NewTx(&types.DynamicFeeTx{
ChainID: chainID,
Nonce: nonce,
To: &toAddress,
Value: value,
Gas: gasLimit,
GasFeeCap: maxFeePerGas,
GasTipCap: tipCap,
Data: data,
})
// Sign the transaction
signer := types.LatestSignerForChainID(chainID)
signedTx, err := types.SignTx(tx, signer, privateKey)
if err != nil {
log.Fatalf("Failed to sign transaction: %v", err)
}
// Send the transaction
err = client.SendTransaction(context.Background(), signedTx)
if err != nil {
log.Fatalf("Failed to send transaction: %v", err)
}
fmt.Printf("Transaction sent: %s\n", signedTx.Hash().Hex())
}
Example 2: Using gasabs for Fee Delegated Transactions
package main
import (
"context"
"crypto/ecdsa"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/node"
"github.com/to-nexus/gasabs"
)
func main() {
// Connect to CROSS chain node for transaction preparation
ethClient, err := ethclient.Dial("http://localhost:8545")
if err != nil {
log.Fatalf("Failed to connect to Cross chain node: %v", err)
}
// Connect to gasabs service
gasabsClient, err := gasabs.Dial(node.GasAbstraction{
GasAbsURL: "http://localhost:8090",
})
if err != nil {
log.Fatalf("Failed to connect to gasabs: %v", err)
}
defer gasabsClient.Close()
// Generate a new private key for the transaction sender
privateKey, err := crypto.GenerateKey()
if err != nil {
log.Fatalf("Failed to generate private key: %v", err)
}
// Get the sender's address
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("Failed to cast public key to ECDSA")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
fmt.Printf("From address: %s\n", fromAddress.Hex())
// Get chain ID
chainID, err := ethClient.NetworkID(context.Background())
if err != nil {
log.Fatalf("Failed to get chain ID: %v", err)
}
// Get the latest nonce for the from address
nonce, err := ethClient.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
log.Fatalf("Failed to get nonce: %v", err)
}
// Get gas price estimates
tipCap, err := ethClient.SuggestGasTipCap(context.Background())
if err != nil {
log.Fatalf("Failed to suggest gas tip cap: %v", err)
}
baseFee, err := ethClient.SuggestGasPrice(context.Background())
if err != nil {
log.Fatalf("Failed to suggest gas price: %v", err)
}
maxFeePerGas := new(big.Int).Add(baseFee, big.NewInt(2000000000)) // Base fee + 2 Gwei buffer
// Target contract address - make sure this is an approved contract in gasabs
contractAddr := common.HexToAddress("0x1234567890123456789012345678901234567890")
// Check if the contract is approved for fee delegation
approved, err := gasabsClient.IsApproved(context.Background(), contractAddr)
if err != nil {
log.Fatalf("Failed to check approval: %v", err)
}
if !approved {
log.Fatalf("Contract address not approved for fee delegation")
}
// Transaction parameters
value := big.NewInt(0) // 0 ETH
gasLimit := uint64(100000) // Gas limit
data := []byte{0x1, 0x2, 0x3, 0x4} // Method signature + parameters (at least 4 bytes)
// Create an EIP-1559 transaction
tx := types.NewTx(&types.DynamicFeeTx{
ChainID: chainID,
Nonce: nonce,
To: &contractAddr,
Value: value,
Gas: gasLimit,
GasFeeCap: maxFeePerGas,
GasTipCap: tipCap,
Data: data,
})
// Sign the transaction with sender's private key
signer := types.LatestSignerForChainID(chainID)
signedTx, err := types.SignTx(tx, signer, privateKey)
if err != nil {
log.Fatalf("Failed to sign transaction: %v", err)
}
// Request fee delegation from gasabs
feeDelegatedTx, err := gasabsClient.SignFeeDelegateTransaction(context.Background(), signedTx)
if err != nil {
log.Fatalf("Failed to get fee delegated transaction: %v", err)
}
// Send the fee delegated transaction to the network
err = ethClient.SendTransaction(context.Background(), feeDelegatedTx)
if err != nil {
log.Fatalf("Failed to send fee delegated transaction: %v", err)
}
fmt.Printf("Original transaction hash: %s\n", signedTx.Hash().Hex())
fmt.Printf("Fee delegated transaction hash: %s\n", feeDelegatedTx.Hash().Hex())
fmt.Println("Fee delegated transaction successfully sent!")
}
Updated 26 days ago