Identifiers for supported assets

Off-chain minting for ERC-20 and ERC-1155 tokens is available beginning with StarkEx Spot Trading 5.0.

The StarkEx API supports the following types of assets:

  • ETH

  • ERC-20

  • Mintable ERC-20

  • ERC-721

  • Mintable ERC-721

  • ERC-1155

  • Mintable ERC-1155

Off-chain: The StarkEx API and SDK

The StarkEx API and SDK only apply off-chain.

The SDK and API use two different terms to refer to a unique off-chain asset:

  • The StarkEx SDK uses the term assetId.

  • The StarkEx API uses the term token_id.

The StarkEx API does not include the keyword asset_id. Use the keyword token_id in API calls to refer to a unique off-chain asset.

On-chain: StarkEx contracts

StarkEx contracts use the following terms:

selector

A 4-byte constant that specifies one of the following asset standards:

  • ETH

  • ERC-20

  • Mintable ERC-20

  • ERC-721

  • Mintable ERC-721

  • ERC-1155

  • Mintable ERC-1155

address

The address of the on-chain contract for a givent asset type.

assetInfo

The string concatenation of selector and address. The assetInfo parameter enables StarkEx to redeem assets according to their initial standard.

Be aware that in the ERC-721 and ERC-1155 on-chain StarkEx contracts, the terms assetId and tokenId have slightly different meanings from those in the contracts for ERC-20, ETH, and mintable ERC-721 assets.

Table 1. Meaning of assetId and tokenId for each type of asset
Asset type Description

ERC-20, ETH

There is no identifier for any one specific coin, unlike with ERC-721 or ERC-1155, because one unit of ETH or of an ERC-20 token has the same value as any other of the same type of token. StarkEx does not track individual assets of these types.

The StarkEx system calculates the value for assetId as follows:

  1. assetId = assetType

  2. assetType = hash(assetInfo, quantum)

  3. assetInfo = L1_contract_address + erc_type (selector)

ERC-721, ERC-1155

An NFT has two identifiers:

tokenId

Identifies the NFT within its on-chain ERC-721 or ERC-1155 contract scope, but another contract can have another asset with the same value for tokenId.

assetId

Uniquely identifies the NFT in the entire Ethereum blockchain.

For example, consider two NFTs within two separate contracts:

  • Mitzy is a digital kitten within contract A. Mitzy’s unique identifier within contract A is tokenId, which has a value of 0x1234.

  • Spot is a digital puppy within contract B. Spot’s unique identifier within contract B is tokenId, which also has a value of 0x1234.

So the value of tokenId is the same for both Mitzy and Spot.

However, both Mitzy and Spot each have their own unique value for assetId within the entire scope of Ethereum.

The value for assetId is calculated as follows:

  1. assetId = hash (selector, assetType, tokenId)

  2. assetType = hash(assetInfo, quantum) (For ERC-721, quantum = 1)

  3. tokenId is a unique identifier within the scope of the contract.

  4. assetInfo = L1_contract_address + erc_type (selector)

Mintable ERC-20, Mintable ERC-721, Mintable ERC-1155

This type of NFT is minted on L2. It does not exist on-chain until your user withdraws it from off-chain to on-chain.

When your user withdraws the NFT from off-chain to on-chain, you need to provide them with the mintingBlob and the assetType and use those values to generate a value for assetsId on your on-chain contract.

The value for assetId is calculated as follows:

assetId = hash(MINTABLE_PREFIX, assetType, blob_hash)

Computing assetInfo, assetType, and assetId

Below you can find a pseudo-code of the computation. For the full implementation, see asset.ts in the starkware-crypto-utils Github repository.

ETH

def getEthAssetInfo():
   ETH_SELECTOR = '0x8322fff2' # '0x8322fff2' = bytes4(keccak256(“ETH()”))
   asset_info = ETH_SELECTOR
   return asset_info


def getEthAssetType(quantum):
   asset_info = getEthAssetInfo()
   asset_type = keccak256(asset_info, quantum)
                & 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
   return asset_type


def getEthAssetId(quantum):
   asset_id = getEthAssetType(quantum)
   return asset_id

ERC-20

def getErc20AssetInfo(address):
   ERC20_SELECTOR = '0xf47261b0'
   # '0xf47261b0' = bytes4(keccak256('ERC20Token(address)'))
   asset_info = ERC20_SELECTOR + bytes.fromhex(address[2:]).rjust(32, b'\0')
   # For ERC20, asset_info is 36 bytes long
   return asset_info


def getErc20AssetType(address, quantum):
   asset_info = getErc20AssetInfo(address)
   asset_type = keccak256(asset_info, quantum)
                & 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
   return asset_type


