Typescript

Core SDK - Typescript

The XpansionChain Core SDK provides convenient access to XpansionChain's APIs and smart contracts to help projects build better web3 games and marketplaces.

💡ROLLUPS THIS SDK SUPPORTS

  • XpansionChain

CONTENTS

  • Installation

  • Initialization

  • Get data (on assets, orders, past transactions, etc.)

  • Operations requiring user signatures

  • Contract requests

  • Smart contract autogeneration

  • Metadata refresh

  • Migration guide

  • Further documentation


📚SDK LINKS

  • npm package

  • SDK reference

  • Code examples

  • Github repository

Installation

Add the npm package to your project:

npm install @imtbl/core-sdk --save
# or
yarn add @imtbl/core-sdk

Initialization

Initialize the Core SDK client with the network on which you want your application to run (see all networks available):

ParamDescription

Config.SANDBOX

The default test network (currently, it is Goërli)

Config.PRODUCTION

Ethereum network

import { XpansionChain, Config } from '@imtbl/core-sdk';

const config = Config.SANDBOX; // Or PRODUCTION
const client = new XpansionChain(config);

Get data (on assets, orders, past transactions, etc.)

These methods allow you to read data about events, transactions or current state on XpansionChain (layer 2). They do not require any user authentication because no state is being changed.

Examples of the types of data that are typically retrieved include:

  • Assets or details of a particular asset

  • Token balances for a particular user

  • Orders or details about a particular order

  • Historical trades and transfers

Get all collections and get assets from a particular collection:

const listCollectionsResponse = await client.listCollections({
  pageSize: 2,
});

const collection = listCollectionsResponse.result[0];

const collectionAssetsResponse = await client.listAssets({
  collection: collection.address,
  pageSize: 10,
});

Operations requiring user signatures

There are two types of operations requiring user signatures:

  1. Transactions that update blockchain state

  2. Operations that XpansionChain require authorization for

In order to get user signatures, applications need to generate "signers".

What are transactions that update blockchain state?

A common transaction type is the transfer of asset ownership from one user to another (ie. asset sale). These operations require users to sign (approve) them to prove that they are valid.

What are operations that require authorization?

These operations add to or update data in XpansionChain's databases and typically require the authorization of an object's owner (ie. a user creating a project on XpansionChain).

How do applications generate and use signers?

Signers are abstractions of user accounts that can be used to sign transactions. A user's private key is required to generate them.

There are two ways to get signers in your application:

  1. Generate your own by obtaining and using the user's private keys

  2. Use our Wallet SDK to connect to a user's wallet application

The first option, where an application obtains a user's private key directly, is risky because these keys allow anyone in possession of them full control of an account.

The second option provides an application with an interface to the user's account by prompting the user to connect with their wallet application (ie. mobile or browser wallet). Once connected the app can begin asking the user to sign transactions and messages without having to reveal their private key.

As XpansionChain enables applications to execute signed transactions on both Ethereum (layer 1) and StarkEx (layer 2), signers are required for both these layers.

1. Generate your own signers

The Core SDK provides functionality for applications to generate STARK (L2) private keys and signers.

🚨🚨🚨 Warning 🚨🚨🚨

If you generate your own STARK private key, you will have to persist it. The key is randomly generated so cannot be deterministically re-generated.

import { AlchemyProvider } from '@ethersproject/providers';
import { Wallet } from '@ethersproject/wallet';
import { generateStarkPrivateKey, createStarkSigner } from '@imtbl/core-sdk';

// Create Ethereum signer
const ethNetwork = 'goerli'; // Or 'mainnet'
const provider = new AlchemyProvider(ethNetwork, YOUR_ALCHEMY_API_KEY);
const ethSigner = new Wallet(YOUR_PRIVATE_ETH_KEY).connect(provider);

// Create STARK signer
const starkPrivateKey = generateStarkPrivateKey(); // Or retrieve previously generated key
const starkSigner = createStarkSigner(starkPrivateKey);

2. Generate signers using the Wallet SDK

The Wallet SDK Web provides connections to Metamask and WalletConnect browser wallets.

See this guide for how to set this up.

Examples

Create a project (requires an Ethereum layer 1 signer)

const createProjectResponse = await client.createProject(ethSigner, {
  company_name: 'My Company',
  contact_email: 'project@company.com',
  name: 'Project name',
});

const projectId = createProjectResponse.id.toString();

const getProjectResponse = await client.getProject(ethSigner, projectId);

Deposit tokens from L1 to L2 (requires an Ethereum layer 1 signer)

