-
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 21 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,19 @@ | ||
| 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/" | ||
|
|
||
| [dex.credentials] | ||
| # 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,78 @@ | ||
| 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. | ||
| 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,163 @@ | ||
| //! DTOs for the Bitget swap API. | ||
| //! Full documentation: https://web3.bitget.com/en/docs/swap/ | ||
|
|
||
| use { | ||
| crate::domain::{dex, eth}, | ||
| bigdecimal::{BigDecimal, ToPrimitive}, | ||
| serde::{Deserialize, Serialize}, | ||
| serde_with::serde_as, | ||
| }; | ||
|
|
||
| /// Bitget chain name used in API requests. | ||
| #[derive(Clone, Copy, Serialize)] | ||
| pub enum ChainName { | ||
| #[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 swap request with enriched response (`requestMod = "rich"`). | ||
| /// | ||
| /// 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 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 - hardcoded to "bgwevmaggregator" for EVM chains. | ||
| pub market: String, | ||
|
|
||
| /// Slippage tolerance as a percentage (e.g. 1.0 for 1%). | ||
| pub slippage: f64, | ||
|
|
||
| /// Request mode - "rich" returns quote data alongside swap calldata. | ||
| pub request_mod: String, | ||
|
|
||
| /// 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, | ||
| slippage: &dex::Slippage, | ||
| 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: "bgwevmaggregator".to_string(), | ||
| slippage: slippage.as_factor().to_f64().unwrap_or_default() * 100.0, | ||
| request_mod: "rich".to_string(), | ||
| fee_rate: Some(0.0), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// A Bitget API enriched swap response (returned when `requestMod = "rich"`). | ||
| #[serde_as] | ||
| #[derive(Deserialize, Clone, Debug)] | ||
| #[serde(rename_all = "camelCase")] | ||
| #[allow(dead_code)] | ||
| pub struct SwapResponse { | ||
| /// Output amount in decimal units. | ||
| #[serde_as(as = "serde_with::DisplayFromStr")] | ||
| pub out_amount: BigDecimal, | ||
|
|
||
| /// Minimum output amount after slippage (computed by API). | ||
| #[serde_as(as = "serde_with::DisplayFromStr")] | ||
| pub min_amount: BigDecimal, | ||
|
|
||
| /// Gas fee information. | ||
| pub gas_fee: GasFee, | ||
|
|
||
| /// Transaction data for the swap. | ||
| pub swap_transaction: SwapTransaction, | ||
| } | ||
|
|
||
| #[serde_as] | ||
| #[derive(Deserialize, Clone, Debug)] | ||
| #[serde(rename_all = "camelCase")] | ||
| pub struct GasFee { | ||
| #[serde_as(as = "serde_with::DisplayFromStr")] | ||
| pub gas_limit: u64, | ||
| } | ||
|
|
||
| #[derive(Deserialize, Clone, Debug)] | ||
| pub struct SwapTransaction { | ||
| /// Contract address (router/spender). | ||
| pub to: eth::Address, | ||
| /// Hex-encoded calldata with "0x" prefix. | ||
| pub data: String, | ||
| } | ||
|
|
||
| impl SwapTransaction { | ||
| /// Decode the hex-encoded calldata (with "0x" prefix) to bytes. | ||
| pub fn decode_calldata(&self) -> Result<Vec<u8>, hex::FromHexError> { | ||
| let hex_str = self.data.strip_prefix("0x").unwrap_or(&self.data); | ||
| 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.