GithubHelp home page GithubHelp logo

oasisprotocol / sapphire-paratime Goto Github PK

View Code? Open in Web Editor NEW
34.0 15.0 24.0 11.29 MB

The Sapphire ParaTime monorepo.

Home Page: https://oasisprotocol.org/sapphire

License: Apache License 2.0

Rust 3.26% JavaScript 0.84% TypeScript 43.12% Go 8.32% Solidity 30.07% Makefile 1.02% Python 12.85% Shell 0.14% CSS 0.38%
blockchain chain confidential crypto ethereum evm network oasis official paratime

sapphire-paratime's Introduction

Sapphire Paratime

license ci-lint ci-test ci-test

The Sapphire ParaTime is the official confidential EVM Compatible ParaTime providing a smart contract development environment with EVM compatibility on the Oasis Network.

This monorepo includes the source code for the following Sapphire packages:

Sub-Project Version Size Downloads
TypeScript version size downloads
Go version
Solidity version downloads
Hardhat version size downloads
Ethers 6.x version size downloads
Wagmi 2.x version size downloads
Viem 2.x version size downloads

Layout

This repository includes all relevant Sapphire and dependencies organized into the following directories:

  • clients: the Go, Python and JavaScript/TypeScript clients
  • contracts: Sapphire and OPL smart contracts
  • docs: topic-oriented Sapphire documentation
  • examples: sample code snippets in popular Ethereum development environments
  • integrations: plugins for popular Ethereum SDKs
  • runtime: the Sapphire Paratime as based off of the Oasis SDK

Documentation

