Skip to content

Express Relay Docs #339

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

Merged
merged 55 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
ba754df
Initial commit
aditya520 Jun 11, 2024
bf983a1
added some framework to docs
aditya520 Jun 12, 2024
e758759
protocol guide wip
aditya520 Jun 12, 2024
52c3346
add intro express relay docs
anihamde Jun 12, 2024
8d46c78
Merge branch '(feat)-add-express-relay' of github.com:pyth-network/do…
anihamde Jun 12, 2024
8cb8c04
up - up - update
aditya520 Jun 13, 2024
0e4d456
updated guide
aditya520 Jun 24, 2024
f45490f
additional resources
aditya520 Jun 24, 2024
0a56469
tiny changes
aditya520 Jun 25, 2024
d524fd3
uhh
aditya520 Jun 25, 2024
73aca99
(WIP) Express relay docs
aditya520 Jun 25, 2024
27fbecc
(WIP) API refernce
aditya520 Jun 25, 2024
9cf9fec
(WIP) Express relay docs
aditya520 Jun 25, 2024
e1c5734
details around auction, opportunities, and permissioning
anihamde Jun 26, 2024
a1ebb8d
Merge branch '(feat)-add-express-relay' of github.com:pyth-network/do…
anihamde Jun 26, 2024
ce9082d
(WIP) Express relay docs
aditya520 Jun 26, 2024
d16b669
(WIP) Express relay docs
aditya520 Jun 27, 2024
ecb7ca6
add some moar content
anihamde Jun 28, 2024
a9d32cd
(WIP) Express relay docs
aditya520 Jun 28, 2024
f044075
content dump
anihamde Jun 28, 2024
b0df6fb
Merge branch '(feat)-add-express-relay' of github.com:pyth-network/do…
anihamde Jun 28, 2024
59b1992
Suggested edits (#360)
jayantk Jul 1, 2024
1780065
(WIP) Express relay docs- Yaser comments
aditya520 Jul 1, 2024
0ee5829
Update tables
m30m Jul 2, 2024
6ad0182
Change MEV definition from the old one
m30m Jul 2, 2024
703c905
added searcher guide to auction-server
anihamde Jul 2, 2024
31eb98f
finalize opportunity adapter docs dump
anihamde Jul 3, 2024
59227c3
Use cards for the main CTAs
m30m Jul 4, 2024
cf27a2e
Separate websocket api reference
m30m Jul 4, 2024
bc60b80
WIP-Searcher-guide
aditya520 Jul 4, 2024
9979e89
WIP-searcher-guide-refactor
aditya520 Jul 5, 2024
2bda439
wip
aditya520 Jul 5, 2024
c35641d
WIP-searcher-guide-refactor
aditya520 Jul 5, 2024
6901e48
Reorg searcher docs
m30m Jul 5, 2024
56d8802
WIP-protocol-guide-refactor
aditya520 Jul 5, 2024
4f2f9e4
WIP-searcher-guide-refactor
aditya520 Jul 5, 2024
d172628
WIP-ER
aditya520 Jul 8, 2024
e24d4b6
Update docs
m30m Jul 8, 2024
fb63c4e
some minor changes
anihamde Jul 9, 2024
47ea3f0
WIP-searcher-guide-refactor
aditya520 Jul 9, 2024
84d8831
WIP-searcher-guide-refactor
aditya520 Jul 9, 2024
078f9f0
WIP-searcher-guide-refactor
aditya520 Jul 9, 2024
d3263cc
WIP-comments-resolved
aditya520 Jul 9, 2024
d816fed
address change
aditya520 Jul 9, 2024
d028c8d
WIP-comments-resolved
aditya520 Jul 10, 2024
2448bc8
WIP-comments-resolved
aditya520 Jul 10, 2024
a842125
few small fixes pt 1
anihamde Jul 10, 2024
04826af
WIP-intro page
aditya520 Jul 10, 2024
5d3e43e
few small fixes pt 2
anihamde Jul 10, 2024
c9963d9
Merge branch '(feat)-add-express-relay' of github.com:pyth-network/do…
anihamde Jul 10, 2024
1338c14
wip docs
aditya520 Jul 10, 2024
c97754c
Express Relay docs v1
aditya520 Jul 10, 2024
78cb484
index change
aditya520 Jul 11, 2024
59459ce
Changed example reference to example repo
aditya520 Jul 11, 2024
dee1c14
Express Relay v1.xx
aditya520 Jul 11, 2024
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
51 changes: 51 additions & 0 deletions components/AddressTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { StyledTd } from "./Table";

const AddressTable = ({
entries,
explorer,
}: {
entries: { name: string; value: string }[];
explorer: string;
}) => {
return (
<table>
<tbody>
{entries.map(({ name, value }) => {
const component = (
<code
className={
"nx-border-black nx-border-opacity-[0.04] nx-bg-opacity-[0.03] nx-bg-black nx-break-words nx-rounded-md nx-border nx-py-0.5 nx-px-[.25em] nx-text-[.9em] dark:nx-border-white/10 dark:nx-bg-white/10 "
}
>
{value}
</code>
);
const addLink =
explorer.includes("$ADDRESS") && value.startsWith("0x");
return (
<tr key={name}>
<StyledTd>{name}</StyledTd>
<StyledTd>
{addLink ? (
<a
href={explorer.replace("$ADDRESS", value)}
className={
"nx-text-primary-600 nx-underline nx-decoration-from-font [text-underline-position:from-font]"
}
target={"_blank"}
>
{component}
</a>
) : (
component
)}
</StyledTd>
</tr>
);
})}
</tbody>
</table>
);
};

export default AddressTable;
20 changes: 20 additions & 0 deletions components/icons/ContractIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const ContractIcon = ({ className }: { className: string }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className={className}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M10.125 2.25h-4.5c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125v-9M10.125 2.25h.375a9 9 0 0 1 9 9v.375M10.125 2.25A3.375 3.375 0 0 1 13.5 5.625v1.5c0 .621.504 1.125 1.125 1.125h1.5a3.375 3.375 0 0 1 3.375 3.375M9 15l2.25 2.25L15 12"
/>
</svg>
);
};

