Wrapper Integration
Generalized wrappers enable custom logic to execute surrounding CoW Protocol settlements. This guide covers both using existing wrappers in your orders and building new wrapper contracts.
Choose your path:
- Building New Wrappers - Develop custom wrapper contracts for advanced DeFi workflows
- Using Existing Wrappers - Add wrappers to your orders and integrate into your application
- Executing Wrappers as a Solver - Everything solvers need to know to execute wrapper orders
For Wrapper Developers
This section covers building new wrapper contracts from scratch.
Overview
To build a wrapper, you will:
- Inherit from the
CowWrapperabstract contract - Implement
_wrap()with your pre/post-settlement logic - Implement
parseWrapperData()for input validation - Test thoroughly on testnets
- Submit for allowlist approval by the CoW Protocol team
Read up on the details of creating a wrapper from the wrapper contract information page.
For Order Creators and Frontend Developers
This section shows you how to use existing wrappers in your orders and integrate wrapper support into your application.
Adding Wrappers to Orders
To use a wrapper in your order, add it to the appData when creating the order:
AppData Structure
interface WrapperCall {
target: string; // Wrapper contract address (must be allowlisted)
data?: string; // Optional hex-encoded wrapper-specific data
is_omittable?: boolean; // Whether solver can skip this wrapper (default: false)
}
Fields:
target(required): Address of the allowlisted wrapper contractdata(optional): Hex-encoded data specific to the wrapper. Can be empty or omitted if the wrapper doesn't need custom data.is_omittable(optional): Defaults tofalsefalse= Solver MUST execute the wrapper with exact data or be slashedtrue= Solver MAY skip the wrapper if they find a better solution
Example: Using the CoW SDK
import { OrderBookApi, OrderQuoteRequest, OrderCreation } from '@cowprotocol/cow-sdk'
// Create order with wrapper
const orderCreation: OrderCreation = {
// ... standard order fields (sellToken, buyToken, amounts, etc.)
appData: {
// ... other appData fields
wrappers: [
{
target: "0x1234...", // Flash loan wrapper address
data: "0xabcd...", // Encoded flash loan params
is_omittable: false // Must execute
}
]
}
}
// Submit order
const orderId = await orderBookApi.sendOrder(orderCreation)
Example: Multiple Wrappers (Nested)
You can chain multiple wrappers in a single order:
appData: {
wrappers: [
{
target: "0x1111...", // Flash loan wrapper
data: "0xaaaa...",
is_omittable: false
},
{
target: "0x2222...", // Leverage wrapper
data: "0xbbbb...",
is_omittable: false
}
]
}
The wrappers execute in sequence: Wrapper1 → Wrapper2 → Settlement → Wrapper2 (post) → Wrapper1 (post). Note that wrappers from other user's orders may be interspersed, though this should generally not affect the execution of the order.
Validating Wrapper Configuration
Before submitting an order, you can confirm the wrapper encoding is valid using CowWrapperHelper:
// On-chain validation (via Ethers/Viem)
const helper = new ethers.Contract(HELPER_ADDRESS, HELPER_ABI, provider)
const isValid = await helper.verifyAndBuildWrapperData(
["0x1234...", "0x5678..."], // Wrapper addresses
["0xabcd...", "0xef01..."] // Wrapper data
)
// Returns encoded wrapperData if valid, reverts if invalid
This checks:
- All wrappers are allowlisted
- All wrappers use the same settlement contract
- Each wrapper can parse its data successfully
For Solvers
This section explains how to execute settlements that include wrapper contracts as part of your solver implementation.
Detecting Wrapper Orders
Wrappers are specified in the order's appData under the wrappers field:
{
"wrappers": [
{
"target": "0x1234...",
"data": "0xabcdef...",
"is_omittable": false
}
]
}
Fields:
target: Address of the wrapper contract (treat as opaque - don't parse)data: Wrapper-specific data (treat as opaque - don't parse)is_omittable: Critical flag for solver requirements (see below)
Wrapper addresses and data should be treated as opaque values. Do not attempt to parse or validate them - simply pass them through in your encoding.
Solver Requirements
1. Execute Non-Omittable Wrappers
Orders with "is_omittable": false MUST be executed with the specified wrapper. You may be slashed for not doing so.
If "is_omittable": true, you MAY skip the wrapper if you find a better solution without it.
2. Verify Wrapper Authentication
All approved wrappers will be approved by the DAO and registered in GPv2AllowlistAuthenticator. It is recommended to verify wrappers are allowlisted before including them in settlements.
3. Include Wrappers in Solution
Whether using the CoW-provided driver or your own, ensure wrapper information flows from the auction to your final settlement transaction.
Encoding Wrapper Settlements
If you're using the driver provided by the CoW team, you can skip this section - the driver handles encoding automatically.
Manual Encoding
To execute a settlement with wrappers:
1. Change Transaction Target
Your transaction should call wrappedSettle() on the first wrapper (not the settlement contract):
// Without wrapper
tx = {
to: SETTLEMENT_CONTRACT,
data: encodeSettle(...)
}
// With wrapper
tx = {
to: wrappers[0].target, // First wrapper address
data: encodeWrappedSettle(...) // See below
}
2. Construct settleData Parameter
The settleData parameter is the exact calldata you would send to GPv2Settlement.settle(), including the 4-byte function selector:
const settleData = settlementContract.interface.encodeFunctionData("settle", [
tokens,
clearingPrices,
trades,
interactions
]);
// This is your settleData - unchanged from normal settlement
3. Encode wrapperData Parameter
The wrapperData combines individual wrapper data with wrapper addresses:
function encodeWrapperData(wrappers: WrapperCall[]): string {
let wrapperData = '0x';
for (const [index, wrapper] of wrappers.entries()) {
// Skip first wrapper's address (it's the transaction target)
if (index !== 0) {
// Add wrapper address (20 bytes, without 0x prefix)
wrapperData += wrapper.target.slice(2);
}
// Encode data length as u16 big-endian (2 bytes)
const dataLength = (wrapper.data.length - 2) / 2; // Remove '0x' and convert to byte length
const lengthHex = dataLength.toString(16).padStart(4, '0');
wrapperData += lengthHex;
// Add wrapper data (without 0x prefix)
wrapperData += wrapper.data.slice(2);
}
return wrapperData;
}
Encoding Structure:
For 2 wrappers:
[length₁(2B)][data₁][address₂(20B)][length₂(2B)][data₂]
For 3 wrappers:
[length₁(2B)][data₁][address₂(20B)][length₂(2B)][data₂][address₃(20B)][length₃(2B)][data₃]
4. Call wrappedSettle
const tx = {
to: wrappers[0].target,
data: wrapperContract.interface.encodeFunctionData("wrappedSettle", [
settleData, // From step 2
chainedWrapperData // From step 3
])
}
Using CowWrapperHelper
Alternatively, use the CowWrapperHelper contract for encoding and validation:
// On-chain encoding and validation
address[] memory wrapperAddresses = [wrapper1, wrapper2];
bytes[] memory wrapperDatas = [data1, data2];
bytes memory wrapperData = CowWrapperHelper(HELPER).verifyAndBuildWrapperData(
wrapperAddresses,
wrapperDatas
);
In addition to producing the correct encoded data, the helper also validates:
- All wrappers are allowlisted
- All wrappers use the same settlement contract
- Each wrapper can parse its data
Accumulating Wrappers in Solutions
Using CoW-Provided Driver
If you're using the CoW team's driver, wrappers are handled automatically. Just ensure your solver process includes wrapper information in the solution output.
Custom Implementation
If implementing your own solver:
- Collect wrappers from orders: As you process orders in an auction, collect all
wrappersarrays from order appData - Aggregate for batch: Combine wrappers needed for all orders in the settlement batch
- Include in solution: Add aggregated wrappers to your solution structure
- Encode transaction: Use the encoding algorithm above to construct the final transaction
Example (conceptual):
// Process auction
const solution = {
orders: [...],
wrappers: [] // Collect here
};
for (const order of auction.orders) {
if (order.appData.wrappers) {
// Add wrappers needed for this order
solution.wrappers.push(...order.appData.wrappers);
}
}
// Encode final transaction
const tx = encodeWrapperSettlement(solution);
Testing and Validation
Gas Estimation
Account for wrapper gas overhead in your bids. The easiest way to do this is to simpulate the wrapper transaction against an empty settlement.
Common Issues
Issue: "Not authorized" error
Cause: Wrapper is not allowlisted in GPv2AllowlistAuthenticator
Solution: Verify wrapper is DAO-approved before including in settlement
Issue: Settlement reverts in wrapper
Cause: Incorrect encoding or wrapper-specific validation failure
Solution:
- Verify
settleDatais identical to what you'd send toGPv2Settlement.settle() - Check
wrapperDataencoding follows specification exactly - Use
CowWrapperHelperfor validation
Solver Resources
Documentation
- Wrapper Concepts - High-level overview
- Contracts Reference - Contract specifications
- Services PR #3700 - Reference encoding implementation in production