Skip to content

Commit 703c905

Browse files
committed
added searcher guide to auction-server
1 parent 6ad0182 commit 703c905

File tree

3 files changed

+172
-4
lines changed

3 files changed

+172
-4
lines changed

pages/express-relay/how-express-relay-works/permissioning.mdx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Permission ID
1+
# Permissioning
22

33
`permissionId` is a `bytes` object that represents the unique identifying information 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.
44

@@ -22,4 +22,8 @@ bytes memory permissionId = abi.encode(borrowerAddress, positionId);
2222
```
2323

2424
The Express Relay contract uses the `permissionId` to toggle permissions for interacting with the protocol.
25-
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.
25+
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`:
26+
27+
```solidity
28+
bytes memory permissionKey = abi.encode(protocolAddress, permissionId);
29+
```

pages/express-relay/integrate-as-searcher.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ The server exposes different endpoints for interaction which can be used directl
66

77
The integration consists of 2 main steps:
88

9-
- Integrate your searcher service with auction server
9+
- Integrate your searcher service with the [auction server](./integrate-as-searcher/auction-server)
1010
- \[Optional\] Use [OpportunityAdapter](./integrate-as-searcher/opportunity-adapter) and setup a wallet with the necessary tokens and approvals
Lines changed: 165 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,167 @@
11
# Integrate with auction server
22

