1+ using System ;
2+ using System . Numerics ;
3+ using System . Threading . Tasks ;
4+ using Sequence . Utils ;
5+
6+ namespace Sequence . Marketplace
7+ {
8+ public class CurrencySwap : ISwap
9+ {
10+ private Chain _chain ;
11+ private IHttpClient _client ;
12+ private const string BaseUrl = "https://api.sequence.app/rpc/API" ;
13+ private IIndexer _indexer ;
14+
15+ public CurrencySwap ( Chain chain , IHttpClient client = null )
16+ {
17+ _chain = chain ;
18+ if ( client == null )
19+ {
20+ client = new HttpClient ( ) ;
21+ }
22+ _client = client ;
23+ _indexer = new ChainIndexer ( _chain ) ;
24+ }
25+
26+ public event Action < SwapPrice > OnSwapPriceReturn ;
27+ public event Action < string > OnSwapPriceError ;
28+
29+ public async Task < SwapPrice > GetSwapPrice ( Address buyCurrency , Address sellCurrency , string buyAmount ,
30+ uint slippagePercent = ISwap . DefaultSlippagePercentage )
31+ {
32+ GetSwapPriceRequest args = new GetSwapPriceRequest ( buyCurrency , sellCurrency , buyAmount , _chain ,
33+ slippagePercent ) ;
34+ string url = BaseUrl . AppendTrailingSlashIfNeeded ( ) + "GetSwapPrice" ;
35+ try
36+ {
37+ GetSwapPriceResponse response =
38+ await _client . SendRequest < GetSwapPriceRequest , GetSwapPriceResponse > ( url , args ) ;
39+ OnSwapPriceReturn ? . Invoke ( response . swapPrice ) ;
40+ return response . swapPrice ;
41+ }
42+ catch ( Exception e )
43+ {
44+ string error =
45+ $ "Error fetching swap price for { buyCurrency } and { sellCurrency } with { nameof ( buyAmount ) } { buyAmount } : { e . Message } ";
46+ OnSwapPriceError ? . Invoke ( error ) ;
47+ throw new Exception ( error ) ;
48+ }
49+ }
50+
51+ public event Action < SwapPrice [ ] > OnSwapPricesReturn ;
52+ public event Action < string > OnSwapPricesError ;
53+
54+ public async Task < SwapPrice [ ] > GetSwapPrices ( Address userWallet , Address buyCurrency , string buyAmount ,
55+ uint slippagePercentage = ISwap . DefaultSlippagePercentage )
56+ {
57+ GetSwapPricesRequest args = new GetSwapPricesRequest ( userWallet , buyCurrency , buyAmount , _chain ,
58+ slippagePercentage ) ;
59+ string url = BaseUrl . AppendTrailingSlashIfNeeded ( ) + "GetSwapPrices" ;
60+ try
61+ {
62+ GetSwapPricesResponse response =
63+ await _client . SendRequest < GetSwapPricesRequest , GetSwapPricesResponse > ( url , args ) ;
64+ OnSwapPricesReturn ? . Invoke ( response . swapPrices ) ;
65+ return response . swapPrices ;
66+ }
67+ catch ( Exception e )
68+ {
69+ string error =
70+ $ "Error fetching swap prices for { buyCurrency } with { nameof ( buyAmount ) } { buyAmount } : { e . Message } ";
71+ OnSwapPricesError ? . Invoke ( error ) ;
72+ throw new Exception ( error ) ;
73+ }
74+ }
75+
76+ public event Action < SwapQuote > OnSwapQuoteReturn ;
77+ public event Action < string > OnSwapQuoteError ;
78+
79+ public async Task < SwapQuote > GetSwapQuote ( Address userWallet , Address buyCurrency , Address sellCurrency ,
80+ string buyAmount , bool includeApprove ,
81+ uint slippagePercentage = ISwap . DefaultSlippagePercentage )
82+ {
83+ try
84+ {
85+ await AssertWeHaveSufficientBalance ( userWallet , buyCurrency , sellCurrency , buyAmount ,
86+ slippagePercentage ) ;
87+ }
88+ catch ( Exception e )
89+ {
90+ string error = $ "Error fetching swap quote for buying { buyAmount } of { buyCurrency } with { sellCurrency } : { e . Message } ";
91+ OnSwapQuoteError ? . Invoke ( error ) ;
92+ throw new Exception ( error ) ;
93+ }
94+
95+ GetSwapQuoteRequest args = new GetSwapQuoteRequest ( userWallet , buyCurrency , sellCurrency , buyAmount , _chain ,
96+ slippagePercentage , includeApprove ) ;
97+ string url = BaseUrl . AppendTrailingSlashIfNeeded ( ) + "GetSwapQuote" ;
98+ try
99+ {
100+ GetSwapQuoteResponse response =
101+ await _client . SendRequest < GetSwapQuoteRequest , GetSwapQuoteResponse > ( url , args ) ;
102+ if ( response . swapQuote == null )
103+ {
104+ string error = $ "Error fetching swap quote for buying { buyAmount } of { buyCurrency } with { sellCurrency } : Unknown error - swap API has returned a null response";
105+ OnSwapQuoteError ? . Invoke ( error ) ;
106+ throw new Exception ( error ) ;
107+ }
108+ OnSwapQuoteReturn ? . Invoke ( response . swapQuote ) ;
109+ return response . swapQuote ;
110+ }
111+ catch ( Exception e )
112+ {
113+ string error =
114+ $ "Error fetching swap quote for buying { buyAmount } of { buyCurrency } with { sellCurrency } : { e . Message } ";
115+ OnSwapQuoteError ? . Invoke ( error ) ;
116+ throw new Exception ( error ) ;
117+ }
118+ }
119+
120+ private async Task AssertWeHaveSufficientBalance ( Address userWallet , Address buyCurrency , Address sellCurrency ,
121+ string buyAmount , uint slippagePercentage = ISwap . DefaultSlippagePercentage )
122+ {
123+ BigInteger required , have ;
124+ try
125+ {
126+ SwapPrice price = await GetSwapPrice ( buyCurrency , sellCurrency , buyAmount , slippagePercentage ) ;
127+ required = BigInteger . Parse ( price . maxPrice) ;
128+ }
129+ catch ( Exception e )
130+ {
131+ throw new Exception ( $ "Error fetching swap price for buying { buyAmount } of { buyCurrency } with { sellCurrency } : { e . Message } ") ;
132+ }
133+
134+ TokenBalance [ ] sellCurrencyBalances ;
135+ try
136+ {
137+ GetTokenBalancesReturn balanceResponse = await _indexer . GetTokenBalances ( new GetTokenBalancesArgs ( userWallet , sellCurrency ) ) ;
138+ sellCurrencyBalances = balanceResponse . balances ;
139+ }
140+ catch ( Exception e )
141+ {
142+ throw new Exception ( $ "Error fetching token balance of { sellCurrency } : { e . Message } ") ;
143+ }
144+
145+ if ( sellCurrencyBalances == null || sellCurrencyBalances . Length == 0 )
146+ {
147+ have = 0 ;
148+ }
149+ else
150+ {
151+ have = sellCurrencyBalances [ 0 ] . balance ;
152+ }
153+
154+ if ( have < required )
155+ {
156+ throw new Exception (
157+ $ "Insufficient balance of { sellCurrency } to buy { buyAmount } of { buyCurrency } , have { have } , need { required } ") ;
158+ }
159+ }
160+ }
161+ }
0 commit comments