Skip to content

Otmoic

Introduction

Otmoic is a trustless automatic value exchanging protocol based on Snowinning Protocol, built for Depin, AI Agent, and Crypto Trading.

The vision of Otmoic is to give public goods a fair price.

Otmoic Protocol has the following features:

  • Provides on-chain reputation mechanism for trader and liquidity provider, solving the free mint problem
  • Supports KYC based on Verifiable Credential
  • RFQ-based price discovery
  • Supports Atomic swap based on-chain transactions
  • Supports automatic market making by liquidity providers through applications installation in Terminus OS

With the above design, Otmoic Protocol can be widely used in Depin, AI Bot, Creator Economy, Crypto Trading, Crypto Crossing Chain, Fiat And Crypto Gateway and other scenarios.

Open-source projects

You can check the protocol codes here:

Below are the details of the protocol.

Spec

Resources

Data

  • BridgeInfo

    nametyperequireddescription
    src_chain_iduintThe chain ID on which the user transfers out tokens, following BIP-44 coin types
    dst_chain_iduintThe chain ID on which the user transfers in tokens, following BIP-44 coin types
    src_tokenStringThe token which the user transfers out
    dst_tokenStringThe token which the user transfers in
    bridge_nameString<src_chain_id>-<src_token>-<dst_chain_id>-<dst_token>
  • QuoteBase

    nametyperequired: amm -> lpnoderequired: lpnode -> relayrequired: ask reply: amm -> lpnoderequired: ask reply: lpnode -> relaydescription
    bridgeBridgeInfoInformation of the trading pair to which this quotation belongs
    lp_bridge_addressStringThe recepient address of LP
    lp_node_uriStringThe publicly accessible address of the LP program, on which the relay relies to communicate with lpnode
    quote_hashStringThe hash of this quotation used as a unique identifier
    priceStringThe exchange price quoted in integer multiples of the token
    native_token_priceStringThe price to exchange for native token, also quoted in integer multiples of the token
    native_token_maxStringHow many native tokens can be exchanged this time
    native_token_minStringThe minimum amount to exchange for native tokens if any
  • QuoteAuthenticationLimiter

    nametyperequireddescription
    limiter_stateStringWhether to turn on the limiter
    country_white_listStringLimit by country - whitelist separated by ","
    country_black_listStringLimit by country - blacklist separated by ","
    min_ageStringThe minimum age at which users can trade

    NOTE

    • If the limiter is on, all counterparties that have not done KYC on the relay will be rejected
    • Only one of the blacklist and whitelist is effective and the whitelist has higher priority. The blacklist takes effect if the whitelist is empty.
    • If the whitelist is configured, all other countries are blacklisted.
  • LPInfo

    nametyperequireddescription
    nameStringThe name of LP - must use Terminus Name
    profileStringIntroduction of LP - arbitrary content
    credit_scoreuintCredit score of LP in the current relay

    NOTE

    • The calculation of credit_score consists of two parts:
      • the basic score is calculated based on the transaction count and average waiting time during a recent period
      • the complaint penalty is a permenant scoring when there is a complaint on the transaction and it is confirmed by the system
  • Quote

    nametyperequireddescription
    quote_baseQuoteBaseQuoting information
    authentication_limiterQuoteAuthenticationLimiterLimiter of this quotation
    lp_infoLPInfoLP information
    timestampLongTimestamp of this quotation
  • Ask

    nametyperequireddescription
    bridgeStringThe name of the trading pair, same as bridge_name in BridgeInfo
    amountStringToken amount that the user expects to exchange for
  • SwapAssetInformation

    nametyperequired: FE -> relayrequired: relay -> lpnoderequired: lpnode -> ammdescription
    bridge_nameStringName of the trading pair
    lp_idStringName of LP
    senderStringWallet address that executes transfer-out
    amountStringToken amount to transfer out
    dst_addressStringRecepient address for transfer-in
    dst_amountStringToken amount to transfer in
    dst_native_amountStringAdditional native token received during transfer-in
    step_time_lockLongThe limitation of duration of every step
    agreement_reached_timeLongThe time when the agreement is reached
    requestorStringThe identity verification address of swap initiator
    user_signStringThe transaction information signature of the user
    lp_signStringThe transaction information signature of the LP
    quoteQuoteThe quotation selected by the transaction initiator
    system_fee_srcuintCommission charged by the current contract - chain for transfer-out
    system_fee_dstuintCommission charged by the current contract - chain for transfer-in
    dst_amount_needStringWhether to exchange for token
    dst_native_amount_needStringWhether to exchange for native token
    append_informationStringAdditional information

    NOTE

    dst_amount_need and dst_native_amount_need is derived by the relay based on information of this swap system_fee_dst and system_fee_src is fetched on-chain by the relay

    The above four variables are not necessary parameters of the exchanging process. They exist only for reducing implementation difficulty of later processes and other modules.

  • About the operation duration limit of each step

    • transferOut: must be called before agreement_reached_time + 1 * step_time_lock otherwise it will fail
    • transferIn: must be called before agreement_reached_time + 2 * step_time_lock otherwise it will fail
    • confirmTransferOut:
      • if using the hashlock of transaction initiator, must be called before agreement_reached_time + 3 * step_time_lock otherwise it will fail
      • if using the hashlock of the relay, must be called before agreement_reached_time + 6 * step_time_lock otherwise it will fail
    • confirmTransferIn: must be called before agreement_reached_time + 5 * step_time_lock otherwise it will fail
    • refundTransferOut: must be called after agreement_reached_time + 7 * step_time_lock otherwise it will fail
    • refundTransferIn: must be called after agreement_reached_time + 7 * step_time_lock otherwise it will fail

