Skip to content

Commit

Permalink
Merge pull request #43 from hyperledger-labs/upgradeable
Browse files Browse the repository at this point in the history
Convert to upgradeable and cloneable contracts
  • Loading branch information
jimthematrix authored Aug 22, 2024
2 parents dfecf4d + be9e994 commit 3b7a354
Show file tree
Hide file tree
Showing 56 changed files with 2,050 additions and 594 deletions.
12 changes: 11 additions & 1 deletion .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,21 @@ jobs:
npm install
npm run test:e2e
- name: Run Zeto Tokens hardhat tests
- name: Run Zeto Tokens hardhat tests as upgradeable contracts
env:
PROVING_KEYS_ROOT: ${{ runner.temp }}/zeto-artifacts
CIRCUITS_ROOT: ${{ runner.temp }}/zeto-artifacts
working-directory: solidity
run: |
npm install
npm t
- name: Run Zeto Tokens hardhat tests as cloned contracts
env:
USE_FACTORY: true
PROVING_KEYS_ROOT: ${{ runner.temp }}/zeto-artifacts
CIRCUITS_ROOT: ${{ runner.temp }}/zeto-artifacts
working-directory: solidity
run: |
npm install
npm t
3 changes: 2 additions & 1 deletion solidity/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
node_modules
artifacts
cache
typechain-types
typechain-types
ignition/deployments
18 changes: 18 additions & 0 deletions solidity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,24 @@ This project contains sample implementations of privacy preserving tokens for bo

