OneEur.com
How it works

One chain per wallet.

Instead of one shared blockchain, every OneEur wallet has its own chain. A payment adds one block to the sender’s chain and one to the receiver’s. That is why it never waits in line.

A payment

Two blocks, two chains.

  1. 01

    Send

    A signs a send block on their own chain. Their balance goes down and the money is now pending for B.

  2. 02

    Confirm

    The primary chain holder checks the signature and balance and adds the block. It handles one block at a time, so if the same money is spent twice, only the first spend goes through.

  3. 03

    Receive

    B signs an open or receive block on their chain that points to A’s send. B’s balance goes up. No other chain changes.

Nobody else waits

A payment from A to B changes only A’s chain and B’s chain. Every other wallet’s chain stays as it is, so payments between other people never queue behind yours.

Receiving happens by itself

Until B adds the receive block, the money is pending for B. The OneEur app collects pending payments automatically, so for the person being paid it simply arrives.

Confirmation

One primary confirms, every holder keeps a copy.

The primary confirms

One chain holder, the primary, checks each new block and adds it. It handles one block at a time, so if two blocks try to spend the same money, the first one is added and the second is refused as a fork. The app gets its answer as soon as the primary has added the block, usually within a few milliseconds.

Copies go to every holder

Right after that, the block is copied to all other chain holders in the background, in order and in batches. Each holder has its own sender, so a slow or unreachable holder never slows payments down.

Holders that fall behind catch up

A holder that was offline compares its block hashes with the primary’s and fetches what it is missing in batches of 1,000. A copy that arrives before the block it builds on is kept aside until that block arrives.

If the primary is down

New payments are refused with primary_unavailable until it is back, so no money can be spent twice in the meantime. Balances and history can still be read from the other holders.

Fixed supply

Every coin was made once.

The genesis block

The first block of the genesis wallet creates the whole supply. No rule can create more coins after that. Every holder checks this at all times:

sum of balances + sum of pending sends == total supply

Amounts are whole numbers of units (1 OEUR = 100,000,000 units), so there is no rounding anywhere.

Block format

What a block holds.

Signatures
Ed25519
Hashes
SHA-256
Crypto library
Erlang/OTP :crypto (OpenSSL), no custom crypto
Private key
32-byte seed that never leaves your phone. The network only sees public keys and signatures.
Addresses
oe_ed25519_… with a built-in checksum
Units
1 OEUR = 100,000,000 units. Amounts are whole numbers, so there are no rounding errors.
Supply
Fixed. The first (genesis) block creates every coin once, and no rule can create more.
Memo
Up to 128 bytes, such as an invoice number. Signed by both sides and kept on both chains.
Storage
One append-only file per wallet on every holder. On restart, holders replay these files and check every signature again.
Block format
ONEEUR-BLOCK-V1
Example block
{
  "type": "send",
  "algorithm": "ed25519",
  "account": "oe_ed25519_…",
  "height": 2,
  "previous": "<64 hex>",
  "balance": "2099999000000000",
  "link": "oe_ed25519_…",
  "memo": "March rent",
  "hash": "<64 hex>",
  "signature": "<128 hex>"
}

Each block points to the one before it on the same chain. Amounts are sent as strings so that no app loses precision.

See every block live in the explorer
What gets hashed and signed
"ONEEUR-BLOCK-V1"   15 bytes   format name
type                 1 byte    1 = open, 2 = send, 3 = receive
account             key        algorithm (1) + length (2) + public key
height               8 bytes   position in the wallet’s chain
previous            32 bytes   hash of the previous block
balance             16 bytes   balance after this block
link                key / 32   send: receiver · open/receive: the send’s hash
memo length          1 byte    0–128
memo                 0–128     UTF-8 text

hash      = SHA-256(bytes above)
signature = Ed25519(wallet key, hash)
Rules

Why a block can be refused.

bad_signature
The signature does not match the block and the wallet’s key. Any changed field causes this.
bad_balance
The new balance does not add up, or a send is for more than the wallet has.
fork
Another block already follows the same previous block. This is what stops a double spend.
bad_previous, gap
The block does not point to the wallet’s latest block, or skips a height.
unknown_send
A receive points to a send that does not exist or is not for this wallet.
already_exists
The send was already received, or the block was already added.
memo_mismatch
A receive must repeat the sender’s memo exactly, so both chains hold the same signed memo.
self_send
A wallet cannot pay itself.
unsupported_algorithm
The block uses a signature algorithm that is not switched on.
Storage

How holders keep the chains.

One file per wallet

Each holder stores every wallet’s chain in its own append-only file, in height order. When a send to a wallet is accepted, an incoming note is added to the receiver’s file too, so each file shows on its own what is still pending.

A journal first

A block can change two files (the sender’s and the receiver’s), so it is first written to the holder’s journal and flushed to disk. From that moment the block counts. If the machine crashes halfway, the journal is replayed on start and the two files never disagree.

Checked again on every start

When a holder restarts, it replays every file through the full ledger rules, checking every signature again. It can confirm payments right away while that runs in the background.