NOTE

The expected normal operation process and time limit are:

  • transferOut: 1 * step_time_lock
  • transferIn: 2 * step_time_lock
  • confirmTransferOut: 3 * step_time_lock
  • confirmTransferIn: 4 * step_time_lock

However, considering possible cheating on both sides, the time limits of confirmTransferOut and confirmTransferIn need to be adjusted.

  • If LP have not performed confirmTransferIn until 4 _ step_time_lock, the relay will perform the operation by itself. The duration 4 _ step_time_lock ~ 5 * step_time_lock is for the relay to prevent cheating.
  • The hashlock used during transferIn is provided by the transaction initiator so relay will use the hashlock of itslef to perform confirmTransferOut if the transaction initiator perform confirmTransferIn near the time limit of 5 _ step_time_lock. The duration 5 _ step_time_lock ~ 6 * step_time_lock is for the relay to prevent cheating.
  • About Transaction signatures

    The transaction initiator should use the requestor to sign the transaction and the signature is filled in user_sign field. LP should use the address that has been verified by the DID contract to sign the transaction and the signature is filled in lp_sign field.

NOTE

The signatures follow EIP-712 standard on EVM-compatible chains. The signatures follow supported similar protocols on other chains.

  • EIP712 Types

    types: {
      EIP712Domain: [
        { name: 'name', type: 'string' },
        { name: 'version', type: 'string' },
        { name: 'chainId', type: 'uint256' },
      ],
      Message: [
        { name: 'src_chain_id', type: 'uint256' },
        { name: 'src_address', type: 'string' },
        { name: 'src_token', type: 'string' },
        { name: 'src_amount', type: 'string' },
        { name: 'dst_chain_id', type: 'uint256' },
        { name: 'dst_address', type: 'string' },
        { name: 'dst_token', type: 'string' },
        { name: 'dst_amount', type: 'string' },
        { name: 'dst_native_amount', type: 'string' },
        { name: 'requestor', type: 'string' },
        { name: 'lp_id', type: 'string' },
        { name: 'step_time_lock', type: 'uint256' },
        { name: 'agreement_reached_time', type: 'uint256' },
      ],
    }

    BidId Generation

    sha3(
      agreement_reached_time +
      src_chain_id +
      lp_bridge_address +
      src_token +
      dst_chain_id +
      dst_address +
      dst_token +
      amount +
      dst_amount +
      dst_native_amount +
      requestor +
      lp_id +
      step_time_lock +
      user_sign +
      lp_sign
    )
  • PreBusiness

    nametyperequired: relay -> lpnoderequired: lpnode -> ammrequired: relay -> FEdescription
    swap_asset_informationSwapAssetInformationThe exchange information
    hashStringThe hash generated from main information in the exchange
    relay_hashlockStringThe hashlock provided by the relay
    is_kycBooleanWhether the transaction initiator have done KYC in the relay's system
    kyc_infoKycInfoComplete KYC information of the transaction initiator
    lockedBooleanWhether the two parties have reached agreement
  • About KYC Info

    Users need to provide their on-chain address when doing KYC with the relay. After KYC is done, the swap initiated with signature of this address will match the limiter with the state of successful KYC and provide complete KYC information like LP for confirmation. For more info see the chapter about KYC below.

  • About The Lock Bit

    In the data returned to frontend, the Lock bit tells whether the agreement is reached and the tokens need to be locked. Its value is false in the following cases:

    NOTE

    • The recovered address calculated from user_sign and other swap information is different from the requestor address
    • The recovered address calculated from lp_sign and other swap information have not been verified on-chain
    • The transaction initiator does not satisfy the limits set in the quotation
    • Other unknown reasons (e.g. the LP may reject this swap request in cases of insufficient balance or large price deviation)
  • TransferOut-EVM

    Below are calling parameters of the contract interface.

    nametyperequireddescription
    senderaddressThe initiator of this operation, same as the requestor in most cases but no such limit
    bridgeaddresslp_bridge_address in QuoteBase
    tokenaddresssrc_token in BridgeInfo
    amountuint256amount in SwapAssetInformation
    hashlockbytes32The hashlock provided by the transaction initiator
    relayHashlockbytes32relay_hashlock in PreBusiness
    stepTimelockuint64step_time_lock in SwapAssetInformation
    dstChainIduint64dst_chain_id in BridgeInfo
    dstAddressuint256dst_address in SwapAssetInformation
    bidIdbytes32hash in PreBusiness
    tokenDstuint256dst_token in BridgeInfo
    amountDstuint256dst_amount in SwapAssetInformation
    nativeAmountDstuint256dst_native_amount in SwapAssetInformation
    agreementReachedTimeuint64agreement_reached_time in SwapAssetInformation
    requestorstringrequestor in SwapAssetInformation
    lpIdstringlp_id in SwapAssetInformation
    userSignstringuserSign in SwapAssetInformation
    lpSignstringlpSign in SwapAssetInformation

    About hashlock

    • The transaction initiator provides bytes32 data as the lock for releasing tokens and will be verified by keccak256(preimage) during Confirm operation. The locked tokens are released if this is verified and other conditions are met.
    • TransferIn uses the same lock as TransferOut.
    • After publishing the preimage during ConfirmTransferOut, the LP can use the preimage to perform TransferIn.
  • EventTransferOut-EVM

    nametyperequireddescription
    transfer_idbytes32The ID of this operation
    senderaddressSame field as in TransferOut
    bridgeaddressSame field as in TransferOut
    tokenaddressSame field as in TransferOut
    amountuint256Same field as in TransferOut
    hashlockbytes32Same field as in TransferOut
    relay_hashlockbytes32Same field as in TransferOut
    step_time_lockuint64Same field as in TransferOut
    dst_chain_iduint64Same field as in TransferOut
    dst_addressuint256Same field as in TransferOut
    bid_idbytes32Same field as in TransferOut
    token_dstuint256Same field as in TransferOut
    amount_dstuint256Same field as in TransferOut
    native_amount_dstuint256Same field as in TransferOut
    agreement_reached_timeuint64Same field as in TransferOut
    requestorstringSame field as in TransferOut
    lp_idstringSame field as in TransferOut
    user_signstringSame field as in TransferOut
    lp_signstringSame field as in TransferOut
  • TransferIn-EVM

    Below are calling parameters of the contract interface.

    nametyperequireddescription
    senderaddressThe initiator of this operation
    dst_addressaddressdst_address in SwapAssetInformation
    tokenaddressdst_token in BridgeInfo
    token_amountuint256dst_amount in SwapAssetInformation
    eth_amountuint256dst_native_amount in SwapAssetInformation
    hashlockbytes32hashlock in EventTransferOut
    step_time_lockuint64step_time_lock in SwapAssetInformation
    src_chain_iduint64src_chain_id in BridgeInfo
    src_transfer_idbytes32transfer_id in EventTransferOut
    agreement_reached_timeuint64agreement_reached_time in SwapAssetInformation
  • EventTransferIn-EVM

    nametyperequireddescription
    transfer_idbytes32The ID of this operation
    senderaddressSame field as in TransferIn
    receiveraddressSame field as in TransferIn
    tokenaddressSame field as in TransferIn
    token_amountuint256Same field as in TransferIn
    eth_amountuint256Same field as in TransferIn
    hashlockbytes32Same field as in TransferIn
    step_time_lockuint64Same field as in TransferIn
    src_chain_iduint64Same field as in TransferIn
    src_transfer_idbytes32Same field as in TransferIn
    agreement_reached_timeuint64Same field as in TransferIn
  • ConfirmTransferOut-EVM

    Below are calling parameters of the contract interface.

    nametyperequireddescription
    senderaddressSame field as in TransferOut
    receiveraddressSame field as in TransferOut
    tokenaddressSame field as in TransferOut
    token_amountuint256Same field as in TransferOut
    eth_amountuint256Same field as in TransferOut
    hashlockbytes32Same field as in TransferOut
    relay_hashlockbytes32Same field as in TransferOut
    step_time_lockuint64Same field as in TransferOut
    preimagebytes32The preimage of hashlock
    relay_preimagebytes32The preimage of relay_hashlock
    agreement_reached_timeuint64Same field as in TransferOut
  • EventConfirmTransferOut-EVM

