Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cowprotocol/solver-rewards/llms.txt

Use this file to discover all available pages before exploring further.

Transfer is the core payment primitive in the solver rewards pipeline. Every reimbursement — whether in a network’s native token or in COW — is represented as a Transfer before being encoded into a Safe multisend transaction. Defined in src/models/transfer.py.

TokenType enum

TokenType lives in src/models/token.py and classifies whether a transfer sends the chain’s native asset or an ERC-20 token.
class TokenType(Enum):
    """Classifications of CSV Airdrop Transfer Types"""

    NATIVE = "native"
    ERC20  = "erc20"

    @classmethod
    def from_str(cls, type_str: str) -> TokenType:
        """Constructs Enum variant from string (case-insensitive)"""
        try:
            return cls[type_str.upper()]
        except KeyError as err:
            raise ValueError(f"No TokenType {type_str}!") from err

Token class

class Token:
    def __init__(self, address: str | Address, decimals: Optional[int] = None):
        ...
Token pairs an on-chain address with its decimal precision. When decimals is omitted the value is fetched via eth_call. Providing it explicitly avoids an RPC call and is preferred in unit tests.

Transfer class

@dataclass
class Transfer:
    """Total amount reimbursed for accounting period"""

    token: Optional[Token]
    _recipient: Address
    amount_wei: int

    def __init__(self, token: Optional[Token], recipient: Address, amount_wei: int):
        assert amount_wei > 0, f"Can't construct non-positive transfer of {amount_wei}"
        self.token = token
        self._recipient = recipient
        self.amount_wei = amount_wei

Constructor parameters

token
Optional[Token]
required
The ERC-20 token to transfer. Pass None for a native token transfer (ETH, xDAI, etc.). When None, token_type returns TokenType.NATIVE and amount is divided by 10¹⁸.
recipient
Address
required
The dune_client.types.Address of the solver wallet that will receive the payment.
amount_wei
int
required
Transfer amount in the smallest token unit (wei / atoms). Must be strictly positive — the constructor raises AssertionError if amount_wei <= 0.
Attempting to construct a zero or negative transfer raises AssertionError: Can't construct non-positive transfer of {amount_wei}.

Properties

recipient
Address
Read-only access to the _recipient field.
@property
def recipient(self) -> Address:
    return self._recipient
token_type
TokenType
Returns TokenType.NATIVE when token is None, otherwise TokenType.ERC20.
@property
def token_type(self) -> TokenType:
    if self.token is None:
        return TokenType.NATIVE
    return TokenType.ERC20
amount
float
Human-readable transfer amount in token units (not atoms).
  • Native transfers: amount_wei / 10¹⁸
  • ERC-20 transfers: amount_wei / 10^token.decimals
@property
def amount(self) -> float:
    if self.token_type == TokenType.NATIVE:
        return self.amount_wei / int(10**18)
    assert self.token is not None
    return self.amount_wei / int(10**self.token.decimals)

Methods

Transfer.summarize(transfers)

Class-level utility that prints a one-line summary of a list of transfers, totalling native and COW amounts separately.
@staticmethod
def summarize(transfers: list[Transfer]) -> str:
    eth_total = sum(
        t.amount_wei for t in transfers if t.token_type == TokenType.NATIVE
    )
    cow_total = sum(
        t.amount_wei for t in transfers if t.token_type == TokenType.ERC20
    )
    return (
        f"Total Native Token Funds needed: {eth_total / 10 ** 18:.4f}\n"
        f"Total COW Funds needed: {cow_total / 10 ** 18:.4f}\n"
    )
Example output:
Total Native Token Funds needed: 1.2345
Total COW Funds needed: 980.0000

as_multisend_tx()

Encodes the transfer as a MultiSendTx ready to be batched into a Safe multisend call.
def as_multisend_tx(self) -> MultiSendTx:
    receiver = Web3.to_checksum_address(self.recipient.address)
    if self.token_type == TokenType.NATIVE:
        return MultiSendTx(
            operation=MultiSendOperation.CALL,
            to=receiver,
            value=self.amount_wei,
            data=HexStr("0x"),
        )
    if self.token_type == TokenType.ERC20:
        assert self.token is not None
        return MultiSendTx(
            operation=MultiSendOperation.CALL,
            to=Web3.to_checksum_address(str(self.token.address)),
            value=0,
            data=ERC20_CONTRACT.encode_abi(
                abi_element_identifier="transfer",
                args=[receiver, self.amount_wei],
            ),
        )
Token typetovaluedata
NATIVERecipient addressamount_wei0x (empty)
ERC20Token contract address0ABI-encoded transfer(address,uint256)

CSVTransfer

CSVTransfer is the serialisation-friendly variant used when writing output CSV files for import into the Safe app.
@dataclass
class CSVTransfer:
    """Essentially a Transfer Object, but with amount as float instead of amount_wei"""

    token_type: TokenType
    token_address: Optional[Address]   # null address for native asset transfers
    receiver: Address
    amount: float                      # human-readable units, not atoms
Convert from a Transfer via the class method:
CSVTransfer.from_transfer(transfer: Transfer) -> CSVTransfer
The Safe Airdrop app expects native transfers to have a null / absent token_address. CSVTransfer.from_transfer() sets token_address=None when the source transfer has no token.

Build docs developers (and LLMs) love