Trading Engine

Overview

Carbon has deployed a suite of contracts to extend the usage of Carbon's trading engine on EVM. EVM users are now able to create orders, query order and position details as well as perform token transfers and token conversion without having prior interaction with Carbon Core. Developers are also able to deploy smart contracts to perform automated trading strategies. dApps to pool liquidity from independent users to employ specific trading strategies, performing automated trades to passively grow funds.

Below are the contracts deployed aimed to provide seamless usage of Carbon's trading engine on Carbon EVM:

Users should always verify the origin of the contracts and ensure that the source of the querier are from Carbon Core Modules. List of modules address are listed here.

  1. OrderQuerier (Order Module)

    • Query the details of your order using the Carbon Order Id or EVM Order Key (orders stemming from OrderCreation contract)

  2. PositionQuerier (Position Module)

    • Query the position details of the specified address for the specific market

  3. MarketQuerier (Market Module)

    • Query the market details such as the base and quote denomination and precision. Mainly targeted for trading contracts to provide the Satoshi quantity for orders

  4. OrderCreation (Order Module)

    • The main bridge for the creation of order via EVM. Current implementation can only support Fill or Kill (FOK) orders.

  5. TransferConverter (EVMContract Module)

    • This utility contract allows users and contract accounts to perform Token conversion or token transfers between Carbon accounts. This allows directs users and contract owners to manage funds under the trading contract address.

  6. AccountMerger (EVMContract Module)

    • This utility contract allows contracts and Externally Owned Addresses (EOA) to create accounts on Carbon accounts for trading. These merge accounts will allow users to maintain the same account details when migrating over to Carbon Core.

Developers - Callback Responses

Querier contract and methods employ the use of callbacks to respond with the requested data. This is due to the nature of EVM hooks of the EVM module. Carbon EVM is not able to directly and immediately respond to queries and actions existing on Carbon Core.

Process Flow

Upon query call, the querier contracts emit events which Carbon Core modules receive and process. Carbon Core modules then make corresponding calls to the querier contracts to update the requested data. Lastly, the querier contracts will make call to the initial caller address using a specified callback signature.

Any contract that wishes to perform queries will need to implement the callback signature in order to receive the requested data from the query.


User Flow

1. Account Merging

Direct Users

This step is not required for users that have previously traded on Carbon Core with their EVM address.

First time users of Carbon's trading engine will need to create a Carbon account by using MergeEVMAccount in AccountMerger contract. Users will then be able to transfer and convert tokens for trading via both EVM and Carbon Core. Users will need to send their public key for verification purposes. A signature is not required if you are attempting to merge your own address.

Developers

Developers can deploy trading contracts to make trades on their behalf. The address of the smart contract will be utilised as the Carbon account when making orders. Prior to trading and transfer of tokens, the deployed contract will need create a Carbon account by calling MergeContractAccount in AccountMerger contract.

Developers looking to merge account on behalf of users will need to

Usage

  1. Users can query this endpoint for the list of contracts available. Look for the contract type of AccountMerger and verify the version number and active status of the contract.

  2. EOA users will need to call MergeEvmAccount passing in your public key as a hexadecimal string. The public key signature field can be left as an empty string "". To merge a contract address simply call MergeContractAccount via the contract you wish to create a Carbon account for.

  3. For contracts that wish to merge accounts on behalf of EOA users can also use MergeEvmAccount. Both public key and a signature from the public key will need to be provided for verification purposes.

  4. Users can utilise the TransferConverter contract to verify the creation of their Carbon account by querying its balance using the method QueryBalance.

AccountMerger Contract

  • For contracts that wish to merge accounts on behalf of EOA users can also use MergeEvmAccount. Both public key and a signature from the public key will need to be provided for verification purposes.

  • Users can utilise the TransferConverter contract to verify the creation of their Carbon account by querying its balance using the method QueryBalance.

MergeEvmAccount

Creates a Carbon address using the public key provided and maps both Carbon and EVM address together. This allows both addresses to be recognised as the same account.

Parameters

  1. pubKey_ (string) Hexadecimal string of the sender's public key

  2. pubKeySig_ (string) Hexadecimal string of the resultant signature from the public key. This field can be left empty ,"", if the message sender is the owner of the public key.

MergeContractAccount

Converts the contract address directly into a Carbon account address and maps both addresses to be recognised as the same account. This method can only be utilised by contracts and will not work unless called by a contract.

2. Transfer and Convert

Once an account is created, funds can now be transferred for trading. As trades are made using Cosmos-native ICS-20 tokens, users with only ERC-20 tokens will need to perform token conversion using TransferConverter contract.

What is Token Conversion?

ERC-20 tokens and balances exist within Carbon EVM are cannot be used for trades on Carbon Native's trading engine. In order to trade on Carbon Native, ERC-20 tokens need to be converted into Cosmos-Native ICS-20 tokens and transferred into to the address's balance. This is done via the Token Conversion Module where token-pair contracts are deployed to map ICS-20 tokens to the equivalent ERC-20 token.

ERC-20 to ICS-20