nametyperequireddescription
transfer_idbytes32transfer_id in EventTransferOut
preimagebytes32Same field as in ConfirmTransferOut
  • ConfirmTransferIn-EVM

    Below are calling parameters of the contract interface.

    nametyperequireddescription
    senderaddressSame field as in TransferIn
    dst_addressaddressSame field as in TransferIn
    tokenaddressSame field as in TransferIn
    token_amountuint256Same field as in TransferIn
    eth_amountuint256Same field as in TransferIn
    hashlockbytes32Same field as in TransferIn
    step_time_lockuint64Same field as in TransferIn
    preimagebytes32preimage in EventConfirmTransferOut
    agreement_reached_timeuint64Same field as in TransferIn
  • EventConfirmTransferIn-EVM

    nametyperequireddescription
    transfer_idbytes32transfer_id in EventTransferIn
    preimagebytes32preimage in ConfirmTransferIn
  • RefundTransferOut-EVM

    Below are calling parameters of the contract interface.

    nametyperequireddescription
    senderaddressSame field as in TransferOut
    receiveraddressSame field as in TransferOut
    tokenaddressSame field as in TransferOut
    token_amountuint256Same field as in TransferOut
    eth_amountuint256Same field as in TransferOut
    hashlockbytes32Same field as in TransferOut
    relay_hashlockbytes32Same field as in TransferOut
    step_time_lockuint64Same field as in TransferOut
    agreement_reached_timeuint64Same field as in TransferOut
  • EventRefundTransferOut-EVM

    nametyperequireddescript
    transfer_idbytes32transfer_id in EventTransferOut
  • RefundTransferIn-EVM

    Below are calling parameters of the contract interface.

    nametyperequireddescription
    senderaddressSame field as in TransferIn
    dst_addressaddressSame field as in TransferIn
    tokenaddressSame field as in TransferIn
    token_amountuint256Same field as in TransferIn
    eth_amountuint256Same field as in TransferIn
    hashlockbytes32Same field as in TransferIn
    step_time_lockuint64Same field as in TransferIn
    agreement_reached_timeuint64Same field as in TransferIn
  • EventRefundTransferIn-EVM

    nametyperequireddescript
    transfer_idbytes32transfer_id in EventTransferIn
  • Business

    nametyperequireddescription
    stepuintCurrent progress of the exchange process
    business_hashStringhash in PreBusiness

    NOTE

    The steps are maintained by the relay.

    • 1: Agreement is reached and LP locks shares
    • 2: Tokens for transfer-out are locked
    • 3: Tokens for transfer-in are locked
    • 4: Tokens for transfer-out are released
    • 5: Tokens for transfer-in are released
    • 6: Tokens for transfer-out are refunded
    • 7: Tokens for transfer-in are refunded
  • BusinessFullData

    Packaged struct for all related data

    ametyperequireddescription
    pre_businessPreBusiness
    businessBusiness
    event_transfer_outEventTransferOut
    event_transfer_inEventTransferIn
    event_transfer_out_confirmEventTransferOutConfirm
    event_transfer_in_confirmEventTransferInConfirm
    event_transfer_out_refundEventTransferOutRefund
    event_transfer_in_refundEventTransferInRefund

