Fill orders
For fulfilment to occur, the player must have sufficient funds to cover the asking price of the order.
Overview
Filling an existing order is the most common way for players to purchase NFTs in a marketplace. This process is pretty straight forward, the player simply needs to sign a fulfilment transaction that includes the listing ID of the order they are wanting to fill and the buyer's wallet address.
To fill a listing, you need to do the following:
- Sign and submit the approval transaction (if required).
- Submit the order fulfilment.
Below is the full code example that demonstrate the essential parts of each of these steps. If you want to see the full implementation, you can take a look at CreateOrderUseCase.cs in our Unity sample game.
For more details on each step, refer to the Typescript Orderbook specification.
FulfillOrder
method described in this page.Fill order workflow
- Passport package setup
- Orderbook package setup
- Login
- Initialise provider and connect wallet
- Link all game contracts to the Immutable Hub to enable pre-approved transactions. For detailed instructions, please refer to the guide here.
The process of filling an order can be broken down into two key steps:
1. Sign and submit the approval transaction (if required)
Once the order fulfilment details are sent, the response will contain actions that need to be taken.
If the player has never approved your contract to interact with the Immutable Orderbook before, the TransactionAction
action will be present in the response.
This TransactionAction
action must be signed and submitted to the blockchain through the Immutable SDK to grant the approvals required to fill orders in the Orderbook. This action only needs to be taken once per user per collection.
If the TransactionAction
action is not present, you can skip this step and continue to submit the order fulfilment.
2. Submit the order fulfilment
Once the approval transaction is signed and submitted, the order fulfilment can be finalised. This step involves sending the fulfilment request to the Immutable Orderbook API, which will process the transaction and update the order status.
Please see the entire code sample below.
using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using Immutable.Orderbook.Api;
using Immutable.Orderbook.Client;
using Immutable.Orderbook.Model;
using Immutable.Passport;
using Immutable.Passport.Model;
using Newtonsoft.Json;
using UnityEngine;
public class FulfilOrderUseCase
{
private static readonly Lazy<FulfilOrderUseCase> s_Instance = new(() => new FulfilOrderUseCase());
private readonly OrderbookApi m_OrderbookApi = new(new Configuration { BasePath = "https://api.immutable.com" });
private FulfilOrderUseCase() { }
public static FulfilOrderUseCase Instance => s_Instance.Value;
/// <summary>
/// Executes an order by fulfilling a listing and optionally confirming its status.
/// </summary>
/// <param name="listingId">The unique identifier of the listing to fulfil.</param>
/// <param name="fees">The taker fees</param>
public async UniTask ExecuteOrder(string listingId, List<FulfillOrderRequestTakerFeesInner> fees)
{
try
{
var request = new FulfillOrderRequest(
takerAddress: LOGGED_IN_WALLET, // Replace with player's wallet
listingId: listingId,
takerFees: fees);
var createListingResponse = await m_OrderbookApi.FulfillOrderAsync(request);
if (createListingResponse.Actions.Count > 0)
{
foreach (var transaction in createListingResponse.Actions)
{
var transactionHash = await Passport.Instance.ZkEvmSendTransaction(new TransactionRequest
{
to = transaction.PopulatedTransactions.To,
data = transaction.PopulatedTransactions.Data,
value = "0"
});
Debug.Log($"Transaction hash: {transactionHash}");
}
}
}
catch (ApiException e)
{
Debug.LogError($"API Error: {e.Message} (Status: {e.ErrorCode})");
Debug.LogError(e.ErrorContent);
Debug.LogError(e.StackTrace);
throw;
}
}
}
After filling the order
The order fulfilment transaction is now being processed. Upon validating the required contract approvals and wallet balance requirements on‑chain, the order will asynchronously transition to the FILLED
status.
We recommend taking an optimistic view and showing the order as FILLED
as soon as it is submitted, then polling the order status to check for updates for the most seamless player experience.
You can see all the different order status types in the table in the order statuses documentation.
For more details on each step, you can read the Typescript documentation for filling orders since the Unity Orderbook closely follows this implementation.
You can also view a full example in the Unity sample game.