QuaiRelay
QuaiRelay solves one narrow problem: some in-app wallets can call a contract but cannot make
a plain value transfer (on Quai this typically surfaces to the user as could not coalesce error). QUAI sitting in such a wallet is otherwise stuck. QuaiRelay turns a transfer into a
contract call — the wallet signs sendTo(recipient) with value attached, and the relay forwards
that exact value to recipient in the same transaction.
wallet ──sendTo(recipient) + value──▶ QuaiRelay ──same transaction──▶ recipientArchitecture
QuaiRelay is a contract, not a service. There is no backend, no database, no indexer and no owner/operator key. The two front ends that call it are:
- quai-relay — the standalone page.
index.html+app.js+relay-core.js, no build step, no dependencies, served statically (including from IPFS). Connects to the wallet's injected provider, reads balance/gas from the public Quai RPC, and submits one transaction. - /blipsend on HartiiLabs (hartii-labs, a separate product — see its own docs). A production page aimed at Blippay in-app-wallet users, offering the same plain-transfer-first / contract-fallback pattern, wired to the same relay contract. It is documented here only because it is QuaiRelay's main real-world caller — see How /blipsend uses the relay below.
Data flow for a relay send:
- The page reads the connected wallet's balance and the current gas price directly from
https://rpc.quai.network/cyprus1(quai_getBalance,quai_gasPrice). - It validates the destination client-side (Cyprus-1 prefix, checksum, not self, not the relay) and computes the maximum sendable amount (balance minus gas cost with 25% headroom).
- The wallet signs a transaction:
to= the relay contract,value= the amount,data= ABI-encodedsendTo(recipient). - The relay contract forwards
msg.valuetorecipientin the same transaction, or reverts the whole thing — there is no partial-failure state.
Live contract
| Network | Address |
|---|---|
| Quai mainnet, Cyprus-1 (chain 9) | 0x0031B09e63592B713768761cdDACC603974c10bD |
Verified live: quai_getCode against this address on https://rpc.quai.network/cyprus1 returns
600 bytes of deployed runtime bytecode (matches deployments.json's recorded runtimeBytes: 600
in the quai-relay repo). Deployed 2026-09-19, solc 0.8.20, EVM paris.
See contracts for the full interface and trust model, and integrate for runnable examples.
How /blipsend uses the relay
HartiiLabs' /blipsend page (hartii-labs/src/pages/BlipSend.jsx) offers two ways to move QUAI
out of a stuck wallet, both to the same address the visitor typed:
- Plain transfer — an ordinary
signer.sendTransaction({ to, value }). Works for any wallet that can send. - Contract route (QuaiRelay) — for wallets that can't:
contract.sendTo(destination, { value })against the relay address above, using the ABI insrc/abi/quaiRelay.js.
The page's own comment explains why it uses the general-purpose relay rather than a
fixed-destination forwarder contract (hartii-labs also has one, QuaiForwarder, used for a single
private payee elsewhere on the site):
In other words: sendTo's lack of a fixed destination isn't a limitation, it's the reason this
contract is safe to expose on a public page at all.