export default ContractIcon;
20 changes: 20 additions & 0 deletions components/icons/SearchIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const SearchIcon = ({ className }: { className: string }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className={className}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"
/>
</svg>
);
};

export default SearchIcon;
21 changes: 21 additions & 0 deletions images/express_relay/express_relay_schematic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions pages/_meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
"type": "page"
},

"express-relay": {
"title": "Express Relay",
"type": "page"
},

"get-in-touch": {
"title": "Get In Touch ↗",
"type": "page",
Expand Down
43 changes: 43 additions & 0 deletions pages/express-relay/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"documentation-home": {
"title": "← Documentation Home",
"href": "/home"
},

"-- Express Relay": {
"title": "Express Relay",
"type": "separator"
},
"index": "Introduction",

"-- How-to Guides": {
"title": "How-To Guides",
"type": "separator"
},

"integrate-as-protocol": "Integrate as a Protocol",
"integrate-as-searcher": "Integrate as a Searcher",

"-- Reference Material": {
"title": "Reference Material",
"type": "separator"
},

"api-reference": {
"title": "HTTP API Reference ↗",
"href": "https://pyth-express-relay-mainnet.asymmetric.re/docs/"
},
"websocket-api-reference": "Websocket API Reference",
"contract-addresses": "Contract Addresses",
"errors": "Error Codes",
"examples": {
"title": "Example Application ↗",
"href": "https://github.com/pyth-network/pyth-crosschain/tree/main/express_relay/examples/easy_lend"
},
"-- Understand Express Relay": {
"title": "Understanding Express Relay",
"type": "separator"
},

"how-express-relay-works": "How Express Relay Works"
}
3 changes: 3 additions & 0 deletions pages/express-relay/api-reference.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# API Reference

Link to swagger
133 changes: 133 additions & 0 deletions pages/express-relay/contract-addresses.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import AddressTable from "../../components/AddressTable";

Express Relay is currently deployed on the following networks:

## Mainnets

You can access the Auction Server via the following endpoint: https://pyth-express-relay-mainnet.asymmetric.re/

### Mode

Network Details:

<AddressTable
explorer={"https://explorer.mode.network/address/$ADDRESS"}
entries={[
{
name: "Express Relay",
value: "0x5Cc070844E98F4ceC5f2fBE1592fB1ed73aB7b48",
},
{
name: "Opportunity Adapter Factory",
value: "0x59F78DE21a0b05d96Ae00c547BA951a3B905602f",
},
{
name: "Network Id",
value: "34443",
},
{
name: "Chain Id",
value: "mode",
},
{
name: "Public RPC",
value: "https://mainnet.mode.network/",
},
{
name: "Wrapped ETH",
value: "0x4200000000000000000000000000000000000006",
},
{
name: "Permit2 Contract",
value: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
},
]}
/>