const depositResponse = await client.deposit(ethSigner, {
  type: 'ETH',
  amount: '500000000000000000', // Amount in wei
});

Create an order (requires an Ethereum layer 1 and StarkEx layer 2 signer)

const signers = { ethSigner, starkSigner };

const orderResponse = await client.createOrder(signers, {
  buy: {
    type: 'ETH',
    amount: '1230000000000000000', // Sale price in wei
  },
  sell: {
    type: 'ERC721',
    tokenAddress: '0x0fb969a08c7c39ba99c1628b59c0b7e5611bd396',
    tokenId: '5',
  },
});

Contract requests

XpansionChain is built as a zkRollup (zero-knowledge rollup) in partnership with StarkWare. The choice of zkRollups is deliberate, as it offers unparalleled scalability without compromising security. This means the following:

  • Cost-effectiveness: When you mint or trade an NFT on XpansionChain, you enjoy the advantage of zero gas fees.

  • Security: All transactions are secured by zero-knowledge proofs, which makes XpansionChain the first ever layer 2 solution for NFTs on Ethereum.

The Core SDK provides an interface with the smart contracts necessary for interacting with the XpansionChain platform.

See all smart contracts available in the Core SDK.

See all smart contracts available in the Core SDK.

import { Contracts, Config } from '@imtbl/core-sdk';

const config = Config.SANDBOX;

// Get instance of core contract
const contract = Contracts.Core.connect(
  config.ethConfiguration.coreContractAddress,
  ethSigner,
);

// Obtain necessary parameters...

// Populate and send transaction
const populatedTransaction = await contract.populateTransaction.depositNft(
  starkPublicKey,
  assetType,
  vaultId,
  tokenId,
);

const transactionResponse = await signer.sendTransaction(populatedTransaction);

Smart contract autogeneration

The XpansionChain Solidity contracts can be found in the contracts folder. Contract bindings in TypeScript are generated using hardhat.

ContractDescription

Core

The Core contract is XpansionChain's main interface with the Ethereum blockchain, based on StarkEx.

Registration

The Registration contract is a proxy smart contract for the Core contract that combines transactions related to onchain registration, deposits, and withdrawals. When a user who is not registered onchain attempts to perform a deposit or a withdrawal, the Registration combines requests to the Core contract in order to register the user first. Users who are not registered onchain are not able to perform a deposit or withdrawal.

IERC20

Standard interface for interacting with ERC20 contracts, taken from OpenZeppelin.

IERC721

Standard interface for interacting with ERC721 contracts, taken from OpenZeppelin.

Metadata refresh

XpansionChain allows developers to request asset metadata refreshes on-demand. This introductory guide shows you how to use the Core Typescript SDK to request and check for updates on your metadata refreshes.

Pre-requisites

  1. Installed the Core Typescript SDK

  2. Initialized the Core Typescript SDK

  3. Have satisified all the metadata refresh requirements

Create Ethereum Signer

First, we need to create an Ethereum Signer to tell XpansionChain that you are the project_owner of the project containing the collection of your assets:

import { XpansionChain, Config } from '@imtbl/core-sdk';
import { Wallet } from '@ethersproject/wallet';

// Create Ethereum Signer
const ethSigner = new Wallet('YOUR_PRIVATE_ETH_KEY');

// Initialize client

const config = Config.SANDBOX;
const client = new XpansionChain(config);

// Address of the collection the asset was minted under.
// This is the address that was generated when you registered
// your collection with XpansionChain e.g 0x6e7eaac66499b8733964f24ae4a9d36bf8118dff

const collectionAddress = 'YOUR_COLLECTION_ADDRESS';

Construct the refresh request

In order to construct the refresh request, we need to grab the token ids for the assets that require a metadata refresh:

// Fetch token ids for refresh
const listAssetsResponse  = await client.listAssets({
    pageSize: 5,
    collection: collectionAddress,
});

// Example response
{
  result: [
    {
      token_address: '0x94742ebb6279a3ddb70a1bec53ecd75',
      token_id: '5',
      id: '0x1111114971ed8cf199c019028dea827bd5f05735111111111',
      user: '0xa257d2c65c91d1e111181da9fbafac8a3111111',
      status: 'imx',
      uri: null,
      name: 'Sample NFT',
      description: null,
      image_url: 'https://www.example.com/some-image/5',
      metadata: {
        name: 'Some image',
        image_url: 'https://www.example.com/some-image/5'
      },
      collection: {
        name: '0x111111bb6279a3bc3e44da9ddb70a1bec111111',
        icon_url: 'https://www.example.com/some-icon/5'
      },
      created_at: '2022-09-30T10:58:32.04664Z',
      updated_at: '2022-09-30T11:58:13.85627Z'
    },
    ......
  ],
  cursor: 'eyJpZCI6IjB4NjczZWY3MDI2NDk0NzAzNjA4OTFiZDZiZTdlN2FiZTdkYTgyNzY0MTIyYzVjNTczMTllNTUyMWVkMGRjN2E5YSIsIm5hbWUiOiJMaW5hIiwidXBkYXRlWUiOiJMaW5hIiwidXBkYXR',
  remaining: 0
}

