# Gas Station

Executive summary
**The Gas Station Service automatically funds transaction fees for sponsored accounts.**

- Eliminates the need for end-user accounts to hold native tokens for gas fees.
- Supports account-level and domain-level sponsorship with subdomain inheritance.
- Works with Ethereum and EVM-compatible blockchains.
- Uses Just-in-Time (JIT) funding to transfer exact fee amounts when needed.
- Provides low-balance alerts to ensure sponsor accounts remain funded.


Why this matters
**For operators**: Gas Station removes friction from end-user transactions. Users don't need to acquire native tokens (e.g., ETH) just to pay fees—your organization sponsors those costs from designated accounts. This is essential for onboarding users who hold only stablecoins or other tokens.

**For architects**: The service integrates with existing Ripple Custody policies and intents. A dedicated bot user handles automated approvals, so you maintain full audit trails while eliminating manual fee-funding steps.

Current limitations
- **Chain support**: Ethereum and EVM-compatible chains only. Support for additional chains (Solana, XRPL) will be added in the future.
- **Alert delivery**: Low-balance alerts are delivered through your monitoring infrastructure. Configure alerts in your monitoring system (e.g., Grafana) to receive email or Slack notifications.
- **Cross-chain sponsorship**: A sponsor account can only fund accounts on the same blockchain network.
- **Implementation approach**: The current Gas Station implementation uses a mechanical funding approach: the service detects pending transactions and transfers gas fees from sponsor accounts to sponsored accounts as standard blockchain transactions. This release does not leverage native gas abstraction mechanisms such as ERC-4337 Paymasters. Support for native paymaster integration (including EIP-7701 Native Account Abstraction) will be added in the future.


Before you begin
**Prerequisites**: Familiarity with Ripple Custody [accounts](/products/custody/v1.34/concepts/accounts), [domains](/products/custody/v1.34/concepts/governance/domains), and [transaction processing](/products/custody/v1.34/concepts/transactions-processing).

**Further reading**:

- [Gas Station reference](/products/custody/v1.34/deployment/reference/gas-station) — On-premise deployment configuration
- [Configure bot users](/products/custody/v1.34/api/environment/user/bot-user) — Set up bot users for automated operations
- [Configure gas sponsorship](/products/custody/v1.34/api/accounting/gas-station/configure-sponsorship) — API guide with step-by-step instructions


## Overview

The Gas Station Service is a background service that monitors transaction events and automatically funds accounts that lack sufficient native tokens to cover gas fees. When a sponsored account initiates a transaction, the service:

1. Detects the pending transaction
2. Estimates the required fee using a dry-run API call
3. Transfers the exact amount (plus a safety margin) from the sponsor account
4. Allows the original transaction to proceed


## Processing flow

The Gas Station Service continuously monitors Ripple Custody for transaction events and automatically funds accounts that need gas. The following state diagram shows the decision logic at each step:


