Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unity/marketplace beta #467

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion 404.html
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ <h1>Page Not Found</h1>
{ oldpath: "/solutions/wallets/embedded-wallet/examples/validation", targetPath: "/solutions/wallets/embedded-wallet/examples/manage-sessions#session-management" },
{ oldpath: "/sdk/unreal/authentication", targetPath: "/sdk/unreal/authentication/intro" },
{ oldpath: "/guide/unity-guide", targetPath: "guide/jelly-forest-unity-guide"},
{ oldpath: "/solutions/payments/onramps/fiat-on-ramps", targetPath: "/solutions/monetization-overview"}
{ oldpath: "/solutions/payments/onramps/fiat-on-ramps", targetPath: "/solutions/monetization-overview"},
{ oldpath: "/sdk/unity/marketplace", targetPath: "/sdk/unity/marketplace/intro" }
];

var currentPath = window.location.pathname;
Expand Down
48 changes: 48 additions & 0 deletions docs/pages/sdk/unity/currency-swaps.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Currency Swaps

Swapping between different ERC20/native token currencies on a given Chain is made easy by Sequence's Smart Swap API.

## GetSwapPrice

This method can be used to get the current `SwapPrice` for a given buyCurrency and buyAmount using a given sellCurrency.

```
ISwap swapper = new CurrencySwap(_chain);
SwapPrice swapPrice = await swapper.GetSwapPrice(buyCurrencyTokenAddress, usdcAddress, "1000"); // where USDC is an example sell currency
```
You can optionally subscribe to the `OnSwapPriceReturn` and `OnSwapPriceError` events in order to handle the response elsewhere.

You can optionally provide a maximum allowable slippagePercentage.

## GetSwapPrices

This method is similar to `GetSwapPrice`, it can be used to get the current `SwapPrice` for a given buyCurrency and buyAmount. Except, instead of providing a sellCurrency, you instead provide the user's wallet address.

This method will detect the eligible currencies (ERC20s or native tokens) that can be swapped for buyAmount of the buyCurrency and will return a `SwapPrice[]`.

```
ISwap swapper = new CurrencySwap(_chain);
SwapPrice[] swapPrices = await swapper.GetSwapPrices(userWalletAddress, buyCurrencyTokenAddress, "1000");
```
You can optionally subscribe to the `OnSwapPricesReturn` and `OnSwapPricesError` events in order to handle the response elsewhere.

You can optionally provide a maximum allowable slippagePercentage.

## GetSwapQuote

This method is used to get an executable `SwapQuote` for a given userWallet address to buy buyAmount of buyCurrency using sellCurrency.

```
ISwap swapper = new CurrencySwap(_chain);
SwapQuote quote = await swapper.GetSwapQuote(userWalletAddress, buyCurrencyTokenAddess, usdcAddress, "1000", true); // where USDC is an example sell currency
```

Once you've obtained a `SwapQuote`, you can transform it into a `Transaction[]` that can be submitted via your EmbeddedWallet to execute the swap.

```
Transaction[] swapTransactions = quote.AsTransactionArray();

_wallet.SendTransaction(_chain, swapTransactions);
```

If `includeApprove = true` the SwapQuote response will also include the information required to create the required spend approval transaction(s). These will also be added to the `Transaction[]` created above via `SwapQuote.AsTransactionArray()`. As usual, with our embedded smart contract wallets, all of these transactions can be submitted at once in a bundle; significantly improving the UX for your players who would usually need to make separate transactions to approve and swap.
19 changes: 0 additions & 19 deletions docs/pages/sdk/unity/marketplace.mdx

This file was deleted.

15 changes: 15 additions & 0 deletions docs/pages/sdk/unity/marketplace/checkout-ui.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Checkout UI

The SDK comes with a default Checkout UI that you are welcome to use.

## Using the Default UI

The SDK provides `CheckoutPanel` and `CheckoutPage` scripts, easily accessible via the `CheckoutPanel` prefab located at `/Sequence/SequenceFrontend/Prefabs/Marketplace/CheckoutPanel.prefab`.

Once you've added the `CheckoutPanel` prefab to your scene, you can open it via the `Open()` method. When opening the `CheckoutPanel`, you'll need to provide an `ICheckoutHelper`.

The `ICheckoutHelper` interface is implemented by `NftCheckout` and `Cart`. In general, `NftCheckout` will be more versatile and should be preferred for most use cases; in future updates, `NftCheckout` will support credit/debit card based payment flows. `Cart` on the other hand, is useful if you plan on only supporting crypto payments as it allows for purchasing multiple collectibles at once.