Lpnode Event Command

  • structure

    parameter nametypedescription
    cmdStringThe type of this command
    cidStringThe ID of this command
    others
  • type

    namedescription
    CMD_UPDATE_QUOTESent from AMM to lpnode - notify lpnode to send bridge keepalive message to relay
    EVENT_QUOTE_REMOVERSent from lpnode to AMM - bridge has been removed from the available list as no keepalive messages are received for long time
    CMD_ASK_QUOTESent from lpnode to AMM - ask for quotation
    EVENT_ASK_REPLYSent from AMM to lpnode - send real-time quotation
    EVENT_LOCK_QUOTESent from lpnode to AMM - new exchange request received
    CALLBACK_LOCK_QUOTESent from AMM to lpnode - tell whether AMM agrees on this transaction
    EVENT_TRANSFER_OUTSent from lpnode to AMM - the transaction initiator has locked tokens in the contract
    CMD_TRANSFER_INSent from AMM to lpnode - notify lpnode to perform TransferIn
    EVENT_TRANSFER_OUT_CONFIRMSent from lpnode to AMM - the transaction initiator has released tokens in the contract
    CMD_TRANSFER_IN_CONFIRMSent from AMM to lpnode - notify lpnode to perfor ConfirmTransferIn
    EVENT_TRANSFER_OUT_REFUNDSent from lpnode to AMM - the transaction initiator has performed refund in the contract
    CMD_TRANSFER_IN_REFUNDSent from AMM to lpnode - notify lpnode to perform RefundTransferIn
    EVENT_TRANSFER_INSent from lpnode to AMM - lpnode has locked tokens in the contract
    EVENT_TRANSFER_IN_CONFIRMSent from lpnode to AMM - lpnode has released tokens in the contract
    EVENT_TRANSFER_IN_REFUNDSent from lpnode to AMM - lpnode has performed refund in the contract

