# CoW Protocol on Solana
[CoW Protocol](https://cow.fi) is an open-source trading protocol that settles user intents in batch auctions. It supports direct matching between users (Coincidence of Wants) as well as on-chain liquidity sources.
This repository hosts the Solana implementation, currently in early development. The protocol is already live on Ethereum and other EVM chains; the Solidity contracts are at [cowprotocol/contracts](https://github.com/cowprotocol/contracts).
> [!CAUTION]
> These Solana programs are a work in progress and are **not ready for production use**. The code is unaudited, subject to change, and may contain significant vulnerabilities that could lead to loss of funds. Please do not rely on it with real assets. Any deployment to mainnet is for testing purposes only. We're sharing it openly to develop in the open and welcome your feedback.
## Design
The design of the program is documented in [DESIGN.md](./DESIGN.md).
It contains a high-level technical description of what the program does and points out meaningful differences from the [Ethereum implementation](https://github.com/cowprotocol/contracts).
The security design is documented in [SECURITY_DESIGN.md](./SECURITY_DESIGN.md).
It lays out the security properties the program aims to guarantee, the trust scope, the privileged roles, and what is explicitly not guaranteed.
## Development
Install the Solana toolchain (Rust, Solana CLI, and friends) by following the [Solana quick setup](https://solana.com/docs/intro/installation).
A Node.JS runtime is also necessary for generating client libraries from the IDL.
Common dev tasks are exposed via [`just`](https://just.systems/) recipes (see `Justfile`).
Most package managers provide this package, see [list of available Just packages](https://just.systems/man/en/packages.html).
Run `just --list` to see what's available.
## Repository layout
The repository is a Cargo workspace following the program / client / interface split:
- [`interface/`](./interface): shared types and the `Instruction` builders. Depends only on the lightweight crates so it can be consumed from both on-chain and off-chain code.
- [`programs/settlement/`](./programs/settlement): the on-chain settlement program.
- [`programs/settlement/idl/`](./programs/settlement/idl): the IDL of the settlement program and its generated associated client libraries.
- [`programs/settlement/idl/client/js/`](./programs/settlement/idl/client/js/): A Typescript client generated from the IDL
- [`client/`](./client): off-chain client helpers that re-export the builders from `interface` and add small convenience wrappers.
### How to build
Build the on-chain program (produces `target/deploy/cow_settlement.so`):
```sh
just build-program
```
Build everything except IDL client libraries (workspace crates plus the on-chain program):
```sh
just build
```
The IDL client libraries can be generated with:
```sh
just generate
```
### How to test
```sh
just test
```
The IDL client libraries can be tested with:
```sh
just test-idl-generated
```
### Benchmarks
`just bench` runs the test suite and regenerates `bench-report.json`:
```sh
just bench
```
## How to build a verified (reproducible) build
Requires [Docker](https://docs.docker.com/engine/install/).
The program bakes in the address it will be deployed at, chosen at build time, so pass the target deployment as `$ENV` (either `prod` for production or `barn` for staging):
```sh
just build-verified "$ENV"
```
Verified builds are only available for the committed `prod` and `barn` addresses, since one can't pass build flags to a verified build process.
## How to deploy
Requires [Docker](https://docs.docker.com/engine/install/) (for the verified build step).
You will need a **deployer keypair** — a Solana wallet funded with enough SOL to cover program storage rent and transaction fees. This wallet becomes the **upgrade authority** for the deployed program.
> Do not fund the program address itself. Only the deployer wallet needs SOL.
There are two environments, each pinned to its own fixed address: barn (staging, used for testing) and prod (production, the actual contract).
Deploy either with `just deploy "$ENV" …`, where `$ENV` is `barn` or `prod`.
The recipe refuses to run unless the keypair/address you pass resolves to that environment's committed address.
It covers both a first-time deploy and an upgrade, and finishes by running the `initialize` script (a no-op if the program is already initialized).
For a one-off build at an arbitrary address use [`just deploy-at`](#devnet--one-off-example).
In the case of a first deployment, the deployer must be `B6acm3swJK9pJ7fe4i4GQgP7x5A3RndvsdV2bKhcA1i5`, otherwise initialization fails.
### Initial deployment
The program only works at the specified hardcoded addresses (either `PROD_ID` or `BARN_ID` from the interface), which its pinned state PDA is derived from. `initialize` rejects a deployment anywhere else.
`initialize` also only accepts the hardcoded `INITIALIZER` (`cow_settlement_interface::instruction::initialize::INITIALIZER`) as its payer, so the deployer keypair must be that key.
Pass the program keypair file as the first argument. Solana derives the program address from it and registers the deployer as the upgrade authority:
```sh
just deploy "$ENV" "$PROGRAM_KEYFILE" "$DEPLOYER_KEYFILE"
```
### Upgrading an existing program
> [!IMPORTANT]
> Before upgrading, if the storage format has been changed for any existing PDAs, ensure that the MINOR (aka v0.x.0) version in the Cargo.toml is bumped. This will relocate all program storage, preventing unintended collisions with incompatible data.
Pass the program's public key (address) as the first argument. The deployer wallet must already be the upgrade authority:
```sh
just deploy "$ENV" "$PROGRAM_ID" "$DEPLOYER_KEYFILE"
```
### Verifying the deployment on-chain
Since we use verified builds, we can have our program marked as verified on various block explorers. This is only possible on mainnet, not on testnets.
To do so, run this once the program is deployed and the matching source is pushed to the public repository:
```sh
just verify "$ENV" "$PROGRAM_ID" "$DEPLOYER_KEYFILE" <optional-commit-hash>
```
- `$ENV`: the environment it was built for (`prod` or `barn`).
- `$PROGRAM_ID`: the program address.
- `$DEPLOYER_KEYFILE`: the upgrade authority keypair.
- `<optional-commit-hash>`: the commit that will be verified; current `HEAD` otherwise.
### Publishing the cargo packages
Authenticate your cargo cli with `cargo login`. Ensure you have permission to publish `cow-settlement-interface`, `cow-settlement-client`, and `cow-test-cli`.
Then, all packages can published in one go:
```sh
cargo publish
```
### One-off example
```sh
solana config set --url devnet
just deploy-at "$PROGRAM_KEYFILE" "$DEPLOYER_KEYFILE"
```
`$PROGRAM_KEYFILE` may be an address in the case of an upgrade.
## Alpha releases
There are two possible release flows while the project is in alpha:
- Program breaking change: the logic of the program changes meaningfully or there's some change on the layout of _any_ PDA.
- Patch update: it's mostly a hotfix for the program that doesn't meaningfully change the program state. The old client/interface should still work with the new program code.
You can use the settle CLI for a smoke test of the programs after a release. See `cargo run -p cow-test-cli -- sell --help` and `cargo run -p cow-test-cli -- settle --help`.
### Breaking change
- Create a new branch based off the `main` branch, pull the latest changes. Make sure there are no local changes (`git status --porcelain` is empty).
- Follow the instruction to [bump the versions in the project](#bump-the-versions-in-the-project) *by at least a minor version*.
- Generate new accounts (`for env in prod barn; do solana-keygen new --no-bip39-passphrase -o "../deploy-v$VERSION-$env.json"; done`). These will be the addresses of the new deployment.
- Store the newly generated accounts in 1password (under "Settlement account by version").
- Update the production address in `solana_pubkey::declare_id!` and `BARN_ID` in `interface/src/lib.rs` to the newly generated addresses (search and replace).
- Update the state PDA bytes in the IDL (use the test to see the bytes to change).
- Commit the code changes resulting from the steps above (excluding the key of the generated account).
- Switch your network to devnet (`solana config set --url devnet`).
- Deploy on `ENV=barn`.
- [Deploy the programs](#how-to-deploy): `PROGRAM_KEYFILE="../deploy-v$VERSION-$ENV.json"`. The deployer keypair is in 1password (under "Solana Deployer"). The program keypair file is the key that was generated before.
- Switch your network to mainnet (`solana config set --url mainnet-beta`).
- Authorize all [currently existing solvers](https://app.notion.com/p/cownation/Solvers-for-Solana-Dev-Contracts-3ca8da5f04ca80968642e85640178cbd) using the solver CLI (`cow solver add --keypair "$DEPLOYER_KEYFILE" --program-id "$ENV" <solver-address>`).
- Deploy on `ENV=prod` as before once confirming that barn is healthy.
- Make sure the package installs without errors: run `cargo install --path ./test-cli --locked` (it depends on all other packages).
- Create a PR with the changes and wait for approval.
- (Only for `ENV=prod`!) [Publish the IDL](#publishing-the-idl).
- Once the PR is merged to `main`, check out that commit and [verify the deployment on-chain](#verifying-the-deployment-on-chain) for both barn and prod.
- [Publish the cargo packages](#publishing-the-cargo-packages).
- Create a [new GitHub release](https://github.com/cowprotocol/solana-programs/releases/new); in doing so, create a new tag like `v0.42`; title "Alpha release, v0.42".
### Patch update
- Create a new branch based off the `main` branch. Make sure there are no local changes (`git status --porcelain` is empty).
- Follow the instruction to [bump the versions in the project](#bump-the-versions-in-the-project) by a patch version.
- Commit the code changes resulting from the changes above.
- Make sure the package installs without errors: run `cargo install --path ./test-cli --locked` (it depends on all other packages).
- Create a PR with the changes and wait for approval, then merge on `main`; check out main and pull the changes.
- [Upgrade](#how-to-deploy) `ENV=barn`.
- [Verify the deployment on-chain](#verifying-the-deployment-on-chain).
- Repeat the previous two steps with `ENV=prod`.
- Only for `prod`, [publish the IDL](#publishing-the-idl), if changed.
- [Publish the cargo packages](#publishing-the-cargo-packages).
- Create a [new GitHub release](https://github.com/cowprotocol/solana-programs/releases/new); in doing so, create a new tag like `v0.42.1337`; title "Alpha release, v0.42.1337".
### Bump the versions in the project
You need to update Cargo's toml and lock file.
Here is a list of commands to help bumping all relevant strings:
```sh
export VERSION=0.42.1337
# Rust workspace crate
perl -i -pe '
s/^version = ".*"/version = "$ENV{VERSION}"/;
s/(path = "[^"]*", version = )"[^"]*"/$1"$ENV{VERSION}"/;
' ./Cargo.toml
# IDL metadata
perl -i -pe 's/^(\s*)"version": "[^"]*"/$1"version": "$ENV{VERSION}"/' \
./programs/settlement/idl/cow_settlement.json \
./programs/settlement/idl/client/js/package.json
just build
```
### Publishing the IDL
Use the following command to publish the IDL.
Block explorers will then use the IDL to show decoded transactions to the user.
```sh
PROGRAM_ID="the IDL will be registered for the program at the address specified in this string"
npx @solana-program/program-metadata@v0.9.3 write idl "$PROGRAM_ID" ./programs/settlement/idl/cow_settlement.json --keypair "$DEPLOYER_KEYFILE"
```
The IDL is only available for the `prod` environment.
## License
[](./COPYING.MIT) [](./COPYING.APACHE) [](./COPYING.LESSER)
The core settlement program rust crate is licensed under the terms of the GNU Lesser General Public License v3.0.
All other crates are dual licensed under the terms of the MIT or Apache 2.0 license.
Copyright (c) 2026 CoW Foundation