# 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>" %}
