# Paymaster SDK

Android library for interacting with the ethOS Paymaster system. Provides balance management, top-up flows (via Daimo), ERC-4337 gas estimation (via Pimlico), and token price lookups — all wrapped in a clean, synchronous Kotlin API designed for `Dispatchers.IO`.

#### Installation

**Step 1.** Add the JitPack repository to your project's `settings.gradle.kts` (inside the `dependencyResolutionManagement` block):

```
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
    }
}
```

> If your project uses a root `build.gradle.kts` with `allprojects { repositories { ... } }` instead, add the maven line there.

**Step 2.** Add the dependency to your app module's `build.gradle.kts`:

```
dependencies {
    implementation("com.github.EthereumPhone:PaymasterSDK:0.1.0")
}
```

#### Quick Start

```
// 1. Create the SDK instance
val paymasterSDK = PaymasterSDK(
    context = applicationContext,
    bundlerApiKey = "your-pimlico-api-key"
)

// 2. Initialize (connects to the on-device PaymasterProxy service)
withContext(Dispatchers.IO) {
    val available = paymasterSDK.initialize()

    if (available) {
        // 3. Read the cached balance
        val balance = paymasterSDK.getBalance()   // e.g. "12.50"

        // 4. Trigger a fresh balance sync from the backend
        paymasterSDK.queryBalanceUpdate()

        // 5. Listen for balance changes
        paymasterSDK.registerBalanceObserver { newBalance ->
            // update your UI
        }

        // 6. Initiate a top-up (returns a Daimo checkout URL)
        val topUp = paymasterSDK.initiateTopUp(
            userId = "0xYourWalletAddress",
            amount = "10"
        )
        topUp?.let {
            // open it.checkoutUrl in a browser / WebView
        }

        // 7. Estimate gas for a UserOperation
        val gasEstimation = paymasterSDK.estimateGas(userOp, chainId = 8453)

        // 8. Fetch token prices for sponsorship
        val prices = paymasterSDK.fetchSponsorshipPrices(
            listOf("0xTokenAddress1", "0xTokenAddress2")
        )
    }
}

// 9. Clean up when done (e.g. in onDestroy)
paymasterSDK.cleanup()
```

#### Permissions

The SDK declares the following permissions in its own manifest (merged automatically):

| Permission             | Purpose                                            |
| ---------------------- | -------------------------------------------------- |
| `INTERNET`             | Communicate with the Paymaster backend and Pimlico |
| `ACCESS_NETWORK_STATE` | Check network availability                         |

No runtime permissions are required — both are normal permissions granted at install time.

#### API

**PaymasterSDK**

**Constructor**

```
PaymasterSDK(
    context: Context,
    bundlerApiKey: String,
    baseUrl: String = "https://api.markushaas.com/"
)
```

| Parameter       | Description                                                  |
| --------------- | ------------------------------------------------------------ |
| `context`       | Application or Activity context                              |
| `bundlerApiKey` | Your Pimlico API key (used for gas estimation & bundler URL) |
| `baseUrl`       | *(Optional)* Paymaster backend base URL                      |

**Methods**

| Method                                                 | Return Type        | Description                                                                                                                                                                         |
| ------------------------------------------------------ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `initialize()`                                         | `Boolean`          | Connect to the on-device `PaymasterProxy` system service. Returns `true` if the service is available (ethOS device), `false` otherwise. **Must be called before any other method.** |
| `getBalance()`                                         | `String?`          | Returns the cached paymaster balance (e.g. `"12.50"`), or `null` if unavailable.                                                                                                    |
| `queryBalanceUpdate()`                                 | `Unit`             | Triggers an asynchronous balance refresh from the backend. Listen for the result with `registerBalanceObserver`.                                                                    |
| `registerBalanceObserver(callback: (String) -> Unit)`  | `Unit`             | Registers a callback that fires whenever the balance changes.                                                                                                                       |
| `initiateTopUp(userId: String, amount: String)`        | `TopUpResult?`     | Starts a top-up flow via Daimo. Returns a `TopUpResult` with a checkout URL, or `null` on failure.                                                                                  |
| `estimateGas(userOp: UserOperation, chainId: Int)`     | `GasEstimation`    | Estimates gas for an ERC-4337 `UserOperation` on the given chain using the Pimlico bundler. Falls back to safe defaults on failure.                                                 |
| `fetchSponsorshipPrices(tokenAddresses: List<String>)` | `List<TokenPrice>` | Fetches USD prices for the given token addresses. Returns an empty list on failure.                                                                                                 |
| `getBundlerUrl(chainId: Int)`                          | `String`           | Returns the Pimlico bundler RPC URL for the given chain ID.                                                                                                                         |
| `cleanup()`                                            | `Unit`             | Releases all internal resources. Call in `onDestroy()` or when the SDK is no longer needed.                                                                                         |

