From 3ab4bb791bb7c277ccbab4660c3dd795cffa7aef Mon Sep 17 00:00:00 2001 From: Quinn Purdy Date: Mon, 21 Apr 2025 11:59:58 -0400 Subject: [PATCH 1/8] Add implementation of GetLifiChains and GetLifiTokens endpoints - these are useful to check which chains and tokens per chain are enabled by the new swap service provider, Lifi. Additionally, refactored PriceFeed.Token to a more generic class so it can be reused. --- .../Marketplace/CurrencySwapTests.cs | 87 +++++++++++++++++++ .../Mocks/MockSwapThatGivesPricesInOrder.cs | 10 +++ .../Sequence/SequenceSDK/Ethereum/Token.cs | 63 ++++++++++++++ .../SequenceSDK/Ethereum/Token.cs.meta | 3 + .../Indexer/DataTypes/GetTokenPricesArgs.cs | 4 +- .../Indexer/DataTypes/TokenPrice.cs | 4 +- .../Sequence/SequenceSDK/Indexer/PriceFeed.cs | 44 +--------- .../SequenceSDK/Marketplace/CurrencySwap.cs | 32 +++++++ .../DataTypes/GetLifiTokensRequest.cs | 30 +++++++ .../DataTypes/GetLifiTokensRequest.cs.meta | 3 + .../DataTypes/GetLifiTokensResponse.cs | 17 ++++ .../DataTypes/GetLifiTokensResponse.cs.meta | 3 + .../DataTypes/LifiSupportedChainsResponse.cs | 29 +++++++ .../LifiSupportedChainsResponse.cs.meta | 3 + .../Sequence/SequenceSDK/Marketplace/ISwap.cs | 13 +++ Packages/Sequence-Unity/package.json | 2 +- 16 files changed, 302 insertions(+), 45 deletions(-) create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs.meta create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensRequest.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensRequest.cs.meta create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensResponse.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiTokensResponse.cs.meta create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs.meta diff --git a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs index 1e088f234..fb405b3d4 100644 --- a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs +++ b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs @@ -120,5 +120,92 @@ 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.AreEqual(0, supportedTokens.Length); + } + catch (Exception e) + { + Assert.Fail($"Exception encountered while fetching supported tokens: {e.Message}"); + } + } } } \ No newline at end of file diff --git a/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs b/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs index 5f17a70ec..ab61fced7 100644 --- a/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs +++ b/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs @@ -48,5 +48,15 @@ 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(); + } } } \ 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 000000000..dc1532591 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs @@ -0,0 +1,63 @@ +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 Token(Chain chain, Address contract, string tokenId = null) + { + Chain = chain; + Contract = contract; + TokenId = tokenId; + } + + [Preserve] + [JsonConstructor] + public Token(BigInteger chainId, string contractAddress, string tokenId = null) + { + Chain = ChainDictionaries.ChainById[chainId.ToString()]; + Contract = new Address(contractAddress); + TokenId = tokenId; + } + } + + 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; + } + + 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(); + string tokenId = jsonObject["tokenId"]?.Value(); + + return new Token(chainId, contractAddress, tokenId); + } + } +} \ No newline at end of file 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 000000000..ea934246f --- /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 ff307407e..3afa855f3 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 9dbb27810..a1c5c76ce 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 b4d7fdbc8..1e78f4543 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 0bef96f33..a58bc46a9 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs @@ -165,5 +165,37 @@ private async Task AssertWeHaveSufficientBalance(Address userWallet, Address buy $"Insufficient balance of {sellCurrency} to buy {buyAmount} of {buyCurrency}, have {have}, need {required}"); } } + + public async Task GetSupportedChains() + { + string url = BaseUrl.AppendTrailingSlashIfNeeded() + "GetLifiChains"; + try + { + LifiSupportedChainsResponse response = + await _client.SendRequest(url, null); + return response.GetChains(); + } + catch (Exception e) + { + string error = $"Error fetching supported chains: {e.Message}"; + throw new Exception(error); + } + } + + public async Task GetSupportedTokens(Chain[] chains) + { + string url = BaseUrl.AppendTrailingSlashIfNeeded() + "GetLifiTokens"; + try + { + GetLifiTokensResponse response = + await _client.SendRequest(url, new GetLifiTokensRequest(chains)); + return response.tokens; + } + catch (Exception e) + { + string error = $"Error fetching supported tokens: {e.Message}"; + throw new Exception(error); + } + } } } \ 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 000000000..227f5a06b --- /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 000000000..36c5e19fa --- /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 000000000..f47631aaf --- /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 000000000..6dec35fec --- /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 000000000..02b50be91 --- /dev/null +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs @@ -0,0 +1,29 @@ +using System; +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; + Chain[] result = new Chain[length]; + for (int i = 0; i < length; i++) + { + result[i] = ChainDictionaries.ChainById[chains[i].ToString()]; + } + return result; + } + } +} \ 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 000000000..03166fb80 --- /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/ISwap.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs index 647f72c04..c21ff2f30 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs @@ -48,5 +48,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 44d3996e9..3dbf8cb32 100644 --- a/Packages/Sequence-Unity/package.json +++ b/Packages/Sequence-Unity/package.json @@ -1,6 +1,6 @@ { "name": "xyz.0xsequence.waas-unity", - "version": "4.0.3", + "version": "4.1.0", "displayName": "Sequence Embedded Wallet SDK", "description": "A Unity SDK for Sequence APIs", "unity": "2021.3", From a22f1ccd24274e6d79e8c45e56ec635dbe050579 Mon Sep 17 00:00:00 2001 From: Quinn Purdy Date: Fri, 25 Apr 2025 15:00:24 -0400 Subject: [PATCH 2/8] Fix get support chains implementation. Fix typo in test --- Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs | 2 +- .../DataTypes/LifiSupportedChainsResponse.cs | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs index fb405b3d4..30a7b645e 100644 --- a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs +++ b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs @@ -200,7 +200,7 @@ public async Task TestGetSupportedTokens_AllSupportedChains() Token[] supportedTokens = await currencySwap.GetSupportedTokens(supportedChains); Assert.IsNotNull(supportedTokens); - Assert.AreEqual(0, supportedTokens.Length); + Assert.Greater(supportedTokens.Length, 0); } catch (Exception e) { diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs index 02b50be91..28b1c8048 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSupportedChainsResponse.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Numerics; using UnityEngine.Scripting; @@ -18,12 +19,16 @@ public LifiSupportedChainsResponse(BigInteger[] chains) public Chain[] GetChains() { int length = chains.Length; - Chain[] result = new Chain[length]; + List result = new List(); for (int i = 0; i < length; i++) { - result[i] = ChainDictionaries.ChainById[chains[i].ToString()]; + 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; + return result.ToArray(); } } } \ No newline at end of file From 4e1f1c6c1bcad300ed18928e5bcd691f3c48990f Mon Sep 17 00:00:00 2001 From: Quinn Purdy Date: Tue, 13 May 2025 13:00:44 -0400 Subject: [PATCH 3/8] Base integration of new Lifi swap routes --- .../Marketplace/CurrencySwapTests.cs | 17 +++++ .../Mocks/MockSwapThatGivesPricesInOrder.cs | 5 ++ .../Sequence/SequenceSDK/Ethereum/Token.cs | 63 +++++++++++++++++-- .../SequenceSDK/Marketplace/CurrencySwap.cs | 22 +++++++ .../DataTypes/GetLifiSwapRoutesArgs.cs | 24 +++++++ .../DataTypes/GetLifiSwapRoutesArgs.cs.meta | 3 + .../Marketplace/DataTypes/LifiSwapRoute.cs | 23 +++++++ .../DataTypes/LifiSwapRoute.cs.meta | 3 + .../DataTypes/LifiSwapRoutesResponse.cs | 17 +++++ .../DataTypes/LifiSwapRoutesResponse.cs.meta | 3 + .../Sequence/SequenceSDK/Marketplace/ISwap.cs | 2 + 11 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapRoutesArgs.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapRoutesArgs.cs.meta create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoute.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoute.cs.meta create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoutesResponse.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoutesResponse.cs.meta diff --git a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs index 30a7b645e..ffa1e6e84 100644 --- a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs +++ b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs @@ -207,5 +207,22 @@ public async Task TestGetSupportedTokens_AllSupportedChains() 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}"); + } + } } } \ No newline at end of file diff --git a/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs b/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs index ab61fced7..3ec1e3f05 100644 --- a/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs +++ b/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs @@ -58,5 +58,10 @@ 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 index dc1532591..00cc4bf02 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs @@ -13,21 +13,44 @@ 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) + 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) + 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()]; - Contract = new Address(contractAddress); + if (!string.IsNullOrWhiteSpace(contractAddress)) + { + Contract = new Address(contractAddress); + } TokenId = tokenId; + Symbol = symbol; + Name = name; + Decimals = decimals; + PriceUsd = priceUsd; + LogoUri = logoUri; + Price = price; } } @@ -44,6 +67,30 @@ public override void WriteJson(JsonWriter writer, Token value, JsonSerializer se { 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); } @@ -56,8 +103,14 @@ public override Token ReadJson(JsonReader reader, Type objectType, Token existin BigInteger chainId = jsonObject["chainId"]?.Value() ?? 0; string contractAddress = jsonObject["contractAddress"]?.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 = (jsonObject["price"]?.Value() ?? 0); - return new Token(chainId, contractAddress, tokenId); + return new Token(chainId, contractAddress, tokenId, symbol, name, decimals, priceUsd, logoUri, price); } } -} \ No newline at end of file +} diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs index a58bc46a9..0bcabdd65 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs @@ -197,5 +197,27 @@ public async Task GetSupportedTokens(Chain[] chains) throw new Exception(error); } } + + 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 + { + 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"); + } + return response.routes; + } + catch (Exception e) + { + string error = $"Error fetching Lifi swap routes: {e.Message}"; + throw new Exception(error); + } + } } } \ 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 000000000..3c09e6911 --- /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 000000000..74d241fbe --- /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/LifiSwapRoute.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapRoute.cs new file mode 100644 index 000000000..1a0ce12c4 --- /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 000000000..5c26882d2 --- /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 000000000..f39a23f01 --- /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 000000000..32889e635 --- /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/ISwap.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs index c21ff2f30..e111a5e17 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs @@ -61,5 +61,7 @@ public Task GetSwapQuote(Address userWallet, Address buyCurrency, Add /// /// public Task GetSupportedTokens(Chain[] chains); + + public Task GetLifiSwapRoutes(Address userWallet, Address buyCurrency, string buyAmount); } } \ No newline at end of file From 86842ae4e9f46355fa5ce63d5ee352a22c9ae759 Mon Sep 17 00:00:00 2001 From: Quinn Purdy Date: Tue, 13 May 2025 14:51:18 -0400 Subject: [PATCH 4/8] Basic integration of new Lifi swap quote --- .../Marketplace/CurrencySwapTests.cs | 34 +++++++++++++ .../Sequence/SequenceSDK/Ethereum/Token.cs | 37 ++++++++++++++ .../SequenceSDK/Marketplace/CurrencySwap.cs | 43 ++++++++++++++++ .../DataTypes/GetLifiSwapQuoteParams.cs | 37 ++++++++++++++ .../DataTypes/GetLifiSwapQuoteParams.cs.meta | 3 ++ .../DataTypes/GetLifiSwapQuoteRequest.cs | 15 ++++++ .../DataTypes/GetLifiSwapQuoteRequest.cs.meta | 3 ++ .../DataTypes/GetLifiSwapQuoteResponse.cs | 17 +++++++ .../GetLifiSwapQuoteResponse.cs.meta | 3 ++ .../Marketplace/DataTypes/LifiSwapQuote.cs | 49 +++++++++++++++++++ .../DataTypes/LifiSwapQuote.cs.meta | 3 ++ .../Sequence/SequenceSDK/Marketplace/ISwap.cs | 8 +++ 12 files changed, 252 insertions(+) create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteParams.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteParams.cs.meta create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteRequest.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteRequest.cs.meta create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteResponse.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/GetLifiSwapQuoteResponse.cs.meta create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapQuote.cs create mode 100644 Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapQuote.cs.meta diff --git a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs index ffa1e6e84..41b86f717 100644 --- a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs +++ b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs @@ -224,5 +224,39 @@ public async Task TestGetLifiSwapRoutes() 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/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs index 00cc4bf02..0a2bd4a7b 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs @@ -113,4 +113,41 @@ public override Token ReadJson(JsonReader reader, Type objectType, Token existin 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/Marketplace/CurrencySwap.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs index 0bcabdd65..2b5aca590 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 { @@ -211,6 +214,8 @@ public async Task GetLifiSwapRoutes(Address userWallet, Address { throw new Exception("No swap path with sufficient liquidity found"); } + + ValidateNoExtraToTokens(response.routes); return response.routes; } catch (Exception e) @@ -219,5 +224,43 @@ public async Task GetLifiSwapRoutes(Address userWallet, Address throw new Exception(error); } } + + private void ValidateNoExtraToTokens(LifiSwapRoute[] routes) + { + foreach (var route in routes) + { + 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}"); + } + } + } + + 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 + { + 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"); + } + + return response.quote; + } + catch (Exception e) + { + string error = $"Error fetching Lifi swap quote: {e.Message}"; + throw new Exception(error); + } + } } } \ No newline at end of file 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 000000000..29ddfb1a1 --- /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 000000000..4ac64812e --- /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 000000000..6d8c3a19a --- /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 000000000..331485695 --- /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 000000000..ccbe50015 --- /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 000000000..c7fbe2d53 --- /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/LifiSwapQuote.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/LifiSwapQuote.cs new file mode 100644 index 000000000..7fbacfbe0 --- /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 000000000..010c0e88e --- /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/ISwap.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs index e111a5e17..2c879477a 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs @@ -62,6 +62,14 @@ public Task GetSwapQuote(Address userWallet, Address buyCurrency, Add /// public Task GetSupportedTokens(Chain[] chains); + /// + /// Base integration of GetLifiSwapRoutes API + /// In general, it is not recommended to use this method directly + /// + /// + /// + /// + /// public Task GetLifiSwapRoutes(Address userWallet, Address buyCurrency, string buyAmount); } } \ No newline at end of file From ba59e1af2c6d8232c0545e86d7663a38bcfbf8ee Mon Sep 17 00:00:00 2001 From: Quinn Purdy Date: Tue, 13 May 2025 15:33:46 -0400 Subject: [PATCH 5/8] Update existing swap methods to use the lifi routes instead --- .../Marketplace/CurrencySwapTests.cs | 13 +- .../Mocks/MockSwapThatGivesPricesInOrder.cs | 5 + .../Sequence/SequenceSDK/Ethereum/Token.cs | 4 + .../SequenceSDK/Marketplace/CurrencySwap.cs | 164 ++++++++++-------- .../Marketplace/DataTypes/SwapPrice.cs | 12 +- .../Marketplace/DataTypes/SwapQuote.cs | 16 ++ .../Sequence/SequenceSDK/Marketplace/ISwap.cs | 23 +-- 7 files changed, 141 insertions(+), 96 deletions(-) diff --git a/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs b/Assets/SequenceSDK/Marketplace/CurrencySwapTests.cs index 41b86f717..dfb0df0e8 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")); } } diff --git a/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs b/Assets/SequenceSDK/Marketplace/Mocks/MockSwapThatGivesPricesInOrder.cs index 3ec1e3f05..69b67b3ec 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) { diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs index 0a2bd4a7b..bb1eedae8 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs @@ -102,6 +102,10 @@ public override Token ReadJson(JsonReader reader, Type objectType, Token existin 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(); diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs index 2b5aca590..52ba525f2 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/CurrencySwap.cs @@ -17,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) { @@ -27,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) { @@ -65,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) { @@ -93,31 +144,11 @@ public async Task GetSwapQuote(Address userWallet, Address buyCurrenc { try { - await AssertWeHaveSufficientBalance(userWallet, buyCurrency, sellCurrency, buyAmount, - slippagePercentage); - } - catch (Exception e) - { - 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"; - 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; + LifiSwapQuote swapQuote = await GetLifiSwapQuote(userWallet, buyCurrency, sellCurrency, buyAmount, null, + includeApprove, slippagePercentage); + SwapQuote quote = new SwapQuote(swapQuote); + OnSwapQuoteReturn?.Invoke(quote); + return quote; } catch (Exception e) { @@ -128,47 +159,6 @@ await AssertWeHaveSufficientBalance(userWallet, buyCurrency, sellCurrency, buyAm } } - private async Task AssertWeHaveSufficientBalance(Address userWallet, Address buyCurrency, Address sellCurrency, - string buyAmount, uint slippagePercentage = ISwap.DefaultSlippagePercentage) - { - BigInteger required, have; - try - { - SwapPrice price = await GetSwapPrice(buyCurrency, sellCurrency, buyAmount, slippagePercentage); - required = BigInteger.Parse(price.maxPrice); - } - catch (Exception e) - { - throw new Exception($"Error fetching swap price for buying {buyAmount} of {buyCurrency} with {sellCurrency}: {e.Message}"); - } - - TokenBalance[] sellCurrencyBalances; - try - { - GetTokenBalancesReturn balanceResponse = await _indexer.GetTokenBalances(new GetTokenBalancesArgs(userWallet, sellCurrency)); - sellCurrencyBalances = balanceResponse.balances; - } - catch (Exception e) - { - throw new Exception($"Error fetching token balance of {sellCurrency}: {e.Message}"); - } - - if (sellCurrencyBalances == null || sellCurrencyBalances.Length == 0) - { - have = 0; - } - else - { - have = sellCurrencyBalances[0].balance; - } - - if (have < required) - { - throw new Exception( - $"Insufficient balance of {sellCurrency} to buy {buyAmount} of {buyCurrency}, have {have}, need {required}"); - } - } - public async Task GetSupportedChains() { string url = BaseUrl.AppendTrailingSlashIfNeeded() + "GetLifiChains"; @@ -201,6 +191,15 @@ public async Task GetSupportedTokens(Chain[] chains) } } + /// + /// 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 = @@ -238,6 +237,19 @@ private void ValidateNoExtraToTokens(LifiSwapRoute[] routes) } } + /// + /// 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"; diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/SwapPrice.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/DataTypes/SwapPrice.cs index d550ebc15..9a7f0810d 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 fcdcadcd3..892a9a513 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 2c879477a..8b71ccb4a 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs @@ -13,11 +13,24 @@ public interface ISwap /// /// Get the current SwapPrice for a given buyCurrency, sellCurrency, and buyAmount /// + /// /// /// /// /// 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 userWallet, Address buyCurrency, Address sellCurrency, string buyAmount); + + /// + /// Get the current SwapPrice for a given buyCurrency, sellCurrency, and buyAmount + /// + /// + /// + /// + /// 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; @@ -61,15 +74,5 @@ public Task GetSwapQuote(Address userWallet, Address buyCurrency, Add /// /// public Task GetSupportedTokens(Chain[] chains); - - /// - /// Base integration of GetLifiSwapRoutes API - /// In general, it is not recommended to use this method directly - /// - /// - /// - /// - /// - public Task GetLifiSwapRoutes(Address userWallet, Address buyCurrency, string buyAmount); } } \ No newline at end of file From 48fbcfb69ac87e21fcb372cc6e0a17bd32cf7979 Mon Sep 17 00:00:00 2001 From: Quinn Purdy Date: Tue, 13 May 2025 15:35:03 -0400 Subject: [PATCH 6/8] Increment package version --- Packages/Sequence-Unity/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/Sequence-Unity/package.json b/Packages/Sequence-Unity/package.json index 3dbf8cb32..1993eee62 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", From 26c9542add76fc2e7729f070511fe3a6592804ce Mon Sep 17 00:00:00 2001 From: Quinn Purdy Date: Tue, 13 May 2025 15:37:36 -0400 Subject: [PATCH 7/8] Fix intellisence summary --- .../Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs index 8b71ccb4a..b6dd689f5 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Marketplace/ISwap.cs @@ -17,9 +17,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 userWallet, Address buyCurrency, Address sellCurrency, string buyAmount); /// From ba05c0797b6da2505ca537ed66accac1eefea353 Mon Sep 17 00:00:00 2001 From: Quinn Purdy Date: Fri, 16 May 2025 12:09:19 -0400 Subject: [PATCH 8/8] Handle null Token.Price case in json --- .../Sequence/SequenceSDK/Ethereum/Token.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs index bb1eedae8..f5dbc6d6b 100644 --- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs +++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Ethereum/Token.cs @@ -112,7 +112,17 @@ public override Token ReadJson(JsonReader reader, Type objectType, Token existin BigInteger decimals = (jsonObject["decimals"]?.Value() ?? 18); decimal priceUsd = jsonObject["priceUsd"]?.Value() ?? default; string logoUri = jsonObject["logoUri"]?.Value(); - BigInteger price = (jsonObject["price"]?.Value() ?? 0); + 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); }