Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/fix/verify-export-issue' into me…
Browse files Browse the repository at this point in the history
…rge/devconsea
  • Loading branch information
yuetloo committed Jun 5, 2024
2 parents 0b0947e + 65dc41b commit 8265745
Show file tree
Hide file tree
Showing 188 changed files with 4,767 additions and 2,911 deletions.
8 changes: 2 additions & 6 deletions .github/workflows/create-version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,14 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Checkout source code
uses: actions/checkout@v3
- name: Install dependencies
- name: Create new version
run: |
# use https to avoid error: unable to connect to github.com
git config --global url."https://".insteadOf git://
yarn && yarn build
- name: setup git config
run: |
# setup the username and email. I tend to use 'GitHub Actions Bot' with no email by default
git config user.name "GitHub Actions Bot"
git config user.email "<>"
- name: Create new version
run: |
yarn && yarn build
echo "Version: ${{ github.event.inputs.version }}"
cd contracts
npm version ${{ github.event.inputs.version }}
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/finalize-round.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ env:
CIRCUIT_TYPE: micro
ZKEYS_DOWNLOAD_SCRIPT: "download-6-9-2-3.sh"
JSONRPC_HTTP_URL: ${{ github.event.inputs.jsonrpc_url }}
PINATA_API_KEY: ${{ secrets.PINATA_API_KEY }}
PINATA_SECRET_API_KEY: ${{ secrets.PINATA_SECRET_API_KEY }}

jobs:
finalize:
Expand Down Expand Up @@ -84,10 +86,9 @@ jobs:
mkdir -p proof_output
yarn hardhat tally --clrfund "${CLRFUND_ADDRESS}" --network "${NETWORK}" \
--rapidsnark ${RAPID_SNARK} \
--circuit-directory ${CIRCUIT_DIRECTORY} \
--params-dir ${CIRCUIT_DIRECTORY} \
--blocks-per-batch ${BLOCKS_PER_BATCH} \
--maci-tx-hash "${MACI_TX_HASH}" --output-dir "./proof_output"
curl --location --request POST 'https://api.pinata.cloud/pinning/pinFileToIPFS' \
--header "Authorization: Bearer ${{ secrets.PINATA_JWT }}" \
--form 'file=@"./proof_output/tally.json"'
yarn hardhat --network "${NETWORK}" finalize --clrfund "${CLRFUND_ADDRESS}"
--maci-tx-hash "${MACI_TX_HASH}" \
--proof-dir "./proof_output"
yarn hardhat --network "${NETWORK}" finalize --clrfund "${CLRFUND_ADDRESS}" \
--proof-dir "./proof_output"
2 changes: 2 additions & 0 deletions .github/workflows/test-scripts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ on:
env:
NODE_VERSION: 20.x
ZKEYS_DOWNLOAD_SCRIPT: "download-6-9-2-3.sh"
PINATA_API_KEY: ${{ secrets.PINATA_API_KEY }}
PINATA_SECRET_API_KEY: ${{ secrets.PINATA_SECRET_API_KEY }}

