Relayers
Private operations in Orbinum — unshield and private_transfer — are submitted as unsigned Substrate extrinsics (ensure_none). There is no signing account, so there is no public address that can be correlated with the private operation.
The fee for including the transaction is not a standard gas payment. It is embedded directly inside the ZK proof as a public input, deducted from the user's note value. The block author — always an Aura validator — includes the unsigned extrinsic and receives the embedded fee, attributed automatically by pallet-shielded-pool.
This means every Aura validator is an implicit relayer. There is no separate relay process, no relay service URL, and no special node configuration required to handle private transactions.
What the relay model solves
unshield and private_transfer use ensure_none — there is no account to deduct gas from. The embedded fee in the ZK proof compensates the validator who authors the block.
If the user submitted from a public account, that account could be correlated with the private operation. Unsigned extrinsics avoid this entirely — the authorization is the ZK proof itself.
Validator registration
Every active validator is automatically an EVM relayer. The EVM H160 address is derived from the validator's Aura session key by the node at startup — the validator does not generate or manage a separate EVM key. Registration in pallet-relayer is performed by sudo or governance on the validator's behalf, not by the validator themselves.
The validator's consensus identity. Used by Aura for block authorship.
- Receives and accumulates fees in
PendingRelayerFees - Identified on-chain as the block author
- Used as the
whoargument when governance callsregister_relayer
Derived automatically from the Aura session key at node startup. Registered on-chain by governance.
- Receives tokens via
claim_relay_fees_to_evm - Linked to the AccountId via
register_relayer(who, evm_address) - Logged automatically by the node — the validator shares the log with the team
Both identities are linked on-chain via relayer.registerRelayer(who, evm_address), a call restricted to ManageOrigin (sudo or governance). This writes two indexes:
RelayerRegistry[H160] → AccountId— used to attribute fees when a relayed call is executedRelayerByAccount[AccountId] → H160— used to transfer claimed fees to the EVM account
register_relayer is a privileged call. It can only be submitted by sudo or the governance council — not by the validator account itself. Validators provide the logged EVM address to the Orbinum team, who submits the extrinsic on-chain.
Where the fee comes from
The relay fee is not a standard gas payment. It is a value committed inside the ZK proof itself:
// Unshield circuit constraint:
note_value === amount + fee
// Transfer circuit constraint:
input_sum === output_sum + fee
The circuit enforces that fee is deducted from the user's note. Changing the fee value after proof generation causes verification to fail. The fee is a public signal — visible to anyone — but immutable once proved.
After on-chain verification, pallet-shielded-pool identifies the current block author's AccountId and increments PendingRelayerFees[AccountId][asset_id]. The fee remains physically inside the shielded pool until the validator claims it.
System component overview
Key components
| Component | Location | Role |
|---|---|---|
pallet-relayer | frame/relayer/ | Registry, fee accounting, RelayerInterface |
pallet-shielded-pool | frame/shielded-pool/ | Executes the private op, attributes fee to block author |
pallet-zk-verifier | frame/zk-verifier/ | Verifies the Groth16 proof on-chain |
| ShieldedPool precompile | precompiles/shielded-pool/ | EVM path: bridges user-signed EVM tx into Substrate |
Section contents
End-to-end flow: from proof generation to on-chain execution and fee attribution.
How fees accumulate inside the pool and the two paths validators use to claim them.
How the EVM relay address is derived and registered for a validator, and how to claim accumulated fees.