Assets:

<AddressTable
explorer={"https://explorer.mode.network/address/$ADDRESS"}
entries={[
{ name: "WETH", value: "0x4200000000000000000000000000000000000006" },
{ name: "USDC", value: "0xd988097fb8612cc24eeC14542bC03424c656005f" },
{ name: "USDT", value: "0xf0F161fDA2712DB8b566946122a5af183995e2eD" },
{ name: "WBTC", value: "0xcDd475325D6F564d27247D1DddBb0DAc6fA0a5CF" },
{ name: "ezETH", value: "0x2416092f143378750bb29b79eD961ab195CcEea5" },
{ name: "STONE", value: "0x80137510979822322193FC997d400D5A6C747bf7" },
{ name: "wrsETH", value: "0xe7903B1F75C534Dd8159b313d92cDCfbC62cB3Cd" },
{ name: "weETH.mode", value: "0x04C0599Ae5A44757c0af6F9eC3b93da8976c150A" },
{ name: "M-BTC", value: "0x59889b7021243dB5B1e065385F918316cD90D46c" },
{ name: "MODE", value: "0xDfc7C877a950e49D2610114102175A06C2e3167a" },
]}
/>

## Testnets

You can access the Auction Server via the following endpoint: https://per-staging.dourolabs.app/

### Optimism Sepolia

Main info:

<AddressTable
explorer={"https://optimism-sepolia.blockscout.com/address/$ADDRESS"}
entries={[
{
name: "Express Relay",
value: "0x2F968931d1B7326d2875E9500980211dcc535eE5",
},
{
name: "Opportunity Adapter Factory",
value: "0xfA119693864b2F185742A409c66f04865c787754",
},
{
name: "Network Id",
value: "11155420",
},
{
name: "Chain Id",
value: "op_sepolia",
},
{
name: "Public RPC",
value: "https://sepolia.optimism.io/",
},
{
name: "Wrapped ETH",
value: "0x74A4A85C611679B73F402B36c0F84A7D2CcdFDa3",
},
{
name: "Permit2 Contract",
value: "0x000000000022D473030F116dDEE9F6B43aC78BA3",
},
]}
/>

Assets:

<AddressTable
explorer={"https://optimism-sepolia.blockscout.com/address/$ADDRESS"}
entries={[
{
name: "BTC",
value: "0x3745007F7C8DD8Bec89b3B35f33f13f58b008533 ",
},
{
name: "USDC",
value: "0x1e3d75F24296abBC7bd10D151F51d758bCE379Ef",
},
{
name: "DOGE",
value: "0x0160Ba0A02A910e27b4189040aC74febcc476687 ",
},
{
name: "SOL",
value: "0x193aD24BeeDfAf27f217395f52fA20C7A36D79B3",
},
{
name: "PYTH",
value: "0x20e0b5Ff7aa971dAd8f489112Ae009A70608d2D5",
},
]}
/>
33 changes: 33 additions & 0 deletions pages/express-relay/errors.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Error Codes

The following table lists the error codes and their explanations for ExpressRelay and OpportunityAdapter contracts.
They can be used to identify the cause of a failed transaction or bid.

## ExpressRelay

| Error | Selector | Explanation |
| -------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------- |
| `Unauthorized()` | `0x82b42900` | This function is called by an unauthorized party. |
| `InvalidMagicValue()` | `0x4ed848c1` | An upgrade was attempted to a contract that does not match the ExpressRelay specification. |
| `InvalidPermission()` | `0x868a64de` | The provided permissionKey is invalid (too short). |
| `InvalidFeeSplit()` | `0x0601f697` | The proposed fee split is invalid (fee is larger than feePrecision, 10\*\*18). |
| `InvalidTargetContract()` | `0x5569851a` | The provided target contract is not allowed. (e.g. can not call the ExpressRelay contract). |
| `DuplicateRelayerSubwallet()` | `0xb40d37c3` | The provided subwallet to add has already been added. |
| `RelayerSubwalletNotFound()` | `0xac4d92b3` | The provided subwallet to delete does not exist in the store. |
| `ExternalCallFailed(MulticallStatus status)` | `0x740d0306` | The external call failed with the following MulticallStatus output. |

## OpportunityAdapter