jobs:
script-tests:
Expand Down
6 changes: 3 additions & 3 deletions common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
},
"dependencies": {
"@openzeppelin/merkle-tree": "^1.0.5",
"ethers": "^6.11.1",
"maci-crypto": "^1.2.0",
"maci-domainobjs": "^1.2.0"
"ethers": "^6.12.1",
"maci-crypto": "1.2.2",
"maci-domainobjs": "1.2.2"
},
"repository": {
"type": "git",
Expand Down
21 changes: 21 additions & 0 deletions common/src/__tests__/keypair.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { expect } from 'chai'
import { Keypair, PubKey } from '../keypair'
import { Wallet, sha256, randomBytes } from 'ethers'

describe('keypair', function () {
for (let i = 0; i < 10; i++) {
it(`should generate key ${i} from seed successfully`, function () {
const wallet = Wallet.createRandom()
const signature = wallet.signMessageSync(randomBytes(32).toString())
const seed = sha256(signature)
const keypair = Keypair.createFromSeed(seed)
expect(keypair.pubKey.serialize()).to.match(/^macipk./)
})
}

it('should throw if pubKey is invalid', () => {
expect(() => {
new PubKey([1n, 1n])
}).to.throw('PubKey not on curve')
})
})
38 changes: 16 additions & 22 deletions common/src/keypair.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,31 @@
import { keccak256, isBytesLike, concat, toBeArray } from 'ethers'
import { Keypair as MaciKeypair, PrivKey, PubKey } from 'maci-domainobjs'

const SNARK_FIELD_SIZE = BigInt(
'21888242871839275222246405745257275088548364400416034343698204186575808495617'
)

/**
* Returns a BabyJub-compatible value. This function is modified from
* the MACI's genRandomBabyJubValue(). Instead of returning random value
* for the private key, it derives the private key from the users
* signature hash
* Derives the MACI private key from the users signature hash
* @param hash - user's signature hash
* @return The MACI private key
*/
function genPrivKey(hash: string): PrivKey {
// Prevent modulo bias
//const lim = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000')
//const min = (lim - SNARK_FIELD_SIZE) % SNARK_FIELD_SIZE
const min = BigInt(
'6350874878119819312338956282401532410528162663560392320966563075034087161851'
)

if (!isBytesLike(hash)) {
throw new Error(`Hash must be a hex string: ${hash}`)
throw new Error(`genPrivKey() error. Hash must be a hex string: ${hash}`)
}

let hashBN = BigInt(hash)
// don't think we'll enter the for loop below, but, just in case
for (let counter = 1; hashBN < min; counter++) {
const data = concat([toBeArray(hashBN), toBeArray(counter)])
hashBN = BigInt(keccak256(data))
let rawPrivKey = BigInt(hash)
let pubKey: PubKey | null = null

for (let counter = 1; pubKey === null; counter++) {
try {
const privKey = new PrivKey(rawPrivKey)
// this will throw 'Invalid public key' if key is not on the Baby Jubjub elliptic curve
const keypair = new Keypair(privKey)
pubKey = keypair.pubKey
} catch {
const data = concat([toBeArray(rawPrivKey), toBeArray(counter)])
rawPrivKey = BigInt(keccak256(data))
}
}

const rawPrivKey = hashBN % SNARK_FIELD_SIZE
return new PrivKey(rawPrivKey)
}

Expand Down
16 changes: 13 additions & 3 deletions common/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import { Keypair } from './keypair'
import { Tally } from './tally'
import { bnSqrt } from './math'

const LEAVES_PER_NODE = 5
// This has to match the MACI TREE_ARITY at:
// github.com/privacy-scaling-explorations/maci/blob/0c18913d4c84bfa9fbfd66dc017e338df9fdda96/contracts/contracts/MACI.sol#L31
export const MACI_TREE_ARITY = 5

export function createMessage(
userStateIndex: number,
Expand Down Expand Up @@ -65,7 +67,7 @@ export function getRecipientClaimData(
const spentTree = new IncrementalQuinTree(
recipientTreeDepth,
BigInt(0),
LEAVES_PER_NODE,
MACI_TREE_ARITY,
hash5
)
for (const leaf of tally.perVOSpentVoiceCredits.tally) {
Expand Down Expand Up @@ -94,6 +96,15 @@ export function getRecipientClaimData(
]
}

/**
* Returns the maximum MACI users allowed by the state tree
* @param stateTreeDepth MACI state tree depth
* @returns the maximum number of contributors allowed by MACI circuit
*/
export function getMaxContributors(stateTreeDepth: number): number {
return MACI_TREE_ARITY ** stateTreeDepth - 1
}

export {
genTallyResultCommitment,
Message,
Expand All @@ -103,5 +114,4 @@ export {
hash2,
hash3,
hashLeftRight,
LEAVES_PER_NODE,
}
6 changes: 5 additions & 1 deletion contracts/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ JSONRPC_HTTP_URL=https://eth-goerli.alchemyapi.io/v2/ADD_API_KEY
WALLET_MNEMONIC=
WALLET_PRIVATE_KEY=

# The coordinator MACI private key, required by the tally script
# The coordinator MACI private key, required by the gen-proofs script
COORDINATOR_MACISK=

# API key used to verify contracts on arbitrum chain (including testnet)
# Update the etherscan section in hardhat.config to add API key for other chains
ARBISCAN_API_KEY=

# PINATE credentials to upload tally.json file to IPFS; used by the tally script
PINATA_API_KEY=
PINATA_SECRET_API_KEY=

# these are used in the e2e testing
CIRCUIT_TYPE=
CIRCUIT_DIRECTORY=
Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/AnyOldERC20Token.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.10;
pragma solidity 0.8.20;

import '@openzeppelin/contracts/token/ERC20/ERC20.sol';

Expand Down
2 changes: 1 addition & 1 deletion contracts/contracts/CloneFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

pragma solidity 0.8.10;
pragma solidity 0.8.20;

contract CloneFactory { // implementation of eip-1167 - see https://eips.ethereum.org/EIPS/eip-1167
function createClone(address target) internal returns (address result) {
Expand Down
35 changes: 15 additions & 20 deletions contracts/contracts/ClrFund.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;
pragma solidity 0.8.20;

import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
Expand Down Expand Up @@ -60,8 +60,14 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params {
error InvalidFundingRoundFactory();
error InvalidMaciFactory();
error RecipientRegistryNotSet();
error MaxRecipientsNotSet();
error NotInitialized();
error VoteOptionTreeDepthNotSet();

modifier maciFactoryInitialized() {
if (address(maciFactory) == address(0)) revert InvalidMaciFactory();
if (maciFactory.maxRecipients() == 0) revert MaxRecipientsNotSet();
_;
}


/**
Expand Down Expand Up @@ -128,20 +134,6 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params {
_setFundingRoundFactory(_roundFactory);
}

/**
* @dev Get the maximum recipients allowed in the recipient registry
*/
function getMaxRecipients() public view returns (uint256 _maxRecipients) {
TreeDepths memory treeDepths = maciFactory.treeDepths();
if (treeDepths.voteOptionTreeDepth == 0) revert VoteOptionTreeDepthNotSet();

uint256 maxVoteOption = maciFactory.TREE_ARITY() ** treeDepths.voteOptionTreeDepth;

// -1 because the first slot of the recipients array is not used
// and maxRecipients is used to generate 0 based index to the array
_maxRecipients = maxVoteOption - 1;
}

/**
* @dev Set registry of verified users.
* @param _userRegistry Address of a user registry.
Expand All @@ -162,10 +154,13 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params {
function setRecipientRegistry(IRecipientRegistry _recipientRegistry)
external
onlyOwner
maciFactoryInitialized
{

recipientRegistry = _recipientRegistry;
uint256 maxRecipients = getMaxRecipients();
recipientRegistry.setMaxRecipients(maxRecipients);

// Make sure that the max number of recipients is set correctly
recipientRegistry.setMaxRecipients(maciFactory.maxRecipients());

emit RecipientRegistryChanged(address(_recipientRegistry));
}
Expand Down Expand Up @@ -220,6 +215,7 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params {
)
external
onlyOwner
maciFactoryInitialized
{
IFundingRound currentRound = getCurrentRound();
if (address(currentRound) != address(0) && !currentRound.isFinalized()) {
Expand All @@ -229,8 +225,7 @@ contract ClrFund is OwnableUpgradeable, DomainObjs, Params {
if (address(recipientRegistry) == address(0)) revert RecipientRegistryNotSet();

// Make sure that the max number of recipients is set correctly
uint256 maxRecipients = getMaxRecipients();
recipientRegistry.setMaxRecipients(maxRecipients);
recipientRegistry.setMaxRecipients(maciFactory.maxRecipients());

// Deploy funding round and MACI contracts
address newRound = roundFactory.deploy(duration, address(this));
Expand Down
4 changes: 2 additions & 2 deletions contracts/contracts/ClrFundDeployer.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.10;
pragma solidity 0.8.20;

import {MACIFactory} from './MACIFactory.sol';
import {ClrFund} from './ClrFund.sol';
Expand All @@ -9,7 +9,7 @@ import {SignUpGatekeeper} from "maci-contracts/contracts/gatekeepers/SignUpGatek
import {InitialVoiceCreditProxy} from "maci-contracts/contracts/initialVoiceCreditProxy/InitialVoiceCreditProxy.sol";
import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';

contract ClrFundDeployer is CloneFactory, Ownable {
contract ClrFundDeployer is CloneFactory, Ownable(msg.sender) {
address public clrfundTemplate;
address public maciFactory;
address public roundFactory;
Expand Down
3 changes: 1 addition & 2 deletions contracts/contracts/ExternalContacts.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.10;
pragma solidity 0.8.20;

/*
* These imports are just for hardhat to find the contracts for deployment
Expand All @@ -9,5 +9,4 @@ pragma solidity ^0.8.10;
import {Poll} from 'maci-contracts/contracts/Poll.sol';
import {PollFactory} from 'maci-contracts/contracts/PollFactory.sol';
import {TallyFactory} from 'maci-contracts/contracts/TallyFactory.sol';
import {SubsidyFactory} from 'maci-contracts/contracts/SubsidyFactory.sol';
import {MessageProcessorFactory} from 'maci-contracts/contracts/MessageProcessorFactory.sol';
Loading

0 comments on commit 8265745

Please sign in to comment.