Order Interface
The Order interface represents a Gnosis Protocol v2 order. All orders must conform to this structure for signing and settlement.
export interface Order {
sellToken : string ;
buyToken : string ;
receiver ?: string ;
sellAmount : BigNumberish ;
buyAmount : BigNumberish ;
validTo : Timestamp ;
appData : HashLike ;
feeAmount : BigNumberish ;
kind : OrderKind ;
partiallyFillable : boolean ;
sellTokenBalance ?: OrderBalance ;
buyTokenBalance ?: OrderBalance ;
}
Order Fields
The ERC20 token address to sell. Must be a valid Ethereum address.
The ERC20 token address to buy. Use BUY_ETH_ADDRESS constant to buy native ETH.
Optional address to receive the buy tokens instead of the order owner. Defaults to address(0) which means the owner receives the tokens.
The amount of sell tokens.
Sell orders : Exact amount to sell
Buy orders : Maximum amount to sell
Partial fill : Component of the limit price fraction
The amount of buy tokens.
Sell orders : Minimum amount to buy
Buy orders : Exact amount to buy
Partial fill : Component of the limit price fraction
Unix timestamp (or Date object) when the order expires. Orders cannot be executed after this time.
Application-specific data as a 32-byte hash or number. Can be used for:
Adding metadata to orders
Ensuring uniqueness between otherwise identical orders
Storing protocol-specific information
Fee amount in sell tokens to pay to the protocol.
The order type: OrderKind.SELL or OrderKind.BUY.
Whether the order can be partially filled across multiple settlements.
How sell tokens are withdrawn. Defaults to OrderBalance.ERC20.
How buy tokens are received. Defaults to OrderBalance.ERC20.
Enums
OrderKind
Defines whether an order is a sell or buy order:
export enum OrderKind {
SELL = "sell" , // Sell exact sellAmount
BUY = "buy" , // Buy exact buyAmount
}
A sell order specifies an exact sellAmount to trade and a minimum buyAmount to receive. const sellOrder : Order = {
sellToken: WETH_ADDRESS ,
buyToken: USDC_ADDRESS ,
sellAmount: ethers . utils . parseEther ( "1" ), // Sell exactly 1 WETH
buyAmount: ethers . utils . parseUnits ( "3000" , 6 ), // Get at least 3000 USDC
kind: OrderKind . SELL ,
// ... other fields
};
A buy order specifies an exact buyAmount to receive and a maximum sellAmount to spend. const buyOrder : Order = {
sellToken: WETH_ADDRESS ,
buyToken: USDC_ADDRESS ,
sellAmount: ethers . utils . parseEther ( "1.1" ), // Spend at most 1.1 WETH
buyAmount: ethers . utils . parseUnits ( "3000" , 6 ), // Buy exactly 3000 USDC
kind: OrderKind . BUY ,
// ... other fields
};
OrderBalance
Specifies how token balances are managed:
export enum OrderBalance {
ERC20 = "erc20" , // Standard ERC20 transfers
EXTERNAL = "external" , // Balancer Vault external balances (sell only)
INTERNAL = "internal" , // Balancer Vault internal balances
}
Use standard ERC20 token balances with transferFrom. Requires ERC20 allowance to the Vault relayer.
Use Balancer Vault external balances. Only valid for sellTokenBalance. Allows reusing Vault ERC20 allowances.
Use Balancer Vault internal balances for trading without token transfers.
Helper Functions
normalizeOrder
Normalizes an order for EIP-712 signing:
export function normalizeOrder ( order : Order ) : NormalizedOrder
import { normalizeOrder } from "@cowprotocol/contracts" ;
const order : Order = {
sellToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" ,
buyToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" ,
sellAmount: ethers . utils . parseEther ( "1" ),
buyAmount: ethers . utils . parseUnits ( "3000" , 6 ),
validTo: new Date ( Date . now () + 3600000 ), // Date object
appData: 42 , // Number
feeAmount: 0 ,
kind: OrderKind . SELL ,
partiallyFillable: false ,
};
const normalized = normalizeOrder ( order );
// normalized.validTo is now a Unix timestamp number
// normalized.appData is now a 32-byte hex string
// normalized.receiver is now address(0)
// normalized.sellTokenBalance is now "erc20"
// normalized.buyTokenBalance is now "erc20"
hashOrder
Computes the EIP-712 hash for an order:
export function hashOrder (
domain : TypedDataDomain ,
order : Order
) : string
import { hashOrder , domain } from "@cowprotocol/contracts" ;
const gpv2Domain = domain ( 1 , settlementContract );
const orderHash = hashOrder ( gpv2Domain , order );
console . log ( "Order hash:" , orderHash );
// Output: "0x1234...abcd"
computeOrderUid
Computes the unique identifier for an order:
export function computeOrderUid (
domain : TypedDataDomain ,
order : Order ,
owner : string
) : string
The order UID is a 56-byte identifier composed of:
Order digest (32 bytes)
Owner address (20 bytes)
Valid-to timestamp (4 bytes)
import { computeOrderUid , domain } from "@cowprotocol/contracts" ;
const gpv2Domain = domain ( 1 , settlementContract );
const ownerAddress = await wallet . getAddress ();
const orderUid = computeOrderUid ( gpv2Domain , order , ownerAddress );
console . log ( "Order UID:" , orderUid );
// Output: "0x1234...abcd" (56 bytes / 112 hex chars)
Extracts components from an order UID:
export function extractOrderUidParams ( orderUid : string ) : OrderUidParams
export interface OrderUidParams {
orderDigest : string ;
owner : string ;
validTo : number ;
}
import { extractOrderUidParams } from "@cowprotocol/contracts" ;
const params = extractOrderUidParams ( orderUid );
console . log ( "Order digest:" , params . orderDigest );
console . log ( "Owner:" , params . owner );
console . log ( "Valid until:" , new Date ( params . validTo * 1000 ));
Constants
BUY_ETH_ADDRESS
Special address to indicate buying native ETH:
export const BUY_ETH_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" ;
This address only has special meaning in the buyToken field. Using it as sellToken will cause the settlement to revert.
const ethBuyOrder : Order = {
sellToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" , // USDC
buyToken: BUY_ETH_ADDRESS , // Buy ETH
sellAmount: ethers . utils . parseUnits ( "3000" , 6 ),
buyAmount: ethers . utils . parseEther ( "1" ),
// ... other fields
};
ORDER_UID_LENGTH
The byte length of an order UID (56 bytes):
export const ORDER_UID_LENGTH = 56 ;
Complete Example
import {
domain ,
Order ,
OrderKind ,
OrderBalance ,
computeOrderUid ,
hashOrder ,
} from "@cowprotocol/contracts" ;
import { ethers } from "ethers" ;
// Setup
const provider = new ethers . providers . JsonRpcProvider ( RPC_URL );
const wallet = new ethers . Wallet ( PRIVATE_KEY , provider );
const settlementContract = "0x9008D19f58AAbD9eD0D60971565AA8510560ab41" ;
const gpv2Domain = domain ( 1 , settlementContract );
// Create order
const order : Order = {
sellToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" , // WETH
buyToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" , // USDC
receiver: ethers . constants . AddressZero ,
sellAmount: ethers . utils . parseEther ( "1" ),
buyAmount: ethers . utils . parseUnits ( "3000" , 6 ),
validTo: Math . floor ( Date . now () / 1000 ) + 3600 ,
appData: ethers . constants . HashZero ,
feeAmount: ethers . utils . parseEther ( "0.001" ),
kind: OrderKind . SELL ,
partiallyFillable: false ,
sellTokenBalance: OrderBalance . ERC20 ,
buyTokenBalance: OrderBalance . ERC20 ,
};
// Compute order hash and UID
const orderHash = hashOrder ( gpv2Domain , order );
const orderUid = computeOrderUid ( gpv2Domain , order , await wallet . getAddress ());
console . log ( "Order hash:" , orderHash );
console . log ( "Order UID:" , orderUid );
Next Steps
Sign Orders Learn how to sign orders with different schemes
Settlement Encode orders into settlements for execution