The Sapphire documentation is deployed as part of the official Oasis documentation. To make changes visible on the docs website:

  1. Merge any changes in the docs folder to the main branch.
  2. Bump the git commit reference of the Sapphire submodule inside the external directory of the Oasis docs repository (you can simply approve the auto-generated dependabot's submodule bump PR).
  3. Merge changes into Oasis docs repository main branch. CI will deploy the docs to the website automatically.

Note: If you want to introduce a new markdown file, don't forget to add it to the Oasis documentation's sidebar. If you remove any chapters, don't forget to define sensible redirects. For more info on how to write the Oasis documentation, manage images and diagrams, reference cross-repo markdown files and similar consult the official README.

The API documentation is auto-generated from the corresponding Sapphire clients and libraries. It is deployed at:

The API docs are generated automatically every 15 minutes from the main branch.

Release

Clients & Integrations

JS libraries should be updated with a version bump in the package.json file and a respective tag in the pattern of {{path}}/v{{semver}}, such as clients/js/v1.1.1.

Contributing

Developers are encouraged to contribute their improvements to the Sapphire Paratime through this repository. Open a pull request and one of the Oasis Protocol Foundation members will check it out and get back to you!

See our Contributing Guidelines.

Build

Oasis remains committed to unlocking the full potential of privacy applications on Web3.

Build with us today!

License

This software is licensed under Apache 2.0.

The content of the documentation (the /docs folder) including the media (e.g. images and diagrams) is licensed under Creative Commons Attribution 4.0 International.

sapphire-paratime's People

Contributors

abukosek avatar aefhm avatar berkliumbirb avatar cedarmist avatar dependabot[bot] avatar jberci avatar kittycatdao avatar kostko avatar liarco avatar lubej avatar lukaw3d avatar matevz avatar mylanos avatar nhynes avatar party-for-illuminati avatar peterjgilbert avatar tharkunas avatar xmzheng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sapphire-paratime's Issues

decrypt_into accepts replays. also next_nonce forces tx/rx to be lockstep synchronous -- is this desirable?

https://github.com/oasislabs/sapphire-paratime/blob/4d20964b38ffdded1357823d7987064d0601f7db/encrypting-proxy/src/crypto/cipher.rs#L101

the incr-by-2 odd/even tx/rx nonce design forces messages to be synchronous, so alice send w/ the tx_nonce which bob checks is as expected and then bob would send a reply w/ rx_nonce which alice checks. this is okay if synchronous back-and-forth is what we want, but if we may need alice to send 2 messages before getting bob's reply, then it is inconvenient to have a single value where we do self.nonce.fetch_add(2, SeqCst).

instead of the low-order bit denoting whether a number is a tx or rx nonce, we could just use a high order bit. this looks like a type bit followed by a 63-bit nonce counter space. or, we could have two separate counters and a "direction" indicator so that messages from alice to bob would not validate as messages from bob to alice (or vice versa). these are, from a functionality view point, pretty much equivalent (63 bit vs 64 bit nonce space is not a big deal). granted, we don't have to be starting off viewing things as two separate nonce sequences and a bit to distinguish the direction, since if/when a future change requiring decoupled send/receive functions can separate out the two nonces as suggested, and encode them as 63-nonce plus direction in a wire-format compatible manner, before migrating to allowing a different number of messages being in-flight etc.

anyway, that's the design nit. it feels weird to me. it's not wrong, but it feels awkward.

oh, idiomatic rust question. L103-L107 splits the slices into fields for writing the actual values into, but values are written in L108-L111. is this idiomatic rust? i don't like it because i have to ensure that every split slice is actually used -- but maybe the compiler will generate a warning if one field is forgotten and rust programmers habitually rely on that instead? checking that every field gets initialized is part of audits, obvs, so being able to eyeball that is good, but maybe i'm being old-school and relying on compiler generated errors is better (though being paranoid, i'd prefer to not rely on that solely).

so the code sends both tx_nonce and rx_nonce when they differ by 1. which is weird.

in decrypt_into L127, no checking of the expected nonce value occurs. it's used as the input for open_into as the expected value and the AAD for AEAD, i believe. so this is a bug, right? since there is no checking of the nonce value from versioned_nonced_tagged_ct with the SessionCipher object's nonce member, a SessionCipher will accept any replayed message and decrypt_into will succeed.

ci: Upgrade to PNPM 8 and Node 18

PNPM:

  • There are some minor problems with peer dependencies with PNPM 7, which are resolved by upgrading to PNPM 8
  • 8 is the default version if you install pnpm
  • PNPM 8 also has roughly 2x the number of downloads vs v7, and 7x the number of downloads as v6, so it's safe to say it's the most common version.
  • PNPM versions: https://www.npmjs.com/package/pnpm?activeTab=versions

NodeJS:

Generally, targeting TypeScript 5.x usually prefers Node.js v18 or v20, unless we want to target minimal compatible versions in which case TypeScript 5 with Node.js v16 and PNPM 7 is fine for now.

Think it would be good to keep note of supported versions in README.md

contracts/opl: Host requires Encave address, Enclave requires Host address?

There is a permanent 1:1 pairing between the two contracts on either side of the MessageBus, and the constructor for either requires the others contract address.

The address can be predicted using const newContractAddress = ethers.utils.getContractAddress({ from: signerAddr, nonce });

However, this could make building OPL contracts difficult when using @oasisprotocol/sapphire-contracts/contracts/OPL.sol as the remote variable of BaseEndpoint is private so it can't be changed after creation so the contracts must be deployed together.

Additionally, the 1:1 relationship between contracts limits the use cases.

Need to document this, and recommend using the Celer IM SDK for more complex use cases.

JS client can't be used with CRA

When trying to import package in Create React App project in development this build error emerges:

./node_modules/@oasisprotocol/sapphire-paratime/lib/esm/cipher.js 246:31
Module parse failed: Unexpected token (246:31)
File was processed with these loaders:
 * ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|   }
| 
>   const fetchImpl = globalThis?.fetch ?? opts?.fetch;
|   const res = await (fetchImpl ? fetchRuntimePublicKeyBrowser(gatewayUrl, fetchImpl) : fetchRuntimePublicKeyNode(gatewayUrl));
|   return arrayify(res.result.key);

When trying to build production build the following error:

Creating an optimized production build...
Failed to compile.

./node_modules/@oasisprotocol/sapphire-paratime/lib/esm/cipher.js
Cannot find module: 'node:https'. Make sure this package is installed.

You can install this package by running: npm install node:https.

CRA version: 4.0.3 (same as in Uniswap)
Node Version: 16.10.0
Sapphire Paratime Version: 1.0.5

@openzeppelin/contracts not imported

When I add @oasisprotocol/sapphire-contracts to a project it complains

Error HH411: The library @openzeppelin/contracts, imported from @oasisprotocol/sapphire-contracts/contracts/opl/Endpoint.sol, is not installed. Try installing it using npm.

HardhatError: HH411: The library @openzeppelin/contracts, imported from @oasisprotocol/sapphire-contracts/contracts/opl/Endpoint.sol, is not installed. Try installing it using npm.

The package @openzeppelin/contracts is included in devDependencies.

It should be moved to dependencies, as it's required to compile the contracts.

My example projects dependency file:

  "devDependencies": {
    "@nomicfoundation/hardhat-toolbox": "^3.0.0",
    "@oasisprotocol/sapphire-hardhat": "^2.16.1",
    "ethers": "^6.7.0",
    "hardhat": "^2.17.2",
    "ts-node": "^10.9.1",
    "typescript": "^5.1.6"
  },
  "dependencies": {
    "@oasisprotocol/sapphire-contracts": "^0.2.4"
  }

Steps to reproduce:

  • Setup new hardhat project
  • Add sapphire-contracts package to dependencies
  • Create new contract
  • import OPL.sol in contract
  • run pnpm hardhat compile

Hardhat: Error when calling Smart Contract's method from signer other then deployer

I'm getting an error if I call the normal Smart Contract method from the signer that is not the original smart contract deployer.

For easy issue replication, I have prepared repo. Issue can be discovered if you run the script test.js on Sapphire TestNet.

Inside test.js script you can find the line:

let testerTokenBalanceBefore = await testerTokenReadInstance.balanceOf(
    tester.address
  );

On this line I'm getting the error:

Error: missing revert data in call exception; Transaction reverted without a reason string [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (data="0x", transaction={"from":"0xC88309139e5809f4E736D700bB8Aca31540C67d8","to":"0x29512C25ac8d5bE86FD83bee380EDAc5a726947C","data":"0x70a08231000000000000000000000000c88309139e5809f4e736d700bb8aca31540c67d8","accessList":null}, error={"name":"ProviderError","_stack":"ProviderError: invalid signed simulate call query: signer != caller\n    at HttpProvider.request ...

Testing on my side has been done with last source version of @oasisprotocol/sapphire-hardhat.

Expose reversion error messages to clients

It takes many extra steps to figure out why a transaction failed with all outputs being made confidential. We can improve developer experience while preserving the ability to be secure by exposing revert statuses and reversion messages.

Pros

  • good for developers who can debug more easily
  • good for users who can see why a transaction failed (e.g., out of gas, application error)
  • makes the block explorer more useful since it shows accurate data

Cons

  • developers must know not to revert based on private data (ever-present side-channel risk. gas usage also leaks this info, so encrypting outputs is not a panacea)
  • specific to the EVM module, requiring extra code not shared with other modules

Overall, given the feedback we've gotten from developers about how difficult it is to debug their dapps, the cons listed above don't seem bad at all. Side-channels are more generally avoided with #67 anyway.

Document callformat

We have a TS compat lib and a Go compat lib, but not a Python compat lib or any other compat lib. That's perhaps because we don't have a spec in any format other than code. It would be good to have document describing the callformat.

Solidity prettifier options could be improved

It results in many inconsistent formats across the files.


One example of weirdness which strips all the semantic information I included is:

            abi.encodePacked(
                hex"a262",
                "to",
                hex"55",
                to,
                hex"66",
                "amount",
                hex"8250",
                value,
                hex"40"
            )

Another example with parameters & type info:

A:

    function subcall(string memory method, bytes memory body)
        internal
        returns (uint64 status, bytes memory data)
    {

vs

B:

    function _subcallWithToAndAmount(
        string memory method,
        StakingPublicKey to,
        uint128 value
    ) internal returns (uint64 status, bytes memory data) {

I prefer the first (A), it separates visibility & return types. But the prettifier sometimes decides to split e.g. internal and view onto their own lines, or sometimes just puts them on the same line. Either way, it's inconsistent.

client-js: Encrypt plain transactions in sendTransaction()

In the onchain-signer and demo-voting examples, we use plain, unwrapped provider in order to call sendTransaction() of the on-chain generated and signed EIP-155 transaction, because the wrapper aborts with Error: Un-enveloped data was passed to sendRawTransaction, which is likely incorrect. Is the dapp using the Sapphire compat lib correctly?.

The downside of this is that the transaction is not encrypted, so we need to encrypt the inner call on the chain to get privacy. This is expensive and makes no sense since the client could encrypt it with the symmetric key when submitting it.

Note: encryption is not related to the fact that the tx was signed by someone else (=on-chain signer in our case), so this should be perfectly doable.

CBOR decode error when view/pure function reverts

SUMMARY

Calling a pure/view function via a Sapphire-wrapped ethers instance throws a CBOR decode error instead of the actual reason when the call reverts

ISSUE TYPE
  • Bug Report
STEPS TO REPRODUCE
  • Deploy a contract containing a Solidity pure/view function that reverts when called
  • In a Node JS/Typescript project, set up ethers with the Sapphire paratime wrapper
  • Call the function of the contract you deployed earlier
ACTUAL RESULTS
Error: CBOR decode error: too many terminals, data makes no sense
    at Module.decode (file:///home/mirayashi/dev/rpc3/node_modules/cborg/esm/lib/decode.js:131:11)
    at X25519DeoxysII.<anonymous> (file:///home/mirayashi/dev/rpc3/node_modules/@oasisprotocol/sapphire-paratime/src/cipher.ts:117:41)
    at Generator.next (<anonymous>)
    at file:///home/mirayashi/dev/rpc3/node_modules/@oasisprotocol/sapphire-paratime/lib/esm/cipher.js:7:71
    at new Promise (<anonymous>)
    at __awaiter (file:///home/mirayashi/dev/rpc3/node_modules/@oasisprotocol/sapphire-paratime/lib/esm/cipher.js:3:12)
    at X25519DeoxysII.decryptEncoded (file:///home/mirayashi/dev/rpc3/node_modules/@oasisprotocol/sapphire-paratime/lib/esm/cipher.js:83:16)
    at file:///home/mirayashi/dev/rpc3/node_modules/@oasisprotocol/sapphire-paratime/src/cipher.ts:274:64
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
EXPECTED RESULTS

I'm expecting to get a more informative error from ethers like

Error: call revert exception; VM Exception while processing transaction: reverted with reason xxx
VERSIONS

@oasisprotocol/[email protected]
[email protected]

Sapphire.randomBytes returns zeros on HardHat

Hardhat has misleading behavior with Sapphire precompiles.

staticcall sets success=true even if precompile doesn't exist, and the bytes memory entropy returned will not point to real return data (it should return an array of length zero)

Example:

// SPDX-License-Identifier: CC-PDDC

pragma solidity ^0.8.0;

contract RandomTest {
    function random()
        external view
        returns (bytes32 a, bytes32 b)
    {
        a = _random_bytes32();

        b = _random_bytes32();
    }

    address internal constant RANDOM_BYTES = 0x0100000000000000000000000000000000000001;

    function _random_bytes32()
        internal view
        returns (bytes32)
    {
        (bool success, bytes memory entropy) = RANDOM_BYTES.staticcall(
            abi.encode(uint256(32), "")
        );
        require( success );
        return bytes32(entropy);
    }
}

Test:

import { expect } from 'chai';
import { ethers } from "hardhat";
describe('RandomTest', function () {
    it("Multiple calls are all random ", async function () {
        const RandomTest_Contract = await ethers.getContractFactory("RandomTest");
        const rt = await RandomTest_Contract.deploy();
        const resp = await rt.random();
        console.log(resp);
        expect(resp.a).to.not.equal(resp.b);
    });
});

If I add require( entropy.length == 32 ); it fails on hardhat (which is correct), and succeeds on Sapphire (which is also correct).

I suggest making it revert with error Precompile_Not_Supported();.

Checking the chainId parameter could also work to test for Sapphire precompiles.


The contract can be tested against Sapphire using the sapphire-dev docker container:

e.g. in hardhat.config.ts use:

const TEST_HDWALLET = {
  mnemonic: "test test test test test test test test test test test junk",
  path: "m/44'/60'/0'/0",
  initialIndex: 0,
  count: 20,
  passphrase: "",
};

const config: HardhatUserConfig = {
...
  networks: {
    hardhat: {
      chainId: 1337 // We set 1337 to make interacting with MetaMask simpler
    },
    sapphire_local: {
      url: "http://localhost:8545",
      accounts: TEST_HDWALLET,
      chainId: 0x5afd,
    },
  }
...

And run a local Sapphire node with:

docker run --rm -it -p8545:8545 -p8546:8546 ghcr.io/oasisprotocol/sapphire-dev:latest -to 'test test test test test test test test test test test junk' -n 20

Then run your hardhat tests with:

pnpm hardhat test --network sapphire_local tests/random.test.ts

Ethereum `ecrecover` compatibility with Secp256k1PrehashedKeccak256

Ethereum compatibility for the signing algorithms is very important for Sapphire.

This consists of:

  • Converting signatures to an Ethereum compatible v, r, and s parameters
  • Converting a generated P256k1 public key to an Ethereum address

To be acceptable there must be an example which performs a round-trip using ecrecover to verify a signature & public key generated by the Sapphire signing precompiles.

The signature format returned by Sapphire is 70 bytes DER encoded, see:

Incompatibility with Hardhat 2.16.1

When using Hardhat 2.16.1 there's an error in extendEnvironment.

The customized fork of hardhat is based on 2.12.6.

> [email protected] test /home/runner/work/sapphire-paratime/sapphire-paratime/examples/hardhat-boilerplate
> hardhat test

An unexpected error occurred:

TypeError: Cannot read properties of undefined (reading 'add')
    at extendEnvironment (/home/runner/work/sapphire-paratime/sapphire-paratime/node_modules/.pnpm/[email protected]_qkpo4aptcl5wogwco44qzoggoq/node_modules/hardhat/src/internal/core/config/config-env.ts:130:19)
    at Object.<anonymous> (/home/runner/work/sapphire-paratime/sapphire-paratime/integrations/hardhat/src/index.ts:8:18)
    at Module._compile (node:internal/modules/cjs/loader:1198:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1252:10)
    at Module.load (node:internal/modules/cjs/loader:1076:32)
    at Function.Module._load (node:internal/modules/cjs/loader:911:12)
    at Module.require (node:internal/modules/cjs/loader:1100:19)
    at require (node:internal/modules/cjs/helpers:108:18)
    at Object.<anonymous> (/home/runner/work/sapphire-paratime/sapphire-paratime/examples/hardhat-boilerplate/hardhat.config.js:1:1)
    at Module._compile (node:internal/modules/cjs/loader:1198:14)

Snippet from config-env.ts in oasislabs 2.12.6 fork:
https://github.com/oasislabs/hardhat/blob/6bf1a3de107b841c737df834da2ba366b5b3e390/packages/hardhat-core/src/internal/core/config/config-env.ts#L127C1-L131

export function extendEnvironment(extender: EnvironmentExtender) {
  const ctx = HardhatContext.getHardhatContext();
  const extenderManager = ctx.extendersManager;
  extenderManager.add(extender);
}

However in 2.16.x the internal implementation is different:
https://github.com/NomicFoundation/hardhat/blob/6779768011cd9a97973c57d6d27ad4e8a49b7d58/packages/hardhat-core/src/internal/core/config/config-env.ts#L128-L131

export function extendEnvironment(extender: EnvironmentExtender) {
  const ctx = HardhatContext.getHardhatContext();
  ctx.environmentExtenders.push(extender);
}

As in, there are is confusion internally where 2.12.6 code is calling 2.16.x code, which isn't ideal.


Various versions of hardhat can be added into the testing matrix, as per:

627b9db

client/js: When using Hardhat, `fetchRuntimePublicKey` falls through to `fetchRuntimePublicKeyByChainId`

There is a problem when using CI or a multi-container environment, for example Hardhat with the sapphire-dev where both are in containers on the same Docker network, where both containers have separate 172.16.x IP addresses.

The fetchRuntimePublicKey function isn't using the configured upstream JSON-RPC provider to request the call data public key. This means it's trying to access 127.0.0.1:8545 which won't work - because the sapphire-dev container is on another 172.x IP.

This is causing hardhat test to fail, but it works when running the tests locally, or when running the tests on the CI host rather than inside a container.

While this is annoying for CI, the more general problem is the provider detection code in fetchRuntimePublicKey doesn't seem to be functioning 100%.


One of the problems is there's duplicated logic to find the correct .send method inside fetchRuntimePublicKey because it's being called prior to wrapping the provider.

If it's moved until after the provider has been wrapped, then it can use the consistent EIP-1193 .request method.

export async function fetchRuntimePublicKey(

is called from

function getCipher(provider: UpstreamProvider): Cipher {

which is called from the top of the wrap function at:

const provider = new JsonRpcProvider(upstream);

and

const cipher = customCipher ?? getCipher(upstream);


Some notes on .send, if the provider isn't EIP-1193 compatible which has a standardized .request method. It will fall back to having to use .send which is wildly inconsistent across implementations.

  • Ethers (v5 & v6) JSON-RPC provider = send(method:string,params[]) -> Promise
  • Truffle = send(payload, callback) -> void

With .request it can be simplified as:

+    // EIP-1193 provider
+    if( 'request' in provider ) {
+      const {key} = await (provider as EIP1193Provider).request({method: OASIS_CALL_DATA_PUBLIC_KEY}) as {key:string};
+      if( key ) return arrayify(key);
+    }

Truffle HDWallet-provider: https://github.com/trufflesuite/truffle/blob/a6fb238ef954d3ad4c6fd4181b78ee3dc047c8bf/packages/hdwallet-provider/src/index.ts#L364-L368

public send(
    payload: JSONRPCRequestPayload,
    // @ts-ignore we patch this method so it doesn't conform to type
    callback: (error: null | Error, response: JSONRPCResponsePayload) => void
  ): void

EIP-1193: https://eips.ethereum.org/EIPS/eip-1193#appendix-i-consumer-facing-api-documentation

interface RequestArguments {
  readonly method: string;
  readonly params?: readonly unknown[] | object;
}

Provider.request(args: RequestArguments): Promise<unknown>;

Ethers JSON-RPC provider: https://github.com/ethers-io/ethers.js/blob/9197f9f938b5f3b5f97c043f2dab06854656c932/src.ts/providers/provider-jsonrpc.ts#L1139

async send(method: string, params: Array<any> | Record<string, any>): Promise<any> {

Web3 provider .send: https://docs.web3js.org/api/web3-providers-http/class/HttpProvider#send which notes the interface is deprecated and to use .request instead.

The big problem seems to be that neither Truffle nor Ethers support .request...

The isEthersSend function tries to determine between them:

function isEthersSend(
send?: AsyncSend | JsonRpcProvider['send'],
): send is JsonRpcProvider['send'] {
if (!send) return false;
// If the function is async, it's likely ethers send.
try {
const res = (send as any)(); // either rejects or calls back with an error
if (res instanceof Promise) {
res.catch(() => void {}); // handle the rejection before the next tick
return true;
}
} catch {
// This is prophyalictic. Neither kind of `send` should synchronously throw.
}
return false;
}

And I used a bad hack to detect Truffle HDWallet provider:

const arg =
'engine' in provider
? // eslint-disable-next-line @typescript-eslint/no-unused-vars
function (err: any, ok?: any) {
return;
}
: [];
const { key } = await source.send(OASIS_CALL_DATA_PUBLIC_KEY, arg);

But this needs cleaning up to make sure it's compatible with:

  • Truffle
  • Hardhat
  • Metamask
  • EIP-1193
  • Ethers

Can we have a more robust isEthers6Signer than `instanceof ethers6.AbstractSigner`?

function isEthers6Signer(upstream: unknown): upstream is ethers6.Signer {
return upstream instanceof ethers6.AbstractSigner;
}
function isEthers6Provider(upstream: unknown): upstream is ethers6.Provider {
return upstream instanceof ethers6.AbstractProvider;
}

Currently isEthers6Signer and isEthers6Provider are very error prone. For it to work, the end project needs to install the exact same version of ethers6 and their package manager must deduplicate it and their bundler must import the same import the same output format ethers6/dist/ vs ethers6/lib.esm/ vs ethers6/lib.commonjs/ (and our library must not bundle dependencies or be served from CDN). If it isn't the same runtime instance then projectEthers6.6.2AbstractSigner instanceof compatEthers6.6.1AbstractSigner returns false

Clients should cache signed calls

If the leash and block range is still valid for a previously-signed call, the old one should be reused to avoid browser wallet popups without requiring the dapp to think about this. A dapp that needs a longer (or shorter) leash wouldn't benefit from this, but most dapps should be well served.

Sapphire hardhat integration state

We would love to start using sapphire in our primary development environment hardhat. I saw there is already an integration with hardhat @oasisprotocol/sapphire-hardhat but it doesn't look like it's available on npm yet. When trying it locally, it also seems to have some problems in our configuration. What's the current state of the plugin so far? And when can we expect to start using it? Thanks!

Golang compatibility library

Many users have requested a Golang version of the compatibility library. The beginnings of it already exist in this repo, so the remaining effort is to pack and the appropriate data in the Sapphire format.

Requirements:

  • able to use the library to send Sapphire-format transactions through go-ethereum
  • able to integrate with any version of go-ethereum
  • compatible with Go abigen
    • wrapper type for bind.ContractCaller, bind.ContractTransactor that implements the same. this should be passed to New method of generated binding
    • the wrapper is just like the js one, but will use public methods for packing the data, so that the library can be used without an abi generator (raw go-ethereum)

Blockscout contract verification

Blockscout cannot verify Sapphire contracts because it tries to verify the deploycode which is encrypted rather than the actual contract code which is public. It should have the latter behavior.

cc @pro-wh for ruminating over the oasis explorer verification service

wagmi support

SUMMARY

There's no instruction on how to set up wagmi with sapphire paratime.

ISSUE TYPE
  • Bug Report

Sapphire JS compatibility library issue with Truffle callback

Reproduction

Using the latest version of Truffle v5.8.2 (core: 5.8.2) with the documented steps for a Sapphire dApp runs into an issue with the JS compatibility library.

UnhandledRejections detected
Promise {
  <rejected> TypeError: callback is not a function
      at /Users/xi/.npm/_npx/7be3639a7343b447/node_modules/truffle/build/webpack:/packages/provider/wrapper.js:165:1
      at /Users/xi/oasis/MetaCoin/node_modules/.pnpm/@[email protected]/node_modules/@oasisprotocol/sapphire-paratime/src/compat.ts:399:2
      at processTicksAndRejections (node:internal/process/task_queues:95:5)
} TypeError: callback is not a function
    at /Users/xi/.npm/_npx/7be3639a7343b447/node_modules/truffle/build/webpack:/packages/provider/wrapper.js:165:1
    at /Users/xi/oasis/MetaCoin/node_modules/.pnpm/@[email protected]/node_modules/@oasisprotocol/sapphire-paratime/src/compat.ts:399:2
    at processTicksAndRejections (node:internal/process/task_queues:95:5)
Promise {
  <rejected> TypeError: callback is not a function
      at /Users/xi/.npm/_npx/7be3639a7343b447/node_modules/truffle/build/webpack:/packages/provider/wrapper.js:165:1
      at /Users/xi/oasis/MetaCoin/node_modules/.pnpm/@[email protected]/node_modules/@oasisprotocol/sapphire-paratime/src/compat.ts:399:2
      at processTicksAndRejections (node:internal/process/task_queues:95:5)
} TypeError: callback is not a function
    at /Users/xi/.npm/_npx/7be3639a7343b447/node_modules/truffle/build/webpack:/packages/provider/wrapper.js:165:1
    at /Users/xi/oasis/MetaCoin/node_modules/.pnpm/@[email protected]/node_modules/@oasisprotocol/sapphire-paratime/src/compat.ts:399:2

Type errors in declaration after installing @oasisprotocol/sapphire-paratime

Type-fest should be a normal dependency, instead of a devDependency because it appears in public type declaration.

Also, @types/bn.js and @types/elliptic look unused.

To reproduce

Fresh typescript project

{
  "dependencies": {
    "@oasisprotocol/sapphire-paratime": "^1.0.3",
    "typescript": "^4.8.3"
  }
}
{
  "include": ["src"],
  "compilerOptions": {
    "esModuleInterop": true,
    "module": "es2020",
    "moduleResolution": "node",
    "target": "es2020",
    "strict": true,
    "allowJs": true,
    "checkJs": true,

    "noEmit": true
  }
}
import * as sapphire from '@oasisprotocol/sapphire-paratime';
const provider = sapphire.wrap
$ yarn tsc
node_modules/@oasisprotocol/sapphire-paratime/lib/cjs/cipher.d.ts:3:28 - error TS2307: Cannot find module 'type-fest' or its corresponding type declarations.

3 import { Promisable } from 'type-fest';
                             ~~~~~~~~~~~

node_modules/@oasisprotocol/sapphire-paratime/lib/cjs/signed_calls.d.ts:5:62 - error TS2307: Cannot find module 'type-fest' or its corresponding type declarations.

5 import type { CamelCasedProperties, RequireExactlyOne } from 'type-fest';
                                                               ~~~~~~~~~~~


Found 2 errors in 2 files.

Errors  Files
     1  node_modules/@oasisprotocol/sapphire-paratime/lib/cjs/cipher.d.ts:3
     1  node_modules/@oasisprotocol/sapphire-paratime/lib/cjs/signed_calls.d.ts:5
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

client/js: Occasional error: TypeError: Cannot read properties of undefined (reading 'key')

This happened when merging from a branch into main.

The tests completed OK on the branch, but after merging into main it fails.

See: https://github.com/oasisprotocol/sapphire-paratime/actions/runs/5465401574/attempts/1

The second attempt succeeds.

Maybe it's worth re-trying the fetch runtime public key function? Or having some other way of safely erroring.

     TypeError: Cannot read properties of undefined (reading 'key')
      at /home/runner/work/sapphire-paratime/sapphire-paratime/clients/js/src/cipher.ts:294:30
      at Generator.next (<anonymous>)
      at fulfilled (/home/runner/work/sapphire-paratime/sapphire-paratime/clients/js/lib/cjs/cipher.cjs:28:58)
      at processTicksAndRejections (node:internal/process/task_queues:96:5)

Create a wrapper connector for web3-react@6

Right now you have to manually write wrapper to use web3-react connectors with web client library. It'll be great if you provide some canonical solution for that.

Also it'll be good to have wrapper for web3-react@8

Upcoming Sapphire 0.6.0 allows Epoch to be specified, clients/js should support this

Re: oasis-sdk/pull/1420

The callformat.rs::CallEnvelopeX25519DeoxysII struct is expanded with an optional epoch parameter.

This allows encrypted calls to specify which epoch they are encrypting a transaction for, otherwise the endpoint will try the previous 2 epochs and fail if neither match.

Additionally an epoch parameters is returned from callDataPublicKey which will need to be returned by the Web3 gateway in https://github.com/oasisprotocol/oasis-web3-gateway/blob/main/rpc/oasis/api.go

type callDataPublicKeyQueryResponse struct {
	// PublicKey is the ephemeral X25519 runtime public key.
	PublicKey types.SignedPublicKey `json:"public_key"`
	// Epoch is the epoch of the ephemeral runtime key.
	Epoch uint64 `json:"epoch,omitempty"`
}

The result from the web3 gateway can be used by the JS & Go clients when encrypting transactions.

Sapphire precompiles in `hardhat node`

One of the benefits of having a Hardhat integration is that we can easily provide a fully featured Sapphire environment, including its precompiles. The precompiles that need to be implemented are (in rough order):

  • randomBytes
  • deriveSymmetricKey
  • decrypt
  • encrypt
  • verifyDigestSignature
  • signDigest

The first three are required by GSN.

Created contracts don't have valid addresses

Downstream components prefer for contract creation output to not be an encoded CallResult, so contract creation should return something that makes these components happy instead of whatever this is.

postMessage should return how much ROSE it would require to submit the cross-chain message

function postMessage(bytes memory _method, bytes memory _message) internal {

Without returning gas transferred to Celer MessageBus an Endpoint inheriting contract doesn't know how much it cost to send a message, so would be unable to charge a different user appropriately and rely on some external benevolent entity to ensure the contract has enough to pay for the relaying.

This could also cause havok if the contract is relaying messages to other chains and also trying to maintain an internal ROSE balance of external user deposits, the contracts internal accounting could have a mismatch of actual ROSE it holds vs how much it thinks it holds.

A temporary workaround would be to duplicate this code before calling postMessage, except txSeq is private so inaccessible to inheriting contracts:

        bytes memory envelope = abi.encodePacked(
            bytes4(keccak256(_method)),
            txSeq,
            _message
        );
        uint256 fee = estimateFee(envelope.length);

Linter for solidity code that points out privacy vulnerabilties

It's possible for MEV to exist if a contract produces observably non-constant execution based on the value of secret data. An inexperienced developer expecting a port of a complex dapp to Just Work™ can easily run into such issues. If there's a linter (particularly one integrated with the block explorer's contract verification), it's easier to spot vulnerable contracts.

This can likely be a plugin to solhint.

client: Runtime Public Key signature is not validated

The public key is returned from a call to oasis_callDataPublicKey to oasis-web3-gateway.

export async function fetchRuntimePublicKey(

Example response:

{
  'jsonrpc': '2.0',
  'id': 3892329,
  'result': {
    'key': '0xd46745ab3a8a8467cc97d57cdcdcdff9ad5a628a4fd4898dfe5c3db331fc1050',
    'checksum': '0x59dd7e7188b9736897ca719ece9dce6d9618e3f487553dccbc601ba848b65d9c',
    'signature': '0x99a5f80cdc6df788495ba36b0d652901d49869f7bb2ff94db83c2a4379f5e4d39c7e9c6ed21ef2e379fa882cfa490f4139af33e01e554280a30d7b7ef2f74d02'
  }
}

However, the signature provided by the Key Manager ( Sign(sk, key||checksum) ) which authenticates the validity of the Runtime public key is not checked.

This allows for the oasis-web3-gateway to MITM encrypted transaction data, which is bad!

Suggested Fix

The public key of the Key Manager must be known to the client library via a route independent of the web3-gateway, or can be provided by the web3-gateway if there is some kind of signature by a long-term trusted keypair hard-coded into the client library which can be used to validate authenticity of the Key Manager's public key.

Then the client must validate the signature before use, and must not submit encrypted transactions if validation fails.

This can be disabled for local testing nodes, but should be enabled on Testnet and must be enabled on Mainnet.

run-vigil.ts incompatible with hardhat 2.16 / ethers v6

When developer follows the tutorial at: https://docs.oasis.io/dapp/sapphire/quickstart

They encounter errors as the latest versions of hardhat, ethers etc. will be used.

The sapphire-paratime repo & examples aren't being tested with latest version of hardhat etc.

See: https://github.com/oasisprotocol/sapphire-paratime/blob/main/examples/hardhat/scripts/run-vigil.ts

Apparently to migrate to ethers v6:

  • replace vigil.address with vigil.getAddress()
  • replace callStatic.revealSecret(0) with revealSecret.staticCall(0)

I suggest running a weekly scheduled CI task which:

  • Acts as a canary, using whatever recent version is installed without specifying a version
  • Follows the general gist of the tutorial, running commands manually
  • Doesn't use packages.json or package log files

Celer MessageBus Contract Address on Sapphire production

SUMMARY

I believe the celer sapphire MessageBus has updated to 0x9B36f165baB9ebe611d491180418d8De4b8f3a1f but it says 0x9Bb46D5100d2Db4608112026951c9C965b233f4D in opl/Endpoint.sol

Reference:
https://im-docs.celer.network/developer/contract-addresses-and-rpc-info

ISSUE TYPE
  • Bug Report
STEPS TO REPRODUCE

reference docs

ACTUAL RESULTS

you would be using a different address for the MessageBus in production

EXPECTED RESULTS

You will be able to successfully use the celer IM protocol

Hardhat Signature problem - state doesn't change

I have a problem with hardhat testing contracts on the sapphire network.
I can't change the state of the already deployed smart contract with a combination when to use or when not to use sapphire.wrap.

To demonstrate my issue I have forked this repo and added some changes and scripts.

Before running please set env PRIVATE_KEY_TESTER beside PRIVATE_KEY.

This is the console output that I'm getting from \examples\hardhat-boilerplate\scripts\deploy-transfer.js

Deploying the contracts with the account: 0x84373E739d2c50eE55EF8a3AF7238f77804f83bF
Account balance: 6417194500000000000
Token address: 0x034BA58e63898205dCCf2dc57578Bb8fb930Bf08
Fauceting tester account: 0xC88309139e5809f4E736D700bB8Aca31540C67d8

And this is the console output that I'm getting from \examples\hardhat-boilerplate\scripts\test.js

Token address: 0x034BA58e63898205dCCf2dc57578Bb8fb930Bf08
Testing the contracts with the account: 0xC88309139e5809f4E736D700bB8Aca31540C67d8
1 - Check if tester account has enough ether
Tester account balance: 3995157700000000000
2 - Check if tester account has at least 100 tokens if he has't, send them from deployer account
Tester account token balance before transfer: 10
Tester account token balance after transfer: 10
3 - Check if tester account can transfer 10 token to deployer account
Tester account token balance before transfer: 10
Tester account token balance after transfer: 10

As you can see in test script I couldn't change the state of the smart contract even from the deployer signer which has worked on deploy-transfer script.

Same contract, and same test scenario works from the frontend example.

runtime: Update parameters before release

  • Use a more recent Testnet trust root with the correct runtime ID.
  • Set debug = false in Cargo.toml under package.metadata.fortanix-sgx.
  • Configure proper runtime IDs in Cargo.toml under package.metadata.orc.*.
  • Check if configured max_tx_size is ok.
  • Change version to 0.1.0-testnet.

Logs query error response, max allowed of rounds in logs query

We are trying to fetch all events emitted by a specific contract on sapphire. Usually, what we expect to do is something like the below snippet.

const Token = await ethers.getContractFactory("ERC20");
const token = Token.attach("0x0");
const events = await token.queryFilter(token.filters.Transfer());

events.forEach((event) => {
  const log = token.interface.parseLog(event);
  console.dir(log);
});

This would return all past Transfer events that happened with that contract. When we try to do that on the public testnet sapphire node we get an error message back invalid request: max allowed of rounds in logs query is: 100

next-dev.js?36dd:25 Error: processing response error (body="{\"jsonrpc\":\"2.0\",\"id\":52,\"error\":{\"code\":-32000,\"message\":\"invalid request: max allowed of rounds in logs query is: 100\"}}\n", error={"code":-32000}, requestBody="{\"method\":\"eth_getLogs\",\"params\":[{\"fromBlock\":\"0x0\",\"toBlock\":\"latest\",\"address\":\"0x5c17ccfa6e5856f1e47c07665f70c5dd8f2cb58d\",\"topics\":[\"0xb6f1a4da918525de56d3dfd92d3be4505f7dddead7d0da429c9786c923689494\"]}],\"id\":52,\"jsonrpc\":\"2.0\"}", requestMethod="POST", url="https://testnet.sapphire.oasis.dev", code=SERVER_ERROR, version=web/5.6.0)

After playing around and researching a bit, the error seems to be related to the number of blocks affected by the query. Doing the same query only 25 blocks at a time seems to do the trick. But doing this kind of paging is impractical. On other chains, we could do this easily with services like alchemy that would allow for historical event fetching, but this is not available on sapphire.

My question is: How can we query events with this kind of scope?

Any ideas are appreciated. Thanks!

client/js: Proof of concept: metamask/eth-json-rpc-middleware + sapphire.wrap = easier?

The metamask/eth-json-rpc-middleware project is used by a number of projects to make specific hooks, monitors, filters, extend functionality for web3 providers. It handles most of the complexity of hooking specific rpc functions.

The idea is to make a proof of concept version of sapphire.wrap which uses eth-json-rpc-middleware behind the scenes to implement Sapphire-specific handling while using an existing provider as an upstream, hopefully this could result in less code to handle edge cases with different providers/signers.

Make it easier to diagnose errors due to unsigned calls

When a signer is not provided, the call will be sent as unsigned. It's impossible to know whether the called function requires signing, and most don't, so this is a sane fallback. Unfortunately, the error message one receives when it fails is something like permission denied or worse, an empty value ("where did my tokens go?"). We should make it easier to notice when this happens.

Suggestions:

  • console.warn before sending an unsigned call
  • analyze the bytecode of the called function and throw an error if the function requires msg.sender equality

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.