diff --git a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs index 1e088f23..dfb0df0e 100644 --- a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs +++ b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs @@ -17,14 +17,11 @@ public async Task GetSwapPriceTest() CurrencySwap currencySwap = new CurrencySwap(_chain); string amount = "1000"; - SwapPrice swapPrice = await currencySwap.GetSwapPrice(new Address(USDC), new Address(USDCe), amount); + SwapPrice swapPrice = await currencySwap.GetSwapPrice(new Address("0xe8db071f698aBA1d60babaE8e08F5cBc28782108"), new Address(USDC), new Address(USDCe), amount); Assert.IsNotNull(swapPrice); Assert.AreEqual(USDCe.ToLower(), swapPrice.currencyAddress.Value.ToLower()); Assert.IsFalse(string.IsNullOrWhiteSpace(swapPrice.price)); - Assert.IsFalse(string.IsNullOrWhiteSpace(swapPrice.maxPrice)); - Assert.IsFalse(string.IsNullOrWhiteSpace(swapPrice.transactionValue)); - Assert.GreaterOrEqual(BigInteger.Parse(swapPrice.transactionValue), BigInteger.Zero); } [Test] @@ -41,9 +38,7 @@ public async Task GetSwapPricesTest() { Assert.IsNotNull(swapPrice); Assert.IsFalse(string.IsNullOrWhiteSpace(swapPrice.price)); - Assert.IsFalse(string.IsNullOrWhiteSpace(swapPrice.maxPrice)); - Assert.IsFalse(string.IsNullOrWhiteSpace(swapPrice.transactionValue)); - Assert.GreaterOrEqual(BigInteger.Parse(swapPrice.transactionValue), BigInteger.Zero); + Assert.NotNull(swapPrice.currencyAddress); } } @@ -81,6 +76,8 @@ public async Task GetSwapQuoteTest() Assert.IsFalse(string.IsNullOrWhiteSpace(swapQuote.transactionValue)); Assert.GreaterOrEqual(BigInteger.Parse(swapQuote.transactionValue), BigInteger.Zero); Assert.IsFalse(string.IsNullOrWhiteSpace(swapQuote.approveData)); + Assert.IsFalse(string.IsNullOrWhiteSpace(swapQuote.amount)); + Assert.IsFalse(string.IsNullOrWhiteSpace(swapQuote.amountMin)); } [Test] @@ -98,7 +95,7 @@ public async Task GetSwapQuoteTest_InsufficientBalance() } catch (Exception e) { - Assert.IsTrue(e.Message.Contains("Insufficient balance")); + Assert.IsTrue(e.Message.Contains("not enough balance for swap")); } } @@ -120,5 +117,143 @@ public async Task GetSwapQuoteTest_FailedToFetchPrice() Assert.IsTrue(e.Message.Contains("Error fetching swap quote")); } } + + [Test] + public async Task TestGetSupportedChains() + { + CurrencySwap currencySwap = new CurrencySwap(_chain); + + try + { + Chain[] supportedChains = await currencySwap.GetSupportedChains(); + Assert.IsNotNull(supportedChains); + Assert.Greater(supportedChains.Length, 0); + } + catch (Exception e) + { + Assert.Fail($"Exception encountered while fetching supported chains: {e.Message}"); + } + } + + [Test] + public async Task TestGetSupportedTokens() + { + CurrencySwap currencySwap = new CurrencySwap(_chain); + + try + { + Token[] supportedTokens = await currencySwap.GetSupportedTokens(new[] { _chain }); + Assert.IsNotNull(supportedTokens); + Assert.Greater(supportedTokens.Length, 0); + } + catch (Exception e) + { + Assert.Fail($"Exception encountered while fetching supported tokens: {e.Message}"); + } + } + + [Test] + public async Task TestGetSupportedTokens_EmptyChains() + { + CurrencySwap currencySwap = new CurrencySwap(_chain); + + try + { + Token[] supportedTokens = await currencySwap.GetSupportedTokens(new Chain[0]); + Assert.Fail("Expected exception but none was thrown"); + } + catch (Exception e) + { + Assert.IsTrue(e.Message.Contains("Error fetching supported tokens:")); + } + } + + [Test] + public async Task TestGetSupportedTokens_NullChains() + { + CurrencySwap currencySwap = new CurrencySwap(_chain); + + try + { + Token[] supportedTokens = await currencySwap.GetSupportedTokens(null); + Assert.Fail("Expected exception but none was thrown"); + } + catch (Exception e) + { + Assert.IsTrue(e.Message.Contains("Error fetching supported tokens:")); + } + } + + [Test] + public async Task TestGetSupportedTokens_AllSupportedChains() + { + CurrencySwap currencySwap = new CurrencySwap(_chain); + + try + { + Chain[] supportedChains = await currencySwap.GetSupportedChains(); + Assert.IsNotNull(supportedChains); + Assert.Greater(supportedChains.Length, 0); + + Token[] supportedTokens = await currencySwap.GetSupportedTokens(supportedChains); + Assert.IsNotNull(supportedTokens); + Assert.Greater(supportedTokens.Length, 0); + } + catch (Exception e) + { + Assert.Fail($"Exception encountered while fetching supported tokens: {e.Message}"); + } + } + + [Test] + public async Task TestGetLifiSwapRoutes() + { + CurrencySwap currencySwap = new CurrencySwap(_chain); + try + { + LifiSwapRoute[] swapRoutes = await currencySwap.GetLifiSwapRoutes( + new Address("0xe8db071f698aBA1d60babaE8e08F5cBc28782108"), new Address(USDC), "1000"); + Assert.NotNull(swapRoutes); + Assert.Greater(swapRoutes.Length, 0); + } + catch (Exception e) + { + Assert.Fail($"Exception encountered while fetching Lifi swap routes: {e.Message}"); + } + } + + [Test] + public async Task TestGetLifiSwapQuote() + { + CurrencySwap currencySwap = new CurrencySwap(_chain); + try + { + LifiSwapQuote swapQuote = await currencySwap.GetLifiSwapQuote( + new Address("0xe8db071f698aBA1d60babaE8e08F5cBc28782108"), new Address(USDC), new Address(USDCe), + "1000"); + Assert.NotNull(swapQuote); + Assert.AreEqual(USDCe.ToLower(), swapQuote.currencyAddress.Value.ToLower()); + } + catch (Exception e) + { + Assert.Fail($"Exception encountered while fetching Lifi swap quote: {e.Message}"); + } + } + + [Test] + public async Task TestGetLifiSwapQuote_NoAmounts() + { + CurrencySwap currencySwap = new CurrencySwap(_chain); + try + { + LifiSwapQuote swapQuote = await currencySwap.GetLifiSwapQuote( + new Address("0xe8db071f698aBA1d60babaE8e08F5cBc28782108"), new Address(USDC), new Address(USDCe)); + Assert.Fail("Expected exception but none was thrown"); + } + catch (Exception e) + { + Assert.IsTrue(e.Message.Contains("Error fetching Lifi swap quote:")); + } + } } } \ No newline at end of file diff --git a/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs b/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs index 5f17a70e..69b67b3e 100644 --- a/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs +++ b/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs @@ -20,6 +20,11 @@ public MockSwapThatGivesPricesInOrder(ulong[] maxPrices) public event Action OnSwapPriceReturn; public event Action OnSwapPriceError; + public Task GetSwapPrice(Address userWallet, Address buyCurrency, Address sellCurrency, string buyAmount) + { + throw new NotImplementedException(); + } + public async Task GetSwapPrice(Address buyCurrency, Address sellCurrency, string buyAmount, uint slippagePercent = ISwap.DefaultSlippagePercentage) { @@ -48,5 +53,20 @@ public Task GetSwapQuote(Address userWallet, Address buyCurrency, Add { throw new NotImplementedException(); } + + public Task GetSupportedChains() + { + throw new NotImplementedException(); + } + + public Task GetSupportedTokens(Chain[] chains) + { + throw new NotImplementedException(); + } + + public Task GetLifiSwapRoutes(Address userWallet, Address buyCurrency, string buyAmount) + { + throw new NotImplementedException(); + } } } \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs new file mode 100644 index 00000000..f5dbc6d6 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs @@ -0,0 +1,167 @@ +using System; +using System.Numerics; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using UnityEngine.Scripting; + +namespace Sequence +{ + [Serializable] + [JsonConverter(typeof(TokenConverter))] + public class Token + { + public Chain Chain; + public Address Contract; + public string TokenId; + public string Symbol; + public string Name; + public BigInteger Decimals; + public BigInteger Price; + public decimal PriceUsd; + public string LogoUri; + + public Token(Chain chain, Address contract, string tokenId = null, string symbol = null, string name = null, + BigInteger decimals = default, decimal priceUsd = default, string logoUri = null, BigInteger price = default) + { + Chain = chain; + Contract = contract; + TokenId = tokenId; + Symbol = symbol; + Name = name; + Decimals = decimals; + PriceUsd = priceUsd; + LogoUri = logoUri; + Price = price; + } + + [Preserve] + [JsonConstructor] + public Token(BigInteger chainId, string contractAddress, string tokenId = null, string symbol = null, + string name = null, BigInteger decimals = default, decimal priceUsd = default, string logoUri = null, BigInteger price = default) + { + Chain = ChainDictionaries.ChainById[chainId.ToString()]; + if (!string.IsNullOrWhiteSpace(contractAddress)) + { + Contract = new Address(contractAddress); + } + TokenId = tokenId; + Symbol = symbol; + Name = name; + Decimals = decimals; + PriceUsd = priceUsd; + LogoUri = logoUri; + Price = price; + } + } + + internal class TokenConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, Token value, JsonSerializer serializer) + { + var jsonObject = new JObject + { + ["chainId"] = ulong.Parse(ChainDictionaries.ChainIdOf[value.Chain]), + ["contractAddress"] = value.Contract.ToString(), + }; + if (value.TokenId != null) + { + jsonObject["tokenId"] = value.TokenId; + } + if (value.Symbol != null) + { + jsonObject["symbol"] = value.Symbol; + } + if (value.Name != null) + { + jsonObject["name"] = value.Name; + } + if (value.Decimals != default) + { + jsonObject["decimals"] = value.Decimals.ToString(); + } + if (value.PriceUsd != default) + { + jsonObject["priceUsd"] = value.PriceUsd; + } + if (value.LogoUri != null) + { + jsonObject["logoUri"] = value.LogoUri; + } + if (value.Price != default) + { + jsonObject["price"] = value.Price.ToString(); + } + + jsonObject.WriteTo(writer); + } + + public override Token ReadJson(JsonReader reader, Type objectType, Token existingValue, + bool hasExistingValue, JsonSerializer serializer) + { + var jsonObject = JObject.Load(reader); + + BigInteger chainId = jsonObject["chainId"]?.Value() ?? 0; + string contractAddress = jsonObject["contractAddress"]?.Value(); + if (string.IsNullOrWhiteSpace(contractAddress)) + { + contractAddress = jsonObject["address"]?.Value(); + } + string tokenId = jsonObject["tokenId"]?.Value(); + string symbol = jsonObject["symbol"]?.Value(); + string name = jsonObject["name"]?.Value(); + BigInteger decimals = (jsonObject["decimals"]?.Value() ?? 18); + decimal priceUsd = jsonObject["priceUsd"]?.Value() ?? default; + string logoUri = jsonObject["logoUri"]?.Value(); + BigInteger price = 0; + JToken priceToken = jsonObject["price"]; + if (priceToken != null && priceToken.Type != JTokenType.Null) + { + string priceStr = priceToken.Value(); + if (!string.IsNullOrWhiteSpace(priceStr) && BigInteger.TryParse(priceStr, out var parsedPrice)) + { + price = parsedPrice; + } + } + + + return new Token(chainId, contractAddress, tokenId, symbol, name, decimals, priceUsd, logoUri, price); + } + } + + public static class TokenExtensions + { + public static bool ContainsToken(this Token[] tokens, Token token) + { + if (tokens == null || token == null) + { + return false; + } + foreach (var t in tokens) + { + if (t.Chain == token.Chain && t.Contract.Equals(token.Contract) && t.TokenId == token.TokenId) + { + return true; + } + } + + return false; + } + + public static bool ContainsToken(this Token[] tokens, Address token) + { + if (tokens == null || token == null) + { + return false; + } + foreach (var t in tokens) + { + if (t.Contract.Equals(token)) + { + return true; + } + } + + return false; + } + } +} diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs.meta new file mode 100644 index 00000000..ea934246 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4f7a9f677198422da3bd8cab76eaa17f +timeCreated: 1745248786 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/DataTypes/GetTokenPricesArgs.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/DataTypes/GetTokenPricesArgs.cs index ff307407..3afa855f 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/DataTypes/GetTokenPricesArgs.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/DataTypes/GetTokenPricesArgs.cs @@ -6,9 +6,9 @@ namespace Sequence [Serializable] internal class GetTokenPricesArgs { - public PriceFeed.Token[] tokens; + public Token[] tokens; - public GetTokenPricesArgs(PriceFeed.Token[] tokens) + public GetTokenPricesArgs(Token[] tokens) { this.tokens = tokens; } diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/DataTypes/TokenPrice.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/DataTypes/TokenPrice.cs index 9dbb2781..a1c5c76c 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/DataTypes/TokenPrice.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/DataTypes/TokenPrice.cs @@ -6,7 +6,7 @@ namespace Sequence [Serializable] public class TokenPrice { - public PriceFeed.Token token; + public Token token; public Price price; public Price price24hChange; public Price floorPrice; @@ -15,7 +15,7 @@ public class TokenPrice public DateTime updatedAt; [Preserve] - public TokenPrice(PriceFeed.Token token, Price price, Price price24hChange, Price floorPrice, Price buyPrice, Price sellPrice, DateTime updatedAt) + public TokenPrice(Token token, Price price, Price price24hChange, Price floorPrice, Price buyPrice, Price sellPrice, DateTime updatedAt) { this.token = token; this.price = price; diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/PriceFeed.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/PriceFeed.cs index b4d7fdbc..1e78f454 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/PriceFeed.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Indexer/PriceFeed.cs @@ -1,58 +1,22 @@ using System; using System.Numerics; using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Sequence.Config; using Sequence.Utils; -using UnityEngine.Scripting; namespace Sequence { public class PriceFeed { - [Serializable] - [JsonConverter(typeof(TokenConverter))] - public class Token + [Obsolete("Use the Token class in the Sequence namespace instead.")] + public class Token : Sequence.Token { - public Chain Chain; - public Address Contract; - - public Token(Chain chain, Address contract) - { - Chain = chain; - Contract = contract; - } - - [Preserve] - [JsonConstructor] - public Token(BigInteger chainId, string contractAddress) + public Token(Chain chain, Address contract, string tokenId = null) : base(chain, contract, tokenId) { - Chain = ChainDictionaries.ChainById[chainId.ToString()]; - Contract = new Address(contractAddress); } - } - private class TokenConverter : JsonConverter - { - public override void WriteJson(JsonWriter writer, Token value, JsonSerializer serializer) + public Token(BigInteger chainId, string contractAddress, string tokenId = null) : base(chainId, contractAddress, tokenId) { - var jsonObject = new JObject - { - ["chainId"] = ulong.Parse(ChainDictionaries.ChainIdOf[value.Chain]), - ["contractAddress"] = value.Contract.ToString(), - }; - jsonObject.WriteTo(writer); - } - - public override Token ReadJson(JsonReader reader, Type objectType, Token existingValue, bool hasExistingValue, JsonSerializer serializer) - { - var jsonObject = JObject.Load(reader); - - BigInteger chainId = jsonObject["chainId"]?.Value() ?? 0; - string contractAddress = jsonObject["contractAddress"]?.Value(); - - return new Token(chainId, contractAddress); } } diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs index 0bef96f3..52ba525f 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs @@ -1,7 +1,10 @@ using System; +using System.Collections.Generic; using System.Numerics; using System.Threading.Tasks; +using Newtonsoft.Json; using Sequence.Utils; +using UnityEngine; namespace Sequence.Marketplace { @@ -14,7 +17,6 @@ public class CurrencySwap : ISwap #else private const string BaseUrl = "https://api.sequence.app/rpc/API"; #endif - private IIndexer _indexer; public CurrencySwap(Chain chain, IHttpClient client = null) { @@ -24,12 +26,41 @@ public CurrencySwap(Chain chain, IHttpClient client = null) client = new HttpClient(); } _client = client; - _indexer = new ChainIndexer(_chain); } public event Action OnSwapPriceReturn; public event Action OnSwapPriceError; - + + public async Task GetSwapPrice(Address userWallet, Address buyCurrency, Address sellCurrency, string buyAmount) + { + try + { + SwapPrice[] swapPrices = await GetSwapPrices(userWallet, buyCurrency, buyAmount); + if (swapPrices == null || swapPrices.Length == 0) + { + throw new Exception("No swap path with sufficient liquidity found"); + } + + foreach (SwapPrice swapPrice in swapPrices) + { + if (swapPrice.currencyAddress.Equals(sellCurrency)) + { + OnSwapPriceReturn?.Invoke(swapPrice); + return swapPrice; + } + } + + throw new Exception("No swap path with sufficient liquidity found"); + } + catch (Exception e) + { + string error = $"Error fetching swap price for buying {buyAmount} of {buyCurrency} with {sellCurrency}: {e.Message}"; + OnSwapPriceError?.Invoke(error); + throw new Exception(error); + } + } + + [Obsolete("Swap provider no longer supports fetching swap prices without provider the user's wallet address")] public async Task GetSwapPrice(Address buyCurrency, Address sellCurrency, string buyAmount, uint slippagePercent = ISwap.DefaultSlippagePercentage) { @@ -62,15 +93,38 @@ public async Task GetSwapPrice(Address buyCurrency, Address sellCurre public async Task GetSwapPrices(Address userWallet, Address buyCurrency, string buyAmount, uint slippagePercentage = ISwap.DefaultSlippagePercentage) { - GetSwapPricesRequest args = new GetSwapPricesRequest(userWallet, buyCurrency, buyAmount, _chain, - slippagePercentage); - string url = BaseUrl.AppendTrailingSlashIfNeeded() + "GetSwapPermit2Prices"; try { - GetSwapPricesResponse response = - await _client.SendRequest(url, args); - OnSwapPricesReturn?.Invoke(response.swapPermit2Prices); - return response.swapPermit2Prices; + LifiSwapRoute[] swapRoutes = await GetLifiSwapRoutes(userWallet, buyCurrency, buyAmount); + List swapPrices = new List(); + foreach (var route in swapRoutes) + { + if (route.fromChainId.ToString() != ChainDictionaries.ChainIdOf[_chain]) + { + continue; + } + if (route.toChainId.ToString() != ChainDictionaries.ChainIdOf[_chain]) + { + continue; + } + + if (!route.toTokens.ContainsToken(buyCurrency)) + { + continue; + } + + foreach (var fromToken in route.fromTokens) + { + swapPrices.Add(new SwapPrice(fromToken.Contract, fromToken.Price.ToString())); + } + } + + if (swapPrices.Count == 0) + { + throw new SystemException($"Unable to find a swap route with the appropriate {nameof(buyCurrency)} address {buyCurrency} in the response from the swap provider"); + } + + return swapPrices.ToArray(); } catch (Exception e) { @@ -90,79 +144,134 @@ public async Task GetSwapQuote(Address userWallet, Address buyCurrenc { try { - await AssertWeHaveSufficientBalance(userWallet, buyCurrency, sellCurrency, buyAmount, - slippagePercentage); + LifiSwapQuote swapQuote = await GetLifiSwapQuote(userWallet, buyCurrency, sellCurrency, buyAmount, null, + includeApprove, slippagePercentage); + SwapQuote quote = new SwapQuote(swapQuote); + OnSwapQuoteReturn?.Invoke(quote); + return quote; } catch (Exception e) { - string error = $"Error fetching swap quote for buying {buyAmount} of {buyCurrency} with {sellCurrency}: {e.Message}"; + string error = + $"Error fetching swap quote for buying {buyAmount} of {buyCurrency} with {sellCurrency}: {e.Message}"; OnSwapQuoteError?.Invoke(error); throw new Exception(error); } - - GetSwapQuoteRequest args = new GetSwapQuoteRequest(userWallet, buyCurrency, sellCurrency, buyAmount, _chain, - slippagePercentage, includeApprove); - string url = BaseUrl.AppendTrailingSlashIfNeeded() + "GetSwapQuoteV2"; + } + + public async Task GetSupportedChains() + { + string url = BaseUrl.AppendTrailingSlashIfNeeded() + "GetLifiChains"; try { - GetSwapQuoteResponse response = - await _client.SendRequest(url, args); - if (response.swapQuote == null) - { - string error = $"Error fetching swap quote for buying {buyAmount} of {buyCurrency} with {sellCurrency}: Unknown error - swap API has returned a null response"; - OnSwapQuoteError?.Invoke(error); - throw new Exception(error); - } - OnSwapQuoteReturn?.Invoke(response.swapQuote); - return response.swapQuote; + LifiSupportedChainsResponse response = + await _client.SendRequest(url, null); + return response.GetChains(); } catch (Exception e) { - string error = - $"Error fetching swap quote for buying {buyAmount} of {buyCurrency} with {sellCurrency}: {e.Message}"; - OnSwapQuoteError?.Invoke(error); + string error = $"Error fetching supported chains: {e.Message}"; throw new Exception(error); } } - private async Task AssertWeHaveSufficientBalance(Address userWallet, Address buyCurrency, Address sellCurrency, - string buyAmount, uint slippagePercentage = ISwap.DefaultSlippagePercentage) + public async Task GetSupportedTokens(Chain[] chains) { - BigInteger required, have; + string url = BaseUrl.AppendTrailingSlashIfNeeded() + "GetLifiTokens"; try { - SwapPrice price = await GetSwapPrice(buyCurrency, sellCurrency, buyAmount, slippagePercentage); - required = BigInteger.Parse(price.maxPrice); + GetLifiTokensResponse response = + await _client.SendRequest(url, new GetLifiTokensRequest(chains)); + return response.tokens; } catch (Exception e) { - throw new Exception($"Error fetching swap price for buying {buyAmount} of {buyCurrency} with {sellCurrency}: {e.Message}"); + string error = $"Error fetching supported tokens: {e.Message}"; + throw new Exception(error); } + } - TokenBalance[] sellCurrencyBalances; + /// + /// Base integration of GetLifiSwapRoutes API + /// In general, it is not recommended to use this method directly - use GetSwapPrice or GetSwapPrices instead + /// + /// + /// + /// + /// + [Obsolete("Use GetSwapPrices or GetSwapPrice instead")] + public async Task GetLifiSwapRoutes(Address userWallet, Address buyCurrency, string buyAmount) + { + GetLifiSwapRoutesArgs args = + new GetLifiSwapRoutesArgs(BigInteger.Parse(ChainDictionaries.ChainIdOf[_chain]), buyCurrency, buyAmount, + userWallet); + string url = BaseUrl.AppendTrailingSlashIfNeeded() + "GetLifiSwapRoutes"; try { - GetTokenBalancesReturn balanceResponse = await _indexer.GetTokenBalances(new GetTokenBalancesArgs(userWallet, sellCurrency)); - sellCurrencyBalances = balanceResponse.balances; + LifiSwapRoutesResponse response = await _client.SendRequest(url, args); + if (response.routes == null || response.routes.Length == 0) + { + throw new Exception("No swap path with sufficient liquidity found"); + } + + ValidateNoExtraToTokens(response.routes); + return response.routes; } catch (Exception e) { - throw new Exception($"Error fetching token balance of {sellCurrency}: {e.Message}"); + string error = $"Error fetching Lifi swap routes: {e.Message}"; + throw new Exception(error); } + } - if (sellCurrencyBalances == null || sellCurrencyBalances.Length == 0) + private void ValidateNoExtraToTokens(LifiSwapRoute[] routes) + { + foreach (var route in routes) { - have = 0; + if (route.toTokens.Length > 1) + { + LifiSwapRoutesResponse response = new LifiSwapRoutesResponse(routes); + string responseJson = JsonConvert.ToString(response); + Debug.LogError($"Received multiple {nameof(route.toTokens)} in response from Lifi: {responseJson}"); + } } - else + } + + /// + /// Base integration of GetLifiSwapQuote API + /// In general, it is not recommended to use this method directly - use GetSwapQuote instead + /// + /// + /// + /// + /// + /// + /// + /// + /// + [Obsolete("Use GetSwapQuote instead")] + public async Task GetLifiSwapQuote(Address userWallet, Address buyCurrency, Address fromCurrency, string buyAmount = null, string fromAmount = null, bool includeApprove = true, ulong slippageInBasisPoints = 50) + { + string url = BaseUrl.AppendTrailingSlashIfNeeded() + "GetLifiSwapQuote"; + try { - have = sellCurrencyBalances[0].balance; - } + GetLifiSwapQuoteParams args = + new GetLifiSwapQuoteParams(ulong.Parse(ChainDictionaries.ChainIdOf[_chain]), userWallet, + fromCurrency, buyCurrency, includeApprove, slippageInBasisPoints, + buyAmount, fromAmount); + GetLifiSwapQuoteResponse response = + await _client.SendRequest(url, new GetLifiSwapQuoteRequest(args)); + if (response.quote == null) + { + throw new Exception("No swap path with sufficient liquidity found"); + } - if (have < required) + return response.quote; + } + catch (Exception e) { - throw new Exception( - $"Insufficient balance of {sellCurrency} to buy {buyAmount} of {buyCurrency}, have {have}, need {required}"); + string error = $"Error fetching Lifi swap quote: {e.Message}"; + throw new Exception(error); } } } diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteParams.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteParams.cs new file mode 100644 index 00000000..29ddfb1a --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteParams.cs @@ -0,0 +1,37 @@ +using System; +using UnityEngine.Scripting; + +namespace Sequence.Marketplace +{ + [Serializable] + internal class GetLifiSwapQuoteParams + { + public ulong chainId; + public string walletAddress; + public string fromTokenAddress; + public string toTokenAddress; + public string fromTokenAmount; + public string toTokenAmount; + public bool includeApprove; + public ulong slippageBps; + + [Preserve] + public GetLifiSwapQuoteParams(ulong chainId, string walletAddress, string fromTokenAddress, string toTokenAddress, bool includeApprove, ulong slippageBps, string fromTokenAmount = null, string toTokenAmount = null) + { + this.chainId = chainId; + this.walletAddress = walletAddress; + this.fromTokenAddress = fromTokenAddress; + this.toTokenAddress = toTokenAddress; + this.fromTokenAmount = fromTokenAmount; + this.toTokenAmount = toTokenAmount; + this.includeApprove = includeApprove; + this.slippageBps = slippageBps; + + if (string.IsNullOrWhiteSpace(toTokenAmount) && string.IsNullOrWhiteSpace(fromTokenAmount)) + { + throw new ArgumentException( + $"Either {nameof(fromTokenAmount)} or {nameof(toTokenAmount)} must be provided."); + } + } + } +} \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteParams.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteParams.cs.meta new file mode 100644 index 00000000..4ac64812 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteParams.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2a201b9cc6674dbaba156c76e2269a7d +timeCreated: 1747156776 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteRequest.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteRequest.cs new file mode 100644 index 00000000..6d8c3a19 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteRequest.cs @@ -0,0 +1,15 @@ +using System; + +namespace Sequence.Marketplace +{ + [Serializable] + internal class GetLifiSwapQuoteRequest + { + public GetLifiSwapQuoteParams @params; + + public GetLifiSwapQuoteRequest(GetLifiSwapQuoteParams @params) + { + this.@params = @params; + } + } +} \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteRequest.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteRequest.cs.meta new file mode 100644 index 00000000..33148569 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteRequest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8dbab6e3b30d45ea9935aac096cb5b5f +timeCreated: 1747161993 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteResponse.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteResponse.cs new file mode 100644 index 00000000..ccbe5001 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteResponse.cs @@ -0,0 +1,17 @@ +using System; +using UnityEngine.Scripting; + +namespace Sequence.Marketplace +{ + [Serializable] + internal class GetLifiSwapQuoteResponse + { + public LifiSwapQuote quote; + + [Preserve] + public GetLifiSwapQuoteResponse(LifiSwapQuote quote) + { + this.quote = quote; + } + } +} \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteResponse.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteResponse.cs.meta new file mode 100644 index 00000000..c7fbe2d5 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteResponse.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f78511f32df445b6861723aa35d68858 +timeCreated: 1747156955 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapRoutesArgs.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapRoutesArgs.cs new file mode 100644 index 00000000..3c09e691 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapRoutesArgs.cs @@ -0,0 +1,24 @@ +using System; +using System.Numerics; +using UnityEngine.Scripting; + +namespace Sequence.Marketplace +{ + [Serializable] + internal class GetLifiSwapRoutesArgs + { + public BigInteger chainId; + public string toTokenAddress; + public string toTokenAmount; + public string walletAddress; + + [Preserve] + public GetLifiSwapRoutesArgs(BigInteger chainId, string toTokenAddress, string toTokenAmount, string walletAddress) + { + this.chainId = chainId; + this.toTokenAddress = toTokenAddress; + this.toTokenAmount = toTokenAmount; + this.walletAddress = walletAddress; + } + } +} \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapRoutesArgs.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapRoutesArgs.cs.meta new file mode 100644 index 00000000..74d241fb --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapRoutesArgs.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e7c67b84befb4be896c29c387e085280 +timeCreated: 1746819271 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensRequest.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensRequest.cs new file mode 100644 index 00000000..227f5a06 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensRequest.cs @@ -0,0 +1,30 @@ +using System; +using System.Numerics; +using Newtonsoft.Json; +using UnityEngine.Scripting; + +namespace Sequence.Marketplace +{ + [Serializable] + public class GetLifiTokensRequest + { + public BigInteger[] chainIds; + + [JsonConstructor] + [Preserve] + public GetLifiTokensRequest(BigInteger[] chainIds) + { + this.chainIds = chainIds; + } + + public GetLifiTokensRequest(Chain[] chains) + { + int length = chains.Length; + chainIds = new BigInteger[length]; + for (int i = 0; i < length; i++) + { + chainIds[i] = BigInteger.Parse(ChainDictionaries.ChainIdOf[chains[i]]); + } + } + } +} \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensRequest.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensRequest.cs.meta new file mode 100644 index 00000000..36c5e19f --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensRequest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2c0c2de0e60345189236b54875874335 +timeCreated: 1745249518 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensResponse.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensResponse.cs new file mode 100644 index 00000000..f47631aa --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensResponse.cs @@ -0,0 +1,17 @@ +using System; +using UnityEngine.Scripting; + +namespace Sequence.Marketplace +{ + [Serializable] + public class GetLifiTokensResponse + { + public Token[] tokens; + + [Preserve] + public GetLifiTokensResponse(Token[] tokens) + { + this.tokens = tokens; + } + } +} \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensResponse.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensResponse.cs.meta new file mode 100644 index 00000000..6dec35fe --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensResponse.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a1bffa4ea37e4ec4b0a1e0d9706f4f62 +timeCreated: 1745249557 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs new file mode 100644 index 00000000..28b1c804 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using UnityEngine.Scripting; + +namespace Sequence.Marketplace +{ + [Serializable] + public class LifiSupportedChainsResponse + { + public BigInteger[] chains; + + [Preserve] + public LifiSupportedChainsResponse(BigInteger[] chains) + { + this.chains = chains; + } + + public Chain[] GetChains() + { + int length = chains.Length; + List result = new List(); + for (int i = 0; i < length; i++) + { + string chainId = chains[i].ToString(); + if (ChainDictionaries.ChainById.TryGetValue(chainId, out Chain chain)) // There may be chains that aren't supported by Sequence + { + result.Add(chain); + } + } + return result.ToArray(); + } + } +} \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs.meta new file mode 100644 index 00000000..03166fb8 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7317e5bccdf84916b9657202923b4a4d +timeCreated: 1745249460 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapQuote.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapQuote.cs new file mode 100644 index 00000000..7fbacfbe --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapQuote.cs @@ -0,0 +1,49 @@ +using Newtonsoft.Json; +using UnityEngine.Scripting; + +namespace Sequence.Marketplace +{ + public class LifiSwapQuote + { + public Address currencyAddress; + public string currencyBalance; + public string price; + public string maxPrice; // Guaranteed price for the swap (including slippage) + public Address to; + public string transactionData; + public string transactionValue; + public string approveData; // Included only if includeApprove is true in request parameters + public string amount; + public string amountMin; + + public LifiSwapQuote(Address currencyAddress, string currencyBalance, string price, string maxPrice, Address to, string transactionData, string transactionValue, string approveData, string amount, string amountMin) + { + this.currencyAddress = currencyAddress; + this.currencyBalance = currencyBalance; + this.price = price; + this.maxPrice = maxPrice; + this.to = to; + this.transactionData = transactionData; + this.transactionValue = transactionValue; + this.approveData = approveData; + this.amount = amount; + this.amountMin = amountMin; + } + + [JsonConstructor] + [Preserve] + public LifiSwapQuote(string currencyAddress, string currencyBalance, string price, string maxPrice, string to, string transactionData, string transactionValue, string approveData, string amount, string amountMin) + { + this.currencyAddress = new Address(currencyAddress); + this.currencyBalance = currencyBalance; + this.price = price; + this.maxPrice = maxPrice; + this.to = new Address(to); + this.transactionData = transactionData; + this.transactionValue = transactionValue; + this.approveData = approveData; + this.amount = amount; + this.amountMin = amountMin; + } + } +} \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapQuote.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapQuote.cs.meta new file mode 100644 index 00000000..010c0e88 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapQuote.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e03382a0985b44d480715c4bd8e27546 +timeCreated: 1747157602 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoute.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoute.cs new file mode 100644 index 00000000..1a0ce12c --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoute.cs @@ -0,0 +1,23 @@ +using System; +using UnityEngine.Scripting; + +namespace Sequence.Marketplace +{ + [Serializable] + public class LifiSwapRoute + { + public ulong fromChainId; + public ulong toChainId; + public Token[] fromTokens; + public Token[] toTokens; + + [Preserve] + public LifiSwapRoute(ulong fromChainId, ulong toChainId, Token[] fromTokens, Token[] toTokens) + { + this.fromChainId = fromChainId; + this.toChainId = toChainId; + this.fromTokens = fromTokens; + this.toTokens = toTokens; + } + } +} \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoute.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoute.cs.meta new file mode 100644 index 00000000..5c26882d --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6f5f843e3ae543f9a1e42c0d880c10bc +timeCreated: 1746818292 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoutesResponse.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoutesResponse.cs new file mode 100644 index 00000000..f39a23f0 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoutesResponse.cs @@ -0,0 +1,17 @@ +using System; +using UnityEngine.Scripting; + +namespace Sequence.Marketplace +{ + [Serializable] + internal class LifiSwapRoutesResponse + { + public LifiSwapRoute[] routes; + + [Preserve] + public LifiSwapRoutesResponse(LifiSwapRoute[] routes) + { + this.routes = routes; + } + } +} \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoutesResponse.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoutesResponse.cs.meta new file mode 100644 index 00000000..32889e63 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoutesResponse.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3853920930b1413b813d1d1a4654bdf0 +timeCreated: 1746818987 \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/SwapPrice.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/SwapPrice.cs index d550ebc1..9a7f0810 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/SwapPrice.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/SwapPrice.cs @@ -7,12 +7,14 @@ namespace Sequence.Marketplace public class SwapPrice { public Address currencyAddress; + [Obsolete("currencyBalance is no longer supported by swap provider")] public string currencyBalance; public string price; + [Obsolete("To retrieve the max price, please request a Swap Quote instead")] public string maxPrice; // Guaranteed price for the swap (including slippage) + [Obsolete("To retrieve the transaction value, please request a Swap Quote instead")] public string transactionValue; - - [Preserve] + public SwapPrice(Address currencyAddress, string currencyBalance, string price, string maxPrice, string transactionValue) { this.currencyAddress = currencyAddress; @@ -21,5 +23,11 @@ public SwapPrice(Address currencyAddress, string currencyBalance, string price, this.maxPrice = maxPrice; this.transactionValue = transactionValue; } + + public SwapPrice(Address currencyAddress, string price) + { + this.currencyAddress = currencyAddress; + this.price = price; + } } } \ No newline at end of file diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/SwapQuote.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/SwapQuote.cs index fcdcadcd..892a9a51 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/SwapQuote.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/SwapQuote.cs @@ -16,6 +16,8 @@ public class SwapQuote public string transactionData; public string transactionValue; public string approveData; // Supplied when includeApprove is true + public string amount; + public string amountMin; [Preserve] public SwapQuote(Address currencyAddress, string currencyBalance, string price, string maxPrice, Address to, string transactionData, string transactionValue, string approveData) @@ -29,6 +31,20 @@ public SwapQuote(Address currencyAddress, string currencyBalance, string price, this.transactionValue = transactionValue; this.approveData = approveData; } + + public SwapQuote(LifiSwapQuote quote) + { + this.currencyAddress = quote.currencyAddress; + this.currencyBalance = quote.currencyBalance; + this.price = quote.price; + this.maxPrice = quote.maxPrice; + this.to = quote.to; + this.transactionData = quote.transactionData; + this.transactionValue = quote.transactionValue; + this.approveData = quote.approveData; + this.amount = quote.amount; + this.amountMin = quote.amountMin; + } } public static class SwapQuoteExtensions diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs index 647f72c0..b6dd689f 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs @@ -10,6 +10,16 @@ public interface ISwap public event Action OnSwapPriceReturn; public event Action OnSwapPriceError; + /// + /// Get the current SwapPrice for a given buyCurrency, sellCurrency, and buyAmount + /// + /// + /// + /// + /// + /// + public Task GetSwapPrice(Address userWallet, Address buyCurrency, Address sellCurrency, string buyAmount); + /// /// Get the current SwapPrice for a given buyCurrency, sellCurrency, and buyAmount /// @@ -18,6 +28,7 @@ public interface ISwap /// /// the maximum slippage percentage allowed /// + [Obsolete("Swap provider no longer supports fetching swap prices without provider the user's wallet address")] public Task GetSwapPrice(Address buyCurrency, Address sellCurrency, string buyAmount, uint slippagePercent = DefaultSlippagePercentage); public event Action OnSwapPricesReturn; @@ -48,5 +59,18 @@ public interface ISwap /// public Task GetSwapQuote(Address userWallet, Address buyCurrency, Address sellCurrency, string buyAmount, bool includeApprove, uint slippagePercentage = DefaultSlippagePercentage); + + /// + /// Get a Chain[] of all supported chains for the swap provider + /// + /// + public Task GetSupportedChains(); + + /// + /// Get the supported tokens by the swap provider for a given set of chains + /// + /// + /// + public Task GetSupportedTokens(Chain[] chains); } } \ No newline at end of file diff --git a/Packages/Sequence-Unity/package.json b/Packages/Sequence-Unity/package.json index 3dbf8cb3..1993eee6 100644 --- a/Packages/Sequence-Unity/package.json +++ b/Packages/Sequence-Unity/package.json @@ -1,6 +1,6 @@ { "name": "xyz.0xsequence.waas-unity", - "version": "4.1.0", + "version": "4.1.1", "displayName": "Sequence Embedded Wallet SDK", "description": "A Unity SDK for Sequence APIs", "unity": "2021.3",