| Error | Selector | Explanation |
| -------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------- |
| `NotCalledByExpressRelay()` | `0xd5668c88` | The OpportunityAdapterFactory contract was not called by the ExpressRelay contract. |
| `NotCalledByFactory()` | `0xb02436cc` | The OpportunityAdapter contract was not called by the OpportunityAdapterFactory contract. |
| `AdapterOwnerMismatch()` | `0x446f3eeb` | The provided executor field does not match the owner of the called OpportunityAdapter contract. |
| `InsufficientTokenReceived()` | `0x4af147aa` | The specified buyTokens were not received after calling the target contract. |
| `InsufficientEthToSettleBid()` | `0x9caaa1d7` | The contract did not receive enough ETH to pay the specified bid. |
| `InsufficientWethForTargetCallValue()` | `0x5e520cd4` | The contract did not receive enough Wrapped ETH to pay the targetCallValue to the targetContract. |
| `TargetCallFailed(bytes returnData)` | `0xa932c97a` | The call to targetContract failed with the specified returnData. |
| `DuplicateToken()` | `0x464e3f6a` | There is a duplicate token in either the sellTokens or buyTokens. |
| `EthOrWethBalanceDecreased()` | `0x1979776d` | The ETH or WETH balance of the contract decreased as a result of the call to targetContract and the bid payment. |
| `TargetContractNotAllowed()` | `0x9c86e59e` | The provided targetContract is not allowed. (e.g. can not call the Permit2 contract). |
| `OnlyOwnerCanCall()` | `0x47a8ea58` | Only the owner of the contract can call this method. |
44 changes: 44 additions & 0 deletions pages/express-relay/how-express-relay-works.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# How Express Relay Works

Express Relay allows protocols to eliminate maximal extractable value (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.

Express Relay solves the problem of MEV by providing protocol developers with an auction primitive that they can use to prioritize access to permissionless 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 determine the priority of their transactions, i.e., the order in which their transactions will be executed.
The winners transactions are forwarded to the blockchain, which both pays their bid and executes the operation.
The profits of the auction are then split between the integrated protocol and other participants in Express Relay.

![](images/express_relay/express_relay_schematic.svg)

The diagram above shows how Express Relay changes the MEV landscape for a liquidation.
In the status quo (left), Searchers tip miners in order to guarantee that their liquidation transaction lands on-chain.
Their transaction directly interacts with the protocol exposing the liquidation opportunity, and the liquidation bonus flows back to the Searcher.
With Express Relay (right), Searchers submit bids for their transaction to the Express Relay auction.
The auction submits the winning bids to the blockchain, where the transactions are processed by the Express Relay Entrypoint before being forwarded on to the integrated protocol.
The Express Relay Entrypoint collects payment from the Searchers and forwards a share of the revenue back to the integrated protocol.

FIXME: I think the diagram is wrong (specifically the liquidation bonus going back to express relay)

## Which protocols can use Express Relay?

Any protocol with permissionless and valuable operations can use Express Relay.
These operations generate MEV, as the validators control which searchers can access them.
Express Relay enables protocols to auction access instead, thereby ensuring the operation is competitively priced.
Lending, perps, and derivatives protocols with liquidation mechanisms are clear candidates that can benefit from integration with Express Relay.

Aside from eliminating MEV, protocols that need a stable set of searchers may choose to use 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. There is a single Relayer chosen by the Pyth DAO.
- Protocol developers integrate their protocol with Express Relay in order to eliminate MEV.
- Searchers participate in auctions to access liquidations and other on-chain opportunities.
- The Pyth DAO owns and governs the Express Relay system
6 changes: 6 additions & 0 deletions pages/express-relay/how-express-relay-works/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"auction": "Auction",
"opportunities": "Opportunities",
"permissioning": "Permissioning",
"relayer": "Relayer"
}
20 changes: 20 additions & 0 deletions pages/express-relay/how-express-relay-works/auction.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Auction

The auction in Express Relay is held off-chain at the auction server.
Liquidation bids arrive at the auction server and compete against other bids, vying for the same [permission key](./permissioning.mdx).
A [relayer](./relayer.mdx) 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 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 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/main/contracts/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. 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.
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.

The revenue from the auction is shared amongst relevant stakeholders in the Express Relay system. These stakeholders include:
- the protocol that generated the relevant opportunity
- the relayer, which handled running the off-chain components of the system

The Express Relay contract enforces the exact revenue splits and is subject to change based on governance decisions.
Loading
Loading