> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kipseli.capital/llms.txt
> Use this file to discover all available pages before exploring further.

# Request Swap Verification

> ABI-encodes `(tokenIn, tokenOut, timestamp, fee, originRate, userAddress)`,
Keccak256-hashes the payload, and signs it with secp256k1.
The recovery ID is adjusted from `[0,1]` to `[27,28]` per the Ethereum Yellow Paper.

The response contains ABI-encoded verification data `(fee, originRate, userAddress, signature)`
ready for on-chain submission.


Before executing a swap on-chain, call this endpoint to obtain `verificationData` and `timestamp`. Both values must be passed directly into the `swap()` function — if either is modified or expired, the transaction will revert.

Optionally, pass `amountIn` (and `minAmountOut`) to receive pre-built `calldata` ready for direct submission.

## Swap Execution Flow

### Step 1 — Call this endpoint

**Minimal (verification data only):**

```bash theme={null}
curl -X POST https://propamm.kipseli.win/v1/swap/sign \
  -H "Content-Type: application/json" \
  -d '{
    "tokenIn":     "0x4200000000000000000000000000000000000006",
    "tokenOut":    "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "fee":         "30",
    "userAddress": "0x1111111111111111111111111111111111111111"
  }'
```

**Response:**

```json theme={null}
{
  "verificationData": "0x...",
  "timestamp": 1741737600
}
```

**With calldata (pass `amountIn` and optionally `minAmountOut`):**

```bash theme={null}
curl -X POST https://propamm.kipseli.win/v1/swap/sign \
  -H "Content-Type: application/json" \
  -d '{
    "tokenIn":      "0x4200000000000000000000000000000000000006",
    "tokenOut":     "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "fee":          "30",
    "userAddress":  "0x1111111111111111111111111111111111111111",
    "amountIn":     "1000000000000000000",
    "minAmountOut": "3150000000"
  }'
```

**Response:**

```json theme={null}
{
  "verificationData": "0x...",
  "timestamp": 1741737600,
  "calldata": "0x..."
}
```

The `calldata` field is ABI-encoded for `swap(address,uint256,address,uint256,uint256,bytes)` and can be submitted directly to the router without further encoding.

### Step 2 — Approve the Router

```solidity theme={null}
IERC20(tokenIn).approve(
    0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99,
    amountIn
);
```

### Step 3 — Execute the swap on-chain

**Option A — build the call yourself:**

```solidity theme={null}
IPropAmm(0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99).swap(
    tokenIn,
    amountIn,
    tokenOut,
    minOutAmount,      // slippage protection — use quote() to calculate
    timestamp,         // from API response
    verificationData   // from API response
);
```

| Parameter          | Description                                                      |
| ------------------ | ---------------------------------------------------------------- |
| `tokenIn`          | Input token address                                              |
| `amountIn`         | Amount of input token (in token decimals)                        |
| `tokenOut`         | Output token address                                             |
| `minOutAmount`     | Minimum acceptable output — set this to protect against slippage |
| `timestamp`        | Returned by this API — pass through unchanged                    |
| `verificationData` | Returned by this API — pass through unchanged                    |

**Option B — use the `calldata` from the API (requires `amountIn` in Step 1):**

```solidity theme={null}
(bool success, ) = address(0x71C2Ed90CC288229Be59F26b8B3EEF3C07d7ab99).call(calldata);
require(success, "swap failed");
```

The `calldata` is already ABI-encoded for `swap(address,uint256,address,uint256,uint256,bytes)` — no further encoding needed.

***

## Fee Parameter

The `fee` field uses **0.1 bps resolution**:

| Value | Rate             |
| ----- | ---------------- |
| `1`   | 0.1 bps (0.001%) |
| `10`  | 1 bps (0.01%)    |
| `30`  | 3 bps (0.03%)    |
| `100` | 10 bps (0.10%)   |

The fee is deducted from the output amount (`amountOut`) and settled monthly in a mutually agreed currency.


## OpenAPI

````yaml post /v1/swap/sign
openapi: 3.0.3
info:
  title: Kipseli PropAMM
  version: 1.0.0
  description: |
    HTTP service that signs PropAMM quote payloads for EVM verification flows
    and serves a live on-chain orderbook for configured token pairs.
  license:
    name: MIT
servers:
  - url: https://propamm.kipseli.win
    description: Production