3-
## TODO
3+
## Submitting bids
4+
5+
Searchers submit their bids on transactions they wish to execute to the off-chain auction server of the Express Relay. The auction server lives at (TODO: INSERT ENDPOINT), and its API documentation can be found here (TODO: INSERT SWAGGER DOCS). You can use the express relay [JavaScript SDK](https://www.npmjs.com/package/@pythnetwork/express-relay-evm-js) or [Python SDK](https://pypi.org/project/express-relay/) for a more native integration.
6+
7+
To submit a bid to the auction server, a searcher can use either websocket (if they wish to subscribe to updates on the status of their bid) or the HTTP `/v1/bids` POST method.
8+
9+
### HTTP
10+
11+
The HTTP POST request should be submitted with a JSON request body representing the searcher's `Bid` object. An example is provided below:
12+
13+
```
14+
{
15+
"chain_id": "op_sepolia",
16+
"permission_key": "0x00000000000000000000000087ee27c5ae396b28a825968b277fece0720f5907000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
17+
"target_contract": "0x87ee27c5ae396b28a825968b277fece0720f5907"
18+
"target_calldata": "0xeadb38050000000000000000000000000000000000000000000000000000000000000064",
19+
"amount": "10",
20+
}
21+
```
22+
23+
The fields of this object are described in more detail below:
24+
- `chain_id`: The `string` identifying the chain on which the searcher wishes to submit the transaction.
25+
- `permission_key`: The `bytes` (in the form of a 0x-prefixed hex string) that serve as the unique identifying information for a position within a protocol
26+
- `target_contract`: The `address` of the contract the searcher wishes to call from the `ExpressRelay` contract. This could be the searcher's own contract or the [`OpportunityAdapterFactory` contract](./integrate-as-searcher/opportunity-adapter).
27+
- `target_calldata`: The `bytes` (in the form of a 0x-prefixed hex string) of the calldata the searcher wishes to call the `targetContract` with.
28+
- `amount`: The amount of ETH (in wei) the searcher is bidding for their transaction's priority.
29+
30+
### WebSocket
31+
32+
The WebSocket version of the above bid is very similar:
33+
34+
```
35+
{
36+
"id": "1",
37+
"method": "post_bid",
38+
"params": {
39+
"bid": {
40+
"chain_id": "op_sepolia",
41+
"permission_key": "0x00000000000000000000000087ee27c5ae396b28a825968b277fece0720f5907000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
42+
"target_contract": "0x87ee27c5ae396b28a825968b277fece0720f5907"
43+
"target_calldata": "0xeadb38050000000000000000000000000000000000000000000000000000000000000064",
44+
"amount": "10",
45+
}
46+
}
47+
}
48+
```
49+
50+
A successful response to bid submission has the following schema:
51+
52+
```
53+
{
54+
"id": "1", // websocket request id
55+
"status": "success"
56+
"result": {
57+
"id": "beedbeed-b346-4fa1-8fab-2541a9e1872d", // bid id
58+
"status": "OK"
59+
}
60+
}
61+
```
62+
63+
From this point on, you will receive notifications about the bid status updates in JSON format. There are four types of bid status updates ("pending", "submitted", "lost", "won"), and you can find more details and examples in the `BidStatus` schema in the Schemas section of the API documentation (TODO: INSERT SWAGGER DOCS).
64+
65+
#### WebSocket connection persistence
66+
67+
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.
68+
69+
## Discovering transactions to bid on
70+
71+
In addition, the server has a set of opportunity endpoints that expose [opportunities](./how-express-relay-works/opportunities) as they become available. An `Opportunity` has the following structure:
72+
73+
```
74+
{
75+
"chain_id": "op_sepolia",
76+
"permission_key": "0x00000000000000000000000087ee27c5ae396b28a825968b277fece0720f5907000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000",
77+
"target_contract": "0x87ee27c5ae396b28a825968b277fece0720f5907",
78+
"target_calldata": "0xdeadbeef",
79+
"target_call_value": "1",
80+
"buy_tokens": [
81+
{
82+
"amount": "3",
83+
"contract": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"
84+
}
85+
],
86+
"sell_tokens": [
87+
{
88+
"amount": "1",
89+
"contract": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599"
90+
}
91+
],
92+
"version": "v1"
93+
}
94+
```
95+
96+
The fields of the `Opportunity` are described below:
97+
- `chain_id`: The chain id where the opportunity is available
98+
- `permission_key`: The permission key corresponding to the opportunity
99+
- `target_contract`: The protocol contract address where the opportunity is available
100+
- `target_calldata`: The calldata to be used to execute the opportunity
101+
- `target_call_value`: The value to be sent to the `target_contract` in wei
102+
- `buy_tokens`: The tokens to be received as a result of the execution of the opportunity
103+
- `sell_tokens`: The tokens to be spent when executing the opportunity
104+
105+
Note that the `target_contract` and `target_calldata` fields of an `Opportunity` are not intended to be used for the fields in a `Bid`. Rather, this `target_contract` and `target_calldata` represent parameters for the call to the [`OpportunityAdapter` contract](./integrate-as-searcher/opportunity-adapter).
106+
107+
To query current opportunities, searchers can either make a HTTP `/v1/opportunities` GET request or subscribe to WebSocket updates on opportunities. To subscribe via WebSocket, you can send a request with the chain_ids parameter which specifies the chains as an array:
108+
109+
```
110+
{
111+
"id": "1",
112+
"method": "subscribe",
113+
"params": {
114+
"chain_ids": ["op_sepolia"]
115+
}
116+
}
117+
```
118+
119+
After a successful subscription you will receive the new opportunities for the selected chains via the websocket in the following format:
120+
121+
```
122+
{
123+
"type": "new_opportunity",
124+
"opportunity": {...}
125+
}
126+
```
127+
128+
with the opportunity being presented in a schema similar to above.
129+
130+
In order to unsubscribe from a list of chains, you can send the following message:
131+
132+
```
133+
{
134+
"id": "1",
135+
"method": "unsubscribe",
136+
"params": {
137+
"chain_ids": ["op_sepolia"]
138+
}
139+
}
140+
```
141+
142+
For most searchers, it is recommended to source opportunities via the opportunity endpoints and construct transactions intended for the [`OpportunityAdapter`](./integrate-as-searcher/opportunity-adapter). The SDKs expose methods to craft the calldata for the `OpportunityAdapter` contract and construct and submit the `Bid`.
143+
144+
If you prefer to use your own custom contracts rather than the `OpportunityAdpater` contract for executing opportunities, you can still use the server's opportunity endpoints to learn about opportunities on specific protocols and then craft a `Bid` based on an `Opportunity`. Here is a simplified example of a custom contract method that uses the `Opportunity` information to call a liquidation.
145+
146+
```solidity
147+
...
148+
function callLiquidation(Opportunity memory opp){
149+
150+
// this is a simplified version since sell and buy tokens are
151+
// an array and multiple assets may be necessary for the liquidation
152+
assert(opp.buy_tokens.length == 1);
153+
assert(opp.sell_tokens.length == 1);
154+
155+
IERC20(opp.sell_tokens[0].contract).approve(opp.contract, opp.sell_tokens[0].amount);
156+
157+
before = IERC20(opp.buy_tokens[0].contract).balanceOf(address(this));
158+
opp.target_contract.call{value: opp.target_call_value}(opp.target_calldata);
159+
160+
after = IERC20(opp.buy_tokens[0].target_contract).balanceOf(address(this));
161+
162+
assert(after == before + opportunity.buy_tokens[0].amount)
163+
}
164+
...
165+
```
166+
167+
Note that the protocol contract (`opp.contract`) expects the caller to have already approved the necessary amount from the `sell_tokens` to the protocol. Also note that the custom contract will be expected to pay the specified bid in ETH while it is called.

0 commit comments

Comments
 (0)