@@ -2,7 +2,7 @@ import { Callout, Tabs, Steps } from "nextra/components";
22
33# SVM Searcher Integration
44
5- SVM Express Relay searchers fulfill opportunities representing limit orders on the [ Limo] ( ) program.
5+ SVM Express Relay searchers fulfill opportunities representing limit orders on the [ Limo] ( https://solscan.io/account/LiMoM9rMhrdYrfzUCxQppvxCSG1FcrUK9G8uLq4A1GF ) program.
66
77<Steps >
88
@@ -19,39 +19,53 @@ Pyth provides a Typescript SDK, which allows searchers to subscribe to opportuni
1919``` typescript
2020import { Client , Opportunity } from " @pythnetwork/express-relay-js" ;
2121
22- const handleOpporunity = async (opportunity : Opportunity ) => {
22+ const handleOpportunity = async (opportunity : Opportunity ) => {
23+ console .log (" Received opportunity" );
2324 // Implement your opportunity handler here
2425};
2526
2627const client = new Client (
2728 { baseUrl: " https://pyth-express-relay-mainnet.asymmetric.re" },
2829 undefined , // Default WebSocket options
29- handleOpporunity
30+ handleOpportunity
3031);
31- await client .subscribeChains ([" development-solana" ]);
32+
33+ async function main() {
34+ await client .subscribeChains ([" solana" ]);
35+ }
36+
37+ main ();
3238```
3339
3440</Tabs.Tab >
3541<Tabs.Tab >
3642Pyth provides a Python SDK, which allows searchers to subscribe to opportunities:
3743
3844``` python copy
45+ import asyncio
3946from express_relay.client import (
4047 ExpressRelayClient,
4148)
42- from express_relay.express_relay_types import Opportunity
49+ from express_relay.models import Opportunity
4350
44- def opportunity_callback (opportunity : Opportunity):
51+ async def opportunity_callback (opportunity : Opportunity):
52+ print (" Received opportunity" )
4553 # Implement your opportunity handler here
46- pass
4754
4855client = ExpressRelayClient(
49- " https://per-staging.dourolabs.app " ,
56+ " https://pyth-express-relay-mainnet.asymmetric.re " ,
5057 None ,
5158 opportunity_callback,
5259 None ,
5360)
54- await client.subscribe_chains([' development-solana' ])
61+
62+ async def main ():
63+ await client.subscribe_chains([" solana" ])
64+ task = await client.get_ws_loop()
65+ await task
66+
67+ if __name__ == " __main__" :
68+ asyncio.run(main())
5569```
5670
5771</Tabs.Tab >
@@ -60,7 +74,7 @@ Searchers can request opportunities through an HTTP **GET** call to the [`/v1/op
6074
6175``` bash copy
6276curl -X ' GET' \
63- ' https://pyth-express-relay-mainnet.asymmetric.re/v1/opportunities?chain_id=development- solana&mode=live'
77+ ' https://pyth-express-relay-mainnet.asymmetric.re/v1/opportunities?chain_id=solana&mode=live'
6478```
6579
6680Opportunities are short-lived and could be executed in a matter of seconds. So, the above endpoint could return an empty response.
@@ -75,7 +89,7 @@ Here is a sample JSON payload to subscribe to opportunities:
7589 " id" : " 1" ,
7690 " method" : " subscribe" ,
7791 " params" : {
78- " chain_ids" : [" development- solana" ]
92+ " chain_ids" : [" solana" ]
7993 }
8094}
8195```
@@ -125,32 +139,41 @@ import * as limo from "@kamino-finance/limo-sdk";
125139 * @returns The generated bid object
126140 */
127141async generateBid (opportunity : OpportunitySvm ): Promise < BidSvm > {
128- const order = opportunity .order ;
129- const limoClient = new limo .LimoClient (
130- this .connectionSvm ,
131- order .state .globalConfig
132- );
133-
134- const ixsTakeOrder = await this .generateTakeOrderIxs (limoClient , order );
135- const txRaw = new anchor .web3 .Transaction ().add (... ixsTakeOrder );
136-
137- const bidData = await this .getBidData (limoClient , order );
138-
139- const bid = await this .client .constructSvmBid (
140- txRaw ,
141- this .searcher .publicKey ,
142- bidData .router ,
143- order .address ,
144- bidData .bidAmount ,
145- new anchor .BN (Math .round (Date .now () / 1000 + DAY_IN_SECONDS )),
146- this .chainId ,
147- bidData .relayerSigner ,
148- bidData .relayerFeeReceiver
149- );
150-
151- bid.transaction.recentBlockhash = this .recentBlockhash [this .chainId ];
152- bid.transaction.sign(this.searcher);
153- return bid;
142+ const order = opportunity .order ;
143+ const limoClient = new limo .LimoClient (
144+ this .connectionSvm ,
145+ order .state .globalConfig
146+ );
147+
148+ const ixsTakeOrder = await this .generateTakeOrderIxs (limoClient , order );
149+ const feeInstruction = ComputeBudgetProgram .setComputeUnitPrice ({
150+ microLamports:
151+ this .latestChainUpdate [this .chainId ].latestPrioritizationFee ,
152+ });
153+ const txRaw = new anchor .web3 .Transaction ().add (
154+ feeInstruction ,
155+ ... ixsTakeOrder
156+ );
157+
158+ const bidAmount = await this .getBidAmount (order );
159+
160+ const config = await this .getExpressRelayConfig ();
161+ const bid = await this .client .constructSvmBid (
162+ txRaw ,
163+ this .searcher .publicKey ,
164+ getPdaAuthority (limoClient .getProgramID (), order .state .globalConfig ),
165+ order .address ,
166+ bidAmount ,
167+ new anchor .BN (Math .round (Date .now () / 1000 + DAY_IN_SECONDS )),
168+ this .chainId ,
169+ config .relayerSigner ,
170+ config .feeReceiverRelayer
171+ );
172+
173+ bid.transaction.recentBlockhash =
174+ this.latestChainUpdate[this .chainId ].blockhash;
175+ bid.transaction.sign(this.searcher);
176+ return bid;
154177}
155178```
156179
@@ -179,24 +202,32 @@ async def assess_opportunity(self, opp: OpportunitySvm) -> BidSvm | None:
179202 A bid object if the opportunity is worth taking to be submitted to the Express Relay server, otherwise None.
180203 """
181204 order: OrderStateAndAddress = {"address": opp.order_address, "state": opp.order}
205+
182206 ixs_take_order = await self.generate_take_order_ixs(order)
183- bid_data = await self .get_bid_data(order)
207+ bid_amount = await self.get_bid_amount(order)
208+ router = self.limo_client.get_pda_authority(
209+ self.limo_client.get_program_id(), order["state"].global_config
210+ )
184211
185212 submit_bid_ix = self.client.get_svm_submit_bid_instruction(
186213 searcher=self.private_key.pubkey(),
187- router = bid_data. router,
214+ router=router,
188215 permission_key=order["address"],
189- bid_amount = bid_data. bid_amount,
216+ bid_amount=bid_amount,
190217 deadline=DEADLINE,
191218 chain_id=self.chain_id,
192- fee_receiver_relayer = bid_data.relayer_fee_receiver,
193- relayer_signer = bid_data.relayer_signer,
219+ fee_receiver_relayer=(await self.get_metadata()).fee_receiver_relayer,
220+ relayer_signer=(await self.get_metadata()).relayer_signer,
221+ )
222+ latest_chain_update = self.latest_chain_update[self.chain_id]
223+ fee_instruction = set_compute_unit_price(
224+ latest_chain_update.latest_prioritization_fee
194225 )
195226 transaction = Transaction.new_with_payer(
196- [submit_bid_ix] + ixs_take_order, self .private_key.pubkey()
227+ [fee_instruction, submit_bid_ix] + ixs_take_order, self.private_key.pubkey()
197228 )
198229 transaction.partial_sign(
199- [self .private_key], recent_blockhash = self .recent_blockhash[ self .chain_id]
230+ [self.private_key], recent_blockhash=latest_chain_update.blockhash
200231 )
201232 bid = BidSvm(transaction=transaction, chain_id=self.chain_id)
202233 return bid
@@ -233,9 +264,9 @@ const generateBid = async (opportunity: OpportunitySvm, recentBlockhash: Blockha
233264 ...
234265}
235266
236- const handleOpporunity = async (opportunity : Opportunity ) => {
267+ const handleOpportunity = async (opportunity: Opportunity) => {
237268 ...
238- const bid = await generateBid (opportunity as OpportunitySvm , this . recentBlockhash [ this . chainId ] );
269+ const bid = await this. generateBid(opportunity as OpportunitySvm);
239270 await client.submitBid(bid);
240271}
241272` ` `
@@ -252,7 +283,7 @@ async def generate_bid(opp: OpportunitySvm) -> BidSvm:
252283 ...
253284
254285def opportunity_callback(opportunity: Opportunity):
255- bid = generate_bid (typing.cast(OpportunitySvm, opportunity ))
286+ bid = await self.assess_opportunity (typing.cast(OpportunitySvm, opp ))
256287 await client.submit_bid(bid, subscribe_to_updates=True)
257288` ` `
258289
@@ -264,7 +295,7 @@ Searchers can submit bids through an HTTP POST call to the [`/v1/bids`](https://
264295curl -X POST https://pyth-express-relay-mainnet.asymmetric.re/v1/bids \
265296 -H "Content-Type: application/json" \
266297 -d '{
267- "chain_id": "development- solana",
298+ "chain_id": "solana",
268299 "transaction": "SGVsbG8sIFdvcmxkIQ=="
269300}'
270301` ` `
@@ -280,7 +311,7 @@ Searchers can submit bids via Websocket to avoid additional network round-trips
280311 "method": "post_bid",
281312 "params": {
282313 "bid": {
283- " chain_id" : " development- solana" ,
314+ "chain_id": "solana",
284315 "transaction": "SGVsbG8sIFdvcmxkIQ=="
285316 }
286317 }
0 commit comments