# Acknowledgements (https://docs.helico.site/docs/acknowledgements)

What Helico is built with.

* [Uniswap v4](https://uniswap.org): the positions, the swap, the Universal Router and the
  Position Manager.
* [Chainlink CRE](https://docs.chain.link/cre): the confidential workflow and the forwarder.
* [Arbitrum One](https://arbitrum.io) and [Ethereum](https://ethereum.org).
* [OpenZeppelin](https://www.openzeppelin.com) and [Foundry](https://getfoundry.sh) for the
  contract; [Astro](https://astro.build), [Go](https://go.dev), [Bun](https://bun.sh) and
  Turborepo for the rest.

These docs are [Fumadocs](https://fumadocs.dev) on Next.js, starting from the
[tailwind-variants-docs](https://github.com/heroui-inc/tailwind-variants-docs) template by
HeroUI, MIT. The content, the branding and the deployment are Helico's.

Helico is a submission to [ETHOnline 2026](https://ethglobal.com/events/ethonline2026).

# Backend API (https://docs.helico.site/docs/backend-api)

The blog's API in Go. One SQLite file, posts served as JSON with the HTML rendered.

[`apps/be`](https://github.com/0xHelico/helico/tree/main/apps/be) serves the posts the landing's blog shows. Markdown files
in `content/` stay the source of truth and are seeded into one SQLite file.

```bash
cd apps/be
BE_ADMIN_TOKEN=change-me go run ./cmd/be     # :8787
go vet ./... && gofmt -l . && go test -race ./...
```

| Variable             | Default                                       |
| -------------------- | --------------------------------------------- |
| `BE_ADDR`            | `:8787`                                       |
| `BE_DB_PATH`         | `data/helico.db`                              |
| `BE_ADMIN_TOKEN`     | empty; writes refused with `503`              |
| `BE_CORS_ORIGINS`    | `http://localhost:4321,http://localhost:4322` |
| `BE_CONTENT_DIR`     | `content`                                     |
| `BE_REQUEST_TIMEOUT` | `10s`                                         |

| Route                             | Auth   | Answer                                                        |
| --------------------------------- | ------ | ------------------------------------------------------------- |
| `GET /healthz`                    |        | ok                                                            |
| `GET /api/posts?limit=20&cursor=` |        | items and a keyset cursor, newest first, `ETag`               |
| `GET /api/posts/slug`             |        | the post with `html` and `markdown`; `304` on `If-None-Match` |
| `PUT /api/posts/slug`             | bearer | create `201` or replace `200`                                 |
| `DELETE /api/posts/slug`          | bearer | `204`                                                         |

Errors are `application/problem+json`; JSON over 1 KiB is gzipped; reads carry
`Cache-Control: public, max-age=60, stale-while-revalidate=300`.

# For builders (https://docs.helico.site/docs/builders)

The repository, how to run the whole flow on a fork, and where each piece lives.

Everything is in [one repository](https://github.com/0xHelico/helico): the contract, the two packages, the runnable CRE
project, the landing, the blog API, the plans written before the code, and the log of AI
assistance.

| Directory                   | What                                                          |
| --------------------------- | ------------------------------------------------------------- |
| `contracts/`                | `HelicoVault` and its tests, Foundry                          |
| `packages/plugins/uniswap/` | Uniswap v4 on chain, `@helico/plugin-uniswap`                 |
| `packages/plugins/cre/`     | the Chainlink CRE confidential workflow, `@helico/plugin-cre` |
| `apps/cre/`                 | what the CRE CLI compiles and simulates, and `rehearse.sh`    |
| `apps/landing/`             | helico.site, Astro                                            |
| `apps/be/`                  | the blog API, Go and SQLite                                   |
| `docs/plans/`               | implementation plans, written before the code                 |

## Run the whole flow
You need `bun`, Foundry (`anvil`, `cast`, `forge`), the `cre` CLI, and `jq`.

```bash
git clone https://github.com/0xHelico/helico && cd helico
bun install
cp apps/cre/.env.example apps/cre/.env
cd apps/cre && ./rehearse.sh
```

About two minutes. It forks Arbitrum One, deploys the vault onto the fork, mints a position
that has drifted below the market, commits a mandate, and runs the workflow twice. The first
run re-centres the position and reads it back; the second holds on the cooldown.

> **warn:** That proves the delivery path and the vault's execution. It does not prove authorisation by a
decentralised oracle network: the simulator is not a TEE, and the mock forwarder verifies no
signatures. Only the position moving counts as evidence; a transaction hash on this path does
not, because the forwarder swallows a revert and still reports success.

## The tests
```bash
cd contracts && ARBITRUM_RPC_URL=https://arb1.arbitrum.io/rpc forge test   # 100, 11 on the fork
bun run --filter @helico/plugin-cre test                                     # 116
bun run --filter @helico/plugin-uniswap test                                 # 52
```

Counts as of 2026-09-06; the commands print the current ones. CI leaves the RPC unset, so the
fork suite reports `SKIP` there rather than a green tick for tests that did not run.

## Read next
[Contracts](https://docs.helico.site/docs/contracts), [Chainlink CRE](https://docs.helico.site/docs/chainlink-cre),
[Uniswap plugin](https://docs.helico.site/docs/uniswap-plugin), [Backend API](https://docs.helico.site/docs/backend-api),
[Evidence](https://docs.helico.site/docs/evidence).

# Chainlink CRE (https://docs.helico.site/docs/chainlink-cre)

The confidential workflow that makes the only decision the product has.

The decision runs inside a Chainlink CRE enclave, registered with `cre.handlerInTee`. The logic
is a package, [`@helico/plugin-cre`](https://github.com/0xHelico/helico/tree/main/packages/plugins/cre), so 116 unit tests
cover it without the CLI; [`apps/cre`](https://github.com/0xHelico/helico/tree/main/apps/cre) is what the CLI compiles.

## Every run
1. `getSecrets` releases six of the seven mandate fields from the Vault DON into the enclave;
   the enclave recomputes `keccak256(abi.encode(Mandate))` and stops if it differs from the
   configured hash.
2. Two `eth_call` batches from inside the enclave: the account from the vault, the pool's
   price, fee and liquidity from `StateView`, the position from the `PositionManager`.
3. Decide: hold on expiry, cooldown, or in range; otherwise a range of exactly
   `rangeWidthTicks` centred on the tick, only if a mirror of the vault's `_checkRange` accepts
   it.
4. Size: what the burn returns, the swap that funds the other side, bounded inside the new
   range, and the liquidity that funds. Below `minRetainedBps` is a hold.
5. Cross out with the verdict only. `delivery: 'forwarder'` writes
   `abi.encode(bool act, bytes32 mandateHash, RecenterParams p)` to the vault's `onReport`;
   `delivery: 'signature'` signs an EIP-712 authorisation with a key that never leaves.

The binary is public. What stays inside is the data, the RPC traffic, and the intermediate
values. The mandate hash proves consistency, not secrecy.

## Config
`schedule`, `rpcUrl`, `delivery`, `vault`, `positionManager`, `stateView`, `owner`, `poolId`,
`mandateHash`, `gasLimit`, `slippageBps`, `maxPoolFeePips`, `deadlineSeconds`; for
`signature` also `chainId`; for `forwarder` also `chainSelectorName`
(`ethereum-mainnet-arbitrum-1`). `secrets.yaml` maps the six mandate fields, and in signature
mode `AGENT_KEY`, to env vars.

## On Arbitrum One
|                                                                             |                                                                                                                                            |
| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `KeystoneForwarder`, production                                             | `0xF8344CFd5c43616a4366C34E3EEE75af79a74482`                                                                                               |
| `MockKeystoneForwarder`, what `simulate --broadcast` uses; verifies nothing | `0xd770499057619c9a76205fd4168161cf94abc532`                                                                                               |
| v4 `PoolManager` / `StateView` / `PositionManager`                          | `0x360E68faCcca8cA495c1B759Fd9EEe466db9FB32` / `0x76Fd297e2D437cd7f76d50F01AfE6160f86e9990` / `0xd88F38F930b7952f2DB2432Cb002E7abbF3dD869` |
| Demo pool, ETH/ARB 0.05%                                                    | `0xb37da7d5beb04539b6c497a15794748fc0ce1da7afc61133e3253eff76229ae5`                                                                       |

## What the simulation proves
> **warn:** In the simulator the enclave is the simulator and the forwarder is the mock. A run proves the
delivery path and the vault's execution, not DON authorisation. Chainlink's qualification text
accepts a CRE CLI simulation as evidence; a live deployment additionally needs the Confidential
Workflows beta.

> **error:** `KeystoneForwarder` calls the receiver inside a `try`. A reverting `onReport` still leaves a
transaction with `status 1`. `rehearse.sh` reads `positionOf` before and after and only counts
a position that changed. That is how [#78](https://github.com/0xHelico/helico/issues/78) was found.

## Where to look
|                                    |                                                                                                                                                         |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `handlerInTee` registration        | [`index.ts#L268-L276`](https://github.com/0xHelico/helico/blob/049f7d848d680a17cca5f4c1ba664ebffd7ea69d/packages/plugins/cre/src/index.ts#L268-L276)    |
| the confidential handler           | [`index.ts#L173-L234`](https://github.com/0xHelico/helico/blob/049f7d848d680a17cca5f4c1ba664ebffd7ea69d/packages/plugins/cre/src/index.ts#L173-L234)    |
| the decision                       | [`index.ts#L111-L170`](https://github.com/0xHelico/helico/blob/049f7d848d680a17cca5f4c1ba664ebffd7ea69d/packages/plugins/cre/src/index.ts#L111-L170)    |
| reads from inside the enclave      | [`chain.ts#L20-L44`](https://github.com/0xHelico/helico/blob/049f7d848d680a17cca5f4c1ba664ebffd7ea69d/packages/plugins/cre/src/chain.ts#L20-L44)        |
| the verdict delivered to the vault | [`index.ts#L244-L265`](https://github.com/0xHelico/helico/blob/049f7d848d680a17cca5f4c1ba664ebffd7ea69d/packages/plugins/cre/src/index.ts#L244-L265)    |
| the vault receiving it             | [`HelicoVault.sol#L469-L482`](https://github.com/0xHelico/helico/blob/049f7d848d680a17cca5f4c1ba664ebffd7ea69d/contracts/src/HelicoVault.sol#L469-L482) |

Check it: `bun run --filter @helico/plugin-cre typecheck` and `... test`.

# Contracts (https://docs.helico.site/docs/contracts)

HelicoVault in one page. What it checks, its three doors, and its known limits.

`HelicoVault` enforces a user's committed mandate on an agent that re-centres their Uniswap v4
position. The user keeps the position NFT and approves the vault to act on it. The vault holds
nothing across a transaction, and asserts at the end of every re-centre that it kept none of
what passed through.

## What a rogue agent can do
Re-range a position **whose owner committed a mandate**, into a band of the committed width,
containing the current price, closer to it than before, no more often than the cooldown allows,
before the mandate expires. The new NFT and every token go to the owner; those are the only
destinations the contract writes. No path pays an agent.

## The checks
| Check                                                               | Rejection                                                  |
| ------------------------------------------------------------------- | ---------------------------------------------------------- |
| owner committed a mandate and still owns the position               | `MandateInactive`, `NotPositionOwner`                      |
| position is in the committed pool                                   | `PoolNotPermitted`                                         |
| ticks ordered and aligned to spacing                                | `TicksNotOrdered`, `TicksNotSpaced`                        |
| range exactly `rangeWidthTicks` wide                                | `RangeWidthMismatch`                                       |
| range contains the current tick                                     | `RangeOffMarket`                                           |
| closer by at least `minImprovementBps`                              | `NotEnoughImprovement`                                     |
| cooldown elapsed                                                    | `CooldownNotElapsed`                                       |
| liquidity within `maxLiquidity`                                     | `LiquidityTooLarge`                                        |
| delivered liquidity at least `minRetainedBps` of what was withdrawn | `LiquidityNotRetained`                                     |
| not expired, not revoked                                            | `MandateExpired`, `MandateInactive`                        |
| caller holds `AGENT_ROLE`, or one signed for it                     | `AccessControlUnauthorizedAccount`, `SignerLacksAgentRole` |

Afterwards: the position asked for is the one that exists, `PositionNotDelivered`,
`RangeNotDelivered`. The range rules are one function,
[`_checkRange`](https://github.com/0xHelico/helico/blob/049f7d848d680a17cca5f4c1ba664ebffd7ea69d/contracts/src/HelicoVault.sol#L827-L851).

## Three doors
| Door                    | Caller                            | Authority                                                                             |
| ----------------------- | --------------------------------- | ------------------------------------------------------------------------------------- |
| `recenter`              | an `AGENT_ROLE` holder            | the role and the mandate                                                              |
| `recenterWithSignature` | anyone, relaying                  | an EIP-712 signature by an `AGENT_ROLE` holder, single use, bound to the mandate hash |
| `onReport`              | the Chainlink `KeystoneForwarder` | `msg.sender == forwarder`; the DON's signatures were verified by the forwarder        |

The door decides who may propose, never what they may propose.

## How a re-centre runs
`recenter` takes numbers, not calldata. Inside its own `unlock` callback it burns the old
position, swaps the excess side through the position's own pool with a price limit at the edge
of the committed range, then mints the new range to the owner. The tick is re-read after the
swap, `amountIn` is capped at what the burn returned, and the mint's maxima are what the vault
holds. Re-centring changes the token id, so accounts are keyed by owner; one address, one
position at a time; `setMandate` on a second position reverts with `MandateAlreadyActive`.

## Roles and upgrades
`AGENT_ROLE` proposes, `GUARDIAN_ROLE` pauses actions but not exits, `UPGRADER_ROLE`
schedules upgrades. Upgrades wait two days, commit the implementation's `codehash`, and expire
seven days after becoming ready. `revoke` is never gated.

## Known limits
* The agent picks the withdrawal's slippage bounds; a dishonest one can pick weak ones.
* `DEFAULT_ADMIN_ROLE` can grant itself `AGENT_ROLE` in one transaction; hold it in a multisig.
* `maxLiquidity` caps the whole position.
* Stray native sent to the vault is stuck, by design.
* The mocks do not model the price curve; swap claims are asserted on a fork or not at all.

## Run
```bash
cd contracts
forge install --no-git --shallow foundry-rs/forge-std@v1.16.2 \
  OpenZeppelin/openzeppelin-contracts@v5.7.0 OpenZeppelin/openzeppelin-contracts-upgradeable@v5.7.0
forge build && forge test
ARBITRUM_RPC_URL=https://arb1.arbitrum.io/rpc forge test
```

CI also runs `scripts/check-no-payable.py` (`multicall` stays non-payable) and
`scripts/check-storage-layout.py` (the upgradeable layout stays at 9 slots). The full
reasoning is in [`contracts/README.md`](https://github.com/0xHelico/helico/blob/main/contracts/README.md).

# Contributing (https://docs.helico.site/docs/contributing)

The rules the repositories follow, and why two of them matter most.

The full guide is [`CONTRIBUTING.md`](https://github.com/0xHelico/helico/blob/main/CONTRIBUTING.md).

## Rules with a penalty behind them
1. **Commit small and often.** Judges read the history. Never squash it.
2. **Write the plan before the code**, in `docs/plans/`, with how it will be verified.
3. **Never claim an integration that is not proven to work.** If it is untested, say so.
4. **Log AI usage** in `AI-USAGE.md`, prompts included.

## Conventions
English everywhere; Conventional Commits; issue, then a `type/short-topic` branch, then a
pull request that the reviewer merges with a merge commit; every partner integration is a
package under `packages/plugins/`; nothing that would help a competitor goes in the public
repository.

## These docs
[`0xHelico/docs`](https://github.com/0xHelico/docs). Pages are MDX under `content/docs`;
`pnpm dev` runs it, and CI runs `pnpm lint`, `pnpm build` and `pnpm lint:links`.

# Evidence (https://docs.helico.site/docs/evidence)

What has run, with the numbers, and what each number does and does not show.

## The rehearsal, 2026-09-06
On a fork of Arbitrum One, against the real ETH/ARB 0.05% pool, through the CRE CLI with
`--broadcast` and the mock forwarder:

|                    |                                                                         |
| ------------------ | ----------------------------------------------------------------------- |
| Position before    | token 202707, `[93270, 93470)`, entirely below tick 94473               |
| Verdict            | `RECENTER 94370..94570`                                                 |
| Position after     | a new token, `[94370, 94570)`, containing the price                     |
| Liquidity retained | 88545095207060353974 of 93889598979339206088, &#x2A;*94.3%**, floor 50% |
| Second run         | `HOLD (cooldown)`                                                       |

Recipe and raw numbers:
[the forwarder-delivery plan](https://github.com/0xHelico/helico/blob/main/docs/plans/2026-09-05-cre-forwarder-delivery.md).
Reproduce it with `apps/cre/rehearse.sh`; it forks `latest`, so the numbers differ each time.

> **warn:** A fork, not the live network. The simulator, not a TEE. A mock forwarder that verifies no
signatures. The run proves delivery and execution, not DON authorisation.

## Tests, as of 2026-09-06
| Suite                    | Count                                      |
| ------------------------ | ------------------------------------------ |
| contracts, Foundry       | 100, of which 11 on a fork of Arbitrum One |
| `@helico/plugin-cre`     | 116                                        |
| `@helico/plugin-uniswap` | 52                                         |

`VaultAttacks.t.sol` holds an automated review's findings as regression tests, each written
before the contract could pass it. CI leaves the RPC unset so the fork suite reports `SKIP`.

## Transactions on real networks
The Uniswap package has run the full position lifecycle on Base Sepolia and Robinhood Chain
Testnet, every step `status: success`, and read pools and quotes on Arbitrum One and Robinhood
Chain. Hashes in [the README](https://github.com/0xHelico/helico/blob/main/packages/plugins/uniswap/README.md#executed-on-chain).

## Reviews
Twelve automated reviewers, then six more. The findings that mattered became tests. Not an
audit, and never called one.

# FAQ (https://docs.helico.site/docs/faq)

The questions people ask first.

## What is Helico, in plain words?
When you put money into a trading pool, it only earns while the price stays inside a band you
chose. Prices drift, and then the money sits idle. Helico watches for that and moves your funds
back into their band, under rules you write down once. A contract checks every rule before
anything moves, and blocks anything else.

## What do I need to start?
A wallet, and funds already sitting in a supported market on the Arbitrum network. Helico does
not create or hold them. Nothing is live yet, so today the honest answer is the code and a
rehearsal on a copy of the market.

## Who holds my money?
You do. Your funds stay in your wallet as a token that proves you own them. You give the
contract permission to move them, not to keep them.

## What can the automation do to it?
One thing: propose a move inside your rules. It cannot pay itself, it cannot spend more than
your funds released, and it cannot send anything anywhere but back to you or into the market.

## When does it do nothing?
Most of the time. It waits while your cooldown runs, and whenever a move would not bring your
funds meaningfully closer to the price, because every move costs a little.

## What stays private?
How the decision is made. The program that decides runs inside a sealed environment. Your rules
themselves are public on the chain, so anyone can check that a move followed them.

## Is it live? Is it audited?
Neither, yet. The whole flow has been run end to end on a copy of the real market and kept 94%
of the funds working. That was a copy, not the live network, and the sealed environment was
simulated. Twelve automated reviewers and then six more went over the contract; that is not a
professional audit.

## Can I stop it?
Yes, at any time. Withdraw the permission or press revoke. Nothing can block that.

# How it works (https://docs.helico.site/docs/how-it-works)

You set the rules. A program decides. A contract checks. Nothing moves otherwise.

## Five steps
1. **You write your rules once.** Which market, how wide, how often, how much to keep. You
   sign them, and the contract stores them. Your funds stay in your wallet.
2. **A program watches.** Every few minutes it reads the price and your funds. It runs inside
   a sealed environment, so how it decides stays private.
3. **It decides.** While the price is inside your band, or your cooldown is running, it does
   nothing. Otherwise it proposes a new band of your chosen width around the price.
4. **The contract checks everything again.** Your rules, one by one, against the price right
   now. If any rule breaks, the move is refused. There is no other way in.
5. **The move happens in one step.** Your funds come out, the exchange only what the new band
   needs, and go back in under your name. Before the step ends, the contract proves it kept
   nothing.

## What that means for you
* Nobody can move your funds outside your rules. Not the program, not us.
* Nobody can keep your funds. Not for a second longer than one move.
* You can stop it at any time, and nothing can block that.

## Why there is an exchange in the middle
When the price leaves your band, your funds end up all on one side. A band around the current
price needs both sides. So the move exchanges just enough to fill the other side, through the
same market, and stops at the edge of your band. The price cannot be pushed past it.

# Introduction (https://docs.helico.site/docs/introduction)

Your funds keep earning while prices move, under rules you set once.

## What Helico does
Put money into a trading pool and it earns only while the price stays near where you put it.
Prices drift. Then your money sits idle.

Helico watches for that. When your funds drift out of their band, it moves them back, under
rules you wrote down once. A contract checks every rule before anything moves, and refuses
anything else.

It can move your money. It can never keep it.

## What you set, once
* Which market.
* How wide the band is.
* How often a move may happen.
* How much of your funds every move must keep.

That is most of it. The full list is on [Your rules](https://docs.helico.site/docs/your-rules).

## What is true today
> **warn:** Nothing is live yet. Helico has been run end to end on a copy of the real market, and it
worked. It has not been deployed to a live network, and it has not been audited. The
[Status](https://docs.helico.site/docs/status) page keeps this honest.

## Where to go next
* [How it works](https://docs.helico.site/docs/how-it-works), in five steps.
* [Your rules](https://docs.helico.site/docs/your-rules), what each one stops.
* [Your money](https://docs.helico.site/docs/your-money), who holds it and what can happen to it.
* [FAQ](https://docs.helico.site/docs/faq).

If you build things, start at [For builders](https://docs.helico.site/docs/builders).

# llms.txt (https://docs.helico.site/docs/llms-txt)

These docs as Markdown, for AI agents.

|                        |                                                                     |
| ---------------------- | ------------------------------------------------------------------- |
| Index                  | [`/llms.txt`](https://docs.helico.site/llms.txt)                    |
| Everything in one file | [`/llms-full.txt`](https://docs.helico.site/llms-full.txt)          |
| Any page               | append `.md` to its URL, or request it with `Accept: text/markdown` |

The **Copy** and **Open in** actions at the top of each page hand the Markdown to an agent.

> **info:** Keep the caveats when quoting: nothing is live, the rehearsal ran on a fork through a
simulator, and the automated reviews are not an audit.

# MCP server (https://docs.helico.site/docs/mcp-server)

Live access to these docs for an AI agent.

A Streamable HTTP MCP server at `https://docs.helico.site/api/mcp` with three tools:
`list_pages`, `search_docs`, and `get_page`.

**Cursor**, in `.cursor/mcp.json` under `mcpServers`:

```json
"helico": { "url": "https://docs.helico.site/api/mcp" }
```

**VS Code**, in `.vscode/mcp.json` under `servers`:

```json
"helico": { "type": "http", "url": "https://docs.helico.site/api/mcp" }
```

**Claude and other HTTP MCP clients**: point them at the URL above. The **Copy** menu on any
page carries a ready-made prompt with these steps.

# Privacy (https://docs.helico.site/docs/privacy)

What stays private, and what is public on purpose.

## Private
How the decision is made. The program that decides runs inside a sealed environment. Which
funds it watches, when it looks, and how it sizes a move never leave it.

Six of your seven rules are released only inside that environment: how wide, worth the move,
how often, how much at once, until when, and how much to keep. They are your strategy.

## Public
Which market. The contract stores it, and anyone can read the chain. Your rules as a whole are
also public on the chain, so anyone can check that a move followed them.

## Why the program is not trusted either
Every decision carries a fingerprint of the rules it was decided against. The contract compares
it with the fingerprint of the rules it stores. If they differ, the move is refused. So a
program with the wrong rules can only produce a refusal, never a wrong move.

> **info:** Today the sealed environment is simulated. The privacy described here becomes real once the
program runs on the live Chainlink network. See [Status](https://docs.helico.site/docs/status).

# Status (https://docs.helico.site/docs/status)

What works, what has been proven, and what is not yet true.

> **warn:** Nothing is deployed to a live network. Read everything below with that sentence next to it.

## Proven
* **The whole flow, on a copy of the real market.** Funds that had drifted out of their band
  were moved back, with 94% of them still working. A second run correctly did nothing, because
  the cooldown was running.
* **Every rule has a test that tries to break it.** 100 tests on the contract, 116 on the
  program that decides, 52 on the market piece. They run on every change.
* **Real transactions on test networks.** The market piece has done the full round trip, put in,
  move, take out, on two test networks.

## Not yet
* **A live network.** The rehearsal ran on a copy of Arbitrum One, through a simulator and a
  test delivery path that checks no signatures.
* **A professional audit.** Twelve automated reviewers went over the contract, then six more.
  That is not an audit, and nothing here calls it one.

## Limits, written down on purpose
* One market at a time per wallet.
* The cap on how much one move may touch covers the whole of your funds, so set it above what
  you have in.
* Every move pays a small exchange fee to the market itself. On a market with a high fee, a
  move can cost more than it recovers. Choose the market with the fee in mind.
* Money sent to the contract by mistake, outside a move, cannot be recovered. That is the price
  of the contract having no way to take money out.

Builders will find the full list, with the reasoning, on [Contracts](https://docs.helico.site/docs/contracts).

# Uniswap plugin (https://docs.helico.site/docs/uniswap-plugin)

Uniswap v4 on chain through the official SDKs and viem, on any chain, without signing or sending.

[`@helico/plugin-uniswap`](https://github.com/0xHelico/helico/tree/main/packages/plugins/uniswap) resolves addresses, reads
pools, quotes, and builds calldata. It never signs or sends. No API key, no wallet.

| Module                  | Does                                                                                                                                                                                                         |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `addresses`, `networks` | addresses and the Universal Router version per chain, from the SDKs; built-ins for Ethereum, Arbitrum, Polygon, BNB, Base, Base Sepolia, Robinhood Chain and its testnet; runtime registration for any other |
| `pool`                  | pool keys, `poolId` matching v4's own, state through `StateView`, tick and price helpers                                                                                                                     |
| `quote`                 | exact-in and exact-out, single and multi-hop, through the v4 `Quoter` over `eth_call`                                                                                                                        |
| `swap`                  | Universal Router calldata for every swap shape, with the router-level `SWEEP` for native exact-output                                                                                                        |
| `approval`              | Permit2 allowances, the two approvals, EIP-712 `PermitSingle` data                                                                                                                                           |
| `liquidity`             | `V4PositionManager` calldata: initialise, mint, increase, decrease, collect                                                                                                                                  |

```ts
import * as uni from '@helico/plugin-uniswap'
import { createPublicClient, http } from 'viem'

const net = uni.network('arbitrum')
const client = createPublicClient({ chain: net.chain, transport: http() })
const poolKey = uni.createPoolKey({ currencyA: '0x0000000000000000000000000000000000000000', currencyB: net.usd.address, fee: 500, tickSpacing: 10 })
const { amountOut } = await uni.quoteExactInputSingle(client, { poolKey, zeroForOne: true, amountIn: 10n ** 18n })
const tx = uni.encodeSwapExactInSingle({ chainId: net.chain.id, poolKey, zeroForOne: true, amountIn: 10n ** 18n, amountOutMinimum: uni.minimumAfterSlippage(amountOut, 50), deadline: uni.deadlineFromNow(600) })
// tx = { to, data, value }: simulate it, or sign and send it yourself
```

## Scripts
```bash
bun run --filter @helico/plugin-uniswap test                     # offline
CHAIN=base bun run --filter @helico/plugin-uniswap smoke         # live, read-only
CHAIN=base-sepolia bun run --filter @helico/plugin-uniswap e2e   # sends real transactions; needs PRIVATE_KEY
```

## Executed on chain
The full lifecycle, wrap, initialise, approve, mint, increase, swap both ways, collect, burn,
has run on Base Sepolia and on Robinhood Chain Testnet with every step `status: success`.
Read-only checks have run on Arbitrum One and Robinhood Chain. The hashes are in
[the README](https://github.com/0xHelico/helico/blob/main/packages/plugins/uniswap/README.md#executed-on-chain); what was
hard about v4 is in [`FEEDBACK.md`](https://github.com/0xHelico/helico/blob/main/FEEDBACK.md).

## Do not forget
`amountOutMinimum` and `amountInMaximum` are the only slippage guards, so derive them from a
fresh quote. The V4\_SWAP input is `V4Planner.finalize()`. Native-input exact-output swaps leave
ETH in the router, which is why the encoders add a `SWEEP`.

# Your money (https://docs.helico.site/docs/your-money)

Who holds it, what can happen to it, and what cannot.

## Who holds it
You do. Your funds stay in your wallet as a token that proves you own them. You give the
contract permission to move them, not to keep them.

During a move, the contract holds your funds for one step, because an exchange has to happen
somewhere. Before that step ends, it checks that it kept nothing. If it did, the whole move is
undone.

## What the program can do
One thing: propose a move inside your rules.

It cannot pay itself. It cannot spend more than your funds released. It cannot send anything
anywhere except back to you or into the market. A misbehaving program could move you within
your own rules, and nothing else.

## What the contract will not do
* Move your funds to another market.
* Make a band wider or narrower than you said.
* Move more often than you allowed.
* Keep less of your funds working than you demanded.
* Act after your rules expire.
* Keep anything.

Each of those is a line in the contract that refuses the move, and each line has a test.

## Updates to the contract
The contract can be updated, and we say so plainly. Three things keep that honest: an update
waits two days after it is announced, the announcement is fixed and expires after seven days,
and your exit is never affected by a pending update.

## The honest part
Nothing is live yet, and the contract has not had a professional audit. Twelve automated
reviewers went over it, then six more; that is not an audit. See [Status](https://docs.helico.site/docs/status).

# Your rules (https://docs.helico.site/docs/your-rules)

Seven things you decide once. Each one stops something.

## The seven rules
| Rule             | What it means                                        | What it stops                           |
| ---------------- | ---------------------------------------------------- | --------------------------------------- |
| Which market     | the one market your funds may be in                  | your funds going anywhere else          |
| How wide         | how wide the band around the price is                | a band wider or narrower than you said  |
| Worth the move   | how much closer a move must bring the band           | churning for no reason, which costs you |
| How often        | at most one move per this much time                  | churning your funds                     |
| How much at once | a cap on how much one move may touch                 | moving more than you allowed            |
| Until when       | the date your rules expire                           | anything after that date                |
| How much to keep | the share of your funds every move must keep working | a move that leaves your funds idle      |

And one more the contract adds by itself: **the new band must contain the current price**. A
band around the wrong price would earn nothing.

> **warn:** "How much to keep" is your protection. Set it to zero and a move is allowed to keep almost
nothing working. Ninety percent is a sensible floor.

## Changing your mind
You can update your rules on the same funds at any time. To switch to a different market, end
the first one yourself, then set new rules. Nothing is ever dropped quietly.

## One market at a time
Each wallet can automate one market at a time. If you have funds in several markets, Helico
manages one of them. This is a real limit and it is written down on purpose.

## Ending it
Withdraw the permission you gave, or press revoke. Either ends everything immediately, and
nothing can block it. Not the program, not us, not a pending update to the contract.