## Building Your Own UI

If you'd like to build your own UI, it is recommended to check out the `CheckoutPage` implementation as an example. The `CheckoutPage` uses the `ICheckoutHelper` interface rather heavily; it handles the majority of the logic when it comes to selecting Currencies, estimating prices, and checking out. You may also find it worthwhile to extend `CheckoutPage` and modify its behaviour as you see fit.
50 changes: 50 additions & 0 deletions docs/pages/sdk/unity/marketplace/filling-orders.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Filling Orders

In order to fill an order (partially or completely) or to cancel an order, you'll be generating and submitting transactions.

The `ICheckout` interface, implemented by `Checkout`, exposes a few helpful methods and events.

## Building Transactions to Interact with Orders

The following async requests will return a `Step[]` these are used to generate transactions that, when submitted, perform the desired action.

```
Step[] steps = await <insert here your desired method>;
TransactionReturn result = await steps.SubmitAsTransactions(_wallet, _chain);
// or
Transaction[] stepTransactions = steps.AsTransactionArray();
```

All of these methods can be awaited directly. You can also subscribe to the `OnTransactionStepsReturn` and `OnTransactionStepsError` events to handle the responses elsewhere.

1. `GenerateBuyTransaction` is used to buy a specified amount of a given collectible in the provided `Order`/listing
```
ICheckout checkout = new Checkout(_wallet, _chain);
Step[] steps = await checkout.GenerateBuyTransaction(listing, 5);
```

2. `GenerateSellTransaction` is used to sell a specified amount for a given collectible in the provided `Order`/offer
```
ICheckout checkout = new Checkout(_wallet, _chain);
Step[] steps = await checkout.GenerateSellTransaction(offer, 3);
```

3. `GenerateListingTransaction` is used to create a new listing for a given collectible, amount, and price.
```
ICheckout checkout = new Checkout(_wallet, _chain);
Step[] steps = await checkout.GenerateListingTransaction(collectionContractAddress, tokenId, 17, ContractType.ERC1155, currencyTokenAddress, 1000, expiryDateTime);
```

4. `GenerateOfferTransaction` is used to create a new offer for a given collectible, amount, and price.
```
ICheckout checkout = new Checkout(_wallet, _chain);
Step[] steps = await checkout.GenerateOfferTransaction(collectionContractAddress, tokenId, 46, ContractType.ERC1155, currencyTokenAddress, 850, expiryDateTime);
```

5. `GenerateCancelTransaction` is used to cancel an existing order created by the user.
```
ICheckout checkout = new Checkout(_wallet, _chain);
Step[] steps = await checkout.GenerateCancelTransaction(collectionContractAddress, order);
// Or alternatively provide the order id
Step[] steps = await checkout.GenerateCancelTransaction(collectionContractAddress, orderIdString);
```
40 changes: 40 additions & 0 deletions docs/pages/sdk/unity/marketplace/intro.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Peer to Peer Trading - Intro

Peer to Peer Trading is facilitated by our [Marketplace API](/api/marketplace/overview).

Users will be able to purchase and sell ERC721/1155s between one another via the marketplace SDK in Unity; paying in cryptocurrency (with currency abstraction enabled by default) or via credit card where available (coming soon!).

## Installation

The V4 version of our SDK is currently in beta and maintained on a separate branch. We are eagerly looking for feedback on this new major update for the SDK, so please get in touch with us!

