# Welcome

<figure><img src="https://704538046-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOdJVVvzak2JMqh009HK7%2Fuploads%2FATAkK53yyXaufRCroF0k%2FHypersurface%20Logo.png?alt=media&amp;token=2f277626-7833-41fd-9854-892f0f88f124" alt=""><figcaption></figcaption></figure>

### Overview - What is Hypersurface?

\
Hypersurface is a DeFi platform for structured products, specializing in on-chain covered calls / cash-secured puts to generate real yield for crypto holders.

It’s designed for holders, funds, treasuries, market makers, DeFi power users, or anyone looking to earn steady yield on assets they already own.

As the end user, you decide when to sell and at what price.

<figure><img src="https://704538046-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FOdJVVvzak2JMqh009HK7%2Fuploads%2FB6NWpyz0miR3q0bGxlKH%2FHypersurface%20Architecture%20-%20x.com%20_%20Landscape.png?alt=media&amp;token=59e8a06a-277e-4921-a824-270a8efb5973" alt=""><figcaption></figcaption></figure>

### Why does it exist?

Traditional finance manages over $10 trillion in structured products, yet most remain unavailable on-chain.

Covered calls / Cash-Secured puts are common in traditional brokerage accounts but are still underutilized in crypto.

There’s a growing demand for transparent, composable, and trustless yield products built around crypto assets.\
\
Inspired by how Hyperliquid transformed on-chain perpetuals trading, Hypersurface aims to bring similar innovation to on-chain options trading.

### Who is it for?

Hypersurface is for anyone who wants to earn extra yield from assets they already hold like HYPE, WBTC, SOL etc,. Whether it is:<br>

* Crypto treasuries and funds looking to monetize their assets passively
* DeFi maxis who want more customizable, composable yield options
* Individual holders who just want some extra juicy yield&#x20;

Hypersurface is for everyone.<br>


# How do Covered Calls work?

A covered call is a simple and powerful tool at your disposal.&#x20;

* You own a crypto asset like HYPE or WBTC
* You sell a call option: the right (although, not an obligation) for someone else to buy your asset at a chosen price (strike) in the future.
* For selling that right, you earn an upfront premium (yield), regardless of the option being exercised or not.
* If the asset stays below the strike price, you keep both the premium and your asset
* If the price rises above the strike price, your asset is sold at the strike price but you still keep the premium as extra profit.<br>

***

#### Example: Selling a Covered Call with a $100 Strike Price

| Scenario            | Price at Expiry | What Happens         | What You Earn  |
| ------------------- | --------------- | -------------------- | -------------- |
| Below Strike price  | $95             | Keep asset + premium | Premium        |
| At the strike price | $100            | Keep asset + premium | Premium        |
| Above strike price  | $110            | Asset sold at $100   | Premium + $100 |

<br>


# How do Cash-Secured Puts work?

A Cash Secured put is a simple and powerful tool at your disposal.

* You hold stable coins equal to the potential purchase price (strike × quantity) of a crypto asset like HYPE or WBTC
* You sell a put option: the right (although, not an obligation) for someone else to sell you their asset at a chosen price (strike) in the future.
* For selling that right, you earn an upfront premium (yield), regardless of the option being exercised or not. This is applied to your required collateral for selling the Cash Secured Put.
* If the asset stays above the strike price, you keep both the premium and your cash
* If the price falls below the strike price, you buy the asset at the strike price using your secured cash, but you still keep the premium which reduces your effective purchase price.

***

#### Example: Selling a Cash-Secured Put with a $100 Strike Price

| Scenario            | Price at Expiry | What Happens                        | What You Earn                                  |
| ------------------- | --------------- | ----------------------------------- | ---------------------------------------------- |
| Below Strike price  | $95             | Buy asset at $100 with secured cash | Premium (reduces cost basis to $100 - premium) |
| At the strike price | $100            | Keep asset + premium                | Premium                                        |
| Above strike price  | $110            | Keep cash + premium                 | Premium                                        |


# Settlement

Options expire at **08:00 UTC** on their listed expiry date. Expiry is not limited to Friday.

Please note that **settlement is not always instantaneous**. After expiry, positions may take up to **\~2 hours** to fully settle before they are reflected in the protocol and become available for withdrawal.

This extended settlement window can occur during periods of high volume, when the protocol requires additional time to process all exercised and expiring positions accurately and ensure proper finalization.

Additionally, **Hypersurface may exercise in-the-money (ITM) options up to \~24 hours before expiry** if it is optimal for the protocol.


# Early Position Closures

Hypersurface allows you to close your positions before expiry directly from the Portfolio Page.To close early:<br>

* Navigate to the Portfolio Page in your dashboard.
* Select the position you want to close.
* Click the “Close Early” button.
* Choose the portion of your position you wish to purchase back by paying the applicable premium.

\\

Once the early closure is completed, your position will be settled and the collateral you had locked for that position will become available.

After closing a position early, you must withdraw your collateral from the protocol to have it returned to your wallet.


# Who can use Hypersurface?

**Individuals located in the United States are not eligible to use Hypersurface at this time.** Otherwise, anyone who wishes to use it, can use it. All you need is a wallet, assets and determination. Whether you are an individual or institutional investor, everyone is welcome on Hypersurface.&#x20;


# Auctions

How Hypersurface auctions option inventory, and how to take part