For tokens created on Carbon EVM, a token-pair contract is deployed to map this ERC-20 token to a newly minted ICS-20 on Carbon Native. During conversion, ERC-20 tokens are escrowed into the contract address and the corresponding amount of ICS-20 tokens are minted and sent to the specified receiver's address. Upon conversion back to ERC-20 tokens, the corresponding ICS-20 tokens are burned to maintain the correct total supply of tokens on Carbon Native and Carbon EVM.

ICS-20 to ERC-20

Inversely, Cosmos-Native ICS-20 tokens can be paired to a new ERC-20 token created on Carbon EVM. During conversion, ICS-20 tokens are escrowed into the Token conversion module address and minted to receiver's address on the token-pair contract specified by the user. The receiver's balance on the token-pair contract is updated and any movement of funds will have to be carried out from the token-pair contract.

Usage

  1. Users can query this endpoint for the list of contracts available. Look for the contract type of TransferConverter and verify the version number and active status of the contract.

  2. Owners of ERC-20 tokens will need to call ConvertERC20ToCoin to convert their ERC-20 tokens to Cosmos-Native ICS-20 tokens and send them to the specified account for trading. This is done using the specified token-pair contract that maps the ERC-20 token to a corresponding Cosmos-Native token.

  3. Users can utilise ConvertCoinToERC20 to convert their Cosmos-Native tokens back to ERC-20 tokens and update the receiver's balance within the corresponding token-pair contract.

  4. Using QueryBalance, users can verify their address's balance. With available balance, users can now perform trades via the OrderCreation contract.

TransferConverter Contract

QueryBalance

Returns the available amount of the specified token denomination in the address provided. The amount returned is represented as an integer including the precision of the token denomination.

Developers

Caller contracts will need to implement the specific callback signature found in balanceCallback, to receive and process the requested data.

Parameters

  1. account_ (address) EVM address of the account to query. This address will need to have a Carbon account created in this step.

  2. denom_ (string) Denomination of the token to be queried.

TransferToken

Allows users to perform transfers of Cosmos-Native ICS-20 tokens between accounts existing on Carbon Native. This method validates that the caller is the source address to only allow the account owner to transfer tokens out of the address. The source address's token balance is validated and the transfer will fail and revert if there is insufficient balance.

Parameters

  1. from_ (address) Token sender's EVM address. This address will need to have a Carbon account created in this step.

  2. to_ (address) Token receiver's EVM address. Similarly, this address will need to an existing Carbon account.

  3. denom_ (string) Specified token denomination for transfer.

  4. amount_ (uint256) Quantity of tokens to be transferred. This quantity is represented as an integer and needs to take into account the specific token precision.

ConvertCoinToERC20

Converts Cosmos-Native ICS-20 tokens to Carbon EVM ERC-20 tokens. Balance of the receiver is updated on the corresponding token-pair smart contract. This method validates that the caller is the sender address to only allow the account owner to perform the conversion.

Parameters

  1. sender_ (address) Token sender's EVM address. This address will need to have a Carbon account created in this step.

  2. receiver_ (address) Token receiver's EVM address. Similarly, this address will need to an existing Carbon account.

  3. denom_ (string) Specified token denomination for transfer.

  4. amount_ (uint256) Quantity of tokens to be transferred. This quantity is represented as an integer and needs to take into account the specific token precision.

ConvertERC20ToCoin

Converts Carbon EVM ERC-20 tokens to Cosmos-Native ICS-20 tokens. The converted coins are directly sent to the receiver's address and balance is updated on Carbon Native. This method validates that the caller is the sender address to only allow the account owner to perform the conversion.

Parameters

  1. sender_ (address) Token sender's EVM address. This address will need to have a Carbon account created in this step.

  2. receiver_ (address) Token receiver's EVM address. Similarly, this address will need to an existing Carbon account.

  3. pairContract_ (address) Token-pair contract address which the ERC-20 token is registered to for balance account on Carbon EVM.

  4. amount_ (uint256) Quantity of tokens to be transferred. This quantity is represented as an integer and needs to take into account the specific token precision.

3. Creating Orders

Currently, only FOK limit or market orders are supported on Carbon EVM

Usage

  1. Users can query this endpoint for the list of contracts available. Look for the contract type of OrderCreation and verify the version number and active status of the contract.

  2. Users should use the MarketQuerier contracts deployed to obtain the list of available markets along with the relevant token denomination and precision required for detailing order.

  3. Orders can be made by simply calling the CreateOrder method on OrderCreation contract. By specifying the order details in the contract call, a corresponding order will be inserted into the order matching engine on Carbon Core for processing. CreateOrder returns the caller a temporary order identifier (Order Key) that will be used to query for the order's final status. More detailed information on order detailing can be found below.

Order Key generated by OrderCreation contract is a temporary identifier and will be replaced by a permanent Order Id generated by Carbon Core's trading engine.

Order Id is a permanent identifier that can be used to query order details any time after creation on CarbonScan and Carbon EVM.

  1. Users should immediate utilise the contract type OrderQuerier and method QueryOrder to query the final status of the order made. QueryOrder is also able to support queries using the Order Id generated by Carbon Core's trading engine.

  2. User can also check their position a the market via the PositionQuerier Contract. Calling the QueryPosition returns the position of the specified address in a particular market.

