Features

Offer

An offer is the core component of the OTC Market. Each offer is composed of a unique identifier (ID) and a set of parameters.

Sell vs. Buy Offers

Every offer can be interpreted either as a sell or a buy offer. For example, selling 100 SOL for 1 ETH is equivalent to buying 1 ETH for 100 SOL. However, when it comes to technical details, we strictly adhere to sell offers.

Parameters

The main parameters of the offer are:

Advertiser Parties

  • Source Seller Address: The address of the account on the source chain used by the advertiser to create the offer. It is required for authorization, ensuring only the seller can cancel the offer.
  • Destination Seller Address: The address where buyers send the destination amount upon accepting the offer.

Path

  • Source Endpoint ID: The LayerZero endpoint ID for the source chain, indicating where the offer is created.
  • Destination Endpoint ID: The LayerZero endpoint ID for the destination chain, indicating where the offer is accepted.

Token Pair

  • Source Token address: The token being sold by the advertiser.
  • Destination Token address: The token received by the advertiser.

Pricing

  • Source Amount: The total amount of the source token to sell. Locked in the Escrow when the offer is created.
  • Exchange Rate: The number of destination tokens paid by the buyer for each source token [dst/src].

Types

Offer structure

struct Offer {
  bytes32 srcSellerAddress;
  bytes32 dstSellerAddress;
  uint32 srcEid;
  uint32 dstEid;
  bytes32 srcTokenAddress;
  bytes32 dstTokenAddress;
  uint64 srcAmountSD;
  uint64 exchangeRateSD;
}

Addresses use bytes32 for handling non-EVM chains. Source amount and exchange rate are represented in uint64 and expressed in shared decimals.

ID

Offers are identified globally by their unique identifier. Once an advertiser creates an offer, they cannot recreate it with the same parameters.

The offer ID is derived hashing source seller address, path, token pair, and exchange rate.

Hash offer

function hashOffer(
  bytes32 _srcSellerAddress,
  uint32 _srcEid,
  uint32 _dstEid,
  bytes32 _srcTokenAddress,
  bytes32 _dstTokenAddress,
  uint64 _exchangeRateSD
) public pure virtual override returns (bytes32 offerId) {
  offerId = keccak256(
      abi.encodePacked(_srcSellerAddress, _srcEid, _dstEid, _srcTokenAddress, _dstTokenAddress, _exchangeRateSD)
  );
}

Lifecycle

The very first step is for the advertiser to create a new offer with the desired parameters.

The created offer keeps track of its own parameters which helps us understand its type and how to handle it.

We will see how to create offers in more details in the following page.

After the offer is created, buyers can see and accept it in whole or in part.

Buyers accept the offer by interacting with the smart contract on the offer's destination chain.

Example:

  • Offer: Selling 10 ETH (Base) for 10 SOL (Solana).

    • Advertiser:

      • Holds ETH on the Base chain.
      • Interacts with the OTC Market smart contract on the Base chain to create the offer.
    • Buyer:

      • Holds SOL on the Solana chain.
      • Interacts with the OTC Market smart contract on the Solana chain to accept the offer.

Once the entire amount in the offer has been purchased by buyers, the advertiser can cancel the offer, allowing them to create a new offer with the same parameters. This will also free some storage on the blockchain and return the rent to the advertiser (on Solana).

In the next steps, advertisers will also have the option to refill the offer instead of canceling it entirely.

Overall, the lifecycle of an offer follows this path:

Offer lifecycle (Created, Accepted, Refilled, Canceled)
Offer lifecycle

We will discuss each of these actions in detail in the features section.

Types

Bakstag is an Omnichain OTC Market, supporting both crosschain and monochain offers.

Crosschain

In crosschain trades, users can exchange assets between different blockchains possible with LayerZero messaging. For example, you can sell ETH on Base and receive SOL on Solana in return. This allows users to trade assets across chains without slippage, bridging, or wrapping.

Monochain

In monochain offers both assets are on the same blockchain. In this case source endpoint ID equals destination endpoint ID. For example, you can sell ETH on Base for USDC on Base.

Token support

We support both native tokens and standard fungible tokens:

  • Native Tokens: ETH, SOL, TRX, etc.
  • Fungible Tokens: ERC20, SPL, TRC20, etc.

In case of native token, token address is set to null bytes.

Previous
Getting Started