HartiiLabs docs

QuaiRelay

Contract reference

QuaiRelay

0x0031B09e63592B713768761cdDACC603974c10bD — Quai mainnet, Cyprus-1. solc 0.8.20, EVM target paris. 600-byte runtime, confirmed live via quai_getCode.

Purpose. Forward exactly msg.value to a caller-supplied recipient, in the same transaction, so a wallet that can call a contract but can't make a plain value transfer can still move its QUAI out. It holds nothing between calls.

Function

solidity
function sendTo(address payable to) external payable;

Forwards the attached QUAI to to. Reverts the whole transaction — nothing is sent, nothing is kept — if any of these hold:

ConditionRevert reason
msg.value == 0"Zero amount"
to == address(0)"Zero recipient"
to == address(this)"Recipient is the relay"
to is not a Cyprus-1 address (uint160(to) >> 152 != 0, i.e. first byte isn't 0x00)"Recipient not Cyprus-1"
the forwarded call to to fails (e.g. to is a contract with no payable fallback)"Payout failed"

There is deliberately no receive() function — a bare transfer sent directly to the relay address (not through sendTo) reverts rather than being accepted and stranded.

Event

solidity
event Relayed(address indexed from, address indexed to, uint256 amount);

Emitted once, after the forward succeeds. from is msg.sender (the caller, i.e. the wallet that signed the transaction), to and amount are exactly what was requested and paid.

Selector

sendTo(address) → 0xe6d25245 (keccak-256 of the signature, asserted against the deployed bytecode's dispatcher in the repo's tests — never hand-typed as trusted).

Trust model

There is nothing to trust beyond reading the ~30 lines of source, by construction:

  • No owner, no admin. There is no privileged address anywhere in the contract — no owner, no onlyOwner, no role that can change behavior.
  • No storage. The contract writes zero storage slots across its lifetime (asserted in test/QuaiRelay.test.cjs). It cannot accumulate state that a future call could read or act on.
  • No upgrade path, no selfdestruct. The deployed bytecode is final; it can never be swapped for different logic.
  • Never holds funds. The only payable path (sendTo) forwards the value before returning, and reverts the whole transaction if the forward fails. The absence of receive() means a stray direct transfer bounces instead of getting stuck in a contract with no withdraw function.
  • The recipient is chosen by the caller, in the same call it pays into. Nothing is remembered between transactions, and no other account's call can redirect a QUAI already in flight — each sendTo is self-contained.

What it cannot protect you from: naming the wrong recipient. That's true of any transfer, and the contract has no way to distinguish a typo from an intended payment — it only refuses recipients that are provably lossy (zero address, itself, another zone).

Quai Network mainnet · chain 9 · Cyprus-1. Figures marked "read on" a date were read from the chain that day; re-read before relying on them.