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.
Avalanche C-Chain is not supported with this approach. Please refer to the SmartAccount guide.
API Guide
The overall flow consists of 3 steps.
| Step | Method | Endpoint |
|---|---|---|
| 1. Sponsor | POST | /core/evm/v2/eoa/paymaster/sponsor |
| 2. Send | POST | /core/evm/v2/eoa/paymaster/send |
| 3. Receipt | GET | /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..."
}
| Field | Description |
|---|---|
network | Target network identifier |
from | Sender EOA address |
to | Recipient address (contract or EOA) |
value | Amount of ETH to transfer (wei, hex) |
data | Contract 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..."
}
| Field | Description |
|---|---|
sponsored_transaction | Data to pass as-is in Step 2 Send |
sign_hash | UserOperation hash the EOA must sign |
authorization | Included only on the first transaction. See below |
authorization_hash | Included 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..."
}
}
| Field | Description |
|---|---|
sponsored_transaction | Pass the sponsored_transaction from Step 1 response as-is |
signature | Signature over sign_hash. See below |
authorization | Included only on the first transaction. See below |
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,
};