use alloy_primitives::{Address, address};
use alloy_sol_types::sol;
pub const GPV2_SETTLEMENT: Address = address!("9008D19f58AAbD9eD0D60971565AA8510560ab41");
pub const GPV2_VAULT_RELAYER: Address = address!("C92E8bdf79f0507f65a392b0ab4667716BFE0110");
sol! {
#[derive(Debug)]
struct GPv2OrderData {
address sellToken;
address buyToken;
address receiver;
uint256 sellAmount;
uint256 buyAmount;
uint32 validTo;
bytes32 appData;
uint256 feeAmount;
bytes32 kind;
bool partiallyFillable;
bytes32 sellTokenBalance;
bytes32 buyTokenBalance;
}
#[derive(Debug)]
struct GPv2TradeData {
uint256 sellTokenIndex;
uint256 buyTokenIndex;
address receiver;
uint256 sellAmount;
uint256 buyAmount;
uint32 validTo;
bytes32 appData;
uint256 feeAmount;
uint256 flags;
uint256 executedAmount;
bytes signature;
}
#[derive(Debug)]
struct GPv2InteractionData {
address target;
uint256 value;
bytes callData;
}
#[derive(Debug)]
interface GPv2Settlement {
event Trade(
address indexed owner,
address sellToken,
address buyToken,
uint256 sellAmount,
uint256 buyAmount,
uint256 feeAmount,
bytes orderUid
);
event Interaction(address indexed target, uint256 value, bytes4 selector);
event Settlement(address indexed solver);
event OrderInvalidated(address indexed owner, bytes orderUid);
event PreSignature(address indexed owner, bytes orderUid, bool signed);
function settle(
address[] tokens,
uint256[] clearingPrices,
GPv2TradeData[] trades,
GPv2InteractionData[][3] interactions
) external;
function setPreSignature(bytes orderUid, bool signed) external;
function setPreSignatures(bytes[] orderUids, bool signed) external;
}
#[derive(Debug)]
interface ERC20 {
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function decimals() external view returns (uint8);
}
#[derive(Debug)]
interface WETH9 {
function deposit() external payable;
function withdraw(uint256 wad) external;
}
#[derive(Debug, Eq, PartialEq)]
enum OnchainSigningScheme {
Eip1271,
PreSign,
}
#[derive(Debug, Eq, PartialEq)]
struct OnchainSignature {
OnchainSigningScheme scheme;
bytes data;
}
#[derive(Debug)]
interface CoWSwapOnchainOrders {
event OrderPlacement(
address indexed sender,
GPv2OrderData order,
OnchainSignature signature,
bytes data
);
event OrderInvalidation(bytes orderUid);
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_primitives::{Bytes, keccak256};
use alloy_sol_types::{SolCall, SolEvent};
#[test]
fn set_pre_signature_selector_matches_keccak() {
let expected = &keccak256("setPreSignature(bytes,bool)")[..4];
assert_eq!(&GPv2Settlement::setPreSignatureCall::SELECTOR, expected);
}
#[test]
fn set_pre_signature_call_round_trips() {
let uid = Bytes::from(vec![0xab; 56]);
let call = GPv2Settlement::setPreSignatureCall {
orderUid: uid.clone(),
signed: true,
};
let encoded = call.abi_encode();
assert_eq!(
&encoded[..4],
&GPv2Settlement::setPreSignatureCall::SELECTOR
);
let decoded = GPv2Settlement::setPreSignatureCall::abi_decode(&encoded).unwrap();
assert_eq!(decoded.orderUid, uid);
assert!(decoded.signed);
}
#[test]
fn erc20_approve_selector_matches_keccak() {
let expected = &keccak256("approve(address,uint256)")[..4];
assert_eq!(&ERC20::approveCall::SELECTOR, expected);
assert_eq!(ERC20::approveCall::SELECTOR, [0x09, 0x5e, 0xa7, 0xb3]);
}
#[test]
fn weth9_deposit_selector_matches_keccak() {
let expected = &keccak256("deposit()")[..4];
assert_eq!(&WETH9::depositCall::SELECTOR, expected);
assert_eq!(WETH9::depositCall::SELECTOR, [0xd0, 0xe3, 0x0d, 0xb0]);
}
#[test]
fn set_pre_signatures_selector_matches_keccak() {
let expected = &keccak256("setPreSignatures(bytes[],bool)")[..4];
assert_eq!(&GPv2Settlement::setPreSignaturesCall::SELECTOR, expected);
}
#[test]
fn settle_selector_matches_keccak() {
let expected = &keccak256(
"settle(address[],uint256[],(uint256,uint256,address,uint256,uint256,uint32,bytes32,uint256,uint256,uint256,bytes)[],(address,uint256,bytes)[][3])",
)[..4];
assert_eq!(&GPv2Settlement::settleCall::SELECTOR, expected);
assert_eq!(
GPv2Settlement::settleCall::SELECTOR,
[0x13, 0xd7, 0x9a, 0x0b]
);
}
#[test]
fn settlement_event_topic_hashes_match_keccak() {
assert_eq!(
GPv2Settlement::Trade::SIGNATURE_HASH,
keccak256("Trade(address,address,address,uint256,uint256,uint256,bytes)")
);
assert_eq!(
GPv2Settlement::Interaction::SIGNATURE_HASH,
keccak256("Interaction(address,uint256,bytes4)")
);
assert_eq!(
GPv2Settlement::Settlement::SIGNATURE_HASH,
keccak256("Settlement(address)")
);
assert_eq!(
GPv2Settlement::OrderInvalidated::SIGNATURE_HASH,
keccak256("OrderInvalidated(address,bytes)")
);
assert_eq!(
GPv2Settlement::PreSignature::SIGNATURE_HASH,
keccak256("PreSignature(address,bytes,bool)")
);
}
#[test]
fn trade_event_data_round_trips() {
let event = GPv2Settlement::Trade {
owner: address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"),
sellToken: address!("A0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"),
buyToken: address!("6B175474E89094C44Da98b954EedeAC495271d0F"),
sellAmount: alloy_primitives::U256::from(1_000_000u64),
buyAmount: alloy_primitives::U256::from(999_000_000_000_000_000u128),
feeAmount: alloy_primitives::U256::from(123u64),
orderUid: Bytes::from(vec![0xab; 56]),
};
let data = event.encode_data();
let decoded = GPv2Settlement::Trade::abi_decode_data(&data).unwrap();
assert_eq!(decoded.0, event.sellToken);
assert_eq!(decoded.1, event.buyToken);
assert_eq!(decoded.2, event.sellAmount);
assert_eq!(decoded.3, event.buyAmount);
assert_eq!(decoded.4, event.feeAmount);
assert_eq!(decoded.5, event.orderUid);
}
#[test]
fn cowswap_onchain_orders_event_topic_hashes_match_keccak() {
assert_eq!(
CoWSwapOnchainOrders::OrderPlacement::SIGNATURE_HASH,
keccak256(
"OrderPlacement(address,(address,address,address,uint256,uint256,\
uint32,bytes32,uint256,bytes32,bool,bytes32,bytes32),(uint8,bytes),bytes)"
)
);
assert_eq!(
CoWSwapOnchainOrders::OrderInvalidation::SIGNATURE_HASH,
keccak256("OrderInvalidation(bytes)")
);
}
#[test]
fn deployment_addresses_match_canonical_hex_literals() {
assert_eq!(
GPV2_SETTLEMENT,
address!("9008D19f58AAbD9eD0D60971565AA8510560ab41")
);
assert_eq!(
GPV2_VAULT_RELAYER,
address!("C92E8bdf79f0507f65a392b0ab4667716BFE0110")
);
assert_ne!(GPV2_SETTLEMENT, GPV2_VAULT_RELAYER);
}
}