security: []
paths:
  /v1/swap/sign:
    post:
      summary: Sign a quote
      description: >
        ABI-encodes `(tokenIn, tokenOut, timestamp, fee, originRate,
        userAddress)`,

        Keccak256-hashes the payload, and signs it with secp256k1.

        The recovery ID is adjusted from `[0,1]` to `[27,28]` per the Ethereum
        Yellow Paper.


        The response contains ABI-encoded verification data `(fee, originRate,
        userAddress, signature)`

        ready for on-chain submission.
      operationId: signQuote
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SignQuoteRequest'
            examples:
              minimal:
                summary: Sign without calldata
                value:
                  tokenIn: '0x4200000000000000000000000000000000000006'
                  tokenOut: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
                  fee: '3000'
                  userAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
              with_calldata:
                summary: Sign and get swap calldata (amountIn provided)
                value:
                  tokenIn: '0x4200000000000000000000000000000000000006'
                  tokenOut: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
                  fee: '3000'
                  userAddress: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
                  amountIn: '1000000000000000000'
                  minAmountOut: '3150000000'
      responses:
        '200':
          description: Quote signed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignQuoteResponse'
              examples:
                without_calldata:
                  summary: Response without calldata
                  value:
                    verificationData: 0xabcdef...
                    timestamp: 1741737600
                with_calldata:
                  summary: Response with calldata (amountIn was provided)
                  value:
                    verificationData: 0xabcdef...
                    timestamp: 1741737600
                    calldata: 0x...
        '400':
          description: Bad request — invalid or unknown fields in JSON body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                invalid_json:
                  summary: Empty or malformed body
                  value:
                    error:
                      code: INVALID_JSON
                      message: request body is required
                      requestId: abc-123
                unsupported_field:
                  summary: Unknown field in body
                  value:
                    error:
                      code: UNSUPPORTED_FIELD
                      message: unknown field in request payload
                      requestId: abc-123
        '422':
          description: Unprocessable entity — validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                error:
                  code: VALIDATION_ERROR
                  message: 'tokenIn: invalid EVM address'
                  requestId: abc-123
        '500':
          description: Internal server error — signing or encoding failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                signing_failed:
                  summary: Signing failed
                  value:
                    error:
                      code: SIGNING_FAILED
                      message: failed to sign quote
                      requestId: abc-123
                encoding_failed:
                  summary: Encoding failed
                  value:
                    error:
                      code: ENCODING_FAILED
                      message: failed to encode verification data
                      requestId: abc-123
      security: []
components:
  schemas:
    SignQuoteRequest:
      type: object
      required:
        - tokenIn
        - tokenOut
        - fee
        - userAddress
      properties:
        tokenIn:
          type: string
          description: EVM hex address of the input token (checksummed or lowercase)
          example: '0x4200000000000000000000000000000000000006'
        tokenOut:
          type: string
          description: EVM hex address of the output token (checksummed or lowercase)
          example: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
        fee:
          type: string
          description: Fee tier as a decimal string in 0.1 bps resolution(e.g. "3000" = 3%)
          example: '3000'
        userAddress:
          type: string
          description: EVM hex address of the user submitting the swap
          example: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
        amountIn:
          type: string
          description: >
            Input token amount in wei as a decimal string. When provided, the
            response

            will include a `calldata` field with ABI-encoded calldata for the
            `swap` function.
          example: '1000000000000000000'
        minAmountOut:
          type: string
          description: |
            Minimum accepted output token amount in wei as a decimal string.
            Only used when `amountIn` is provided. Defaults to `0` if omitted.
          example: '3150000000'
      additionalProperties: false
    SignQuoteResponse:
      type: object
      properties:
        verificationData:
          type: string
          description: |
            ABI-encoded hex string (with `0x` prefix) containing
            `(fee, originRate, userAddress, signature)`. Pass this directly
            to the on-chain verification contract.
          example: 0xabcdef...
        timestamp:
          type: integer
          format: int64
          description: Unix timestamp (seconds) at which the signature was generated
          example: 1741737600
        calldata:
          type: string
          description: >
            ABI-encoded calldata (with `0x` prefix) for the
            `swap(address,uint256,address,uint256,uint256,bytes)`

            function. Only present when `amountIn` was provided in the request.

            The encoded arguments are `(tokenIn, amountIn, tokenOut,
            minAmountOut, quoteTimestamp, verificationData)`.
          example: 0x...
    ErrorResponse:
      type: object
      properties:
        error:
          $ref: '#/components/schemas/ErrorDetail'
    ErrorDetail:
      type: object
      properties:
        code:
          type: string
          description: Machine-readable error code
          enum:
            - INVALID_JSON
            - VALIDATION_ERROR
            - UNSUPPORTED_FIELD
            - SIGNING_FAILED
            - ENCODING_FAILED
            - INTERNAL_ERROR
          example: VALIDATION_ERROR
        message:
          type: string
          description: Human-readable error message
          example: 'tokenIn: invalid EVM address'
        requestId:
          type: string
          description: Request ID for correlation with server logs
          example: abc-123

````