Skip to main content

Transaction Fee Sponsorship

With ABC Paymaster, you can sponsor transaction fees for your users without changing their existing EOA wallet address.
It is powered by EIP-7702, which automatically handles delegation setup on the first sponsored transaction.
After that, users can send transactions fee-free by simply providing transaction parameters.

Supported Networks

Currently, the supported networks for gas sponsorship are Ethereum, Kaia, and Base.
For testnets, Ethereum Sepolia, Kaia Kairos, and Base Sepolia are supported.

Using Avalanche C-Chain?

Avalanche C-Chain is not supported with this approach. Please refer to the SmartAccount guide.

API Guide

The overall flow consists of 3 steps.

StepMethodEndpoint
1. SponsorPOST/core/evm/v2/eoa/paymaster/sponsor
2. SendPOST/core/evm/v2/eoa/paymaster/send
3. ReceiptGET/core/evm/v2/eoa/paymaster/receipt

1. Sponsor

Send the gas sponsorship request and receive the data to sign.

Request

POST /core/evm/v2/eoa/paymaster/sponsor
{
"network": "ethereum-sepolia",
"from": "0xAbC...",
"to": "0xDeF...",
"value": "0x0",
"data": "0x..."
}
FieldDescription
networkTarget network identifier
fromSender EOA address
toRecipient address (contract or EOA)
valueAmount of ETH to transfer (wei, hex)
dataContract call data. Use "0x" for simple transfers

Response

{
"sponsored_transaction": {
"sender": "0xAbC...",
"nonce": "0x1",
"callData": "0x...",
"callGasLimit": "0x...",
"verificationGasLimit": "0x...",
"preVerificationGas": "0x...",
"maxFeePerGas": "0x...",
"maxPriorityFeePerGas": "0x...",
"paymasterAndData": "0x...",
"signature": "0x"
},
"sign_hash": "0xabcdef...",
"authorization": {
"chainId": "0x...",
"address": "0x...",
"nonce": "0x..."
},
"authorization_hash": "0x..."
}
FieldDescription
sponsored_transactionData to pass as-is in Step 2 Send
sign_hashUserOperation hash the EOA must sign
authorizationIncluded only on the first transaction. See below
authorization_hashIncluded only on the first transaction. See below

2. Send

Submit the signed data.

Request

POST /core/evm/v2/eoa/paymaster/send
{
"network": "ethereum-sepolia",
"sponsored_transaction": { "..." },
"signature": "0x...",
"authorization": {
"chainId": "0x...",
"address": "0x...",
"nonce": "0x...",
"v": 0,
"r": "0x...",
"s": "0x..."
}
}
FieldDescription
sponsored_transactionPass the sponsored_transaction from Step 1 response as-is
signatureSignature over sign_hash. See below
authorizationIncluded only on the first transaction. See below
warning

Modifying any field in sponsored_transaction will cause signature verification to fail. Pass it exactly as received.

Response

{
"tx_id": "0x..."
}

3. Receipt

Query the transaction result using tx_id.

Request

GET /core/evm/v2/eoa/paymaster/receipt?tx_id={tx_id}&network={network}

The response may return null if the transaction is still processing. Poll until the result is available.

Signing

Both sign_hash and authorization_hash are signed using the WaaS MPC Sign API.

POST /v3/wallet/sign
{
"curve": "secp256k1",
"encrypted_share": "Encrypted MPC share from wallet generation/recovery",
"key_id": "Unique identifier of the signing key",
"message": "Hash to sign (hex string)",
"secret_store": "Key used to decrypt the share"
}

Signing sign_hash

sign_hash requires personal_sign. Compute the Ethereum personal_sign prefixed hash before passing it to /v3/wallet/sign.

import { keccak256, toBytes, concat, toHex } from 'viem';

// Apply personal_sign prefix
const prefix = toBytes(`\x19Ethereum Signed Message:\n32`);
const messageHash = keccak256(concat([prefix, toBytes(sponsorResponse.sign_hash)]));

const signRes = await fetch('/v3/wallet/sign', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` },
body: JSON.stringify({
curve: 'secp256k1',
encrypted_share: encryptedShare,
key_id: keyId,
message: messageHash,
secret_store: secretStore,
}),
});
const { signature } = await signRes.json();

const sendSignature = `0x${signature}`;

Signing authorization_hash (first transaction only)

authorization and authorization_hash are included in the Sponsor response only when the EOA is sending a sponsored transaction for the first time. They are omitted in subsequent transactions.

Pass authorization_hash as message, then split the 65-byte signature (130 hex chars) into r, s, v to populate the authorization object.

const authSignRes = await fetch('/v3/wallet/sign', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` },
body: JSON.stringify({
curve: 'secp256k1',
encrypted_share: encryptedShare,
key_id: keyId,
message: sponsorResponse.authorization_hash,
secret_store: secretStore,
}),
});
const { signature: authSig } = await authSignRes.json();

// Split 65-byte signature (130 hex chars) into r, s, v
const r = `0x${authSig.slice(0, 64)}`;
const s = `0x${authSig.slice(64, 128)}`;
const v = parseInt(authSig.slice(128, 130), 16) - 27; // 0 or 1

const authorization = {
...sponsorResponse.authorization,
v,
r,
s,
};