Victor Jonah I am a Software Developer with over three years of experience working with JavaScript and its frameworks. I currently work as a remote software developer for a tech agency.

How to market make and transact with Hashflow

6 min read 1922

How To Market Make Transact Hashflow

There has been a rise in the amount of DeFi traders in recent years which has resulted in more decentralized exchanges (DEXs) being brought to the market as well.

Web3 is increasing its impact on major industries, and the trading industry is not exception. We had seen the deficiencies in centralized exchanges like a lack of transparency, insecurity, financial exclusiveness, and privacy, and this has provided the need for DEXs.

DEX is a way of exchanging cryptocurrencies without any intermediary like brokers or third parties. They follow a different approach from centralized exchanges by relying on smart contracts to handle transactions peer-to-peer.

The business model focuses on privacy for its users where transactions are carried out anonymously, even though the transaction details are stored on the blockchain.

We have a lot of DEX platforms on the market, like Coinbase and Binance, but in this article, we will focus on Hashflow.

We will look at how traders are connected with pinpoints via a Hashflow token, how it works differently from others, how to market make, and how to trade.

What is Hashflow and what is its goal?

First of all, Hashflow is known for its bridge-less cross-chain swaps, which means it is highly interoperable, has zero slippage, and no MEV.

This is possible because Hashflow ensures market makers sign the price quotes so it remains unchanged during the trade.

Liquidity providers and traders are connected with professional market makers on Hashflow and its core features offer better flexibility for its market makers — no slippage, MEV resistant, better price quotes, and a cheaper trading fee are all advantages of it.

All the above mentioned are only possible because of the architecture Hashflow uses, which is the Pool-based architecture.



How Hashflow works

Starting with a transaction, the user has to connect his wallet to Hashflow, input a number they would like to trade, and then a quote is displayed to them.

If the user accepts, the order is submitted and that transaction is verified and added to the Hashflow network (or blockchain). On the other end, there are maker markets that deal with the issuing of price quotes which the user had already accepted.

The market maker then signs the trade and it is executed without slippage (whatever order was submitted by the user stands). Unlike other DEXs, which do usually have AMMs (Automated Market Maker) that handles market making and assets pricing on-chain using Lazy Liquidity Provision, Hashflow goes traditionally just like the order-book mechanism.

The pricing is done off-chain but the trade is executed on-chain.

Hashflow was in 2021 and has grown significantly, offering the best prices because of its optimized gas fee and zero slippage. As of the time of this article being published, Hashflow currently supports bridge-less cross-chain swaps which makes you initiate a swap on EVM compatible chains, and it is expected to include Solana integration, smart order Routing, gasless trading, limit orders, and Hashverse in future.

In summary, Hashflow is a DeFi protocol which serves as a decentralized exchange running on the Ethereum blockchain.

Hashflow tokens

Hashflow provides its token called the HFT (Hashflow token), which is an ERC-20 on the Ethereum chain deployed on December 22, 2021. With one billion units of HFT in supply, Hashflow distributed this cryptocurrency in this manner: 19% to the core team; 25% to the early investors; and 56% to the ecosystem. A further 6.75% will be given to early users as a reward.


More great articles from LogRocket:


Hashflow Allocation

The Hashflow NFT, which is also called the Hashbots, will be used in the Hashverse that will be released in future. NFT holders will receive HFT that tallies to the value of the NFT, because each NFT will have an HFT value. And Hashflow states that after four years, 5% of HFT will be issued to the community.

How to market make

Market markers are essentially important in Hashflow and in the market as a whole. They are the liquidity providers that make the market functional by buying and selling assets. This doesn’t mean that they can buy and sell at anytime right away, but they are always on standby, ready to buy and sell.

In most decentralized exchanges, the market makers are automatic and smart contracts are deployed to find market pairs in AMMs (Automatic Market Makers) but they are prone to attacks and also a bit laggy because the price quotes are handled on-chain.

In Hashflow, the market makers are firms, institutions, or individuals that are given the privilege to make these market decisions using their professionalism, and this is done off-chain, which in turn reduces gas fees and slippage, as mentioned earlier.

To market make on Hashflow, we will follow the steps below. Integrating with Hashflow as a market maker is quite simple.

Connect to WebSocket

You will need to connect to the WebSocket from Hashflow API just as you see on line 10 below. And you might need to contact the team on Telegram or Discord to be added to the allowlisted makers.