def getErc20AssetId(quantum, address):
   asset_id = getErc20AssetType(quantum, address)
   return asset_id

Mintable ERC-20

def getErcMintable20AssetInfo(address):
   MINTABLE_ERC20_SELECTOR = '0x68646e2d'
   # 0xb8b86672 = bytes4(keccak256('MintableERC20Token(address)'))
   asset_info = MINTABLE_ERC20_SELECTOR + bytes.fromhex(address[2:]).rjust(32, b'\0')
   # For Mintable ERC20, asset_info is 36 bytes long.
   return asset_info


def getMintableErc20AssetType(address, quantum):
   asset_info = getErcMintable20AssetInfo(address)
   asset_type = keccak256(asset_info, quantum)
                & 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
   return asset_type

def getMintableErc20AssetId(minting_blob, address, quantum):
   asset_type = getMintableErc20AssetType(address, quantum)
   blob_hash = keccak256(minting_blob)
   asset_id = keccak256('MINTABLE:', asset_type, blob_hash)
              & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
   asset_id = asset_id
              | 0x700000000000000000000000000000000000000000000000000000000000000
   return asset_id

ERC-721

def getErc721AssetInfo(address):
   ERC721_SELECTOR = '0x02571792'
   # 0x02571792 = bytes4(keccak256('ERC721Token(address,uint256)'))
   asset_info = ERC721_SELECTOR + bytes.fromhex(address[2:]).rjust(32, b'\0')
   # For ERC721, asset_info is 36 bytes long.
   return asset_info


def getErc721AssetType(address):
   asset_info = getErc721AssetInfo(address)
   asset_type = keccak256(asset_info, 1)
                & 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
   return asset_type


def getErc721AssetId(token_id, address):
   asset_type = getErc721AssetType(address)
   asset_id = keccak256('NFT:', asset_type, token_id)
               & 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
   return asset_id

Mintable ERC-721

def getErcMintable721AssetInfo(address):
   MINTABLE_ERC721_SELECTOR = '0xb8b86672'
   # 0xb8b86672 = bytes4(keccak256('MintableERC721Token(address,uint256)'))
   asset_info = MINTABLE_ERC721_SELECTOR + bytes.fromhex(address[2:]).rjust(32, b'\0')
   # For Mintable ERC721, asset_info is 36 bytes long.
   return asset_info


def getMintableErc721AssetType(address):
   asset_info = getErcMintable721AssetInfo(address)
   asset_type = keccak256(asset_info, 1)
                & 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
   return asset_type


def getMintableErc721AssetId(minting_blob, address):
   asset_type = getMintableErc721AssetType(address)
   blob_hash = keccak256(minting_blob)
   asset_id = keccak256('MINTABLE:', asset_type, blob_hash)
              & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
   asset_id = asset_id
              | 0x400000000000000000000000000000000000000000000000000000000000000
   return asset_id

ERC-1155

def getErc1155AssetInfo(address):
    ERC1155_SELECTOR = `0x3348691d`
    # 0x3348691d = bytes4(keccak256('ERC1155Token(address,uint256)'))
    asset_info = ERC1155_SELECTOR + bytes.fromhex(address[2:]).rjust(32, b'\0')
    return asset_info

def getErc1155AssetType(address,quantum):
    asset_info = getErc1155AssetInfo(address)
    asset_type = keccak256(asset_info, quantum)
                 & 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
    return asset_type

def getErc1155AssetId(token_id, address):
    asset_type = getErc1155AssetType(address)
    asset_id = keccak256("NON_MINTABLE:", asset_type, token_id)
               & 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
    return asset_id

Mintable ERC-1155

def getErcMintable1155AssetInfo(address):
   MINTABLE_ERC1155_SELECTOR = '0xbae32628'
   # 0xbae32628 = bytes4(keccak256('MintableERC1155Token(address,uint256)'))
   asset_info = MINTABLE_ERC1155_SELECTOR + bytes.fromhex(address[2:]).rjust(32, b'\0')
   # For Mintable ERC1155, asset_info is 36 bytes long.
   return asset_info


def getMintableErc1155AssetType(address, quantum):
   asset_info = getErcMintable1155AssetInfo(address)
   asset_type = keccak256(asset_info, quantum)
                & 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
   return asset_type

def getMintableErc1155AssetId(minting_blob, address):
   asset_type = getMintableErc1155AssetType(address)
   blob_hash = keccak256(minting_blob)
   asset_id = keccak256('MINTABLE:', asset_type, blob_hash)
              & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
   asset_id = asset_id
              | 0x600000000000000000000000000000000000000000000000000000000000000
   return asset_id