# How it works

Every product in this API - staking, unstaking, stock trades and bridging -
runs through the same pipeline. Your backend asks Restake to **build** a
transaction, your user's wallet **checks and signs** it, and Restake
**executes** it on-chain. Restake never holds a user's private key, and your
users never need native gas tokens.

## The big picture

<Mermaid
  chart={`
%%{init: {"flowchart": {"wrappingWidth": 360}}}%%
flowchart TB
  BE["<b>Partner backend</b><br/>your server, client credentials"]
  BUILD["<b>1 · Build</b> - Restake API<br/>reads prices, routes, balances<br/>returns userOpHash + intentId"]
  DATA[("Market data<br/>Ondo · 1inch · vaults")]
  INTENT[("Intent store<br/>single-use, short-lived")]
  W["<b>2 · Verify and sign</b> - user wallet<br/>userOpHash + EIP-7702 authorization"]
  V["Batch Verifier<br/>eth_call on your RPC"]
  SUBMIT["<b>3 · Submit</b> - Restake API<br/>pairs the signatures with the stored batch"]
  BUNDLER["<b>4 · Execute</b> - bundler + paymaster<br/>gas sponsored"]
  ACC["User's address - EIP-7702 smart account<br/>executeBatch: all calls or none"]
  VAULT["ERC-4626 vaults<br/>Morpho · Fluid · …"]
  AAVE["Aave v3<br/>pools"]
  SWAP["1inch router<br/>Ondo stocks"]
  BRIDGE["Across<br/>bridge"]
  NOTIFY["<b>5 · Notify</b> - callbacks and stream<br/>back to your backend"]

  BE -- "build request" --> BUILD
  DATA -.-> BUILD
  BUILD -.-> INTENT
  BUILD -- "batch to sign" --> W
  W <-. "optional check" .-> V
  W -- "signatures, via your backend" --> SUBMIT
  INTENT -.-> SUBMIT
  SUBMIT -- "signed user operation" --> BUNDLER
  BUNDLER --> ACC
  ACC --> VAULT & AAVE & SWAP & BRIDGE
  VAULT & AAVE & SWAP & BRIDGE -.-> NOTIFY
`}
/>

| Party | Role |
| --- | --- |
| **Partner backend** | Authenticates with client credentials, owns its users, asks for transactions and submits signatures. The only party that talks to the Restake API. |
| **User wallet** | Holds the user's key. Signs two things per transaction: the user operation hash and the EIP-7702 authorization. |
| **Batch Verifier** | An on-chain, read-only contract you call on your own node to check a batch against what the user actually asked for, before they sign. See [Batch Verifier](/batch-verifier). |
| **Restake API** | Reads market data, builds the batch, keeps the unsigned operation server-side under an `intentId`, and submits it once it is signed. |
| **Bundler and paymaster** | Carry the signed operation on-chain and pay its gas. The gas is recovered inside the batch through the platform fee, so the user needs no ETH or BNB. |
| **User's smart account** | The user's own address, upgraded with EIP-7702 to a pinned smart-account implementation. It executes every call in the batch atomically. |
| **Protocols** | Where the money actually goes: ERC-4626 vaults, Aave pools, the 1inch router for Ondo stock tokens, and Across for bridging. |

## Step by step

<Mermaid
  chart={`
%%{init: {"sequence": {"messageFontSize": 16, "actorFontSize": 16, "noteFontSize": 15, "actorMargin": 40, "boxMargin": 12, "noteMargin": 12, "messageMargin": 44, "width": 150, "wrap": true}}}%%
sequenceDiagram
  autonumber
  participant BE as Partner backend
  participant W as User wallet
  participant V as Batch Verifier
  participant API as Restake API
  participant CH as Blockchain

  BE->>API: Build request<br/>POST …/construct/…/batch
  Note over API: Reads prices, routes,<br/>balances, allowances.<br/>Stores the batch<br/>under intentId.
  API-->>BE: userOpHash, authorization,<br/>calls, intentId
  BE->>W: Confirm amount and asset
  opt Recommended
    W->>V: eth_call verify(...)
    V-->>W: verifiedHash + deadline
  end
  Note over W: Signs userOpHash<br/>+ 7702 authorization
  W-->>BE: Signatures
  BE->>API: Submit<br/>POST …/batch/send
  API->>CH: Signed user operation
  API-->>BE: userOpHash
  Note over CH: executeBatch:<br/>all calls or none
  API-->>BE: Callback / stream event
`}
/>

1. **Build.** Your backend calls the construct endpoint for the action - stake,
   unstake, buy, sell or bridge - on behalf of one of your users. Restake reads
   the live state it needs (prices, the swap route, the wallet's balance and
   allowances) and assembles an EIP-7702 batch. The unsigned operation stays on
   the Restake side under an `intentId`; you receive the hash to sign and the
   list of calls so you can show and verify them.