const tokenIds: string[] = listAssetsResponse.result.map((asset) => asset.token_id);

const createRefreshRequestParams = {
  collection_address: collectionAddress,
  token_ids: tokenIds // Token ids for metadata refresh, limit to 1000 per request
};

CUSTOMISING LIST ASSETS

You can narrow down the results returned by listAssets. Please refer to the listAssets request SDK reference.

For more information regarding limits on metadata refreshes, please refer to metadata refresh limits.

Request the refresh

const createMetadataRefreshResponse = await client.createMetadataRefresh(ethSigner, createRefreshRequestParams);
// Example response

{ refresh_id: '8cc5552-6276-4af7-9099-ce4135350e2d' }

Checking the status of your request

The duration of the refresh depends on the amount of tokens in the request. You can check on the status of your request using the following code:

const refresh_id = createMetadataRefreshResponse.refresh_id;
const getMetadataRefreshResultsResponse = await client.getMetadataRefreshResults(ethSigner, refresh_id);
// Example response
{
  refresh_id: '8cc5552-6276-4af7-9099-ce4135350e2d',
  status: 'in_progress',
  collection_address: '0x6e7eaa111499b876b964f24ae4a9d36bf8228dff',
  started_at: '2022-10-20T04:17:51.351675Z',
  completed_at: null,
  summary: { succeeded: 3, failed: 0, pending: 2 }
}

// Once the metadata refresh request has been completed
{
  refresh_id: '8cc5552-6276-4af7-9099-ce4135350e2d',
  status: 'completed',
  collection_address: '0x6e7eaa111499b876b964f24ae4a9d36bf8228dff',
  started_at: '2022-10-20T04:17:51.351675Z',
  completed_at: '2022-10-20T04:19:23.240863Z',
  summary: { succeeded: 5, failed: 0, pending: 0 }
}

METADATA REFRESH STATUSES

For more information regarding refresh and summary statuses, please refer to viewing status of a metadata refresh.

Please note, currently there's no webhook or push notification that can notify you about the status of your request, hence, it's up to the developers to keep polling for any updates. The expected maximum time (estimate) to complete a refresh is approximately 48 hours. Updated metadata values will only be reflected in downstream systems e.g. marketplaces once the refresh for that asset is complete.

Checking the status of failed requests

If your requests fails for some reason, you should see the following response:

{
  refresh_id: '2a5796a1-2f2f-4443-8142-bfcf0ffcdfcb',
  status: 'completed',
  collection_address: '0x6e7eaac66111b876b964f24ae4a9d36bf8228dff',
  started_at: '2022-10-20T04:23:52.316555Z',
  completed_at: '2022-10-20T04:25:26.359759Z',
  summary: { succeeded: 0, failed: 5, pending: 0 }
}

To check why your requests failed, you can use the following snippet:

const getMetadataRefreshErrors = await client.getMetadataRefreshErrors(ethSigner, refresh_id);
// Example output
{
  result: [
    {
      token_id: '12',
      collection_address: '0x6e7eaa111119b876b964f24ae4a9d36bf8228dff',
      client_token_metadata_url: 'https://your-metadata-url.com/12',
      client_response_status_code: 400,
      client_response_body: "{message: 'Bad request'}",
      error_code: 'unable_to_retrieve_metadata',
      created_at: '2022-10-20T04:25:26.354327Z'
    },
    ......
  ],
  cursor: 'eyJjcmVhdGVkX2F0IjoiMjAyMi0xMC0yMFQwNDoyNDo1Ny4xMjYxODZaIiwiaWQiOiI2MTZkMTg4MC0zOTZiLTRmMGUtOGZmaaa',
  remaining: 0
}

METADATA REFRESH ERRORS

For more information regarding metadata refresh errors and various error codes, please refer to viewing metadata refresh errors.

Viewing all your current and previous refreshes

const listMetadataRefreshesRespose = await client.listMetadataRefreshes(ethSigner, collectionAddress);

