From 9e9d9800ea54537566ed648c42eb7b5dc5491362 Mon Sep 17 00:00:00 2001 From: Kaze Date: Fri, 13 Feb 2026 00:53:14 +0900 Subject: [PATCH 01/11] docs: add comprehensive generalized wrappers documentation Add complete documentation for CoW Protocol's generalized wrappers feature across three audience-specific files: - concepts/order-types/wrappers.md: High-level overview explaining what wrappers are, use cases (Euler leverage, flash loans, TWAP, protocol hooks), benefits, and considerations - integrate/wrappers.mdx: Practical integration guide with three sections: * For Order Creators: How to add wrappers to orders via appData * For Wrapper Developers: Building custom wrapper contracts with security requirements and implementation examples * For Solvers: Encoding wrapper settlements and handling wrapper execution - reference/contracts/periphery/wrapper.mdx: Smart contract reference focused on ICowWrapper interface, CowWrapper abstract contract, implementation patterns, and on-chain behavior Each file serves a distinct purpose and audience while cross-linking to provide comprehensive coverage of the wrapper system. Co-Authored-By: Claude Sonnet 4.5 --- .../concepts/order-types/wrappers.md | 99 ++++ docs/cow-protocol/integrate/wrappers.mdx | 346 ++++++++++++ .../reference/contracts/periphery/wrapper.mdx | 497 ++++++++++++++++++ 3 files changed, 942 insertions(+) create mode 100644 docs/cow-protocol/concepts/order-types/wrappers.md create mode 100644 docs/cow-protocol/integrate/wrappers.mdx create mode 100644 docs/cow-protocol/reference/contracts/periphery/wrapper.mdx diff --git a/docs/cow-protocol/concepts/order-types/wrappers.md b/docs/cow-protocol/concepts/order-types/wrappers.md new file mode 100644 index 000000000..3c91d0058 --- /dev/null +++ b/docs/cow-protocol/concepts/order-types/wrappers.md @@ -0,0 +1,99 @@ +--- +sidebar_position: 7 +--- + +# Generalized Wrappers + +Generalized wrappers is a new framework to allow custom logic to execute before and/or after order settlement on CoW Protocol. They enable complex DeFi workflows—like flash loans, leveraged positions, and progmatic orders--all while preserving the security and assurances granted by CoW Protocol. + +## What are Wrappers? + +Wrappers are smart contracts that "wrap" the settlement process, executing custom logic surrounding settlement contract. When a solver executes a settlement that includes a wrapper, they call the wrapper contract instead of the settlement contract directly. The wrapper calls the settlement contract on behalf of the solver. + +This mechanism extends CoW Protocol's functionality in a modular way, allowing new features and integrations to be added without modifying the core settlement contract or requiring any changes to solver implementations. + +### Wrapper Authentication + +For security, all wrappers must be approved through CoW Protocol's `GPv2AllowlistAuthenticator` before they can be used. This ensures that only audited and wrappers can interact with the settlement contract, protecting users, solver, and the protocol from malicious contracts. Unlike [hooks](./cow-hooks.mdx), Wrapper functionality can revert the execution of a transaction, ensuring sensitive user operations such as cross-chain operations can be guarenteed to be completed. + +### Wrapper Nesting + +One of the powerful features of wrappers is their ability to be nested. Multiple wrappers can be chained together in a single settlement transaction, allowing different orders in the same batch to each use their required wrapper functionality. For example, one order might need a flash loan wrapper while another needs a leverage wrapper—both can be executed in the same settlement through wrapper nesting. + +## Use Cases + +Wrappers enable a wide variety of advanced trading and DeFi operations: + +### Leverage Positions + +By wrapping the execution context of a CoW settlement, protocols implementing leveraged position opening capabilities can be supported. + +As the flagship GW implementation, Euler demonstrates a quintessential implementation of this use case. The wrapper: + +1. Coordinates with Euler's Ethereum Vault Connector (EVC) batch execution system +2. Executes the necessary EVC batch operations before settlement +3. Performs the settlement to acquire the leveraged asset +4. Completes the position setup after settlement + +This enables users to open leveraged positions on Euler through a single CoW Protocol order, with all the complexity handled by the wrapper. Leveraged positions are associated with high-volume trading, so CoW benefits from increased revenue from such integrations. + +### Flash Loan Integration + +Currently, CoW Protocol uses a dedicated `FlashLoanRouter` contract for flash loan functionality. However, this implementation comes with additional implementation effort from both the solvers and the CoW Protocol backend infrastructure. With generalized wrappers, flash loan integration becomes simpler and more flexible. + +### Progmatic Orders + +By introducing a wrapped order type combined with [composable-cow](../../reference/periphery/composable-cow/README.mdx) conditional order generators, it is possible for any account (EOA or smart contract wallet) to authorize delayed orders that can be triggered at a specified time. The wrapper contract provides the signing authentication, the conditional order contract controls the logic for when the order can execute, and the CoW Settlement contract protects the execution of the swap generated by the conditional order. + +### Protocol-Approved Hooks + +Unlike [CoW Hooks](./cow-hooks.mdx), which can revert even if the order is executed successfully, wrappers provide a way to enforce required pre- and post-settlement operations. Since wrappers are protocol-approved through the allowlist authenticator, they can implement critical functionality that must execute: + +- Compliance checks (e.g., OFAC screening) +- Cross chain transfers (pre- or post- transfer) +- Deposit in a vault or other wrapper contract (swap and stake) + +The key difference from hooks is that if a wrapper is required for an order, the settlement cannot proceed without it—making wrappers ideal for functionality that must not be skipped that is also approved. + +## Considerations + +While wrappers are powerful, there are important considerations to keep in mind: + +### Gas Overhead + +Wrappers add gas overhead to settlement transactions. Benchmarks show that even an empty wrapper (one that does nothing but pass through to settlement) adds approximately 22,272 gas, or about 11.4% overhead. The actual overhead depends on: + +- The complexity of the wrapper's logic +- The size of the settlement data being passed through +- The number of nested wrappers in the chain + +For many use cases, this overhead is acceptable given the functionality unlocked, but it's an important factor in deciding whether to use a wrapper. + +### Requires Protocol Approval + +Wrappers cannot be deployed and used immediately—they must be approved by the CoW DAO through the allowlist authenticator. This approval process ensures high quality wrapper implementations and safety for solvers, but means there's a roadblock for developers looking to extend CoW Protocol. Developers should plan for this approval process when building wrapper-based integrations. + +### Execution Not Enforced by the on-chain Protocol + +Despite official rules enforcing the execution of wrappers when required by the user, a solver could still not execute a wrapper with an order. This means wrappers must be designed defensively: + +- If a wrapper is strictly required, the order should fail to settle without it +- Wrappers should validate all input data and fail in cases where a user's funds could be at risk + +### Encoding Complexity + +To improve gas performance, wrapper data is encoded in a condensed format. Constructing wrapper calldata correctly can be complex, especially when nesting multiple wrappers. While the protocol provides helper contracts like `CowWrapperHelper` to simplify this, developers need to understand the encoding scheme to build robust integrations. + +## Getting Started + +Wrappers are a powerful tool for advanced integrations on CoW Protocol. To start building with wrappers: + +- **For developers**: See the [Integration Guide](../../integrate/wrappers.mdx) for implementation details, code examples, and security guidelines +- **For technical specs**: Consult the [Technical Reference](../../reference/contracts/periphery/wrapper.md) for detailed contract documentation and API specifications + +To learn more about wrappers and see example implementations: + +- [Euler Integration Contracts Repository](https://github.com/cowprotocol/euler-integration-contracts) - Contains the `CowWrapper` abstract contract and example implementations +- [Services Repository PR #3700](https://github.com/cowprotocol/services/pull/3700) - Backend integration implementation. Good reference for solvers looking to support wrappers. + +Wrappers represent a significant evolution in CoW Protocol's capabilities, enabling complex DeFi workflows while maintaining security and simplicity for solvers. As more wrappers are developed and approved, they will continue to expand what's possible with intent-based trading. diff --git a/docs/cow-protocol/integrate/wrappers.mdx b/docs/cow-protocol/integrate/wrappers.mdx new file mode 100644 index 000000000..93661ef1a --- /dev/null +++ b/docs/cow-protocol/integrate/wrappers.mdx @@ -0,0 +1,346 @@ +# 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](#for-wrapper-developers)** - Develop custom wrapper contracts for advanced DeFi workflows +- **[Using Existing Wrappers](#for-order-creators--frontend-developers)** - Add wrappers to your orders and integrate into your application +- **[Executing Wrappers as a Solver](#for-solvers) - 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: + +1. Inherit from the `CowWrapper` abstract contract +2. Implement `_wrap()` with your pre/post-settlement logic +3. Implement `parseWrapperData()` for input validation +4. Test thoroughly on testnets +5. Submit for allowlist approval by the CoW Protocol team + +Read up on the details of creating a wrapper from [the wrapper contract information page](../reference/contracts/periphery/wrapper.mdx). + +--- + +# For Order Creators / 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 + +```typescript +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 contract +- **`data`** (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 to `false` + - `false` = Solver MUST execute the wrapper with exact data or be slashed + - `true` = Solver MAY skip the wrapper if they find a better solution + +### Example: Using the CoW SDK + +```typescript +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: + +```typescript +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`: + +```typescript +// 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`](TODO) under the `wrappers` field: + +```json +{ + "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) + +:::warning +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`](../references/contracts/core/allowlist.md). 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 + +:::info +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): + +```typescript +// 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: + +```typescript +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: + +```typescript +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 + +```typescript +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: + +```solidity +// 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: + +1. **Collect wrappers from orders**: As you process orders in an auction, collect all `wrappers` arrays from order appData +2. **Aggregate for batch**: Combine wrappers needed for all orders in the settlement batch +3. **Include in solution**: Add aggregated wrappers to your solution structure +4. **Encode transaction**: Use the encoding algorithm above to construct the final transaction + +**Example (conceptual):** + +```typescript +// 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 `settleData` is identical to what you'd send to `GPv2Settlement.settle()` +- Check `wrapperData` encoding follows specification exactly +- Use `CowWrapperHelper` for validation + +## Solver Resources + +### Documentation +- **[Wrapper Concepts](../concepts/order-types/wrappers.md)** - High-level overview +- **[Contracts Reference](../reference/contracts/periphery/wrapper.md)** - Contract specifications +- **[Services PR #3700](https://github.com/cowprotocol/services/pull/3700)** - Reference encoding implementation in production + +--- \ No newline at end of file diff --git a/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx b/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx new file mode 100644 index 000000000..1a067e0b1 --- /dev/null +++ b/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx @@ -0,0 +1,497 @@ +--- +sidebar_position: 7 +--- + +# Generalized Wrappers + +Generalized wrappers are smart contracts that enable custom logic to execute before and after CoW Protocol settlement operations. This reference documents the contract interfaces, implementation patterns, and on-chain behavior of the wrapper system. + +## Architecture + +### Execution Flow + +```mermaid +sequenceDiagram + participant Solver + participant Wrapper1 + participant Wrapper2 + participant Settlement + + Solver->>Wrapper1: wrappedSettle(settleData, wrapperData) + activate Wrapper1 + Note over Wrapper1: Pre-settlement logic + Wrapper1->>Wrapper2: _next(remainingData) + activate Wrapper2 + Note over Wrapper2: Pre-settlement logic + Wrapper2->>Settlement: settle(settleData) + activate Settlement + Note over Settlement: Execute trades + Settlement-->>Wrapper2: Return + deactivate Settlement + Note over Wrapper2: Post-settlement logic + Wrapper2-->>Wrapper1: Return + deactivate Wrapper2 + Note over Wrapper1: Post-settlement logic + Wrapper1-->>Solver: Return + deactivate Wrapper1 +``` + +### Key Design Principles + +1. **Abstract**: There are very few limitations on what a wrapper can/can't do around a settlement transaction +2. **Efficient Encoding**: Wrapper-specific data appended to minimize gas overhead +3. **Nested Support**: Multiple wrappers chain by encoding addresses sequentially, allowing CoW orders +4. **Authentication**: Only allowlisted wrappers can call settlement contract + +## Implementation + +Developers looking to integrate using wrappers should copy this all-in-one solidity file in your project. + +It provides a few base contracts which can serve as the foundation for your integration: + +- **`ICowWrapper`**: Core interface all wrappers must implement +- **`CowWrapper`**: Abstract base contract providing security and utilities that all wrappers should use + + + + +### Quick Start Example + +Here's a minimal wrapper implementation to use as a starting point: + +```solidity +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.0; + +import { CowWrapper } from "./CowWrapper.sol"; + +contract MyWrapper is CowWrapper { + constructor(address settlement) CowWrapper(settlement) {} + + function _wrap(bytes calldata wrapperData) internal override { + // Your custom pre-settlement logic here + // Example: pull tokens, initiate flash loan, etc. + + // Continue the wrapper chain (calls settlement or next wrapper) + _next(wrapperData); + + // Your custom post-settlement logic here + // Example: repay flash loan, stake tokens, etc. + } + + function parseWrapperData(bytes calldata wrapperData) + external + view + override + returns (bytes memory) + { + // Validate and parse wrapper-specific data + // This must be deterministic - same input always returns same output + // Revert if data is invalid + return wrapperData; + } +} +``` + +### Wrapper Public Functions + +#### `wrappedSettle` + +Entry point for wrapper execution. Validates caller authentication and delegates to `_wrap()`--where integrators place their custom logic. + +```solidity +function wrappedSettle( + bytes calldata settleData, + bytes calldata chainedWrapperData +) external override { + // Verify caller is an authenticated solver + require( + GPv2Authentication(SETTLEMENT).isSolver(msg.sender), + "Not authorized" + ); + + _wrap(wrapperData); +} +``` + +**Parameters:** +- `settleData`: Original `GPv2Settlement.settle(...)` calldata +- `chainedWrapperData`: + +#### Chained Wrapper Data Encoding + +Each wrapper in the chain consists of: +- 2 bytes: uint16 length of wrapper-specific data +- `length` bytes: wrapper-specific data for this wrapper +- 20 bytes: address of next wrapper (omitted for the final wrapper) +The final wrapper in the chain omits the next wrapper address and calls SETTLEMENT directly. + +``` +Example: +``` +[0x0005][0xAABBCCDDEE][0x1234...ABCD][0x0003][0x112233] +↑len ↑data ↑next wrapper ↑len ↑data +``` + +Each wrapper in the chain will successively pull off their own data and then call the next wrapper address (or the settlement address if no further wrapper data is supplied). + +### Virtual Functions for integrators + +#### `_wrap` + +Contains custom surrounding settlement logic. **Must** call `_next()` to continue the chain to the settlement contract. + +```solidity +function _wrap(bytes calldata wrapperData) internal virtual; +``` + +**Implementation Requirements:** +- Parse wrapper-specific data from `wrapperData` as required +- Execute pre-settlement logic +- Call `_next(remainingWrapperData)` to continue chain +- Execute post-settlement logic + +**Example:** + +```solidity +function _wrap(bytes calldata wrapperData) internal override { + // 1. Parse data (first 2 bytes = length) + uint16 myDataLength = uint16(bytes2(wrapperData[:2])); + bytes calldata myData = wrapperData[2:2+myDataLength]; + + (address token, uint256 amount) = abi.decode(myData, (address, uint256)); + + // 2. Pre-settlement logic. Example, receive tokens from user + IERC20(token).transferFrom(msg.sender, address(this), amount); + + // 3. Continue chain (REQUIRED) + _next(wrapperData[2+myDataLength:]); + + // 4. Post-settlement logic. Example: stake tokens to a contract (for swap and stake) + stakeTokens(token, amount); +} +``` + +### Internal Functions (Provided) + +#### `_next` + +Continues the wrapper chain or calls settlement. Handles all parsing and routing automatically. + +```solidity +function _next(bytes calldata remainingWrapperData) internal; +``` + +**Behavior:** +- Reads next wrapper address from `remainingWrapperData` +- Determines if more wrappers exist or if settlement is next +- Makes appropriate call with correct data +- Handles wrapper nesting automatically + +**Implementation Details:** +- Extracts next target address (last 20 bytes) +- Separates settle data from remaining wrapper data +- Calls next wrapper via `wrappedSettle()` or settlement via `settle()` + +## Calldata Encoding Specification + +Wrapper data uses an optimized encoding to minimize gas overhead: + +### Structure + +``` +┌─────────────────────┬──────┬──────────┬──────────┬──────┬──────────┬────────────┐ +│ Settle Calldata │ Len₁ │ Data₁ │ Addr₂ │ Len₂ │ Data₂ │ Settlement │ +│ (to settlement) │(2 B) │ (wrap1) │ (20 B) │(2 B) │ (wrap2) │ (20 B) │ +└─────────────────────┴──────┴──────────┴──────────┴──────┴──────────┴────────────┘ +│<─── settleData ───>│<────────────────── wrapperData ──────────────────────────>│ +``` + +**Components:** +- **Settle Calldata**: `GPv2Settlement.settle(...)` calldata (function selector + args) +- **Len₁**: 2-byte (uint16) length of wrapper 1's data +- **Data₁**: Wrapper 1's custom data +- **Addr₂**: 20-byte address of wrapper 2 +- **Len₂**: 2-byte (uint16) length of wrapper 2's data +- **Data₂**: Wrapper 2's custom data +- **Settlement**: 20-byte address of settlement contract (final target) + +### Data Consumption + +Each wrapper in the chain: +1. Reads length prefix (2 bytes) +2. Extracts its data (next N bytes) +3. Passes remaining bytes to `_next()` + +The `_next()` function: +1. Reads next address (from appropriate offset) +2. Calls next wrapper or settlement +3. Passes remaining data + +## CowWrapperHelper + +Utility contract for on-chain validation and encoding. + +### Interface + +```solidity +contract CowWrapperHelper { + /// @notice Validate and build wrapper data for multiple wrappers + /// @param wrapperAddresses Array of wrapper contract addresses + /// @param wrapperDatas Array of wrapper-specific data (parallel to addresses) + /// @return wrapperData Encoded wrapper data ready for wrappedSettle call + function verifyAndBuildWrapperData( + address[] calldata wrapperAddresses, + bytes[] calldata wrapperDatas + ) external view returns (bytes memory wrapperData); +} +``` + + +### `CowWrapperHelpers` + +To aid external integrators in encoding and verifying wrapper data, an additional view-only contract is provided. + + + + +#### `parseWrapperData` + +Validates wrapper-specific data. Must be deterministic and revert on invalid input. + +```solidity +function parseWrapperData( + bytes calldata wrapperData +) external view override returns (bytes memory); +``` + +**Requirements:** +- **Deterministic**: Same input must always produce same output +- **No time-based logic**: Cannot use `block.timestamp`, `block.number`, etc. +- **No mutable state**: Cannot read external mutable state +- **View function**: Cannot modify state +- **Revert on invalid**: Revert if data is malformed + +## Implementation Guidelines for Integrators + +### Security Requirements + +:::warning Critical Requirements + +#### 1. Use CowWrapper Abstract Contract + +It is strongly reccomended to **NOT** implement `ICowWrapper` directly. The `CowWrapper` abstract contract provides: +- Solver authentication checks +- Correct calldata parsing and decoding +- Safe wrapper chain continuation +- Sanity checks for the settlement call + +#### 2. Intermediate Contracts for User Calls + +If allowing user-defined calls, route through intermediate contracts: + +```solidity +// ❌ DANGEROUS +function _wrap(bytes calldata wrapperData) internal override { + (address target, bytes memory data) = abi.decode(wrapperData, (address, bytes)); + target.call(data); // User could call anything they want, including the settlement contract, using the wrapper's authenticated context +} + +// ✅ SAFE +function _wrap(bytes calldata wrapperData) internal override { + (address target, bytes memory data) = abi.decode(wrapperData, (address, bytes)); + HooksTrampoline(TRAMPOLINE).execute(target, data); // Isolated execution +} +``` + +#### 3. Assume All Parameters Are Untrusted + +Settlement data can be modified by nested wrappers, and solvers can supply arbitrary calldata. If it is important for your wrapper to be able to validate the wrapper it is receiving, only trust signature-protected or on-chain validated parameters. + +#### 4. Deterministic Parsing Required + +`parseWrapperData()` must always return same result for same input: + +```solidity +// ❌ NOT DETERMINISTIC +function parseWrapperData(bytes calldata wrapperData) + external view override returns (bytes memory) +{ + uint256 deadline = abi.decode(wrapperData, (uint256)); + require(block.timestamp < deadline, "Expired"); // Changes over time! + return wrapperData; +} + +// ✅ DETERMINISTIC +function parseWrapperData(bytes calldata wrapperData) + external view override returns (bytes memory) +{ + uint256 deadline = abi.decode(wrapperData, (uint256)); + require(deadline > 0, "Invalid deadline"); // Always same result + return wrapperData; +} +``` + +In the example above, your `_wrap` code can always reject deadline past expired instead. + +#### 5. Defensive Design + +Though a solver would be slashed for doing so, there is no hard guarantee wrapper executes even if user specifies it. If wrapper is critical: + +**Option A: Make Order Fail Without Wrapper** +```solidity +// Pull required funds in wrapper +function _wrap(bytes calldata wrapperData) internal override { + vault.withdraw(user, token, amount); // Funds now in wrapper + _next(wrapperData); + // Settlement uses these funds - fails if wrapper didn't execute +} +``` + +**Option B: EIP-1271 Authentication** +```solidity +// Order signature only valid if wrapper executed +function isValidSignature(bytes32 hash, bytes memory signature) + external view returns (bytes4) +{ + require(wrapperExecuted[hash], "Wrapper required"); + return EIP1271_MAGIC; +} +``` + +There may be other similar ways to enforce execution, but these patterns serve as a starting point. + +::: + +### Gas Overhead + +Wrapper execution adds gas overhead to settlements. + +**Benchmark (EmptyWrapper on Ethereum mainnet):** + +| Metric | Value | +|--------|-------| +| With EmptyWrapper | 217,033 gas | +| Without wrapper | 194,761 gas | +| **Overhead** | **22,272 gas (11.4%)** | + +**Scaling Factors:** +- Settlement data size (calldata copying) +- Wrapper logic complexity +- Number of nested wrappers + +**Methodology:** Single Uniswap V3 WETH→USDC trade. See [services PR #3700](https://github.com/cowprotocol/services/pull/3700). + +## Example Implementations + +### EmptyWrapper + +Minimal wrapper demonstrating the pattern: + +```solidity +contract EmptyWrapper is CowWrapper { + constructor(address settlement) CowWrapper(settlement) {} + + function _wrap(bytes calldata wrapperData) internal override { + // No pre-settlement logic + _next(wrapperData); // Pass through + // No post-settlement logic + } + + function parseWrapperData(bytes calldata wrapperData) + external + view + override + returns (bytes memory) + { + // No validation needed + return wrapperData; + } +} +``` + +### Flash Loan Wrapper + +Wrapper coordinating with lending protocol: + +```solidity +contract FlashLoanWrapper is CowWrapper { + ILendingPool public immutable lendingPool; + + constructor(address settlement, address _lendingPool) + CowWrapper(settlement) + { + lendingPool = ILendingPool(_lendingPool); + } + + function _wrap(bytes calldata wrapperData) internal override { + (address asset, uint256 amount, bytes memory params) = + abi.decode(wrapperData, (address, uint256, bytes)); + + // Initiate flash loan (calls executeOperation) + lendingPool.flashLoan(address(this), asset, amount, params); + } + + function executeOperation( + address asset, + uint256 amount, + uint256 premium, + address, + bytes calldata params + ) external returns (bool) { + require(msg.sender == address(lendingPool), "Unauthorized"); + + // Execute settlement with borrowed funds + _next(params); + + // Approve repayment + IERC20(asset).approve(address(lendingPool), amount + premium); + return true; + } + + function parseWrapperData(bytes calldata wrapperData) + external + view + override + returns (bytes memory) + { + require(wrapperData.length >= 96, "Invalid data length"); + (address asset, uint256 amount,) = abi.decode( + wrapperData, + (address, uint256, bytes) + ); + require(asset != address(0) && amount > 0, "Invalid parameters"); + return wrapperData; + } +} +``` + +## Known Limitations + +### Authentication Required + +Wrappers need protocol approval, and are not fully permissionless. + +### Settlement Upgrades + +When settlement contract upgrades, all wrappers must be redeployed. It is reccomended to use [Cannon](https://usecannon.com/learn) to make it easy to redeploy your wrappers. + +## Events + +No wrapper-specific events are emitted. Wrapper usage can be identified by: + +1. Transaction target is wrapper address (not settlement) +2. Function signature is `wrappedSettle(bytes,bytes)` (not `settle(...)`) +3. Analyzing transaction trace for wrapper contract calls + +## Resources + +### Documentation +- **[Wrapper Concepts](../../../concepts/order-types/wrappers.md)** - High-level overview and use cases +- **[Integration Guide](../../../integrate/wrappers.mdx)** - Implementation guide for order creators and developers +- **[GPv2Settlement](../core/settlement.md)** - Core settlement contract documentation + +### Code +- **[CowWrapper.sol](https://github.com/cowprotocol/euler-integration-contracts/blob/main/src/CowWrapper.sol)** - Abstract contract and interfaces +- **[EmptyWrapper](https://github.com/cowprotocol/euler-integration-contracts)** - Minimal reference implementation +- **[Euler Integration](https://github.com/cowprotocol/euler-integration-contracts/pull/6)** - Complete production wrapper example From 4248b8f16bbe0cbb023f0cc7d4da63d87e97074f Mon Sep 17 00:00:00 2001 From: Kaze Date: Fri, 13 Feb 2026 01:08:46 +0900 Subject: [PATCH 02/11] fix compile errors --- .../concepts/order-types/wrappers.md | 4 ++-- docs/cow-protocol/integrate/wrappers.mdx | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/cow-protocol/concepts/order-types/wrappers.md b/docs/cow-protocol/concepts/order-types/wrappers.md index 3c91d0058..36f4aea24 100644 --- a/docs/cow-protocol/concepts/order-types/wrappers.md +++ b/docs/cow-protocol/concepts/order-types/wrappers.md @@ -43,7 +43,7 @@ Currently, CoW Protocol uses a dedicated `FlashLoanRouter` contract for flash lo ### Progmatic Orders -By introducing a wrapped order type combined with [composable-cow](../../reference/periphery/composable-cow/README.mdx) conditional order generators, it is possible for any account (EOA or smart contract wallet) to authorize delayed orders that can be triggered at a specified time. The wrapper contract provides the signing authentication, the conditional order contract controls the logic for when the order can execute, and the CoW Settlement contract protects the execution of the swap generated by the conditional order. +By introducing a wrapped order type combined with [composable-cow](../../reference/contracts/periphery/composable_cow.md) conditional order generators, it is possible for any account (EOA or smart contract wallet) to authorize delayed orders that can be triggered at a specified time. The wrapper contract provides the signing authentication, the conditional order contract controls the logic for when the order can execute, and the CoW Settlement contract protects the execution of the swap generated by the conditional order. ### Protocol-Approved Hooks @@ -89,7 +89,7 @@ To improve gas performance, wrapper data is encoded in a condensed format. Const Wrappers are a powerful tool for advanced integrations on CoW Protocol. To start building with wrappers: - **For developers**: See the [Integration Guide](../../integrate/wrappers.mdx) for implementation details, code examples, and security guidelines -- **For technical specs**: Consult the [Technical Reference](../../reference/contracts/periphery/wrapper.md) for detailed contract documentation and API specifications +- **For technical specs**: Consult the [Technical Reference](../../reference/contracts/periphery/wrapper.mdx) for detailed contract documentation and API specifications To learn more about wrappers and see example implementations: diff --git a/docs/cow-protocol/integrate/wrappers.mdx b/docs/cow-protocol/integrate/wrappers.mdx index 93661ef1a..c1a8c4352 100644 --- a/docs/cow-protocol/integrate/wrappers.mdx +++ b/docs/cow-protocol/integrate/wrappers.mdx @@ -4,12 +4,12 @@ Generalized wrappers enable custom logic to execute surrounding CoW Protocol set **Choose your path:** - **[Building New Wrappers](#for-wrapper-developers)** - Develop custom wrapper contracts for advanced DeFi workflows -- **[Using Existing Wrappers](#for-order-creators--frontend-developers)** - Add wrappers to your orders and integrate into your application -- **[Executing Wrappers as a Solver](#for-solvers) - Everything solvers need to know to execute wrapper orders +- **[Using Existing Wrappers](#for-order-creators-and-frontend-developers)** - Add wrappers to your orders and integrate into your application +- **[Executing Wrappers as a Solver](#for-solvers)** - Everything solvers need to know to execute wrapper orders --- -# For Wrapper Developers +## For Wrapper Developers This section covers building new wrapper contracts from scratch. @@ -27,7 +27,7 @@ Read up on the details of creating a wrapper from [the wrapper contract informat --- -# For Order Creators / Frontend Developers +## 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. @@ -122,13 +122,13 @@ This checks: --- -# For Solvers +## 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`](TODO) under the `wrappers` field: +Wrappers are specified in the order's [`appData`](../reference/core/auctions/schema.md) under the `wrappers` field: ```json { @@ -161,7 +161,7 @@ If `"is_omittable": true`, you MAY skip the wrapper if you find a better solutio ### 2. Verify Wrapper Authentication -All approved wrappers will be approved by the DAO and registered in [`GPv2AllowlistAuthenticator`](../references/contracts/core/allowlist.md). It is recommended to verify wrappers are allowlisted before including them in settlements. +All approved wrappers will be approved by the DAO and registered in [`GPv2AllowlistAuthenticator`](../reference/contracts/core/allowlist.md). It is recommended to verify wrappers are allowlisted before including them in settlements. ### 3. Include Wrappers in Solution @@ -340,7 +340,7 @@ Account for wrapper gas overhead in your bids. The easiest way to do this is to ### Documentation - **[Wrapper Concepts](../concepts/order-types/wrappers.md)** - High-level overview -- **[Contracts Reference](../reference/contracts/periphery/wrapper.md)** - Contract specifications +- **[Contracts Reference](../reference/contracts/periphery/wrapper.mdx)** - Contract specifications - **[Services PR #3700](https://github.com/cowprotocol/services/pull/3700)** - Reference encoding implementation in production --- \ No newline at end of file From 8e0fcdd32d0cef39b0a92e8084d6e33624d1590e Mon Sep 17 00:00:00 2001 From: Kaze Date: Tue, 17 Feb 2026 12:07:21 +0900 Subject: [PATCH 03/11] try to clean up wording of the wrapper description --- docs/cow-protocol/concepts/order-types/wrappers.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/cow-protocol/concepts/order-types/wrappers.md b/docs/cow-protocol/concepts/order-types/wrappers.md index 36f4aea24..db8c686d8 100644 --- a/docs/cow-protocol/concepts/order-types/wrappers.md +++ b/docs/cow-protocol/concepts/order-types/wrappers.md @@ -12,13 +12,13 @@ Wrappers are smart contracts that "wrap" the settlement process, executing custo This mechanism extends CoW Protocol's functionality in a modular way, allowing new features and integrations to be added without modifying the core settlement contract or requiring any changes to solver implementations. -### Wrapper Authentication +### Wrapper Nesting -For security, all wrappers must be approved through CoW Protocol's `GPv2AllowlistAuthenticator` before they can be used. This ensures that only audited and wrappers can interact with the settlement contract, protecting users, solver, and the protocol from malicious contracts. Unlike [hooks](./cow-hooks.mdx), Wrapper functionality can revert the execution of a transaction, ensuring sensitive user operations such as cross-chain operations can be guarenteed to be completed. +One of the powerful features of wrappers is their ability to be nested. Multiple wrappers can be chained together in a single settlement transaction, allowing different orders in the same batch to each use their required wrapper functionality. For example, one order might need a flash loan wrapper while another needs a leverage wrapper—both can be executed in the same settlement. -### Wrapper Nesting +### Wrapper Authentication -One of the powerful features of wrappers is their ability to be nested. Multiple wrappers can be chained together in a single settlement transaction, allowing different orders in the same batch to each use their required wrapper functionality. For example, one order might need a flash loan wrapper while another needs a leverage wrapper—both can be executed in the same settlement through wrapper nesting. +To ensure security and quality, all wrappers must be approved through CoW Protocol's `GPv2AllowlistAuthenticator` before they can be used. This ensures that solvers can interact confidently with any approved wrapper. It also unlocks additional features, such as guarenteed execution or revert, which is not supported with hooks because untrusted contracts can grief the settlement process by reverting. ## Use Cases From 44a2d3b798447d5b934a4ad5016c7d6137def0e5 Mon Sep 17 00:00:00 2001 From: Kaze Date: Tue, 17 Feb 2026 12:10:12 +0900 Subject: [PATCH 04/11] wording for guarenteed execution --- docs/cow-protocol/concepts/order-types/wrappers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cow-protocol/concepts/order-types/wrappers.md b/docs/cow-protocol/concepts/order-types/wrappers.md index db8c686d8..ea62d5ab2 100644 --- a/docs/cow-protocol/concepts/order-types/wrappers.md +++ b/docs/cow-protocol/concepts/order-types/wrappers.md @@ -53,7 +53,7 @@ Unlike [CoW Hooks](./cow-hooks.mdx), which can revert even if the order is execu - Cross chain transfers (pre- or post- transfer) - Deposit in a vault or other wrapper contract (swap and stake) -The key difference from hooks is that if a wrapper is required for an order, the settlement cannot proceed without it—making wrappers ideal for functionality that must not be skipped that is also approved. +The key difference from hooks is that if a wrapper is required for an order, the settlement cannot proceed without it—making wrappers ideal for transactions requiring robust execution. ## Considerations From 5563ab8fbdce7ee9e24787dce1d660039e9fdd7e Mon Sep 17 00:00:00 2001 From: Kaze Date: Tue, 17 Feb 2026 12:13:32 +0900 Subject: [PATCH 05/11] fix wordings --- docs/cow-protocol/concepts/order-types/wrappers.md | 10 +--------- docs/cow-protocol/integrate/wrappers.mdx | 4 ++-- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/docs/cow-protocol/concepts/order-types/wrappers.md b/docs/cow-protocol/concepts/order-types/wrappers.md index ea62d5ab2..6498ffcea 100644 --- a/docs/cow-protocol/concepts/order-types/wrappers.md +++ b/docs/cow-protocol/concepts/order-types/wrappers.md @@ -12,14 +12,6 @@ Wrappers are smart contracts that "wrap" the settlement process, executing custo This mechanism extends CoW Protocol's functionality in a modular way, allowing new features and integrations to be added without modifying the core settlement contract or requiring any changes to solver implementations. -### Wrapper Nesting - -One of the powerful features of wrappers is their ability to be nested. Multiple wrappers can be chained together in a single settlement transaction, allowing different orders in the same batch to each use their required wrapper functionality. For example, one order might need a flash loan wrapper while another needs a leverage wrapper—both can be executed in the same settlement. - -### Wrapper Authentication - -To ensure security and quality, all wrappers must be approved through CoW Protocol's `GPv2AllowlistAuthenticator` before they can be used. This ensures that solvers can interact confidently with any approved wrapper. It also unlocks additional features, such as guarenteed execution or revert, which is not supported with hooks because untrusted contracts can grief the settlement process by reverting. - ## Use Cases Wrappers enable a wide variety of advanced trading and DeFi operations: @@ -71,7 +63,7 @@ For many use cases, this overhead is acceptable given the functionality unlocked ### Requires Protocol Approval -Wrappers cannot be deployed and used immediately—they must be approved by the CoW DAO through the allowlist authenticator. This approval process ensures high quality wrapper implementations and safety for solvers, but means there's a roadblock for developers looking to extend CoW Protocol. Developers should plan for this approval process when building wrapper-based integrations. +Wrappers cannot be deployed and used immediately—they must be approved by CoW DAO through the allowlist authenticator. This approval process ensures high quality wrapper implementations and safety for solvers, but means there's a roadblock for developers looking to extend CoW Protocol. Developers should plan for this approval process when building wrapper-based integrations. ### Execution Not Enforced by the on-chain Protocol diff --git a/docs/cow-protocol/integrate/wrappers.mdx b/docs/cow-protocol/integrate/wrappers.mdx index c1a8c4352..98a4d26bc 100644 --- a/docs/cow-protocol/integrate/wrappers.mdx +++ b/docs/cow-protocol/integrate/wrappers.mdx @@ -23,7 +23,7 @@ To build a wrapper, you will: 4. Test thoroughly on testnets 5. Submit for allowlist approval by the CoW Protocol team -Read up on the details of creating a wrapper from [the wrapper contract information page](../reference/contracts/periphery/wrapper.mdx). +Read more on the details of creating a wrapper from [the wrapper contract information page](../reference/contracts/periphery/wrapper.mdx). --- @@ -343,4 +343,4 @@ Account for wrapper gas overhead in your bids. The easiest way to do this is to - **[Contracts Reference](../reference/contracts/periphery/wrapper.mdx)** - Contract specifications - **[Services PR #3700](https://github.com/cowprotocol/services/pull/3700)** - Reference encoding implementation in production ---- \ No newline at end of file +--- From ad8f9e67925334f69b063b79a118c5dd4b0430a7 Mon Sep 17 00:00:00 2001 From: Kaze Date: Tue, 17 Feb 2026 12:16:44 +0900 Subject: [PATCH 06/11] use protocol terminology --- docs/cow-protocol/integrate/wrappers.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/cow-protocol/integrate/wrappers.mdx b/docs/cow-protocol/integrate/wrappers.mdx index 98a4d26bc..891f5aada 100644 --- a/docs/cow-protocol/integrate/wrappers.mdx +++ b/docs/cow-protocol/integrate/wrappers.mdx @@ -163,9 +163,9 @@ If `"is_omittable": true`, you MAY skip the wrapper if you find a better solutio All approved wrappers will be approved by the DAO and registered in [`GPv2AllowlistAuthenticator`](../reference/contracts/core/allowlist.md). It is recommended to verify wrappers are allowlisted before including them in settlements. -### 3. Include Wrappers in Solution +### 3. Include Wrappers in the Solution -Whether using the CoW-provided driver or your own, ensure wrapper information flows from the auction to your final settlement transaction. +Whether using the CoW Protocol provided driver or your own, ensure wrapper information flows from the auction to your final settlement transaction. ## Encoding Wrapper Settlements From 3e58601c5f585e12ab4f520cbfc810286faba3be Mon Sep 17 00:00:00 2001 From: Kaze Date: Tue, 17 Feb 2026 12:18:20 +0900 Subject: [PATCH 07/11] fix more wording for CoW team --- docs/cow-protocol/integrate/wrappers.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/cow-protocol/integrate/wrappers.mdx b/docs/cow-protocol/integrate/wrappers.mdx index 891f5aada..4dc9cad1d 100644 --- a/docs/cow-protocol/integrate/wrappers.mdx +++ b/docs/cow-protocol/integrate/wrappers.mdx @@ -170,7 +170,7 @@ Whether using the CoW Protocol provided driver or your own, ensure wrapper infor ## Encoding Wrapper Settlements :::info -If you're using the driver provided by the CoW team, you can skip this section - the driver handles encoding automatically. +If you're using the driver provided by CoW Protocol, you can skip this section - the driver handles encoding automatically. ::: ### Manual Encoding @@ -282,7 +282,7 @@ In addition to producing the correct encoded data, the helper also validates: ### 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. +If you're using the CoW Protocol's provided driver, wrappers are handled automatically. Just ensure your solver process includes wrapper information in the solution output. ### Custom Implementation From aba6279ec93897e46beaac0448c52933abcd8a4a Mon Sep 17 00:00:00 2001 From: Kaze Date: Tue, 17 Feb 2026 12:20:04 +0900 Subject: [PATCH 08/11] fix wording in periphery guide --- docs/cow-protocol/reference/contracts/periphery/wrapper.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx b/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx index 1a067e0b1..dde2f1c2f 100644 --- a/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx +++ b/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx @@ -45,7 +45,7 @@ sequenceDiagram ## Implementation -Developers looking to integrate using wrappers should copy this all-in-one solidity file in your project. +Developers looking to integrate using wrappers should copy this all-in-one solidity file into their project as vendored dependency. It provides a few base contracts which can serve as the foundation for your integration: From 9678bb8a8017a1aa57213f57013070d56cf5c749 Mon Sep 17 00:00:00 2001 From: Kaze Date: Tue, 17 Feb 2026 12:29:41 +0900 Subject: [PATCH 09/11] actually embed the code since the gist embed script doesn't seem to work --- .../reference/contracts/periphery/wrapper.mdx | 211 +++++++++++++++++- 1 file changed, 209 insertions(+), 2 deletions(-) diff --git a/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx b/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx index dde2f1c2f..e6b5ee17c 100644 --- a/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx +++ b/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx @@ -47,13 +47,220 @@ sequenceDiagram Developers looking to integrate using wrappers should copy this all-in-one solidity file into their project as vendored dependency. -It provides a few base contracts which can serve as the foundation for your integration: +It provides a few base contracts which can serve as the foundation for integration: - **`ICowWrapper`**: Core interface all wrappers must implement - **`CowWrapper`**: Abstract base contract providing security and utilities that all wrappers should use - +```solidity +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity ^0.8; + +/** + * Title: CoW Wrapper all-in-one integration file + * Author: CoW DAO + * This file is completely self-contained (ie no dependencies) and can be portably copied to whatever projects it is needed. + * It contains: + * * CowWrapper -- an abstract base contract which should be inherited by all wrappers + * * ICowWrapper -- the required interface for all wrappers + * * ICowSettlement -- A minimized interface and base structures for CoW Protocol settlement contract. From https://github.com/cowprotocol/contracts/blob/main/src/contracts/GPv2Settlement.sol + * * ICowAuthentication -- The authentication interface used by ICowSettlement. From https://github.com/cowprotocol/contracts/blob/main/src/contracts/interfaces/GPv2Authentication.sol + */ + +/// @title CoW Protocol Authentication Interface +/// @author CoW DAO developers +interface ICowAuthentication { + /// @dev determines whether the provided address is an authenticated solver. + /// @param prospectiveSolver the address of prospective solver. + /// @return true when prospectiveSolver is an authenticated solver, otherwise false. + function isSolver(address prospectiveSolver) external view returns (bool); +} + +/// @title CoW Protocol Settlement Interface +/// @notice Minimal interface for CoW Protocol's settlement contract +/// @dev Used for type-safe calls to the settlement contract's settle function +interface ICowSettlement { + /// @notice Trade data structure matching GPv2Settlement + struct Trade { + uint256 sellTokenIndex; + uint256 buyTokenIndex; + address receiver; + uint256 sellAmount; + uint256 buyAmount; + uint32 validTo; + bytes32 appData; + uint256 feeAmount; + uint256 flags; + uint256 executedAmount; + bytes signature; + } + + /// @notice Interaction data structure for pre/intra/post-settlement actions which are supplied by the solver to complete the user request + struct Interaction { + address target; + uint256 value; + bytes callData; + } + + /// @notice Returns the authentication contract used by the settlement contract. + function authenticator() external view returns (ICowAuthentication); + + /// @notice Returns the address of the vaultRelayer, the target for approvals for funds entering the settlement contract. + function vaultRelayer() external view returns (address); + + /// @notice Returns the domain separator for EIP-712 signing + function domainSeparator() external view returns (bytes32); + + /// @notice Allows for approval of orders by submitting an authorized hash on-chain prior to order execution. + function setPreSignature(bytes calldata orderUid, bool signed) external; + + /// @notice Settles a batch of trades atomically + /// @param tokens Array of token addresses involved in the settlement + /// @param clearingPrices Array of clearing prices for each token + /// @param trades Array of trades to execute + /// @param interactions Array of three interaction arrays (pre, intra, post-settlement) + function settle( + address[] calldata tokens, + uint256[] calldata clearingPrices, + Trade[] calldata trades, + Interaction[][3] calldata interactions + ) external; +} + +/// @title CoW Protocol Wrapper Interface +/// @notice Interface for wrapper contracts that add custom logic around CoW settlements +/// @dev Wrappers can be chained together to compose multiple settlement operations +interface ICowWrapper { + /// @notice A human readable label for this wrapper. Used for display in explorer/analysis UIs + function name() external view returns (string memory); + + /// @notice The settlement contract used by this wrapper + /// @return The CowSettlement contract address + function SETTLEMENT() external view returns (ICowSettlement); + + /// @notice Initiates a wrapped settlement call + /// @dev This is the entry point for wrapped settlements. The wrapper will execute custom logic + /// before calling the next wrapper or settlement contract in the chain. + /// @dev SECURITY: `settleData` is NOT guaranteed to remain unchanged through the wrapper chain. + /// Intermediate wrappers could modify it before passing it along. Do not rely on + /// `settleData` validation for security-critical checks. + /// @param settleData ABI-encoded call to ICowSettlement.settle() containing trade data + /// @param chainedWrapperData Encoded wrapper chain with the following format: + /// Structure: [uint16 len1][bytes data1][address wrapper2][uint16 len2][bytes data2][address wrapper3]... + /// + /// Each wrapper in the chain consists of: + /// - 2 bytes: uint16 length of wrapper-specific data + /// - `length` bytes: wrapper-specific data for this wrapper + /// - 20 bytes: address of next wrapper (omitted for the final wrapper) + /// + /// The final wrapper in the chain omits the next wrapper address and calls SETTLEMENT directly. + /// + /// Example: [0x0005][0xAABBCCDDEE][0x1234...ABCD][0x0003][0x112233] + /// ↑len ↑data ↑next wrapper ↑len ↑data (final, no next address) + /// + function wrappedSettle(bytes calldata settleData, bytes calldata chainedWrapperData) external; + + /// @notice Confirms validity of wrapper-specific data + /// @dev Used by CowWrapperHelpers to validate wrapper data before execution. Reverts if the wrapper data is not valid for some reason. + /// @param wrapperData The wrapper-specific data to parse + function validateWrapperData(bytes calldata wrapperData) external view; +} +/// @title CoW Protocol Wrapper Base Contract +/// @notice Abstract base contract for creating wrapper contracts around CoW Protocol settlements +/// @dev A wrapper enables custom pre/post-settlement and context-setting logic and can be chained with other wrappers. +/// Wrappers must: +/// - Be approved by the ICowAuthentication contract +/// - Verify the caller is an authenticated solver +/// - Eventually call settle() on the approved ICowSettlement contract +/// - Implement _wrap() for custom logic +abstract contract CowWrapper is ICowWrapper { + /// @notice Thrown when the caller is not an authenticated solver + /// @param unauthorized The address that attempted to call wrappedSettle + error NotASolver(address unauthorized); + + /// @notice Thrown when settle data doesn't contain the correct function selector + /// @param invalidSettleData The invalid settle data that was provided + error InvalidSettleData(bytes invalidSettleData); + + /// @notice The settlement contract + ICowSettlement public immutable SETTLEMENT; + + /// @notice The authentication contract used to verify solvers + /// @dev This is derived from `SETTLEMENT.authenticator()`. + ICowAuthentication public immutable AUTHENTICATOR; + + /// @notice Constructs a new CowWrapper + /// @param settlement_ The ICowSettlement contract to use at the end of the wrapper chain. Also used for wrapper authentication. + constructor(ICowSettlement settlement_) { + SETTLEMENT = settlement_; + AUTHENTICATOR = settlement_.authenticator(); + } + + /// @inheritdoc ICowWrapper + function wrappedSettle(bytes calldata settleData, bytes calldata chainedWrapperData) external { + // Revert if not a valid solver + require(AUTHENTICATOR.isSolver(msg.sender), NotASolver(msg.sender)); + + // Find out how long the next wrapper data is supposed to be + // We use 2 bytes to decode the length of the wrapper data because it allows for up to 64KB of data for each wrapper. + // This should be plenty of length for all identified use-cases of wrappers in the forseeable future. + uint256 nextWrapperDataLen = uint256(uint16(bytes2(chainedWrapperData[0:2]))); + + // Delegate to the wrapper's custom logic + uint256 remainingWrapperDataStart = 2 + nextWrapperDataLen; + _wrap( + settleData, chainedWrapperData[2:remainingWrapperDataStart], chainedWrapperData[remainingWrapperDataStart:] + ); + } + + /// @inheritdoc ICowWrapper + function validateWrapperData(bytes calldata wrapperData) external view virtual; + + /// @notice Internal function containing the wrapper's custom logic + /// @dev Must be implemented by concrete wrapper contracts. Should execute custom logic + /// then eventually call _next() to continue the wrapped settlement chain. + /// @param settleData ABI-encoded call to ICowSettlement.settle() + /// @param wrapperData The wrapper data which should be consumed by this wrapper + /// @param remainingWrapperData The reminder bytes resulting from consuming the current's wrapper data from the original `chainedWrapperData` in the `wrappedSettle` call. This should be passed unaltered to `_next` that will call the settlement function if this remainder is empty, or delegate the settlement to the next wrapper + function _wrap(bytes calldata settleData, bytes calldata wrapperData, bytes calldata remainingWrapperData) + internal + virtual; + + /// @notice Continues the wrapped settlement chain by calling the next wrapper or settlement contract + /// @dev Extracts the next target address from wrapperData and either: + /// - Calls ICowSettlement.settle() directly if no more wrappers remain, or + /// - Calls the next CowWrapper.wrappedSettle() to continue the chain + /// @param settleData ABI-encoded call to ICowSettlement.settle() + /// @param remainingWrapperData Remaining wrapper data starting with the next target address (20 bytes) + function _next(bytes calldata settleData, bytes calldata remainingWrapperData) internal { + if (remainingWrapperData.length == 0) { + // No more wrapper data - we're calling the final settlement contract + // Verify the settle data has the correct function selector + require(bytes4(settleData[:4]) == ICowSettlement.settle.selector, InvalidSettleData(settleData)); + + // Call the settlement contract directly with the settle data + (bool success, bytes memory returnData) = address(SETTLEMENT).call(settleData); + + if (!success) { + // Bubble up the revert reason from the settlement contract + assembly ("memory-safe") { + revert(add(returnData, 0x20), mload(returnData)) + } + } + } else { + // Extract the next wrapper address from the first 20 bytes of wrapperData + address nextWrapper = address(bytes20(remainingWrapperData[:20])); + + // Skip past the address we just read + remainingWrapperData = remainingWrapperData[20:]; + + // More wrapper data remains - call the next wrapper in the chain + CowWrapper(nextWrapper).wrappedSettle(settleData, remainingWrapperData); + } + } +} +``` ### Quick Start Example From e65d348ff77ba671edf340e7da43f7f0e1cb3888 Mon Sep 17 00:00:00 2001 From: Kaze Date: Tue, 17 Feb 2026 12:36:48 +0900 Subject: [PATCH 10/11] fix ai comments --- docs/cow-protocol/concepts/order-types/wrappers.md | 6 +++--- docs/cow-protocol/integrate/wrappers.mdx | 4 ++-- .../reference/contracts/periphery/wrapper.mdx | 9 ++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/cow-protocol/concepts/order-types/wrappers.md b/docs/cow-protocol/concepts/order-types/wrappers.md index 6498ffcea..e492d1fe2 100644 --- a/docs/cow-protocol/concepts/order-types/wrappers.md +++ b/docs/cow-protocol/concepts/order-types/wrappers.md @@ -4,7 +4,7 @@ sidebar_position: 7 # Generalized Wrappers -Generalized wrappers is a new framework to allow custom logic to execute before and/or after order settlement on CoW Protocol. They enable complex DeFi workflows—like flash loans, leveraged positions, and progmatic orders--all while preserving the security and assurances granted by CoW Protocol. +Generalized wrappers is a new framework to allow custom logic to execute before and/or after order settlement on CoW Protocol. They enable complex DeFi workflows—like flash loans, leveraged positions, and programmatic orders—all while preserving the security and assurances granted by CoW Protocol. ## What are Wrappers? @@ -33,7 +33,7 @@ This enables users to open leveraged positions on Euler through a single CoW Pro Currently, CoW Protocol uses a dedicated `FlashLoanRouter` contract for flash loan functionality. However, this implementation comes with additional implementation effort from both the solvers and the CoW Protocol backend infrastructure. With generalized wrappers, flash loan integration becomes simpler and more flexible. -### Progmatic Orders +### Programmatic Orders By introducing a wrapped order type combined with [composable-cow](../../reference/contracts/periphery/composable_cow.md) conditional order generators, it is possible for any account (EOA or smart contract wallet) to authorize delayed orders that can be triggered at a specified time. The wrapper contract provides the signing authentication, the conditional order contract controls the logic for when the order can execute, and the CoW Settlement contract protects the execution of the swap generated by the conditional order. @@ -63,7 +63,7 @@ For many use cases, this overhead is acceptable given the functionality unlocked ### Requires Protocol Approval -Wrappers cannot be deployed and used immediately—they must be approved by CoW DAO through the allowlist authenticator. This approval process ensures high quality wrapper implementations and safety for solvers, but means there's a roadblock for developers looking to extend CoW Protocol. Developers should plan for this approval process when building wrapper-based integrations. +Wrappers cannot be deployed and used immediately—they must be approved by CoW DAO through the allowlist authenticator. This approval process ensures high-quality wrapper implementations and safety for solvers, but means there's a roadblock for developers looking to extend CoW Protocol. Developers should plan for this approval process when building wrapper-based integrations. ### Execution Not Enforced by the on-chain Protocol diff --git a/docs/cow-protocol/integrate/wrappers.mdx b/docs/cow-protocol/integrate/wrappers.mdx index 4dc9cad1d..09cf10889 100644 --- a/docs/cow-protocol/integrate/wrappers.mdx +++ b/docs/cow-protocol/integrate/wrappers.mdx @@ -253,7 +253,7 @@ const tx = { to: wrappers[0].target, data: wrapperContract.interface.encodeFunctionData("wrappedSettle", [ settleData, // From step 2 - chainedWrapperData // From step 3 + wrapperData // From step 3 ]) } ``` @@ -317,7 +317,7 @@ const tx = encodeWrapperSettlement(solution); ### 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. +Account for wrapper gas overhead in your bids. The easiest way to do this is to simulate the wrapper transaction against an empty settlement. ## Common Issues diff --git a/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx b/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx index e6b5ee17c..8d0bdb490 100644 --- a/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx +++ b/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx @@ -333,9 +333,8 @@ Each wrapper in the chain consists of: - 20 bytes: address of next wrapper (omitted for the final wrapper) The final wrapper in the chain omits the next wrapper address and calls SETTLEMENT directly. -``` -Example: -``` +Example: +```text [0x0005][0xAABBCCDDEE][0x1234...ABCD][0x0003][0x112233] ↑len ↑data ↑next wrapper ↑len ↑data ``` @@ -487,7 +486,7 @@ function parseWrapperData( #### 1. Use CowWrapper Abstract Contract -It is strongly reccomended to **NOT** implement `ICowWrapper` directly. The `CowWrapper` abstract contract provides: +It is strongly recommended to **NOT** implement `ICowWrapper` directly. The `CowWrapper` abstract contract provides: - Solver authentication checks - Correct calldata parsing and decoding - Safe wrapper chain continuation @@ -681,7 +680,7 @@ Wrappers need protocol approval, and are not fully permissionless. ### Settlement Upgrades -When settlement contract upgrades, all wrappers must be redeployed. It is reccomended to use [Cannon](https://usecannon.com/learn) to make it easy to redeploy your wrappers. +When settlement contract upgrades, all wrappers must be redeployed. It is recommended to use [Cannon](https://usecannon.com/learn) to make it easy to redeploy your wrappers. ## Events From 2bc9013ea04e8fea363c817ed88208ecc2e12fd5 Mon Sep 17 00:00:00 2001 From: Kaze Date: Tue, 17 Feb 2026 12:49:04 +0900 Subject: [PATCH 11/11] other ai fixes misc --- .../concepts/order-types/wrappers.md | 4 +- docs/cow-protocol/integrate/wrappers.mdx | 56 +++++----- .../reference/contracts/periphery/wrapper.mdx | 100 +++++++++--------- 3 files changed, 81 insertions(+), 79 deletions(-) diff --git a/docs/cow-protocol/concepts/order-types/wrappers.md b/docs/cow-protocol/concepts/order-types/wrappers.md index e492d1fe2..7d6ebc7a8 100644 --- a/docs/cow-protocol/concepts/order-types/wrappers.md +++ b/docs/cow-protocol/concepts/order-types/wrappers.md @@ -65,9 +65,9 @@ For many use cases, this overhead is acceptable given the functionality unlocked Wrappers cannot be deployed and used immediately—they must be approved by CoW DAO through the allowlist authenticator. This approval process ensures high-quality wrapper implementations and safety for solvers, but means there's a roadblock for developers looking to extend CoW Protocol. Developers should plan for this approval process when building wrapper-based integrations. -### Execution Not Enforced by the on-chain Protocol +### On-Chain Protocol Does Not Enforce Execution -Despite official rules enforcing the execution of wrappers when required by the user, a solver could still not execute a wrapper with an order. This means wrappers must be designed defensively: +Despite official rules enforcing the execution of wrappers when required by the user, a solver may choose not to execute a wrapper with an order. This means wrappers must be designed defensively: - If a wrapper is strictly required, the order should fail to settle without it - Wrappers should validate all input data and fail in cases where a user's funds could be at risk diff --git a/docs/cow-protocol/integrate/wrappers.mdx b/docs/cow-protocol/integrate/wrappers.mdx index 09cf10889..7256dfa35 100644 --- a/docs/cow-protocol/integrate/wrappers.mdx +++ b/docs/cow-protocol/integrate/wrappers.mdx @@ -13,7 +13,7 @@ Generalized wrappers enable custom logic to execute surrounding CoW Protocol set This section covers building new wrapper contracts from scratch. -## Overview +### Overview To build a wrapper, you will: @@ -31,7 +31,7 @@ Read more on the details of creating a wrapper from [the wrapper contract inform This section shows you how to use existing wrappers in your orders and integrate wrapper support into your application. -## Adding Wrappers to Orders +### Adding Wrappers to Orders To use a wrapper in your order, add it to the `appData` when creating the order: @@ -98,9 +98,9 @@ appData: { } ``` -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. +The wrappers execute in sequence: Wrapper1 → Wrapper2 → Settlement → Wrapper2 (post) → Wrapper1 (post). Note that wrappers from other users' orders may be interspersed, though this should generally not affect the execution of the order. -## Validating Wrapper Configuration +### Validating Wrapper Configuration Before submitting an order, you can confirm the wrapper encoding is valid using `CowWrapperHelper`: @@ -126,7 +126,7 @@ This checks: This section explains how to execute settlements that include wrapper contracts as part of your solver implementation. -## Detecting Wrapper Orders +### Detecting Wrapper Orders Wrappers are specified in the order's [`appData`](../reference/core/auctions/schema.md) under the `wrappers` field: @@ -151,33 +151,33 @@ Wrappers are specified in the order's [`appData`](../reference/core/auctions/sch 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 +### Solver Requirements -### 1. Execute Non-Omittable Wrappers +#### 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 +#### 2. Verify Wrapper Authentication All approved wrappers will be approved by the DAO and registered in [`GPv2AllowlistAuthenticator`](../reference/contracts/core/allowlist.md). It is recommended to verify wrappers are allowlisted before including them in settlements. -### 3. Include Wrappers in the Solution +#### 3. Include Wrappers in the Solution -Whether using the CoW Protocol provided driver or your own, ensure wrapper information flows from the auction to your final settlement transaction. +Whether using the CoW Protocol-provided driver or your own, ensure wrapper information flows from the auction to your final settlement transaction. -## Encoding Wrapper Settlements +### Encoding Wrapper Settlements :::info If you're using the driver provided by CoW Protocol, you can skip this section - the driver handles encoding automatically. ::: -### Manual Encoding +#### Manual Encoding To execute a settlement with wrappers: -#### 1. Change Transaction Target +##### 1. Change Transaction Target Your transaction should call `wrappedSettle()` on the **first** wrapper (not the settlement contract): @@ -195,7 +195,7 @@ tx = { } ``` -#### 2. Construct settleData Parameter +##### 2. Construct settleData Parameter The `settleData` parameter is the **exact** calldata you would send to `GPv2Settlement.settle()`, including the 4-byte function selector: @@ -209,7 +209,7 @@ const settleData = settlementContract.interface.encodeFunctionData("settle", [ // This is your settleData - unchanged from normal settlement ``` -#### 3. Encode wrapperData Parameter +##### 3. Encode wrapperData Parameter The `wrapperData` combines individual wrapper data with wrapper addresses: @@ -246,7 +246,7 @@ For 3 wrappers: [length₁(2B)][data₁][address₂(20B)][length₂(2B)][data₂][address₃(20B)][length₃(2B)][data₃] ``` -#### 4. Call wrappedSettle +##### 4. Call wrappedSettle ```typescript const tx = { @@ -258,7 +258,7 @@ const tx = { } ``` -### Using CowWrapperHelper +#### Using CowWrapperHelper Alternatively, use the `CowWrapperHelper` contract for encoding and validation: @@ -278,13 +278,13 @@ In addition to producing the correct encoded data, the helper also validates: - All wrappers use the same settlement contract - Each wrapper can parse its data -## Accumulating Wrappers in Solutions +### Accumulating Wrappers in Solutions -### Using CoW-Provided Driver +#### Using CoW-Provided Driver -If you're using the CoW Protocol's provided driver, wrappers are handled automatically. Just ensure your solver process includes wrapper information in the solution output. +If you're using the CoW Protocol-provided driver, wrappers are handled automatically. Just ensure your solver process includes wrapper information in the solution output. -### Custom Implementation +#### Custom Implementation If implementing your own solver: @@ -313,21 +313,21 @@ for (const order of auction.orders) { const tx = encodeWrapperSettlement(solution); ``` -## Testing and Validation +### Testing and Validation -### Gas Estimation +#### Gas Estimation Account for wrapper gas overhead in your bids. The easiest way to do this is to simulate the wrapper transaction against an empty settlement. -## Common Issues +### Common Issues -### Issue: "Not authorized" error +#### 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 +#### Issue: Settlement reverts in wrapper **Cause**: Incorrect encoding or wrapper-specific validation failure @@ -336,9 +336,9 @@ Account for wrapper gas overhead in your bids. The easiest way to do this is to - Check `wrapperData` encoding follows specification exactly - Use `CowWrapperHelper` for validation -## Solver Resources +### Solver Resources -### Documentation +#### Documentation - **[Wrapper Concepts](../concepts/order-types/wrappers.md)** - High-level overview - **[Contracts Reference](../reference/contracts/periphery/wrapper.mdx)** - Contract specifications - **[Services PR #3700](https://github.com/cowprotocol/services/pull/3700)** - Reference encoding implementation in production diff --git a/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx b/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx index 8d0bdb490..b25b2f840 100644 --- a/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx +++ b/docs/cow-protocol/reference/contracts/periphery/wrapper.mdx @@ -275,27 +275,25 @@ import { CowWrapper } from "./CowWrapper.sol"; contract MyWrapper is CowWrapper { constructor(address settlement) CowWrapper(settlement) {} - function _wrap(bytes calldata wrapperData) internal override { + function _wrap(bytes calldata settleData, bytes calldata wrapperData, bytes calldata remainingWrapperData) internal override { // Your custom pre-settlement logic here // Example: pull tokens, initiate flash loan, etc. // Continue the wrapper chain (calls settlement or next wrapper) - _next(wrapperData); + _next(settleData, remainingWrapperData); // Your custom post-settlement logic here // Example: repay flash loan, stake tokens, etc. } - function parseWrapperData(bytes calldata wrapperData) + function validateWrapperData(bytes calldata wrapperData) external view override - returns (bytes memory) { - // Validate and parse wrapper-specific data + // Validate wrapper-specific data // This must be deterministic - same input always returns same output // Revert if data is invalid - return wrapperData; } } ``` @@ -312,12 +310,18 @@ function wrappedSettle( bytes calldata chainedWrapperData ) external override { // Verify caller is an authenticated solver - require( - GPv2Authentication(SETTLEMENT).isSolver(msg.sender), - "Not authorized" - ); + require(AUTHENTICATOR.isSolver(msg.sender), NotASolver(msg.sender)); + + // Find out how long the next wrapper data is supposed to be + uint256 nextWrapperDataLen = uint256(uint16(bytes2(chainedWrapperData[0:2]))); - _wrap(wrapperData); + // Delegate to the wrapper's custom logic + uint256 remainingWrapperDataStart = 2 + nextWrapperDataLen; + _wrap( + settleData, + chainedWrapperData[2:remainingWrapperDataStart], + chainedWrapperData[remainingWrapperDataStart:] + ); } ``` @@ -348,7 +352,7 @@ Each wrapper in the chain will successively pull off their own data and then cal Contains custom surrounding settlement logic. **Must** call `_next()` to continue the chain to the settlement contract. ```solidity -function _wrap(bytes calldata wrapperData) internal virtual; +function _wrap(bytes calldata settleData, bytes calldata wrapperData, bytes calldata remainingWrapperData) internal virtual; ``` **Implementation Requirements:** @@ -360,18 +364,15 @@ function _wrap(bytes calldata wrapperData) internal virtual; **Example:** ```solidity -function _wrap(bytes calldata wrapperData) internal override { - // 1. Parse data (first 2 bytes = length) - uint16 myDataLength = uint16(bytes2(wrapperData[:2])); - bytes calldata myData = wrapperData[2:2+myDataLength]; - - (address token, uint256 amount) = abi.decode(myData, (address, uint256)); +function _wrap(bytes calldata settleData, bytes calldata wrapperData, bytes calldata remainingWrapperData) internal override { + // 1. Parse data + (address token, uint256 amount) = abi.decode(wrapperData, (address, uint256)); // 2. Pre-settlement logic. Example, receive tokens from user IERC20(token).transferFrom(msg.sender, address(this), amount); // 3. Continue chain (REQUIRED) - _next(wrapperData[2+myDataLength:]); + _next(settleData, remainingWrapperData); // 4. Post-settlement logic. Example: stake tokens to a contract (for swap and stake) stakeTokens(token, amount); @@ -385,7 +386,7 @@ function _wrap(bytes calldata wrapperData) internal override { Continues the wrapper chain or calls settlement. Handles all parsing and routing automatically. ```solidity -function _next(bytes calldata remainingWrapperData) internal; +function _next(bytes calldata settleData, bytes calldata remainingWrapperData) internal; ``` **Behavior:** @@ -395,7 +396,7 @@ function _next(bytes calldata remainingWrapperData) internal; - Handles wrapper nesting automatically **Implementation Details:** -- Extracts next target address (last 20 bytes) +- Extracts next target address (first 20 bytes) - Separates settle data from remaining wrapper data - Calls next wrapper via `wrappedSettle()` or settlement via `settle()` @@ -406,11 +407,11 @@ Wrapper data uses an optimized encoding to minimize gas overhead: ### Structure ``` -┌─────────────────────┬──────┬──────────┬──────────┬──────┬──────────┬────────────┐ -│ Settle Calldata │ Len₁ │ Data₁ │ Addr₂ │ Len₂ │ Data₂ │ Settlement │ -│ (to settlement) │(2 B) │ (wrap1) │ (20 B) │(2 B) │ (wrap2) │ (20 B) │ -└─────────────────────┴──────┴──────────┴──────────┴──────┴──────────┴────────────┘ -│<─── settleData ───>│<────────────────── wrapperData ──────────────────────────>│ +┌─────────────────────┬──────┬──────────┬──────────┬──────┬──────────┐ +│ Settle Calldata │ Len₁ │ Data₁ │ Addr₂ │ Len₂ │ Data₂ │ +│ (to settlement) │(2 B) │ (wrap1) │ (20 B) │(2 B) │ (wrap2) │ +└─────────────────────┴──────┴──────────┴──────────┴──────┴──────────┘ +│<─── settleData ───>│<──────────── wrapperData ─────────────────────>│ ``` **Components:** @@ -420,7 +421,8 @@ Wrapper data uses an optimized encoding to minimize gas overhead: - **Addr₂**: 20-byte address of wrapper 2 - **Len₂**: 2-byte (uint16) length of wrapper 2's data - **Data₂**: Wrapper 2's custom data -- **Settlement**: 20-byte address of settlement contract (final target) + +Note: The settlement contract address is derived from the `SETTLEMENT` immutable and is not included in `wrapperData`. ### Data Consumption @@ -458,15 +460,15 @@ contract CowWrapperHelper { To aid external integrators in encoding and verifying wrapper data, an additional view-only contract is provided. - +See the [CowWrapperHelper contract source code](https://github.com/cowprotocol/euler-integration-contracts/blob/main/src/CowWrapperHelper.sol) for the complete implementation. -#### `parseWrapperData` +#### `validateWrapperData` Validates wrapper-specific data. Must be deterministic and revert on invalid input. ```solidity -function parseWrapperData( +function validateWrapperData( bytes calldata wrapperData ) external view override returns (bytes memory); ``` @@ -516,11 +518,11 @@ Settlement data can be modified by nested wrappers, and solvers can supply arbit #### 4. Deterministic Parsing Required -`parseWrapperData()` must always return same result for same input: +`validateWrapperData()` must always return same result for same input: ```solidity // ❌ NOT DETERMINISTIC -function parseWrapperData(bytes calldata wrapperData) +function validateWrapperData(bytes calldata wrapperData) external view override returns (bytes memory) { uint256 deadline = abi.decode(wrapperData, (uint256)); @@ -529,7 +531,7 @@ function parseWrapperData(bytes calldata wrapperData) } // ✅ DETERMINISTIC -function parseWrapperData(bytes calldata wrapperData) +function validateWrapperData(bytes calldata wrapperData) external view override returns (bytes memory) { uint256 deadline = abi.decode(wrapperData, (uint256)); @@ -598,20 +600,18 @@ Minimal wrapper demonstrating the pattern: contract EmptyWrapper is CowWrapper { constructor(address settlement) CowWrapper(settlement) {} - function _wrap(bytes calldata wrapperData) internal override { + function _wrap(bytes calldata settleData, bytes calldata wrapperData, bytes calldata remainingWrapperData) internal override { // No pre-settlement logic - _next(wrapperData); // Pass through + _next(settleData, remainingWrapperData); // Pass through // No post-settlement logic } - function parseWrapperData(bytes calldata wrapperData) + function validateWrapperData(bytes calldata wrapperData) external view override - returns (bytes memory) { // No validation needed - return wrapperData; } } ``` @@ -630,12 +630,15 @@ contract FlashLoanWrapper is CowWrapper { lendingPool = ILendingPool(_lendingPool); } - function _wrap(bytes calldata wrapperData) internal override { - (address asset, uint256 amount, bytes memory params) = - abi.decode(wrapperData, (address, uint256, bytes)); + function _wrap(bytes calldata settleData, bytes calldata wrapperData, bytes calldata remainingWrapperData) internal override { + (address asset, uint256 amount) = + abi.decode(wrapperData, (address, uint256)); + + // Store data for use in callback + // (In a real implementation, you would store settleData and remainingWrapperData) // Initiate flash loan (calls executeOperation) - lendingPool.flashLoan(address(this), asset, amount, params); + lendingPool.flashLoan(address(this), asset, amount, ""); } function executeOperation( @@ -648,26 +651,25 @@ contract FlashLoanWrapper is CowWrapper { require(msg.sender == address(lendingPool), "Unauthorized"); // Execute settlement with borrowed funds - _next(params); + // (In a real implementation, retrieve stored settleData and remainingWrapperData) + // _next(settleData, remainingWrapperData); // Approve repayment IERC20(asset).approve(address(lendingPool), amount + premium); return true; } - function parseWrapperData(bytes calldata wrapperData) + function validateWrapperData(bytes calldata wrapperData) external view override - returns (bytes memory) { - require(wrapperData.length >= 96, "Invalid data length"); - (address asset, uint256 amount,) = abi.decode( + require(wrapperData.length >= 64, "Invalid data length"); + (address asset, uint256 amount) = abi.decode( wrapperData, - (address, uint256, bytes) + (address, uint256) ); require(asset != address(0) && amount > 0, "Invalid parameters"); - return wrapperData; } } ```