CoW Protocol

The following guide explains how to use Liquorice quotes to settle trades on CoW swap

1. Providing GPv2Settlement address in the RFQ

From the perspective of Liquorice, trade is performed with the CoW’s GPv2Settlement contract, not directly with the trader.

Therefore, a solver must first and foremost provide the address of the CoW's GPv2Settlement smart contract in both trader and effectiveTrader fields of the RFQ message.

2. Calling GPv2Settlement.settle function

CoW settlement signature

function settle(
        IERC20[] calldata tokens,
        uint256[] calldata clearingPrices,
        GPv2Trade.Data[] calldata trades,
        GPv2Interaction.Data[][3] calldata interactions
    ) external

During the settlement process, funds from the trader are transferred to the GPv2Settlement contract.

2.1 Trades argument

To assemble trades[] argument solver would need to use data from signed CoW’s trader order and configure flags argument according to the trader's signed GPv2Order

However, when creating a GPv2Order to pass it for trader's signature, certain flags should comply with the following:

bytes32 kind = GPv2Order.KIND_SELL;
bytes32 buyTokenBalance GPv2Order.BALANCE_ERC20;

If the selected kind is GPv2Order.KIND_SELL

Otherwise, if kind is GPv2Order.KIND_BUY, then

bytes32 kind = GPv2Order.KIND_BUY;
bytes32 sellTokenBalance GPv2Order.BALANCE_ERC20;

2.2 Interactions

CoW’s GPv2Settlement.settle function receives interactions in the following format:

GPv2Interaction.Data[][3] calldata interactions

This format reflects that inside CoW’s settlement there are 3 groups of interactions

To interact with LiquoriceSettlement solver should use the second group (index [][1] of array)

Here is what should be contained inside this array:

Approval

When performing the trade, Liquorice Balance Manager contract must have a baseToken approval given by the GPv2Settlement contract.

Interaction with LiquoriceSettlement

To make interaction with LiquoriceSettlement solver would need to use the following field from API:

  • baseToken

  • baseTokenAmount

  • tx

Solidity example

address public constant LIQUORICE_BALANCE_MANAGER = <liquorice-balance-manager>;

struct Transaction {
  address to;
  bytes data;
}

// RFQ Quote payload sample returned from the Liquorice API
struct LiquoriceRFQQuoteLevel {
  address baseToken;
  uint256 baseTokenAmount;
  Transaction tx;
}

function getCoWInteractions(LiquoriceRFQQuoteLevel calldata quoteLevel) public returns (GPv2Interaction.Data[][3] memory) {
  GPv2Interaction.Data[] memory preInteractions = new GPv2Interaction.Data[](0);
  GPv2Interaction.Data[] memory interactions = new GPv2Interaction.Data[](2);
  GPv2Interaction.Data[] memory postInteractions = new GPv2Interaction.Data[](0);

  // GPv2Settlement gives approve to Liquorice Balance Manager
  bytes memory approveCalldata =
    abi.encodeWithSelector(IERC20.approve.selector, LIQUORICE_BALANCE_MANAGER, quoteLevel.baseTokenAmount);

  interactions[0] = GPv2Interaction.Data(quoteLevel.baseToken, 0, approveCalldata);
  // And executes LiquoriceSettlement calldata
  interactions[1] = GPv2Interaction.Data(quoteLevelote.tx.to, 0, quoteLevel.tx.data);

  return [preInteractions, interactions, postInteractions];
}

2.3 Remaining arguments

Remaining arguments such as signature and order provided as is.

Last updated