```mermaid
stateDiagram-v2
    [*] --> PollEvents

    state "Poll Events" as PollEvents
    state "Outbound Transaction Detected" as OutboundTx
    state "Is Account Sponsored?" as AcctSponsored
    state "Is Domain Sponsored?" as DomainSponsored
    state "Estimate Fee via Dry-Run API" as EstimateFee
    state "Create Funding Transaction Intent" as CreateIntent
    state "Does Sponsor Have Sufficient Balance?" as SponsorBal
    state "Funding Successful" as FundingSuccess
    state "Does Sponsor Still Have Sufficient Balance?" as SponsorStillBal
    state "Account Has Sufficient Funds for Fees" as AcctHasFunds
    state "Send Low Balance Alert" as SendAlert
    state "Do nothing" as DoNothing

    PollEvents --> OutboundTx : Event detected

    state check_funds <<choice>>
    OutboundTx --> check_funds
    check_funds --> AcctHasFunds : Has sufficient funds
    check_funds --> AcctSponsored : Insufficient funds

    state is_acct_sponsored <<choice>>
    AcctSponsored --> is_acct_sponsored
    is_acct_sponsored --> EstimateFee : Yes (account sponsored)
    is_acct_sponsored --> DomainSponsored : No

    state is_domain_sponsored <<choice>>
    DomainSponsored --> is_domain_sponsored
    is_domain_sponsored --> EstimateFee : Yes (domain sponsored)
    is_domain_sponsored --> DoNothing : No sponsor found

    EstimateFee --> CreateIntent
    CreateIntent --> SponsorBal

    state has_sufficient_balance <<choice>>
    SponsorBal --> has_sufficient_balance
    has_sufficient_balance --> FundingSuccess : Yes (sufficient balance)
    has_sufficient_balance --> SendAlert : No (low balance)

    FundingSuccess --> SponsorStillBal

    state still_has_balance <<choice>>
    SponsorStillBal --> still_has_balance
    still_has_balance --> [*] : Yes
    still_has_balance --> SendAlert : No

    AcctHasFunds --> [*] : No sponsorship needed
    SendAlert --> [*]
    DoNothing --> [*]
```

### Flow steps

#### 1. Poll Events

The Gas Station Service continuously polls Ripple Custody for transaction events using the `/v1/domains/{domainId}/events` endpoint. The polling interval is configurable (default: 5 seconds).

#### 2. Detect Transaction

When an event is received, the service identifies outbound transactions by checking the `orderReference` field. Inbound transactions (where `orderReference` is null) are ignored.

#### 3. Check Balance

The service retrieves the account's native token balance using `/v1/domains/{domainId}/accounts/{accountId}/balances`. If the account already has sufficient funds for the estimated fee, no sponsorship is needed.

#### 4. Check Sponsorship

For accounts with insufficient balance, the service looks up sponsorship configuration:

- **Account-level first**: Check if the specific account has a dedicated sponsor
- **Domain-level second**: Check if the account's domain has a sponsor (with optional subdomain inheritance)


If no sponsor is found, the transaction remains in "Preparing" state until funds are manually added.

#### 5. Estimate Fee

The service uses Ripple Custody's dry-run API to calculate the exact gas amount required for the transaction. A configurable safety margin (default: 10%) is applied to account for fee volatility.

#### 6. Create Funding Intent

The service generates a transaction order payload to transfer the required gas amount from the sponsor account to the sponsored account. This payload is signed by the bot user's private key.

#### 7. Check Sponsor Balance

Before submitting, the service verifies the sponsor account has sufficient funds via a dry-run check. If the sponsor lacks funds, the funding transaction is not submitted.

#### 8. Alert if Low

After successful funding (or if funding fails due to low balance), the service checks the sponsor's remaining balance against configured alert thresholds. If the balance falls below the threshold, a notification is sent to the monitoring system.

## Detailed sequence

The following diagram shows the complete API interactions between the Gas Station Service and Ripple Custody, including the specific endpoints called at each step:


