Send Enygma Transactions

Enygma Payments is the privacy-preserving payment flow built into the Rayls ecosystem. It lets institutions transfer shielded ERC-20 tokens between their Rayls Sovereign ledgers with full privacy, using Pedersen commitments, zk-SNARKs and post-quantum encryption to deliver:

  • Confidentiality: Sender, recipient, and amount are hidden from public view.
  • Anonymity: Each transfer is batched with others into an anonymity set, so an observer cannot tell which participant initiated which transfer. The supported set sizes are two and six.
  • Auditability: The network's designated Private Network Auditor, typically a financial regulator, can decrypt and view full transaction data under Auditor View.
  • Compliance: Auditability is preserved without giving up privacy.

Enygma suits financial institutions that need private token transfers, such as CBDC distribution, confidential settlement, or internal ledgering.

Before working through the examples, it is worth being clear about which chain holds what, because the balances shown below are only one half of the picture. The Enygma contracts are deployed as a package on the Private Network Hub, or on the Rayls Public Chain where the transfer settles there. The Hub-side contract holds the canonical state: the balance commitments for every participating institution, the total supply, and the nullifiers that prevent a transfer being replayed. It verifies the zero-knowledge proof for each batch and it is the point at which a transfer becomes final.

What lives in an institution's own Rayls Sovereign ledger is the handler contract and a wrapped token balance that Enygma keeps synchronised one for one with the Hub-side commitment. That wrapped balance is what a user sees and what the examples below show moving. The atomicity of a multi-recipient transfer is enforced on the Hub, not in any institution's ledger.

How to Use

  1. Single Transfer – A → B

Scenario:
Alice (in ledger A) sends 10 private tokens to Bob (in ledger B).

await tokenOnPLA.crossTransfer(
  [signerB.address], [10], [chainIdB], [[]]
);

Outcome:

  • Alice's wrapped token balance decreases, for example from 1000 to 990.
  • Bob receives 10 tokens in ledger B.
  1. Multi-Recipient Transfer – A → B, C, D, E, F

Scenario:

Alice (in ledger A) sends 5 private tokens each to:

  • Bob (ledger B)
  • Carol (ledger C)
  • Dan (ledger D)
  • Emma (ledger E)
  • Frank (ledger F)
await tokenOnPLA.crossTransfer(
  [signerB.address, signerC.address, signerD.address, signerE.address, signerF.address],
  [5, 5, 5, 5, 5],
  [chainIdB, chainIdC, chainIdD, chainIdE, chainIdF],
  [[], [], [], [], []]
);

Outcome:

  • A total of 25 tokens are burned from Alice's balance (1000 → 975).
  • Each recipient receives 5 Enygma tokens in their own ledger.
  • A Reference ID is emitted to track the grouped operation.
  • All five destination Sovereign ledgers:
    • Deploy the correct wrapped token contract.
    • Mint tokens to the specified recipient.
  • The process is atomic, so either all recipients receive the tokens or none do. Atomicity is enforced by the Enygma contract on the Private Network Hub, which verifies the proof for the whole batch before any destination mints.
  • Five is the ceiling. A single crossTransfer can address at most five unique destination chains, and can carry at most five callable actions.
  1. Multi-Sender → Bidirectional Transfer in Same Block – A → B–F and B → A–F

Scenario:
In a single block:

  • Alice (ledger A) sends tokens to Bob, Carol, Dan, Emma, and Frank (ledgers B to F).
  • Bob (ledger B) sends tokens to Alice and the same group (C to F) in return.

This simulates multi-party net settlement, which is what financial clearing and real-time bilateral agreements require.

const txAtoB = await tokenOnPLA.crossTransfer(
  [signerB.address, signerC.address, signerD.address, signerE.address, signerF.address],
  [100, 2, 2, 2, 2],
  [chainIdB, chainIdC, chainIdD, chainIdE, chainIdF],
  [[], [], [], [], []]
);

const txBtoA = await tokenOnPLB.crossTransfer(
  [signerA.address, signerC.address, signerD.address, signerE.address, signerF.address],
  [1, 1, 1, 1, 1],
  [chainIdA, chainIdC, chainIdD, chainIdE, chainIdF],
  [[], [], [], [], []]
);

await txAtoB.wait();
await txBtoA.wait();

Outcome:

  • Total movement from ledger A:
    108 tokens (100 to B plus 2 × 4 to C–F) burned.
  • Total movement from ledger B:
    5 tokens (1 each to A and C–F) burned.
  • Final net balances:
    • Alice (ledger A):
      975 - 108 + 1 = 868
    • Bob (ledger B):
      5 (previous) + 100 (from A) - 5 (sent) = 100
  • All balances across C–F increment accordingly, by +1 from Bob and +2 from Alice, a net +3.
  • The whole operation is atomic, secured with Enygma commitments, and finalised against the same Private Network Hub block state. Finalisation is not instant: batching, proof generation and Hub verification together take on the order of tens of seconds, so plan for that rather than for the sub-second finality of an internal transaction.

Did this page help you?