The Hardhat test cases make use of the `zeto-js` library, which must be built first. Refer to the steps in [the library's README](/zkp/js/README.md#build) to build the proving keys, and verification keys. Make sure you can successfully run the unit tests for the zeto-js library, before returning back here to continue with the hardhat tests for the Solidity implementation.

# Deploy Zeto Token Contracts

Zeto token contracts are all upgradeable contracts. They can be deployed with one of the two hardhat scripts:

- [deploy_upgradeable](/solidity/scripts/deploy_upgradeable.ts): Deploys the target contract, designated by the `ZETO_NAME` environment variable, as a [UUPSUpgradeable contract](https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent-vs-uups).

```console
export ZETO_NAME=Zeto_AnonEncNullifier
npx hardhat run scripts/deploy_upgradeable.js
```

- [deploy_cloneable](/solidity/scripts/deploy_cloneable.ts): Deploys the target contract, designated by the `ZETO_NAME` environment variable, as a [cloneable contract](https://blog.openzeppelin.com/workshop-recap-cheap-contract-deployment-through-clones).

```console
export ZETO_NAME=Zeto_AnonEncNullifier
npx hardhat run scripts/deploy_cloneable.js
```

# Run The Hardhat Tests

Once the above pre-reqs are complete, you can proceed to run the hardhat tests in this project.
Expand Down
7 changes: 3 additions & 4 deletions solidity/contracts/erc20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ import "hardhat/console.sol";
/// - the hashes in the input and output match the `hash(value, salt, owner public key)` formula
/// - the sender possesses the private BabyJubjub key, whose public key is part of the pre-image of the input commitment hashes
contract SampleERC20 is ERC20, Ownable {
constructor()
ERC20("Sample ERC20 token", "SampleERC20")
Ownable(msg.sender)
{
constructor(
address initialOwner
) ERC20("Sample ERC20 token", "SampleERC20") Ownable(initialOwner) {
_mint(msg.sender, 1000000 * 10 ** 18);
}

Expand Down
75 changes: 75 additions & 0 deletions solidity/contracts/factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright © 2024 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pragma solidity ^0.8.20;

import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {IZetoFungibleInitializable} from "./lib/interfaces/zeto_fungible_initializable.sol";
import {IZetoNonFungibleInitializable} from "./lib/interfaces/zeto_nf_initializable.sol";

contract ZetoTokenFactory {
event ZetoTokenDeployed(address indexed zetoToken);

mapping(string => address) internal implementations;

constructor() {}

function registerImplementation(
string memory name,
address implementation
) public {
implementations[name] = implementation;
}

function deployZetoFungibleToken(
string memory name,
address initialOwner,
address _depositVerifier,
address _withdrawVerifier,
address _verifier
) public returns (address) {
address instance = Clones.clone(implementations[name]);
require(
instance != address(0),
"Factory: failed to find implementation"
);
(IZetoFungibleInitializable(instance)).initialize(
initialOwner,
_depositVerifier,
_withdrawVerifier,
_verifier
);
emit ZetoTokenDeployed(instance);
return instance;
}

function deployZetoNonFungibleToken(
string memory name,
address initialOwner,
address _verifier
) public returns (address) {
address instance = Clones.clone(implementations[name]);
require(
instance != address(0),
"Factory: failed to find implementation"
);
(IZetoNonFungibleInitializable(instance)).initialize(
initialOwner,
_verifier
);
emit ZetoTokenDeployed(instance);
return instance;
}
}
25 changes: 25 additions & 0 deletions solidity/contracts/lib/interfaces/zeto_fungible_initializable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © 2024 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pragma solidity ^0.8.20;

interface IZetoFungibleInitializable {
function initialize(
address initialOwner,
address _depositVerifier,
address _withdrawVerifier,
address _verifier
) external;
}
20 changes: 20 additions & 0 deletions solidity/contracts/lib/interfaces/zeto_nf_initializable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright © 2024 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pragma solidity ^0.8.20;

interface IZetoNonFungibleInitializable {
function initialize(address initialOwner, address _verifier) external;
}
5 changes: 3 additions & 2 deletions solidity/contracts/lib/registry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// limitations under the License.
pragma solidity ^0.8.20;

import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {SmtLib} from "@iden3/contracts/lib/SmtLib.sol";
import {PoseidonUnit2L, PoseidonUnit3L} from "@iden3/contracts/lib/Poseidon.sol";
import {Commonlib} from "./common.sol";
Expand All @@ -28,15 +29,15 @@ uint256 constant MAX_SMT_DEPTH = 64;
/// submitters can generate proofs of membership for the
/// accounts in a privacy-preserving manner.
/// @author Kaleido, Inc.
abstract contract Registry {
abstract contract Registry is OwnableUpgradeable {
SmtLib.Data internal _publicKeysTree;
using SmtLib for SmtLib.Data;

event IdentityRegistered(uint256[2] publicKey);

error AlreadyRegistered(uint256[2]);

constructor() {
function __Registry_init() internal onlyInitializing {
_publicKeysTree.initialize(MAX_SMT_DEPTH);
}

Expand Down
4 changes: 3 additions & 1 deletion solidity/contracts/lib/zeto_base.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ abstract contract ZetoBase is ZetoCommon {
// maintains all the UTXOs
mapping(uint256 => UTXOStatus) internal _utxos;

constructor() ZetoCommon() {}
function __ZetoBase_init(address initialOwner) internal onlyInitializing {
__ZetoCommon_init(initialOwner);
}

/// @dev query whether a UTXO is currently spent
/// @return bool whether the UTXO is spent
Expand Down
7 changes: 5 additions & 2 deletions solidity/contracts/lib/zeto_common.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ pragma solidity ^0.8.20;

import {Commonlib} from "./common.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

/// @title A sample base implementation of a Zeto based token contract
/// @author Kaleido, Inc.
/// @dev Implements common functionalities of Zeto based tokens
abstract contract ZetoCommon is Ownable {
abstract contract ZetoCommon is OwnableUpgradeable {
event UTXOMint(uint256[] outputs, address indexed submitter);

event UTXOTransfer(
Expand Down Expand Up @@ -51,7 +52,9 @@ abstract contract ZetoCommon is Ownable {
// that did the locking.
mapping(bytes32 => address) internal lockedProofs;

constructor() Ownable(msg.sender) {}
function __ZetoCommon_init(address initialOwner) internal onlyInitializing {
__Ownable_init(initialOwner);
}

// should be called by escrow contracts that will use uploaded proofs
// to execute transactions, in order to prevent the proof from being used
Expand Down
8 changes: 5 additions & 3 deletions solidity/contracts/lib/zeto_fungible.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,22 @@ import {Groth16Verifier_CheckHashesValue} from "./verifier_check_hashes_value.so
import {Groth16Verifier_CheckNullifierValue} from "./verifier_check_nullifier_value.sol";
import {Commonlib} from "./common.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

/// @title A sample implementation of a base Zeto fungible token contract
/// @author Kaleido, Inc.
/// @dev Defines the verifier library for checking UTXOs against a claimed value.
abstract contract ZetoFungible is Ownable {
abstract contract ZetoFungible is OwnableUpgradeable {
// depositVerifier library for checking UTXOs against a claimed value.
// this can be used in the optional deposit calls to verify that
// the UTXOs match the deposited value
Groth16Verifier_CheckHashesValue internal depositVerifier;

IERC20 internal erc20;

constructor(Groth16Verifier_CheckHashesValue _depositVerifier) {
function __ZetoFungible_init(
Groth16Verifier_CheckHashesValue _depositVerifier
) public onlyInitializing {
depositVerifier = _depositVerifier;
}

Expand Down
6 changes: 3 additions & 3 deletions solidity/contracts/lib/zeto_fungible_withdraw.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {Groth16Verifier_CheckInputsOutputsValue} from "./verifier_check_inputs_o
import {ZetoFungible} from "./zeto_fungible.sol";
import {Commonlib} from "./common.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

/// @title A sample implementation of a base Zeto fungible token contract
/// @author Kaleido, Inc.
Expand All @@ -31,10 +30,11 @@ abstract contract ZetoFungibleWithdraw is ZetoFungible {
// match the withdrawn value
Groth16Verifier_CheckInputsOutputsValue internal withdrawVerifier;

constructor(
function __ZetoFungibleWithdraw_init(
Groth16Verifier_CheckHashesValue _depositVerifier,
Groth16Verifier_CheckInputsOutputsValue _withdrawVerifier
) ZetoFungible(_depositVerifier) {
) public onlyInitializing {
__ZetoFungible_init(_depositVerifier);
withdrawVerifier = _withdrawVerifier;
}

Expand Down
5 changes: 3 additions & 2 deletions solidity/contracts/lib/zeto_fungible_withdraw_nullifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ abstract contract ZetoFungibleWithdrawWithNullifiers is ZetoFungible {
// match the withdrawn value
Groth16Verifier_CheckNullifierValue internal withdrawVerifier;

constructor(
function __ZetoFungibleWithdrawWithNullifiers_init(
Groth16Verifier_CheckHashesValue _depositVerifier,
Groth16Verifier_CheckNullifierValue _withdrawVerifier
) ZetoFungible(_depositVerifier) {
) internal onlyInitializing {
__ZetoFungible_init(_depositVerifier);
withdrawVerifier = _withdrawVerifier;
}

Expand Down
5 changes: 4 additions & 1 deletion solidity/contracts/lib/zeto_nullifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ abstract contract ZetoNullifier is ZetoCommon {

error UTXORootNotFound(uint256 root);

constructor() ZetoCommon() {
function __ZetoNullifier_init(
address initialOwner
) internal onlyInitializing {
__ZetoCommon_init(initialOwner);
_commitmentsTree.initialize(MAX_SMT_DEPTH);
}

Expand Down
12 changes: 9 additions & 3 deletions solidity/contracts/zeto_anon.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {ZetoBase} from "./lib/zeto_base.sol";
import {ZetoFungible} from "./lib/zeto_fungible.sol";
import {ZetoFungibleWithdraw} from "./lib/zeto_fungible_withdraw.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "hardhat/console.sol";

/// @title A sample implementation of a Zeto based fungible token with anonymity and no encryption
Expand All @@ -33,17 +34,22 @@ import "hardhat/console.sol";
/// - the sum of the input values match the sum of output values
/// - the hashes in the input and output match the `hash(value, salt, owner public key)` formula
/// - the sender possesses the private BabyJubjub key, whose public key is part of the pre-image of the input commitment hashes
contract Zeto_Anon is ZetoBase, ZetoFungibleWithdraw {
contract Zeto_Anon is ZetoBase, ZetoFungibleWithdraw, UUPSUpgradeable {
Groth16Verifier_Anon internal verifier;

constructor(
function initialize(
address initialOwner,
Groth16Verifier_CheckHashesValue _depositVerifier,
Groth16Verifier_CheckInputsOutputsValue _withdrawVerifier,
Groth16Verifier_Anon _verifier
) ZetoBase() ZetoFungibleWithdraw(_depositVerifier, _withdrawVerifier) {
) public initializer {
__ZetoBase_init(initialOwner);
__ZetoFungibleWithdraw_init(_depositVerifier, _withdrawVerifier);
verifier = _verifier;
}

function _authorizeUpgrade(address) internal override onlyOwner {}

/**
* @dev the main function of the contract.
*
Expand Down
12 changes: 9 additions & 3 deletions solidity/contracts/zeto_anon_enc.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {ZetoFungible} from "./lib/zeto_fungible.sol";
import {Registry} from "./lib/registry.sol";
import {Commonlib} from "./lib/common.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "hardhat/console.sol";

/// @title A sample implementation of a Zeto based fungible token with anonymity, and encryption
Expand All @@ -35,17 +36,22 @@ import "hardhat/console.sol";
/// - the sender possesses the private BabyJubjub key, whose public key is part of the pre-image of the input commitment hashes
/// - the encrypted value in the input is derived from the receiver's UTXO value and encrypted with a shared secret using
/// the ECDH protocol between the sender and receiver (this guarantees data availability for the receiver)
contract Zeto_AnonEnc is ZetoBase, ZetoFungibleWithdraw {
contract Zeto_AnonEnc is ZetoBase, ZetoFungibleWithdraw, UUPSUpgradeable {
Groth16Verifier_AnonEnc internal verifier;

constructor(
function initialize(
address initialOwner,
Groth16Verifier_CheckHashesValue _depositVerifier,
Groth16Verifier_CheckInputsOutputsValue _withdrawVerifier,
Groth16Verifier_AnonEnc _verifier
) ZetoBase() ZetoFungibleWithdraw(_depositVerifier, _withdrawVerifier) {
) public initializer {
__ZetoBase_init(initialOwner);
__ZetoFungibleWithdraw_init(_depositVerifier, _withdrawVerifier);
verifier = _verifier;
}

function _authorizeUpgrade(address) internal override onlyOwner {}

/**
* @dev the main function of the contract.
*
Expand Down
Loading

0 comments on commit 3b7a354

Please sign in to comment.