-
Notifications
You must be signed in to change notification settings - Fork 12
BitGet solver #203
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
Closed
Closed
BitGet solver #203
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
26c0ae6
Init
squadgazzz 7d03510
Set TO amount
squadgazzz 20e214b
Better formats
squadgazzz 1adba62
Comment
squadgazzz 74887c1
Partner code config
squadgazzz 7467167
Constants
squadgazzz 9c41769
Refactor
squadgazzz b295fa1
Correct partner code
squadgazzz c2da065
Correct API url
squadgazzz 5e4bc52
Simplify
squadgazzz f6d4d8e
Redundant change
squadgazzz 8139430
Fixed formats
squadgazzz 1369bae
Drop slippage
squadgazzz c95570c
Better types
squadgazzz 7972884
Polygon & ArbitrumOne
squadgazzz 3e494a8
Nits
squadgazzz 0f219b4
Redundant change
squadgazzz 3c1b9a8
Leftovers
squadgazzz 543bed7
Structured config
squadgazzz ffac752
No quote request anymore
squadgazzz eacdd91
Nit
squadgazzz ecd108c
BadRequest
squadgazzz adc171d
Use out amount
squadgazzz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| node-url = "http://localhost:8545" | ||
|
|
||
| [dex] | ||
| # Specify which chain to use, 1 for Ethereum. | ||
| # Supported chains: eth (1), bsc (56), base (8453) | ||
| chain-id = "1" | ||
|
|
||
| # Optionally specify a custom Bitget swap API endpoint | ||
| # endpoint = "https://bopenapi.bgwapi.io/bgw-pro/swapx/pro/" | ||
|
|
||
| # Bitget API key (obtain from Bitget integration team) | ||
| api-key = "$BITGET_API_KEY" | ||
|
|
||
| # Bitget API secret for signing requests | ||
| api-secret = "$BITGET_API_SECRET" | ||
|
|
||
| # Partner code sent in the Partner-Code header (defaults to "Cowswap") | ||
| # partner-code = "Cowswap" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| use { | ||
| crate::{ | ||
| domain::eth, | ||
| infra::{config::dex::file, dex::bitget}, | ||
| }, | ||
| serde::Deserialize, | ||
| serde_with::serde_as, | ||
| std::path::Path, | ||
| }; | ||
|
|
||
| #[serde_as] | ||
| #[derive(Deserialize)] | ||
| #[serde(rename_all = "kebab-case", deny_unknown_fields)] | ||
| struct Config { | ||
| /// The base URL for the Bitget swap API. | ||
| #[serde(default = "default_endpoint")] | ||
| #[serde_as(as = "serde_with::DisplayFromStr")] | ||
| endpoint: reqwest::Url, | ||
|
|
||
| /// Chain ID used to automatically determine contract addresses. | ||
| chain_id: eth::ChainId, | ||
|
|
||
| /// Bitget API credentials. | ||
| #[serde(flatten)] | ||
squadgazzz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| credentials: BitgetCredentialsConfig, | ||
|
|
||
| /// Partner code sent in the `Partner-Code` header. | ||
| #[serde(default = "default_partner_code")] | ||
| partner_code: String, | ||
| } | ||
|
|
||
| #[derive(Deserialize)] | ||
| #[serde(rename_all = "kebab-case", deny_unknown_fields)] | ||
| struct BitgetCredentialsConfig { | ||
| /// Bitget API key. | ||
| api_key: String, | ||
|
|
||
| /// Bitget API secret for signing requests. | ||
| api_secret: String, | ||
| } | ||
|
|
||
| #[allow(clippy::from_over_into)] | ||
| impl Into<bitget::BitgetCredentialsConfig> for BitgetCredentialsConfig { | ||
| fn into(self) -> bitget::BitgetCredentialsConfig { | ||
| bitget::BitgetCredentialsConfig { | ||
| api_key: self.api_key, | ||
| api_secret: self.api_secret, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| fn default_partner_code() -> String { | ||
| "cowswap".to_string() | ||
| } | ||
|
|
||
| fn default_endpoint() -> reqwest::Url { | ||
| bitget::DEFAULT_ENDPOINT.parse().unwrap() | ||
| } | ||
|
|
||
| /// Load the Bitget solver configuration from a TOML file. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// This method panics if the config is invalid or on I/O errors. | ||
| pub async fn load(path: &Path) -> super::Config { | ||
| let (base, config) = file::load::<Config>(path).await; | ||
|
|
||
| super::Config { | ||
| bitget: bitget::Config { | ||
| endpoint: config.endpoint, | ||
| chain_id: config.chain_id, | ||
| credentials: config.credentials.into(), | ||
| partner_code: config.partner_code, | ||
| block_stream: base.block_stream.clone(), | ||
| settlement_contract: base.contracts.settlement, | ||
| }, | ||
| base, | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| pub mod file; | ||
|
|
||
| pub struct Config { | ||
| pub bitget: crate::infra::dex::bitget::Config, | ||
| pub base: super::Config, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| pub mod balancer; | ||
| pub mod bitget; | ||
| mod file; | ||
| pub mod okx; | ||
| pub mod oneinch; | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,205 @@ | ||
| //! DTOs for the Bitget swap API. | ||
| //! Full documentation: https://web3.bitget.com/en/docs/swap/ | ||
|
|
||
| use { | ||
| crate::domain::{dex, eth}, | ||
| bigdecimal::BigDecimal, | ||
| serde::{Deserialize, Serialize}, | ||
| serde_with::serde_as, | ||
| }; | ||
|
|
||
| /// Bitget chain name used in API requests. | ||
| #[derive(Clone, Copy, Serialize)] | ||
| pub enum ChainName { | ||
squadgazzz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| #[serde(rename = "eth")] | ||
| Mainnet, | ||
| #[serde(rename = "bsc")] | ||
| Bnb, | ||
| #[serde(rename = "base")] | ||
| Base, | ||
| #[serde(rename = "polygon")] | ||
| Polygon, | ||
| #[serde(rename = "arb")] | ||
| ArbitrumOne, | ||
| } | ||
|
|
||
| impl ChainName { | ||
| pub fn new(chain_id: eth::ChainId) -> Self { | ||
| match chain_id { | ||
| eth::ChainId::Mainnet => Self::Mainnet, | ||
| eth::ChainId::Bnb => Self::Bnb, | ||
| eth::ChainId::Base => Self::Base, | ||
| eth::ChainId::Polygon => Self::Polygon, | ||
| eth::ChainId::ArbitrumOne => Self::ArbitrumOne, | ||
| _ => panic!("unsupported Bitget chain: {chain_id:?}"), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// A Bitget API quote request. | ||
| /// | ||
| /// See [API](https://web3.bitget.com/en/docs/swap/) | ||
| /// documentation for more detailed information on each parameter. | ||
| #[serde_as] | ||
| #[derive(Clone, Serialize)] | ||
| #[serde(rename_all = "camelCase")] | ||
| pub struct QuoteRequest { | ||
| /// Source token contract address (empty string for native token). | ||
squadgazzz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| pub from_contract: eth::Address, | ||
|
|
||
| /// Input amount in human-readable decimal units (e.g. "1" for 1 WETH). | ||
| #[serde_as(as = "serde_with::DisplayFromStr")] | ||
| pub from_amount: BigDecimal, | ||
|
|
||
| /// Source chain name (e.g., "eth", "bsc", "base"). | ||
| pub from_chain: ChainName, | ||
|
|
||
| /// Debit address for gas estimation. | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub from_address: Option<eth::Address>, | ||
|
|
||
| /// Target token contract address (empty string for native token). | ||
squadgazzz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| pub to_contract: eth::Address, | ||
|
|
||
| /// Target chain name (same as from_chain for same-chain swaps). | ||
| pub to_chain: ChainName, | ||
|
||
|
|
||
| /// Whether to estimate gas. | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub estimate_gas: Option<bool>, | ||
| } | ||
|
|
||
| impl QuoteRequest { | ||
| pub fn from_order( | ||
| order: &dex::Order, | ||
| chain_name: ChainName, | ||
| settlement_contract: eth::Address, | ||
| sell_decimals: u8, | ||
| ) -> Self { | ||
| Self { | ||
| from_contract: order.sell.0, | ||
| from_amount: super::wei_to_decimal(order.amount.get(), sell_decimals), | ||
| from_chain: chain_name, | ||
| to_contract: order.buy.0, | ||
| to_chain: chain_name, | ||
| from_address: Some(settlement_contract), | ||
| estimate_gas: Some(true), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// A Bitget API swap (calldata) request. | ||
| #[serde_as] | ||
| #[derive(Clone, Serialize)] | ||
| #[serde(rename_all = "camelCase")] | ||
| pub struct SwapRequest { | ||
| /// Source token contract address. | ||
| pub from_contract: eth::Address, | ||
|
|
||
| /// Input amount in human-readable decimal units (e.g. "1" for 1 WETH). | ||
| #[serde_as(as = "serde_with::DisplayFromStr")] | ||
| pub from_amount: BigDecimal, | ||
|
|
||
| /// Source chain name. | ||
| pub from_chain: ChainName, | ||
|
|
||
| /// Target token contract address. | ||
| pub to_contract: eth::Address, | ||
|
|
||
| /// Target chain name. | ||
| pub to_chain: ChainName, | ||
|
|
||
| /// Debit address. | ||
| pub from_address: eth::Address, | ||
|
|
||
| /// Recipient address. | ||
| pub to_address: eth::Address, | ||
|
|
||
| /// Optimal channel from quote API. | ||
| pub market: String, | ||
|
|
||
| /// Minimum amount to receive in decimal units. When provided, the | ||
| /// `slippage` field is ignored by the API. By setting this explicitly we | ||
| /// ensure the generated calldata will revert on-chain if the output drops | ||
| /// below this value — avoiding a race between quote and swap calls. | ||
| #[serde_as(as = "serde_with::DisplayFromStr")] | ||
| pub to_min_amount: BigDecimal, | ||
|
|
||
| /// Fee rate in per mille. 0 for no fee. | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub fee_rate: Option<f64>, | ||
| } | ||
|
|
||
| impl SwapRequest { | ||
| pub fn from_order( | ||
| order: &dex::Order, | ||
| chain_name: ChainName, | ||
| settlement_contract: eth::Address, | ||
| market: String, | ||
| to_min_amount: BigDecimal, | ||
| sell_decimals: u8, | ||
| ) -> Self { | ||
| Self { | ||
| from_contract: order.sell.0, | ||
| from_amount: super::wei_to_decimal(order.amount.get(), sell_decimals), | ||
| from_chain: chain_name, | ||
| to_contract: order.buy.0, | ||
| to_chain: chain_name, | ||
| from_address: settlement_contract, | ||
| to_address: settlement_contract, | ||
| market, | ||
| to_min_amount, | ||
| fee_rate: Some(0.0), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// A Bitget API quote response. | ||
| #[serde_as] | ||
| #[derive(Deserialize, Clone, Debug)] | ||
| #[serde(rename_all = "camelCase")] | ||
| pub struct QuoteResponse { | ||
squadgazzz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// Output amount in decimal units (e.g. "1964.365496"). | ||
| #[serde_as(as = "serde_with::DisplayFromStr")] | ||
| pub to_amount: BigDecimal, | ||
|
|
||
| /// Channel name (e.g., "uniswap.v3"). | ||
| pub market: String, | ||
|
|
||
| /// Estimated gas limit. | ||
| #[serde(default)] | ||
| pub gas_limit: u64, | ||
| } | ||
|
|
||
| /// A Bitget API swap response. | ||
| #[derive(Deserialize, Clone, Debug)] | ||
| #[serde(rename_all = "camelCase")] | ||
| pub struct SwapResponse { | ||
| /// Contract address to interact with (EVM chains only). | ||
| /// This is the router/spender address. | ||
| pub contract: eth::Address, | ||
|
|
||
| /// Hex-encoded calldata for the transaction (with "0x" prefix). | ||
| pub calldata: String, | ||
| } | ||
|
|
||
| impl SwapResponse { | ||
| /// Decode the hex-encoded calldata (with "0x" prefix) to bytes. | ||
| pub fn decode_calldata(&self) -> Result<Vec<u8>, hex::FromHexError> { | ||
| let hex_str = self.calldata.strip_prefix("0x").unwrap_or(&self.calldata); | ||
| hex::decode(hex_str) | ||
| } | ||
| } | ||
|
|
||
| /// A Bitget API response wrapper. | ||
| /// | ||
| /// On success `status` is 0 and `data` contains the result. | ||
| /// On error `status` is non-zero and `data` is null. | ||
| #[derive(Deserialize, Clone, Debug)] | ||
| pub struct Response<T> { | ||
| /// Response status code (0 = success). | ||
| pub status: i64, | ||
|
|
||
| /// Response data — `None` when the API returns an error. | ||
| pub data: Option<T>, | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.