@@ -603,6 +603,54 @@ impl<Provider: EthereumRpcProvider<Transaction = TransactionRequest> + Send + Sy
603
603
return Err ( ( ) ) ;
604
604
} ;
605
605
606
+ let ( trade_symbol, order_side) = match binance_coin_name. as_str ( ) {
607
+ "USDC" => ( "BNBUSDC" . to_string ( ) , BinanceOrderSide :: BUY ) ,
608
+ "USDT" => ( "BNBUSDT" . to_string ( ) , BinanceOrderSide :: BUY ) ,
609
+ "SOL" => ( "SOLBNB" . to_string ( ) , BinanceOrderSide :: SELL ) ,
610
+ _ => {
611
+ log:: error!( "Unsupported asset: {:?}" , binance_coin_name) ;
612
+ return Err ( ( ) ) ;
613
+ } ,
614
+ } ;
615
+
616
+ let estimated_bnb_receive = estimate_bnb_amount (
617
+ & self . binance_api ,
618
+ & trade_symbol,
619
+ & binance_coin_name,
620
+ from_amount_decimal,
621
+ )
622
+ . await ?;
623
+ let mut payout_amount = match str_to_u256 ( & estimated_bnb_receive, 18 ) {
624
+ Some ( a) => a,
625
+ None => {
626
+ log:: error!(
627
+ "Fail to convert bnb amount {} to U256" ,
628
+ estimated_bnb_receive
629
+ ) ;
630
+ let body = CrossFailBody {
631
+ request_id : intent_id,
632
+ fail_reason :
633
+ "Fail to construct payout request due to U256 conversion error"
634
+ . to_string ( ) ,
635
+ } ;
636
+ self . pumpx_api . cross_fail ( & access_token, body) . await . map_err ( |_| {
637
+ log:: error!( "Failed to notify pumpx-signer" ) ;
638
+ } ) ?;
639
+ return Err ( ( ) ) ;
640
+ } ,
641
+ } ;
642
+
643
+ // Fetch contract balance
644
+ let balance = self . accounting_contract_client . get_balance ( ) . await ?;
645
+ if balance < payout_amount {
646
+ log:: error!(
647
+ "There is not enough balance in the accounting contract, {} < {}" ,
648
+ balance,
649
+ payout_amount
650
+ ) ;
651
+ return Err ( ( ) ) ;
652
+ }
653
+
606
654
let remote_signer = RemoteSigner :: new (
607
655
self . pumpx_signer_client . clone ( ) ,
608
656
pumpx_config. wallet_index ,
@@ -644,16 +692,6 @@ impl<Provider: EthereumRpcProvider<Transaction = TransactionRequest> + Send + Sy
644
692
tx_id = Some ( signature) ;
645
693
}
646
694
647
- let ( trade_symbol, order_side) = match binance_coin_name. as_str ( ) {
648
- "USDC" => ( "BNBUSDC" . to_string ( ) , BinanceOrderSide :: BUY ) ,
649
- "USDT" => ( "BNBUSDT" . to_string ( ) , BinanceOrderSide :: BUY ) ,
650
- "SOL" => ( "SOLBNB" . to_string ( ) , BinanceOrderSide :: SELL ) ,
651
- _ => {
652
- log:: error!( "Unsupported asset: {:?}" , binance_coin_name) ;
653
- return Err ( ( ) ) ;
654
- } ,
655
- } ;
656
-
657
695
let mut bnb_to_receive = "" . to_string ( ) ;
658
696
659
697
if should_wait_for_deposit_confirm {
@@ -797,7 +835,7 @@ impl<Provider: EthereumRpcProvider<Transaction = TransactionRequest> + Send + Sy
797
835
// - `executedQty` indicates the amount of the base-asset bought
798
836
// - `cummulativeQuoteQty`` shows the total amount of the quote-asset spent
799
837
let mut trade_success = false ;
800
- let mut bnb_received = "" . to_string ( ) ;
838
+ let mut bnb_acquired = "" . to_string ( ) ;
801
839
loop {
802
840
let trade_order = self
803
841
. binance_api
@@ -811,7 +849,7 @@ impl<Provider: EthereumRpcProvider<Transaction = TransactionRequest> + Send + Sy
811
849
match trade_order. status {
812
850
BinanceOrderStatus :: FILLED => {
813
851
log:: info!( "Binance order filled" ) ;
814
- bnb_received = match trade_order. side {
852
+ bnb_acquired = match trade_order. side {
815
853
BinanceOrderSide :: BUY => trade_order. executed_qty ,
816
854
BinanceOrderSide :: SELL => trade_order. cummulative_quote_qty ,
817
855
} ;
@@ -868,70 +906,41 @@ impl<Provider: EthereumRpcProvider<Transaction = TransactionRequest> + Send + Sy
868
906
return Err ( ( ) ) ;
869
907
}
870
908
871
- debug ! ( "Total received {} bnb" , bnb_received) ;
872
- } else {
873
- // Estimate BNB payout (simulate spot trade, apply service fee)
874
- let price_str = self
875
- . binance_api
876
- . spot_trading ( )
877
- . get_symbol_price ( & trade_symbol)
878
- . await
879
- . map_err ( |_| {
880
- log:: error!( "Failed to get symbol price for {}" , trade_symbol) ;
881
- } ) ?;
909
+ debug ! ( "Total acquired {} bnb" , bnb_acquired) ;
882
910
883
- let price = if binance_coin_name == "SOL" {
884
- // For SOL, we sell SOL to get BNB, so get SOLBNB price
885
- Decimal :: from_str ( & price_str) . map_err ( |_| {
886
- log:: error!( "Failed to parse symbol price {}" , price_str) ;
887
- } ) ?
888
- } else {
889
- // For USDC/USDT, we buy BNB with USDC/USDT, so get BNBUSDC/BNBUSDT price and invert
890
- let price = Decimal :: from_str ( & price_str) . map_err ( |_| {
891
- log:: error!( "Failed to parse symbol price {}" , price_str) ;
892
- } ) ?;
893
- if price. is_zero ( ) {
894
- log:: error!( "Symbol price is zero for {}" , trade_symbol) ;
911
+ // We need to recalculate payout amount based on the order filled
912
+ payout_amount = match str_to_u256 ( & bnb_acquired, 18 ) {
913
+ Some ( a) => a,
914
+ None => {
915
+ log:: error!(
916
+ "Fail to convert bnb amount {} to U256" ,
917
+ bnb_to_receive
918
+ ) ;
919
+ let body = CrossFailBody {
920
+ request_id : intent_id,
921
+ fail_reason :
922
+ "Fail to construct payout request due to U256 conversion error"
923
+ . to_string ( ) ,
924
+ } ;
925
+ self . pumpx_api . cross_fail ( & access_token, body) . await . map_err (
926
+ |_| {
927
+ log:: error!( "Failed to notify pumpx-signer" ) ;
928
+ } ,
929
+ ) ?;
930
+ // TODO: what to do with user asset?
895
931
return Err ( ( ) ) ;
896
- }
897
- Decimal :: ONE / price
932
+ } ,
898
933
} ;
899
934
900
- let bnb_estimated = from_amount_decimal * price;
901
-
902
- // Apply 0.1% service fee
903
- let service_fee_rate =
904
- Decimal :: from_str ( "0.001" ) . expect ( "Failed to parse service fee rate" ) ;
905
- let decimal_bnb_to_receive =
906
- bnb_estimated * ( Decimal :: ONE - service_fee_rate) ;
907
- bnb_to_receive = decimal_bnb_to_receive. to_string ( ) ;
908
-
909
- debug ! (
910
- "BNB estimated: {}, after 0.1% fee: {}" ,
911
- bnb_estimated, bnb_to_receive
912
- ) ;
935
+ bnb_to_receive = bnb_acquired
936
+ } else {
937
+ // Estimate BNB payout (simulate spot trade, apply service fee)
938
+ bnb_to_receive = estimated_bnb_receive;
913
939
}
914
940
915
941
let payout_address = Address :: from_str ( & to_address) . map_err ( |_| {
916
942
log:: error!( "Failed to parse payout address" ) ;
917
943
} ) ?;
918
- let payout_amount = match str_to_u256 ( & bnb_to_receive, 18 ) {
919
- Some ( a) => a,
920
- None => {
921
- log:: error!( "Fail to convert bnb amount {} to U256" , bnb_to_receive) ;
922
- let body = CrossFailBody {
923
- request_id : intent_id,
924
- fail_reason :
925
- "Fail to construct payout request due to U256 conversion error"
926
- . to_string ( ) ,
927
- } ;
928
- self . pumpx_api . cross_fail ( & access_token, body) . await . map_err ( |_| {
929
- log:: error!( "Failed to notify pumpx-signer" ) ;
930
- } ) ?;
931
- // TODO: what to do with user asset?
932
- return Err ( ( ) ) ;
933
- } ,
934
- } ;
935
944
936
945
debug ! ( "Getting {:?} nonce for payout request" , payout_address) ;
937
946
// 4. Call accounting contract on BSC
@@ -1088,3 +1097,42 @@ fn calculate_amount_in(amount: &str, gas: &str) -> Option<String> {
1088
1097
Some ( ( amount - gas) . to_string ( ) )
1089
1098
}
1090
1099
}
1100
+
1101
+ async fn estimate_bnb_amount (
1102
+ binance_api : & Arc < BinanceApi > ,
1103
+ trade_symbol : & str ,
1104
+ binance_coin_name : & str ,
1105
+ from_amount_decimal : Decimal ,
1106
+ ) -> Result < String , ( ) > {
1107
+ let price_str =
1108
+ binance_api. spot_trading ( ) . get_symbol_price ( trade_symbol) . await . map_err ( |_| {
1109
+ log:: error!( "Failed to get symbol price for {}" , trade_symbol) ;
1110
+ } ) ?;
1111
+
1112
+ let price = if binance_coin_name == "SOL" {
1113
+ // For SOL, we sell SOL to get BNB, so get SOLBNB price
1114
+ Decimal :: from_str ( & price_str) . map_err ( |_| {
1115
+ log:: error!( "Failed to parse symbol price {}" , price_str) ;
1116
+ } ) ?
1117
+ } else {
1118
+ // For USDC/USDT, we buy BNB with USDC/USDT, so get BNBUSDC/BNBUSDT price and invert
1119
+ let price = Decimal :: from_str ( & price_str) . map_err ( |_| {
1120
+ log:: error!( "Failed to parse symbol price {}" , price_str) ;
1121
+ } ) ?;
1122
+ if price. is_zero ( ) {
1123
+ log:: error!( "Symbol price is zero for {}" , trade_symbol) ;
1124
+ return Err ( ( ) ) ;
1125
+ }
1126
+ Decimal :: ONE / price
1127
+ } ;
1128
+
1129
+ let bnb_estimated = from_amount_decimal * price;
1130
+
1131
+ // Apply 0.1% service fee
1132
+ let service_fee_rate = Decimal :: from_str ( "0.001" ) . expect ( "Failed to parse service fee rate" ) ;
1133
+ let decimal_bnb_to_receive = bnb_estimated * ( Decimal :: ONE - service_fee_rate) ;
1134
+
1135
+ debug ! ( "BNB estimated: {}, after 0.1% fee: {}" , bnb_estimated, decimal_bnb_to_receive) ;
1136
+
1137
+ Ok ( decimal_bnb_to_receive. to_string ( ) )
1138
+ }
0 commit comments