Swaps
The Zodiac Roles SDK provides built-in support for token swaps through COW Protocol , enabling efficient trading secured by tightly scoped role permissions.
Swaps incur a small fee of 0.25% of the swap value, in addition to the network fee. This fee is automatically collected by COW Protocol only for successful swaps.
Zodiac OS Enterprise customers can reach out for custom pricing.
Overview
The SDK offers a dedicated entrypoint zodiac-roles-sdk/swaps
allowing you to:
- Generate permissions for token swaps
- Get quotes from swaps from the COW API
- Sign orders using your role permissions
- Post signed orders to COW API
Example
Configure permissions
Before your role can execute swaps, you need to configure the appropriate permissions. The SDK provides allowCowOrderSigning
to generate the necessary permissions for COW swaps:
import {
allowCowOrderSigning,
processPermissions,
applyTargets,
} from "zodiac-roles-sdk/swaps";
// Define the tokens your role should be able to swap
const permissions = allowCowOrderSigning({
sell: [
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
"0xA0b86a33E6441b8dB4B2b6b0b0b6B0b0b0b0b0b0", // USDC
],
buy: [
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
"0xA0b86a33E6441b8dB4B2b6b0b0b6B0b0b0b0b0b0", // USDC
"0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB", // COW
],
// Optional: specify custom receiver (defaults to avatar address)
// receiver: "0x...",
});
Permission Parameters
sell
: Array of token addresses that the role can sellbuy
: Array of token addresses that the role can buyreceiver
(optional): Address that can receive the bought tokens. Defaults to the avatar address of the Roles Modifier
What Permissions Are Created
The allowCowOrderSigning
function creates permissions for:
- ERC20 Approvals: Allows approving the specified sell tokens to the COW Protocol Vault Relayer (
0xC92E8bdf79f0507f65a392b0ab4667716BFE0110
) - Order Signing: Allows calling
signOrder
on the COW Order Signer contract (0x23dA9AdE38E4477b23770DeD512fD37b12381FAB
) with the specified token constraints - Order Unsigning: Allows calling
unsignOrder
to cancel orders if needed
Apply Permissions to Your Roles Modifier
Once you have the permissions, apply them to a role in your Roles Modifier:
import {
planExtendRole,
processPermissions,
encodeKey,
} from "zodiac-roles-sdk";
// Convert permissions to targets
const { targets } = processPermissions(permissions);
// Plan the role extension (this fetches current state and calculates the diff)
// `planExtendRole` is strictly additive, for replacing permissions that have been applied earlier, use `planApplyRole`.
const calls = await planExtendRole(
{
key: encodeKey("trader-role"),
targets, // The swap permissions
},
{
chainId: 1, // Ethereum mainnet
address: "0x27d8bb2e33Bc38A9CE93fdD90C80677b8436aFfb", // Your Roles Modifier address
log: true, // Optional: log the planned changes
}
);
// Execute the calls (requires owner permissions on the Roles Modifier)
for (const call of calls) {
await signer.sendTransaction(call);
}
Once permissions are applied, you can make swaps using your role.
Make a swap using your role
Use getCowQuote
to get a price quote for a token swap:
import { getCowQuote, SupportedChainId } from "zodiac-roles-sdk/swaps";
const quote = await getCowQuote({
// Order type and side
kind: "sell",
// Token addresses
sellToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
buyToken: "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB", // COW
// Amount to sell (1 ETH in wei)
sellAmountBeforeFee: BigInt("1000000000000000000"),
// Order validity (30 minutes from now)
validTo: Math.floor(Date.now() / 1000) + 30 * 60,
// Network and Roles Modifier configuration
chainId: SupportedChainId.MAINNET,
rolesModifier: "0x27d8bb2e33Bc38A9CE93fdD90C80677b8436aFfb",
roleKey: "trader-role",
});
console.log("Quote:", quote);
// {
// sellToken: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
// buyToken: "0xDEf1CA1fb7FBcDC777520aa7f396b4E015F497aB",
// sellAmount: "1000000000000000000",
// buyAmount: "4000000000000000000",
// // ... other quote fields
// }
Quote Request Parameters
Required Parameters
kind
: Order type -"sell"
or"buy"
sellToken
: Address of the token to sellbuyToken
: Address of the token to buychainId
: Network chain ID (seeSupportedChainId
enum)rolesModifier
: Address of your Roles Modifier instanceroleKey
: Identifier for the role making the swap
Amount Parameters
For sell orders, provide:
sellAmountBeforeFee
: Amount to sell (before fees) asbigint
For buy orders, provide:
buyAmountAfterFee
: Desired amount to buy (after fees) asbigint
Optional Parameters
receiver
: Recipient address (defaults to the avatar address of the Roles Modifier)validTo
: Order expiration timestamp (defaults to 30 minutes from now)partiallyFillable
: Allow partial fills (defaults tofalse
)sellTokenBalance
: Token balance source ("erc20"
,"external"
,"internal"
)buyTokenBalance
: Token balance destination ("erc20"
,"internal"
)priceQuality
: Quote quality ("fast"
,"optimal"
)
Signing the Order
After getting a quote, you need to sign the order. The SDK provides signCowOrder
to generate the transaction that will mark the order as signed through your role:
import { signCowOrder } from "zodiac-roles-sdk/swaps";
// Generate the signing transaction
const signingTx = signCowOrder(quote);
// Execute the signing transaction using the role member wallet
await roleSigner.sendTransaction(signingTx);
The Signing Transaction
The signCowOrder
function returns a transaction object with:
{
to: "0x27d8bb2e33Bc38A9CE93fdD90C80677b8436aFfb", // Your Roles Modifier address
data: "0x...", // Encoded call to sign the order
value: 0,
chainId: 1, // The network chain ID
}
Role Signer Requirements
The signer executing the transaction must:
- Be a member of the role that has swap permissions
- Have sufficient ETH for gas fees
- Be connected to the correct network
The signing process uses the COW Protocol’s presign mechanism, which means the order is marked as “signed” on-chain without requiring an actual cryptographic signature from the avatar.
Posting the Order
In addition to marking the order as signed, you need to post it to the COW API to be executed:
import { postCowOrder } from "zodiac-roles-sdk/swaps";
// Assume you have a signed quote
const orderId = await postCowOrder(quote);
console.log("Order posted with ID:", orderId);
// "0x1234567890abcdef..."