Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit

* Implement sendMax for native tokens

* Correctly handle "max fee per gas less than block base fee" error

* Fix native send max for Optimism

* Specify gasPrice when sending max to stop wallets from rugging us

* Throw error when native balance < toll

* yarn prettier + yarn lint

* Add Chinese translation for error msg

* Apply suggestions from code review

Co-authored-by: Matt Solomon <>

* If the network doesn't support 1559 pricing, base fee is 0 not 1

* Fix failing builds


Co-authored-by: garyghayrat <>
Co-authored-by: Matt Solomon <>

Git stats


Failed to load latest commit information.
Latest commit message
Commit time
February 1, 2023 09:22
December 9, 2020 11:21
February 20, 2023 09:35
November 21, 2022 22:33
February 1, 2023 18:33
February 1, 2023 09:22
February 22, 2021 07:37
Umbra Logo

Privacy Preserving Stealth Payments for EVM Blockchain Networks.

🚀 🐦 @UmbraCash 💬 Discord 🤑 Gitcoin 🏗️ @ScopeLift

Umbra Logo


Umbra is a protocol for stealth payments on EVM blockchain networks. It enables privacy preserving transactions where the receiver's identity is only known to the sender and receiver.

Diagram showing how Umbra provides privacy.


What is Umbra?

Umbra is a stealth address protocol for EVM networks. That means it allows a payer to send funds to a fresh address. That address is controlled by the intended receiver, but only the payer and the receiver know that.

One way to think of Umbra is this: before anyone sent you funds, you sent them a brand new, never before used address. Only the sender would know you control that address, which adds a layer of privacy to your payment. Payments via Umbra work similarly, but are non-interactive—you don’t need to give someone a fresh address, the sender can just generate one they know only you will be able to access.

Can you walk me through an example?

Alice owns a business and hires Bob to subcontract for her. She agrees to pay Bob 1,000 Dai/week for his work. Bob owns the ENS address bob.eth. If Alice sent the funds each week to bob.eth, anyone looking at the chain could trivially know that Alice is paying Bob 1,000 Dai each week.

Instead, Bob and Alice will use Umbra for private payments. The first time Bob visits the Umbra app, he sets up his account, enabling anyone to privately pay him via Umbra using the name bob.eth, or his normal Ethereum address. Alice then uses Umbra to send 1,000 Dai to Bob each week— she only needs to know his ENS name.

On chain, we see Alice pays 1,000 Dai to a new empty address each week. Behind the scenes, Bob controls the keys to each of these addresses via Umbra, but nobody except Alice and Bob knows this.

Bob uses Umbra to withdraw his 1,000 Dai each week. He only needs to provide an address to send it to. It’s best for him to use an address that’s not tied to his identity. He usually chooses to send it straight to an exchange, where he sells it for fiat as needed. Importantly, this means Bob's exchange now knows this payment went to him. To the casual chain observer— one without access to proprietary centralized exchange data— the fact that Alice's payment went to Bob is obscured.

Consider another example: Liza runs a website that asks for donations. If everyone donated by directly sending her funds, everyone would know how much Liza received in donations. If donations were sent with Umbra instead, each donation would be sent to a different address, and only Liza would know the total amount of donations she received.

How does it work?

  1. When setting up your Umbra account, users sign a message. The hash of this message is used to generate two private keys—a "spending key" and a "viewing key".
  2. The corresponding public keys are both published on-chain as records associated with your address.
  3. A payer uses your address, ENS, or CNS name to look up your two public keys. Separately, the payer generates a random number.
  4. The random number is used with the spending public key to generate a "stealth address" to send funds to. The viewing public key is used to encrypt the random number.
  5. Using the Umbra contract, the payer sends funds to the stealth address and the stealth address and encrypted random number are emitted as an Announcement event.
  6. The receiver scans all Announcement events from the Umbra contract. For each, they use their viewing private key to decrypt the random number, then multiply that number by their spending private key to generate the stealth private key. If the stealth private key controls the stealth address emitted in the Announcement, this payment was for the receiver
  7. The receiver can now use the spending private key to either directly send the transaction required to withdraw funds to another address, or sign a meta-transaction to have the withdrawal request processed by a relayer.

