Skip to content

Docs / Alma Bond

How a bond works, and where its limits are.

Everything on this page describes what is implemented in this release. Where something is not implemented, it says so.

Overview

AlmaChain is an application. It runs on an existing network, the one this build is configured for, and is not a blockchain of its own. Its one product is Alma Bond.

A bond is a deposit held by a contract for its owner: one ERC-20 token, one amount, one owner address. The word means an asset-backed position in this application. It does not mean debt, it pays no interest or yield, and it promises no return. The contract gives back exactly what was deposited, once.

This release implements one mode, public escrow with receipt-gated redemption. Public, because the depositor, the token, the amount, the current owner and every transfer are on chain for anyone to read. Receipt-gated, because moving or redeeming a bond takes two things together: a transaction from the owner address, and the secret of the bond's receipt, which exists only on the owner's device until it is used.

The contract is AlmaBondEscrow. It is covered by tests and has not been audited.

The project's only official account is @almachainhood on X. Announcements about deployments are made there and on this site, and a contract address is only real when this page shows it under Deployments.

Operation

Create

  1. Connect the wallet that will own the bond and choose a token from the escrow's allowlist and an amount.
  2. The browser makes the receipt: 32 random bytes from its secure generator, bound to your address, the contract and the network.
  3. You download the receipt file and confirm that it is saved. The deposit cannot be requested before that.
  4. You approve exactly the amount for the escrow, not more, and then send the deposit.
  5. The bond exists when the network confirms the deposit. The app says so only then.

Hold

The portfolio lists the bonds your address owns and the transfers waiting for it, read from the contract at a block that the page names. For each bond it says whether its receipt is on this device. A bond without its receipt can be looked at, and its ownership can be proven, but it cannot be moved or redeemed until the receipt file is imported.

Transfer, rotate, redeem

Each of these opens a review that states the account, the network, the asset and amount, the exact contract call and the network fee, and then asks your wallet. They are described under Transfers and Receipts. Redeeming pays the whole amount to an address you name and closes the bond for good.

What a transaction can say

StateMeaning
CheckingThe request is being checked against the contract. Nothing has been signed.
Waiting for your walletThe wallet is asking you to confirm or cancel.
SubmittedThe wallet returned a transaction hash. The network has not included it yet. The step is not offered again.
ConfirmedIncluded and successful. Only now does the app report the result.
CancelledYou cancelled in the wallet. Nothing was sent.
Not sentThe checks refused the request, or the wallet or network failed before a hash existed. Nothing was sent.
RevertedIncluded, and the contract reverted it. Nothing moved.
Sent, confirmation not readA hash exists but its confirmation could not be read. It may be included: check the hash before sending anything again.

A reload does not lose a submitted transaction: its hash is recorded in the browser the moment the wallet returns it, and the app keeps watching it. The contract is the source of truth throughout. There is no indexer between it and the page; the event history on a bond's page is a convenience, and the state never depends on it.

Receipts

A receipt is a small JSON file. It holds the secret of a bond's active commitment and what is needed to recognise the bond: network, escrow contract, protocol version and the owner address it is bound to.

The commitment

commitment = keccak256(abi.encode(
  RECEIPT_TYPEHASH,   // keccak256("AlmaBondReceipt(uint256 chainId,address escrow,
                      //            uint16 protocolVersion,address owner,bytes32 secret)")
  chainId,            // uint256
  escrow,             // address of the escrow contract
  protocolVersion,    // uint16, 1 in this release
  owner,              // address the receipt is bound to
  secret              // bytes32
))

Six static values, 192 bytes, so the encoding has one reading. The network, the contract and the protocol version are inside the hash: a receipt made for one deployment says nothing on another. The app computes the hash on your device; the secret is not sent anywhere to be hashed.

What a receipt does and does not authorise

  • A receipt alone authorises nothing. The contract accepts a secret only in a transaction sent by the bond's owner.
  • The owner address alone moves nothing. Redeeming, transferring and rotating all need the active secret. Without the receipt, the owner can only withdraw an open transfer proposal and sign ownership attestations.

Draft and funded

A receipt starts as a draft: made on a device, with no confirmed transaction behind it. It becomes funded when a confirmed transaction installs its commitment for a bond. The file is a snapshot; whether a receipt controls a bond right now is always read from the contract. Because the contract records which bond each commitment was installed for, a draft backup made before the deposit is enough to find and control the bond afterwards.

If a deposit never confirms, the draft stays a draft. You can try again with it. One receipt cannot fund two bonds: the contract refuses a commitment that the same address has already used.

Backups

  • The file. Plain JSON, or protected with a passphrase: AES-256-GCM with a key derived by PBKDF2-HMAC-SHA-256 (600,000 rounds, random salt), done in your browser. The passphrase is not stored. A forgotten passphrase cannot be recovered.
  • The browser. A copy is held in this browser so that a reload does not lose it. It is stored in IndexedDB, encrypted with a key the browser generates and will not export. That keeps it out of the browser's storage files in readable form. It does not protect against malicious software on your device, and clearing the browser removes it. It is a convenience, not a backup.

