Skip to main content

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 resign member, rather than leaving you to guess. (One signature)

Pinning: the mistake worth avoiding​

An address is not a network identifier

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:

  1. Pin the contract address and the chain id in your own configuration.
  2. Compare that chain id with the chainID of every transaction you are about to sign.
  3. 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 sendingNo 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 actionStructurally 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 keyOnly the cold owner key can add a relayer address. The operator can only activate ones the owner already added.
Keep unused escrow lockedTurning 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 movingAn upgrade reverts unless all four money scopes are paused first.
Raise the price without notice48 hours for an increase, enforced by a compiled constant, not a setting.
Reach into what you already boughtA 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 modelThis page: the trust model, with its residual risks named rather than left out.
Invariants with testsThe 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 refusalsThe 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 vectorsThe 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 examplesEvery 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-writtenAPI 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 behaviourRead the ABI and call the views. They cost nothing.
The pricegetPricingConfig, getTiers, getTariffHistory: the whole pricing model is three views.
That a relayer is legitimategetRelayerState, through a node that is not ours. (Verify a relayer)
That the Relay Unit schedule is the committed oneCompare the document's hash against getRuSchedule.
That your transaction was not alteredBoth 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.

RiskWhy it existsWhat bounds it
A compromised signing hostRelayer keys have to be on a machine that can signOnly 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 keyNo multisig, by decisionIt 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 keyServer-side keys exist so that services can pay for their usersA 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 logMCP hosts and model transcripts log tool argumentsA 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.