npm package: @seer-pm/api-gateway
Description: Shared types and helpers for the Seer API gateway (AA signing context, supported chains).
Latest version: 0.1.0

# @seer-pm/api-gateway

Shared **TypeScript** types and small helpers used by the Seer API gateway and clients:

- `SigningContext` and `parseSigningContext` for ERC-4337 / Safe signing metadata
- `ENTRY_POINT_*` / `SAFE_ACCOUNT_VERSION` constants
- `SUPPORTED_CHAINS`, `getChainById`, `getSigningContext`
- `gatewayRequest` — **`gatewayRequest(baseUrl)`** returns a fluent client (`.split()`, `.merge()`, `.quote()`, `.relay()`, …); use **`.request({ path, method, body })`** for ad-hoc paths. `fetch` + JSON + optional `relayHint`.
- `signUserOperation` — Safe account + `signUserOperation` (permissionless)

Peer dependencies: **viem** `^2`, **permissionless** `^0.3`.

## Install

```bash
npm install @seer-pm/api-gateway viem permissionless
```

```bash
yarn add @seer-pm/api-gateway viem permissionless
```

## Usage

### `gatewayRequest(baseUrl)`

Call `gatewayRequest` with your API base URL (no trailing slash required). It returns a client with typed helpers for each route. Non-OK HTTP status codes throw; responses that include `userOperation` must also include a valid `signingContext` or the client throws.

```ts
import { gatewayRequest } from "@seer-pm/api-gateway";

const api = gatewayRequest("https://your-gateway.example.com/api");

// Convenience methods (paths match the Netlify/API handler)
const health = await api.health();

const split = await api.split(chainId, marketAddress, {
  owner: "0x…",
  amount: "1000000000000000000",
  useMainCollateral: true
});

// When the gateway returns a UserOperation to sign, `relayHint` is set:
const hint = split.relayHint;
if (hint) {
  const { intentId, userOperation, signingContext } = hint;
  // … sign with signUserOperation, then submit:
  await api.relay(chainId, {
    intentId,
    userOperation: { /* …signed op with `signature` field set… */ }
  });
}

// Ad-hoc path when you already have path/method/body:
await api.request({
  path: `/markets/${chainId}/${marketAddress}/merge`,
  method: "POST",
  body: { /* … */ }
});
```

Other methods include `merge`, `redeem`, `quote`, `executeTrade`, `createMarket`, `predictWallet`, and `userOperationReceipt`.

### `signUserOperation`

After a POST that returns `userOperation` + `signingContext`, use `signUserOperation` with a viem `walletClient`, the Safe owners (EOA account(s) or EIP-1193 provider(s), depending on your setup), and the same `chainId` as the request. The helper builds the Safe smart account from `signingContext` and returns the ERC-4337 signature.

```ts
import type { UserOperation } from "viem/account-abstraction";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { gnosis } from "viem/chains";
import { gatewayRequest, signUserOperation } from "@seer-pm/api-gateway";

const account = privateKeyToAccount(process.env.OWNER_PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
  account,
  chain: gnosis,
  transport: http()
});

const build = await gatewayRequest(API_BASE_URL).split(CHAIN_ID, MARKET_ADDRESS, {
  owner: account.address,
  amount: "10000000",
  useMainCollateral: true
});

if (!build.relayHint) {
  throw new Error("Expected relayHint from gateway");
}

const { intentId, userOperation, signingContext } = build.relayHint;

const { signature, userOperation: signedOp } = await signUserOperation({
  walletClient,
  signingContext,
  userOperation: {
    ...(userOperation as Record<string, unknown>),
    signature: "0x"
  } as unknown as UserOperation,
  chainId: CHAIN_ID,
  owners: [account],
  saltNonce: 0n // optional; must match the salt your Safe uses if non-default
});

await gatewayRequest(API_BASE_URL).relay(CHAIN_ID, {
  intentId,
  userOperation: {
    ...signedOp,
    signature
  }
});
```

In browser apps with wagmi, `owners` is often `[eip1193Provider]` and you pass the wallet client from `getWalletClient`. Align `chainId` with `signingContext.chainId` and the chain the user selected.

## Publishing (maintainers)

From the repo root after `yarn install` (which builds `dist/` via `postinstall`):

```bash
cd packages/api-gateway
npm version patch   # or minor / major
npm publish --access public
```

Ensure the `@seer` scope exists on npm and you are logged in (`npm login`).