The app never uploads a receipt, never writes one to localStorage and never puts a secret in a URL.

If you lose it

The bond cannot be redeemed or transferred, by you or by anyone. There is no recovery path and no administrator override. The deposit stays in the contract. This is the cost of the second factor, which is why the app does not request a deposit before the backup is confirmed.

If someone else sees it

They still cannot take the bond, because every action also needs a transaction from your address. The receipt is no longer a second factor, though. Rotate it from the bond's page: the bond gets a new receipt and the exposed one stops working in the same transaction.

When the secret becomes public

Using a secret puts it in a transaction's calldata, which is public. That happens when you redeem, when you propose a transfer and when you rotate. In each case the secret is spent by that same transaction: the bond is closed, or a new commitment takes the old one's place. After any successful call, no bond depends on a secret that has been published. If a transaction that carried the secret is included but reverts, the secret is public while the bond still uses it; the app says so and offers rotation.

For the same reason the app does not simulate or estimate these three calls through an RPC server: a simulation would hand the secret to that server before you have signed anything. It checks the same conditions on your device instead, shows a typical fee, and lets the wallet send the transaction. The app's own read relay refuses such calls outright.

Transfers

A bond changes hands in two steps, and the recipient has to take the second one.

  1. The owner proposes a recipient. This spends the owner's current receipt and installs a replacement receipt of the owner's in the same transaction.
  2. The recipient accepts from their own wallet with a commitment made on their own device. Ownership and the active commitment change together. The previous owner and every earlier receipt lose all authority.

Sending someone a receipt file is not a transfer and is not safe to treat as one: the file is useless without the owner address, and the sender would still own the bond.

SituationRedeemRotateProposeWithdraw proposalAccept
No proposal openOwner, with the receiptOwner, with the receiptOwner, with the receiptNothing to withdrawNothing to accept
Proposal openRefusedRefusedRefused: one at a timeOwner (cancel) or recipient (decline)Recipient only, naming the proposal it reviewed
RedeemedRefused: finalRefusedRefusedRefusedRefused
  • Cancelled or declined: the owner keeps the bond. Its receipt is the replacement receipt saved when proposing; the receipt used to propose is spent.
  • Stale acceptance: every proposal of a bond has a number. An acceptance names the number it reviewed. If the proposal was withdrawn and made again, the number is different and the old acceptance fails.
  • Duplicate acceptance: the second one finds no open proposal and fails.
  • The recipient is bound to nothing until they accept. A proposal does not move the deposit and cannot be redeemed against.

Ownership Attestation

An attestation answers one question for one verifier: does this address own this bond? It is a signature. It is not a zero-knowledge proof and it hides nothing: the signing address is part of it, and the bond it names is public.

  1. The verifier issues a challenge: bond number, chain id, escrow contract address, audience (who is asking), a random nonce, and an expiry of at most 24 hours.
  2. The owner signs it as EIP-712 typed data whose domain is the escrow contract on that chain. The message states that it proves ownership only and authorises no transaction. Signing costs nothing and does not involve the receipt.
  3. The verifier checks it, all at one block: the network and contract are the ones it trusts; the attestation answers exactly the challenge it issued (same bond, audience, nonce and validity); the challenge has not expired by the chain's clock; the signature is the claimed address's (contract accounts are asked through ERC-1271); and the contract names that address as the bond's owner.

A passed check says who owned the bond at the checked block, and the result names that block. A transfer or a redemption in any later block makes it stale. A verifier that needs it to stay true has to check again.

The Verify page does all three steps. The check runs in the verifier's browser against the chain and needs no wallet.

Privacy model

The honest summary: this mode is not private. A hash on chain does not hide a deposit, an amount, an address or a transaction history. What the receipt adds is a second factor for moving the bond, not secrecy about the bond.

Public on chainStays on your deviceBecomes visible when you redeem
Token and amountPublic from the moment the bond is created.Nothing to keep.Already public. The payout is a public token transfer.
Owner addressPublic. The address that deposited, and every address the bond is transferred to.Nothing to keep.Already public. The redeeming address is the owner.
TransfersEvery proposal, cancellation and acceptance is a public transaction with both addresses in it.Nothing to keep.Already public.
Receipt commitmentPublic. A hash; it hides the secret and nothing else about the bond.Also written in the receipt file.Already public.
Receipt secretNot on chain while the bond is held.In the receipt file you download and, encrypted, in this browser. Never sent to a server by this app.Published in the redemption transaction, and spent by it. Transferring or rotating publishes it the same way.
Payout addressNot known before redemption.You choose it when you redeem.Public, as part of the transaction you sign.
Ownership attestationNot on chain. It is a signed message.You hold it and decide who receives it. It shows your address and the bond number, which are public anyway.A redeemed bond has no owner, so an attestation for it no longer verifies.

What an observer learns

  • Which address deposited which token and how much, and when.
  • Every address the bond was proposed to, who accepted, who declined, and when.
  • Who redeemed, to which payout address, and the receipt secret that was used.
  • That the same address created or held other bonds: nothing unlinks them.

