diff --git a/apps/developer-hub/content/docs/express-relay/contract-addresses.mdx b/apps/developer-hub/content/docs/express-relay/contract-addresses.mdx
index eec914ec7e..17e9fc31fc 100644
--- a/apps/developer-hub/content/docs/express-relay/contract-addresses.mdx
+++ b/apps/developer-hub/content/docs/express-relay/contract-addresses.mdx
@@ -1,45 +1,54 @@
---
title: "SVM Contract Addresses"
description: >-
- Contract addresses and network details for Express Relay deployment on Solana Virtual Machine environments.
+ Express Relay is currently deployed on the following SVM environments:
---
-# SVM Contract Addresses
-
-Express Relay is currently deployed on the following SVM environments:
-
-## Production (Solana Mainnet-Beta)
-
-**Auction Server endpoint:** https://per-mainnet.dourolabs.app/
-
-| Name | Address/Value |
-| ------------------------ | --------------------------------------------------------------------------------------------------------------------- |
-| Express Relay Program | [PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou](https://solscan.io/account/PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou) |
-| Limo Limit Order Program | [LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF](https://solscan.io/account/LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF) |
-| Chain Id | solana |
-| Public RPC | https://api.mainnet-beta.solana.com |
-| Limo Global Order Config | [prod7Mog8r56sn5dPwze8nVdf94veEawdxNNqd5v7A1](https://solscan.io/account/prod7Mog8r56sn5dPwze8nVdf94veEawdxNNqd5v7A1) |
-| Frontend | https://swap.kamino.finance |
-
-## Testing (Solana Mainnet-Beta)
-
-> **Warning**: To simulate real performance conditions and activity, the staging/testing environment for Solana is on the mainnet-beta network. This environment is not for production use and should only be used for testing.
-
-**Auction Server endpoint:** https://per-staging.dourolabs.app/
-
-| Name | Address/Value |
-| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
-| Express Relay Program (Swaps) | [stag1NN9voD7436oFvKmy1kvRZYLLW8drKocSCt2W79](https://solscan.io/account/stag1NN9voD7436oFvKmy1kvRZYLLW8drKocSCt2W79) |
-| Express Relay Program (Limit Orders) | [PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou](https://solscan.io/account/PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou) |
-| Limo Limit Order Program | [LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF](https://solscan.io/account/LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF) |
-| Chain Id | development-solana |
-| Public RPC | https://api.mainnet-beta.solana.com |
-| Limo Global Order Config | [TeStcUQMmECYEtdeXo9cXpktQWaGe4bhJ7zxAUMzB2X](https://solscan.io/account/TeStcUQMmECYEtdeXo9cXpktQWaGe4bhJ7zxAUMzB2X) |
-| Testing Frontend | https://limo.kamino-webapp.pages.dev/swap |
-
-### Common Assets on development-solana
-
-| Asset | Address |
-| ----- | ----------------------------------------------------------------------------------------------------------------------- |
-| WSOL | [So11111111111111111111111111111111111111112](https://solscan.io/account/So11111111111111111111111111111111111111112) |
-| USDC | [EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v](https://solscan.io/account/EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v) |
+import CopyAddress from "../../../src/components/CopyAddress";
+
+
+
+
+**Auction Server endpoint:**
+
+**Network Details (Solana Mainnet-Beta):**
+| Name | Address/Value |
+| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Express Relay Program | |
+| Limo Limit Order Program | |
+| Chain Id | |
+| Public RPC | |
+| Limo Global Order Config | |
+| Frontend | |
+
+
+
+
+
+ To simulate real performance conditions and activity, the staging/testing
+ environment for Solana is on the mainnet-beta network. This environment is not
+ for production use and should only be used for testing.
+
+
+**Auction Server endpoint:**
+
+**Network Details (Solana Mainnet-Beta):**
+| Name | Address/Value |
+| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| Express Relay Program (Swaps) | |
+| Express Relay Program (Limit Orders) | |
+| Limo Limit Order Program | |
+| Chain Id | |
+| Public RPC | |
+| Limo Global Order Config | |
+| Testing Frontend | |
+
+\*\* This list contains the addresses of the commonly used assets present in opportunities on development-solana:
+
+| Asset | Address |
+| ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
+| WSOL | |
+| USDC | |
+
+
+
diff --git a/apps/developer-hub/content/docs/express-relay/errors.mdx b/apps/developer-hub/content/docs/express-relay/errors.mdx
index 2d4609c3ea..f4788ae683 100644
--- a/apps/developer-hub/content/docs/express-relay/errors.mdx
+++ b/apps/developer-hub/content/docs/express-relay/errors.mdx
@@ -1,204 +1,31 @@
---
-title: "Error Codes"
+title: "SVM Error Codes"
description: >-
Reference guide for Express Relay error codes and troubleshooting common issues.
---
-# Error Codes
-
-This page provides a reference for common error codes you may encounter when integrating with Express Relay, along with explanations and suggested solutions.
-
-## HTTP API Errors
-
-### 400 Bad Request
-
-**Invalid chain_id**
-
-- **Error:** Chain ID is not supported
-- **Solution:** Ensure you're using a supported chain ID (e.g., "solana", "development-solana")
-
-**Invalid transaction format**
-
-- **Error:** Transaction data is not properly encoded
-- **Solution:** Ensure transaction is base64 encoded and properly formatted
-
-**Missing required fields**
-
-- **Error:** Required fields are missing from the request
-- **Solution:** Check that all required parameters are included in your request
-
-### 401 Unauthorized
-
-**Invalid authentication**
-
-- **Error:** Authentication credentials are invalid or missing
-- **Solution:** Verify your API credentials and authentication headers
-
-### 404 Not Found
-
-**Opportunity not found**
-
-- **Error:** The requested opportunity does not exist
-- **Solution:** Check that the opportunity ID is correct and the opportunity hasn't expired
-
-### 429 Too Many Requests
-
-**Rate limit exceeded**
-
-- **Error:** Too many requests sent in a short time period
-- **Solution:** Implement exponential backoff and respect rate limits
-
-### 500 Internal Server Error
-
-**Server error**
-
-- **Error:** Internal server error occurred
-- **Solution:** Retry the request after a brief delay. If the issue persists, contact support
-
-## WebSocket Errors
-
-### Connection Errors
-
-**Connection failed**
-
-- **Error:** Unable to establish WebSocket connection
-- **Solution:** Check network connectivity and WebSocket endpoint URL
-
-**Authentication failed**
-
-- **Error:** WebSocket authentication failed
-- **Solution:** Verify authentication credentials for WebSocket connection
-
-### Subscription Errors
-
-**Invalid subscription**
-
-- **Error:** Subscription parameters are invalid
-- **Solution:** Check that chain_ids array contains valid chain identifiers
-
-**Subscription limit exceeded**
-
-- **Error:** Too many active subscriptions
-- **Solution:** Unsubscribe from unused chains before subscribing to new ones
-
-## Transaction Errors
-
-### Bid Submission Errors
-
-**Insufficient balance**
-
-- **Error:** Insufficient funds to cover bid amount
-- **Solution:** Ensure wallet has sufficient balance for the bid amount plus transaction fees
-
-**Invalid bid amount**
-
-- **Error:** Bid amount is below minimum or above maximum
-- **Solution:** Check bid amount constraints for the specific opportunity
-
-**Permission denied**
-
-- **Error:** Not authorized to submit bid for this opportunity
-- **Solution:** Verify permission key and ensure proper authorization
-
-### On-Chain Execution Errors
-
-**Transaction failed**
-
-- **Error:** Transaction execution failed on-chain
-- **Solution:** Check transaction logs for specific failure reasons
-
-**Transaction expired**
-
-- **Error:** Transaction expired before execution
-- **Solution:** Submit bids with sufficient time before deadline
-
-**Insufficient gas/compute**
-
-- **Error:** Transaction ran out of gas or compute units
-- **Solution:** Increase gas limit or compute unit allocation
-
-## SDK-Specific Errors
-
-### JavaScript SDK Errors
-
-**Network timeout**
-
-- **Error:** Request timed out
-- **Solution:** Increase timeout configuration or check network connectivity
-
-**Invalid configuration**
-
-- **Error:** SDK configuration is invalid
-- **Solution:** Verify baseUrl and other configuration parameters
-
-### Python SDK Errors
-
-**Connection error**
-
-- **Error:** Failed to connect to Express Relay server
-- **Solution:** Check network connectivity and server endpoint
-
-**Serialization error**
-
-- **Error:** Failed to serialize/deserialize data
-- **Solution:** Ensure data types match expected format
-
-## Troubleshooting Tips
-
-### General Guidelines
-
-1. **Check network connectivity** - Ensure your application can reach Express Relay endpoints
-2. **Verify parameters** - Double-check all request parameters for correct format and values
-3. **Monitor rate limits** - Implement proper rate limiting to avoid 429 errors
-4. **Handle timeouts** - Implement retry logic with exponential backoff
-5. **Check logs** - Review both client and server logs for detailed error information
-
-### Getting Help
-
-If you encounter persistent issues:
-
-1. Check the [API documentation](https://per-mainnet.dourolabs.app/docs) for detailed endpoint specifications
-2. Review example implementations in the SDK repositories
-3. Join the community Discord for support and discussion
-4. Contact technical support with detailed error information and reproduction steps
-
-### Common Patterns
-
-**Retry Logic Example**
-
-```typescript
-const maxRetries = 3;
-let retryCount = 0;
-
-while (retryCount < maxRetries) {
- try {
- const result = await client.submitBid(bid);
- return result;
- } catch (error) {
- retryCount++;
- if (retryCount === maxRetries) {
- throw error;
- }
- await new Promise((resolve) => setTimeout(resolve, 1000 * retryCount));
- }
-}
-```
-
-**Error Handling Example**
-
-```typescript
-try {
- const opportunities = await client.getOpportunities();
-} catch (error) {
- if (error.status === 429) {
- // Rate limited - wait and retry
- await new Promise((resolve) => setTimeout(resolve, 5000));
- } else if (error.status === 500) {
- // Server error - log and alert
- console.error("Server error:", error);
- } else {
- // Other errors - handle appropriately
- console.error("Request failed:", error);
- }
-}
-```
+The following table lists the error codes and their explanations for the ExpressRelay programs. They can be used to identify the cause of a failed transaction or bid.
+
+## ExpressRelay
+
+| Error Code | Name | Description |
+| ---------- | ---------------------------------- | ---------------------------------------------------------- |
+| 6000 | `InvalidPermissionPda` | The permission PDA is invalid |
+| 6001 | `InvalidPermissionKeypair` | The permission keypair is invalid |
+| 6002 | `InvalidRouter` | The router is invalid |
+| 6003 | `DeadlineExceeded` | The bid deadline has been exceeded |
+| 6004 | `InsufficientFee` | The fee is insufficient |
+| 6005 | `InvalidChainId` | The chain ID is invalid |
+| 6006 | `InvalidFeeReceiver` | The fee receiver is invalid |
+| 6007 | `InvalidFeePayer` | The fee payer is invalid |
+| 6008 | `InvalidRelayerSigner` | The relayer signer is invalid |
+| 6009 | `RouterExecutionFailed` | Router execution failed |
+| 6010 | `BidAmountTooLow` | The bid amount is too low |
+| 6011 | `InvalidBidAmount` | The bid amount is invalid |
+| 6012 | `PermissionAccountNotWritable` | The permission account is not writable |
+| 6013 | `InvalidDestination` | The destination is invalid |
+| 6014 | `InvalidMetadata` | The metadata is invalid |
+| 6015 | `InvalidConfigPda` | The config PDA is invalid |
+| 6016 | `InvalidAdmin` | The admin is invalid |
+| 6017 | `FeeSplitOutOfRange` | The fee split is out of range |
+| 6018 | `MaxBidAmountLessThanMinBidAmount` | The maximum bid amount is less than the minimum bid amount |
diff --git a/apps/developer-hub/content/docs/express-relay/how-express-relay-works/auction.mdx b/apps/developer-hub/content/docs/express-relay/how-express-relay-works/auction.mdx
index 942892365a..28449fb783 100644
--- a/apps/developer-hub/content/docs/express-relay/how-express-relay-works/auction.mdx
+++ b/apps/developer-hub/content/docs/express-relay/how-express-relay-works/auction.mdx
@@ -1,29 +1,25 @@
---
-title: "Auction Mechanism"
+title: "Auction"
description: >-
Learn how Express Relay's off-chain auction determines winning bids and maximizes revenue sharing with integrated protocols.
---
-# Auction
-
The auction in Express Relay is held off-chain at the auction server.
-Bids arrive at the auction server and compete against other bids, vying for the same [permission key](./permissioning).
+Bids arrive at the auction server and compete against other bids, vying for the same [permission key](permissioning).
A relayer selected by governance serves as the auctioneer and determines the auction in line with the criterion of maximizing the revenue shared back to the protocol that generated this opportunity. That means the auctioneer is expected to forward on-chain the subset of bids that maximizes the revenue back to the protocol.
Thus, the Express Relay auction is analogous to a sealed-bid auction, i.e., participants in the auction will not have the contents of their bid disclosed publicly unless they win the auction and are forwarded on-chain.
-The forwarded subset of transactions is submitted on-chain and first processed by the [`ExpressRelay`](https://github.com/pyth-network/per/blob/fccac65b00cff1cfe5c278b333a582fe66bda0f8/contracts/evm/src/express-relay/ExpressRelay.sol) contract before individual searchers' submissions are routed to their corresponding **targetContracts**.
+The forwarded subset of transactions is submitted on-chain and first processed by the [`ExpressRelay`](https://github.com/pyth-network/per/blob/fccac65b00cff1cfe5c278b333a582fe66bda0f8/contracts/evm/src/express-relay/ExpressRelay.sol) contract before individual searchers' submissions are routed to their corresponding `targetContract`s.
-Generally, the auction server expects bids to execute successfully on-chain. Fallback bids are also forwarded in case of execution failures for the predicted winners.
+Generally, the auction server expects bids to execute successfully on-chain. Falback bids are also forwarded in case of execution failures for the predicted winners.
-The **ExpressRelay** contract extracts the payment of the specified bid amount only if the searcher's bid is successfully executed on-chain.
+The `ExpressRelay` contract extracts the payment of the specified bid amount only if the searcher's bid is successfully executed on-chain.
Hence, the Express Relay auction can be seen as a generalization of a [first-price sealed-bid auction](https://en.wikipedia.org/wiki/First-price_sealed-bid_auction), in that multiple bids can win and pay their first price.
-## Revenue Sharing
-
The revenue from the auction is shared amongst relevant stakeholders in the Express Relay system. These stakeholders include:
-- **The protocol** that generates the relevant opportunity
-- **The relayer**, which handles running the off-chain components of the system
+- the protocol that generates the relevant opportunity
+- the relayer, which handles running the off-chain components of the system
-> **ℹ️ Revenue Distribution**: The Express Relay contract enforces the exact revenue splits and is subject to change based on governance decisions.
+The Express Relay contract enforces the exact revenue splits and is subject to change based on governance decisions.
diff --git a/apps/developer-hub/content/docs/express-relay/how-express-relay-works/index.mdx b/apps/developer-hub/content/docs/express-relay/how-express-relay-works/index.mdx
index 101f148b73..fb632ad642 100644
--- a/apps/developer-hub/content/docs/express-relay/how-express-relay-works/index.mdx
+++ b/apps/developer-hub/content/docs/express-relay/how-express-relay-works/index.mdx
@@ -4,134 +4,43 @@ description: >-
Understand how Express Relay eliminates MEV through off-chain auctions and priority mechanisms for protocol operations.
---
-import { IntegrationCard } from "../../../../src/components/IntegrationCard";
-import { Gavel, Lightning, Shield } from "@phosphor-icons/react/dist/ssr";
-
-# How Express Relay Works
-
-Express Relay is a protocol that allows applications to auction off the right to execute on-chain operations. This protocol allows protocols to eliminate MEV by capturing the value that would otherwise go to validators and sharing it with the protocol's users.
-
-Express Relay consists of two components:
-
-1. **An off-chain auction server** that auctions off the right to execute protocol operations
-2. **An on-chain smart contract** that validates auction results and executes the winning transactions
-
-## The MEV Problem
-
-Many DeFi protocols generate [Maximal Extractable Value](https://www.ledger.com/academy/glossary/maximal-extractable-value-mev) (MEV) on a regular basis. For example, lending protocols provide bonuses to searchers for liquidating undercollateralized loans. Searchers compete for these bonuses by tipping validators to include their transactions first.
-
-The problem with this approach is that validators capture most of the MEV value through these tips, creating a wealth transfer from protocol users to validators.
-
-## The Express Relay Solution
-
-Express Relay solves this problem by moving the auction off-chain, where protocols can capture the MEV and share it with their users.
-
-Here's how it works:
-
-1. **Protocol Integration**: Protocols integrate with Express Relay by wrapping their valuable operations (like liquidations) with permission checks
-2. **Opportunity Detection**: When opportunities arise, they're broadcast to searchers through the Express Relay auction server
-3. **Off-chain Auction**: Searchers submit bids for the right to execute these operations
-4. **On-chain Execution**: The auction server relays winning bids to the Express Relay smart contract, which validates permissions and executes the operations
-5. **Revenue Sharing**: The smart contract collects payments from searchers and distributes them according to predefined splits
-
-### Before Express Relay
-
-Searchers tip miners/validators to guarantee transaction execution, with validators capturing most of the MEV value.
-
-### After Express Relay
-
-Searchers bid in off-chain auctions, with auction profits shared between integrated protocols and Express Relay participants.
-
-The comparison above shows how Express Relay changes the MEV landscape for a liquidation.
+Express Relay allows protocols to eliminate [Maximal Extractable Value](https://www.ledger.com/academy/glossary/maximal-extractable-value-mev) (MEV).
+Many protocols generate MEV on a regular basis.
+For example, borrow-lending protocols provide bonuses to searchers for liquidating undercollateralized loans.
+Searchers compete for these bonuses by tipping the chain's miners or validators.
+The validators capture most of the value of the liquidation bonus via these tips, so the liquidation bonus is in essence a transfer of wealth from the protocol's users to the validators in the form of tips.
+
+Express Relay solves the problem of MEV by providing protocol developers with an [auction](./how-express-relay-works/auction) primitive that they can use to prioritize access to valuable protocol operations.
+Developers specify a set of operations in their protocol that must be accessed through Express Relay.
+Searchers then participate in an off-chain auction to access these operations.
+Their bids in the auction are used to determine the order in which their transactions will be executed.
+The winners' transactions are forwarded to the Express Relay smart contract. As part of the transaction, searchers must pay their specified bid.
+The auction profits are then split between the integrated protocol and other participants in Express Relay.
+
+
+
+
+The diagram above shows how Express Relay changes the MEV landscape for a liquidation.
In the status quo (above), Searchers tip miners to guarantee that their liquidation transaction lands on-chain and that their transaction directly interacts with the protocol, exposing the liquidation opportunity.
With Express Relay (below), Searchers submit bids for their transaction to the Express Relay auction.
After the auction, the winning bids are relayed to the blockchain, where the Express Relay smart contract processes the transactions before being forwarded on to the integrated protocol.
The Express Relay contract collects payment from the Searchers and forwards a share of the revenue back to the integrated protocol.
-## Key Components
-
-### Off-chain Auction Server
-
-The auction server receives bids from searchers and determines winners based on bid amounts and other criteria. It then submits winning transactions to the blockchain in the optimal order.
-
-### On-chain Smart Contract
-
-The Express Relay smart contract validates that transactions have won the auction and enforces payment collection. It also handles revenue distribution between protocols and other stakeholders.
-
-### Permission System
-
-Express Relay uses a permission system to ensure only auction winners can execute protected operations. This prevents frontrunning and ensures MEV capture.
-
-## Benefits for Protocols
-
-Express Relay offers several advantages for protocol developers:
-
-- **MEV Recapture**: Convert MEV from validator tips into protocol revenue
-- **Reliable Execution**: Access to a dedicated network of professional searchers
-- **Reduced Complexity**: No need to build custom liquidation infrastructure
-- **Better UX**: Faster execution and lower gas costs for users
-
-## Benefits for Searchers
-
-Express Relay also provides advantages for searchers:
-
-- **Unified Access**: Single integration point for multiple protocols
-- **Fair Competition**: Transparent auction mechanism
-- **Reduced Costs**: Lower gas costs through batch execution
-- **New Opportunities**: Access to exclusive protocol operations
-
## Which protocols can use Express Relay?
-Express Relay is suitable for any protocol with valuable, time-sensitive operations:
-
-- **Lending Protocols**: Liquidations of undercollateralized positions
-- **Perpetual Protocols**: Liquidations and funding rate updates
-- **DEX Protocols**: Arbitrage opportunities and order book operations
-- **Derivatives Protocols**: Option exercises and settlement operations
-- **Cross-chain Protocols**: Bridge operations and relay transactions
-
-## Integration Requirements
-
-To integrate with Express Relay, protocols need to:
+Any protocol with valuable operations can use Express Relay.
+These operations generate MEV, as the validators control which searchers have the right to access them.
+Express Relay enables protocols to auction access instead of the validators.
+Lending, perps, and derivatives protocols with liquidation mechanisms are clear candidates that can benefit from integration with Express Relay.
-1. **Identify Valuable Operations**: Determine which operations generate MEV
-2. **Add Permission Checks**: Wrap operations with Express Relay permission validation
-3. **Deploy Integration**: Update smart contracts with Express Relay integration
-4. **Configure Revenue Sharing**: Set up distribution of auction proceeds
+Aside from eliminating MEV, protocols that need a stable set of searchers would benefit from using Express Relay.
+Express Relay provides access to a robust network of searchers who are already active in the Express Relay ecosystem.
## Participants in Express Relay
There are four types of participants in the Express Relay protocol:
-- **The Relayer** runs the off-chain auction and forwards winning transactions onto the blockchain.
-- **Protocol developers** integrate their protocol with Express Relay in order to eliminate MEV and gain access to searchers.
-- **Searchers** participate in auctions to access on-chain opportunities such as liquidations.
-- **The Pyth DAO** owns and governs the Express Relay system.
-
-## Learn More
-
-
- }
- />
-
-}
-/>
-
- }
- />
-
+- The Relayer runs the off-chain auction and forwards winning transactions onto the blockchain.
+- Protocol developers integrate their protocol with Express Relay in order to eliminate MEV and gain access to searchers.
+- Searchers participate in auctions to access on-chain opportunities such as liquidations.
+- The Pyth DAO owns and governs the Express Relay system.
diff --git a/apps/developer-hub/content/docs/express-relay/how-express-relay-works/opportunities.mdx b/apps/developer-hub/content/docs/express-relay/how-express-relay-works/opportunities.mdx
index 2f2e51e378..5c5556dece 100644
--- a/apps/developer-hub/content/docs/express-relay/how-express-relay-works/opportunities.mdx
+++ b/apps/developer-hub/content/docs/express-relay/how-express-relay-works/opportunities.mdx
@@ -18,28 +18,28 @@ Opportunities do not refer to only transactions that use an oracle. In truth, an
Examples of opportunities include:
-- **Liquidations** - Undercollateralized positions in lending protocols
-- **Open trade offers** - Limit orders waiting to be filled
-- **NFT mints** - Limited supply token drops
-- **Top-of-block DEX arbitrage** - Price discrepancies between exchanges
+- liquidations
+- open trade offers
+- NFT mints
+- top-of-block DEX arbitrage
## Opportunity Adapter
-The Opportunity Adapter contract enables searchers to engage with opportunities from different protocols without needing to do any bespoke integration work per protocol. Instead of exposing lower-level fields determined by protocols (e.g. amountCollateral, addressBorrower), the Opportunity Adapter abstracts away the semantics of the opportunity and instead [exposes the fundamental traits](https://github.com/pyth-network/per/blob/30c3fc695034f518225f8255ebe8423604e8aca3/contracts/src/opportunity-adapter/Structs.sol#L20-L23) of any opportunity:
+The Opportunity Adapter contract enables searchers to engage with opportunities from different protocols without needing to do any bespoke integration work per protocol. Instead of exposing lower-level fields determined by protocols (e.g. `amountCollateral`, `addressBorrower`), the Opportunity Adapter abstracts away the semantics of the opportunity and instead [exposes the fundamental traits](https://github.com/pyth-network/per/blob/30c3fc695034f518225f8255ebe8423604e8aca3/contracts/src/opportunity-adapter/Structs.sol#L20-L23) of any opportunity:
-- The tokens sold by the searcher
-- The tokens bought by the searcher
-- The identity of the searcher executing this opportunity
-- The contract to call and the calldata and value to call with
-- The user's bid
+- the tokens sold by the searcher
+- the tokens bought by the searcher
+- the identity of the searcher executing this opportunity
+- the contract to call and the calldata and value to call with
+- the user's bid
Thus, the Opportunity Adapter unifies the disparate interfaces of different protocols with respect to their different opportunities. This unification in a single interface is what makes Express Relay an opportunity hub connecting protocols and searchers.
-To use the Opportunity Adapter workflow, a searcher submits a bid with the target contract set to the **OpportunityAdapterFactory** contract. The factory contract then routes the searcher's transaction to their respective **OpportunityAdapter** contract. Each searcher has their own **OpportunityAdapter** contract per chain that is automatically created for them when they first interact with **OpportunityAdapterFactory**.
+To use the Opportunity Adapter workflow, a searcher submits a bid with the target contract set to the `OpportunityAdapterFactory` contract. The factory contract then routes the searcher's transaction to their respective `OpportunityAdapter` contract. Each searcher has their own `OpportunityAdapter` contract per chain that is automatically created for them when they first interact with `OpportunityAdapterFactory`.
### Permit2
-The **OpportunityAdapter** contract uses the [Permit2](https://github.com/Uniswap/permit2) token approval system, which handles the validation of a searcher's signature. Permit2 enables users to authorize token approvals for specific transaction data. In combination with Permit2, **OpportunityAdapter** allows a searcher to authorize use of their tokens only with a call to a particular contract with specified calldata and conditional on receipt of a set of specified **buyTokens**.
+The `OpportunityAdapter` contract uses the [Permit2](https://github.com/Uniswap/permit2) token approval system, which handles the validation of a searcher's signature. Permit2 enables users to authorize token approvals for specific transaction data. In combination with Permit2, `OpportunityAdapter` allows a searcher to authorize use of their tokens only with a call to a particular contract with specified calldata and conditional on receipt of a set of specified `buyTokens`.
## Opportunity Server
@@ -47,13 +47,8 @@ Once on-chain opportunities arise, searchers can be notified of their existence
In addition to learning about present opportunities, searchers can also query the opportunity server for data about historical opportunities.
-### Before Express Relay
-
-Each searcher must connect to every new protocol with a custom integration, creating integration overhead and friction.
-
-### After Express Relay
-
-Searchers integrate once with Express Relay to access all current and future integrated protocols.
+
+
The diagrams above illustrate the difference between the nature of integrations pre- and post-Express Relay. In the status quo, each searcher must connect to every new protocol with a custom integration. Similarly, protocols have to court and incentivize individual searchers. This creates a lot of integration overhead and friction for both parties.
diff --git a/apps/developer-hub/content/docs/express-relay/how-express-relay-works/permissioning.mdx b/apps/developer-hub/content/docs/express-relay/how-express-relay-works/permissioning.mdx
index 4c4c772462..b2b9887766 100644
--- a/apps/developer-hub/content/docs/express-relay/how-express-relay-works/permissioning.mdx
+++ b/apps/developer-hub/content/docs/express-relay/how-express-relay-works/permissioning.mdx
@@ -4,41 +4,29 @@ description: >-
Learn how Express Relay uses permission IDs and keys to manage access control and distinguish between different opportunities.
---
-# Permissioning
-
-**permissionId** is a **bytes** object that represents the unique identifier of a position within the protocol. **permissionId** allows the system to distinguish between bids competing on different opportunities and thereby run more scoped and efficient auctions.
+`permissionId` is a `bytes` object that represents the unique identifier of a position within the protocol. `permissionId` allows the system to distinguish between bids competing on different opportunities and thereby run more scoped and efficient auctions.
Each borrower has a unique position for some protocols, so the borrower address uniquely identifies a position.
-In other protocols, each borrower might have multiple positions, distinguished by the address of the collateral asset or by a **uint256** ID number.
+In other protocols, each borrower might have multiple positions, distinguished by the address of the collateral asset or by a `uint256` ID number.
In those cases, the information set that uniquely identifies a position would include multiple fields.
-**permissionId** can be the concatenation of all these fields in bytes format. You can call **abi.encode()** to concatenate these fields together.
-
-## Examples
-
-### Single Position Per Borrower
+`permissionId` can be the concatenation of all these fields in bytes format. You can call `abi.encode(){:solidity}` to concatenate these fields together.
-For example, if a protocol featured a unique position per borrower, then it could form **permissionId** as:
+For example, if a protocol featured a unique position per borrower, then it could form `permissionId` as
```solidity
bytes memory permissionId = abi.encode(borrowerAddress);
```
-### Multiple Positions Per Borrower
-
-On the other hand, if a protocol allowed a borrower to open as many new positions as they wanted, denoted by an identifier **uint256 positionId**, then it could form **permissionId** as:
+On the other hand, if a protocol allowed a borrower to open as many new positions as they wanted, denoted by an identifier `uint256 positionId{:solidity}`, then it could form `permissionId` as
```solidity
bytes memory permissionId = abi.encode(borrowerAddress, positionId);
```
-## Permission Key
-
-The Express Relay contract uses the **permissionId** to toggle permissions for interacting with the protocol.
-This toggling is checked within the protocol's code to ensure that the current transaction is within the context of Express Relay so that the recaptured value can be returned to the protocol. In particular, the Express Relay contract checks the toggling of the **permissionKey**, which is the concatenation of the protocol address and the **permissionId**:
+The Express Relay contract uses the `permissionId` to toggle permissions for interacting with the protocol.
+This toggling is checked within the protocol's code to ensure that the current transaction is within the context of Express Relay so that the recaptured value can be returned to the protocol. In particular, the Express Relay contract checks the toggling of the `permissionKey`, which is the concatenation of the protocol address and the `permissionId`:
```solidity
bytes memory permissionKey = abi.encode(protocolAddress, permissionId);
```
-
-> **ℹ️ Access Control**: The permission key system ensures that only Express Relay can grant access to protocol operations, enabling MEV recapture and proper revenue sharing.
diff --git a/apps/developer-hub/content/docs/express-relay/http-api-reference.mdx b/apps/developer-hub/content/docs/express-relay/http-api-reference.mdx
index 46996a6950..c9a9eccf39 100644
--- a/apps/developer-hub/content/docs/express-relay/http-api-reference.mdx
+++ b/apps/developer-hub/content/docs/express-relay/http-api-reference.mdx
@@ -4,18 +4,10 @@ description: >-
Complete HTTP API reference for Express Relay endpoints, including opportunities, bids, and configuration.
---
-# HTTP API Reference
-
-Express Relay provides a comprehensive HTTP API for interacting with the protocol. The API allows you to fetch opportunities, submit bids, and access configuration data.
-
## Interactive API Documentation
The complete HTTP API reference is available as an interactive Swagger/OpenAPI documentation:
-### 🌐 Live API Documentation
-
-_Interactive API explorer with live examples_
-
**Production (Mainnet):**
[https://per-mainnet.dourolabs.app/docs](https://per-mainnet.dourolabs.app/docs)
@@ -28,98 +20,3 @@ Use the appropriate base URL for your environment:
- **Production (Mainnet):** https://per-mainnet.dourolabs.app
- **Staging (Testing):** https://per-staging.dourolabs.app
-
-## Key Endpoints
-
-### Opportunities
-
-**GET /v1/opportunities**
-
-- Retrieve available opportunities for bidding
-- Query parameters: chain_id, mode (live/historical)
-- Returns: Array of opportunity objects
-
-**Example:**
-
-```bash
-curl "https://per-mainnet.dourolabs.app/v1/opportunities?chain_id=solana&mode=live"
-```
-
-### Bids
-
-**POST /v1/bids**
-
-- Submit a bid for an opportunity
-- Request body: JSON with chain_id and transaction (base64 encoded)
-- Returns: Bid status and ID
-
-**Example:**
-
-```bash
-curl -X POST "https://per-mainnet.dourolabs.app/v1/bids" \
- -H "Content-Type: application/json" \
- -d '{
- "chain_id": "solana",
- "transaction": "SGVsbG8sIFdvcmxkIQ=="
- }'
-```
-
-### Configuration
-
-**GET /v1/chains**
-
-- Get supported chains and their configurations
-- Returns: Array of supported chain configurations
-
-### WebSocket
-
-**WS /v1/ws**
-
-- Real-time WebSocket connection for opportunities and bid updates
-- See [WebSocket API Reference](./websocket-api-reference) for details
-
-## Authentication
-
-Most Express Relay endpoints are public and don't require authentication. However, some advanced features may require API keys or signed requests.
-
-## Rate Limits
-
-Express Relay implements rate limiting to ensure fair usage:
-
-- Standard endpoints: 100 requests per minute
-- WebSocket connections: 10 concurrent connections per IP
-- Bid submissions: 1000 bids per minute
-
-## Error Handling
-
-All API endpoints return standard HTTP status codes:
-
-- **200** - Success
-- **400** - Bad Request (invalid parameters)
-- **429** - Rate Limit Exceeded
-- **500** - Internal Server Error
-
-Error responses include detailed error messages in JSON format. See the [Error Codes](./errors) page for specific error scenarios and solutions.
-
-## SDKs
-
-Instead of calling the HTTP API directly, consider using the official SDKs:
-
-- **TypeScript/JavaScript:** [@pythnetwork/express-relay-js](https://www.npmjs.com/package/@pythnetwork/express-relay-js)
-- **Python:** Available in the [Express Relay GitHub repository](https://github.com/pyth-network/per/tree/main/sdk/python)
-
-## Examples
-
-For complete integration examples, see:
-
-- [Integrate as a Protocol](./integrate-as-protocol) - Frontend integration guide
-- [Integrate as a Searcher](./integrate-as-searcher) - Searcher integration guide
-
-## Support
-
-If you encounter issues with the API:
-
-1. Check the [Error Codes](./errors) page for common issues
-2. Review the interactive API documentation for parameter requirements
-3. Join the Pyth Discord for community support
-4. Contact technical support for persistent issues
diff --git a/apps/developer-hub/content/docs/express-relay/images/after_express.jpg b/apps/developer-hub/content/docs/express-relay/images/after_express.jpg
new file mode 100644
index 0000000000..1481dee035
Binary files /dev/null and b/apps/developer-hub/content/docs/express-relay/images/after_express.jpg differ
diff --git a/apps/developer-hub/content/docs/express-relay/images/after_searcher.jpg b/apps/developer-hub/content/docs/express-relay/images/after_searcher.jpg
new file mode 100644
index 0000000000..a376598686
Binary files /dev/null and b/apps/developer-hub/content/docs/express-relay/images/after_searcher.jpg differ
diff --git a/apps/developer-hub/content/docs/express-relay/images/before_express.jpg b/apps/developer-hub/content/docs/express-relay/images/before_express.jpg
new file mode 100644
index 0000000000..9db37f9e5a
Binary files /dev/null and b/apps/developer-hub/content/docs/express-relay/images/before_express.jpg differ
diff --git a/apps/developer-hub/content/docs/express-relay/images/before_searcher.jpg b/apps/developer-hub/content/docs/express-relay/images/before_searcher.jpg
new file mode 100644
index 0000000000..46a9024acd
Binary files /dev/null and b/apps/developer-hub/content/docs/express-relay/images/before_searcher.jpg differ
diff --git a/apps/developer-hub/content/docs/express-relay/integrate-as-protocol.mdx b/apps/developer-hub/content/docs/express-relay/integrate-as-protocol.mdx
index afeac17216..278e1098ce 100644
--- a/apps/developer-hub/content/docs/express-relay/integrate-as-protocol.mdx
+++ b/apps/developer-hub/content/docs/express-relay/integrate-as-protocol.mdx
@@ -1,13 +1,9 @@
---
-title: "Integrate as a Protocol"
+title: "How to Integrate Express Relay Swaps"
description: >-
- Learn how frontends can integrate Express Relay to empower token swapping with better pricing and MEV recapture.
+ This guide will explain how frontends can integrate Express Relay to empower swapping.
---
-# How to Integrate Express Relay Swaps
-
-This guide will explain how frontends can integrate Express Relay to empower swapping.
-
## Step 1: Install the Express Relay SDK
Pyth provides a [Typescript SDK](https://www.npmjs.com/package/@pythnetwork/express-relay-js) to help developers integrate Express Relay into their frontends.
@@ -46,7 +42,7 @@ const quoteRequest = {
const quote = await client.getQuote(quoteRequest);
```
-**quote** contains the full details, including the amount the searcher is quoting and the transaction that the user needs to sign. It also contains an **expirationTime**; after this time, the transaction will no longer succeed on chain, so you should request a new quote a few seconds before the **expirationTime**.
+_quote_ contains the full details, including the amount the searcher is quoting and the transaction that the user needs to sign. It also contains an _expirationTime_; after this time, the transaction will no longer succeed on chain, so you should request a new quote a few seconds before the _expirationTime_.
## Step 3: Submit User Signature to the Express Relay Server
diff --git a/apps/developer-hub/content/docs/express-relay/integrate-as-searcher/index.mdx b/apps/developer-hub/content/docs/express-relay/integrate-as-searcher/index.mdx
index 136ef6385f..9772cf7447 100644
--- a/apps/developer-hub/content/docs/express-relay/integrate-as-searcher/index.mdx
+++ b/apps/developer-hub/content/docs/express-relay/integrate-as-searcher/index.mdx
@@ -1,26 +1,12 @@
---
-title: "Integrate as a Searcher"
+title: "How to Integrate Express Relay as a Searcher"
description: >-
- Integrate once and access all existing and future opportunities across integrated DeFi protocols through Express Relay's bidding system.
+ Express Relay allows searchers to integrate once and access all existing and future opportunities across integrated DeFi protocols. Searchers bid on these opportunities exposed by Express Relay.
---
import { IntegrationCard } from "../../../../src/components/IntegrationCard";
import { Code } from "@phosphor-icons/react/dist/ssr";
-# How to Integrate Express Relay as a Searcher
-
-Express Relay allows searchers to integrate once and access all existing and future opportunities across integrated DeFi protocols. Searchers **bid** on these opportunities exposed by Express Relay.
-
-Express Relay exposes different endpoints for interaction, which can be used directly via HTTP, WebSocket, or one of the SDKs for convenience.
-
-## What is a Searcher?
-
-Searchers are sophisticated actors who monitor blockchain networks for profitable opportunities such as arbitrage, liquidations, and MEV extraction. With Express Relay, searchers can:
-
-- **Access unified opportunities** across multiple integrated DeFi protocols
-- **Compete in fair auctions** for the right to fulfill user transactions
-- **Capture value** while providing better execution for users
-
## Integration Methods
Express Relay provides multiple ways for searchers to integrate:
@@ -61,14 +47,8 @@ If your bid wins the auction, execute the opportunity by:
- **Capturing the bid amount** as compensation for providing the service
- **Ensuring proper execution** to maintain reputation in the system
-## Supported Chains
-
-Searchers can currently integrate with Express Relay on **Solana Virtual Machine (SVM)** chains, with support for additional chains coming soon.
-
## Getting Started
-Ready to integrate as a searcher? Start with our detailed integration guides:
-
}
/>
-
-## Additional Resources
-
-Explore these resources to enhance your searcher integration:
-
-### API Documentation
-
-- **[WebSocket API Reference](/express-relay/websocket-api-reference)** - Real-time opportunity streaming
-- **[HTTP API Reference](/express-relay/http-api-reference)** - REST endpoints for opportunities and bidding
-
-### Technical Resources
-
-- **[Contract Addresses](/express-relay/contract-addresses)** - Smart contract addresses across supported chains
-- **[Error Codes](/express-relay/errors)** - Complete list of error codes and troubleshooting guide
-
-### Understanding Express Relay
-
-- **[How Express Relay Works](/express-relay/how-express-relay-works)** - Deep dive into the auction mechanism and architecture
diff --git a/apps/developer-hub/content/docs/express-relay/integrate-as-searcher/svm.mdx b/apps/developer-hub/content/docs/express-relay/integrate-as-searcher/svm.mdx
index ce6c2e5021..a706985115 100644
--- a/apps/developer-hub/content/docs/express-relay/integrate-as-searcher/svm.mdx
+++ b/apps/developer-hub/content/docs/express-relay/integrate-as-searcher/svm.mdx
@@ -4,15 +4,14 @@ description: >-
Learn how to integrate Express Relay as a searcher on Solana Virtual Machine chains to fulfill market orders and limit orders.
---
-# SVM Searcher Integration
-
SVM Express Relay searchers fulfill market order opportunities as well as limit orders on the [Limo](https://solscan.io/account/LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF) program.
## Step 1: Subscribe to New Opportunities
Express Relay provides searchers with [Typescript](https://github.com/pyth-network/per/tree/358eedc1f9072cdfc3418fba309697580f2474f9/sdk/js) and [Python](https://github.com/pyth-network/per/tree/358eedc1f9072cdfc3418fba309697580f2474f9/sdk/python) SDKs to interact with Express Relay. Searchers can also directly fetch available opportunities via HTTP or subscribe to them via WebSocket.
-### Typescript SDK
+
+
Pyth provides a Typescript SDK, which allows searchers to subscribe to opportunities:
@@ -37,7 +36,20 @@ async function main() {
main();
```
-### Python SDK
+The server responds with opportunities in the following format:
+
+```json
+{
+ "order": "UxMUbQAsjrfQUp5stVwMJ6Mucq7VWTvt4ICe69BJ8lVXqwM+0sysV8OqZTdM0W4p...", // The Limo order to be executed, encoded in base64
+ "order_address": "DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5", // Address of the order account
+ "program": "limo", // Identifier of the program that the order exists in
+ "chain_id": "development-solana",
+ "version": "v1" // Opportunity format version
+}
+```
+
+
+
Pyth provides a Python SDK, which allows searchers to subscribe to opportunities:
@@ -68,7 +80,20 @@ if __name__ == "__main__":
asyncio.run(main())
```
-### HTTP API
+The server responds with opportunities in the following format:
+
+```json
+{
+ "order": "UxMUbQAsjrfQUp5stVwMJ6Mucq7VWTvt4ICe69BJ8lVXqwM+0sysV8OqZTdM0W4p...", // The Limo order to be executed, encoded in base64
+ "order_address": "DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5", // Address of the order account
+ "program": "limo", // Identifier of the program that the order exists in
+ "chain_id": "development-solana",
+ "version": "v1" // Opportunity format version
+}
+```
+
+
+
Searchers can request opportunities through an HTTP **GET** call to the [/v1/opportunities](https://per-mainnet.dourolabs.app/docs#tag/opportunity/operation/get_opportunities) endpoint.
@@ -79,7 +104,20 @@ curl -X 'GET' \
Opportunities are short-lived and could be executed in a matter of seconds. So, the above endpoint could return an empty response.
-### WebSocket API
+The server responds with opportunities in the following format:
+
+```json
+{
+ "order": "UxMUbQAsjrfQUp5stVwMJ6Mucq7VWTvt4ICe69BJ8lVXqwM+0sysV8OqZTdM0W4p...", // The Limo order to be executed, encoded in base64
+ "order_address": "DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5", // Address of the order account
+ "program": "limo", // Identifier of the program that the order exists in
+ "chain_id": "development-solana",
+ "version": "v1" // Opportunity format version
+}
+```
+
+
+
Searchers can connect to the server via WebSocket to reduce latency and subscribe to various events. The WebSocket endpoint lives at `/v1/ws` (e.g `wss://per-mainnet.dourolabs.app/v1/ws`). Here is a sample JSON payload to subscribe to opportunities:
@@ -107,17 +145,22 @@ The server responds with opportunities in the following format:
}
```
+
+
+
## Step 2: Construct the Bid
Searchers should construct a bid by evaluating the fetched opportunity.
-> **Warning**: Before constructing the bid, make sure your wallet has the required assets to fulfill the limit order and SOL to pay the bid amount.
+> ⚠️ **Warning**
+> Before constructing the bid, make sure your wallet has the required assets to fulfill the limit order and SOL to pay the bid amount.
See the following examples of how to construct a bid object via the SDKs:
-### Typescript SDK
+
+
-Below is an excerpt of example code. See the full example in the [Typescript SDK](https://github.com/pyth-network/per/blob/4be711525948cf24c0ebd4ebab007dc7f51b7069/sdk/js/src/examples/simpleSearcherLimo.ts).
+Below is an excerpt of example code. See the full example in the [Typescript SDK](https://github.com/pyth-network/per/blob/main/sdk/js/src/examples/simpleSearcherLimo.ts).
```typescript
import { OpportunitySvm } from "../index";
@@ -127,11 +170,11 @@ import * as anchor from "@coral-xyz/anchor";
import * as limo from "@kamino-finance/limo-sdk";
/**
- * Generates a bid for a given opportunity.
- * The transaction in this bid transfers assets from the searcher's wallet to fulfill the limit order.
- * @param opportunity The SVM opportunity to bid on.
- * @returns The generated bid object.
- */
+ * Generates a bid for a given opportunity.
+ * The transaction in this bid transfers assets from the searcher's wallet to fulfill the limit order.
+ * @param opportunity The SVM opportunity to bid on.
+ * @returns The generated bid object.
+ */
async generateBid(opportunity: OpportunitySvm): Promise {
const order = opportunity.order;
const limoClient = new limo.LimoClient(
@@ -139,74 +182,165 @@ async generateBid(opportunity: OpportunitySvm): Promise {
order.state.globalConfig
);
- const { bid: bidAmountLamports, transaction } = await this.fulfillLimoOrder(
- limoClient,
- order,
- this.searcherKeypair,
- this.bidAmountLamports
+ const ixsTakeOrder = await this.generateTakeOrderIxs(limoClient, order);
+ const feeInstruction = ComputeBudgetProgram.setComputeUnitPrice({
+ microLamports:
+ this.latestChainUpdate[this.chainId].latestPrioritizationFee,
+ });
+ const txRaw = new anchor.web3.Transaction().add(
+ feeInstruction,
+ ...ixsTakeOrder
+ );
+
+ const bidAmount = await this.getBidAmount(order);
+
+ const config = await this.getExpressRelayConfig();
+ const bid = await this.client.constructSvmBid(
+ txRaw,
+ this.searcher.publicKey,
+ getPdaAuthority(limoClient.getProgramID(), order.state.globalConfig),
+ order.address,
+ bidAmount,
+ new anchor.BN(Math.round(Date.now() / 1000 + DAY_IN_SECONDS)),
+ this.chainId,
+ config.relayerSigner,
+ config.feeReceiverRelayer
);
- return {
- amount: bidAmountLamports.toString(),
- transaction: transaction,
- valid_until: this.getValidUntil(),
- };
+ bid.transaction.recentBlockhash =
+ this.latestChainUpdate[this.chainId].blockhash;
+ bid.transaction.sign(this.searcher);
+ return bid;
}
```
-### Python SDK
+The bid you construct will look like
+
+```
+{
+ // serialized transaction object, in base-64 encoding
+ "transaction": "SGVsbG8sIFdvcmxkIQ==",
+ "chain_id": "solana",
+ "env": "svm"
+}
+```
+
+where the serialized transaction object should contain an Express Relay SubmitBid instruction that specifies the amount you are bidding and the permission details.
+
+
+
Below is an excerpt of example code. See the full example in the [Python SDK](https://github.com/pyth-network/per/blob/4be711525948cf24c0ebd4ebab007dc7f51b7069/sdk/python/express_relay/examples/simple_searcher_limo.py).
```python
-import asyncio
-from typing import Dict, Any
+import logging
+
+from solders.transaction import Transaction
+
+from express_relay.models.svm import BidSvm
+from express_relay.svm.limo_client import OrderStateAndAddress
-from solders.keypair import Keypair # type: ignore
-from solders.transaction import VersionedTransaction # type: ignore
+DEADLINE = 2**62
+logger = logging.getLogger(__name__)
-async def construct_bid(self, opportunity: Dict[str, Any]) -> Dict[str, Any]:
+async def generate_bid(self, opp: OpportunitySvm) -> BidSvm:
"""
- Constructs a bid for the given opportunity.
+ Generates a bid for a given opportunity.
+ The transaction in this bid transfers assets from the searcher's wallet to fulfill the limit order.
+
+ Args:
+ opp: The SVM opportunity to bid on.
+ Returns:
+ The generated bid object.
"""
- order = opportunity["order"]
- order_address = opportunity["order_address"]
+ order: OrderStateAndAddress = {"address": opp.order_address, "state": opp.order}
- # Calculate bid amount and construct fulfillment transaction
- bid_amount, transaction = await self.fulfill_limo_order(
- order, order_address, self.searcher_keypair, self.bid_amount_lamports
+ ixs_take_order = await self.generate_take_order_ixs(order)
+ bid_amount = await self.get_bid_amount(order)
+ router = self.limo_client.get_pda_authority(
+ self.limo_client.get_program_id(), order["state"].global_config
)
- return {
- "amount": str(bid_amount),
- "transaction": transaction,
- "valid_until": self.get_valid_until(),
- }
+ submit_bid_ix = self.client.get_svm_submit_bid_instruction(
+ searcher=self.private_key.pubkey(),
+ router=router,
+ permission_key=order["address"],
+ bid_amount=bid_amount,
+ deadline=DEADLINE,
+ chain_id=self.chain_id,
+ fee_receiver_relayer=(await self.get_metadata()).fee_receiver_relayer,
+ relayer_signer=(await self.get_metadata()).relayer_signer,
+ )
+ latest_chain_update = self.latest_chain_update[self.chain_id]
+ fee_instruction = set_compute_unit_price(latest_chain_update.latest_prioritization_fee)
+ transaction = Transaction.new_with_payer(
+ [fee_instruction, submit_bid_ix] + ixs_take_order, self.private_key.pubkey()
+ )
+ transaction.partial_sign(
+ [self.private_key], recent_blockhash=latest_chain_update.blockhash
+ )
+ bid = BidSvm(transaction=transaction, chain_id=self.chain_id)
+ return bid
```
-## Step 3: Submit the Bid
+The bid you construct will look like
-After constructing the bid, searchers should submit it to Express Relay to participate in the auction.
+```
+{
+ // serialized transaction object, in base-64 encoding
+ "transaction": "SGVsbG8sIFdvcmxkIQ==",
+ "chain_id": "solana",
+ "env": "svm"
+}
+
+```
-### Typescript SDK
+where the serialized transaction object should contain an Express Relay SubmitBid instruction that specifies the amount you are bidding and the permission details.
+
+
+
+
+## Step 3: Submit Bids on Opportunities to Express Relay
+
+Searchers can submit their constructed bids to Express Relay via the SDKs, an HTTP POST request, or a WebSocket connection.
+
+
+
+
+The code snippet below demonstrates how to submit a bid using the Typescript SDK:
```typescript
-// Submit the bid to Express Relay
-const bidResponse = await client.submitBid(bid);
-console.log("Bid submitted:", bidResponse);
+const generateBid = async (opportunity: OpportunitySvm, recentBlockhash: Blockhash): BidSvm => {
+ ...
+}
+
+const handleOpportunity = async (opportunity: Opportunity) => {
+ ...
+ const bid = await this.generateBid(opportunity as OpportunitySvm);
+ await client.submitBid(bid);
+}
```
-### Python SDK
+
+
+
+The code snippet below demonstrates how to submit a bid using the Python SDK:
```python
-# Submit the bid to Express Relay
-bid_response = await client.submit_bid(bid)
-print(f"Bid submitted: {bid_response}")
+import typing
+
+async def generate_bid(opp: OpportunitySvm) -> BidSvm:
+ ...
+
+def opportunity_callback(opportunity: Opportunity):
+ bid = await self.assess_opportunity(typing.cast(OpportunitySvm, opp))
+ await client.submit_bid(bid, subscribe_to_updates=True)
```
-### HTTP API
+
+
-Searchers can submit bids through an HTTP **POST** call to the [/v1/bids](https://per-mainnet.dourolabs.app/docs#tag/bid/operation/post_bid) endpoint.
+Searchers can submit bids through an HTTP **POST** call to the [/v1/bids](https://per-mainnet.dourolabs.app/docs#tag/bid/operation/post_bid) endpoint. This endpoint accepts a JSON payload containing the details of the bid.
```bash
curl -X 'POST' \
@@ -214,92 +348,44 @@ curl -X 'POST' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
- "amount": "1000000",
- "transaction": "...",
"chain_id": "solana",
- "valid_until": "2024-05-30T13:23:00.000Z"
+ "transaction": "SGVsbG8sIFdvcmxkIQ=="
}'
-```
-
-## Step 4: Monitor Bid Results
-
-After submitting a bid, searchers should monitor whether their bid was accepted and the transaction was successfully executed.
-
-### Winning Bids
-
-If your bid wins the auction, Express Relay will execute your transaction on-chain. You can monitor the transaction status through:
-
-- **Transaction hash** returned in the bid response
-- **WebSocket notifications** for bid status updates
-- **HTTP polling** of bid status endpoints
-### Failed Bids
-
-If your bid is not selected or execution fails, you'll receive appropriate error notifications. Common reasons for bid failure include:
-
-- **Insufficient bid amount** - Another searcher bid higher
-- **Transaction execution failure** - Insufficient funds or invalid transaction
-- **Timeout** - Bid submitted after opportunity expired
-
-## Error Handling
+```
-Implement proper error handling for common scenarios:
+
+
-### Network Errors
+Searchers can submit bids via Websocket to avoid additional network round-trips and get notified about changes to the bid status.
-```typescript
-try {
- const bidResponse = await client.submitBid(bid);
-} catch (error) {
- if (error.code === "NETWORK_ERROR") {
- // Retry submission
- console.log("Network error, retrying...");
+```json
+{
+ "id": "1",
+ "method": "post_bid",
+ "params": {
+ "bid": {
+ "chain_id": "solana",
+ "transaction": "SGVsbG8sIFdvcmxkIQ=="
+ }
}
}
```
-### Invalid Opportunities
-
-```typescript
-const handleOpportunity = async (opportunity: Opportunity) => {
- try {
- // Validate opportunity before bidding
- if (!isValidOpportunity(opportunity)) {
- console.log("Invalid opportunity, skipping");
- return;
- }
+A successful response to a bid submission has the following schema:
- const bid = await generateBid(opportunity);
- await client.submitBid(bid);
- } catch (error) {
- console.error("Error processing opportunity:", error);
+```json
+{
+ "id": "1", // Websocket request id
+ "status": "success",
+ "result": {
+ "id": "beedbeed-b346-4fa1-8fab-2541a9e1872d", // Bid id
+ "status": "OK"
}
-};
+}
```
-## Best Practices
-
-### Performance Optimization
-
-- **Use WebSocket connections** for real-time opportunity updates
-- **Implement efficient bid calculation** to minimize latency
-- **Cache frequently used data** like token prices and account information
-
-### Risk Management
-
-- **Set maximum bid amounts** to control potential losses
-- **Implement position limits** to manage overall exposure
-- **Monitor profitability** and adjust strategies accordingly
-
-### Monitoring and Logging
-
-- **Log all opportunities** received for analysis
-- **Track bid success rates** and profitability metrics
-- **Monitor system health** and performance indicators
-
-## Additional Resources
+Consult Websocket API reference for more details.
-- [Express Relay HTTP API Documentation](../http-api-reference)
-- [WebSocket API Reference](../websocket-api-reference)
-- [Contract Addresses](../contract-addresses)
-- [Error Codes Reference](../errors)
+
+
diff --git a/apps/developer-hub/content/docs/express-relay/websocket-api-reference.mdx b/apps/developer-hub/content/docs/express-relay/websocket-api-reference.mdx
index 23a93a6908..6b4b0c7c7b 100644
--- a/apps/developer-hub/content/docs/express-relay/websocket-api-reference.mdx
+++ b/apps/developer-hub/content/docs/express-relay/websocket-api-reference.mdx
@@ -1,12 +1,9 @@
---
title: "WebSocket API Reference"
description: >-
- Complete reference for Express Relay's WebSocket API for subscribing to opportunities and submitting bids with reduced latency.
+ Searchers can connect to the server via WebSocket to reduce latency and subscribe to various events.
---
-# WebSocket API Reference
-
-Searchers can connect to the server via WebSocket to reduce latency and subscribe to various events.
The WebSocket endpoint lives at `/v1/ws` (e.g wss://per-mainnet.dourolabs.app/v1/ws).
## General Format
@@ -113,9 +110,8 @@ A successful response to a bid submission has the following schema:
After submitting your bid via WebSocket, you will receive notifications about the bid status updates in JSON format.
-### Status Types
-
-**Pending**
+
+
```json
// The temporary state which means the auction for this bid is pending.
@@ -131,7 +127,8 @@ After submitting your bid via WebSocket, you will receive notifications about th
}
```
-**Submitted**
+
+
```json
// The bid won the auction and was submitted to the chain, with the signature
@@ -150,7 +147,8 @@ After submitting your bid via WebSocket, you will receive notifications about th
}
```
-**Lost**
+
+
```json
// The bid did not win the auction and therefore was not submitted.
@@ -165,8 +163,8 @@ After submitting your bid via WebSocket, you will receive notifications about th
}
```
-**Won**
-
+
+
```json
// The final state which means the bid was submitted to the chain and successfully executed.
{
@@ -181,7 +179,8 @@ After submitting your bid via WebSocket, you will receive notifications about th
}
```
-**Failed**
+
+
```json
// The final state which means the bid was submitted to the chain but failed to execute.
@@ -197,7 +196,8 @@ After submitting your bid via WebSocket, you will receive notifications about th
}
```
-**Expired**
+
+
```json
// The final state which means the bid was submitted to the chain but expired before execution.
@@ -212,3 +212,12 @@ After submitting your bid via WebSocket, you will receive notifications about th
}
}
```
+
+
+
+
+## Connection Persistence
+
+The WebSocket server responds to ping messages according to WebSocket standards.
+
+Additionally, the server periodically sends a ping message to the client to ensure the connection is still active and expects a pong in return.
diff --git a/apps/developer-hub/src/mdx-components.tsx b/apps/developer-hub/src/mdx-components.tsx
index 89e6db5256..c6a3bb3106 100644
--- a/apps/developer-hub/src/mdx-components.tsx
+++ b/apps/developer-hub/src/mdx-components.tsx
@@ -3,8 +3,6 @@ import { Tab, Tabs } from "fumadocs-ui/components/tabs";
import defaultMdxComponents from "fumadocs-ui/mdx";
import type { MDXComponents } from "mdx/types";
-import { IntegrationCard } from "./components/IntegrationCard";
-
export function getMDXComponents(components?: MDXComponents): MDXComponents {
return {
...defaultMdxComponents,
@@ -12,7 +10,6 @@ export function getMDXComponents(components?: MDXComponents): MDXComponents {
Tab,
...components,
InfoBox: InfoBox,
- IntegrationCard,
// Fuma has a Callout component in `defaultMdxComponents` which we still want to overwrite
Callout: InfoBox,
};
diff --git a/apps/entropy-debugger/next-env.d.ts b/apps/entropy-debugger/next-env.d.ts
index 1b3be0840f..830fb594ca 100644
--- a/apps/entropy-debugger/next-env.d.ts
+++ b/apps/entropy-debugger/next-env.d.ts
@@ -1,5 +1,6 @@
///
///
+///
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.