# Broadcast Gasless Tx

Gasless swaps for non-custodial wallets — submit the signature for the `txHashToSign` returned by Execute Gasless.

## Overview

When [Execute Gasless](https://docs.aureahub.com/docs/swap-gasless.md) returns `requiresClientSigning: true`, Aurea has already submitted the permit if one was needed and prepared the swap as an unsigned EIP-1559 transaction from the user's wallet on Gnosis. Sign `txHashToSign` with the wallet key and send `{ preparedTxId, v, r, s }` here. The API rebuilds the prepared transaction, checks that the signature recovers to the wallet's address, and broadcasts it. The swap transaction is sent from the user's wallet, which pays its gas.

- The request carries no permit and no swap parameters — only the signature. `v` is the recovery parity, `0` or `1`.
- The API attaches the resulting `txHash` to the wallet's most recent `pending` swap record created within the last 10 minutes — normally the `transactionId` returned by Execute Gasless. Track the swap with [Get Tx Status](https://docs.aureahub.com/docs/tx-status.md).
- Only `txHash` and `status: "pending"` carry information in the response. `fromAmount`, `toAmount`, `gasUsed` and `gasPrice` are always `"0"`, `executionMethod` is `self-pay` and `routingMethod` is `direct`.
- The prepared transaction expires 5 minutes after Execute Gasless (`expiresAt`). Rate limit: 10 requests per 10 seconds.

> ⚠️ The prepared transaction is marked as used **before** the signature is checked. After a `422`, the same `preparedTxId` returns `409`.

## Endpoint

### `POST /v1/swap/broadcast-gasless`

Authentication: bearer token required.

Validates a client signature for a prepared gasless swap transaction and broadcasts it.

**Request body**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `preparedTxId` | string (uuid) | yes | `preparedTxId` from Execute Gasless. |
| `v` | integer | yes | Signature recovery parity: `0` or `1`. |
| `r` | string | yes | `0x` + 64 hex characters. |
| `s` | string | yes | `0x` + 64 hex characters. |

**Responses**

`200` OK

```json
{
  "txHash": "0x…",
  "status": "pending",
  "fromAmount": "0",
  "toAmount": "0",
  "gasUsed": "0",
  "gasPrice": "0",
  "executionMethod": "self-pay",
  "routingMethod": "direct"
}
```

`404` Not Found

```json
{
  "statusCode": 404,
  "error": "NotFoundError",
  "message": "Prepared transaction not found"
}
```

`422` Wrong Signer

```json
{
  "statusCode": 422,
  "error": "BlockchainError",
  "message": "Signature does not correspond to the expected wallet address",
  "code": "WRONG_SIGNER",
  "retryable": false,
  "details": { "code": "WRONG_SIGNER", "retryable": false }
}
```

## Errors

- `400` `Request validation failed` — the body does not match the schema.
- `404` `Prepared transaction not found` — unknown `preparedTxId`, or it belongs to another user.
- `409` `PREPARED_TX_ALREADY_USED` — already submitted.
- `410` `PREPARED_TX_EXPIRED` — more than 5 minutes after Execute Gasless.
- `422` `SIGNATURE_DECODE_FAILED` or `WRONG_SIGNER`.

## Implementation

```javascript
import { SigningKey } from 'ethers';

// result = response of POST /v1/swap/execute-gasless with requiresClientSigning: true
async function broadcastGasless(token, result, privateKey) {
  const sig = new SigningKey(privateKey).sign(result.txHashToSign);

  const res = await fetch('https://api.aureahub.com/v1/swap/broadcast-gasless', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${token}`
    },
    body: JSON.stringify({
      preparedTxId: result.preparedTxId,
      v: sig.yParity, // 0 or 1
      r: sig.r,
      s: sig.s
    })
  });

  const body = await res.json();
  if (!res.ok) throw new Error(`${res.status} ${body.code ?? ''}: ${body.message}`);

  // Track with the transactionId returned by execute-gasless
  return { transactionId: result.transactionId, txHash: body.txHash };
}
```

---

Web version: https://docs.aureahub.com/#swap-broadcast-gasless
