Skip to main content

Fill orders

To purchase an NFT the player needs to “fill” an existing order. This page explains how to fill an order using the Immutable Unity Orderbook package.

For fulfilment to occur, the player must have sufficient funds to cover the asking price of the order.
Unity OrderbookUnity Orderbook
💡Who is this for?
Developers who want to build an in-game marketplace in Unity.
💡Alpha version
This module is experimental and may change in the future. We recommend using it for testing purposes only.

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:

  1. Sign and submit the approval transaction (if required).
  2. 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.

💡Core functionality
There are other mechanisms for buying NFTs available in the Typescript Orderbook, such as placing bids or filling bulk orders. In this initial release, the Unity SDK is limited to filling a single order using the FulfillOrder method described in this page.
💡Marketplace
To display active listings in your in-game marketplace, you can utilise the Unity zkEVM API package. For an example, refer to this use case.

Fill order workflow

📋Prerequisites
Ensure you have completed the following prerequisites:

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 onchain, 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.

💡Status polling
You can poll the Get Listing endpoint to check on status updates. In the near future we also plan on introducing push based (webhook) integration for order events.

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.


Related content