See the Technical Details: How does it work? for more details.

How private is Umbra?

Umbra offers a limited set of privacy guarantees and it’s important to understand them before using the protocol. Umbra does not offer "full" privacy like Aztec or Zcash. It simply makes it impossible for any outside observers (i.e. anyone who is not the sender or the receiver) to know who the sender paid by looking at the receiving address.

It’s important to understand that poor hygiene by the receiver— for example, sending the funds directly to a publicly known address— reduces the privacy benefits for both the sender and receiver.

The privacy properties of Umbra can also be diminished if an observer can narrow down the set of potential recipients for a given transaction. Any valid public key can be used as a recipient, and anyone who has sent a transaction on Ethereum has a publicly available public key. Therefore, by default, the "anonymity set"—the set of potential recipients of a transaction—is anyone who has ever sent an Ethereum transaction!

In practice this isn’t necessarily the case, and an observer may be able to narrow down the list of recipients in a few ways:

  1. Most users will use ENS names to send funds, so the recipient most likely has published keys under an ENS name
  2. Poor hygiene when withdrawing funds from your stealth addresses can reduce or entirely remove the privacy properties provided by Umbra. See Which addresses are safe for withdrawing funds? for more details. Always use caution when withdrawing!

Is Umbra a mixer?

No. Umbra is not a mixer and does not use zero knowledge proofs. Instead, Umbra is based on ordinary elliptic curve cryptography. It’s meant for payments between two entities, and comes with a different set of privacy tradeoffs. Rather than breaking the link between sending and receiving address, like a mixer, Umbra makes that link meaningless. Everyone can see who sent the funds, and everyone can see the address funds were sent to, but that receiving address has never been seen on-chain so it’s impossible for any outside observers to know who controls it.

Where can I learn more?

Check out the full FAQ to get more details about Umbra.


This repository uses yarn for package management and volta for dev tool version management. Both are prerequisites for setting up your development environment. The repository also requires foundry for development of periphery smart contracts.


Umbra is a monorepo consisting of 4 packages:

  • frontend — Frontend web3 app for setting up and using Umbra, deployed at
  • contracts-core — Solidity contracts used in the Umbra Protocol.
  • contracts-periphery — Solidity contracts used by the Umbra frontend to add features and improve UX.
  • umbra-js — A TypeScript library for building Umbra-enabled web3 apps in node.js or in the browser.

The monorepo structure simplifies the development workflow.


To get started, clone this repo, then follow these instructions:

# run these commands from workspace root!
cp contracts-core/.env.example contracts-core/.env # please edit the .env with your own environment variable values
cp frontend/.env.example frontend/.env # please edit the .env with your own environment variable values
cp umbra-js/.env.example umbra-js/.env # please edit the .env with your own environment variable values
curl -L | bash # install foundryup binary
foundryup # install Foundry
yarn install # installs dependencies for each of the 3 packages. Also builds umbra-js.
yarn test # runs the test suite for each package

# Additional commands also available from the workspace root:
yarn build # builds each of the 3 packages
yarn clean # removes build artifacts for each of the 3 packages
yarn lint # lints each of the 3 packages
yarn prettier # runs formatting on each of the 3 packages
yarn test # runs tests for each of the 3 packages

Note: If you want to be more precise with your command (e.g. just building, cleaning, or testing 1 package), simply run any above command from the package directory. For example, if you were just working on the contract code, you might:

cd contracts-core # move into the contracts-core sub directory
yarn build # build only the contracts
yarn clean # remove only the contract build artifacts
yarn test # run only the contract tests


Contributions to Umbra are welcome! Fork the project, create a new branch from master, and open a PR. Ensure the project can be fast-forward merged by rebasing if necessary.


Umbra is available under the MIT license.

Copyright (c) 2023 ScopeLift