The trust model
A relaying service sits between you and the chain. The useful question is not whether we are trustworthy — it is what we would be able to do if we were not.
Four answers, each of which follows from the protocol rather than from our promises.
We cannot alter your transaction
Your signature covers every field: the receiver, the value, the data, the gas limit, the chain id and the relayer address. Change one byte and the signature is worthless and the network rejects it.
Our signature is a second, separate signature over exactly the same bytes. It authorises the fee payment and nothing else.
Check it yourself: the transaction on the explorer carries both signatures over the bytes you signed. Compare the fields with what your wallet showed you.
We cannot make it execute twice
The transaction occupies one (sender, nonce) slot. Once that nonce has executed, another
transaction carrying it is rejected by the network. Re-broadcasting identical bytes is the same
transaction, with the same hash.
Check it yourself: the nonce is in the signed bytes and visible on chain. (Delivery guarantees)
We cannot spend your funds
A relayer pays the network fee in EGLD. It has no authority over your balances. There is no approval step, no allowance and no custody — because relayed v3 has no mechanism that would create one.
The USDC you pay for a plan goes to the contract, not to a wallet of ours, and it is swapped and split in the same call. (Where the money goes)
We can delay, or decline
This is the real risk in the design, and pretending otherwise would be dishonest. A relayer can be slow to co-sign, or refuse.
What bounds it:
- the relayer is named to you before you sign, and you can verify its registry state on chain through a node that is not ours;
- a refusal happens before anything is co-signed, so nothing was sent and your signed payload is inert;
- the service tells you which case you are in through the
resignmember, rather than leaving you to guess. (One signature)
Pinning: the mistake worth avoiding
The CoRelayer owner and relayer wallets have the same addresses on devnet and on mainnet — one key per role, and a signed transaction's chain id is what keeps the networks apart. The contract address may coincide too.
So recognising an address tells you nothing about which network you are on.
The rule for every client:
- Pin the contract address and the chain id in your own configuration.
- Compare that chain id with the
chainIDof every transaction you are about to sign. - Where a discovery file disagrees with your pin, refuse — do not adopt the file's value.
The discovery files this project publishes are convenience copies. They are not authority. (Discovery)
What the service is built not to be able to do
| Return an error after sending | No error is returned after the relayer signature exists. Before it, nothing can execute; after it, the honest answer is a state, never a failure. |
| Ask you to sign twice for one action | Structurally enforced in the SDK; the only second signature is an explicit, explained re-sign after a failure that sent nothing. |
| Register a relayer with a warm key | Only the cold owner key can add a relayer address. The operator can only activate ones the owner already added. |
| Keep unused escrow locked | Turning pay-as-you-go off always returns unused escrow to your credits: through the closing settlement line, or — if the settlement key is dead or hostile — through releaseEscrow, which anyone may call seven days later and which no pause scope blocks. |
| Upgrade the contract while money is moving | An upgrade reverts unless all four money scopes are paused first. |
| Raise the price without notice | 48 hours for an increase, enforced by a compiled constant, not a setting. |
| Reach into what you already bought | A purchase freezes its terms. Nothing later touches them. |
Reproducible build and verified source
The plan, in the order that makes each step meaningful: build the contract reproducibly, so that anyone building the published source with the published toolchain gets the same bytes; publish the source for verification on the explorer; and deploy to mainnet only the hash that passed the devnet exit criteria — a check in the deploy procedure rather than something a reviewer has to remember.
The reproducible build and the explorer verification are open work. Each step is announced in the changelog when it is done. (The ABI and verification)
How the code is checked
| A written threat model | This page: the trust model, with its residual risks named rather than left out. |
| Invariants with tests | The delivery guarantees are numbered invariants — no signature before its record is durable, no co-signature without a verified lease, one transaction hash per slot, no error after the commit point — each with a test. (Delivery guarantees) |
| Structural refusals | The one-signature rule is enforced by the shape of the SDK, not by a convention. The signer pins its chain id. The contract refuses an upgrade unless every money scope is paused. |
| Golden vectors | The Relay Unit formula has a published set of twelve vectors that an independent implementation can reproduce; this site's own test suite recomputes them on every build. The contract and the backend each reproduce the settlement specification's worked example in their own tests. |
| Runnable, tested examples | Every code sample on this site is compiled against the API's generated types and run against a stand-in API that verifies its signatures. |
| Generated, not hand-written | API types, the API reference, the contract reference and the error catalogue are generated from their sources. A drift check fails the build. |
What you can verify without us
| The contract's behaviour | Read the ABI and call the views. They cost nothing. |
| The price | getPricingConfig, getTiers, getTariffHistory: the whole pricing model is three views. |
| That a relayer is legitimate | getRelayerState, through a node that is not ours. (Verify a relayer) |
| That the Relay Unit schedule is the committed one | Compare the document's hash against getRuSchedule. |
| That your transaction was not altered | Both signatures are over the same bytes, and the bytes are on chain. |
The residual risks, stated
A trust model that lists only the reassuring parts is not a trust model.
| Risk | Why it exists | What bounds it |
|---|---|---|
| A compromised signing host | Relayer keys have to be on a machine that can sign | Only the active relayer floats — our working capital, not customer funds. No plan, credit or user token is reachable. Every affected wallet is replaced from cold spares. |
| The owner key is a single key | No multisig, by decision | It is a cold, offline keystore, never on a server. Increases carry 48 hours of notice. Upgrades need everything paused, and emit an event. |
| A leaked sponsor key | Server-side keys exist so that services can pay for their users | A mandatory, non-empty receiver allow-list for the relay scope, plus per-day unit limits, an optional IP allow-list, and no key may mint or revoke keys. |
| A signed payload in a log | MCP hosts and model transcripts log tool arguments | A payload we never co-signed is inert. The tools never echo it back. The risk is not zero. |
Reporting something
security@co-relayer.com, or the policy at
Responsible disclosure. The same contact is published at
/.well-known/security.txt.