diff --git a/Cargo.lock b/Cargo.lock index bb69b13b..12f2c0c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -719,7 +719,7 @@ dependencies = [ [[package]] name = "auction-server" -version = "0.18.1" +version = "0.19.0" dependencies = [ "anchor-lang", "anchor-lang-idl", diff --git a/apps/swap/src/app/page.tsx b/apps/swap/src/app/page.tsx index 5ed68c9e..93035751 100644 --- a/apps/swap/src/app/page.tsx +++ b/apps/swap/src/app/page.tsx @@ -50,12 +50,19 @@ export default function Home() { { inputAmount: quote.inputToken.amount.toString(), outputAmount: quote.outputToken.amount.toString(), - expirationTime: quote.expirationTime.toISOString(), + expirationTime: quote.expirationTime + ? quote.expirationTime.toISOString() + : "undefined", }, null, 2, ), ]); + if (!quote.transaction) { + throw new Error( + "Transaction not found due to wallet not being connected", + ); + } const signedTransaction = await signTransaction(quote.transaction); // Do not call getAccountKeys() in case there is an unresolved lookup table const accountPosition = diff --git a/auction-server/Cargo.toml b/auction-server/Cargo.toml index 5321066e..6a07d2b2 100644 --- a/auction-server/Cargo.toml +++ b/auction-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "auction-server" -version = "0.18.1" +version = "0.19.0" edition = "2021" license-file = "license.txt" diff --git a/auction-server/api-types/src/opportunity.rs b/auction-server/api-types/src/opportunity.rs index 0f4f42da..ff664d6a 100644 --- a/auction-server/api-types/src/opportunity.rs +++ b/auction-server/api-types/src/opportunity.rs @@ -524,10 +524,10 @@ pub struct OpportunityBidEvm { #[serde_as] #[derive(Serialize, Deserialize, ToSchema, Clone, PartialEq, Debug)] pub struct QuoteCreateV1SvmParams { - /// The user wallet address which requested the quote from the wallet. - #[schema(example = "DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5", value_type = String)] - #[serde_as(as = "DisplayFromStr")] - pub user_wallet_address: Pubkey, + /// The user wallet address which requested the quote from the wallet. If not provided, an indicative price without a transaction will be returned. + #[schema(example = "DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5", value_type = Option)] + #[serde_as(as = "Option")] + pub user_wallet_address: Option, /// The mint address of the token the user will provide in the swap. #[schema(example = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", value_type = String)] #[serde_as(as = "DisplayFromStr")] @@ -591,15 +591,23 @@ pub enum QuoteCreate { Svm(QuoteCreateSvm), } +impl QuoteCreate { + pub fn get_user_wallet_address(&self) -> Option { + match self { + QuoteCreate::Svm(QuoteCreateSvm::V1(params)) => params.user_wallet_address, + } + } +} + #[derive(Serialize, Deserialize, ToSchema, Clone, PartialEq, Debug)] pub struct QuoteV1Svm { - /// The transaction for the quote to be executed on chain which is valid until the expiration time. - #[schema(example = "SGVsbG8sIFdvcmxkIQ==", value_type = String)] - #[serde(with = "crate::serde::transaction_svm")] - pub transaction: VersionedTransaction, - /// The expiration time of the quote (in seconds since the Unix epoch). - #[schema(example = 1_700_000_000_000_000i64, value_type = i64)] - pub expiration_time: i64, + /// The transaction for the quote to be executed on chain which is valid until the expiration time. Not provided if the quote to return is only an indicative price. + #[schema(example = "SGVsbG8sIFdvcmxkIQ==", value_type = Option)] + #[serde(with = "crate::serde::nullable_transaction_svm")] + pub transaction: Option, + /// The expiration time of the quote (in seconds since the Unix epoch). Not provided if indicative price. + #[schema(example = 1_700_000_000_000_000i64, value_type = Option)] + pub expiration_time: Option, /// The token and amount that the user needs to send to fulfill the swap transaction. pub input_token: TokenAmountSvm, /// The token and amount that the user will receive when the swap is complete. diff --git a/auction-server/api-types/src/serde.rs b/auction-server/api-types/src/serde.rs index b64c417a..37029837 100644 --- a/auction-server/api-types/src/serde.rs +++ b/auction-server/api-types/src/serde.rs @@ -134,6 +134,56 @@ pub mod transaction_svm { } } +pub mod nullable_transaction_svm { + use { + base64::{ + engine::general_purpose::STANDARD, + Engine as _, + }, + serde::{ + de::Error as _, + ser::Error, + Deserialize, + Deserializer, + Serializer, + }, + solana_sdk::transaction::VersionedTransaction, + }; + + pub fn serialize(t: &Option, s: S) -> Result + where + S: Serializer, + { + match t { + Some(t) => { + let serialized = + bincode::serialize(t).map_err(|e| S::Error::custom(e.to_string()))?; + let base64_encoded = STANDARD.encode(serialized); + s.serialize_str(base64_encoded.as_str()) + } + None => s.serialize_none(), + } + } + + pub fn deserialize<'de, D>(d: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let s: Option = Deserialize::deserialize(d)?; + match s { + Some(s) => { + let base64_decoded = STANDARD + .decode(s) + .map_err(|e| D::Error::custom(e.to_string()))?; + let transaction: VersionedTransaction = bincode::deserialize(&base64_decoded) + .map_err(|e| D::Error::custom(e.to_string()))?; + Ok(Some(transaction)) + } + None => Ok(None), + } + } +} + pub mod nullable_signature_svm { use { serde::{ diff --git a/auction-server/src/opportunity/api.rs b/auction-server/src/opportunity/api.rs index 5cc14ff3..53050a4b 100644 --- a/auction-server/src/opportunity/api.rs +++ b/auction-server/src/opportunity/api.rs @@ -1,5 +1,6 @@ use { super::{ + entities::QuoteCreate as QuoteCreateEntity, repository::OPPORTUNITY_PAGE_SIZE_CAP, service::{ add_opportunity::AddOpportunityInput, @@ -45,6 +46,7 @@ use { }, ErrorBodyResponse, }, + solana_sdk::pubkey::Pubkey, std::sync::Arc, time::OffsetDateTime, }; @@ -198,6 +200,12 @@ pub async fn get_opportunities( } } +/// This corresponds to the base58 pubkey "Price11111111111111111111111111111111111112" +pub const INDICATIVE_PRICE_TAKER: Pubkey = Pubkey::new_from_array([ + 0x05, 0xda, 0xfe, 0x58, 0xfc, 0xc9, 0x54, 0xbe, 0x96, 0xc9, 0x32, 0xae, 0x8e, 0x9a, 0x17, 0x68, + 0x9d, 0x10, 0x17, 0xf8, 0xc9, 0xe1, 0xb0, 0x7c, 0x86, 0x32, 0x71, 0xc0, 0x00, 0x00, 0x00, 0x01, +]); + /// Submit a quote request. /// /// The server will create an opportunity and receive searcher bids @@ -211,11 +219,18 @@ pub async fn post_quote( State(store): State>, Json(params): Json, ) -> Result, RestError> { + if params.get_user_wallet_address() == Some(INDICATIVE_PRICE_TAKER) { + return Err(RestError::BadParameters( + "Invalid user wallet address".to_string(), + )); + } + let quote_create: QuoteCreateEntity = params.into(); + let quote = store .opportunity_service_svm .get_quote(GetQuoteInput { - quote_create: params.into(), - program: ProgramSvm::Swap, + quote_create, + program: ProgramSvm::Swap, }) .await?; diff --git a/auction-server/src/opportunity/entities/quote.rs b/auction-server/src/opportunity/entities/quote.rs index a30b783a..da4850d0 100644 --- a/auction-server/src/opportunity/entities/quote.rs +++ b/auction-server/src/opportunity/entities/quote.rs @@ -17,9 +17,9 @@ use { #[derive(Debug, Clone, PartialEq)] pub struct Quote { - pub transaction: VersionedTransaction, + pub transaction: Option, // The expiration time of the quote (in seconds since the Unix epoch) - pub expiration_time: i64, + pub expiration_time: Option, pub searcher_token: TokenAmountSvm, pub user_token: TokenAmountSvm, pub referrer_fee: TokenAmountSvm, @@ -36,7 +36,7 @@ pub struct ReferralFeeInfo { #[derive(Debug, Clone, PartialEq)] pub struct QuoteCreate { - pub user_wallet_address: Pubkey, + pub user_wallet_address: Option, pub tokens: QuoteTokens, pub referral_fee_info: Option, pub chain_id: ChainId, diff --git a/auction-server/src/opportunity/service/get_quote.rs b/auction-server/src/opportunity/service/get_quote.rs index a2bfaf82..d43cac75 100644 --- a/auction-server/src/opportunity/service/get_quote.rs +++ b/auction-server/src/opportunity/service/get_quote.rs @@ -28,6 +28,7 @@ use { Svm, }, opportunity::{ + api::INDICATIVE_PRICE_TAKER, entities::{ self, TokenAmountSvm, @@ -255,9 +256,13 @@ impl Service { }, }, }; + let user_wallet_address = match quote_create.user_wallet_address { + Some(address) => address, + None => INDICATIVE_PRICE_TAKER, + }; let permission_account = get_quote_virtual_permission_account( &tokens_for_permission, - "e_create.user_wallet_address, + &user_wallet_address, &router_token_account, referral_fee_info.referral_fee_bps, ); @@ -282,7 +287,7 @@ impl Service { let program_opportunity = match program { ProgramSvm::Swap => { entities::OpportunitySvmProgram::Swap(entities::OpportunitySvmProgramSwap { - user_wallet_address: quote_create.user_wallet_address, + user_wallet_address, fee_token, referral_fee_bps: referral_fee_info.referral_fee_bps, platform_fee_bps: metadata.swap_platform_fee_bps, @@ -401,18 +406,24 @@ impl Service { bids.sort_by(|a, b| a.amount.cmp(&b.amount)); } } + let mut bids_filtered: Vec> = Vec::new(); // here optimize_bids is used to batch the bid simulation. // the first bid in the returned vector is the best bid that passes simulation. if !bids.is_empty() { - bids_filtered = auction_service - .optimize_bids(&bids) - .await - .map(|x| x.value) - .map_err(|e| { - tracing::error!("Failed to simulate swap bids: {:?}", e); - RestError::TemporarilyUnavailable - })?; + if input.quote_create.user_wallet_address.is_none() { + // TODO: we may want to filter out bids by simulation later, but for now we just take the best bid as an indicative price + bids_filtered = bids.clone(); + } else { + bids_filtered = auction_service + .optimize_bids(&bids) + .await + .map(|x| x.value) + .map_err(|e| { + tracing::error!("Failed to simulate swap bids: {:?}", e); + RestError::TemporarilyUnavailable + })?; + } } if bids_filtered.is_empty() { @@ -535,28 +546,36 @@ impl Service { ), }; + let (transaction, expiration_time) = match input.quote_create.user_wallet_address { + None => (None, None), + Some(_) => ( + Some(winner_bid.chain_data.transaction.clone()), + Some(deadline), + ), + }; + Ok(entities::Quote { - transaction: winner_bid.chain_data.transaction.clone(), - expiration_time: deadline, + transaction, + expiration_time, searcher_token: TokenAmountSvm { token: searcher_token.token, amount: searcher_amount, }, - user_token: TokenAmountSvm { + user_token: TokenAmountSvm { token: user_token.token, amount: user_amount, }, - referrer_fee: TokenAmountSvm { + referrer_fee: TokenAmountSvm { token: fee_token, amount: fees.relayer_fee, }, - platform_fee: TokenAmountSvm { + platform_fee: TokenAmountSvm { token: fee_token, amount: fees.express_relay_fee + fees.relayer_fee, }, - chain_id: input.quote_create.chain_id, - reference_id: auction.id, + chain_id: input.quote_create.chain_id, + reference_id: auction.id, }) } } diff --git a/sdk/js/package.json b/sdk/js/package.json index 982f42b6..f1f327d3 100644 --- a/sdk/js/package.json +++ b/sdk/js/package.json @@ -1,6 +1,6 @@ { "name": "@pythnetwork/express-relay-js", - "version": "0.21.2", + "version": "0.22.0", "description": "Utilities for interacting with the express relay protocol", "homepage": "https://github.com/pyth-network/per/tree/main/sdk/js", "author": "Douro Labs", diff --git a/sdk/js/src/index.ts b/sdk/js/src/index.ts index a1b19a2c..ec931e6d 100644 --- a/sdk/js/src/index.ts +++ b/sdk/js/src/index.ts @@ -516,7 +516,9 @@ export class Client { } : null, specified_token_amount: quoteRequest.specifiedTokenAmount, - user_wallet_address: quoteRequest.userWallet.toBase58(), + user_wallet_address: quoteRequest.userWallet + ? quoteRequest.userWallet.toBase58() + : null, version: "v1" as const, }; // TODO: we may want to wrap all the GET/POST calls in a try/catch block to handle errors @@ -753,7 +755,9 @@ export class Client { ): QuoteResponse { return { chainId: quoteResponse.chain_id, - expirationTime: new Date(quoteResponse.expiration_time * 1000), + expirationTime: quoteResponse.expiration_time + ? new Date(quoteResponse.expiration_time * 1000) + : undefined, inputToken: { token: new PublicKey(quoteResponse.input_token.token), amount: BigInt(quoteResponse.input_token.amount), @@ -762,9 +766,11 @@ export class Client { token: new PublicKey(quoteResponse.output_token.token), amount: BigInt(quoteResponse.output_token.amount), }, - transaction: VersionedTransaction.deserialize( - new Uint8Array(base64.decode(quoteResponse.transaction)), - ), + transaction: quoteResponse.transaction + ? VersionedTransaction.deserialize( + new Uint8Array(base64.decode(quoteResponse.transaction)), + ) + : undefined, referenceId: quoteResponse.reference_id, }; } diff --git a/sdk/js/src/serverTypes.d.ts b/sdk/js/src/serverTypes.d.ts index 6fdda938..fee8d856 100644 --- a/sdk/js/src/serverTypes.d.ts +++ b/sdk/js/src/serverTypes.d.ts @@ -3,221 +3,109 @@ * Do not make direct changes to the file. */ +/** OneOf type helpers */ +type Without = { [P in Exclude]?: never }; +type XOR = T | U extends object + ? (Without & U) | (Without & T) + : T | U; +type OneOf = T extends [infer Only] + ? Only + : T extends [infer A, infer B, ...infer Rest] + ? OneOf<[XOR, ...Rest]> + : never; + export interface paths { "/v1/bids": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; /** * Returns at most 20 bids which were submitted after a specific time. * @deprecated * @description If no time is provided, the server will return the first bids. - * This api is deprecated and will be removed soon. Use /v1/{chain_id}/bids instead. + * This api is deprecated and will be removed soon. Use /v1/{chain_id}/bids instead. */ get: operations["get_bids_by_time_deprecated"]; - put?: never; /** * Bid on a specific permission key for a specific chain. * @description Your bid will be verified by the server. Depending on the outcome of the auction, a transaction - * containing your bid will be sent to the blockchain expecting the bid amount to be paid in the transaction. + * containing your bid will be sent to the blockchain expecting the bid amount to be paid in the transaction. */ post: operations["post_bid"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; }; "/v1/bids/{bid_id}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; /** * Query the status of a specific bid. * @deprecated * @description This api is deprecated and will be removed soon. Use /v1/{chain_id}/bids/{bid_id} instead. */ get: operations["get_bid_status_deprecated"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; }; "/v1/opportunities": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; /** * Fetch opportunities ready for execution or historical opportunities - * depending on the mode. + * depending on the mode. * @description You need to provide `chain_id` for historical mode. - * Opportunities are sorted by creation time in ascending order. - * Total number of opportunities returned is capped by the server to preserve bandwidth. + * Opportunities are sorted by creation time in ascending order. + * Total number of opportunities returned is capped by the server to preserve bandwidth. */ get: operations["get_opportunities"]; - put?: never; /** * Submit an opportunity ready to be executed. * @description The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database - * and will be available for bidding. + * and will be available for bidding. */ post: operations["post_opportunity"]; /** Delete all opportunities for specified data. */ delete: operations["delete_opportunities"]; - options?: never; - head?: never; - patch?: never; - trace?: never; }; "/v1/opportunities/quote": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; /** * Submit a quote request. * @description The server will create an opportunity and receive searcher bids - * After a certain time, the winning bid will be returned as the response. + * After a certain time, the winning bid will be returned as the response. */ post: operations["post_quote"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; }; "/v1/opportunities/{opportunity_id}/bids": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; /** Bid on opportunity. */ post: operations["opportunity_bid"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; }; "/v1/profiles/access_tokens": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - post?: never; /** * Revoke the authenticated profile access token. * @description Returns empty response. */ delete: operations["delete_profile_access_token"]; - options?: never; - head?: never; - patch?: never; - trace?: never; }; "/v1/{chain_id}/bids": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - /** Returns at most 20 bids which were submitted after a specific time and chain. - * If no time is provided, the server will return the first bids. */ + /** + * Returns at most 20 bids which were submitted after a specific time and chain. + * If no time is provided, the server will return the first bids. + */ get: operations["get_bids_by_time"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; }; "/v1/{chain_id}/bids/{bid_id}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; /** Query the status of a specific bid. */ get: operations["get_bid_status"]; - put?: never; - post?: never; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; }; "/v1/{chain_id}/bids/{bid_id}/cancel": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; /** * Cancel a specific bid. * @description Bids can only be cancelled if they are in the awaiting signature state. - * Only the user who created the bid can cancel it. + * Only the user who created the bid can cancel it. */ post: operations["post_cancel_bid"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; }; "/v1/{chain_id}/quotes/submit": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; /** * Signs and submits the transaction for the specified quote. * @description Server will verify the quote and checks if the quote is still valid. - * If the quote is valid, the server will submit the transaction to the blockchain. + * If the quote is valid, the server will submit the transaction to the blockchain. */ post: operations["post_submit_quote"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; }; } + export type webhooks = Record; + export interface components { schemas: { APIResponse: components["schemas"]["BidResult"]; @@ -274,7 +162,7 @@ export interface components { /** * Format: int64 * @description The minimum slot required for the bid to be executed successfully - * None if the bid can be executed at any recent slot + * None if the bid can be executed at any recent slot * @example 293106477 */ slot?: number | null; @@ -373,12 +261,13 @@ export interface components { BidStatus: | components["schemas"]["BidStatusSvm"] | components["schemas"]["BidStatusEvm"]; - BidStatusEvm: - | { + BidStatusEvm: OneOf< + [ + { /** @enum {string} */ type: "pending"; - } - | { + }, + { /** * Format: int32 * @example 1 @@ -388,8 +277,8 @@ export interface components { result: string; /** @enum {string} */ type: "submitted"; - } - | { + }, + { /** * Format: int32 * @example 1 @@ -399,8 +288,8 @@ export interface components { result?: string | null; /** @enum {string} */ type: "lost"; - } - | { + }, + { /** * Format: int32 * @example 1 @@ -410,7 +299,9 @@ export interface components { result: string; /** @enum {string} */ type: "won"; - }; + }, + ] + >; BidStatusSvm: | { /** @enum {string} */ @@ -492,7 +383,7 @@ export interface components { bid_amount: number; /** * @description The permission key for bid in base64 format. - * This is the concatenation of the opportunity type, the router, and the permission account. + * This is the concatenation of the opportunity type, the router, and the permission account. * @example DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5 */ permission_key: string; @@ -507,43 +398,46 @@ export interface components { Bids: { items: components["schemas"]["Bid"][]; }; - ClientMessage: - | { + ClientMessage: OneOf< + [ + { /** @enum {string} */ method: "subscribe"; params: { chain_ids: string[]; }; - } - | { + }, + { /** @enum {string} */ method: "unsubscribe"; params: { chain_ids: string[]; }; - } - | { + }, + { /** @enum {string} */ method: "post_bid"; params: { bid: components["schemas"]["BidCreate"]; }; - } - | { + }, + { /** @enum {string} */ method: "post_opportunity_bid"; params: { opportunity_bid: components["schemas"]["OpportunityBidEvm"]; opportunity_id: string; }; - } - | { + }, + { /** @enum {string} */ method: "cancel_bid"; params: { data: components["schemas"]["BidCancel"]; }; - }; + }, + ] + >; ClientRequest: components["schemas"]["ClientMessage"] & { id: string; }; @@ -620,10 +514,12 @@ export interface components { /** @enum {string} */ version: "v1"; }; - /** @description Opportunity parameters needed for on-chain execution. - * If a searcher signs the opportunity and have approved enough tokens to opportunity adapter, - * by calling this target contract with the given target calldata and structures, they will - * send the tokens specified in the `sell_tokens` field and receive the tokens specified in the `buy_tokens` field. */ + /** + * @description Opportunity parameters needed for on-chain execution. + * If a searcher signs the opportunity and have approved enough tokens to opportunity adapter, + * by calling this target contract with the given target calldata and structures, they will + * send the tokens specified in the `sell_tokens` field and receive the tokens specified in the `buy_tokens` field. + */ OpportunityCreateV1Evm: { buy_tokens: components["schemas"]["TokenAmountEvm"][]; /** @@ -653,8 +549,10 @@ export interface components { */ target_contract: string; }; - /** @description Opportunity parameters needed for on-chain execution. - * Parameters may differ for each program. */ + /** + * @description Opportunity parameters needed for on-chain execution. + * Parameters may differ for each program. + */ OpportunityCreateV1Svm: { /** * @description The Limo order to be executed, encoded in base64. @@ -694,15 +592,18 @@ export interface components { slot: number; }; /** @description The input type for deleting opportunities. */ - OpportunityDelete: - | (components["schemas"]["OpportunityDeleteSvm"] & { + OpportunityDelete: OneOf< + [ + components["schemas"]["OpportunityDeleteSvm"] & { /** @enum {string} */ chain_type: "svm"; - }) - | (components["schemas"]["OpportunityDeleteEvm"] & { + }, + components["schemas"]["OpportunityDeleteEvm"] & { /** @enum {string} */ chain_type: "evm"; - }); + }, + ] + >; OpportunityDeleteEvm: components["schemas"]["OpportunityDeleteV1Evm"] & { /** @enum {string} */ version: "v1"; @@ -770,10 +671,13 @@ export interface components { version: "v1"; }; OpportunityParamsV1Evm: components["schemas"]["OpportunityCreateV1Evm"]; - /** @description Opportunity parameters needed for on-chain execution. - * Parameters may differ for each program. */ - OpportunityParamsV1Svm: ( - | { + /** + * @description Opportunity parameters needed for on-chain execution. + * Parameters may differ for each program. + */ + OpportunityParamsV1Svm: OneOf< + [ + { /** * @description The Limo order to be executed, encoded in base64. * @example UxMUbQAsjrfQUp5stVwMJ6Mucq7VWTvt4ICe69BJ8lVXqwM+0sysV8OqZTdM0W4p... @@ -792,8 +696,8 @@ export interface components { * @example 293106477 */ slot: number; - } - | { + }, + { /** @description Specifies whether the fees are to be paid in the searcher or user token. */ fee_token: components["schemas"]["FeeToken"]; /** @@ -838,8 +742,9 @@ export interface components { * @example DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5 */ user_wallet_address: string; - } - ) & { + }, + ] + > & { /** @example solana */ chain_id: string; }; @@ -884,22 +789,28 @@ export interface components { */ output_token_mint: string; /** @description Information about the referral fee and the router to send the fee to. If not provided, referral fee will be set to 0. */ - referral_fee_info?: null | { - /** - * Format: int32 - * @description The referral fee in basis points. - * @example 10 - */ - referral_fee_bps: number; - /** - * @description The router account to send referral fees to. - * @example DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5 - */ - router: string; - }; + referral_fee_info?: OneOf< + [ + null, + { + /** + * Format: int32 + * @description The referral fee in basis points. + * @example 10 + */ + referral_fee_bps: number; + /** + * @description The router account to send referral fees to. + * @example DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5 + */ + router: string; + }, + ] + >; /** @description The token amount that the user wants to swap out of/into. */ - specified_token_amount: - | { + specified_token_amount: OneOf< + [ + { /** * Format: int64 * @example 100 @@ -907,8 +818,8 @@ export interface components { amount: number; /** @enum {string} */ side: "input"; - } - | { + }, + { /** * Format: int64 * @example 50 @@ -916,19 +827,22 @@ export interface components { amount: number; /** @enum {string} */ side: "output"; - }; + }, + ] + >; /** - * @description The user wallet address which requested the quote from the wallet. + * @description The user wallet address which requested the quote from the wallet. If not provided, an indicative price without a transaction will be returned. * @example DUcTi3rDyS5QEmZ4BNRBejtArmDCWaPYGfN44vBJXKL5 */ - user_wallet_address: string; + user_wallet_address?: string | null; }; QuoteSvm: components["schemas"]["QuoteV1Svm"] & { /** @enum {string} */ version: "v1"; }; - QuoteTokens: - | { + QuoteTokens: OneOf< + [ + { /** * Format: int64 * @description The exact amount that the searcher will provide @@ -946,8 +860,8 @@ export interface components { * @example So11111111111111111111111111111111111111112 */ user_token: string; - } - | { + }, + { /** * @description The token that the searcher will provide * @example EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v @@ -970,7 +884,9 @@ export interface components { * @example EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v */ user_token: string; - }; + }, + ] + >; QuoteV1Svm: { /** * @description The chain id for the quote. @@ -979,10 +895,10 @@ export interface components { chain_id: string; /** * Format: int64 - * @description The expiration time of the quote (in seconds since the Unix epoch). + * @description The expiration time of the quote (in seconds since the Unix epoch). Not provided if indicative price. * @example 1700000000000000 */ - expiration_time: number; + expiration_time?: number | null; /** @description The token and amount that the user needs to send to fulfill the swap transaction. */ input_token: components["schemas"]["TokenAmountSvm"]; /** @description The token and amount that the user will receive when the swap is complete. */ @@ -997,10 +913,10 @@ export interface components { /** @description The token and amount of the referral fee paid to the party that routed the swap request to Express Relay. */ referrer_fee: components["schemas"]["TokenAmountSvm"]; /** - * @description The transaction for the quote to be executed on chain which is valid until the expiration time. + * @description The transaction for the quote to be executed on chain which is valid until the expiration time. Not provided if the quote to return is only an indicative price. * @example SGVsbG8sIFdvcmxkIQ== */ - transaction: string; + transaction?: string | null; }; ReferralFeeInfo: { /** @@ -1015,46 +931,55 @@ export interface components { */ router: string; }; - ServerResultMessage: - | { + ServerResultMessage: OneOf< + [ + { result: null | components["schemas"]["APIResponse"]; /** @enum {string} */ status: "success"; - } - | { + }, + { result: string; /** @enum {string} */ status: "error"; - }; - /** @description This enum is used to send the result for a specific client request with the same id. - * Id is only None when the client message is invalid. */ + }, + ] + >; + /** + * @description This enum is used to send the result for a specific client request with the same id. + * Id is only None when the client message is invalid. + */ ServerResultResponse: components["schemas"]["ServerResultMessage"] & { id?: string | null; }; /** @description This enum is used to send an update to the client for any subscriptions made. */ - ServerUpdateResponse: - | { + ServerUpdateResponse: OneOf< + [ + { opportunity: components["schemas"]["Opportunity"]; /** @enum {string} */ type: "new_opportunity"; - } - | { + }, + { status: components["schemas"]["BidStatusWithId"]; /** @enum {string} */ type: "bid_status_update"; - } - | { + }, + { /** @enum {string} */ type: "svm_chain_update"; update: components["schemas"]["SvmChainUpdate"]; - } - | { + }, + { opportunity_delete: components["schemas"]["OpportunityDelete"]; /** @enum {string} */ type: "remove_opportunities"; - }; - SpecifiedTokenAmount: - | { + }, + ] + >; + SpecifiedTokenAmount: OneOf< + [ + { /** * Format: int64 * @example 100 @@ -1062,8 +987,8 @@ export interface components { amount: number; /** @enum {string} */ side: "input"; - } - | { + }, + { /** * Format: int64 * @example 50 @@ -1071,7 +996,9 @@ export interface components { amount: number; /** @enum {string} */ side: "output"; - }; + }, + ] + >; /** @description Parameters needed to submit a quote from server. */ SubmitQuote: { /** @@ -1089,7 +1016,7 @@ export interface components { SubmitQuoteResponse: { /** * @description The fully signed versioned transaction that was submitted. - * The transaction is encoded in base64. + * The transaction is encoded in base64. * @example SGVsbG8sIFdvcmxkIQ== */ transaction: string; @@ -1122,7 +1049,7 @@ export interface components { /** * Format: int64 * @description The token amount, represented in the smallest denomination of that token - * (e.g. lamports for SOL). + * (e.g. lamports for SOL). * @example 1000 */ amount: number; @@ -1135,9 +1062,6 @@ export interface components { }; responses: { BidResult: { - headers: { - [name: string]: unknown; - }; content: { "application/json": { /** @@ -1154,9 +1078,6 @@ export interface components { }; }; Bids: { - headers: { - [name: string]: unknown; - }; content: { "application/json": { items: components["schemas"]["Bid"][]; @@ -1165,9 +1086,6 @@ export interface components { }; /** @description An error occurred processing the request */ ErrorBodyResponse: { - headers: { - [name: string]: unknown; - }; content: { "application/json": { error: string; @@ -1175,9 +1093,6 @@ export interface components { }; }; Opportunity: { - headers: { - [name: string]: unknown; - }; content: { "application/json": | components["schemas"]["OpportunityEvm"] @@ -1190,25 +1105,28 @@ export interface components { headers: never; pathItems: never; } + export type $defs = Record; + +export type external = Record; + export interface operations { + /** + * Returns at most 20 bids which were submitted after a specific time. + * @deprecated + * @description If no time is provided, the server will return the first bids. + * This api is deprecated and will be removed soon. Use /v1/{chain_id}/bids instead. + */ get_bids_by_time_deprecated: { parameters: { query?: { /** @example 2024-05-23T21:26:57.329954Z */ from_time?: string | null; }; - header?: never; - path?: never; - cookie?: never; }; - requestBody?: never; responses: { /** @description Paginated list of bids for the specified query */ 200: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["Bids"]; }; @@ -1216,13 +1134,12 @@ export interface operations { 400: components["responses"]["ErrorBodyResponse"]; }; }; + /** + * Bid on a specific permission key for a specific chain. + * @description Your bid will be verified by the server. Depending on the outcome of the auction, a transaction + * containing your bid will be sent to the blockchain expecting the bid amount to be paid in the transaction. + */ post_bid: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; requestBody: { content: { "application/json": components["schemas"]["BidCreate"]; @@ -1231,9 +1148,6 @@ export interface operations { responses: { /** @description Bid was placed successfully */ 200: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["BidResult"]; }; @@ -1241,31 +1155,26 @@ export interface operations { 400: components["responses"]["ErrorBodyResponse"]; /** @description Chain id was not found */ 404: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["ErrorBodyResponse"]; }; }; }; }; + /** + * Query the status of a specific bid. + * @deprecated + * @description This api is deprecated and will be removed soon. Use /v1/{chain_id}/bids/{bid_id} instead. + */ get_bid_status_deprecated: { parameters: { - query?: never; - header?: never; path: { /** @description Bid id to query for */ bid_id: string; }; - cookie?: never; }; - requestBody?: never; responses: { 200: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["BidStatus"]; }; @@ -1273,15 +1182,19 @@ export interface operations { 400: components["responses"]["ErrorBodyResponse"]; /** @description Bid was not found */ 404: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["ErrorBodyResponse"]; }; }; }; }; + /** + * Fetch opportunities ready for execution or historical opportunities + * depending on the mode. + * @description You need to provide `chain_id` for historical mode. + * Opportunities are sorted by creation time in ascending order. + * Total number of opportunities returned is capped by the server to preserve bandwidth. + */ get_opportunities: { parameters: { query?: { @@ -1305,17 +1218,10 @@ export interface operations { */ limit?: number; }; - header?: never; - path?: never; - cookie?: never; }; - requestBody?: never; responses: { /** @description Array of opportunities ready for bidding */ 200: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["Opportunity"][]; }; @@ -1323,22 +1229,18 @@ export interface operations { 400: components["responses"]["ErrorBodyResponse"]; /** @description Chain id was not found */ 404: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["ErrorBodyResponse"]; }; }; }; }; + /** + * Submit an opportunity ready to be executed. + * @description The opportunity will be verified by the server. If the opportunity is valid, it will be stored in the database + * and will be available for bidding. + */ post_opportunity: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; requestBody: { content: { "application/json": components["schemas"]["OpportunityCreate"]; @@ -1347,9 +1249,6 @@ export interface operations { responses: { /** @description The created opportunity */ 200: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["Opportunity"]; }; @@ -1357,22 +1256,14 @@ export interface operations { 400: components["responses"]["ErrorBodyResponse"]; /** @description Chain id was not found */ 404: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["ErrorBodyResponse"]; }; }; }; }; + /** Delete all opportunities for specified data. */ delete_opportunities: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; requestBody: { content: { "application/json": components["schemas"]["OpportunityDelete"]; @@ -1381,30 +1272,23 @@ export interface operations { responses: { /** @description Opportunities deleted successfully */ 204: { - headers: { - [name: string]: unknown; - }; - content?: never; + content: never; }; 400: components["responses"]["ErrorBodyResponse"]; /** @description Chain id was not found */ 404: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["ErrorBodyResponse"]; }; }; }; }; + /** + * Submit a quote request. + * @description The server will create an opportunity and receive searcher bids + * After a certain time, the winning bid will be returned as the response. + */ post_quote: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; requestBody: { content: { "application/json": components["schemas"]["QuoteCreate"]; @@ -1413,9 +1297,6 @@ export interface operations { responses: { /** @description The created quote */ 200: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["Quote"]; }; @@ -1423,24 +1304,19 @@ export interface operations { 400: components["responses"]["ErrorBodyResponse"]; /** @description No quote available right now */ 404: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["ErrorBodyResponse"]; }; }; }; }; + /** Bid on opportunity. */ opportunity_bid: { parameters: { - query?: never; - header?: never; path: { /** @description Opportunity id to bid on */ opportunity_id: string; }; - cookie?: never; }; requestBody: { content: { @@ -1450,9 +1326,6 @@ export interface operations { responses: { /** @description Bid Result */ 200: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["OpportunityBidResult"]; }; @@ -1460,41 +1333,35 @@ export interface operations { 400: components["responses"]["ErrorBodyResponse"]; /** @description Opportunity or chain id was not found */ 404: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["ErrorBodyResponse"]; }; }; }; }; + /** + * Revoke the authenticated profile access token. + * @description Returns empty response. + */ delete_profile_access_token: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody?: never; responses: { /** @description The token successfully revoked */ 200: { - headers: { - [name: string]: unknown; - }; - content?: never; + content: never; }; 400: components["responses"]["ErrorBodyResponse"]; }; }; + /** + * Returns at most 20 bids which were submitted after a specific time and chain. + * If no time is provided, the server will return the first bids. + */ get_bids_by_time: { parameters: { query?: { /** @example 2024-05-23T21:26:57.329954Z */ from_time?: string | null; }; - header?: never; path: { /** * @description The chain id to query for @@ -1502,15 +1369,10 @@ export interface operations { */ chain_id: string; }; - cookie?: never; }; - requestBody?: never; responses: { /** @description Paginated list of bids for the specified query */ 200: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["Bids"]; }; @@ -1518,24 +1380,18 @@ export interface operations { 400: components["responses"]["ErrorBodyResponse"]; }; }; + /** Query the status of a specific bid. */ get_bid_status: { parameters: { - query?: never; - header?: never; path: { /** @example op_sepolia */ chain_id: string; /** @example obo3ee3e-58cc-4372-a567-0e02b2c3d479 */ bid_id: string; }; - cookie?: never; }; - requestBody?: never; responses: { 200: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["BidStatus"]; }; @@ -1543,19 +1399,19 @@ export interface operations { 400: components["responses"]["ErrorBodyResponse"]; /** @description Bid was not found */ 404: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["ErrorBodyResponse"]; }; }; }; }; + /** + * Cancel a specific bid. + * @description Bids can only be cancelled if they are in the awaiting signature state. + * Only the user who created the bid can cancel it. + */ post_cancel_bid: { parameters: { - query?: never; - header?: never; path: { /** * @description The chain id of the bid to cancel. @@ -1568,33 +1424,28 @@ export interface operations { */ bid_id: string; }; - cookie?: never; }; - requestBody?: never; responses: { /** @description Bid was cancelled successfully */ 200: { - headers: { - [name: string]: unknown; - }; - content?: never; + content: never; }; 400: components["responses"]["ErrorBodyResponse"]; /** @description Chain id was not found */ 404: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["ErrorBodyResponse"]; }; }; }; }; + /** + * Signs and submits the transaction for the specified quote. + * @description Server will verify the quote and checks if the quote is still valid. + * If the quote is valid, the server will submit the transaction to the blockchain. + */ post_submit_quote: { parameters: { - query?: never; - header?: never; path: { /** * @description The chain id to submit the quote for @@ -1602,7 +1453,6 @@ export interface operations { */ chain_id: string; }; - cookie?: never; }; requestBody: { content: { @@ -1611,9 +1461,6 @@ export interface operations { }; responses: { 200: { - headers: { - [name: string]: unknown; - }; content: { "application/json": components["schemas"]["SubmitQuoteResponse"]; }; diff --git a/sdk/js/src/types.ts b/sdk/js/src/types.ts index d77e1068..f7d1a109 100644 --- a/sdk/js/src/types.ts +++ b/sdk/js/src/types.ts @@ -386,18 +386,18 @@ export type QuoteRequest = { */ specifiedTokenAmount: SpecifiedTokenAmount; /** - * @description The user wallet account + * @description The user wallet account. If not provided, queries for an indicative price. * @example 11111111111111111111111111111111 */ - userWallet: PublicKey; + userWallet?: PublicKey; }; export type QuoteResponse = { chainId: ChainId; - expirationTime: Date; + expirationTime?: Date; inputToken: TokenAmountSvm; outputToken: TokenAmountSvm; - transaction: VersionedTransaction; + transaction?: VersionedTransaction; referenceId: string; };