Message

Quotation process

  • Trading pair survives

    Flow Direction

    null

    Data

    flowdata
    amm -> lpnodeLpnodeEventCommand<QuoteBase>
    lpnode -> relayQuoteBase
  • Ask

    Flow Direction

    null

    Data

    flowdata
    front end -> relayAsk
    relay -> lpnodeAsk
    lpnode -> ammLpnodeEventCommand<Ask>
  • Ask Reply

    Flow Direction

    null

    Data

    flowdata
    amm -> lpnodeLpnodeEventCommand<QuoteBase>
    lpnode -> relayQuoteBase
    relay -> front endQuote

Exchange process

  • Confirm Quotation

    Flow Direction

    null

    Data

    flowdata
    Confirm Quotation - FE -> relaySwapAssetInformation
    Confirm Quotation - relay -> lpnodePreBusiness
    Confirm Quotation - lpnode -> ammLpnodeEventCommand<PreBusiness>
    agree/not - amm -> lpnodeLpnodeEventCommand<PreBusiness>
    agree/not - lpnode -> relayPreBusiness
    agree/not - relay -> FEPreBusiness
  • TransferOut

    Flow Direction

    null

    Data

    flowdata
    TransferOutTransferOut
    EventTransferOutEventTransferOut
    BusinessUpdate - relay -> FEBusiness
    BusinessUpdate - relay -> lpnodeBusinessFullData
    BusinessUpdate - lpnode -> ammLpnodeEventCommand<BusinessFullData>
  • TransferIn

    Flow Direction

    null

    Data

    flowdata
    DoTransferInLpnodeEventCommand<BusinessFullData>
    TransferInTransferIn
    EventTransferInEventTransferIn
    TransferInFinishedBusinessFullData
    BusinessUpdateBusiness
  • ConfirmTransferOut

    Flow Direction

    null

    Data

    flowdata
    ConfirmTransferOutConfirmTransferOut
    EventConfirmTransferOutEventConfirmTransferOut
    BusinessUpdate - relay -> FEBusiness
    BusinessUpdate - relay -> lpnodeBusinessFullData
    BusinessUpdate - lpnode -> ammLpnodeEventCommand<BusinessFullData>
  • ConfirmTransferIn

    Flow Direction

    null

    Data

    flowdata
    DoTransferInLpnodeEventCommand<BusinessFullData>
    TransferInConfirmTransferIn
    EventTransferInEventConfirmTransferIn
    ConfirmTransferInFinishedBusinessFullData
    BusinessUpdateBusiness

KYC

Use the TermiPass browser plugin to sign "Otmoic KYC Verifiable Credential Request Schema" and submit it to the relay. After manual review by managers of the relay, the system will issue "Otmoic KYC Verifiable Credential Schema" and synchronize the issued VC to TermiPass in the frontend, then submit "Otmoic KYC Presentation Definition" to the relay to finish KYC.

Main Information in KYC

namedescription
addressReal address
address_on_chainWallet address separated by ","
birthdayBirthday, will be matched with the limiter
countryCountry, will be matched with the limiter
emailE-mail address
first_nameFirst name
last_nameLast name
genderGender
id_numberIdentity document number
id_typeIdentity document type
phonePhone number
id_end_imagePhoto of the back of the identity document
id_front_imagePhoto of the front of the identity document
image1Other identity verification documents (eg. bills with the address)
image2Other identity verification documents (eg. bills with the address)