Please [install via Package Manager with Git URL](/sdk/unity/installation#or-using-package-manager-ui):

`https://github.com/0xsequence/sequence-unity.git?path=/Packages/Sequence-Unity#v4-beta`

If you already have the Sequence Unity SDK installed in your project, you will likely need to remove it.

## Understanding the Basics

Before diving into the details behind the marketplace, let's first establish an understanding of some basic concepts.

### Orders

There are two basic types of Orders: listings and offers.

Listings indicate an intent to sell a given amount of a collectible (where a collectible is the combination of a Chain, contract address, and token id) at a certain price per collectible in a given Currency. Once created, listings can be queried and bought by another user.
Offers indicate an intent to purchase a given amount of a collectible at a certain price per collectible in a given Currency. Once created, offers can be queried and sold by another user.

In order to create, fill, or cancel an Order, you must use the appropriate Generate_Method_Transaction call based on which method you are using. This will give you a `Step[]` that can be submitted as a transaction in order to perform the desired action. More on this in the [Filling Orders section](/sdk/unity/marketplace/filling-orders) of the docs.

### Currencies
A Currency is an ERC20 token or native token that has been whitelisted for a given project and Chain for use in the marketplace. You can add a new currency to the whitelist for you project by adding it as a custom currency when creating a white-label marketplace in the Sequence Builder. Please see [this guide](http://localhost:5173/solutions/marketplaces/white-label-marketplace/guide#add-a-custom-currency). All orders must be priced in whitelisted currencies or they will be ignored by the API.

### Collections

A Collection is a group of Collectibles, identified by an ERC721 or ERC1155 contract address.

### Collectibles

A Collectible is a specific instance of a Collection, identified by the ERC721/ERC1155 contract address and the token id.

138 changes: 138 additions & 0 deletions docs/pages/sdk/unity/marketplace/reading-orders.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Reading Orders

Reading orders from the marketplace API is done with the `IMarketplaceReader` interface, implemented by `MarketplaceReader`.

The IMarketplaceReader interface has IntelliSense summaries to help you understand what each method is used for, but, we'll call out a few of them here as well.

## Usage

All IMarketplaceReader methods are asynchronous Tasks and can be awaited directly and/or you can subscribe to the associated events.

## Methods

### ListCurrencies

Fetch an array of whitelisted [Currencies](/sdk/unity/marketplace/intro#currencies) that can be used in your game's marketplace.

```
IMarketplaceReader reader = new MarketplaceReader(_chain);

// optionally subscribe to callback events
reader.OnListCurrenciesReturn += OnCurrenciesFetched;
reader.OnListCurrenciesError += OnCurrencyFetchError;

Currency[] currencies = await reader.ListCurrencies();
// or if only listening to event handlers
reader.ListCurrencies();
...


private void OnCurrenciesFetched(Currency[] fetchedCurrencies) {
// Do something
}

private void OnCurrencyFetchError(string error) {
// Do something
}
```

### Fetching Listings

There are a few different ways to fetch listings.

1. `ListCollectibleListingsWithLowestPricedListingsFirst` is used to get the listings associated with a given contract address. The listings will be ordered with the lowest priced listings first. In addition, only the lowest priced listing for each collectible (i.e. each token id) will be returned.

```
IMarketplaceReader reader = new MarketplaceReader(_chain);
ListCollectiblesReturn collectiblesReturn = await reader.ListCollectibleListingsWithLowestPricedListingsFirst(myCollectionContractAddress);
CollectibleOrder[] orders = collectiblesReturn.collectibles;
```
Optionally, you can provide a `CollectiblesFilter` to apply filters on your query.

This request uses pagination. If you're dealing with a rather small collection and don't want to deal with pagination, you can use the `ListAllCollectibleListingsWithLowestPricedListingsFirst` helper function; this will handle the pagination for you and continue to make requests until all the relevant `CollectibleOrder`s have been retrieved.

You can also optionally subscribe to the `OnListCollectibleOrdersReturn` and `OnListCollectibleOrdersError` events in order to handle the responses elsewhere.

2. `GetLowestPriceListingForCollectible` and `GetHighestPriceListingForCollectible` can be used to fetch the lowest and highest priced listing for a collectible respectively.

```
IMarketplaceReader reader = new MarketplaceReader(_chain);
Order lowestPricedListing = await reader.GetLowestPriceListingForCollectible(collectionContractAddress, tokenId);
Order highestPricedListing = await reader.GetHighestPriceListingForCollectible(collectionContractAddress, tokenId);
```
Optionally, you can provide an `OrderFilter` to apply filters on your query.

Additionally, you have the option to subscribe to the `OnGetCollectibleOrderReturn` and `OnGetCollectibleOrderError` events in order to handle the response elsewhere.

3. `ListListingsForCollectible` is used to get all of the listings for a given Collectible.

```
IMarketplaceReader reader = new MarketplaceReader(_chain);
ListCollectibleListingsReturn listingsReturn = await reader.ListListingsForCollectible(collectionContractAddress, tokenId);
Order[] listings = listingsReturn.listings;
```
Optionally, you can provide an `OrderFilter` to apply filters on your query.

This request uses pagination. If you're dealing with a rather small set of listings and don't want to deal with pagination, you can use the `ListAllListingsForCollectible` helper function; this will handle the pagination for you and continue to make requests until all the relevant `Order`s have been retrieved.

Additionally, you have the option to subscribe to the `OnListCollectibleListingsReturn` and `OnListCollectibleListingsError` events in order to handle the response elsewhere.

4. `ListAllPurchasableListings` is a convenience helper method that can be used to `ListAllCollectibleListingsWithLowestPricedListingsFirst`, filtering for listings not created by `purchasableBy`. Then, using a `ChainIndexer` for the configured Chain to fetch `purchasableBy`'s token balances and removing any listings they cannot afford to purchase without swapping.

```
IMarketplaceReader reader = new MarketplaceReader(_chain);
CollectibleOrder[] purchasableListings = await reader.ListAllPurchasableListings(userWalletAddress, collectionContractAddress);
```

This method will handle pagination for you, continuing to make requests until all `CollectibleOrder`s have been fetched. Be careful to use it on collections with a small amount of listings (as with other helper methods that handle pagination for you) so that you do not use too much memory. This method's implementation can also serve as an example for how you can work with the [Indexer](/sdk/unity/read-from-blockchain) in conjunction with the peer to peer marketplaces.

### Fetching Offers

There are a few different ways to fetch offers. They all function similarly to their listing-equivalent methods.

1. `ListCollectibleOffersWithHighestPricedOfferFirst` is used to get the offers associated with a given contract address. The listings will be ordered with the highest priced offer first. In addition, only the highest priced offer for each collectible (i.e. each token id) will be returned.

```
IMarketplaceReader reader = new MarketplaceReader(_chain);
ListCollectiblesReturn collectiblesReturn = await reader.ListCollectibleOffersWithHighestPricedOfferFirst(myCollectionContractAddress);
CollectibleOrder[] orders = collectiblesReturn.collectibles;
```
Optionally, you can provide a `CollectiblesFilter` to apply filters on your query.

This request uses pagination. If you're dealing with a rather small collection and don't want to deal with pagination, you can use the `ListAllCollectibleOffersWithHighestPricedOfferFirst` helper function; this will handle the pagination for you and continue to make requests until all the relevant `CollectibleOrder`s have been retrieved.

You can also optionally subscribe to the `OnListCollectibleOrdersReturn` and `OnListCollectibleOrdersError` events in order to handle the responses elsewhere.

2. `GetLowestPriceOfferForCollectible` and `GetHighestPriceOfferForCollectible` can be used to fetch the lowest and highest priced offer for a collectible respectively.

```
IMarketplaceReader reader = new MarketplaceReader(_chain);
Order lowestPricedOffer = await reader.GetLowestPriceOfferForCollectible(collectionContractAddress, tokenId);
Order highestPricedOffer = await reader.GetHighestPriceOfferForCollectible(collectionContractAddress, tokenId);
```
Optionally, you can provide an `OrderFilter` to apply filters on your query.

Additionally, you have the option to subscribe to the `OnGetCollectibleOrderReturn` and `OnGetCollectibleOrderError` events in order to handle the response elsewhere.

3. `ListOffersForCollectible` is used to get all of the offers for a given Collectible.

```
IMarketplaceReader reader = new MarketplaceReader(_chain);
ListCollectibleOffersReturn offersReturn = await reader.ListOffersForCollectible(collectionContractAddress, tokenId);
Order[] offers = offersReturn.offers;
```
Optionally, you can provide an `OrderFilter` to apply filters on your query.

This request uses pagination. If you're dealing with a rather small set of offers and don't want to deal with pagination, you can use the `ListAllOffersForCollectible` helper function; this will handle the pagination for you and continue to make requests until all the relevant `Order`s have been retrieved.

Additionally, you have the option to subscribe to the `OnListCollectibleOffersReturn` and `OnListCollectibleOffersError` events in order to handle the response elsewhere.

4. `ListAllSellableOffers` is a convenience helper method that can be used to `ListAllCollectibleOffersWithHighestPricedOfferFirst`, filtering for offers not created by `sellableBy` and where `sellableBy` has at least one of the collectibles being requested.

```
IMarketplaceReader reader = new MarketplaceReader(_chain);
CollectibleOrder[] sellableOffers = await reader.ListAllSellableOffers(userWalletAddress, collectionContractAddress);
```

This method will handle pagination for you, continuing to make requests until all `CollectibleOrder`s have been fetched. Be careful to use it on collections with a small amount of offers (as with other helper methods that handle pagination for you) so that you do not use too much memory. This method's implementation can also serve as an example for how you can work with `CollectiblesFilter`s.

Loading