Gas Tank
The Gas Tank pays network fees on behalf of WaaP users, so they can transact without holding native tokens for gas. It comes in two forms:
- Personal gas tanks: every WaaP user has one, funded and used entirely from inside the wallet. No integration work is needed on your side.
- Sponsor gas tanks: a pre-funded tank owned by your project. Once configured, transactions your users make on your dApp are paid from your tank instead of theirs, so they never think about gas at all.
This guide covers setting up sponsorship for your project. Everything is managed in the Gas Tank Console with your WaaP wallet.
The gas tank is not a paymaster. It does not co-sign or wrap your transaction. The user signs the exact transaction they reviewed, the gas tank transfers gas to their wallet, and then that unchanged transaction is broadcast. Nothing about the transaction differs from an unsponsored one.
Sponsoring your users’ gas
1. Create a project
Open the Gas Tank Console and sign in with your WaaP wallet. Opening your project creates it if it doesn’t exist yet: you get a project ID and an empty sponsor gas tank administered by your wallet.
2. Pass your project ID to the SDK
import { initWaaP } from "@human.tech/waap-sdk";
initWaaP({
project: {
projectId: "<your-project-id>",
// ...other project fields, e.g. name, logo
},
config: {
// ...UI configuration
},
});config is UI configuration (auth methods, styles) and has no projectId
field. A project ID passed there is silently ignored and nothing is ever
sponsored.
The same field works on the single-chain entry points, initWaaP({ chain: 'sui', project: { projectId } }) and initWaaP({ chain: 'solana', project: { projectId } }), and on initWaaPMulti.
With the project ID set, eligible transactions from your dApp are checked against your project’s gas tank and sponsored automatically.
3. Configure allowlists
Sponsorship is scoped by two allowlists, managed in the Gas Tank Console:
-
Targets: what your tank pays gas for, per chain. What counts as a target depends on the chain:
Chain Allowlisted target Matching EVM Transaction’s top-level toaddress (contract or EOA)Case-insensitive Sui Every Move call package ID and TransferObjectsrecipient encoded as a pure address inputCase-insensitive, zero-padding ignored Solana Every top-level instruction program ID in the compiled message Case-sensitive base58 -
Domains: the exact site origins allowed to request sponsorship. Enter only
scheme://host[:port], for examplehttps://app.example.com, without a path, query string, or fragment.
A transaction is sponsored only when the requesting origin and every target extracted from the transaction match. Anything outside the allowlists is not sponsored and the user pays gas as usual. The target allowlist is per chain, so the same address on another chain is a different entry.
The settings use [chain, target] tuples. EVM chains use numeric chain IDs; Sui
and Solana use their network references:
{
"transactions_allowed_to": [
[42161, "0x0000000000000000000000000000000000000001"],
["sui:mainnet", "0x0000000000000000000000000000000000000000000000000000000000000002"],
["solana:mainnet", "11111111111111111111111111111111"]
],
"domains_allowed": ["https://app.example.com"]
}Targets are extracted from the transaction structure, not from a full execution trace.
EVM allowlist examples
EVM extracts only the transaction’s outer to address:
- A native ETH transfer targets the recipient address.
USDC.transfer(recipient, amount)andUSDC.approve(spender, amount)both target the USDC contract. The recipient or spender encoded in calldata is not a target.- A router, proxy, or multicall transaction targets only the outer router, proxy, or multicall contract. Tokens, pools, implementations, and nested call destinations are not extracted.
For example, these entries allow a direct Arbitrum transfer to the first address and calls to the Arbitrum USDC contract:
[
[42161, "0x1111111111111111111111111111111111111111"],
[42161, "0xaf88d065e77c8cc2239327c5edb3a432268e5831"]
]Calling Permit2 directly requires a Permit2 entry, but approving Permit2 as an
ERC-20 spender requires the token contract entry instead. Contract creation has
no to address and cannot be sponsored.
Sui allowlist examples
Sui extracts each MoveCall.package and each TransferObjects recipient that
is encoded as a 32-byte pure address input. Duplicate targets are collapsed.
For a programmable transaction containing:
MoveCall: 0xabc::pool::swap
MoveCall: 0x2::coin::value
TransferObjects: output coin to 0xbbbb...bbbbthe allowlist needs all three targets:
[
["sui:mainnet", "0xabc"],
["sui:mainnet", "0x2"],
["sui:mainnet", "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"]
]Sui targets are lowercased and left-padded to 64 hex characters. Package IDs
used only as type arguments, object and coin IDs, SplitCoins, and MergeCoins
are not targets. A transaction with no Move call and no extractable transfer
recipient has an empty target list and is not eligible for project sponsorship.
If a transaction explicitly transfers its result to the current user, that user’s address is a target and must be allowlisted.
Solana allowlist examples
Solana extracts each unique top-level instruction program ID in the compiled message. A managed native SOL transfer contains Compute Budget and System Program instructions, so it needs both entries:
[
["solana:mainnet", "ComputeBudget111111111111111111111111111111"],
["solana:mainnet", "11111111111111111111111111111111"]
]An SPL token transfer that creates the recipient’s associated token account contains Compute Budget, Associated Token Account, and SPL Token instructions:
[
["solana:mainnet", "ComputeBudget111111111111111111111111111111"],
["solana:mainnet", "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"],
["solana:mainnet", "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"]
]A swap must allow every top-level program present in its compiled instructions, such as Compute Budget, the swap program, and SPL Token. Recipient wallets, mints, token accounts, pools, vaults, and programs invoked only through CPI are not extracted. Sponsored instruction program IDs must be present in the message’s static accounts. Solana IDs remain case-sensitive.
4. Fund the tank
Fund your tank from the Gas Tank Console. The deposit is sent from your admin wallet and credited to the project. The current balance is shown in the console, and each sponsored transaction is deducted from it.
A tank holds one balance per asset, and each chain is paid in its own asset: EVM sponsorship spends the ETH balance, Sui spends SUI, Solana spends SOL. Fund every chain you intend to sponsor on.
For the ETH balance, the amount shown is the gross balance and the amount spendable on gas is 90% of it. Each sponsored transaction deducts its gas cost ÷ 0.9.
When sponsorship applies
There is no SDK method to call at send time. When a transaction is eligible, WaaP sponsors it during send; when it is not, the transaction proceeds normally and the user pays gas. Your integration code is identical either way.
The order matters, and it is deliberate:
- The user reviews and signs the exact transaction.
- Eligibility is re-validated server-side. The check at preparation time is advisory and is not trusted at send time.
- Gas is transferred to the user’s wallet.
- The funding is observed on-chain.
- The original, unchanged transaction is broadcast.
Signing happens before funding, and broadcast happens only after funding is observed. Preparing a transaction never spends or reserves tank balance, so a prepared-then-abandoned transaction costs nothing.
What is not eligible
- Any chain outside the supported list below.
- Contract creation.
- A target or domain outside your project’s allowlists.
- Anything when the tank’s balance is insufficient.
Rejections are deliberately generic in production responses. The gas tank owns its own identity, allowlist, and balance rules, and does not leak which one failed. In local development the bounded detail is retained so you can tell a missing tank from a sender mismatch or an empty balance.
Supported chains
- EVM: ETH-native mainnet chains: Ethereum, Optimism, Base, Arbitrum, zkSync, Shape, World Chain, Linea, and Scroll. Chains whose native token is not ETH (such as Polygon, Gnosis, Avalanche, or Celo) cannot be sponsored. See Supported Networks for the full chain list.
- Sui: sponsored from the project’s SUI balance when every Move call package
ID and every
TransferObjectsrecipient encoded as a pure address input is allowlisted. - Solana: sponsored from the project’s SOL balance when every top-level instruction program ID in the compiled message is allowlisted.
Testnet transactions are never sponsored.
A chain appearing in some other registry does not start being sponsored as a side effect. Adding one here is a deliberate decision.
Sui sponsorship works by having the sponsor’s own coin pay for gas, so a
sponsored transaction may not take its value from transaction.gas. A plain
SUI transfer built that way can never be sponsored, however the project is
configured. Move a non-gas asset instead.
Solana also refuses to leave an account below the rent-exempt minimum, so a user account holding no SOL at all cannot move SOL however well funded the project is.
Security notes
- The gas tank never has access to user funds. It only ever sends gas money to the user’s address before a transaction.
- Wallet addresses are resolved server-side from the user’s keyshares; the sponsorship API never trusts a client-supplied address.
- The requesting origin is verified server-side against your domain allowlist; a page cannot claim an origin it is not served from.
Related
- Gas Tank Console: Create, configure, and fund your project’s tank
- Transactions: Sending sponsored transactions with the SDK
- Supported Networks: Full chain list