In the Ethereum blockchain, the amounts of tokens are represented by a 256-bit number. However, for reasons of efficiency, all the amounts in StarkEx are represented by a 64-bit number.
Since the inputs to all the off-chain transactions and some on-chain requests are given in StarkEx representation, it is crucial that the code that generates the transaction signature uses the correct quantization/resolution. Therefore, the quantization/resolution is reflected in the
assetId, i.e. a unique StarkEx asset representation, as we explain in detail below.
In this section, we explain how to convert between one representation to the other.
The quantization factor (sometimes referred to as quantum) represents the multiplier of a StarkEx amount of tokens to get the blockchain amount. Namely, if the quantization of an asset is it means that tokens in StarkEx represent tokens in blockchain representation.
The resolution factor represents the reverse direction from quantization. That is, instead of asking "how many WEI are represented by writing '1' in the system" we ask: "what is the number in the system that represents 1 ETH" .
In perpetual trading, we use resolution, rather than quantization, for all the synthetic assets. Notice that since these assets are not represented on-chain, quantization is not needed. However, resolution provides the following benefits:
Since signed external Oracle prices are given in round units, for example, BTC/ETH and not Satoshi/WEI, it makes the translation to the price used in the system, sound.
Since users usually refer to buying/selling in round units, for example, BTC and not satoshi, it makes the system easier to understand.
Inside StarkEx and independently of their standard (ETH/ERC20/ERC721/Synthetics), all assets have the same APIs.
In the off-chain application, the
assetId uniquely identifies the asset for all the off-chain flows (Transfer/Conditional Transfer/Limit Order/Withdrawal)
For on-chain assets (non-synthetic assets), the off-chain
assetId is cryptographically bound to the identity of the token as represented on-chain (external ERC20/721 for deposit/withdraw goes through, correct quantization, etc), and therefore the calculation of
assetId is as follows:
assetInfo, the string concatenation of
selector (explained below) and
address _(if relevant)._ It enables StarkEx to redeem assets according to their initial standard.
assetType, the 250-bit hash of
quantum. It enables StarkEx to convert off-chain __balance to on-chain balance
assetId, a 250-bit number which definition depends on the asset standard.
assetId is the only asset identifier off-chain.
assetId, we need:
Selector, the 4-byte constant specifying the asset standard. Either ETH, ERC20, or ERC721.
Address **(if relevant), __the asset contract address
Quantum **(if relevant), the multiplicative factor from the on-chain 256-bits integer balance to the 63-bits integer used as balance in StarkEx. Only amounts divisible by the quantum can be deposited in the system.
TokenId **(if relevant), __the asset serial number in the context of ERC721
Below you can find a pseudo-code of the computation. Full implementation in JS can be found here.
def getEthAssetInfo():ETH_SELECTOR = '0x8322fff2' # '0x8322fff2' = bytes4(keccak256(“ETH()”))asset_info = ETH_SELECTORreturn asset_infodef getEthAssetType(quantum):asset_info = getEthAssetInfo()asset_type = keccak256(asset_info, quantum)& 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFreturn asset_typedef getEthAssetId(quantum):asset_id = getEthAssetType(quantum)return asset_id
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 longreturn asset_infodef getErc20AssetType(quantum, address):asset_info = getErc20AssetInfo(address)asset_type = keccak256(asset_info, quantum)& 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFreturn asset_typedef getErc20AssetId(quantum, address):asset_id = getErc20AssetType(quantum, address)return asset_id
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_infodef getErc721AssetType(address):asset_info = getErc721AssetInfo(address)asset_type = keccak256(asset_info, 1)& 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFreturn asset_typedef getErc721AssetId(token_id, address):asset_type = getErc721AssetType(address)asset_id = keccak256('NFT:', asset_type, token_id)& 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFreturn asset_id
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_infodef getMintableErc721AssetType(address):asset_info = getErcMintable721AssetInfo(address)asset_type = keccak256(asset_info, 1)& 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFreturn asset_typedef getMintableErc721AssetId(minting_blob, address):asset_type = getMintableErc721AssetType(address)blob_hash = keccak256(minting_blob)asset_id = keccak256('MINTABLE:', asset_type, blob_hash)& 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFasset_id = asset_id| 0x4000000000000000000000000000000000000000000000000000000000000000return asset_id
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_infodef getMintableErc20AssetType(address, quantum):asset_info = getErcMintable20AssetInfo(address)asset_type = keccak256(asset_info, quantum)& 0x03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFreturn asset_typedef getMintableErc20AssetId(minting_blob, address, quantum):asset_type = getMintableErc721AssetType(address, quantum)blob_hash = keccak256(minting_blob)asset_id = keccak256('MINTABLE:', asset_type, blob_hash)& 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFasset_id = asset_id| 0x4000000000000000000000000000000000000000000000000000000000000000return asset_id