Milkman contracts allow to create an order on CoW Swap, while its validity is dependent on additional smart contract logic. This allows to define the time of execution and defer the choice of the limit price, from order initiation (pre DAO vote) to order execution time (solver settling the trade). It does so by using ERC1271 signatures and considers a proposed execution price valid if it’s within a predefined range from an external oracle (e.g. Uniswap TWAP).

In the following example, we used both the uniswapV3 price checker, and the validFrom decorator. The relevant uniswap pool for this purpose is the WETH/USDC 0.05% fee pool.

A multicall was used to wrap ETH, approve it and deploy a series of “Good After Time” orders with an adaptive slippage tolerance check, at -5% below the price on the chosen pool. (execution price is still expected to be at best market prices thanks to CoW Protocol)

In order to explore the actual execution, head to the deployment transaction on etherscan, every “swapRequested” represents one leg of the TWAP order:

Untitled

Copy the address under the order contract into the CoW Explorer, where you can see the exact execution details (you might see multiple expired orders, those happen due to the indexing redundancy. what matters is the one that got executed)

As you can see, the “to” address is identical to the “orderCreator” address, which is the Gnosis Safe that was used to deploy the TWAP strategy. Under its token transfers page it is easy to see the WETH that was sent out, and the USDC proceeds from each leg of the order coming in every hour.

Untitled

Code

Here is the supporting code for generating the Safe transaction bundle JSON that can be imported with the transaction builder:

milkman.js

import { ethers } from "<https://cdn.ethers.io/lib/ethers-5.6.esm.min.js>";

export function uniV3PriceCheck({ slippage, path, fees }) {
  return {
    priceChecker: "0x2F965935f93718bB66d53a37a97080785657f0AC",
    priceCheckerData: ethers.utils.defaultAbiCoder.encode(
      ["uint256", "bytes"],
      [
        slippage,
        ethers.utils.defaultAbiCoder.encode(
          ["address[]", "uint24[]"],
          [path, fees],
        ),
      ],
    ),
  };
}

export function validFromPriceCheck(
  { validFrom, priceChecker, priceCheckerData },
) {
  return {
    priceChecker: "0x67FE9d6bbeeccb8c7Fe694BE62E08b5fCB5486D7",
    priceCheckerData: ethers.utils.defaultAbiCoder.encode(
      ["uint256", "address", "bytes"],
      [validFrom, priceChecker, priceCheckerData],
    ),
  };
}

export const MILKMAN = new ethers.Contract(
  "0x11C76AD590ABDFFCD980afEC9ad951B160F02797",
  [`
    function requestSwapExactTokensForTokens(
      uint256 amountIn,
      address fromToken,
      address toToken,
      address receiver,
      address priceChecker,
      bytes priceCheckerData
    )
  `],
);

twap.js

import { ethers } from "<https://cdn.ethers.io/lib/ethers-5.6.esm.min.js>";

import { MILKMAN, uniV3PriceCheck, validFromPriceCheck } from "./milkman.js";

// The Safe owner of the TWAP orders
const SAFE = "0x9b82D791B1451ec214B054135Fc1C812ba7c2487";
// The number of parts to split the TWAP order into
const COUNT = 8;
// The delay, in seconds, between each part
const DELAY = 3600;
// The total traded amount
const AMOUNT = ethers.utils.parseEther("2.0");

const WETH = new ethers.Contract(
  "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
  [
    `function deposit() payable`,
    `function approve(address spender, uint256 value) returns (bool)`,
  ],
);
const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";

function method(contract, ident) {
  const { inputs, name, payable } = contract.interface.getFunction(ident);
  return {
    inputs: inputs.map(({ name, type }) => ({ name, type })),
    name,
    payable,
  };
}

console.log(JSON.stringify(
  {
    version: "1.0",
    chainId: "1",
    createdAt: Date.now(),
    meta: {
      createdFromSafeAddress: SAFE,
    },
    transactions: [
      {
        to: WETH.address,
        value: AMOUNT.toString(),
        data: null,
        contractMethod: method(WETH, "deposit"),
        contractInputsValues: {},
      },
      {
        to: WETH.address,
        value: "0",
        data: null,
        contractMethod: method(WETH, "approve"),
        contractInputsValues: {
          spender: MILKMAN.address,
          value: AMOUNT.toString(),
        },
      },
      ...[...Array(COUNT)].map((_, i) => ({
        to: MILKMAN.address,
        value: "0",
        data: null,
        contractMethod: method(MILKMAN, "requestSwapExactTokensForTokens"),
        contractInputsValues: {
          amountIn: AMOUNT.div(COUNT).toString(),
          fromToken: WETH.address,
          toToken: USDC,
          receiver: SAFE,
          ...validFromPriceCheck({
            validFrom: ~~(Date.now() / 1000) + i * DELAY,
            ...uniV3PriceCheck({
              slippage: 500, // 5%
              path: [WETH.address, USDC],
              fees: [5], // the 0.05% fee pool
            }),
          }),
        },
      })),
    ],
  },
  undefined,
  "  ",
));