**Constants**

| Constant                       | Value                                          | Description                                          |
| ------------------------------ | ---------------------------------------------- | ---------------------------------------------------- |
| `PaymasterSDK.ERROR`           | `"error"`                                      | Sentinel value indicating an error response          |
| `PaymasterSDK.UNAVAILABLE`     | `"unavailable"`                                | Sentinel value indicating the service is unavailable |
| `PaymasterSDK.ENTRY_POINT_V06` | `"0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"` | ERC-4337 EntryPoint v0.6 contract address            |

**Data Classes**

**`PaymasterSDK.TopUpResult`**

Returned by `initiateTopUp()`.

| Property         | Type     | Description                                  |
| ---------------- | -------- | -------------------------------------------- |
| `daimoPaymentId` | `String` | Unique Daimo payment identifier              |
| `checkoutUrl`    | `String` | URL to open for the user to complete payment |

**`PaymasterSDK.UserOperation`**

Input for `estimateGas()`. Represents an ERC-4337 UserOperation (v0.6).

| Property               | Type         | Description                          |
| ---------------------- | ------------ | ------------------------------------ |
| `sender`               | `String`     | Smart account address                |
| `nonce`                | `BigInteger` | Account nonce                        |
| `initCode`             | `String`     | Init code (empty string if deployed) |
| `callData`             | `String`     | Encoded call data                    |
| `callGasLimit`         | `BigInteger` | Gas limit for the main execution     |
| `verificationGasLimit` | `BigInteger` | Gas limit for verification           |
| `preVerificationGas`   | `BigInteger` | Pre-verification gas                 |
| `maxFeePerGas`         | `BigInteger` | Maximum fee per gas                  |
| `maxPriorityFeePerGas` | `BigInteger` | Maximum priority fee per gas         |
| `paymasterAndData`     | `String`     | Paymaster address + data             |
| `signature`            | `String`     | Signature bytes                      |

**`PaymasterSDK.GasEstimation`**

Returned by `estimateGas()`.

| Property               | Type         | Description                      |
| ---------------------- | ------------ | -------------------------------- |
| `preVerificationGas`   | `BigInteger` | Estimated pre-verification gas   |
| `verificationGasLimit` | `BigInteger` | Estimated verification gas limit |
| `callGasLimit`         | `BigInteger` | Estimated call gas limit         |

**`PaymasterSDK.TokenPrice`**

Returned by `fetchSponsorshipPrices()`.

| Property   | Type      | Description                  |
| ---------- | --------- | ---------------------------- |
| `address`  | `String`  | Token contract address       |
| `symbol`   | `String?` | Token symbol (e.g. `"USDC"`) |
| `priceUsd` | `Double?` | Current price in USD         |

**Error Handling**

The SDK does **not** throw custom exceptions. Instead it uses safe return values:

| Scenario                                 | Behavior                                                                                                                       |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| Service not available (non-ethOS device) | `initialize()` returns `false`                                                                                                 |
| Balance unavailable                      | `getBalance()` returns `null`                                                                                                  |
| Top-up request fails                     | `initiateTopUp()` returns `null`                                                                                               |
| Gas estimation fails                     | `estimateGas()` returns safe defaults (`preVerificationGas = 70000`, `verificationGasLimit = 400000`, `callGasLimit = 200000`) |
| Price fetch fails                        | `fetchSponsorshipPrices()` returns an empty list                                                                               |

> **Threading:** All public methods are synchronous and perform I/O. Call them from a background thread or wrap in `withContext(Dispatchers.IO)`.

#### Requirements

* Android API 33+ (minSdk 33)
* ethOS device (for balance & top-up features via `PaymasterProxy` system service)
* Pimlico API key (for gas estimation)

#### GitHub Repo

{% embed url="<https://github.com/EthereumPhone/PaymasterSDK>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.freedomfactory.io/sdks/paymaster-sdk.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