OrderQuerier and PositionQuerier respond to queries via callbacks and are unable to support calls directly from EOA users.

OrderCreation Contract

CreateOrder

This method generates a Fill Or Kill order which is passed onto Carbon Core's trading engine for creation and order matching.

Parameters

  1. market_ (string) Name of the market that the order is to be placed into

  2. side_ (OrderTypes.Side / uint8) Enumerated type denoting if the order is a "buy" or "sell" order. 0 - Buy 1 - Sell

  3. quantity_ (uint256) Total quantity of tokens the order is for. This value needs to take into account the token's precision.

  4. orderType_ (OrderTypes.OrderType / unit8) Enumerated type denoting if the order is a Limit or Market order. 0 - Limit 1 - Market

  5. price_ (unit256) Price that the order will be executed at. This value is an integer representation of a decimal value with 18 places (last 18 digits represent the value of the decimals). This field can be left as zero if a market order is placed.

  6. isReduceOnly_ (bool) Specifies a reduce only option for the order whereby the order will only execute if it reduces the creator's position. This option is not available for Spot markets.

Returns

  1. orderKey (string) Temporary identifier generated by OrderCreation contract for the purpose of identifying the order created and utilised for the querying of the order's final state.

The below querier contracts are designed to provide users with further utility to interact with the trading engine.

MarketQuerier Contract

This querier contract contains the essential information on all trading market in Carbon Core. User are able to query the contract for details of a specified market such as the token's precision (required to correctly specify the quantity of the order).

MarketNames

This method lists all the market names which can be querier on the contract.

Returns

  1. names ([ ]string) An array of all the market names with details store within the contract for querying.

Markets

The method return the details of the market specified by the caller.

Parameters

  1. marketName_ (string) Market name of the market to be queried

Returns

  1. market (MarketTypes.Market) Define struct containing the following details of a market. - Name - DisplayName - Base - Base token denomination - Quote - Quote token denomination - BasePrecision - Precision of the base token - QuotePrecision - Precision of the quote token - MinQuantity - Minimum quantity that an order must have to be considered valid - IsActive - denotes if the market is currently active for trading

OrderQuerier Contract

The nature of Carbon's batched-based matching does not allow OrderCreation contract to immediately return the final status of the order placed. OrderQuerier contract allows smart contracts to query for the status of an order and process them by utilising callbacks.

QueryOrder

Returns the finalised order details for the given EVM Order Key or Carbon Core Order Id

Developers

Caller contracts will need to implement the specific callback signature found in queryCallback, to receive and process the requested data.

Parameters

  1. orderKey_ (string) EVM Order Key or Carbon Core Order Id

Return

  1. orderKey (string) EVM Order Key if it exists

  2. Order (OrderTypes.Order)

    1. id (string) - Carbon Core generated Order Id

    2. market (string) - Market name that the order was made to

    3. Side (enum) - 0 for "Buy" and 1 for "Sell"

    4. Price (enum) - Specified price for order execution. Integer representation of a decimal with 18 places.

    5. Quantity (uint256) - Quantity of the order with the token precision taken into account

    6. Status (enum) - 0 for "unprocessed" - Order has not been inserted into the trading engine 1 for "pending" - Order is pending order matching by the trading engine 2 for "closed" - Order has been completely filled 3 for "cancelled" - Order has been cancelled and was not fulfilled 4 for "open" - Order is still open with available quantity

    7. OrderType (enum) - 0 for Limit order and 1 for Market order

    8. TimeInForce (enum) - 0 for Fill Or Kill order

    9. AvgFilledPrice (uint256) - Average price that the order was filled at. Integer representation of a decimal with 18 places.

    10. IsReduceOnly (bool) - Reduce only option selected for the order

    11. EvmCreator (address) - EVM address of the order creator

  3. Error (string) Error message if it exists.

PositionQuerier Contract

User are able to check on their current position through PositionQuerier. Position queries are responded to after the trading has finalised trades in order to return the finalised position for the current block.

QueryPosition

Returns the position details of the specified address and market.

Developers

Caller contracts will need to implement the specific callback signature found in queryCallback to receive and process the requested data.

Parameters

  1. accountAddress_ (address) EVM address of the account to query

  2. market_ (string) Name of the market to query position

Returns

  1. evmAddress (address) EVM address of the position queried

  2. Position (OrderTypes.Position)

    1. market (string) - Market name that the position belongs to

    2. carbonAddress (string) - Merged Carbon address that the EVM address corresponds to

    3. Lots (int256) - Quantity held by the position

    4. EntryPrice (uint256) - Entry price of the position, integer representation of an decimal with 18 places.

    5. RealizedPnl (int256) - Realized profit and loss of the position

    6. AllocatedMarginDenom (string) - Denomination of the token held as margin

    7. AllocatedMarginAmount (uint256) - Quantity of tokens held as margin, taking into account the precision of the token.

    8. OpenedBlockHeight (uint256) - Block height at which the position was initially opend

Last updated