```mermaid
sequenceDiagram
    actor User
    participant RCUS
    participant GasStation

    User->>RCUS: createTransactionOrderIntent()
    Note over RCUS: Transaction will stay in preparing if not enough fees

    GasStation->>RCUS: pollTransactionCreatedEvents(): { transactionId }
    Note right of GasStation: /v1/domains/{domainId}/events

    GasStation->>RCUS: getTransactionDetails(transactionId): { orderReference.id }
    Note right of GasStation: /v1/domains/{domainId}/transactions/{transactionId}

    alt orderReference is null
        Note right of GasStation: Inbound transaction, ignore it
    else orderReference is not null
        GasStation->>RCUS: getTransactionOrderDetails(orderReference.id): { accountSourceId, ... }
        Note right of GasStation: /v1/domains/{domainId}/transactions/orders/{transactionOrderId}

        GasStation->>RCUS: getAccountNativeBalance(accountSourceId): accountNativeBalance
        Note right of GasStation: /v1/domains/{domainId}/accounts/{accountId}/balances

        GasStation->>RCUS: getIntentForTransactionOrder(orderReference.id, "v0_CreateTransactionOrder"): intent
        Note right of GasStation: /v1/domains/{domainId}/intents?entityId={transactionOrderId}&details.payload.type="v0_CreateTransactionOrder"

        GasStation->>RCUS: runDryRunForIntent(intent.id): { estimate.fee }
        Note right of GasStation: Get estimated transaction fee

        alt accountNativeBalance >= estimate.fee
            Note right of GasStation: Account has sufficient balance<br/>No sponsorship needed
        else accountNativeBalance < estimate.fee
            GasStation->>GasStation: findSponsoringAccount(accountSourceId): sponsorAccountId

            alt sponsorAccountId is null
                Note right of GasStation: No sponsor found<br/>Transaction remains in preparing state
            else sponsor found
                GasStation->>GasStation: createTransactionOrderPayload(sponsorAccountId, accountSourceId, estimate.fee)

                GasStation->>RCUS: runDryRun(payload): dryRunResult

                alt dryRunResult is success (Enough funds in sponsor)
                    GasStation->>GasStation: signIntent(payload)
                    GasStation->>RCUS: submitIntent(signedPayload)
                    Note right of GasStation: Fund the sponsored account with gas

                    GasStation->>RCUS: getSponsorBalance(sponsorAccountId): sponsorBalance

                    alt sponsorBalance < configuredAlertLimit
                        GasStation->>RCUS: sendNotification("Sponsor low balance")
                        Note right of GasStation: Alert user to refill sponsor account
                    end
                end
            end
        end
    end
```

## Sponsorship hierarchy

The Gas Station Service supports flexible sponsorship configurations:

| Level | Description |
|  --- | --- |
| **Account-level** | A sponsor account funds a specific list of accounts |
| **Domain-level** | A sponsor account funds all accounts within a domain |
| **Subdomain inheritance** | When `includeSubDomains` is enabled, sponsorship extends to all child domains |


### Lookup algorithm

When determining which sponsor to use, the service follows this hierarchy:

1. **Direct account sponsor**: Check if the account has a dedicated sponsor
2. **Domain sponsor**: Check if the account's domain has a sponsor
3. **Parent domain sponsor**: If `includeSubDomains` is enabled, walk up the domain hierarchy



```mermaid
flowchart TD
    A[Transaction detected] --> B{Account has direct sponsor?}
    B -->|Yes| C[Use account sponsor]
    B -->|No| D{Domain has sponsor?}
    D -->|Yes| E[Use domain sponsor]
    D -->|No| F{Parent domain with includeSubDomains?}
    F -->|Yes| G[Use parent domain sponsor]
    F -->|No| H[No sponsorship - transaction waits]
```

Each account can have only one sponsor. If you configure both account-level and domain-level sponsorship, the account-level sponsor takes precedence.

## Supported chains

The Gas Station Service currently supports Ethereum and EVM-compatible blockchains:

| Chain type | Networks | Fee token |
|  --- | --- | --- |
| **EVM-compatible** | Ethereum, Polygon, Avalanche, BSC | ETH, MATIC, AVAX, BNB |


Support for additional chains (Solana, XRPL) will be added in the future.

The service uses Ripple Custody's dry-run API to estimate fees. All chain-specific fee calculations are handled automatically.

## Bot user and automation

The Gas Station Service uses a dedicated **bot user** to sign and submit funding transactions automatically:

- **No manual approval required**: Once you configure the bot user with auto-approval policies, gas funding transactions are approved automatically without human intervention
- **Full audit trail**: All bot user actions are logged in the Ripple Custody intent system
- **Secure key storage**: The bot user's private key is stored in a secure vault (Kubernetes Secret or HashiCorp Vault)