2. **Verify.** Before the user signs, your wallet can pass the batch and the
   intent your UI showed to the [Batch Verifier](/batch-verifier) with a free
   `eth_call`. It rejects anything that does more than the user asked for - an
   unknown contract, a different receiver, an unlimited approval, a fee above
   your limit.
3. **Sign.** The user's wallet signs the operation hash and the EIP-7702
   authorization. Nothing else is signed and no key leaves the wallet. See
   [Signing with Privy](/privy) or [Signing with Wallet Core](/wallet-core).
4. **Submit.** Your backend returns the two signatures with the `intentId`.
   Restake pairs them with the stored operation and sends it to the network.
   An intent is single-use and expires within minutes, so a signature cannot be
   replayed later or against a different amount, chain or target.
5. **Execute.** On-chain, the user's account runs the whole batch in one
   transaction. If any call fails - a swap returns less than the minimum, the
   deadline has passed - everything reverts: no approval, no transfer, no fee.
6. **Notify.** Confirmations and the resulting positions reach you through
   [callbacks](/callbacks) and the [stream](/stream), and are readable at any
   time from the [portfolio API](/portfolio).

## What a batch looks like

Every batch follows the same shape. Only the main call changes from one product
to another:

```
[0] DeadlineGuard.requireBefore(deadline)   batch expires within minutes
[1] token.approve(spender, amount)          exact amount, never unlimited
[2] main call                               the product action
[3] token.approve(spender, 0)               revoke, when an allowance would remain
[4] USDC.transfer(feeRecipient, fee)        platform fee, always last
```

Calls that are not needed are left out - a stock trade with enough existing
allowance has no approve, a stake with no fee has no transfer. See
[Security overview](/security) for each protection in detail.

### Examples

<Mermaid
  chart={`
flowchart TB
  subgraph BUY["Buy a stock"]
    direction LR
    B1["approve USDC<br/>exact amount"] --> B2["1inch swap<br/>USDC → stock token<br/>min. return from quote"] --> B3["fee<br/>in USDC"]
  end
  subgraph SELL["Sell a stock"]
    direction LR
    S1["approve stock token<br/>exact amount"] --> S2["1inch swap<br/>stock token → USDC<br/>min. return from quote"] --> S3["fee<br/>from the proceeds"]
  end
  subgraph STAKE["Stake"]
    direction LR
    K1["approve USDC<br/>exact amount"] --> K2["ERC-4626 deposit<br/>or Aave supply"] --> K3["fee"]
  end
  subgraph UNSTAKE["Unstake"]
    direction LR
    U1["ERC-4626 redeem<br/>or Aave withdraw"] --> U2["revoke allowance<br/>approve 0"] --> U3["fee"]
  end
  BUY ~~~ SELL ~~~ STAKE ~~~ UNSTAKE
`}
/>

| Action | Product | Main call | What the user ends up with |
| --- | --- | --- | --- |
| **Buy** | [Stocks](/stocks) | 1inch swap from a USD stablecoin to an Ondo tokenized stock | The stock token in their own wallet |
| **Sell** | [Stocks](/stocks) | 1inch swap from the stock token back to the stablecoin | Stablecoin, with the fee taken from the proceeds in the same batch |
| **Stake** | [Staking](/staking) | `deposit` on an ERC-4626 vault (Morpho, Fluid, …) or `supply` on an Aave v3 pool | Vault shares or aTokens, earning the pool's yield |
| **Unstake** | [Staking](/staking) | `redeem` / `withdraw` on the vault, or `withdraw` on Aave | The base token back, and no standing approval to the pool |
| **Bridge** | [Bridge](/bridge) | Across `deposit` on the source chain | USDC on the destination chain, or a refund if it is not filled in time |

**Stocks.** Prices, charts and the catalogue come from Ondo, the issuer of the
tokenized shares. The trade itself is filled on-chain through a 1inch route at
the price in your quote, with a minimum return built into the batch; stock
tokens follow the US market calendar - see
[Market hours](/stocks#market-hours-are-the-thing-to-design-around).

**Staking pools.** Each pool is a yield-bearing vault - a standard ERC-4626
vault such as Morpho or Fluid, or an Aave v3 market. Staking deposits the base
token and the user receives shares in their own wallet; unstaking redeems those
shares and revokes the allowance the deposit needed.

## What this means for you

- **Non-custodial.** Funds move only from and to the user's own address, and
  only after the user signs. Restake cannot move them on its own.
- **One integration for every product.** Build, sign, submit is the same three
  calls for stocks, staking and bridging; only the construct endpoint differs.
- **No gas tokens.** Gas is sponsored and recovered from the platform fee
  inside the same atomic batch.
- **Verifiable.** Every call is visible in the build response, and the
  [Batch Verifier](/batch-verifier) lets you check it on your own node instead
  of trusting the API.
- **All or nothing.** A batch that would leave the user worse off than quoted
  reverts as a whole, including the fee.