// Example response
{
  result: [
    {
      refresh_id: '2a5796a1-1f1f-4443-8142-bfcf0ffcdfcb',
      status: 'completed',
      collection_address: '0x6e7e111199b876b964f24ae4a9d36bf8228dff',
      started_at: '2022-10-20T04:23:52.316555Z',
      completed_at: '2022-10-20T04:25:26.359759Z'
    },
    {
      refresh_id: '8cc2c472-6276-4af7-9099-ce4135350e2d',
      status: 'completed',
      collection_address: '0x6e7e111199b876b964f24ae4a9d36bf8228dff',
      started_at: '2022-10-20T04:17:51.351675Z',
      completed_at: '2022-10-20T04:19:23.240863Z'
    }
  ],
  cursor: 'eyJjcmVhdGVkX2F0IjoiMjAyMi0xMC0yMFQwNDoxNzo1MS4zNTE2NzVaIiwiaWQiOiI4Y2MyYzQ3Mi02Mjc2LTRhZjctOTA5OS1jZ111111',
  remaining: 0
}

Migration guide

Migrate from XpansionChain JavaScript SDK

The Core TypeScript SDK was released recently to make integrating with XpansionChain more straightforward and intuitive. We listened to a lot of your feedback, spent much time iterating on the interface of the Core SDK and have landed on a new interface.

Our old imx-sdk-js is bloated, unintuitive and hard to grok. It’s worth investing the time to migrate to the new Core SDK.

Why should you migrate?

The new Core SDK is vastly improved when working with the XpansionChain API. It's easy to understand and use. The new Core SDK’s improvement statistics speak for themselves:

  • Hand-written code reduced from 10,589 lines to 2,365 lines (down 78% 📉)

  • Package size reduced from 1.9MB to 668kB (down 65% 📉)

  • Minified package size reduced from 575kB to 195kB (down 67% 📉)

  • External dependencies reduced from 42 to 9 (down 79% 📉)

  • The number of publicly-exposed functions was reduced from hundreds to just 45 via one XpansionChain class, making it easy to understand all the functionality on offer.

  • The confusing fp-ts library has been completely eradicated.

When should you migrate?

You should consider migrating to the Core SDK if you use the imx-sdk from the backend to:

  • Create projects

  • Create and manage collections

  • Manage metadata schema

  • Mint assets

  • Create and manage orders including bids

  • Execute trades

The Core SDK supports newer features like metadata refresh. If you’d like to trigger asset metadata refreshes using the SDK, you should consider migrating to the Core SDK.

What has changed in Core SDK v2.0.0

Changed:

  • Order creation and management targets upgraded v3 endpoints.

    • createOrder -> createOrderV3

    • cancelOrder -> cancelOrderV3

    • getSignableCancelOrder -> getSignableCancelOrderV3

    • getOrder -> getOrderV3

    • listOrders -> listOrdersV3

  • Trade creation and management targets upgraded v3 endpoints.

    • createTrade -> createTradeV3

    • listTrades -> listTradesV3

Migration path from imx-sdk to Core SDK v2.0.0 for use in the backend

  1. Retrieve and persist your stark key using the generate-stark-key tool. Add an entry for your stark key in your secrets manager or .env file like the one below.

PRIVATE_KEY=<your-eth-key-here>
STARK_PRIVATE_KEY=<your-stark-key-here>
  1. Remove imx-sdk from the list of dependencies

npm remove @imtbl/imx-sdk
  1. Add @imtbl/core-sdk as a dependency.

npm i @imtbl/core-sdk
  1. Call the method of choice. Check out the examples to see how to call individual endpoints.

Migration path from Core SDK v1.0.0 to Core SDK v2.0.0

  1. Retrieve and persist your stark key using the generate-stark-key tool. Add an entry for your stark key in your secrets manager or .env file like the one below.

PRIVATE_KEY=<your-eth-key-here>
STARK_PRIVATE_KEY=<your-stark-key-here>
  1. Remove imx-core-sdk v1.0.0 from the list of dependencies

npm remove @imtbl/core-sdk
  1. Add @imtbl/core-sdk v2.0.0 as a dependency.

npm i @imtbl/core-sdk
  1. Call the method of choice. Check out the examples to see how to call individual endpoints.

Further documentation

  • See the Developer homepage for general information on building on XpansionChain.

  • Build on XpansionChain zkEVM:

    • Documentation

    • API reference

    • Support

  • Build on XpansionChain:

    • Documentation

    • API reference

    • Support

Last updated