const PING_PONG_INTERVAL_MS = 30000;
const PING_PONG_GRACE_PERIOD_MS = 1000;

function getWebsocketConnection(
  marketMakerName,
  onMessageCallBack,
  onCloseCallback,
  onHeartbeatCallback,
) {
  const ws = new WebSocket(`${process.env.HASHFLOW_WS_API}/maker/v1`, {
    headers: { marketmaker: marketMakerName, }
  });
  const heartbeat = () => {
    if (ws.pingTimeout) {
      clearTimeout(ws.pingTimeout);
    }
    ws.pingTimeout = setTimeout(() => {
      ws.terminate();
    }, PING_PONG_INTERVAL_MS + PING_PONG_GRACE_PERIOD_MS);

    onHeartbeatCallback();
  }
  ws.on('open', heartbeat);
  ws.on('ping', heartbeat);
  ws.on('message', message => onMessageCallBack(message));

  ws.on('close', () => {
    if (ws.pingTimeout) {
      clearTimeout(ws.pingTimeout);
    }
    setTimeout(() => {
      ws.removeAllListeners();
      onCloseCallback();
    }, 5000);
  });

  ws.on('error', err => {});

  ws.on('unexpected-response', (_, res) => {
    let message = '';
    res.on('data', (chunk) => {
      message += chunk;
    });
    res.on('end', () => {
      if (res.statusCode === 401) {
        logger.error(`WS access not authorized. ${message}`);
      } else {
        logger.error(`Unexpexted response from server: [${res.statusCode}] ${message}.`);
      }
      ws.close()
    });
  });
  return ws;
}

And Hashflow is connected to you, as seen in the following:

// TODO: Replace this with your market maker name (once added to the backend)
const MARKET_MAKER_NAME = 'TestMM';
// TODO: Set true if you want to MM on 1inch, etc – and have signed legal agreements
const SUPPORT_AGGREGATORS = false;
const levelsInterval = SUPPORT_AGGREGATORS 
  ? setInterval(() => publishPriceLevels(mainSocket), 1000)
  : undefined;
const onMessageCallback = message => processMessage(mainSocket, message);
const onHeartbeatCallback = () => {
  for (const networkId of Object.keys(SUPPORTED_PAIRS)) {
    sendMessage(mainSocket, 'subscribeToTrades', { networkId, pool: POOL });
  }
};
const onCloseCallback = () => {
  if (SUPPORT_AGGREGATORS) {
    clearInterval(levelsInterval);
  }
  mainSocket = connectToHashflow();
};

const connectToHashflow = () => {
  return getWebsocketConnection(
    MARKET_MAKER_NAME,
    onMessageCallback,
    onCloseCallback,
    onHeartbeatCallback,
  );
}
let mainSocket = connectToHashflow();

The ‘TestMM’ is replaced with yours after contacting the team. You should also refer to this sample codebase to see how to connect to the WebSocket from Hashflow.

Create a Pool

You will need to connect to your wallet after connecting to the WebServer to create a Pool that will offer quotes.

To do this, head over using this link and fill in your Pool name, signer address, and finally identify if you want your Pool to be public or private. After completing the process, you should get a page like this:

MIB Pool

Receive RFQ and respond with quote

Now to the interesting part; Hashflow receives a request-for-quote from a user when they want to trade to our server which then supplies the data to the specified market maker:

{
  "messageType": "rfq",
  "message": {
    // This is a unique RFQ ID -- you need to use this when sending back a quote.
    "rfqId": string,

    // This will be something like: hashflow, 1inch. This is useful
    // since 1inch charge fees for their trades
    "source": string,

    // 1 for ETH L1
    "networkId": number,

    // Base token (the token the trader sells).
    "baseToken": string,  // contract address
    "baseTokenName": string,  // token name (e.g. USDC, ETH, ...)
    "baseTokenNumDecimals": number,  // token decimals (e.g. DAI: 18, USDC: 6)

    // Quote token (the token the trader buys).
    "quoteToken": string,  // contract address
    "quoteTokenName": string,  // token name (e.g. USDC, ETH, ...)
    "quoteTokenNumDecimals": number,  // token decimals (e.g. DAI: 18, USDC: 6)


    // Exactly one of the following fields will be present in the RFQ.
    // If baseTokenAmount is present, quoteTokenAmount needs to be filled by the quote.
    // If quoteTokenAmount is present, baseTokenAmount needs to be filled by the quore.
    // Amounts are in decimals, e.g. "1000000" for 1 USDT.
    "baseTokenAmount": ?string,
    "quoteTokenAmount": ?string,

    // The trader wallet address that will swap with the contract. This can be a proxy
    // contract (e.g. 1inch)
    "trader": string,

    // The wallet address of the actual trader (e.g. end user wallet for 1inch).
    // This is helpful in order to understand user behavior.
    // If effectiveTrader is not present, you can assume that trader == effectiveTrader.
    "effectiveTrader": ?string,
  }
}

