diff --git a/Assets/SequenceSDK/Adapter.meta b/Assets/SequenceSDK/Adapter.meta
new file mode 100644
index 000000000..74ff581c9
--- /dev/null
+++ b/Assets/SequenceSDK/Adapter.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: c80db533ce3049719d92ba7d1b9a6fe6
+timeCreated: 1750361202
\ No newline at end of file
diff --git a/Assets/SequenceSDK/Adapter/Tests.meta b/Assets/SequenceSDK/Adapter/Tests.meta
new file mode 100644
index 000000000..3f6ad50c2
--- /dev/null
+++ b/Assets/SequenceSDK/Adapter/Tests.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: c7fe56b63fed4a80a6017040e7404806
+timeCreated: 1750361210
\ No newline at end of file
diff --git a/Assets/SequenceSDK/Adapter/Tests/AdapterTests.cs b/Assets/SequenceSDK/Adapter/Tests/AdapterTests.cs
new file mode 100644
index 000000000..91aea060c
--- /dev/null
+++ b/Assets/SequenceSDK/Adapter/Tests/AdapterTests.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+namespace Sequence.Pay.Tests.Transak
+{
+ public class AdapterTests
+ {
+ private const string TokenId = "0";
+
+ private static readonly Address TokenAddress = new ("");
+ private static readonly Address CurrencyAddress = new ("");
+ private static readonly Address SellCurrencyAddress = new ("");
+ private static readonly Address RecipientAddress = new ("");
+
+ [Test]
+ public async Task UnifiedEndToEndTest()
+ {
+ var sequenceUnified = new Adapter.Sequence(Chain.TestnetArbitrumSepolia);
+ await sequenceUnified.TryRecoverWalletFromStorage();
+
+ var recovered = await sequenceUnified.TryRecoverWalletFromStorage();
+ if (!recovered)
+ await sequenceUnified.GuestLogin();
+
+ await sequenceUnified.GetIdToken();
+
+ var nativeTokenBalance= await sequenceUnified.GetMyNativeTokenBalance();
+ var tokenBalance = await sequenceUnified.GetMyTokenBalance(TokenAddress);
+
+ await sequenceUnified.SendToken(TokenAddress, RecipientAddress, TokenId, 1);
+ await sequenceUnified.SwapToken(SellCurrencyAddress, CurrencyAddress, 1000);
+
+ await sequenceUnified.CreateListingOnMarketplace(TokenAddress, CurrencyAddress, TokenId,
+ 1, 1000, DateTime.MaxValue);
+
+ var listings = await sequenceUnified.GetAllListingsFromMarketplace(TokenAddress);
+ await sequenceUnified.PurchaseOrderFromMarketplace(listings[0].order, 1);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assets/SequenceSDK/Adapter/Tests/AdapterTests.cs.meta b/Assets/SequenceSDK/Adapter/Tests/AdapterTests.cs.meta
new file mode 100644
index 000000000..ae9034cf3
--- /dev/null
+++ b/Assets/SequenceSDK/Adapter/Tests/AdapterTests.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 1be23cc916d046b69e5b0c2e9c905be7
+timeCreated: 1750361251
\ No newline at end of file
diff --git a/Assets/SequenceSDK/Adapter/Tests/SequenceAdapterTests.asmdef b/Assets/SequenceSDK/Adapter/Tests/SequenceAdapterTests.asmdef
new file mode 100644
index 000000000..cb8f400a5
--- /dev/null
+++ b/Assets/SequenceSDK/Adapter/Tests/SequenceAdapterTests.asmdef
@@ -0,0 +1,18 @@
+{
+ "name": "SequenceUnifiedTests",
+ "rootNamespace": "",
+ "references": ["GUID:03d0ed9c50cfd4cb28a56d2d06580ffa","GUID:f7fd4ba36aabd1d499450c174865e70b","GUID:19b9eb7db56cc47349571a4fbb0dd677","GUID:403077141e1554429a890cbc129df651","GUID:4e0a798abbda240658187632ae443a67","GUID:f78a27d6a73d94c4baf04337e0add4dc"],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [
+ "UNITY_INCLUDE_TESTS"
+ ],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Assets/SequenceSDK/Adapter/Tests/SequenceAdapterTests.asmdef.meta b/Assets/SequenceSDK/Adapter/Tests/SequenceAdapterTests.asmdef.meta
new file mode 100644
index 000000000..875fd8229
--- /dev/null
+++ b/Assets/SequenceSDK/Adapter/Tests/SequenceAdapterTests.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 10f7025d30db4b42b66b8d746923d16f
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/SequenceSDK/Authentication/Tests/MockLogin.cs b/Assets/SequenceSDK/Authentication/Tests/MockLogin.cs
index d6d49c9a3..0af1e5914 100644
--- a/Assets/SequenceSDK/Authentication/Tests/MockLogin.cs
+++ b/Assets/SequenceSDK/Authentication/Tests/MockLogin.cs
@@ -91,7 +91,7 @@ public void TryToRestoreSession()
}
- public void GuestLogin()
+ public Task GuestLogin()
{
throw new System.NotImplementedException();
}
diff --git a/Assets/SequenceSDK/Authentication/Tests/MockLoginCustomEventTiming.cs b/Assets/SequenceSDK/Authentication/Tests/MockLoginCustomEventTiming.cs
index 717b38dc3..2a6cd6895 100644
--- a/Assets/SequenceSDK/Authentication/Tests/MockLoginCustomEventTiming.cs
+++ b/Assets/SequenceSDK/Authentication/Tests/MockLoginCustomEventTiming.cs
@@ -80,7 +80,7 @@ public void TryToRestoreSession()
}
- public void GuestLogin()
+ public Task GuestLogin()
{
throw new System.NotImplementedException();
}
diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter.meta
new file mode 100644
index 000000000..784342f5a
--- /dev/null
+++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2fbda8d3e94840b497881679b1ee831b
+timeCreated: 1750351968
\ No newline at end of file
diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/ISequence.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/ISequence.cs
new file mode 100644
index 000000000..3263bb496
--- /dev/null
+++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/ISequence.cs
@@ -0,0 +1,133 @@
+using System;
+using System.Numerics;
+using System.Threading.Tasks;
+using Sequence.EmbeddedWallet;
+using Sequence.Marketplace;
+
+namespace Sequence.Adapter
+{
+ public interface ISequence
+ {
+ ///
+ /// The underlying Sequence Embedded Wallet reference. Use it for more control, such as transaction batches.
+ ///
+ public IWallet Wallet { get; }
+
+ // ONBOARDING
+
+ ///
+ /// Recover a wallet from secure storage.
+ ///
+ /// 'true' if a stored wallet was found or 'false' if not or if session recovery is disabled in your SequenceConfig file.
+ Task TryRecoverWalletFromStorage();
+
+ ///
+ /// Login using Email OTP. You will receive a code to your email. Use it with the 'ConfirmEmailCode' function to finish the login process.
+ ///
+ /// Email of the given user.
+ ///
+ Task EmailLogin(string email);
+
+ ///
+ /// You receive a code after calling 'EmailLogin'. Use it with this function to complete the login process.
+ ///
+ ///
+ ///
+ ///
+ Task ConfirmEmailCode(string email, string code);
+
+ ///
+ /// Login as a guest. When the user uninstall the application, they lose access to a guest wallet, unless they use our Account Federation feature to link the guest wallet to another login option.
+ ///
+ ///
+ Task GuestLogin();
+
+ ///
+ /// Sign In with Google. The user is redirected to an external browser.
+ ///
+ void GoogleLogin();
+
+ ///
+ /// Sign In with Apple. The user is redirected to an external browser. On iOS, this function uses the native Sign In SDK.
+ ///
+ void AppleLogin();
+
+ ///
+ /// Get an id token as a JWT you can use to verify the user on your backend. Use any JWKS library to verify this token.
+ ///
+ /// JWT Id Token
+ Task GetIdToken();
+
+ // POWER
+
+ ///
+ /// Get the native token balance for your local user. For example, the native token on the Ethereum Mainnet is the amount of 'ETH'
+ ///
+ /// Balance in wei.
+ Task GetMyNativeTokenBalance();
+
+ ///
+ /// Get the token balance for your local user.
+ ///
+ /// Address of your token contract. This could be an ERC20, ERC1155, or ERC721 contract you deployed on https//sequence.build/
+ /// Balance in wei and the token metadata.
+ Task<(BigInteger Balance, TokenMetadata TokenMetadata)> GetMyTokenBalance(Address tokenAddress);
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task GetTokenSupplies(Address tokenAddress);
+
+ ///
+ /// Send any ERC20, ERC1155 or ERC721 token to another wallet.
+ ///
+ /// The address of the wallet you want to send the token to.
+ /// The address of your token. For example one you have deployed through https://sequence.build/
+ /// Leave it blank for ERC20 contracts.
+ /// Leave it blank for ERC721 contracts.
+ /// Transaction receipt used to check transaction information onchain.
+ ///
+ Task SendToken(Address recipientAddress, Address tokenAddress, string tokenId, BigInteger amount);
+
+ // MONETIZATION
+
+ ///
+ /// Swap one of your tokens to another one. Make sure you have configured enough liquidity on a DEX such as UniSwap.
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task SwapToken(Address sellToken, Address buyToken, BigInteger buyAmount);
+
+ ///
+ /// Get all listings from your Marketplace on a given collection. Please make sure you have configured your Marketplace on https://sequence.build/
+ ///
+ ///
+ ///
+ Task GetAllListingsFromMarketplace(Address collectionAddress);
+
+ ///
+ /// Create a listing for a given token you own. Please make sure you have configured your Marketplace on https://sequence.build/
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ Task CreateListingOnMarketplace(Address contractAddress, Address currencyAddress,
+ string tokenId, BigInteger amount, BigInteger pricePerToken, DateTime expiry);
+
+ ///
+ /// Purchase an order from your Marketplace. Please make sure you have configured your Marketplace on https://sequence.build/
+ ///
+ /// The order as returned from the 'GetAllListingsFromMarketplace' function.
+ /// The amount of orders you wish to purchase.
+ ///
+ Task PurchaseOrderFromMarketplace(Order order, BigInteger amount);
+ }
+}
\ No newline at end of file
diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/ISequence.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/ISequence.cs.meta
new file mode 100644
index 000000000..c935552eb
--- /dev/null
+++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/ISequence.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 56129c265d66491ba5529d572d6ac2e0
+timeCreated: 1750401684
\ No newline at end of file
diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/Sequence.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/Sequence.cs
new file mode 100644
index 000000000..c62295487
--- /dev/null
+++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/Sequence.cs
@@ -0,0 +1,193 @@
+using System;
+using System.Numerics;
+using System.Threading.Tasks;
+using NUnit.Framework;
+using Sequence.EmbeddedWallet;
+using Sequence.Marketplace;
+
+namespace Sequence.Adapter
+{
+ public class Sequence : ISequence, IDisposable
+ {
+ private IWallet _wallet;
+ public IWallet Wallet
+ {
+ get
+ {
+ EnsureWalletReferenceExists();
+ return _wallet;
+ }
+ set => _wallet = value;
+ }
+
+ private SequenceLogin _loginHandler;
+ private SequenceLogin LoginHandler
+ {
+ get
+ {
+ _loginHandler ??= SequenceLogin.GetInstance();
+ return _loginHandler;
+ }
+ }
+
+ private readonly Chain _chain;
+ private readonly ChainIndexer _indexer;
+ private readonly CurrencySwap _swap;
+ private readonly MarketplaceReader _marketplace;
+ private Checkout _checkout;
+
+ public Sequence(Chain chain)
+ {
+ _chain = chain;
+ _indexer = new ChainIndexer(_chain);
+ _swap = new CurrencySwap(_chain);
+ _marketplace = new MarketplaceReader(_chain);
+
+ SequenceWallet.OnWalletCreated += UpdateWallet;
+ }
+
+ public void Dispose()
+ {
+ SequenceWallet.OnWalletCreated -= UpdateWallet;
+ }
+
+ public async Task TryRecoverWalletFromStorage()
+ {
+ var result = await _loginHandler.TryToRestoreSessionAsync();
+ if (!result.StorageEnabled || result.Wallet == null)
+ return false;
+
+ Wallet = result.Wallet;
+ return true;
+ }
+
+ public async Task EmailLogin(string email)
+ {
+ await _loginHandler.Login(email);
+ }
+
+ public async Task ConfirmEmailCode(string email, string code)
+ {
+ await _loginHandler.Login(email, code);
+ }
+
+ public async Task GuestLogin()
+ {
+ await LoginHandler.GuestLogin();
+ }
+
+ public void GoogleLogin()
+ {
+ LoginHandler.GoogleLogin();
+ }
+
+ public void AppleLogin()
+ {
+ LoginHandler.AppleLogin();
+ }
+
+ public async Task GetIdToken()
+ {
+ var response = await Wallet.GetIdToken();
+ return response.IdToken;
+ }
+
+ public async Task GetMyNativeTokenBalance()
+ {
+ var result = await _indexer.GetNativeTokenBalance(Wallet.GetWalletAddress());
+ return result.balanceWei;
+ }
+
+ public async Task<(BigInteger Balance, TokenMetadata TokenMetadata)> GetMyTokenBalance(Address tokenAddress)
+ {
+ var args = new GetTokenBalancesArgs(Wallet.GetWalletAddress(), tokenAddress, true);
+ var result = await _indexer.GetTokenBalances(args);
+ var balance = result.balances[0];
+ return (balance.balance, balance.tokenMetadata);
+ }
+
+ public async Task GetTokenSupplies(Address tokenAddress)
+ {
+ var args = new GetTokenSuppliesArgs(tokenAddress, true);
+ var result = await _indexer.GetTokenSupplies(args);
+ return result.tokenIDs;
+ }
+
+ public async Task SendToken(Address recipientAddress, Address tokenAddress, string tokenId, BigInteger amount)
+ {
+ EnsureWalletReferenceExists();
+ var supplies = await _indexer.GetTokenSupplies(new GetTokenSuppliesArgs(tokenAddress, true));
+
+ Transaction transaction = supplies.contractType switch
+ {
+ ContractType.ERC20 => new SendERC20(tokenAddress, recipientAddress, amount.ToString()),
+ ContractType.ERC1155 => new SendERC1155(tokenAddress, recipientAddress,
+ new SendERC1155Values[] { new(tokenId, amount.ToString()) }),
+ ContractType.ERC721 => new SendERC721(tokenAddress, recipientAddress, tokenId),
+ _ => throw new Exception("Unknown contract type")
+ };
+
+ return await SendTransaction(new[] { transaction });
+ }
+
+ public async Task SwapToken(Address sellToken, Address buyToken, BigInteger buyAmount)
+ {
+ var walletAddress = Wallet.GetWalletAddress();
+ var quote = await _swap.GetSwapQuote(walletAddress, buyToken,
+ sellToken, buyAmount.ToString(), true);
+
+ await SendTransaction(new Transaction[]
+ {
+ new RawTransaction(sellToken, string.Empty, quote.approveData),
+ new RawTransaction(quote.to, quote.transactionValue, quote.transactionData),
+ }
+ );
+ }
+
+ public async Task GetAllListingsFromMarketplace(Address collectionAddress)
+ {
+ return await _marketplace.ListAllCollectibleListingsWithLowestPricedListingsFirst(collectionAddress);
+ }
+
+ public async Task CreateListingOnMarketplace(Address contractAddress, Address currencyAddress,
+ string tokenId, BigInteger amount, BigInteger pricePerToken, DateTime expiry)
+ {
+ EnsureWalletReferenceExists();
+ var steps = await _checkout.GenerateListingTransaction(contractAddress, tokenId, amount,
+ Marketplace.ContractType.ERC20, currencyAddress, pricePerToken, expiry);
+
+ var transactions = steps.AsTransactionArray();
+ return await SendTransaction(transactions);
+ }
+
+ public async Task PurchaseOrderFromMarketplace(Order order, BigInteger amount)
+ {
+ EnsureWalletReferenceExists();
+ var steps = await _checkout.GenerateBuyTransaction(order, amount);
+ var transactions = steps.AsTransactionArray();
+ return await SendTransaction(transactions);
+ }
+
+ private async Task SendTransaction(Transaction[] transactions)
+ {
+ var transactionResult = await Wallet.SendTransaction(_chain, transactions);
+ return transactionResult switch
+ {
+ SuccessfulTransactionReturn success => success.receipt.txnReceipt,
+ FailedTransactionReturn failed => throw new Exception($"Failed transaction {failed.error}"),
+ _ => throw new Exception("Unknown error while sending transaction.")
+ };
+ }
+
+ private void UpdateWallet(IWallet wallet)
+ {
+ Wallet = wallet;
+ _checkout = new Checkout(wallet, _chain);
+ }
+
+ private void EnsureWalletReferenceExists()
+ {
+ Assert.IsNotNull(Wallet, "Please sign in first. For example, call 'new SequenceQuickstart().GuestLogin();'");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/Sequence.cs.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/Sequence.cs.meta
new file mode 100644
index 000000000..3f665db39
--- /dev/null
+++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/Sequence.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: da7ded03c99be413e8cc8f4cb9456807
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/SequenceAdapter.asmdef b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/SequenceAdapter.asmdef
new file mode 100644
index 000000000..3e434670a
--- /dev/null
+++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/SequenceAdapter.asmdef
@@ -0,0 +1,24 @@
+{
+ "name": "SequenceAdapter",
+ "rootNamespace": "Sequence.Adapter",
+ "references": [
+ "GUID:a35e3a53d4439435f8b36ed2c6158cd8",
+ "GUID:4e0a798abbda240658187632ae443a67",
+ "GUID:f7fd4ba36aabd1d499450c174865e70b",
+ "GUID:b4f9c0f8f363f439b9e337f79050f189",
+ "GUID:f78a27d6a73d94c4baf04337e0add4dc",
+ "GUID:403077141e1554429a890cbc129df651",
+ "GUID:19b9eb7db56cc47349571a4fbb0dd677",
+ "GUID:a67bc3d548bec4971b914c7b64c9e959",
+ "GUID:94b67778c44684afdab21990eebf60aa"
+ ],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/SequenceAdapter.asmdef.meta b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/SequenceAdapter.asmdef.meta
new file mode 100644
index 000000000..566183831
--- /dev/null
+++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Adapter/SequenceAdapter.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 03d0ed9c50cfd4cb28a56d2d06580ffa
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/Authentication/ILogin.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/Authentication/ILogin.cs
index 927ab6cee..2763f4c30 100644
--- a/Packages/Sequence-Unity/Sequence/SequenceSDK/Authentication/ILogin.cs
+++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/Authentication/ILogin.cs
@@ -95,7 +95,7 @@ public interface ILogin
///
/// Login as a guest
///
- public void GuestLogin();
+ public Task GuestLogin();
///
/// Login with PlayFab
diff --git a/Packages/Sequence-Unity/Sequence/SequenceSDK/EmbeddedWallet/SequenceLogin.cs b/Packages/Sequence-Unity/Sequence/SequenceSDK/EmbeddedWallet/SequenceLogin.cs
index f68b4a2a1..ebff2f4a1 100644
--- a/Packages/Sequence-Unity/Sequence/SequenceSDK/EmbeddedWallet/SequenceLogin.cs
+++ b/Packages/Sequence-Unity/Sequence/SequenceSDK/EmbeddedWallet/SequenceLogin.cs
@@ -229,9 +229,9 @@ public void TryToRestoreSession()
TryToLoginWithStoredSessionWallet();
}
- public void GuestLogin()
+ public async Task GuestLogin()
{
- ConnectToWaaSAsGuest();
+ await ConnectToWaaSAsGuest();
}
private void SetupAuthenticatorAndListeners()