> **Legacy deployment reference.** This page describes the previously documented USD₮0 auction system. Compatibility and availability for the current USDC PremiumPool have not been verified. See the [historical contract entries](/contracts/hyper-evm#legacy-addresses) and [current integration guide](/integration-guide) before choosing a deployment.

Hypersurface holds the options it buys from sellers. Auctions sell that inventory back to the market. Anyone can take part, with no sign-up or whitelist.

The price opens high and falls over a few minutes. Take the whole auction or part of it, at the current price. Settlement is one transaction, in USDT0.

### Participating in an auction

Live auctions are at [app.hypersurface.io/auctions](https://app.hypersurface.io/auctions).

* Pick an auction and an amount.
* Set a maximum premium to cap what you pay.
* First come, first served. An auction closes once it is fully taken.

### What it means for option sellers

When an auction sells above the protocol's price, the difference goes back to whoever sold those options. See the [Rebate Ledger](/overview/rebate-ledger).

### Developer integration

Take auctions through the contracts directly, or through the app at [app.hypersurface.io/auctions](https://app.hypersurface.io/auctions). The [Integration Guide](/integration-guide) has the contract addresses and chain configuration.


# Rebate Ledger

How option sellers earn and claim auction rebates

> **Legacy deployment reference.** This page describes the previously documented USD₮0 auction system. Compatibility and availability for the current USDC PremiumPool have not been verified. See the [historical contract entries](/contracts/hyper-evm#legacy-addresses) and [current integration guide](/integration-guide) before choosing a deployment.

When an auction sells above the protocol's price, the extra goes back to whoever sold those options. That payment is your **rebate**.

You earn rebates on any option you sold to Hypersurface and still hold. Your share scales with your position. Rebates are paid in USDT0.

### Claiming your rebate

Your rebates are at [app.hypersurface.io/rebates](https://app.hypersurface.io/rebates), listed by option.

* Claim sends your rebate to your wallet. No approval needed.
* Rebates build up until you claim them.
* Rebates you have already earned stay yours, even if you later close, exercise, or settle the position.


# Points Program

Hypersurface's reward program where traders earn points based on on-chain activity. Points are distributed weekly and will evolve across different seasons, stay tuned for more.

### Season 1

**Earning Points**

* Earn points by trading on Hypersurface, engaging with the community and interacting the the protocol.
* The exact formula (weightings, thresholds, multipliers) is internal and may change.

**Distribution**

* Points are calculated weekly.
* Distributions happen every Wednesday.

**Eligibility & Anti-Abuse**

* We may exclude accounts showing signs of abuse.
* Hypersurface retains full discretion to define abusive behavior and adjust or void point balances.

**Disclaimer**

* Points don’t guarantee future token rewards, airdrops, or cash.
* Right now, points have **no inherent monetary value**.
* Hypersurface retains the right to adjust how points are earned, change bonus mechanics, or modify distribution at any time.
* Hypersurface may adjust points retroactively in cases of abuse
* To remain eligible for multiplier boosts in the Points Program, users must hold both the Pass NFT and the partner NFT at the time of each points distribution.\
  If either NFT is sold or transferred beforehand, the multiplier is will not be applied at time of weekly point distribution.


# Referrals & Affiliate Program

Hypersurface also facilitates an affiliate program where you can generate a unique referral link in your dashboard to share with your friends or your community and earn a kickback on protocol fees generated through them. Top referrers unlock tiered perks, higher affiliate fee shares and exclusive discord/telegram community roles.\
In addition to this, there is a leaderboard for competitiveness, which may have special rewards or early access to future products.

<br>


# HyperEVM (current + legacy)

## Current USDC PremiumPool

Reviewed **2026-10-15** against the current application manifest and read-only HyperEVM mainnet RPC at block **48635813**. Chain ID: **999**. RPC: `https://rpc.hyperliquid.xyz/evm`.

| Contract      | Address                                                                                                                    | Integration role                                       |
| ------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
| PremiumPool   | [`0x6806c2c11d9aa3464792d10455a6480d793eedc1`](https://hyperevmscan.io/address/0x6806c2c11d9aa3464792d10455a6480d793eedc1) | Trading entry point; buyback premium approval          |
| AddressBook   | [`0xcb8c52725e6662ae8e954c8fede1b1d7166091e3`](https://hyperevmscan.io/address/0xcb8c52725e6662ae8e954c8fede1b1d7166091e3) | Component registry                                     |
| Controller    | [`0x99029d0f8ac8ff66b210054eef1820ca68073f09`](https://hyperevmscan.io/address/0x99029d0f8ac8ff66b210054eef1820ca68073f09) | Vault state and settlement                             |
| MarginPool    | [`0x724a3031f22a5d8b8ec45fcf66de398dedba4edf`](https://hyperevmscan.io/address/0x724a3031f22a5d8b8ec45fcf66de398dedba4edf) | Collateral custody                                     |
| TradeExecutor | [`0x2238868e70bf7e9200ce9979018a7ecbaeb076ab`](https://hyperevmscan.io/address/0x2238868e70bf7e9200ce9979018a7ecbaeb076ab) | Collateral approval for opening shorts                 |
| USDC          | [`0xb88339cb7199b77e23db6e890353e22632ba630f`](https://hyperevmscan.io/address/0xb88339cb7199b77e23db6e890353e22632ba630f) | Premium and strike token; 6 decimals                   |
| OrderUtil     | [`0x71deaf4771bf8280a3d3735bac9df5835b20eb1a`](https://hyperevmscan.io/address/0x71deaf4771bf8280a3d3735bac9df5835b20eb1a) | AddressBook `getOrderUtil()`                           |
| Oracle        | [`0xb654b726f7eec3f417578ba4e498bc4b914dd796`](https://hyperevmscan.io/address/0xb654b726f7eec3f417578ba4e498bc4b914dd796) | AddressBook `getOracle()`; pool `oracle()`             |
| FeeCollector  | [`0x14325e60129242cc9925437b867b04ea94a64f8a`](https://hyperevmscan.io/address/0x14325e60129242cc9925437b867b04ea94a64f8a) | AddressBook `getFeeCollector()`                        |
| BlackScholes  | [`0x3cff8f2c684462f51a1fa015b35018a85f33d6a4`](https://hyperevmscan.io/address/0x3cff8f2c684462f51a1fa015b35018a85f33d6a4) | AddressBook `getBlackScholes()`; pool `blackScholes()` |

Use the [current integration guide](/integration-guide) with this deployment. The old USD₮0 HedgedPool order ABI is incompatible.

## Verification evidence

* The application manifest at b5e0d39 supplies the first six addresses; the remaining addresses come from the AddressBook getters listed above. The production application's JavaScript bundle also contains this PremiumPool address and the USDC quote-service URL.
* At the review block, all ten listed addresses had nonempty bytecode. `PremiumPool.addressBook()` matched the listed AddressBook; `premiumToken()` and `strikeToken()` both matched USDC. USDC returned symbol `USDC` and decimals `6`.
* AddressBook role getters matched the table. Public pool `oracle()` and `blackScholes()` matched the AddressBook. `TradeExecutor.authorizedPools(PremiumPool)` returned `true`. These checks establish public registry relationships at a snapshot; they do not establish an audit or bytecode equivalence to a source commit.
* The contract interfaces at 7508cfa are the source used for the current guide's ABI. Upgradeable addresses can retain their address while implementation code changes; recheck before integrating.

### Maintainer source snapshots

The source review used the organization-access repositories `frontend-handoff` at `b5e0d39ed6975c664d33f93e4ab35203466a9dd3` (`src/deployments/handoff.ts`, `src/config.ts`) and `contracts-handoff` at `7508cfa4b12de7463a3fe7c03ff74d16f5ae486b` (`IOrderUtil.sol`, `IPremiumPool.sol`, `PremiumPool.sol`, `PremiumPoolStorage.sol`, `TradeExecutor.sol`, `IGamma.sol`). These repositories require organization access; the addresses, integration ABI and public RPC checks are reproduced here so readers do not depend on that access.

## Read-only verification

These commands require Foundry's `cast` and submit no transactions. Pin a fresh block for a consistent read; compare every returned address with the table. A public RPC can prune older state, so the review block may require an archive RPC later.

```sh
RPC_URL=https://rpc.hyperliquid.xyz/evm
POOL=0x6806c2c11d9aa3464792d10455a6480d793eedc1
ADDRESS_BOOK=0xcb8c52725e6662ae8e954c8fede1b1d7166091e3
USDC=0xb88339cb7199b77e23db6e890353e22632ba630f
BLOCK=$(cast block-number --rpc-url "$RPC_URL")

cast chain-id --rpc-url "$RPC_URL" # expected: 999
cast code "$POOL" --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$POOL" 'addressBook()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$POOL" 'premiumToken()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$POOL" 'strikeToken()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$POOL" 'oracle()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$POOL" 'blackScholes()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$ADDRESS_BOOK" 'getController()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$ADDRESS_BOOK" 'getMarginPool()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$ADDRESS_BOOK" 'getTradeExecutor()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$ADDRESS_BOOK" 'getOrderUtil()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$ADDRESS_BOOK" 'getOracle()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$ADDRESS_BOOK" 'getFeeCollector()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$ADDRESS_BOOK" 'getBlackScholes()(address)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$USDC" 'symbol()(string)' --block "$BLOCK" --rpc-url "$RPC_URL"
cast call "$USDC" 'decimals()(uint8)' --block "$BLOCK" --rpc-url "$RPC_URL"
```

The pool caches component addresses. Controller, MarginPool, TradeExecutor, OrderUtil and FeeCollector are internal fields without public pool getters; these checks do not attest their cached values. Simulate the intended operation before submission. If public reads disagree with the registry, stop and resolve the deployment mismatch.

## Legacy addresses

The entries below are historical addresses retained from the earlier docs for identifying old positions and integrations. They are **not the current USDC deployment** and were not revalidated as operational during this review. Do not reuse their approvals, ABI or auction configuration for PremiumPool. See the [legacy guide](/legacy-integration-guide).

### Historical HedgedPool contracts

<table><thead><tr><th width="195.984375">Contract</th><th>Address</th></tr></thead><tbody><tr><td><strong>HedgedPool</strong></td><td><a href="https://hyperevmscan.io/address/0x0095acdd705cfcc11eaffb6c19a28c0153ad196f"><code>0x0095aCDD705Cfcc11eAfFb6c19A28C0153ad196F</code></a></td></tr><tr><td><strong>Hedger</strong></td><td><a href="https://hyperevmscan.io/address/0xa8c9403BDf554C047Ad91a448DDb24208Ab5313c"><code>0xa8c9403BDf554C047Ad91a448DDb24208Ab5313c</code></a></td></tr><tr><td><strong>MarginPool</strong></td><td><a href="https://hyperevmscan.io/address/0x7D2e4b4d7ba55C423F5CCe194ae8194eFD1C6e35"><code>0x7D2e4b4d7ba55C423F5CCe194ae8194eFD1C6e35</code></a></td></tr><tr><td><strong>MMTradeHelper</strong></td><td><a href="https://hyperevmscan.io/address/0x5d2CBe54e4a27FDBffaf8De29b95c584c910269D"><code>0x5d2CBe54e4a27FDBffaf8De29b95c584c910269D</code></a></td></tr></tbody></table>

### Historical auction references

<table><thead><tr><th width="195.984375">Contract</th><th>Address</th></tr></thead><tbody><tr><td><strong>Auction</strong></td><td><a href="https://hyperevmscan.io/address/0xf077393F8d2e6fB8151a53c5209686544a0E3749"><code>0xf077393F8d2e6fB8151a53c5209686544a0E3749</code></a></td></tr><tr><td><strong>RebateLedger</strong></td><td><a href="https://hyperevmscan.io/address/0x06D44b2ad3A8827613B1a3813722D3870EdF26c1"><code>0x06D44b2ad3A8827613B1a3813722D3870EdF26c1</code></a></td></tr><tr><td><strong>BlackScholes</strong></td><td><a href="https://hyperevmscan.io/address/0x84d4c4771CC3c47F43c608E08A3Ac5D9f80C54aB"><code>0x84d4c4771CC3c47F43c608E08A3Ac5D9f80C54aB</code></a></td></tr></tbody></table>


# Audits

| Auditor                                  | Audit Report                                                                                 |
| ---------------------------------------- | -------------------------------------------------------------------------------------------- |
| <h3><strong>Simply Staking</strong></h3> | <h3><a href="https://github.com/SimplyStaking/security-audit-reports">Audit Report</a> </h3> |

### Security Practices

{% hint style="info" %}
Ongoing Security:

* Comprehensive test suite
* Automated testing on every code change
* Real-time monitoring

Report Issues:  [@hypersurfaceX](https://t.me/hypersurfaceX)
{% endhint %}

{% hint style="warning" %}
All DeFi carries risk. Only trade with funds you can afford to lose hypersurface is not responsible for loss of funds.&#x20;
{% endhint %}


# TERMS AND CONDITIONS

TERMS AND CONDITIONS These terms and conditions outline the rules and regulations for the use of Hypersurface, located at https\://hypersurface.io/ TERMS AND CONDITIONS Welcome! By accessing this websi

#### Welcome!

By accessing this website we assume you accept these terms and conditions. Do not continue to use Hypersurface if you do not agree to all of the terms and conditions stated on this page.

The following terminology applies to these Terms and Conditions, Privacy Statement and Disclaimer Notice and all Agreements: "Site Visitor", "You" and "Your" refers to you, this website and compliant to the Company’s terms and conditions. "The Company", "Ourselves", "We", "Our" and "Us", refers to our Company. "Party", "Parties", or "Us", refers to both You, as the Site Visitor, and ourselves. All terms refer to the offer, acceptance and our assistance to the Site Visitor in the most appropriate manner for the express purpose of meeting the Site Visitor’s needs in respect of provision of the Company’s stated services, in accordance with and subject to, prevailing laws where Hypersurface is domiciled. Any use of the above terminology or other words in the singular, plural, capitalization and/or he/she or they, are taken as interchangeable and therefore as referring to the same.

#### Cookies

We employ the use of cookies. By accessing Hypersurface, you agreed to use cookies in agreement with Hypersurface's Privacy Policy.

<br>

Most interactive websites use cookies to let us retrieve the user’s details for each visit. Cookies are used by our website to enable the functionality of certain areas to make it easier for people visiting our website. Some of our affiliate/advertising partners may also use cookies.

#### License

Unless otherwise stated, Hypersurface and/or its licensors own the intellectual property rights for all material on Hypersurface. All intellectual property rights are reserved. You may access this from Hypersurface for your own personal use subjected to restrictions set in these terms and conditions.

You must not (without written permission from us):

* Republish material from Hypersurface
* Sell, rent or sub-license material from Hypersurface
* Reproduce, duplicate or copy material from Hypersurface
* Redistribute content from Hypersurface
* This Agreement shall begin on the date hereof.

<br>

Parts of this website offer an opportunity for users to post and reply to opportunities and exchange opinions and information ("Content") in certain areas of the website. Content does not reflect the views and opinions of Hypersurface, its agents and/or affiliates. Content reflects the views and opinions of the person who posts their opportunities, views and opinions. To the extent permitted by applicable laws, Hypersurface shall not be liable for the Content or for any liability, damages or expenses caused and/or suffered as a result of any use of and/or posting of and/or appearance of the Content on this website.

<br>

Hypersurface reserves the right to monitor all Content and to remove any Content which can be considered inappropriate, offensive or causes breach of these Terms and Conditions.

You warrant and represent that:

<br>

* You are entitled to post and respond to opportunities on our website and have all necessary licenses and consents to do so;
* The Content does not invade any intellectual property right, including without limitation copyright, patent or trademark of any third party;
* The Content does not contain any defamatory, libelous, offensive, indecent or otherwise unlawful material which is an invasion of privacy
* The Content will not be used to solicit or promote business or custom or present commercial activities or unlawful activity.
* You hereby grant Hypersurface a non-exclusive license to use, reproduce, edit and authorize others to use, reproduce and edit any of your Content in any and all forms, formats or media.

#### iFrames

Without prior approval and written permission, you may not create frames around our Webpages that alter in any way the visual presentation or appearance of our Website.

#### Content Liability

We shall not be held responsible for any content that appears on your Website. You agree to protect and defend us against all claims that are rising on your Website. No link(s) should appear on any Website that may be interpreted as libelous, obscene or criminal, or which infringes, otherwise violates, or advocates the infringement or other violation of, any third party rights. We reserve the right to request that you remove all links or any particular link to our Website. You approve to immediately remove all links to our Website upon request. We also reserve the right to amend these terms and conditions and its linking policy at any time. By continuously linking to our Website, you agree to be bound to and follow these linking terms and conditions.

#### Removal of Content from our website

If you find any Content on our Website that is offensive for any reason, you are free to contact and inform us at any moment. We will consider requests to remove Content but we are not obligated to or so or to respond to you directly.

We do not ensure that the information on this website is correct, we do not warrant its completeness or accuracy; nor do we promise to ensure that the website remains available or that the material on the website is kept up to date.

#### Disclaimer

To the maximum extent permitted by applicable law, we exclude all representations, warranties and conditions relating to our website and the use of this website.

The limitations and prohibitions of liability set in this Section and elsewhere in this disclaimer govern all liabilities arising under the disclaimer, including liabilities arising in contract, in tort and for breach of statutory duty.

As long as the website and the information and services on the website are provided free of charge, we will not be liable for any loss or damage of any nature. In the event information or services are provided for a fee, we will only be liable for the amount paid as a result of any loss or damage.


# Community & Support

Join Hypersurface’s vibrant community on [Telegram](https://t.me/+9_RXVXXlSRZmNzk1).

You can also reach out to us in the [Telegram community group](https://t.me/hypersurfaceX) or DM us on [X](https://x.com/hypersurfaceX) (formerly Twitter) in case of any queries or support.

If you experience any technical issues, please open a support ticket through our [support bot](https://t.me/HypersurfaceSupportBot).<br>


# FAQs

> **Current deployment:** HyperEVM USDC PremiumPool. See the [verified contract registry](/contracts/hyper-evm) and [current integration guide](/integration-guide). The auction/rebate section below describes the legacy USD₮0 deployment.

Welcome to Hypersurface **FAQs**. Below you’ll find answers to common questions about yield, options, settlement, and platform mechanics.

***

### 📌 General

#### Q:What is Hypersurface?

A: Hypersurface is a structured yield platform where users earn upfront premium by selling covered calls or secured puts with simple on-chain UX.

**Q: What is the settlement/delivery time?**\
\
**A:** Settlement starts after the option expires at **08:00 UTC** on its listed expiry date. Expiry is not limited to Friday.

Please note:

* After expiry at 08:00 UTC, positions may take up to **\~2 hours** to fully settle before they are reflected in the protocol and available for withdrawal.
* This extended settlement period may occur during times of high volume, as the protocol requires additional processing time to accurately handle all exercised and expiring positions.
* Additionally, **in-the-money (ITM) options may be exercised up to \~24 hours before expiry** if it is optimal for the protocol.

#### Q: Can settlement happen before expiry?

A: Yes, but this applies only if you close your position early. Please check [**Early Position Closure**](/overview/early-position-closures) for more details.

***

### 📈 Covered Calls & Puts

#### Q: What is a covered call?

A: A covered call lets you earn upfront premium by committing to sell your asset at a chosen strike price while keeping exposure until expiry.

#### Q: How does a covered call work on Hypersurface?

A: You select a strike and expiry, receive the premium instantly, and at expiry either sell at the strike or keep your tokens plus the premium.

#### Q: What happens if my call option is exercised?

A: If your covered call is exercised, the committed asset is exchanged at the strike price. The current deployment's strike and premium token is USDC. Settlement and withdrawal depend on the position state; see the [current integration guide](/integration-guide#closing-collateral-withdrawal-and-expiry).

#### Q: What happens if the strike is not hit and the price drops?

A: You keep the upfront premium and continue holding the asset, helping offset part of the downside.

#### Q: When does exercise happen?

A: Exercise may occur during the final 24-hour window if the position is in the money.

Users should not assume exercise happens only at the final moment of expiry.

#### Q: Are secured puts supported?

A: Yes. Cash-secured puts are live for assets like ZORA, AVNT, HYPE, and more.

***

### 💰 Yield, Premiums & APR

#### Q: When do I get my yield?

A: Yield (the premium) is paid upfront when the position is opened, not at expiry.

#### Q: Is the premium fixed?

A: No. Premiums vary based on asset, strike price, expiry, and market volatility.

#### Q: Why are APRs so high?

A: APR reflects asset volatility and strike selection. Higher volatility produces higher premiums.

#### Q: Where does APR come from?

A: APR comes from market-driven option pricing based on volatility and demand.

#### Q: Is Hypersurface a yield engine?

A: Hypersurface is a structured yield platform that generates market-driven premiums from selling options.

***

### ⚠️ Risk & Lockups

#### Q: Can I withdraw before expiry?

A: Yes, please refer to [**Early Position Closures**](/overview/early-position-closures) for more information.

#### Q: Is my principal at risk?

A: The main risk is ending up buying or selling the asset at the price you selected.

For puts, this means you may buy an asset that continues to decline in price after execution until expiry.

There are no liquidation risks because positions are fully collateralized.

#### Q: Do I need to understand options?

A: No. If you can pick a sell price and asset, the rest is handled with simple UX.

***

### 🏦 Liquidity, Hedging & Counterparties

#### Q: Who is the counterparty on trades?

A: The counterparty is an on-chain liquidity pool that delta-hedges using perpetuals and spot trading.

#### Q: Who provides the liquidity?

A: Liquidity is currently provided by the protocol.

#### Q: How does Hypersurface hedge risk?

A: Risk is hedged using perpetual futures, spot trading, and on-chain limit orders.

#### Q: Are liquidity pools open to everyone?

A: No.

***

### 🔁 Auctions & Rebates (legacy USD₮0 deployment)

These references have not been verified as compatible with the current USDC PremiumPool. See the [historical contract entries](/contracts/hyper-evm#legacy-addresses).

#### Q: What is an auction on Hypersurface?

A: It is how Hypersurface sells option inventory back to the market. The price opens high and ticks down over a short window, and anyone with a wallet can take it. See [Auctions](/overview/auctions).

#### Q: Can anyone take an auction?

A: Yes — anyone with a wallet, with no sign-up or whitelist.

#### Q: What is the Rebate Ledger?

A: When an option you sold is auctioned for more than the protocol's price, the extra is paid back to you as a rebate. The Rebate Ledger tracks those rebates and lets you claim them. See [Rebate Ledger](/overview/rebate-ledger).

#### Q: Do I earn a rebate if my position is auctioned?

A: If you sold an option to Hypersurface and still hold the position, you earn a share of the proceeds whenever that option is auctioned, proportional to your position size. Rebates are paid in USDT0.

#### Q: How do I claim my rebate?

A: Go to [app.hypersurface.io/rebates](https://app.hypersurface.io/rebates), where your rebates are shown by option, and click claim. No token approval is needed, and rebates build up until you claim them.

#### Q: Do I lose my rebate if I close or settle my position?

A: No. Rebates you have already earned stay yours to claim, even after you close, exercise, or settle the position.

***

### 🎯 Strikes, Probabilities & Limits

#### Q: How are strike prices determined?

A: Strikes are generated automatically as percentages relative to the current market price.

#### Q: How is sell probability calculated?

A: Sell probability is implied from option premium using the Black–Scholes pricing model.

#### Q: Is sell probability guaranteed?

A: No. It’s an estimate meant to help users compare market pricing with expectations.

***

### 🧾 Settlement & Portfolio

#### Q: Do I receive yield only after expiry?

A: No. Premium is paid upfront when the position is opened.

#### Q: Why does the premium not show separately for puts?

A: For the current USDC deployment, the premium is netted against the required USDC collateral, with the fee included in the amount the trader supplies. See the [approval and trading details](/integration-guide#approvals-and-trading).

#### Q: What happens after my position expires?

A: You must settle to receive either your asset back or the sale proceeds.

#### Q: I can’t find my collateral after expiry. What should I do?

A: Go to Portfolio → Expired → Settle All.

***

### 🪙 Assets & Wallets

#### Q: What assets are supported?

A: BTC, ETH, HYPE, and more

#### Q: Do I need wHYPE instead of HYPE?

A: Yes. Hypersurface uses wrapped assets on HyperEVM like uBTC, uETH, and uHYPE.

#### Q: Can I wrap HYPE in the app?

A: Yes. Wrapping is available directly inside Hypersurface.

#### Q: Can I use an API wallet?

A: No. Only main Hyperliquid accounts are supported.

<br>


# F.A.Q. (old)

> **Legacy FAQ.** This page describes an earlier deployment. Use the [current FAQs](/references/faqs), [HyperEVM registry](/contracts/hyper-evm) and [integration guide](/integration-guide) for the current USDC deployment.

### Q: What happens if my call option is exercised?

A: If the option finishes in the money, your asset is automatically sold at your strike price. You receive the agreed amount in USDT0 (or other settlement asset), plus the original premium.

### Q: When do I get my yield?

A: Yield (the premium) is paid upfront when the option is sold, not at expiry.<br>

### Q: Can I withdraw before expiry?

A: Positions are locked until expiry atm.

### Q: Is my principal at risk?

A: The maximum risk is that your asset is sold at your target price (strike). No other hidden risks.

### Q: What assets are supported?

A: At launch: HYPE, WTBC, SOL. More assets expected soon.

### Q: Do I need to understand options?

A: No! If you can pick a sell price and asset, the rest is handled for you with simple UX.

<br>


# Integration Guide

Integrate the current HyperEVM USDC PremiumPool deployment

This guide targets the **HyperEVM USDC PremiumPool** used by [the application](https://app.hypersurface.io). Use the [current contract registry](/contracts/hyper-evm) for addresses and verification evidence. The previous HyperEVM USD₮0 HedgedPool examples are preserved in the [legacy integration guide](/legacy-integration-guide); their addresses and order ABI are not interchangeable with this deployment.

## Network and services

| Setting                  | Value                                                              |
| ------------------------ | ------------------------------------------------------------------ |
| Network                  | HyperEVM mainnet                                                   |
| Chain ID                 | `999`                                                              |
| Native gas token         | HYPE                                                               |
| Public RPC               | `https://rpc.hyperliquid.xyz/evm`                                  |
| Explorer                 | `https://hyperevmscan.io`                                          |
| Quote API                | `https://market-api-sh-usdc.hypersurface.io`                       |
| Premium and strike token | USDC; address and decimals in the [registry](/contracts/hyper-evm) |

Services are configured in the application configuration and deployment manifest.

Read-only quote-service availability check:

```sh
curl --fail 'https://market-api-sh-usdc.hypersurface.io/underlyingPrices?symbol=HYPE'
```

This endpoint returned HTTP 200 during the registry review. `/health` returned HTTP 404; do not use the old guide's `/health` request as a current health check. A price response does not establish that a signed order can execute.

## Resolve the deployment

Use the PremiumPool proxy as the entry point. It exposes `addressBook()`, `premiumToken()`, `strikeToken()`, `oracle()` and `blackScholes()`. Resolve Controller, MarginPool and TradeExecutor through the AddressBook's `getController()`, `getMarginPool()` and `getTradeExecutor()`.

Compare the public getters and AddressBook values with the registry at a consistent block. The pool's cached Controller, MarginPool and TradeExecutor fields are internal; there are no public getters for those cached fields. AddressBook reads alone do not prove their cache freshness. Simulate the intended operation before submission. The [registry](/contracts/hyper-evm#read-only-verification) includes read-only commands. Do not substitute a legacy component when a read fails.

Get eligible underlyings from `PremiumPool.getAllUnderlyings()`. Collateral can differ from the underlying for a supported staked-asset product. Read token `decimals()` and use the supported underlying/collateral pairing from the current application and quote service; historical token tables do not establish current support.

## Request and preserve a signed quote

`POST /quote` uses the structure below. The function arguments are caller-supplied values for the selected market. `signedAmount` is a signed integer string in option units, not a floating-point token amount. Select a currently offered series symbol rather than a hard-coded expiry from an old example.

```javascript
const PREMIUM_POOL = "0x6806c2c11d9aa3464792d10455a6480d793eedc1";
const QUOTE_API = "https://market-api-sh-usdc.hypersurface.io";

async function requestQuote({ account, underlying, collateral, referrer, symbol, signedAmount }) {
  const response = await fetch(`${QUOTE_API}/quote`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      sign: true,
      order: {
        account,
        poolAddress: PREMIUM_POOL,
        underlying,
        collateral,
        referrer,
        legs: [{ symbol, amount: signedAmount }],
      },
    }),
  });
  const body = await response.json();
  if (!response.ok || !body.result?.order) throw new Error("Quote request failed");
  return body.result.order;
}
```

This follows the current application quote client (source snapshots are recorded in the [registry](/contracts/hyper-evm#maintainer-source-snapshots)). Preserve `result.order`, including every signed field. Validate its account, pool, underlying, collateral, side, size, expiry, premium, fee and validity deadline against the user's intent. Use integer strings, BigInt or a big-number library throughout; do not convert token amounts to `Number`.

## Current order ABI

This interface matches IOrderUtil.sol and PremiumPool.sol. Field order is part of the ABI.

```solidity
interface IPremiumPoolIntegration {
    struct Signature {
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    struct OptionLeg {
        uint256 strike;
        uint256 expiration;
        bool isPut;
        int256 amount;
        int256 premium;
        uint256 fee;
        uint256 iv;
    }

    struct Order {
        address account;
        address poolAddress;
        address underlying;
        address collateral;
        address referrer;
        uint256 validUntil;
        uint256 nonce;
        uint256 underlyingPrice;
        OptionLeg[] legs;
        Signature signature;
        Signature[] coSignatures;
    }

    function trade(Order calldata order, uint256 traderVaultId, bool autoCreateVault)
        external returns (address);

    function withdrawVaultCollateral(uint256 vaultId, address collateralAsset, uint256 withdrawalAmount)
        external;
}
```

`underlyingPrice` uses `1e8` precision. `iv` uses `1e18` fixed-point precision. Both are signed quote fields required by this contract version. An older generated SDK that omits either field encodes a different function selector. Generate bindings from the current interface instead of copying the legacy ABI.

## Approvals and trading

Calculate required collateral using the current vault state and the MarginCalculator resolved through `AddressBook.getMarginCalculator()`, following the TradeExecutor behavior below. Use the registry's current spender addresses and finite allowances for the amount required by the selected operation.

| Operation                  | Token approved       | Spender       | Trade arguments                                                               |
| -------------------------- | -------------------- | ------------- | ----------------------------------------------------------------------------- |
| Open a covered call        | Selected collateral  | TradeExecutor | Negative leg amount; new vault: `traderVaultId = 0`, `autoCreateVault = true` |
| Open a cash-secured put    | Strike token (USDC)  | TradeExecutor | Negative leg amount; new vault: `traderVaultId = 0`, `autoCreateVault = true` |
| Buy back an existing short | Premium token (USDC) | PremiumPool   | Positive leg amount; existing vault ID; `autoCreateVault = false`             |

For a put requiring additional collateral, the executor pulls the margin shortfall minus gross premium plus fee from the trader; the pool contributes gross premium minus fee. For a covered call, the executor pulls the required collateral and the pool pays gross premium minus fee. For buyback, PremiumPool pulls premium plus fee. Account for existing vault collateral when calculating a shortfall. Do not approve MarginPool merely because it ultimately holds collateral.

Simulate the exact call from the intended account and estimate gas before submission. Refresh an expired or invalid quote rather than modifying signed values. The current pool processes a single option leg. A positive amount is the buyback path for an existing short vault, not a standalone long-opening trade.

`trade()` returns an **oToken address**, not a vault ID. A receipt does not directly expose a Solidity return value. When opening a vault, obtain its ID from the TradeExecutor's `MarginVaultOpened(address indexed trader, uint256 vaultId)` event and persist it with the chain, owner, pool and series. Never assume a global vault number.

## Closing, collateral withdrawal and expiry

For early closure, request a fresh buyback quote for the same series and submit it with the existing vault ID. After the short is burned, collateral withdrawal is a separate operation through `withdrawVaultCollateral(uint256,address,uint256)`; Controller collateral constraints still apply.

For expiry settlement, the current application submits a `SettleVault` action to `Controller.operate`, with the trader as owner and recipient. The action uses the existing `vaultId`, the trader address for both `owner` and `secondAddress`, and zero for `asset`, `amount` and `index`. The Controller ABI is `operate((uint8 actionType,address owner,address secondAddress,address asset,uint256 vaultId,uint256 amount,uint256 index,bytes data)[] actions)`; `SettleVault` is action type `7`. The current application uses the zero address encoded as bytes for `data`. Read `canSettleExpiry(expiry)` and the exercise-window views before offering settlement. Expiry alone does not guarantee immediate settlement or an automatic wallet payout.

The application window checks use `exerciseWindow()`, `exerciseWindowAfterExpiration()` and `canExercise(oToken)`. Treat RPC errors separately from a valid `false` result.

## Indexing and historical positions

The application manifest selects this subgraph:

```
https://api.goldsky.com/api/public/project_clysuc3c7f21y01ub6hd66nmp/subgraphs/hypersurface-hyperevm-subgraph/latest/gn
```

Use on-chain state for final transaction decisions. Indexer configuration does not guarantee freshness. Preserve deployment identity: a legacy USD₮0 vault is not a USDC vault, and its allowance or settlement target cannot be migrated by replacing an address in a code sample.

See [historical HyperEVM addresses](/contracts/hyper-evm#legacy-addresses) and the [legacy integration guide](/legacy-integration-guide). The legacy auction and rebate references have not been certified as compatible with the current PremiumPool deployment.


# Legacy Integration Guide

> **Legacy guide.** This archived guide describes the previous HyperEVM USD₮0 HedgedPool deployment. Its addresses, API endpoints, ABI and examples are historical and have not been revalidated for current use. For the USDC PremiumPool, use the [current integration guide](/integration-guide) and [current registry](/contracts/hyper-evm).

## Overview

Hypersurface is an on-chain options protocol for **covered calls** and **cash-secured puts**. You sell options to the protocol and receive premium. The trade lifecycle is:

```
1. Price    →  GET /optionsPrices (indicative pricing + Greeks)
2. Quote    →  POST /quote (protocol co-signs the order)
3. Approve  →  ERC-20 approve on TradeExecutor (one-time per token)
4. Trade    →  HedgedPool.trade() (on-chain, collateral pulled automatically)
5. Hold     →  Position locked until 08:00 UTC expiry
6. Settle   →  Controller.operate() (unlock collateral after expiry)
7. Withdraw →  HedgedPool.withdrawVaultCollateral() (get your tokens back)
```

You can also **close early** at any time by buying back the option (step 4 with positive amount).

### Key Terms

| Term             | Description                                                             |
| ---------------- | ----------------------------------------------------------------------- |
| HedgedPool       | Entry point contract for trading                                        |
| TradeExecutor    | Handles collateral transfers (you approve this, never call it directly) |
| Controller       | Gamma protocol vault operations (settlement, reads)                     |
| oToken           | ERC-20 representing a specific option series                            |
| Vault            | Gamma margin vault holding your collateral and short position           |
| Premium          | Payment received when selling an option (in USD₮0)                      |
| Covered Call     | Sell upside on an asset you hold as collateral                          |
| Cash-Secured Put | Sell downside protection, backed by stablecoin collateral               |

***

## Setup

### Chain Configuration

#### HyperEVM

| Property        | Value                                   |
| --------------- | --------------------------------------- |
| Chain ID        | `999`                                   |
| RPC URL         | `https://rpc.hyperliquid.xyz/evm`       |
| Block Explorer  | `https://explorer.hyperliquid.xyz`      |
| Native Currency | HYPE (18 decimals)                      |
| API Base URL    | `https://market-api-sh.hypersurface.io` |

### Contract Addresses

#### HyperEVM (Chain 999)

| Contract      | Address                                      | Purpose                                                     |
| ------------- | -------------------------------------------- | ----------------------------------------------------------- |
| HedgedPool    | `0x0095aCDD705Cfcc11eAfFb6c19A28C0153ad196F` | Entry point for `trade()`, buy-back premium approval target |
| TradeExecutor | `0x25dD9EAae2e0b118a2CefdD229233654840BA7A0` | Collateral approval target for sell trades                  |
| Controller    | `0x7730e6bfbfCE8Ff0b7a50b72D0601c209Eb818C4` | Vault settlement via `operate()`, vault state reads         |
| MarginPool    | `0x7D2e4b4d7ba55C423F5CCe194ae8194eFD1C6e35` | Holds collateral and oTokens                                |
| Auction       | `0xf077393F8d2e6fB8151a53c5209686544a0E3749` | Dutch IV-auction venue for takers                           |

### Token Addresses

#### HyperEVM (Chain 999) -- Underlyings

| Asset | Symbol | Address                                      | Decimals |
| ----- | ------ | -------------------------------------------- | -------- |
| HYPE  | wHYPE  | `0x5555555555555555555555555555555555555555` | 18       |
| BTC   | UBTC   | `0x9fdbda0a5e284c32744d2f17ee5c74b284993463` | 8        |
| ETH   | UETH   | `0xbe6727b535545c67d5caa73dea54865b92cf7907` | 18       |
| SOL   | USOL   | `0x068f321fa8fb9f0d135f290ef6a3e2813e1c8a29` | 9        |
| XPL   | UXPL   | `0x33af3c2540ba72054e044efe504867b39ae421f5` | 18       |
| PUMP  | UPUMP  | `0x27ec642013bcb3d80ca3706599d3cda04f6f4452` | 6        |
| ENA   | UENA   | `0x58538e6a46e07434d7e7375bc268d3cb839c0133` | 18       |
| KNTQ  | KNTQ   | `0x000000000000780555bd0bca3791f89f9542c2d6` | 18       |
| kHYPE | kHYPE  | `0xfd739d4e423301ce9385c1fb8850539d657c296d` | 18       |

**Premium token:** USD₮0 at `0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb` (6 decimals)

> **Note:** Strike increments are set on-chain and may change. To discover current active strikes and expiries, query the subgraph:
>
> ```graphql
> {
>   otokens(where: { expiryTimestamp_gt: "CURRENT_UNIX_TIMESTAMP" }) {
>     strikePrice
>     expiryTimestamp
>     isPut
>     underlyingAsset { symbol }
>   }
> }
> ```
>
> Or test strikes via the API — `GET /optionsPrices?symbol=BTC-03APR26-65500-C` will return pricing if that strike exists.

***

## API Reference

No authentication required. Trades are authenticated by the EIP-712 signature embedded in the order itself.

### Base URLs

| Chain    | Base URL                                |
| -------- | --------------------------------------- |
| HyperEVM | `https://market-api-sh.hypersurface.io` |

### Endpoints

| Method | Path                | Description                                   |
| ------ | ------------------- | --------------------------------------------- |
| GET    | `/optionsPrices`    | Indicative pricing for an option symbol       |
| POST   | `/quote`            | Co-signed order ready for on-chain submission |
| GET    | `/underlyingPrices` | Spot prices for underlying assets             |
| GET    | `/health`           | Vol surface and price feed health status      |

> Use `symbol` (singular) as the query parameter, not `symbols`.

### Symbol Format

```
{UNDERLYING}-{DDMMMYY}-{STRIKE}-{C|P}
```

| Part         | Description             | Examples                                                           |
| ------------ | ----------------------- | ------------------------------------------------------------------ |
| `UNDERLYING` | Asset symbol            | `HYPE`, `ETH`, `BTC`, `SOL`, `XPL`, `PUMP`, `ENA`, `KNTQ`, `kHYPE` |
| `DDMMMYY`    | Expiry date (08:00 UTC) | Use an available expiry date                                       |
| `STRIKE`     | Strike price in USD     | `25`, `3000`, `100000`                                             |
| `C\|P`       | Call or Put             | `C`, `P`                                                           |

**Build-your-own URL guide:**

1. Pick the base URL for your chain.
2. Pick your asset, an available expiry date, an available strike (query the subgraph or test via the API), and C or P.
3. Assemble: `https://market-api-sh.hypersurface.io/optionsPrices?symbol=HYPE-28MAR26-25-C`

Strikes are set on-chain. Query the subgraph or test via the API to confirm availability. `HYPE-28MAR26-25.50-C` is invalid if that strike does not exist.

> **Note:** To discover available expiry dates, query the subgraph for active oTokens:
>
> ```graphql
> {
>   otokens(first: 100, where: { expiryTimestamp_gt: "CURRENT_UNIX_TIMESTAMP" }) {
>     expiryTimestamp
>   }
> }
> ```
>
> Or try dates programmatically — the API returns an error for invalid expiries.

### GET /optionsPrices

```bash
curl "https://market-api-sh.hypersurface.io/optionsPrices?symbol=HYPE-28MAR26-25-C"
```

[Try it live](https://market-api-sh.hypersurface.io/optionsPrices?symbol=HYPE-28MAR26-25-C)

**Response:**

```json
{
  "result": {
    "HYPE-28MAR26-25-C": {
      "ask": 3.45,
      "bid": 2.81,
      "premium": 3.10,
      "probability_otm": 0.72
    }
  }
}
```

| Field             | Type  | Description                                         |
| ----------------- | ----- | --------------------------------------------------- |
| `ask`             | float | Ask price in USD (cost to buy back)                 |
| `bid`             | float | Bid price in USD (premium you receive when selling) |
| `premium`         | float | Mid/mark premium in USD                             |
| `probability_otm` | float | Probability of expiring out-of-the-money (0 to 1)   |

Add `&greeks=true` for delta, gamma, theta, vega, and implied volatility:

```bash
curl "https://market-api-sh.hypersurface.io/optionsPrices?symbol=HYPE-28MAR26-25-C&greeks=true"
```

[Try it live](https://market-api-sh.hypersurface.io/optionsPrices?symbol=HYPE-28MAR26-25-C\&greeks=true)

### POST /quote

`POST /quote` returns a co-signed order ready for on-chain execution.

**Covered call request:**

```bash
curl -X POST "https://market-api-sh.hypersurface.io/quote" \
  -H "Content-Type: application/json" \
  -d '{
    "sign": true,
    "order": {
      "account": "0xYourWalletAddress",
      "poolAddress": "0x0095aCDD705Cfcc11eAfFb6c19A28C0153ad196F",
      "underlying": "0x5555555555555555555555555555555555555555",
      "collateral": "0x5555555555555555555555555555555555555555",
      "referrer": "0x0000000000000000000000000000000000000000",
      "legs": [
        {
          "symbol": "HYPE-28MAR26-25-C",
          "amount": -100000000
        }
      ]
    }
  }'
```

**Request Fields:**

| Field                  | Type    | Required | Description                                                              |
| ---------------------- | ------- | -------- | ------------------------------------------------------------------------ |
| `sign`                 | boolean | Yes      | Must be `true` to receive a co-signed order                              |
| `order.account`        | address | Yes      | Your wallet address (EOA) or your contract address                       |
| `order.poolAddress`    | address | Yes      | HedgedPool address for the target chain                                  |
| `order.underlying`     | address | Yes      | Underlying token contract address                                        |
| `order.collateral`     | address | Yes      | Collateral token address (underlying for calls, stablecoin for puts)     |
| `order.referrer`       | address | Yes      | Referral address, or `0x0000000000000000000000000000000000000000`        |
| `order.legs[0].symbol` | string  | Yes      | Option symbol in `UNDERLYING-DDMMMYY-STRIKE-C/P` format                  |
| `order.legs[0].amount` | integer | Yes      | Quantity scaled by 1e8. Negative = sell to protocol, Positive = buy back |

> The `legs` array must contain exactly 1 element. Multi-leg trades are not supported.

**Response:**

```json
{
  "result": {
    "order": {
      "account": "0xYourWalletAddress",
      "poolAddress": "0x0095aCDD705Cfcc11eAfFb6c19A28C0153ad196F",
      "underlying": "0x5555555555555555555555555555555555555555",
      "collateral": "0x5555555555555555555555555555555555555555",
      "referrer": "0x0000000000000000000000000000000000000000",
      "validUntil": 1711612500,
      "nonce": "72800786012994460315784275982664160146348565358057253425559922099161226915767",
      "legs": [
        {
          "strike": "2500000000",
          "expiration": 1711612800,
          "isPut": false,
          "amount": "-100000000",
          "premium": "-3100000",
          "fee": "0"
        }
      ],
      "signature": { "r": "0x...", "s": "0x...", "v": "0x1b" },
      "coSignatures": []
    }
  }
}
```

**Response Fields:**

| Field        | Scale   | Description                                                             |
| ------------ | ------- | ----------------------------------------------------------------------- |
| `strike`     | 1e8     | Strike price. `"2500000000"` = $25.00                                   |
| `expiration` | unix    | Expiry timestamp (08:00 UTC)                                            |
| `isPut`      | boolean | `true` = put, `false` = call                                            |
| `amount`     | 1e8     | Signed quantity. `"-100000000"` = selling 1 option                      |
| `premium`    | 1e6     | Signed premium. `"-3100000"` = you receive $3.10                        |
| `fee`        | 1e6     | Protocol fee in premium token units                                     |
| `validUntil` | unix    | Quote expiry. Request a fresh quote immediately before your on-chain tx |
| `nonce`      | uint256 | Unique nonce for replay protection                                      |
| `signature`  | -       | Protocol's EIP-712 co-signature                                         |

**Put request** -- set `collateral` to the stablecoin address:

```json
{
  "sign": true,
  "order": {
    "account": "0xYourWalletAddress",
    "poolAddress": "0x0095aCDD705Cfcc11eAfFb6c19A28C0153ad196F",
    "underlying": "0x5555555555555555555555555555555555555555",
    "collateral": "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
    "referrer": "0x0000000000000000000000000000000000000000",
    "legs": [
      {
        "symbol": "HYPE-28MAR26-25-P",
        "amount": -100000000
      }
    ]
  }
}
```

### GET /health

```bash
curl "https://market-api-sh.hypersurface.io/health?symbol=HYPE"
```

[Try it live](https://market-api-sh.hypersurface.io/health?symbol=HYPE)

```json
{
  "HYPE": {
    "model": { "status": "OK", "timestamp": 1774634618 },
    "underlyingPrice": { "status": "OK", "timestamp": 1774634578 }
  },
  "currentTimestamp": 1774634622
}
```

> If a model or price feed status is not `"OK"`, pricing for that asset may be unavailable. Wait for recovery before trading.

### GET /underlyingPrices

```bash
curl "https://market-api-sh.hypersurface.io/underlyingPrices?symbol=HYPE&symbol=ETH&symbol=BTC"
```

[Try it live](https://market-api-sh.hypersurface.io/underlyingPrices?symbol=HYPE)

```json
{
  "result": {
    "HYPE": { "price": 38.21, "timestamp": 1774634639 },
    "ETH": { "price": 1978.00, "timestamp": 1774634639 },
    "BTC": { "price": 65666.93, "timestamp": 1774634639 }
  }
}
```

***

## EOA Trading Guide

Complete start-to-finish guide for wallet users. See the [Full Python Example](/integration-guide#full-example-python-trading-bot) for a copy-paste-ready version with all ABIs inline.

{% stepper %}
{% step %}

### Approval Targets

| Action                    | Token to Approve        | Approve To    | HyperEVM Address                             |
| ------------------------- | ----------------------- | ------------- | -------------------------------------------- |
| Sell covered call         | Underlying (e.g. wHYPE) | TradeExecutor | `0x25dD9EAae2e0b118a2CefdD229233654840BA7A0` |
| Sell cash-secured put     | Stablecoin (USD₮0)      | TradeExecutor | `0x25dD9EAae2e0b118a2CefdD229233654840BA7A0` |
| Buy back (close position) | Premium token (USD₮0)   | HedgedPool    | `0x0095aCDD705Cfcc11eAfFb6c19A28C0153ad196F` |

> Collateral approvals go to **TradeExecutor**. Buy-back premium approvals go to **HedgedPool**. Approving the wrong contract will revert your transaction.
> {% endstep %}

{% step %}

### Get a Signed Quote

```python
import requests
from web3 import Web3

API_URL = "https://market-api-sh.hypersurface.io"
HEDGED_POOL = "0x0095aCDD705Cfcc11eAfFb6c19A28C0153ad196F"
WHYPE = "0x5555555555555555555555555555555555555555"
TRADE_EXECUTOR = "0x25dD9EAae2e0b118a2CefdD229233654840BA7A0"
ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"

w3 = Web3(Web3.HTTPProvider("https://rpc.hyperliquid.xyz/evm"))
account = w3.eth.account.from_key("YOUR_PRIVATE_KEY")

quote_resp = requests.post(f"{API_URL}/quote", json={
    "sign": True,
    "order": {
        "account": account.address,
        "poolAddress": HEDGED_POOL,
        "underlying": WHYPE,
        "collateral": WHYPE,
        "referrer": ADDRESS_ZERO,
        "legs": [{"symbol": "HYPE-28MAR26-25-C", "amount": -100000000}],
    },
})
quote_resp.raise_for_status()
api_order = quote_resp.json()["result"]["order"]
```

{% endstep %}

{% step %}

### Approve Collateral

```python
ERC20_ABI = [
    {
        "inputs": [
            {"name": "spender", "type": "address"},
            {"name": "amount", "type": "uint256"},
        ],
        "name": "approve",
        "outputs": [{"name": "", "type": "bool"}],
        "stateMutability": "nonpayable",
        "type": "function",
    }
]

token = w3.eth.contract(address=Web3.to_checksum_address(WHYPE), abi=ERC20_ABI)

tx = token.functions.approve(
    Web3.to_checksum_address(TRADE_EXECUTOR),
    10 * 10**18,  # 10 wHYPE
).build_transaction({
    "from": account.address,
    "nonce": w3.eth.get_transaction_count(account.address),
    "chainId": 999,
})

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
w3.eth.wait_for_transaction_receipt(tx_hash)
```

{% endstep %}

{% step %}

### Execute Trade

`trade()` function signature:

```solidity
function trade(
    IOrderUtil.Order calldata order,
    uint256 traderVaultId,
    bool autoCreateVault
) external nonReentrant returns (address oToken);
```

> `trade()` returns the address of the oToken that was traded. An `eth_call` simulation returns it directly; from a sent transaction, read it from the emitted events.

| Parameter         | Type    | Description                                  |
| ----------------- | ------- | -------------------------------------------- |
| `order`           | Order   | Complete signed order from `/quote` response |
| `traderVaultId`   | uint256 | Your vault ID. Use `0` on first trade        |
| `autoCreateVault` | bool    | `true` on first trade to auto-create a vault |

```python
contract_order = format_order_for_contract(api_order)  # See Reference section

HEDGED_POOL_ABI = [
    {
        "inputs": [
            {
                "components": [
                    {"name": "account", "type": "address"},
                    {"name": "poolAddress", "type": "address"},
                    {"name": "underlying", "type": "address"},
                    {"name": "collateral", "type": "address"},
                    {"name": "referrer", "type": "address"},
                    {"name": "validUntil", "type": "uint256"},
                    {"name": "nonce", "type": "uint256"},
                    {
                        "name": "legs",
                        "type": "tuple[]",
                        "components": [
                            {"name": "strike", "type": "uint256"},
                            {"name": "expiration", "type": "uint256"},
                            {"name": "isPut", "type": "bool"},
                            {"name": "amount", "type": "int256"},
                            {"name": "premium", "type": "int256"},
                            {"name": "fee", "type": "uint256"},
                        ],
                    },
                    {
                        "name": "signature",
                        "type": "tuple",
                        "components": [
                            {"name": "v", "type": "uint8"},
                            {"name": "r", "type": "bytes32"},
                            {"name": "s", "type": "bytes32"},
                        ],
                    },
                    {
                        "name": "coSignatures",
                        "type": "tuple[]",
                        "components": [
                            {"name": "v", "type": "uint8"},
                            {"name": "r", "type": "bytes32"},
                            {"name": "s", "type": "bytes32"},
                        ],
                    },
                ],
                "name": "order",
                "type": "tuple",
            },
            {"name": "traderVaultId", "type": "uint256"},
            {"name": "autoCreateVault", "type": "bool"},
        ],
        "name": "trade",
        "outputs": [{"name": "", "type": "address"}],
        "stateMutability": "nonpayable",
        "type": "function",
    },
]

hedged_pool = w3.eth.contract(
    address=Web3.to_checksum_address(HEDGED_POOL),
    abi=HEDGED_POOL_ABI,
)

tx = hedged_pool.functions.trade(
    contract_order,
    0,     # traderVaultId (0 = auto-create)
    True,  # autoCreateVault
).build_transaction({
    "from": account.address,
    "nonce": w3.eth.get_transaction_count(account.address),
    "chainId": 999,
    "gas": 1_500_000,
})

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"Trade tx: {tx_hash.hex()}")
```

{% endstep %}

{% step %}

### Parse Vault ID from Receipt

```python
trade_executor = w3.eth.contract(
    address=Web3.to_checksum_address(TRADE_EXECUTOR),
    abi=[{
        "anonymous": False,
        "inputs": [
            {"indexed": True, "name": "trader", "type": "address"},
            {"indexed": False, "name": "vaultId", "type": "uint256"},
        ],
        "name": "MarginVaultOpened",
        "type": "event",
    }],
)
events = trade_executor.events.MarginVaultOpened().process_receipt(receipt)
vault_id = events[0]["args"]["vaultId"]
print(f"Vault ID: {vault_id}")
```

{% endstep %}

{% step %}

### Buy Back (Close Early)

Buy back your option using `trade()` with a **positive** amount. You pay the current premium to close, then withdraw your collateral.

**Approve HedgedPool for premium payment:**

```python
USDT0 = "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb"

premium_token = w3.eth.contract(
    address=Web3.to_checksum_address(USDT0), abi=ERC20_ABI,
)

tx = premium_token.functions.approve(
    Web3.to_checksum_address(HEDGED_POOL),
    100 * 10**6,  # 100 USD₮0
).build_transaction({
    "from": account.address,
    "nonce": w3.eth.get_transaction_count(account.address),
    "chainId": 999,
})

signed = account.sign_transaction(tx)
w3.eth.send_raw_transaction(signed.raw_transaction)
```

**Request a buy-back quote (positive amount):**

```python
quote_resp = requests.post(f"{API_URL}/quote", json={
    "sign": True,
    "order": {
        "account": account.address,
        "poolAddress": HEDGED_POOL,
        "underlying": WHYPE,
        "collateral": WHYPE,
        "referrer": ADDRESS_ZERO,
        "legs": [{"symbol": "HYPE-28MAR26-25-C", "amount": 100000000}],  # positive = buy back
    },
})
api_order = quote_resp.json()["result"]["order"]
contract_order = format_order_for_contract(api_order)
```

**Execute the buy-back:**

```python
tx = hedged_pool.functions.trade(
    contract_order,
    vault_id,  # your existing vault ID
    False,     # do NOT auto-create
).build_transaction({
    "from": account.address,
    "nonce": w3.eth.get_transaction_count(account.address),
    "chainId": 999,
    "gas": 500_000,
})

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
w3.eth.wait_for_transaction_receipt(tx_hash)
```

Then [withdraw your collateral](/integration-guide#9-withdraw-collateral).
{% endstep %}

{% step %}

### Settlement After Expiry

Options expire at 08:00 UTC on their expiry date. After expiry, you must settle your vault before you can withdraw collateral.

Settlement uses `Controller.operate()` with the `SettleVault` action type (7).

```python
CONTROLLER = "0x7730e6bfbfCE8Ff0b7a50b72D0601c209Eb818C4"
ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"

CONTROLLER_ABI = [
    {
        "inputs": [
            {
                "components": [
                    {"name": "actionType", "type": "uint8"},
                    {"name": "owner", "type": "address"},
                    {"name": "secondAddress", "type": "address"},
                    {"name": "asset", "type": "address"},
                    {"name": "vaultId", "type": "uint256"},
                    {"name": "amount", "type": "uint256"},
                    {"name": "index", "type": "uint256"},
                    {"name": "data", "type": "bytes"},
                ],
                "name": "actions",
                "type": "tuple[]",
            }
        ],
        "name": "operate",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function",
    }
]

controller = w3.eth.contract(
    address=Web3.to_checksum_address(CONTROLLER),
    abi=CONTROLLER_ABI,
)

# Settle one or more vaults in a single transaction
actions = [
    {
        "actionType": 7,  # SettleVault
        "owner": account.address,
        "secondAddress": account.address,  # payout destination
        "asset": Web3.to_checksum_address(ADDRESS_ZERO),
        "vaultId": vault_id,
        "amount": 0,
        "index": 0,
        "data": b"",
    }
    # Add more entries to batch-settle multiple vaults
]

tx = controller.functions.operate(actions).build_transaction({
    "from": account.address,
    "nonce": w3.eth.get_transaction_count(account.address),
    "chainId": 999,
})

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
w3.eth.wait_for_transaction_receipt(tx_hash)
```

{% endstep %}

{% step %}

### Settlement Payout

| Option Type      | Condition           | You Receive                                               |
| ---------------- | ------------------- | --------------------------------------------------------- |
| Covered Call     | OTM (spot < strike) | Your underlying collateral returned                       |
| Covered Call     | ITM (spot > strike) | Strike price in stablecoin (you delivered the underlying) |
| Cash-Secured Put | OTM (spot > strike) | Your stablecoin collateral returned                       |
| Cash-Secured Put | ITM (spot < strike) | Underlying asset (you bought at the strike price)         |
| {% endstep %}    |                     |                                                           |

{% step %}

### Withdraw Collateral

After settlement or a buy-back, withdraw collateral from your vault.

```python
# Read vault state to get collateral info
CONTROLLER_READ_ABI = [
    {
        "inputs": [
            {"name": "owner", "type": "address"},
            {"name": "vaultId", "type": "uint256"},
        ],
        "name": "getVault",
        "outputs": [
            {
                "components": [
                    {"name": "shortOtokens", "type": "address[]"},
                    {"name": "longOtokens", "type": "address[]"},
                    {"name": "collateralAssets", "type": "address[]"},
                    {"name": "shortAmounts", "type": "uint256[]"},
                    {"name": "longAmounts", "type": "uint256[]"},
                    {"name": "collateralAmounts", "type": "uint256[]"},
                ],
                "name": "vault",
                "type": "tuple",
            }
        ],
        "stateMutability": "view",
        "type": "function",
    }
]

controller = w3.eth.contract(
    address=Web3.to_checksum_address(CONTROLLER),
    abi=CONTROLLER_READ_ABI,
)

vault = controller.functions.getVault(account.address, vault_id).call()
collateral_asset = vault[2][0]   # collateralAssets[0]
collateral_amount = vault[5][0]  # collateralAmounts[0]

# Withdraw
WITHDRAW_ABI = [
    {
        "inputs": [
            {"name": "vaultId", "type": "uint256"},
            {"name": "collateralAsset", "type": "address"},
            {"name": "withdrawalAmount", "type": "uint256"},
        ],
        "name": "withdrawVaultCollateral",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function",
    }
]

pool = w3.eth.contract(
    address=Web3.to_checksum_address(HEDGED_POOL),
    abi=WITHDRAW_ABI,
)

tx = pool.functions.withdrawVaultCollateral(
    vault_id,
    collateral_asset,
    collateral_amount,
).build_transaction({
    "from": account.address,
    "nonce": w3.eth.get_transaction_count(account.address),
    "chainId": 999,
})

signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
w3.eth.wait_for_transaction_receipt(tx_hash)
```

{% endstep %}

{% step %}

### Position Tracking

**Get vault state:**

```solidity
Controller.getVault(address owner, uint256 vaultId) returns (Vault memory)
```

```solidity
struct Vault {
    address[] shortOtokens;
    address[] longOtokens;
    address[] collateralAssets;
    uint256[] shortAmounts;
    uint256[] longAmounts;
    uint256[] collateralAmounts;
}
```

All fields are arrays, but in practice each contains 0 or 1 element.

**Vault ID discovery:**

* **First trade:** Use `autoCreateVault=true` and parse `MarginVaultOpened` event from the receipt.
* **After the fact:** Call `Controller.getAccountVaultCounter(yourAddress)`. Vault IDs are sequential starting from 1.

**Vault status check:**

```python
import time

OTOKEN_ABI = [
    {
        "inputs": [],
        "name": "expiryTimestamp",
        "outputs": [{"type": "uint256"}],
        "stateMutability": "view",
        "type": "function",
    },
]

vault = controller.functions.getVault(account.address, vault_id).call()
has_short = len(vault[3]) > 0 and vault[3][0] > 0
has_collateral = any(a > 0 for a in vault[5])

if has_short:
    otoken = w3.eth.contract(address=vault[0][0], abi=OTOKEN_ABI)
    expiry = otoken.functions.expiryTimestamp().call()
    if expiry < int(time.time()):
        print("Expired -- needs settlement")
    else:
        print("Open position -- not yet expired")
elif has_collateral:
    print("Settled -- ready to withdraw collateral")
else:
    print("Fully settled and withdrawn")
```

{% endstep %}
{% endstepper %}

## Contract Integration Guide

Complete guide for smart contracts and vaults. See the [Full Solidity Example](/integration-guide#full-example-solidity-vault-contract) for a compilable contract with all interfaces inlined.

### How It Works

1. Your backend calls `POST /quote` with `account` = your contract address (the API co-signs the order for that address).
2. Your keeper/owner calls your contract, passing in the signed order.
3. Your contract calls `HedgedPool.trade(order, vaultId, autoCreateVault)`.
4. The TradeExecutor pulls collateral from `msg.sender` (your contract), not from the original caller.

> Your contract must hold the collateral tokens and have approved TradeExecutor before the trade call. The `/quote` API co-signs the order -- your contract does not need to produce its own signature.

### Setup (One-Time)

1. Your contract approves TradeExecutor to spend its collateral tokens.
2. Your contract calls `Controller.setOperator(hedgedPoolAddress, true)` so the protocol can manage vaults on its behalf.

### Trading from a Contract

```solidity
// Your contract calls this -- the order comes from your backend via /quote API
function executeTrade(
    IOrderUtil.Order calldata order,
    uint256 vaultId,
    bool autoCreateVault
) external onlyOwner {
    IHedgedPool(HEDGED_POOL).trade(order, vaultId, autoCreateVault);
}
```

### Buy Back from a Contract

Your backend gets a buy-back quote (positive amount) from `/quote`, and your contract forwards it to `HedgedPool.trade()`.

Your contract must have approved HedgedPool for the premium token (USD₮0 or USDC) before the buy-back call.

```solidity
function executeBuyBack(
    IOrderUtil.Order calldata order,
    uint256 vaultId
) external onlyOwner {
    IHedgedPool(HEDGED_POOL).trade(order, vaultId, false);
}
```

### Settlement from a Contract

Your contract calls `Controller.operate()` directly.

```solidity
function settleVault(uint256 vaultId) external onlyOwner {
    IController.ActionArgs[] memory actions = new IController.ActionArgs[](1);
    actions[0] = IController.ActionArgs(
        IController.ActionType.SettleVault,
        address(this),  // owner
        address(this),  // payout destination
        address(0),     // not used
        vaultId,
        0,              // not used
        0,              // not used
        ""              // not used
    );
    IController(CONTROLLER).operate(actions);
}
```

### Collateral Withdrawal from a Contract

```solidity
function withdrawCollateral(
    uint256 vaultId,
    address collateralAsset,
    uint256 amount
) external onlyOwner {
    IHedgedPool(HEDGED_POOL).withdrawVaultCollateral(vaultId, collateralAsset, amount);
}
```

***

## Auctions

The guide above covers selling options to the protocol. Hypersurface also runs **auctions**, where the protocol sells option inventory back to the market and any address can buy it.

The format is a Dutch auction priced in implied volatility: the offered price descends over a short window. A take is a single transaction: you pay premium in USDT0 and receive the oTokens. Access is permissionless, with no whitelist or sign-up. See [Auctions](/overview/auctions) for the user-facing overview.

### Integration paths

* **On-chain.** The `Auction` contract on HyperEVM is permissionless. Any address can read the current price and submit a take directly. The address is listed under [Contract Addresses](#contract-addresses).
* **API.** The same API that powers the auctions page is available to programmatic takers. The full auction API specification is provided on request while it is being finalized, and will be added to this guide after initial production use.

A take can revert even on a live auction. The most common case is `NoEligibleHolders`, which fires when the option series has no short holders to receive the surplus. Programmatic takers should simulate or handle reverts rather than assume a take always succeeds.

To request the auction API specification, or to discuss pricing and settlement, contact the team through [Community & Support](/references/community-and-support).

***

## Subgraph (Goldsky)

Public GraphQL endpoints, no authentication required.

| Chain    | Endpoint                                                                                                            |
| -------- | ------------------------------------------------------------------------------------------------------------------- |
| HyperEVM | `https://api.goldsky.com/api/public/project_clysuc3c7f21y01ub6hd66nmp/subgraphs/hypersurface-sh-subgraph/latest/gn` |

**Sample trades query (HyperEVM):**

```bash
curl -X POST \
  "https://api.goldsky.com/api/public/project_clysuc3c7f21y01ub6hd66nmp/subgraphs/hypersurface-sh-subgraph/latest/gn" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "{ trades(first: 10, orderBy: timestamp, orderDirection: desc) { id account totalPremium totalFee totalNotional underlyingPrice timestamp legs { oToken amount premium fee } } }"
  }'
```

***

## Reference

### Order Struct (Solidity)

These are the Solidity structs passed to `HedgedPool.trade()`. The `/quote` API returns these fields as JSON strings which you convert before submitting on-chain.

```solidity
struct Order {
    address account;            // Your wallet or contract address
    address poolAddress;        // HedgedPool address
    address underlying;         // Underlying token contract address
    address collateral;         // Collateral token contract address
    address referrer;           // Referral address (address(0) if none)
    uint256 validUntil;         // Unix timestamp -- order expires after this
    uint256 nonce;              // Unique nonce for replay protection
    OptionLeg[] legs;           // Must contain exactly 1 element
    Signature signature;        // Protocol's EIP-712 co-signature
    Signature[] coSignatures;   // Additional co-signer signatures (usually empty)
}

struct OptionLeg {
    uint256 strike;             // Strike price, 1e8 scaled ($25 = 2500000000)
    uint256 expiration;         // Expiry timestamp (08:00 UTC)
    bool isPut;                 // true = put, false = call
    int256 amount;              // Signed, 1e8 scaled. Negative = selling
    int256 premium;             // Signed, 1e6 scaled. Negative = you receive
    uint256 fee;                // Protocol fee, 1e6 scaled
}

struct Signature {
    uint8 v;
    bytes32 r;
    bytes32 s;
}
```

### Collateral Requirements

The contract automatically calculates and pulls collateral from `msg.sender` during `trade()`. You do not pass a collateral amount.

| Option Type      | Collateral Token              | Amount Required                        | Example                                                        |
| ---------------- | ----------------------------- | -------------------------------------- | -------------------------------------------------------------- |
| Covered Call     | Underlying asset (e.g. wHYPE) | 1:1 with option quantity               | Sell 1 HYPE call = deposit 1 wHYPE (1e18 units)                |
| Cash-Secured Put | Stablecoin (USD₮0 or USDC)    | Strike price x quantity, minus premium | Sell 1 put at $25 strike = deposit up to 25 USD₮0 (25e6 units) |

> For puts, the premium is netted against the collateral requirement. If you sell a $25 put and receive $3.10 premium, the protocol pulls approximately $21.90 from your wallet as collateral (the exact amount depends on the margin calculator).

### Decimal Conventions

| Data Type                             | Scale     | Example               | Meaning                    |
| ------------------------------------- | --------- | --------------------- | -------------------------- |
| Strike (on-chain)                     | 1e8       | `2500000000`          | $25.00                     |
| Premium (`/quote`)                    | 1e6       | `"-3100000"`          | -$3.10 (you receive $3.10) |
| Premium (`/optionsPrices`)            | float USD | `3.10`                | $3.10                      |
| Amount (quantity)                     | 1e8       | `-100000000`          | Sell 1 option              |
| HYPE / ETH / ENA / XPL / KNTQ / kHYPE | 1e18      | `1000000000000000000` | 1.0 token                  |
| BTC (UBTC)                            | 1e8       | `100000000`           | 1.0 BTC                    |
| SOL (USOL)                            | 1e9       | `1000000000`          | 1.0 SOL                    |
| PUMP (UPUMP)                          | 1e6       | `1000000`             | 1.0 PUMP                   |
| USD₮0 / USDC                          | 1e6       | `1000000`             | $1.00                      |

### On-Chain Errors

| Error                                    | Description                                               |
| ---------------------------------------- | --------------------------------------------------------- |
| `SignatureInvalid()`                     | Order signature verification failed                       |
| `NonceAlreadyUsed(uint256)`              | Nonce has already been consumed (stale quote)             |
| `TooCloseToExpiration()`                 | Trade rejected -- within 24h of expiry                    |
| `InventoryCapExceeded(uint256, uint256)` | Pool inventory cap reached. Args: (cap, inventoryBalance) |
| `InvalidOrder()`                         | Invalid amount/premium combination                        |
| `InvalidUnderlying()`                    | Underlying token not supported by the pool                |
| `InvalidPoolAddress()`                   | Order's poolAddress does not match the contract           |
| `InvalidAccount()`                       | `order.account` does not match `msg.sender`               |
| `Unauthorized()`                         | Signer is not a registered quote provider                 |
| `SeriesExpired()`                        | Option expiry is in the past                              |
| `InvalidLegsCount()`                     | `legs` array must contain exactly 1 element               |
| `InsufficientBalance()`                  | Insufficient token balance                                |
| `ZeroValue()`                            | Zero amount not allowed                                   |

### API Errors

| HTTP Code | Scenario           | Description                                           |
| --------- | ------------------ | ----------------------------------------------------- |
| 400       | Invalid symbol     | Symbol format is malformed or unrecognized            |
| 400       | Invalid parameters | Missing or incorrect query/body parameters            |
| 400       | Expired option     | The requested expiry date is in the past              |
| 400       | No oToken          | No oToken contract exists for this option series      |
| 403       | Access restricted  | The requested action is not permitted for this wallet |
| 404       | Asset not found    | The underlying asset is not supported on this chain   |
| 422       | ITM rejection      | Selling in-the-money options is not allowed           |
| 500       | Internal error     | API encountered an unexpected error                   |
| 503       | Unhealthy feed     | Vol surface or price feed is stale or unavailable     |

Error response format:

```json
{
  "error": {
    "code": 400,
    "message": "Invalid symbol format"
  }
}
```

### format\_order\_for\_contract() Python Helper

Converts the `/quote` API response into the format expected by `HedgedPool.trade()`.

```python
def format_order_for_contract(api_order: dict) -> dict:
    """
    Convert the /quote API response order into the format expected
    by HedgedPool.trade() on-chain.

    Key transformations:
    - KEEP 'account' field (it IS part of the Solidity struct)
    - Convert string numbers to int (strike, amount, premium, fee, nonce, validUntil)
    - Convert signature v from hex string to int, r/s from hex to bytes
    """
    legs = []
    for leg in api_order["legs"]:
        legs.append({
            "strike": int(leg["strike"]),
            "expiration": int(leg["expiration"]),
            "isPut": leg["isPut"],
            "amount": int(leg["amount"]),
            "premium": int(leg["premium"]),
            "fee": int(leg["fee"]),
        })

    signature = api_order.get("signature", {})
    formatted_sig = {
        "v": int(signature["v"], 16) if isinstance(signature["v"], str) else signature["v"],
        "r": bytes.fromhex(signature["r"][2:]) if isinstance(signature["r"], str) else signature["r"],
        "s": bytes.fromhex(signature["s"][2:]) if isinstance(signature["s"], str) else signature["s"],
    }

    co_sigs = []
    for cs in api_order.get("coSignatures", []):
        co_sigs.append({
            "v": int(cs["v"], 16) if isinstance(cs["v"], str) else cs["v"],
            "r": bytes.fromhex(cs["r"][2:]) if isinstance(cs["r"], str) else cs["r"],
            "s": bytes.fromhex(cs["s"][2:]) if isinstance(cs["s"], str) else cs["s"],
        })

    return {
        "account": api_order["account"],
        "poolAddress": api_order["poolAddress"],
        "underlying": api_order["underlying"],
        "collateral": api_order["collateral"],
        "referrer": api_order["referrer"],
        "validUntil": int(api_order["validUntil"]),
        "nonce": int(api_order["nonce"]),
        "legs": legs,
        "signature": formatted_sig,
        "coSignatures": co_sigs,
    }
```

### ActionArgs Struct

```solidity
struct ActionArgs {
    ActionType actionType;  // enum: 0=OpenVault, 6=WithdrawCollateral, 7=SettleVault, etc.
    address owner;          // vault owner address
    address secondAddress;  // payout destination
    address asset;          // not used for SettleVault (set to address(0))
    uint256 vaultId;        // vault to settle
    uint256 amount;         // not used for SettleVault (set to 0)
    uint256 index;          // not used for SettleVault (set to 0)
    bytes data;             // not used for SettleVault (set to empty)
}
```

**Action type reference:**

| Action             | Type | Purpose                          |
| ------------------ | ---- | -------------------------------- |
| OpenVault          | 0    | Open a new margin vault          |
| MintShortOption    | 1    | Mint (write) an option           |
| BurnShortOption    | 2    | Burn (close) an option           |
| DepositCollateral  | 5    | Deposit collateral into a vault  |
| WithdrawCollateral | 6    | Withdraw collateral from a vault |
| SettleVault        | 7    | Settle an expired vault          |
| Redeem             | 8    | Redeem expired long oTokens      |

## Full Example: Python Trading Bot

`HypersurfaceClient` class with all ABIs inline. `pip install web3 requests` then run.

```python
"""
Hypersurface Protocol -- Python Trading Bot
Covers: pricing, quoting, sell, buy-back, settlement, withdrawal.
Target: HyperEVM (Chain 999)

Dependencies:
    pip install web3 requests
"""

import time
import requests
from datetime import datetime, timezone
from web3 import Web3

# ── Configuration ─────────────────────────────────────────────────
HYPERSURFACE_API = "https://market-api-sh.hypersurface.io"
RPC_URL = "https://rpc.hyperliquid.xyz/evm"
CHAIN_ID = 999

HEDGED_POOL = "0x0095aCDD705Cfcc11eAfFb6c19A28C0153ad196F"
TRADE_EXECUTOR = "0x25dD9EAae2e0b118a2CefdD229233654840BA7A0"
CONTROLLER = "0x7730e6bfbfCE8Ff0b7a50b72D0601c209Eb818C4"
PREMIUM_TOKEN = "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb"  # USD₮0
ADDRESS_ZERO = "0x0000000000000000000000000000000000000000"

SETTLE_VAULT = 7

TOKENS = {
    "HYPE":  "0x5555555555555555555555555555555555555555",  # wHYPE, 18 decimals
    "BTC":   "0x9fdbda0a5e284c32744d2f17ee5c74b284993463",  # UBTC, 8 decimals
    "ETH":   "0xbe6727b535545c67d5caa73dea54865b92cf7907",  # UETH, 18 decimals
    "SOL":   "0x068f321fa8fb9f0d135f290ef6a3e2813e1c8a29",  # USOL, 9 decimals
    "XPL":   "0x33af3c2540ba72054e044efe504867b39ae421f5",  # UXPL, 18 decimals
    "PUMP":  "0x27ec642013bcb3d80ca3706599d3cda04f6f4452",  # UPUMP, 6 decimals
    "ENA":   "0x58538e6a46e07434d7e7375bc268d3cb839c0133",  # UENA, 18 decimals
    "KNTQ":  "0x000000000000780555bd0bca3791f89f9542c2d6",  # KNTQ, 18 decimals
    "kHYPE": "0xfd739d4e423301ce9385c1fb8850539d657c296d",  # kHYPE, 18 decimals
}

# ── ABIs ──────────────────────────────────────────────────────────

HEDGED_POOL_ABI = [
    {
        "inputs": [
            {
                "components": [
                    {"name": "account", "type": "address"},
                    {"name": "poolAddress", "type": "address"},
                    {"name": "underlying", "type": "address"},
                    {"name": "collateral", "type": "address"},
                    {"name": "referrer", "type": "address"},
                    {"name": "validUntil", "type": "uint256"},
                    {"name": "nonce", "type": "uint256"},
                    {
                        "name": "legs",
                        "type": "tuple[]",
                        "components": [
                            {"name": "strike", "type": "uint256"},
                            {"name": "expiration", "type": "uint256"},
                            {"name": "isPut", "type": "bool"},
                            {"name": "amount", "type": "int256"},
                            {"name": "premium", "type": "int256"},
                            {"name": "fee", "type": "uint256"},
                        ],
                    },
                    {
                        "name": "signature",
                        "type": "tuple",
                        "components": [
                            {"name": "v", "type": "uint8"},
                            {"name": "r", "type": "bytes32"},
                            {"name": "s", "type": "bytes32"},
                        ],
                    },
                    {
                        "name": "coSignatures",
                        "type": "tuple[]",
                        "components": [
                            {"name": "v", "type": "uint8"},
                            {"name": "r", "type": "bytes32"},
                            {"name": "s", "type": "bytes32"},
                        ],
                    },
                ],
                "name": "order",
                "type": "tuple",
            },
            {"name": "traderVaultId", "type": "uint256"},
            {"name": "autoCreateVault", "type": "bool"},
        ],
        "name": "trade",
        "outputs": [{"name": "", "type": "address"}],
        "stateMutability": "nonpayable",
        "type": "function",
    },
    {
        "inputs": [
            {"name": "vaultId", "type": "uint256"},
            {"name": "collateralAsset", "type": "address"},
            {"name": "withdrawalAmount", "type": "uint256"},
        ],
        "name": "withdrawVaultCollateral",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function",
    },
]

CONTROLLER_ABI = [
    {
        "inputs": [
            {
                "components": [
                    {"name": "actionType", "type": "uint8"},
                    {"name": "owner", "type": "address"},
                    {"name": "secondAddress", "type": "address"},
                    {"name": "asset", "type": "address"},
                    {"name": "vaultId", "type": "uint256"},
                    {"name": "amount", "type": "uint256"},
                    {"name": "index", "type": "uint256"},
                    {"name": "data", "type": "bytes"},
                ],
                "name": "actions",
                "type": "tuple[]",
            }
        ],
        "name": "operate",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function",
    },
    {
        "inputs": [
            {"name": "owner", "type": "address"},
            {"name": "vaultId", "type": "uint256"},
        ],
        "name": "getVault",
        "outputs": [
            {
                "components": [
                    {"name": "shortOtokens", "type": "address[]"},
                    {"name": "longOtokens", "type": "address[]"},
                    {"name": "collateralAssets", "type": "address[]"},
                    {"name": "shortAmounts", "type": "uint256[]"},
                    {"name": "longAmounts", "type": "uint256[]"},
                    {"name": "collateralAmounts", "type": "uint256[]"},
                ],
                "name": "vault",
                "type": "tuple",
            }
        ],
        "stateMutability": "view",
        "type": "function",
    },
    {
        "inputs": [{"name": "owner", "type": "address"}],
        "name": "getAccountVaultCounter",
        "outputs": [{"name": "", "type": "uint256"}],
        "stateMutability": "view",
        "type": "function",
    },
]

ERC20_ABI = [
    {
        "inputs": [
            {"name": "spender", "type": "address"},
            {"name": "amount", "type": "uint256"},
        ],
        "name": "approve",
        "outputs": [{"name": "", "type": "bool"}],
        "stateMutability": "nonpayable",
        "type": "function",
    },
    {
        "inputs": [
            {"name": "owner", "type": "address"},
            {"name": "spender", "type": "address"},
        ],
        "name": "allowance",
        "outputs": [{"name": "", "type": "uint256"}],
        "stateMutability": "view",
        "type": "function",
    },
    {
        "inputs": [{"name": "account", "type": "address"}],
        "name": "balanceOf",
        "outputs": [{"name": "", "type": "uint256"}],
        "stateMutability": "view",
        "type": "function",
    },
]

TRADE_EXECUTOR_ABI = [
    {
        "anonymous": False,
        "inputs": [
            {"indexed": True, "name": "trader", "type": "address"},
            {"indexed": False, "name": "vaultId", "type": "uint256"},
        ],
        "name": "MarginVaultOpened",
        "type": "event",
    },
]

OTOKEN_ABI = [
    {
        "inputs": [],
        "name": "expiryTimestamp",
        "outputs": [{"type": "uint256"}],
        "stateMutability": "view",
        "type": "function",
    },
]

# ── Helpers ───────────────────────────────────────────────────────

def format_expiry_code(expiry: datetime) -> str:
    """Format a supported expiry datetime as DDMMMYY. Expiries occur at 08:00 UTC."""
    return expiry.astimezone(timezone.utc).strftime("%d%b%y").upper()


def format_order_for_contract(api_order: dict) -> dict:
    """
    Convert /quote API response into the format expected by
    HedgedPool.trade() on-chain.
    """
    legs = []
    for leg in api_order["legs"]:
        legs.append(
            {
                "strike": int(leg["strike"]),
                "expiration": int(leg["expiration"]),
                "isPut": leg["isPut"],
                "amount": int(leg["amount"]),
                "premium": int(leg["premium"]),
                "fee": int(leg["fee"]),
            }
        )

    signature = api_order.get("signature", {})
    formatted_sig = {
        "v": int(signature["v"], 16)
        if isinstance(signature["v"], str)
        else signature["v"],
        "r": bytes.fromhex(signature["r"][2:])
        if isinstance(signature["r"], str)
        else signature["r"],
        "s": bytes.fromhex(signature["s"][2:])
        if isinstance(signature["s"], str)
        else signature["s"],
    }

    co_sigs = []
    for cs in api_order.get("coSignatures", []):
        co_sigs.append(
            {
                "v": int(cs["v"], 16)
                if isinstance(cs["v"], str)
                else cs["v"],
                "r": bytes.fromhex(cs["r"][2:])
                if isinstance(cs["r"], str)
                else cs["r"],
                "s": bytes.fromhex(cs["s"][2:])
                if isinstance(cs["s"], str)
                else cs["s"],
            }
        )

    return {
        "account": api_order["account"],
        "poolAddress": api_order["poolAddress"],
        "underlying": api_order["underlying"],
        "collateral": api_order["collateral"],
        "referrer": api_order["referrer"],
        "validUntil": int(api_order["validUntil"]),
        "nonce": int(api_order["nonce"]),
        "legs": legs,
        "signature": formatted_sig,
        "coSignatures": co_sigs,
    }


# ── Client Class ──────────────────────────────────────────────────

class HypersurfaceClient:
    """Full trade lifecycle client for Hypersurface Protocol on HyperEVM."""

    def __init__(self, private_key: str):
        self.w3 = Web3(Web3.HTTPProvider(RPC_URL))
        self.account = self.w3.eth.account.from_key(private_key)

        self.hedged_pool = self.w3.eth.contract(
            address=Web3.to_checksum_address(HEDGED_POOL),
            abi=HEDGED_POOL_ABI,
        )
        self.controller = self.w3.eth.contract(
            address=Web3.to_checksum_address(CONTROLLER),
            abi=CONTROLLER_ABI,
        )
        self.trade_executor = self.w3.eth.contract(
            address=Web3.to_checksum_address(TRADE_EXECUTOR),
            abi=TRADE_EXECUTOR_ABI,
        )

    # ── Pricing ───────────────────────────────────────────────────

    def get_option_price(self, symbol: str) -> dict:
        """Fetch option pricing. Returns dict with ask, bid, premium, probability_otm."""
        resp = requests.get(
            f"{HYPERSURFACE_API}/optionsPrices",
            params={"symbol": symbol},
        )
        resp.raise_for_status()
        return resp.json()["result"][symbol]

    def get_option_chain(
        self, underlying: str, expiry: str, strikes: list[float]
    ) -> list[dict]:
        """Scan calls and puts across multiple strikes for a given expiry."""
        chain = []
        for strike in strikes:
            strike_str = f"{strike:g}"
            for opt_type in ["C", "P"]:
                symbol = f"{underlying}-{expiry}-{strike_str}-{opt_type}"
                try:
                    price = self.get_option_price(symbol)
                    chain.append(
                        {
                            "symbol": symbol,
                            "ask": price["ask"],
                            "bid": price["bid"],
                            "premium": price["premium"],
                            "type": "call" if opt_type == "C" else "put",
                        }
                    )
                except requests.HTTPError:
                    continue
        return chain

    # ── Quoting ───────────────────────────────────────────────────

    def get_quote(
        self,
        symbol: str,
        amount: int,
        underlying: str,
        collateral: str,
        is_sell: bool,
    ) -> dict:
        """
        Request a signed quote from the API.

        Args:
            symbol: e.g. "HYPE-28MAR26-25-C"
            amount: Number of options (positive integer, e.g. 1)
            underlying: Underlying token address
            collateral: Collateral token address (underlying for calls, stablecoin for puts)
            is_sell: True to sell (open), False to buy back (close)
        """
        scaled_amount = amount * 100_000_000
        if is_sell:
            scaled_amount = -scaled_amount

        payload = {
            "sign": True,
            "order": {
                "account": self.account.address,
                "poolAddress": HEDGED_POOL,
                "underlying": Web3.to_checksum_address(underlying),
                "collateral": Web3.to_checksum_address(collateral),
                "referrer": ADDRESS_ZERO,
                "legs": [{"symbol": symbol, "amount": scaled_amount}],
            },
        }

        resp = requests.post(f"{HYPERSURFACE_API}/quote", json=payload)
        resp.raise_for_status()
        return resp.json()

    # ── Approvals ─────────────────────────────────────────────────

    def _ensure_allowance(self, token_address: str, spender: str, required: int):
        """Approve spender if current allowance is insufficient."""
        token = self.w3.eth.contract(
            address=Web3.to_checksum_address(token_address),
            abi=ERC20_ABI,
        )
        current = token.functions.allowance(
            self.account.address, Web3.to_checksum_address(spender)
        ).call()
        if current < required:
            tx = token.functions.approve(
                Web3.to_checksum_address(spender), 2**128
            ).build_transaction(
                {
                    "from": self.account.address,
                    "nonce": self.w3.eth.get_transaction_count(self.account.address),
                    "chainId": CHAIN_ID,
                }
            )
            signed = self.account.sign_transaction(tx)
            tx_hash = self.w3.eth.send_raw_transaction(signed.raw_transaction)
            self.w3.eth.wait_for_transaction_receipt(tx_hash)

    # ── Trade Execution ───────────────────────────────────────────

    def execute_trade(self, quote: dict, vault_id: int = 0) -> dict:
        """
        Execute a sell trade on-chain. Returns dict with tx_hash and vault_id.

        Args:
            quote: Full API response from get_quote()
            vault_id: Existing vault ID, or 0 to auto-create
        """
        api_order = quote["result"]["order"]
        auto_create = vault_id == 0

        # Approve TradeExecutor for collateral
        self._ensure_allowance(api_order["collateral"], TRADE_EXECUTOR, 2**128)

        contract_order = format_order_for_contract(api_order)

        tx = self.hedged_pool.functions.trade(
            contract_order, vault_id, auto_create
        ).build_transaction(
            {
                "from": self.account.address,
                "nonce": self.w3.eth.get_transaction_count(self.account.address),
                "chainId": CHAIN_ID,
                "gas": 1_500_000,
            }
        )

        signed = self.account.sign_transaction(tx)
        tx_hash = self.w3.eth.send_raw_transaction(signed.raw_transaction)
        receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)

        result_vault_id = vault_id
        if auto_create:
            events = self.trade_executor.events.MarginVaultOpened().process_receipt(
                receipt
            )
            if events:
                result_vault_id = events[0]["args"]["vaultId"]

        return {"tx_hash": tx_hash.hex(), "vault_id": result_vault_id}

    # ── Buy Back ──────────────────────────────────────────────────

    def buy_back(
        self,
        symbol: str,
        underlying: str,
        collateral: str,
        amount: int = 1,
        vault_id: int = 0,
    ) -> dict:
        """Buy back (close) an existing short position. Returns dict with tx_hash."""
        quote = self.get_quote(symbol, amount, underlying, collateral, is_sell=False)
        api_order = quote["result"]["order"]

        # Approve HedgedPool for premium token (buy-back costs premium)
        self._ensure_allowance(PREMIUM_TOKEN, HEDGED_POOL, 2**128)

        contract_order = format_order_for_contract(api_order)

        tx = self.hedged_pool.functions.trade(
            contract_order, vault_id, False
        ).build_transaction(
            {
                "from": self.account.address,
                "nonce": self.w3.eth.get_transaction_count(self.account.address),
                "chainId": CHAIN_ID,
                "gas": 500_000,
            }
        )

        signed = self.account.sign_transaction(tx)
        tx_hash = self.w3.eth.send_raw_transaction(signed.raw_transaction)
        self.w3.eth.wait_for_transaction_receipt(tx_hash)

        return {"tx_hash": tx_hash.hex()}

    # ── Vault Reads ───────────────────────────────────────────────

    def get_vault_state(self, vault_id: int) -> dict:
        """Read a vault's current state from the Controller."""
        vault = self.controller.functions.getVault(
            self.account.address, vault_id
        ).call()
        return {
            "short_otokens": vault[0],
            "long_otokens": vault[1],
            "collateral_assets": vault[2],
            "short_amounts": vault[3],
            "long_amounts": vault[4],
            "collateral_amounts": vault[5],
        }

    def get_vault_count(self) -> int:
        """Return the total number of vaults owned by this wallet."""
        return self.controller.functions.getAccountVaultCounter(
            self.account.address
        ).call()

    # ── Withdrawal ────────────────────────────────────────────────

    def withdraw_collateral(self, vault_id: int, asset: str, amount: int) -> str:
        """Withdraw collateral from a vault. Returns tx hash."""
        tx = self.hedged_pool.functions.withdrawVaultCollateral(
            vault_id,
            Web3.to_checksum_address(asset),
            amount,
        ).build_transaction(
            {
                "from": self.account.address,
                "nonce": self.w3.eth.get_transaction_count(self.account.address),
                "chainId": CHAIN_ID,
            }
        )

        signed = self.account.sign_transaction(tx)
        tx_hash = self.w3.eth.send_raw_transaction(signed.raw_transaction)
        self.w3.eth.wait_for_transaction_receipt(tx_hash)
        return tx_hash.hex()

    # ── Settlement ────────────────────────────────────────────────

    def settle_vaults(self, vault_ids: list[int]) -> str:
        """Settle one or more expired vaults. Returns tx hash."""
        actions = [
            {
                "actionType": SETTLE_VAULT,
                "owner": self.account.address,
                "secondAddress": self.account.address,
                "asset": Web3.to_checksum_address(ADDRESS_ZERO),
                "vaultId": vid,
                "amount": 0,
                "index": 0,
                "data": b"",
            }
            for vid in vault_ids
        ]

        tx = self.controller.functions.operate(actions).build_transaction(
            {
                "from": self.account.address,
                "nonce": self.w3.eth.get_transaction_count(self.account.address),
                "chainId": CHAIN_ID,
            }
        )

        signed = self.account.sign_transaction(tx)
        tx_hash = self.w3.eth.send_raw_transaction(signed.raw_transaction)
        self.w3.eth.wait_for_transaction_receipt(tx_hash)
        return tx_hash.hex()

    # ── Full Post-Expiry Sweep ────────────────────────────────────

    def settle_and_withdraw_all(self):
        """Find all vaults, settle expired ones, withdraw all available collateral."""
        vault_count = self.get_vault_count()
        print(f"You have {vault_count} vault(s)")

        expired_vaults = []
        withdrawable_vaults = []

        for vid in range(1, vault_count + 1):
            state = self.get_vault_state(vid)
            has_short = len(state["short_amounts"]) > 0 and state["short_amounts"][0] > 0
            has_collateral = any(a > 0 for a in state["collateral_amounts"])

            if has_short:
                otoken_addr = state["short_otokens"][0]
                otoken = self.w3.eth.contract(address=otoken_addr, abi=OTOKEN_ABI)
                expiry = otoken.functions.expiryTimestamp().call()
                if expiry < int(time.time()):
                    expired_vaults.append(vid)
                    print(f"  Vault {vid}: expired, needs settlement")
                else:
                    print(f"  Vault {vid}: still active (expires {expiry})")
            elif has_collateral:
                withdrawable_vaults.append((vid, state))
                print(f"  Vault {vid}: settled, ready to withdraw")
            else:
                print(f"  Vault {vid}: empty")

        # Step 1: Settle expired vaults in a single transaction
        if expired_vaults:
            print(f"\nSettling {len(expired_vaults)} vault(s)...")
            tx = self.settle_vaults(expired_vaults)
            print(f"Settlement tx: {tx}")

            for vid in expired_vaults:
                state = self.get_vault_state(vid)
                if any(a > 0 for a in state["collateral_amounts"]):
                    withdrawable_vaults.append((vid, state))

        # Step 2: Withdraw collateral from each vault
        for vid, state in withdrawable_vaults:
            for asset, amount in zip(
                state["collateral_assets"], state["collateral_amounts"]
            ):
                if amount > 0:
                    print(f"\nWithdrawing from vault {vid} (asset: {asset})...")
                    tx = self.withdraw_collateral(vid, asset, amount)
                    print(f"Withdrawal tx: {tx}")

        print("\nDone.")


# ── Usage ─────────────────────────────────────────────────────────

if __name__ == "__main__":
    client = HypersurfaceClient("YOUR_PRIVATE_KEY")

    # 1. Check prices
    price = client.get_option_price("HYPE-28MAR26-25-C")
    print(f"Ask: ${price['ask']:.2f}, Bid: ${price['bid']:.2f}")

    # 2. Scan an option chain
    chain = client.get_option_chain("HYPE", "28MAR26", [23, 24, 25, 26, 27])
    for opt in chain:
        print(f"  {opt['symbol']}: ask={opt['ask']:.4f}, bid={opt['bid']:.4f}")

    # 3. Get a quote for selling 1 covered call
    quote = client.get_quote(
        symbol="HYPE-28MAR26-25-C",
        amount=1,
        underlying=TOKENS["HYPE"],
        collateral=TOKENS["HYPE"],
        is_sell=True,
    )
    premium = quote["result"]["order"]["legs"][0]["premium"]
    print(f"Premium (1e6 scaled): {premium}")

    # 4. Execute the trade (uncomment when ready)
    # result = client.execute_trade(quote)
    # print(f"Trade tx: {result['tx_hash']}, Vault ID: {result['vault_id']}")

    # 5. Format a supported expiry date
    example_expiry = datetime(2026, 3, 28, 8, 0, tzinfo=timezone.utc)
    print("Example expiry code:", format_expiry_code(example_expiry))

    # 6. After expiry, settle and withdraw all
    # client.settle_and_withdraw_all()
```

***

## Full Example: Solidity Vault Contract

Solidity vault that trades options via Hypersurface. All interfaces inlined -- only needs OpenZeppelin.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.18; // Requires OpenZeppelin v4.x

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

// ── Interfaces (inlined) ─────────────────────────────────────────

interface IOrderUtil {
    struct Order {
        address account;
        address poolAddress;
        address underlying;
        address collateral;
        address referrer;
        uint256 validUntil;
        uint256 nonce;
        OptionLeg[] legs;
        Signature signature;
        Signature[] coSignatures;
    }

    struct OptionLeg {
        uint256 strike;
        uint256 expiration;
        bool isPut;
        int256 amount;
        int256 premium;
        uint256 fee;
    }

    struct Signature {
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    function cancel(uint256[] calldata nonces) external;
    function cancelUpTo(uint256 minimumNonce) external;
    function nonceUsed(address, uint256) external view returns (bool);
}

interface IHedgedPool {
    function trade(
        IOrderUtil.Order calldata order,
        uint256 traderVaultId,
        bool autoCreateVault
    ) external returns (address);

    function withdrawVaultCollateral(
        uint256 vaultId,
        address collateralAsset,
        uint256 withdrawalAmount
    ) external;
}

interface IController {
    enum ActionType {
        OpenVault,
        MintShortOption,
        BurnShortOption,
        DepositLongOption,
        WithdrawLongOption,
        DepositCollateral,
        WithdrawCollateral,
        SettleVault,
        Redeem,
        Call,
        Liquidate
    }

    struct ActionArgs {
        ActionType actionType;
        address owner;
        address secondAddress;
        address asset;
        uint256 vaultId;
        uint256 amount;
        uint256 index;
        bytes data;
    }

    function operate(ActionArgs[] calldata _actions) external;
    function getAccountVaultCounter(address owner) external view returns (uint256);
    function setOperator(address _operator, bool _isOperator) external;
}

// ── Vault Contract ───────────────────────────────────────────────

contract MinimalOptionsVault is Ownable {
    using SafeERC20 for IERC20;

    // HyperEVM addresses
    address public constant HEDGED_POOL = 0x0095aCDD705Cfcc11eAfFb6c19A28C0153ad196F;
    address public constant TRADE_EXECUTOR = 0x25dD9EAae2e0b118a2CefdD229233654840BA7A0;
    address public constant CONTROLLER = 0x7730e6bfbfCE8Ff0b7a50b72D0601c209Eb818C4;
    address public constant PREMIUM_TOKEN = 0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb;

    uint256 public currentVaultId;

    constructor() {
        // Allow HedgedPool to manage vaults on behalf of this contract
        IController(CONTROLLER).setOperator(HEDGED_POOL, true);
    }

    /// @notice Approve TradeExecutor to spend a collateral token (call once per token)
    function approveCollateral(address token, uint256 amount) external onlyOwner {
        IERC20(token).safeApprove(TRADE_EXECUTOR, amount);
    }

    /// @notice Approve HedgedPool to spend the premium token (for buy-backs)
    function approvePremium(uint256 amount) external onlyOwner {
        IERC20(PREMIUM_TOKEN).safeApprove(HEDGED_POOL, amount);
    }

    /// @notice Deposit collateral tokens into this contract
    function deposit(address token, uint256 amount) external onlyOwner {
        IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
    }

    /// @notice Execute a sell trade. The order comes from your backend via POST /quote.
    /// @param order The signed order from the Hypersurface API
    /// @param autoCreateVault True on the first trade to auto-create a margin vault
    function executeTrade(
        IOrderUtil.Order calldata order,
        bool autoCreateVault
    ) external onlyOwner {
        IHedgedPool(HEDGED_POOL).trade(order, currentVaultId, autoCreateVault);

        // On first trade, discover the vault ID
        if (autoCreateVault) {
            currentVaultId = IController(CONTROLLER).getAccountVaultCounter(address(this));
        }
    }

    /// @notice Buy back (close) a position before expiry
    function executeBuyBack(
        IOrderUtil.Order calldata order
    ) external onlyOwner {
        IHedgedPool(HEDGED_POOL).trade(order, currentVaultId, false);
    }

    /// @notice Settle an expired vault
    function settleVault(uint256 vaultId) external onlyOwner {
        IController.ActionArgs[] memory actions = new IController.ActionArgs[](1);
        actions[0] = IController.ActionArgs(
            IController.ActionType.SettleVault,
            address(this),  // owner
            address(this),  // payout destination
            address(0),
            vaultId,
            0,
            0,
            ""
        );
        IController(CONTROLLER).operate(actions);
    }

    /// @notice Withdraw collateral from a settled vault
    function withdrawCollateral(
        uint256 vaultId,
        address collateralAsset,
        uint256 amount
    ) external onlyOwner {
        IHedgedPool(HEDGED_POOL).withdrawVaultCollateral(vaultId, collateralAsset, amount);
    }

    /// @notice Withdraw any ERC-20 token from this contract to the owner
    function sweep(address token, uint256 amount) external onlyOwner {
        IERC20(token).safeTransfer(owner(), amount);
    }

    /// @notice Accept native currency
    receive() external payable {}
}
```

**Deployment and usage:**

1. Deploy `MinimalOptionsVault` on HyperEVM.
2. Call `approveCollateral(wHYPE_address, type(uint256).max)` for each collateral token.
3. Call `approvePremium(type(uint256).max)` for buy-backs.
4. Call `deposit(wHYPE_address, amount)` to fund the contract with collateral.
5. Your backend calls `POST /quote` with `account` = your contract address.
6. Call `executeTrade(order, true)` for the first trade, `executeTrade(order, false)` for subsequent trades into the same vault.
7. After expiry, call `settleVault(vaultId)`, then `withdrawCollateral(...)`, then `sweep(token, amount)`.


