Skip to main content

Oasis Privacy Layer

The Oasis Privacy Layer (OPL) is an EVM-compatible privacy solution that empowers developers to add new functionality to smart contracts on the most popular EVM networks like Ethereum, BNB Chain, and Polygon with encrypted transactions and confidential state.

By using a Solidity library that integrates Sapphire into your existing and future Web3 applications, developers on any supported network can seamlessly add confidential state and selective disclosures to their dApps when using contract a deployed on Sapphire without leaving their existing networks.

For more information about OPL and to catch the latest news, please visit the official OPL page.

Oasis Privacy Layer diagram

The user submits a transaction on the Home network to a contract which uses postMessage to notify the SGN that it should approve the cross-chain message. The Executor waits, when the SGN approves the message the Executor submits a transaction to the target contract on Sapphire.

Transaction Flow

The Home Contract pays the SGN to watch and approve the message, but the Executor needs to be run by somebody willing to pay for the gas to submit transactions to the destination chain.

Quickstart

A pair of contracts are linked bidirectionally 1-1 to each other across chains, with one end on Sapphire and the other on a supported EVM-compatible chain (the Home Network). They can post and receive messages to & from each other using the message-passing bridge, but must register endpoints to define which messages they handle from each other.

Start by adding the @oasisprotocol/sapphire-contracts NPM package to your Hardhat project so you can import OPL.sol:

npm install @oasisprotocol/sapphire-contracts

Then define the two contracts, starting with a contract on Sapphire which runs inside the confidential enclave and can be called via the secretExample handler. Use the constructor to provide the Sapphire contract with the location (address and chain) of the contract on the Home network:

import {Enclave, Result, autoswitch} from "@oasisprotocol/sapphire-contracts/contracts/OPL.sol";

contract SapphireContract is Enclave {
constructor(address otherEnd, string chain) Enclave(otherEnd, autoswitch(chain)) {
registerEndpoint("secretExample", on_example);
}
function on_example(bytes calldata _args) internal returns (Result) {
(uint256 a, bool b) = abi.decode(args, (uint256, bool));
// TODO: do confidential things here
return Result.Success;
}
}

Then on the other chain, define your contract which can be called via triggerExample to send a message to the contract on Sapphire using the postMessage interface.

import {Host, Result} from "@oasisprotocol/sapphire-contracts/contracts/OPL.sol";

contract HomeContract is Host {
constructor(address otherEnd) Host(otherEnd) {
}
function triggerExample (uint256 a, bool b) external payable {
postMessage("secretExample", abi.encode(a, b));
}
}

After a few minutes the bridge will detect and then the executor will invoke the SapphireContract.on_example method.

Monitoring

The Celer IM Scan API can be used to retrieve status and message details by providing the globally unique transaction ID from the chain which originated the message.

https://api.celerscan.com/scan/searchByTxHash?tx=0x...

For details of the response format, see the Query IM Tx Status page of the Celer Inter-Chain Message (IM) documentation. Using this API lets you to check if messages have been delivered.

Mainnet Deployment

It is necessary to run a Message Executor which monitors the Celer State Guardian Network (SGN) for cross-chain messages and then submits the proof on-chain to deliver them to the target contract.

If you are participating in a Hackathon or Grant, please fill out the relay request form to be allowed to use the shared Message Executor.

Supported Networks

Mainnets

NameInt IDHex IDautoswitch name
Ape163500x3fdeape
Arbitrum Nova421700xa4baarbitrum-nova
Arbitrum One42161a4b1arbitrum-one
Astar5920x250astar
Aurora13131615540x4e454152aurora
Avalanche431140xa86aavalanche
Binance Smart Chain560x38bsc
Ethereum10x1ethereum
Fantom2500xfafantom
Filecoin3140x13afilecoin
Milkomeda C120010x7d1milkomeda
Moonriver12850x505moonriver
Polygon1370x89polygon
Sapphire232940x5afesapphire
Syscoin570x39syscoin
Polygon zkEVM11010x44dpolygon-zkevm
Optimism100xaoptimism
zkSync Era3240x144zksync-era

Testnets

NameInt IDHex IDautoswitch name
Arbitrum Testnet4216110x66eebarbitrum-testnet
Avalanche C-Chain Fuji Testnet431130xa869avalanche-fuji
BSC Testnet970x61bsc-testnet
ConsenSys zkEVM Testnet591400xe704zkevm-testnet
Dexalot Testnet4322010x69849dexalot-testnet
Fantom Testnet40020xfa2fantom-testnet
Filecoin Hyperspace Testnet31410xc45filecoin-testnet
FNCY Testnet9230180xe158afncy-testnet
Godwoken Testnet714010x116e9godwoken-testnet
Goerli Testnet50x5goerli
Polygon Mumbai Testnet800010x13881polygon-mumbai
Polygon zkEVM Testnet14420x5a2zkevm-testnet
Sapphire Testnet232950x5affsapphire-testnet
Scroll Alpha Testnet5343530x82751scroll-testnet
Shibuya Testnet810x51shibuya-testnet

In the following sections we will look at a concrete example on how to build a confidential, cross-chain DAO-voting dApp from scratch using the Oasis Privacy Layer!