And based on your implemented logic in your codebase, a quote is returned to the user in this format as well:

{
  "messageType": "quote",
  "message": {
    "rfqId": string,  // This should be the same rfqId that was sent by the server
    "pool": string,  // This should be the contract address of the pool.

    // This is optional. If using an EOA (externally owned account), this should 
    // contain the wallet address of the EOA. 
    // The EOA needs to have allowance set to the Pool.
    "eoa": ?string,

    // Same as RFQ
    "baseToken": string,
    "quoteToken": string,

    // Amounts are in decimals.
    "baseTokenAmount": string,
    "quoteTokenAmount": string,

    // Set this to "0" for private pool / EOA trading.
    "fees": string,

    // The unix timestamp when the quote expires, in seconds.
    "quoteExpiry": number,
  }
}

Support signing quotes

This only happens if the user doesn’t supply a specific market maker, and in that context Hashflow will make a request for a quote from all market makers and picks the best one.

When the best quote is picked, we send a signQuote message type back to the market maker for them to sign (get a signature from them). The request is also in this format:

  "messageType": "signQuote",
  "message": {
    // The RFQ ID that generated the quote.
    "rfqId": string,
    "networkId": number,  // The chain ID (e.g. 1 for Ethereum mainnet)
    "quoteData": {
      "txid": string,  // Unique identifier of the quote -- different from the RFQ ID.

      "pool": string,
      "eoa": string,

      "baseToken": string,
      "quoteToken": string,

      "baseTokenAmount": string,
      "quoteTokenAmount": string,

      "fees": string,

      "quoteExpiry": number,

      // The account that will be executing the swap. For 1inch, this is the 1inch proxy.
      "trader": string,
      // Trader actually executing the swap, if different from 'trader'.
      "effectiveTrader": ?string,

      // The following parameter is internal to hashflow contracts.
      // It is leveraged to mitigate quote replay.
      "nonce": number
    }
  }
}

Get the first signed RFQ

You can test your WebServer to see if you get a signed RFQ from it by making a request to Hashflow’s staging API with the following body params as a sample:

POST https://api-staging.hashflow.com/taker/v1/quote/signedRfq


{
    "networkId": 42,  // 42 is Kovan, 1 is Mainnet
    "source": "hashflow", 
    "baseToken": "0x07de306ff27a2b630b1141956844eb1552b956b5",  // USDT (Kovan)
    "quoteToken": "0xa0a5ad2296b38bd3e3eb59aaeaf1589e8d9a29a9",  // WBTC (Kovan)
    "trader": "0x2150DD462B496bd5e4A37b5411c13319427BE83E",
    "baseTokenAmount": "1000000",
    "marketMaker": "TestMM"  // don't forget to change this
}

Once you get a response, then your market maker is set. You should also refer to the documentation for more edge cases.

Conclusion

In this article, we focused on demystifying the connection between Hashflow, its users, and market makers and the key aspects of Hashflow — namely, that it offers bridgeless cross-chain swaps and off-chain market decisions; i.e., quotes are done without automated makers.

Hashflow is bringing the multichain world closer to us just as Vitalik of Ethereum had speculated. We are hoping to get more Hashflow support for other chains as this is currently under mass adoption. To also view its metric, head over to this dashboard.

Join organizations like Bitso and Coinsquare who use LogRocket to proactively monitor their Web3 apps

Client-side issues that impact users’ ability to activate and transact in your apps can drastically affect your bottom line. If you’re interested in monitoring UX issues, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.https://logrocket.com/signup/

LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web and mobile apps — .

Victor Jonah I am a Software Developer with over three years of experience working with JavaScript and its frameworks. I currently work as a remote software developer for a tech agency.

Leave a Reply