Skip to content

Express Relay: Add Mkt Order Docs #733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added images/express_relay/bid_status_diagram.png
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any other diagram? I would suggest you to send this to Yanis and he can make it more readable.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/express_relay/market-orders-flow.webp
Binary file not shown.
11 changes: 8 additions & 3 deletions pages/express-relay/integrate-as-searcher.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@ Searchers can integrate with Express Relay in three steps:
2. Construct the bid
3. Submit the bid to Express Relay.

Searchers can integrate with Express Relay on Solana Virtual Machine (SVM) chains.
Searchers can integrate with Express Relay on Solana Virtual Machine (SVM) chains to fulfill [market order](./integrate-as-searcher/market-orders.mdx) opportunities as well as [limit orders](./integrate-as-searcher/limit-orders.mdx) on the [Limo](https://solscan.io/account/LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF) program.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Searchers can integrate with Express Relay on Solana Virtual Machine (SVM) chains to fulfill [market order](./integrate-as-searcher/market-orders.mdx) opportunities as well as [limit orders](./integrate-as-searcher/limit-orders.mdx) on the [Limo](https://solscan.io/account/LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF) program.
Searchers can integrate with Express Relay on Solana Virtual Machine (SVM) chains to fulfill both, **[market orders]**(./integrate-as-searcher/market-orders.mdx) and **[limit orders]**(./integrate-as-searcher/limit-orders.mdx) on the [Limo](https://solscan.io/account/LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF) program.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we need to explain [Limo] here?


<Cards>
<Card
icon={<CodeIcon />}
title="Integrate with Express Relay on SVM Chains"
href="/express-relay/integrate-as-searcher/svm"
title="Integrate with Market Orders"
href="/express-relay/integrate-as-searcher/market-orders"
/>
<Card
icon={<CodeIcon />}
title="Integrate with Limit Orders"
href="/express-relay/integrate-as-searcher/limit-orders"
/>
</Cards>
3 changes: 2 additions & 1 deletion pages/express-relay/integrate-as-searcher/_meta.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"svm": "Integrate on SVM chains"
"market-orders": "Integrate on Market Orders",
"limit-orders": "Integrate on Limit Orders"
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Callout, Tabs, Steps } from "nextra/components";

# 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.
# Limit Orders Integration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Limit Orders Integration
# Integrate on Limit Orders


<Steps>

Expand Down
207 changes: 207 additions & 0 deletions pages/express-relay/integrate-as-searcher/market-orders.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
import { Callout, Tabs, Steps } from "nextra/components";

# Market Orders Integration
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Market Orders Integration
# Integrate on Market Orders


Unlike limit orders, market orders are created by users and need instant fulfilment within a single transaction.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Unlike limit orders, market orders are created by users and need instant fulfilment within a single transaction.
Market orders are user-initiated trades that must be executed immediately at the best available price, within a single transaction. Unlike limit orders, they do not wait for specific price conditions to be met.


### Request Flow

The following diagram illustrates the flow of a market order:
![Market Orders Flow](images/express_relay/market-orders-flow.webp)

### Opportunity Structure

Quote requests are broadcast through the same WebSocket channel used for receiving other opportunities. To receive market order quote requests, you should subscribe to WebSocket updates; see the [WebSocket API reference](../websocket-api-reference.mdx) for more details.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Quote requests are broadcast through the same WebSocket channel used for receiving other opportunities. To receive market order quote requests, you should subscribe to WebSocket updates; see the [WebSocket API reference](../websocket-api-reference.mdx) for more details.
Quote requests for market orders are sent over the same WebSocket stream as other trading opportunities. To receive them, just subscribe to the appropriate updates. See the [WebSocket API reference](../websocket-api-reference.mdx) for more info.


Here is a sample payload:

```jsx
{
'opportunity_id': '27dc5825-5b7f-4146-b00d-76be08a7139c',
'creation_time': 1751077051829889,
'version': 'v1',
'program': 'swap',
'user_wallet_address': '64Z52fmBUqAL6MFdC8garjrbvnV1w8iFGnGLWWbieYhc',
'user_mint_user_balance': 99999999979999552,
'permission_account': 'Hsto7eviBUvgFNS4KWRtVYRMnCcMHYEYMuq6YmBLkNJL',
'router_account': '69ib85nGQS2Hzr4tQ8twbkGh76gKFUfWJFeJfQ37R3hW',
'referral_fee_bps': 0,
'referral_fee_ppm': 0,
'platform_fee_bps': 10,
'platform_fee_ppm': 1000,
'fee_token': 'user_token',
'tokens': {
'side_specified': 'user',
'searcher_token': 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
'user_token': 'Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB',
'user_amount': 2218,
'user_amount_including_fees': 2220,
'token_program_searcher': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
'token_program_user': 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'
},
'token_account_initialization_configs': {
'user_ata_mint_searcher': 'user_payer',
'user_ata_mint_user': 'unneeded',
'router_fee_receiver_ta': 'unneeded',
'relayer_fee_receiver_ata': 'unneeded',
'express_relay_fee_receiver_ata': 'unneeded'
},
'memo': 'memo',
'cancellable': True,
'minimum_deadline': 1751077057,
'profile_id': None,
'chain_id': 'solana'
}
```

The user token refers to the token that the user puts in to the trade, while the searcher token refers to the token that the searcher contributes to the trade. In this example the user with wallet address `64Z52fmBUqAL6MFdC8garjrbvnV1w8iFGnGLWWbieYhc` wants to sell 1.000000 USDT (`Es9vMF…`) in exchange for the maximum USDC (`EPjFWdd…`) possible.

The `side_specified` field in the opportunity shows whether the user has specified a certain amount for the token they are selling (`side_specified="user"`) or the token they are buying (`side_specified="searcher"`). Here is a sample payload when `side_specified` is `searcher`:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The `side_specified` field in the opportunity shows whether the user has specified a certain amount for the token they are selling (`side_specified="user"`) or the token they are buying (`side_specified="searcher"`). Here is a sample payload when `side_specified` is `searcher`:
The side_specified field indicates which side of the trade the user has fixed.
- If side_specified = "user", the user has specified the amount they want to sell.
- If side_specified = "searcher", the user has specified the amount they want to buy, and it’s up to you to determine how much of the sell token to provide.
Here’s an example payload where side_specified is set to "searcher":


```jsx
"tokens": {
"side_specified": "searcher",
"searcher_token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"user_token": "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
"searcher_amount": 4023,
"token_program_searcher": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"token_program_user": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
}
```

This means the user wants to receive the best possible quote--i.e. send the least amount of USDT (`Es9vMF…`)--to receive exactly 1.000000 USDC (`EPjFWdd…`).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This means the user wants to receive the best possible quote--i.e. send the least amount of USDT (`Es9vMF…`)--to receive exactly 1.000000 USDC (`EPjFWdd`).
In this example, side_specified is set to "searcher", meaning the user has specified the amount they want to receive — in this case, exactly 1.000000 USDC (EPjFWdd...).
Searcher has to return the best possible quote by determining the minimum amount of USDT (Es9vMF...) required to fulfill this request.


Other fields necessary for constructing the transaction include:

- `user_wallet_address` The address of the counterparty in the trade. Should be included as a signer in the Express Relay program instruction
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `user_wallet_address` The address of the counterparty in the trade. Should be included as a signer in the Express Relay program instruction
- `user_wallet_address`: The address of the counterparty in the trade. It should be included as a signer in the Express Relay program instruction.

- `fee_token` Whether the fees will be deducted from the searcher token or the user token
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `fee_token` Whether the fees will be deducted from the searcher token or the user token
- `fee_token`: Specifies which token the fees will be deducted from — either the searcher’s token or the user’s token.

- `router_account` The account receiving the referral fees
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `router_account` The account receiving the referral fees
- `router_account`: The account that will receive the referral fees.

- `permission_account` The account to be specified as the permission in the Express Relay program instruction
- `referral_fee_bps` Amount of referral fees deducted from the swap in basis points
- `referral_fee_ppm` Amount of referral fees deducted from the swap in parts per million (1 basis point = 100 parts per million)
- `platform_fee_bps` Amount of platform fees deducted from the swap in basis points
- `platform_fee_ppm` Amount of platform fees deducted from the swap in parts per million
- `token_account_initialization_configs` Specifies which token accounts are required to be created in this transaction. Each of the internal fields represent one of the token accounts that potentially needs to be created.
The value for each field can be one of the following: - `unneeded`: This token account already exists and no creation instructions are needed - `user_payer`: This token account should be created and the account storage can be paid by the user - `searcher_payer`: This token account should be created and the account storage must be paid by the searcher
- `memo` A field indicating a string that should be included via a memo program instruction in the submitted transaction (SDK handles this automatically)
- `cancellable` A boolean indicating whether the searcher's quote can be cancelled
- `minimum_deadline` The minimum acceptable deadline for the quote, in seconds since the Unix epoch. The transaction must have a deadline greater than this value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `minimum_deadline` The minimum acceptable deadline for the quote, in seconds since the Unix epoch. The transaction must have a deadline greater than this value.
- `permission_account`: The account to be specified as the permission in the Express Relay program instruction.
- `referral_fee_bps`: The amount of referral fees deducted from the swap, expressed in basis points (bps).
(1 basis point = 0.01%)
- `referral_fee_ppm`: The same referral fee amount, represented in parts per million (ppm).
(1 basis point = 100 parts per million)
- `platform_fee_bps`: The amount of platform fees deducted from the swap, expressed in basis points.
- `platform_fee_ppm`: The same platform fee amount, represented in parts per million.
- `token_account_initialization_configs`: Specifies which token accounts must be created as part of the transaction. Each field inside this object corresponds to a token account, and its value determines the creation behavior:
- `unneeded`: The token account already exists; no action required.
- `user_payer`: This token account should be created and the account storage can be paid by the user.
- `searcher_payer`: The token account should be created, and the searcher will pay the storage cost.
- `memo`: An string to be included in the transaction via the Memo program. (Handled automatically by the SDK.)
- `cancellable`: Indicates whether the searcher’s quote can be cancelled.
- `minimum_deadline`: The minimum acceptable deadline (in seconds since Unix epoch) for the quote. The transaction must specify a deadline greater than this value.


#### Fee Token Dynamics

There are four possible combinations of `side_specified` and `fee_token`, and the way searchers should handle each case differs. We cover them here for clarity:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
There are four possible combinations of `side_specified` and `fee_token`, and the way searchers should handle each case differs. We cover them here for clarity:
There are four possible combinations of `side_specified` and `fee_token`.
Each has slightly different implications for how searchers should handle fees and construct their quotes. Below is a breakdown of each case:


1. **side_specified = "user", fee_token = "user_token"**

- The user specifies the amount of tokens they want to sell.
- Fees are deducted from the user's token.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Fees are deducted from the user's token.
- Fees are deducted from the **user's token**.

- `user_amount_including_fees` is greater than `user_amount`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `user_amount_including_fees` is greater than `user_amount`.
- `user_amount_including_fees` is **greater than** `user_amount`.

- The searcher receives `user_amount`.
- You need still need to provide `user_amount_including_fees` to the contract as parameters for correct validation (SDK handles this automatically).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- You need still need to provide `user_amount_including_fees` to the contract as parameters for correct validation (SDK handles this automatically).
- `user_amount_including_fees` must be included in the transaction for proper validation (handled automatically by SDK).


2. **side_specified = "user", fee_token = "searcher_token"**

- The user specifies the amount of tokens they want to sell.
- Fees are deducted from the searcher's token.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Fees are deducted from the searcher's token.
- Fees are deducted from the **searcher's token**.

- `user_amount_including_fees` equals `user_amount`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `user_amount_including_fees` equals `user_amount`.
- `user_amount_including_fees` is equal to `user_amount`.

- The searcher receives `user_amount`.

3. **side_specified = "searcher", fee_token = "user_token"**

- The user specifies the amount of tokens they want to receive.
- Fees are deducted from the user's token.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Fees are deducted from the user's token.
- Fees are deducted from the **user's token**.

- The searcher provides the exact `searcher_amount`.
- The searcher's quote should include the fact that fees will be taken from the user's token. For example, if the searcher is willing to receive 1000 tokens but there is a total fee of 10 bps, the searcher should quote 1001 tokens to include the 1 token fee.
- Here, the searcher needs to specify in the Express Relay contract instruction the total amount that the user should pay inclusive of fees (SDK handles this automatically).

4. **side_specified = "searcher", fee_token = "searcher_token"**

- The user specifies the amount of tokens they want to receive.
- Fees are deducted from the searcher's token.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Fees are deducted from the searcher's token.
- Fees are deducted from the **searcher's token**.

- The opportunity broadcast from the server will already include fees in the `searcher_amount` shown to searchers. So the searcher just needs to provide exactly `searcher_amount`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is repetitive. We can be say this like.
The searcher_amount value in the opportunity already includes the fee.

- The user receives the exact requested amount.

Again, the SDK handles all four of these cases; refer to the logic and documentation therein.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you put it in a callout as a NOTE.

"The SDK abstracts all of the cases/logic ..... )"


### Bid Submission

The transaction containing the bid should include the following instructions:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The transaction containing the bid should include the following instructions:
While submitting a bid, the transaction must include the following instructions:


- A `setComputeUnitPrice` instruction to adjust priority fees (similar to limit order bids). Priority fees should be set in line with the [prioritization fee updates](../websocket-api-reference.mdx#prioritization-fees) broadcast from the server via WebSocket.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@anihamde
Sorry, I am not able understand this.

- A set of instructions ensuring that the fee token accounts for the `user_wallet_address` , `router`, `searcher` and the `protocol` exist, as needed. You can use the `createAssociatedTokenAccountIdempotentInstruction` instruction in the spl-token library to do this.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you link it if you this it's necessary?

- A single `swap_v2` instruction calling the Pyth Express Relay program with the necessary accounts and data. If the input amount is already specified by user, you need to set the output amount and vice versa. This would essentially represent your bid or quote for the request.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- A single `swap_v2` instruction calling the Pyth Express Relay program with the necessary accounts and data. If the input amount is already specified by user, you need to set the output amount and vice versa. This would essentially represent your bid or quote for the request.
- Include a single `swap_v2` instruction calling the Pyth Express Relay program with the necessary accounts and data. If the user specified the input amount, you must provide the output amount in your bid and vice versa.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, what do you mean by represent your bid or quote for the request.


The SDKs provided will help you construct these instructions. Please note that at the moment, these are the only instructions permitted in an swap transaction; if other types of instructions are included, the bid will not be accepted. This is for security reasons, and if you find that you need to use a different instruction not listed above please inform us.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth mentioning this in a callout.


The schema for swap bids includes a partially signed transaction (with searcher as the fee payer, i.e. the first signature is the searchers) along with the `opportunity_id` received:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The schema for swap bids includes a partially signed transaction (with searcher as the fee payer, i.e. the first signature is the searchers) along with the `opportunity_id` received:
Bids for market orders include a partially signed transaction (with the searcher as the fee payer, i.e., the first signature is the searchers) and the corresponding opportunity_id:


```jsx
{
chain_id: 'solana',
opportunity_id: '44382da2-5971-453c-b647-2ba2317c7d56',
type: 'swap',
transaction: 'Ai22...'
}
```

You must include `opportunity_id` and `type` field in bids related to market orders. Once the opportunity is created and broadcast, there is a window of 250 milliseconds that the server waits to receive bids. You must submit your bid within that window for it to be considered in the auction. Otherwise, if your bid arrives too late, the opportunity corresponding to the `opportunity_id` you provide will have expired, and you will receive the error message `No swap opportunity with the given id found`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Callout ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or too many callouts? 😅

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
You must include `opportunity_id` and `type` field in bids related to market orders. Once the opportunity is created and broadcast, there is a window of 250 milliseconds that the server waits to receive bids. You must submit your bid within that window for it to be considered in the auction. Otherwise, if your bid arrives too late, the opportunity corresponding to the `opportunity_id` you provide will have expired, and you will receive the error message `No swap opportunity with the given id found`.
You must include `opportunity_id` and `type` field in bids related to market orders. Bids must be submitted within **250 milliseconds** of the opportunity being broadcast. You **must submit your bid within that window** for it to be considered in the auction. If your bid arrives too late, the opportunity associated with the provided `opportunity_id` will have already expired, and the server will return the error: `No swap opportunity with the given id found`.


The winner bid will be communicated to the users for the final signature and on-chain submission.

### Status Updates

Bid status notifications will be sent in the same WebSocket channel. The bid status can have the following values:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

status notifications -> status updates.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sent in -> sent through

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Bid status notifications will be sent in the same WebSocket channel. The bid status can have the following values:
Bid status updates are sent through the same WebSocket channel. These possible status updates are:


- `lost`: Bid was not high enough and another searcher won the auction.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `lost`: Bid was not high enough and another searcher won the auction.
- `lost`: The bid was not high enough and another searcher won the auction.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be high, or can we say competitive?

- `won` : Bid was submitted on-chain and is now confirmed and successful.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `won` : Bid was submitted on-chain and is now confirmed and successful.
- `won` : The bid was successfully submitted and confirmed on-chain.

- `failed`: Bid was submitted on-chain but the transaction failed.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `failed`: Bid was submitted on-chain but the transaction failed.
- `failed`: The bid was submitted on-chain, but the transaction failed.

- `expired`: Bid didn't land on-chain, either because the user didn't submit their signature or due to congestion.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `expired`: Bid didn't land on-chain, either because the user didn't submit their signature or due to congestion.
- `expired`: The bid didn't land on-chain, either because the user didn't submit their signature or due to network congestion.

- `awaiting_signature`: Bid won the auction and is sent to the user. Waiting for user to sign the transaction.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `awaiting_signature`: Bid won the auction and is sent to the user. Waiting for user to sign the transaction.
- `awaiting_signature`: The bid won the auction and is sent to the user. Waiting for user to sign the transaction.

- `submitted`: User has signed the transaction, and the transaction is now being submitted on-chain.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `submitted`: User has signed the transaction, and the transaction is now being submitted on-chain.
- `submitted`: The user has signed the transaction, and the transaction is now being submitted on-chain.

- `sent_to_user_for_submission`: Waiting for the user to sign the transaction and submit it directly (only for non-cancellable requests).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `sent_to_user_for_submission`: Waiting for the user to sign the transaction and submit it directly (only for non-cancellable requests).
- `sent_to_user_for_submission`: The transaction has been sent to the user to sign and submit themselves (used for non-cancellable requests).

- `submission_failed_cancelled`: The user submitted the signature but the searcher submitted a cancellation in the meantime, so the transaction will not be submitted on-chain. This will count towards the cancellation ratio of searchers.
- `submission_failed_deadline_passed`: The user submitted the signature but it already passed the specified deadline, so it will not be submitted on-chain.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `submission_failed_deadline_passed`: The user submitted the signature but it already passed the specified deadline, so it will not be submitted on-chain.
- `submission_failed_deadline_passed`: The user submitted the signature but it already passed the specified deadline, so it will **not be** submitted on-chain.


Below is a thorough transition diagram that details the interactions among the different statuses.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Below is a thorough transition diagram that details the interactions among the different statuses.
Below is a status transition diagram showing how bids progress through these states:


![B](images/express_relay/bid_status_diagram.png)

### Cancelling Bids

Searchers are able to cancel their submitted bids for quotes marked with `'cancellable': True` as long as the transactions are not signed by the user (before step 6 in the flow diagram above). This feature increases flexibility for more competitive pricing without additional risk of adverse selection.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Searchers are able to cancel their submitted bids for quotes marked with `'cancellable': True` as long as the transactions are not signed by the user (before step 6 in the flow diagram above). This feature increases flexibility for more competitive pricing without additional risk of adverse selection.
Searchers are able to cancel their submitted bids for quotes marked with `'cancellable': True`, as long as the user has not yet signed the transaction (i.e., before **Step 6** in the flow diagram above).
This feature enables greater flexibility and allows searchers to offer more competitive pricing without additional risk of adverse selection.


This functionality is available via the `cancel_bid` api. Here is a sample payload that can be sent via WebSocket:

```jsx
{
"method": "cancel_bid",
"params": {
"data": {
"bid_id": "fd586110-b22c-4e7e-a199-99c4db9c7515",
"chain_id": "solana"
}
}
}
```

# Endpoints and addresses:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Endpoints and addresses:
# Endpoints and Addresses:


- Program address: [`PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou`](https://solscan.io/address/PytERJFhAKuNNuaiXkApLfWzwNwSNDACpigT3LwQfou)
- Auction Server Endpoint: [`https://per-mainnet.dourolabs.app/`](https://per-staging.dourolabs.app/)
- Chain id: `solana`

You can test your service using real tokens like USDC and USDT.

# Links and references:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Links and references:
# Links and References:


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please give some one liner information about every reference.

JS SDK: https://www.npmjs.com/package/@pythnetwork/express-relay-js/

Python SDK: https://pypi.org/project/express-relay/

Rust Client SDK: https://crates.io/crates/express-relay-client

Rust API Types: https://crates.io/crates/express-relay-api-types/

Api References: https://per-mainnet.dourolabs.app/docs

Testing Ui: You can use [Kamino Swap](https://swap.kamino.finance/) or Jupiter to test
15 changes: 15 additions & 0 deletions pages/express-relay/websocket-api-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,21 @@ Refer to the examples below:

</Tabs>

## Prioritization Fees

For SVM chains, you will also receive `svm_chain_update` messages which include recent prioritization fee estimates needed for your transactions to land on chain. These prioritization fees will be specified in microlamports per compute unit; refer to [Solana docs](https://solana.com/developers/guides/advanced/how-to-use-priority-fees) to learn more about prioritization fees. The format for these updates is:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For SVM chains, you will also receive `svm_chain_update` messages which include recent prioritization fee estimates needed for your transactions to land on chain. These prioritization fees will be specified in microlamports per compute unit; refer to [Solana docs](https://solana.com/developers/guides/advanced/how-to-use-priority-fees) to learn more about prioritization fees. The format for these updates is:
For SVM chains, you will also receive `svm_chain_update` messages that include the latest prioritization fee estimates. These estimates help you determine the minimum fee needed for your transactions to be included on-chain.
These prioritization fees is expressed in **microlamports per compute unit**; refer to [Solana docs](https://solana.com/developers/guides/advanced/how-to-use-priority-fees) to learn more about prioritization fees.
Here is an example of a update message:


```json
{
"type": "svm_chain_update",
"update": {
"chain_id": "solana",
"blockhash": "PTgMRAF9GXRvYnWnpmDcX9gc1zesYV37kDjrax8kz3o",
"latest_prioritization_fee": 1000
}
}
```

## Connection Persistence

The WebSocket server responds to ping messages according to WebSocket standards.
Expand Down
Loading