Skip to content

Commit

Permalink
Convert to upgradeable contracts
Browse files Browse the repository at this point in the history
Signed-off-by: Jim Zhang <jim.zhang@kaleido.io>
  • Loading branch information
jimthematrix committed Aug 20, 2024
1 parent 9776b53 commit 9d40e02
Show file tree
Hide file tree
Showing 56 changed files with 2,052 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
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 authority
) ERC20("Sample ERC20 token", "SampleERC20") Ownable(authority) {
_mint(msg.sender, 1000000 * 10 ** 18);
}

Expand Down
79 changes: 79 additions & 0 deletions solidity/contracts/factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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 {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {IZetoFungible} from "./lib/interfaces/zeto_fungible.sol";
import {IZetoFungibleInitializable} from "./lib/interfaces/zeto_fungible_initializable.sol";
import {IZetoNonFungibleInitializable} from "./lib/interfaces/zeto_nf_initializable.sol";
import {SampleERC20} from "./erc20.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 authority,
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(
authority,
_depositVerifier,
_withdrawVerifier,
_verifier
);
emit ZetoTokenDeployed(instance);
return instance;
}

function deployZetoNonFungibleToken(
string memory name,
address authority,
address _verifier
) public returns (address) {
address instance = Clones.clone(implementations[name]);
require(
instance != address(0),
"Factory: failed to find implementation"
);
(IZetoNonFungibleInitializable(instance)).initialize(
authority,
_verifier
);
emit ZetoTokenDeployed(instance);
return instance;
}
}
22 changes: 22 additions & 0 deletions solidity/contracts/lib/interfaces/zeto_fungible.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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 {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IZetoFungible {
function setERC20(IERC20 _erc20) external;
}
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 authority,
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 authority, 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 authority) internal onlyInitializing {
__ZetoCommon_init(authority);
}

/// @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 authority) internal onlyInitializing {
__Ownable_init(authority);
}

// 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
9 changes: 6 additions & 3 deletions solidity/contracts/lib/zeto_fungible.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,24 @@ pragma solidity ^0.8.20;
import {Groth16Verifier_CheckHashesValue} from "./verifier_check_hashes_value.sol";
import {Groth16Verifier_CheckNullifierValue} from "./verifier_check_nullifier_value.sol";
import {Commonlib} from "./common.sol";
import {IZetoFungible} from "./interfaces/zeto_fungible.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 IZetoFungible, 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
3 changes: 2 additions & 1 deletion solidity/contracts/lib/zeto_nullifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ abstract contract ZetoNullifier is ZetoCommon {

error UTXORootNotFound(uint256 root);

constructor() ZetoCommon() {
function __ZetoNullifier_init(address authority) internal onlyInitializing {
__ZetoCommon_init(authority);
_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 authority,
Groth16Verifier_CheckHashesValue _depositVerifier,
Groth16Verifier_CheckInputsOutputsValue _withdrawVerifier,
Groth16Verifier_Anon _verifier
) ZetoBase() ZetoFungibleWithdraw(_depositVerifier, _withdrawVerifier) {
) public initializer {
__ZetoBase_init(authority);
__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 authority,
Groth16Verifier_CheckHashesValue _depositVerifier,
Groth16Verifier_CheckInputsOutputsValue _withdrawVerifier,
Groth16Verifier_AnonEnc _verifier
) ZetoBase() ZetoFungibleWithdraw(_depositVerifier, _withdrawVerifier) {
) public initializer {
__ZetoBase_init(authority);
__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 9d40e02

Please sign in to comment.