If your organization adds additional approval requirements to the bot user's transactions, automatic sponsorship will be blocked. Funding transactions will require manual approval, defeating the purpose of the Gas Station.

## Low-balance alerts

Configure alert thresholds to receive notifications when sponsor account balances fall below specified levels.

### Alert configuration

When you configure a sponsor, you can set alert thresholds for each native token the sponsor holds:

| Field | Description |
|  --- | --- |
| **tickerId** | The UUID of the native token to monitor (e.g., ETH, MATIC, AVAX) |
| **amount** | The balance threshold—alerts trigger when the balance falls to or below this amount |


You can configure multiple alert thresholds per sponsor, one for each token type.

### How alerts work

The Gas Station Service checks the sponsor account balance after each funding transaction:

1. After successfully funding a sponsored account, the service retrieves the sponsor's current balance
2. For each configured alert threshold, it compares the current balance to the threshold amount
3. If the balance is at or below the threshold, the service emits an alert event


### Alert delivery

Alerts are delivered through your monitoring infrastructure:

- **Grafana integration**: All alerts are sent to Grafana as log events and metrics
- **Configure notifications**: Set up Grafana alerting rules to receive notifications via email, Slack, PagerDuty, or other channels
- **Monitor the metric**: `gas_station_sponsor_low_balance` indicates when a sponsor balance is below threshold


Configure Grafana alerts to notify your operations team before sponsor accounts run out of funds. This ensures uninterrupted sponsorship for your users.

## Fee estimation and safety margin

The service estimates transaction fees using the Ripple Custody dry-run API:

1. Retrieve the original transaction intent
2. Execute a dry-run to simulate the transaction
3. Apply a configurable safety margin (default: 10%)
4. Transfer the total amount to the sponsored account


The safety margin accounts for fee volatility between estimation and actual transaction broadcast.

## Retry and fault tolerance

The Gas Station Service implements a two-tier retry mechanism to handle transient failures:

### Tier 1: Immediate retries

For transient failures during event processing, the service performs immediate in-memory retries:

| Parameter | Value |
|  --- | --- |
| **Max attempts** | 3 retries per operation |
| **Backoff strategy** | Exponential [1s, 2s, 4s] |
| **Timeout** | 10 seconds per attempt |
| **Total time** | ~17 seconds worst case |


### Tier 2: Queue-based retries

When immediate retries are exhausted, jobs are persisted to a database queue for background processing:

| Parameter | Value |
|  --- | --- |
| **Retry interval** | Fixed 5 minutes between cycles |
| **Maximum age** | 24 hours from job creation |
| **Maximum retry count** | 20 attempts |


Jobs exceeding these limits are moved to a dead letter queue for manual investigation.

The two-tier retry mechanism ensures that temporary failures (network issues, API timeouts) don't cause permanent funding failures while preventing infinite retry loops.

## Performance

The Gas Station Service is designed to meet strict performance requirements:

| Metric | Target |
|  --- | --- |
| **End-to-end funding time** | < 2 minutes |
| **Polling interval** | 5 seconds (configurable) |
| **Happy path** | ~35 seconds (including blockchain confirmation) |
| **Worst case with retries** | ~72 seconds (well within SLA) |


### SLA breakdown

- Event polling interval: 5 seconds
- Dry-run API call: 1-3 seconds
- Funding transaction submission: 1-2 seconds
- Blockchain confirmation: varies by chain (EVM: 12-15s)


## Next steps

| Topic | Description |
|  --- | --- |
| [Gas Station reference](/products/custody/v1.34/deployment/reference/gas-station) | Configuration parameters and deployment options |
| [Configure bot users](/products/custody/v1.34/api/environment/user/bot-user) | Set up bot users for automated operations |
| [Configure gas sponsorship](/products/custody/v1.34/api/accounting/gas-station/configure-sponsorship) | Set up sponsor accounts and configure sponsorship rules |