Who else sees something

  • RPC providers see your IP address and what you read. On public networks the app reads through its own relay, so the upstream provider sees the app's server rather than you, and the relay's operator sees your reads. Your wallet uses its own RPC to send transactions.
  • The explorer sees what you open on it.
  • A verifier you send an attestation to learns that your address owns the bond, which the chain shows anyway.

Private bonds

Not available. Hiding amounts or owners would take a complete, reviewed protocol: commitments, membership proofs, nullifiers that prevent double spending, a proof system with a correct verifier, proofs bound to asset, value, recipient, chain and contract, conservation of assets, and a documented model of what metadata still leaks. None of that is implemented here. Nothing in this app is a placeholder for it, and the app does not call itself private because a receipt or a hash is involved.

Deployments

This build

Value
NetworkRobinhood Chain · chain id 4663
Environmentproduction
Escrow contract0xb13852329E1192Fcd5aE9C6511F3C02ED5375C12
Deployed atblock 80669707
Administrator0xbcd17865408836709e06b6A538DeDa61cC685361
Auditnone

Networks the app can be built for

NetworkChain idPublic RPCExplorer
Local development chain31337http://127.0.0.1:9301none
Robinhood Chain Testnet46630https://rpc.testnet.chain.robinhood.comexplorer.testnet.chain.robinhood.com
Robinhood Chain4663https://rpc.mainnet.chain.robinhood.comrobinhoodchain.blockscout.com

The Robinhood Chain values were checked against the official documentation and the live endpoints on 2026-10-05. Robinhood Chain is an Arbitrum Nitro chain; its documentation describes the public RPC endpoints as rate limited and recommends a provider endpoint for production, which the server reads from RPC_UPSTREAM_URL.

Running it locally

pnpm install
pnpm contracts:build && pnpm abi
pnpm chain        # Anvil on port 9301, escrow and test tokens deployed
pnpm dev          # http://localhost:22700

Deploying to a public network

From a wallet. The operator opens the Deploy page, names the administrator and the tokens accepted from the start, and signs one transaction. Every token address is read from the chain before it can be listed, the page shows the size and hash of the code it is about to send, and the transaction is recorded in the browser the moment the wallet returns it, so a reload never offers it twice. No key passes through this site.

Then it is published. The page hands out a small deployment file. The site's maintainer runs pnpm contracts:ca <file>, which checks on chain that the code at the address is this build byte for byte, that the deployment transaction created it, and who the administrator and which the tokens are, and only then writes deployments/<chainId>.json and ships the site. The app takes its contract address from that file and from nowhere else: there is no address to type into the code, and the app does not start using a contract because a browser says so.

Or from a shell, with a deployer key read from the environment of that one command:

pnpm deploy:plan --network=robinhood --tokens=0xToken1,0xToken2        # nothing is sent
DEPLOYER_PRIVATE_KEY=0x... pnpm deploy:network \
  --network=robinhood --tokens=0xToken1,0xToken2 --confirm=4663 --production

Both ways deploy the same bytecode. On a test network the script can also deploy a clearly labelled token with an open faucet (--with-test-token).

List only plain ERC-20 tokens. A token that takes a fee on transfer is refused when it is deposited. A rebasing token cannot be detected on chain and must not be listed.

Administrator

The contract has one privileged address. This is everything it can do:

  • allow a token for new deposits, or stop new deposits of a token;
  • hand the role to another address (the other address has to accept), or give it up.

It cannot move, freeze, seize or redirect a deposit. It cannot pause redemption. It cannot change a bond. The contract is not upgradeable. Stopping deposits of a token does not affect bonds that already hold it: they stay transferable and redeemable.

Token

$ALMACHAIN is the AlmaChain project’s token, an ERC-20 on Robinhood Chain (chain id 4663). Its contract address is not published yet: CA: Soon.

What it is not

It has no role in the Alma Bond protocol. The escrow contract, AlmaBondEscrow, does not reference it, and bonds do not require it, pay it or accrue it.

Where the address appears

On this site: in the token section of the home page, on this page, and as JSON at /api/token. An address is $ALMACHAIN only when this site shows it. Until one appears here, any contract offered as $ALMACHAIN is not this project’s token.

How to check an address

  1. Compare every character with the address on this site, not only the first and last few. Tokens on Robinhood Chain can take any name and symbol, ALMACHAIN included, so a name or a symbol proves nothing.
  2. Check the network: Robinhood Chain, chain id 4663. The same address on another network is another contract, or none.
  3. Look it up on Blockscout, the network’s explorer (robinhoodchain.blockscout.com).
  4. In a wallet, add the token by its address, never by searching for its name.

Limits

  • Not audited. Tests passing is not an audit.
  • Not upgradeable, no pause. That is what keeps the administrator powerless over deposits. It also means a defect cannot be patched in place.
  • A lost receipt locks its bond for good. See Receipts.
  • Tokens with special rules keep their rules. If a token can block addresses, a payout to a blocked address fails; redeem to another address. If a token can be paused, redemption waits with it.
  • One bond, one token, one amount. A bond cannot be split, topped up or partly redeemed.
  • No lending, no yield, no trading. The contract holds deposits and gives them back. Nothing else.