diff --git a/.github/workflows/test-scripts.yml b/.github/workflows/test-scripts.yml
index 41937c33d..bb3b38612 100644
--- a/.github/workflows/test-scripts.yml
+++ b/.github/workflows/test-scripts.yml
@@ -29,13 +29,24 @@ jobs:
- name: Install zkutil
run: |
cargo install zkutil --version 0.3.2
+ - name: Checkout rapidsnark source code
+ uses: actions/checkout@v3
+ with:
+ repository: iden3/rapidsnark
+ path: rapidsnark
+ - name: Install rapidsnark
+ npm install
+ git submodule init
+ git submodule update
+ npx task createFieldSources
+ npx task buildProver
- name: Checkout source code
uses: actions/checkout@v3
with:
path: monorepo
- name: Download batch 64 params
run: |
- $GITHUB_WORKSPACE/monorepo/.github/scripts/download-batch64-params.sh
+ $GITHUB_WORKSPACE/monorepo/.github/scripts/download-6-8-2-3.sh
- name: Build CLR
run: |
cd monorepo
@@ -48,14 +59,6 @@ jobs:
yarn start:node &
- name: Run script tests
run: |
+ export RAPIDSNARK_DIRECTORY=$GITHUB_WORKSPACE/rapidsnark
cd monorepo/contracts
- export NODE_CONFIG=$(node -e "const snarkParamsPath=process.env.GITHUB_WORKSPACE + '/params'; console.log(JSON.stringify({ snarkParamsPath }));")
- echo $NODE_CONFIG
- yarn deploy:local
- yarn deployTestRound:local
- yarn contribute:local
- yarn vote:local
- yarn hardhat evm-increase-time 1200 --network localhost
- yarn tally:local
- yarn finalize:local
- yarn claim:local
+ ./sh/runScriptTests.sh
diff --git a/contracts/.env.example b/contracts/.env.example
index c3c9355ba..5c61baf56 100644
--- a/contracts/.env.example
+++ b/contracts/.env.example
@@ -23,7 +23,7 @@ WALLET_PRIVATE_KEY=
NATIVE_TOKEN_ADDRESS=
# Required to use in the tally and finalize scripts
-FACTORY_ADDRESS=
+CLRFUND=
ROUND_ADDRESS=
COORDINATOR_PK=
COORDINATOR_ETH_PK=
@@ -50,7 +50,15 @@ CIRCUIT_TYPE=prod
# The IPFS gateway url used by the prepare-results.ts script
IPFS_GATEWAY_URL=
-# circuit params and directory used by e2e script
+# Parameters used in the tally script
CIRCUIT_TYPE=
CIRCUIT_DIRECTORY=
RAPIDSNARK_DIRECTORY=
+# Used in MACI queue merging operation before genProofs, default is 4
+NUM_QUEUE_OPS=
+# Used in e2e testing to store intermediate states
+STATE_FILE=
+# MACI creation transaction hash, used to find the start block of MACI logs
+MACI_TRANSACTION_HASH=
+# genProofs output directory
+PROOF_OUTPUT_DIR=
diff --git a/contracts/.gitignore b/contracts/.gitignore
index b68456558..0f8b3e642 100644
--- a/contracts/.gitignore
+++ b/contracts/.gitignore
@@ -7,5 +7,5 @@ proofs.json
tally.json
.env
.DS_Store
-tasks/addresses.txt
+addresses.txt
proof_output
diff --git a/contracts/contracts/ClrFund.sol b/contracts/contracts/ClrFund.sol
index 21a0a5bb2..eaf988db7 100644
--- a/contracts/contracts/ClrFund.sol
+++ b/contracts/contracts/ClrFund.sol
@@ -16,6 +16,8 @@ import './userRegistry/IUserRegistry.sol';
import './recipientRegistry/IRecipientRegistry.sol';
import {FundingRound} from './FundingRound.sol';
import './OwnableUpgradeable.sol';
+import {FundingRoundFactory} from './FundingRoundFactory.sol';
+import {TopupToken} from './TopupToken.sol';
contract ClrFund is OwnableUpgradeable, IPubKey, SnarkCommon, Params {
using EnumerableSet for EnumerableSet.AddressSet;
@@ -33,6 +35,8 @@ contract ClrFund is OwnableUpgradeable, IPubKey, SnarkCommon, Params {
EnumerableSet.AddressSet private fundingSources;
FundingRound[] private rounds;
+ FundingRoundFactory public roundFactory;
+
// Events
event FundingSourceAdded(address _source);
event FundingSourceRemoved(address _source);
@@ -40,6 +44,10 @@ contract ClrFund is OwnableUpgradeable, IPubKey, SnarkCommon, Params {
event RoundFinalized(address _round);
event TokenChanged(address _token);
event CoordinatorChanged(address _coordinator);
+ event Initialized();
+ event UserRegistrySet();
+ event RecipientRegistrySet();
+ event FundingRoundTemplateChanged();
// errors
error FundingSourceAlreadyAdded();
@@ -53,14 +61,27 @@ contract ClrFund is OwnableUpgradeable, IPubKey, SnarkCommon, Params {
error NoRecipientRegistry();
error NoUserRegistry();
error NotOwnerOfMaciFactory();
+ error InvalidFundingRoundFactory();
+ error InvalidMaciFactory();
+ /**
+ * @dev Initialize clrfund instance with MACI factory and new round templates
+ */
function init(
- MACIFactory _maciFactory
+ address _maciFactory,
+ address _roundFactory
)
external
{
__Ownable_init();
- maciFactory = _maciFactory;
+
+ if (address(_maciFactory) == address(0)) revert InvalidMaciFactory();
+ if (_roundFactory == address(0)) revert InvalidFundingRoundFactory();
+
+ maciFactory = MACIFactory(_maciFactory);
+ roundFactory = FundingRoundFactory(_roundFactory);
+
+ emit Initialized();
}
/**
@@ -72,6 +93,8 @@ contract ClrFund is OwnableUpgradeable, IPubKey, SnarkCommon, Params {
onlyOwner
{
userRegistry = _userRegistry;
+
+ emit UserRegistrySet();
}
/**
@@ -85,6 +108,8 @@ contract ClrFund is OwnableUpgradeable, IPubKey, SnarkCommon, Params {
recipientRegistry = _recipientRegistry;
(, uint256 maxVoteOptions) = maciFactory.maxValues();
recipientRegistry.setMaxRecipients(maxVoteOptions);
+
+ emit RecipientRegistrySet();
}
/**
@@ -150,18 +175,20 @@ contract ClrFund is OwnableUpgradeable, IPubKey, SnarkCommon, Params {
(, uint256 maxVoteOptions) = maciFactory.maxValues();
recipientRegistry.setMaxRecipients(maxVoteOptions);
// Deploy funding round and MACI contracts
- FundingRound newRound = new FundingRound(
+ FundingRound newRound = roundFactory.deploy(
nativeToken,
userRegistry,
recipientRegistry,
- coordinator
+ coordinator,
+ address(this)
);
rounds.push(newRound);
+ TopupToken topupToken = newRound.topupToken();
MACI maci = maciFactory.deployMaci(
SignUpGatekeeper(newRound),
InitialVoiceCreditProxy(newRound),
- address(nativeToken),
+ address(topupToken),
duration,
coordinator,
coordinatorPubKey
diff --git a/contracts/contracts/ClrFundDeployer.sol b/contracts/contracts/ClrFundDeployer.sol
index b7d2707a0..8db5bc7fd 100644
--- a/contracts/contracts/ClrFundDeployer.sol
+++ b/contracts/contracts/ClrFundDeployer.sol
@@ -2,46 +2,85 @@
pragma solidity 0.8.10;
-import './MACIFactory.sol';
-import './ClrFund.sol';
+import {MACIFactory} from './MACIFactory.sol';
+import {ClrFund} from './ClrFund.sol';
import {CloneFactory} from './CloneFactory.sol';
import {SignUpGatekeeper} from "@clrfund/maci-contracts/contracts/gatekeepers/SignUpGatekeeper.sol";
import {InitialVoiceCreditProxy} from "@clrfund/maci-contracts/contracts/initialVoiceCreditProxy/InitialVoiceCreditProxy.sol";
+import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
-contract ClrFundDeployer is CloneFactory {
+contract ClrFundDeployer is CloneFactory, Ownable {
+ address public clrfundTemplate;
+ address public maciFactory;
+ address public roundFactory;
+ mapping (address => bool) public clrfunds;
- address public template;
- mapping (address => bool) public clrfunds;
+ event NewInstance(address indexed clrfund);
+ event Register(address indexed clrfund, string metadata);
+ event NewFundingRoundTemplate(address newTemplate);
+ event NewClrfundTemplate(address newTemplate);
- constructor(address _template) {
- template = _template;
- }
-
- event NewInstance(address indexed clrfund);
- event Register(address indexed clrfund, string metadata);
+ // errors
+ error ClrFundAlreadyRegistered();
+ error InvalidMaciFactory();
+ error InvalidClrFundTemplate();
+ error InvalidFundingRoundFactory();
- // errors
- error ClrFundAlreadyRegistered();
+ constructor(
+ address _clrfundTemplate,
+ address _maciFactory,
+ address _roundFactory
+ )
+ {
+ if (_clrfundTemplate == address(0)) revert InvalidClrFundTemplate();
+ if (_maciFactory == address(0)) revert InvalidMaciFactory();
+ if (_roundFactory == address(0)) revert InvalidFundingRoundFactory();
- function deployClrFund(MACIFactory _maciFactory) public returns (address) {
+ clrfundTemplate = _clrfundTemplate;
+ maciFactory = _maciFactory;
+ roundFactory = _roundFactory;
+ }
- ClrFund clrfund = ClrFund(createClone(template));
- clrfund.init(_maciFactory);
- emit NewInstance(address(clrfund));
+ /**
+ * @dev Set a new clrfund template
+ * @param _clrfundTemplate New template
+ */
+ function setClrFundTemplate(address _clrfundTemplate)
+ external
+ onlyOwner
+ {
+ if (_clrfundTemplate == address(0)) revert InvalidClrFundTemplate();
- return address(clrfund);
- }
-
- function registerInstance(
- address _clrFundAddress,
- string memory _metadata
- ) public returns (bool) {
+ clrfundTemplate = _clrfundTemplate;
+ emit NewClrfundTemplate(_clrfundTemplate);
+ }
- if (clrfunds[_clrFundAddress] == true) revert ClrFundAlreadyRegistered();
+ /**
+ * @dev Deploy a new instance of ClrFund
+ */
+ function deployClrFund() public returns (address) {
+ ClrFund clrfund = ClrFund(createClone(clrfundTemplate));
+ clrfund.init(maciFactory, roundFactory);
+ emit NewInstance(address(clrfund));
- clrfunds[_clrFundAddress] = true;
+ return address(clrfund);
+ }
- emit Register(_clrFundAddress, _metadata);
- return true;
- }
+ /**
+ * @dev Register the clrfund instance of subgraph event processing
+ * @param _clrFundAddress ClrFund address
+ * @param _metadata Clrfund metadata
+ */
+ function registerInstance(
+ address _clrFundAddress,
+ string memory _metadata
+ ) public returns (bool) {
+
+ if (clrfunds[_clrFundAddress] == true) revert ClrFundAlreadyRegistered();
+
+ clrfunds[_clrFundAddress] = true;
+
+ emit Register(_clrFundAddress, _metadata);
+ return true;
+ }
}
diff --git a/contracts/contracts/FundingRound.sol b/contracts/contracts/FundingRound.sol
index efc98c230..a4f465a39 100644
--- a/contracts/contracts/FundingRound.sol
+++ b/contracts/contracts/FundingRound.sol
@@ -10,6 +10,7 @@ import {DomainObjs} from '@clrfund/maci-contracts/contracts/DomainObjs.sol';
import {MACI} from '@clrfund/maci-contracts/contracts/MACI.sol';
import {Poll} from '@clrfund/maci-contracts/contracts/Poll.sol';
import {Tally} from '@clrfund/maci-contracts/contracts/Tally.sol';
+import {TopupToken} from './TopupToken.sol';
import {SignUpGatekeeper} from "@clrfund/maci-contracts/contracts/gatekeepers/SignUpGatekeeper.sol";
import {InitialVoiceCreditProxy} from "@clrfund/maci-contracts/contracts/initialVoiceCreditProxy/InitialVoiceCreditProxy.sol";
@@ -93,6 +94,7 @@ contract FundingRound is Ownable, SignUpGatekeeper, InitialVoiceCreditProxy, Dom
address public coordinator;
MACI public maci;
ERC20 public nativeToken;
+ TopupToken public topupToken;
IUserRegistry public userRegistry;
IRecipientRegistry public recipientRegistry;
string public tallyHash;
@@ -143,6 +145,7 @@ contract FundingRound is Ownable, SignUpGatekeeper, InitialVoiceCreditProxy, Dom
userRegistry = _userRegistry;
recipientRegistry = _recipientRegistry;
coordinator = _coordinator;
+ topupToken = new TopupToken();
}
/**
diff --git a/contracts/contracts/FundingRoundFactory.sol b/contracts/contracts/FundingRoundFactory.sol
new file mode 100644
index 000000000..6d4d586de
--- /dev/null
+++ b/contracts/contracts/FundingRoundFactory.sol
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-3.0
+
+pragma solidity ^0.8.10;
+
+import {FundingRound} from './FundingRound.sol';
+import {ERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol';
+import {IUserRegistry} from './userRegistry/IUserRegistry.sol';
+import {IRecipientRegistry} from './recipientRegistry/IRecipientRegistry.sol';
+
+contract FundingRoundFactory {
+ function deploy(
+ ERC20 _nativeToken,
+ IUserRegistry _userRegistry,
+ IRecipientRegistry _recipientRegistry,
+ address _coordinator,
+ address _owner
+ )
+ external
+ returns (FundingRound newRound)
+ {
+ newRound = new FundingRound(
+ _nativeToken,
+ _userRegistry,
+ _recipientRegistry,
+ _coordinator
+ );
+
+ newRound.transferOwnership(_owner);
+ }
+}
diff --git a/contracts/contracts/MACIFactory.sol b/contracts/contracts/MACIFactory.sol
index 2f5e35983..e633fead4 100644
--- a/contracts/contracts/MACIFactory.sol
+++ b/contracts/contracts/MACIFactory.sol
@@ -11,7 +11,6 @@ import {VkRegistry} from '@clrfund/maci-contracts/contracts/VkRegistry.sol';
import {SnarkCommon} from '@clrfund/maci-contracts/contracts/crypto/SnarkCommon.sol';
import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
import {Params} from '@clrfund/maci-contracts/contracts/Params.sol';
-import {PollFactoryCreator} from './PollFactoryCreator.sol';
import {IPubKey} from '@clrfund/maci-contracts/contracts/DomainObjs.sol';
contract MACIFactory is Ownable, Params, SnarkCommon, IPubKey {
@@ -20,6 +19,7 @@ contract MACIFactory is Ownable, Params, SnarkCommon, IPubKey {
// State
VkRegistry public vkRegistry;
+ PollFactory public pollFactory;
uint8 public stateTreeDepth;
TreeDepths public treeDepths;
MaxValues public maxValues;
@@ -31,27 +31,41 @@ contract MACIFactory is Ownable, Params, SnarkCommon, IPubKey {
// errors
error NotInitialized();
- error CannotDecreaseVoteOptionDepth();
error ProcessVkNotSet();
error TallyVkNotSet();
error InvalidVkRegistry();
+ error InvalidPollFactory();
- constructor(VkRegistry _vkRegistry) {
- _setVkRegistry(_vkRegistry);
+ constructor(address _vkRegistry, address _pollFactory) {
+ if (_vkRegistry == address(0)) revert InvalidVkRegistry();
+ if (_pollFactory == address(0)) revert InvalidPollFactory();
+
+ vkRegistry = VkRegistry(_vkRegistry);
+ pollFactory = PollFactory(_pollFactory);
}
- function _setVkRegistry(VkRegistry _vkRegistry) internal {
- if (address(_vkRegistry) == address(0)) {
- revert InvalidVkRegistry();
- }
+ /**
+ * @dev set vk registry
+ */
+ function setVkRegistry(address _vkRegistry) public onlyOwner {
+ if (_vkRegistry == address(0)) revert InvalidVkRegistry();
- vkRegistry = _vkRegistry;
+ vkRegistry = VkRegistry(_vkRegistry);
}
- function setVkRegistry(VkRegistry _vkRegistry) public onlyOwner {
- _setVkRegistry(_vkRegistry);
+ /**
+ * @dev set poll factory in MACI factory
+ * @param _pollFactory poll factory
+ */
+ function setPollFactory(address _pollFactory) public onlyOwner {
+ if (_pollFactory == address(0)) revert InvalidPollFactory();
+
+ pollFactory = PollFactory(_pollFactory);
}
+ /**
+ * @dev set MACI zkeys parameters
+ */
function setMaciParameters(
uint8 _stateTreeDepth,
TreeDepths calldata _treeDepths,
@@ -63,10 +77,6 @@ contract MACIFactory is Ownable, Params, SnarkCommon, IPubKey {
public
onlyOwner
{
- if (_treeDepths.voteOptionTreeDepth < treeDepths.voteOptionTreeDepth) {
- revert CannotDecreaseVoteOptionDepth();
- }
-
if (!vkRegistry.hasProcessVk(
_stateTreeDepth,
_treeDepths.messageTreeDepth,
@@ -128,20 +138,15 @@ contract MACIFactory is Ownable, Params, SnarkCommon, IPubKey {
revert TallyVkNotSet();
}
- PollFactory pollFactory = PollFactoryCreator.create();
_maci = new MACI(
pollFactory,
signUpGatekeeper,
initialVoiceCreditProxy
);
- pollFactory.transferOwnership(address(_maci));
_maci.init(vkRegistry, TopupCredit(topupCredit));
- _maci.deployPoll(duration, maxValues, treeDepths, coordinatorPubKey);
-
- // this is a brand new maci, get poll 0
- Poll poll = _maci.getPoll(0);
- poll.transferOwnership(coordinator);
+ address poll = _maci.deployPoll(duration, maxValues, treeDepths, coordinatorPubKey);
+ Poll(poll).transferOwnership(coordinator);
emit MaciDeployed(address(_maci));
}
diff --git a/contracts/contracts/PollFactoryCreator.sol b/contracts/contracts/PollFactoryCreator.sol
deleted file mode 100644
index 24b8b0f9d..000000000
--- a/contracts/contracts/PollFactoryCreator.sol
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-
-pragma solidity 0.8.10;
-
-import {PollFactory} from '@clrfund/maci-contracts/contracts/Poll.sol';
-
-library PollFactoryCreator {
- function create() external returns (PollFactory pollFactory) {
- pollFactory = new PollFactory();
- }
-}
\ No newline at end of file
diff --git a/contracts/contracts/TopupToken.sol b/contracts/contracts/TopupToken.sol
new file mode 100644
index 000000000..c70068ae7
--- /dev/null
+++ b/contracts/contracts/TopupToken.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-3.0
+
+pragma solidity ^0.8.10;
+
+import {ERC20} from '@openzeppelin/contracts/token/ERC20/ERC20.sol';
+import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
+
+/**
+ * TopupToken is used by MACI Poll contract to validate the topup credits of a user
+ * In clrfund, this is only used as gateway to pass the topup amount to the Poll contract
+ */
+contract TopupToken is ERC20, Ownable {
+ constructor() ERC20("TopupCredit", "TopupCredit") {}
+
+ function airdrop(uint256 amount) public onlyOwner {
+ _mint(msg.sender, amount);
+ }
+}
diff --git a/contracts/contracts/VkRegistryCreator.sol b/contracts/contracts/VkRegistryCreator.sol
deleted file mode 100644
index ef43411c9..000000000
--- a/contracts/contracts/VkRegistryCreator.sol
+++ /dev/null
@@ -1,11 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0
-
-pragma solidity 0.8.10;
-
-import {VkRegistry} from '@clrfund/maci-contracts/contracts/VkRegistry.sol';
-
-library VkRegistryCreator {
- function create() public returns (VkRegistry vkRegistry) {
- vkRegistry = new VkRegistry();
- }
-}
\ No newline at end of file
diff --git a/contracts/e2e/index.ts b/contracts/e2e/index.ts
index e6ead998a..4738c4755 100644
--- a/contracts/e2e/index.ts
+++ b/contracts/e2e/index.ts
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/camelcase */
-import { ethers, waffle } from 'hardhat'
+import { ethers, waffle, config } from 'hardhat'
import { use, expect } from 'chai'
import { solidity } from 'ethereum-waffle'
import { BigNumber, Contract, Signer, Wallet } from 'ethers'
@@ -9,23 +9,23 @@ import { genTallyResultCommitment } from '@clrfund/common'
import { UNIT } from '../utils/constants'
import { getEventArg } from '../utils/contracts'
import {
- deployMaciFactory,
deployContract,
- mergeMessages,
- mergeSignups,
- genProofs,
- proveOnChain,
deployPoseidonLibraries,
- deployContractWithLinkedLibraries,
+ deployMaciFactory,
+ deployMessageProcesorAndTally,
} from '../utils/deployment'
import { getIpfsHash } from '../utils/ipfs'
import {
bnSqrt,
- MaciParameters,
+ genProofs,
+ proveOnChain,
+ mergeMaciSubtrees,
addTallyResultsBatch,
getRecipientClaimData,
getGenProofArgs,
} from '../utils/maci'
+import { DEFAULT_CIRCUIT } from '../utils/circuits'
+import { MaciParameters } from '../utils/maciParameters'
import { readFileSync, existsSync, mkdirSync } from 'fs'
import path from 'path'
@@ -36,10 +36,13 @@ const DEFAULT_SR_QUEUE_OPS = 4
const roundDuration = 7 * 86400
// MACI zkFiles
-const circuit = process.env.CIRCUIT_TYPE || 'micro'
+const circuit = process.env.CIRCUIT_TYPE || DEFAULT_CIRCUIT
const circuitDirectory = process.env.CIRCUIT_DIRECTORY || '../../params'
const rapidSnarkDirectory =
process.env.RAPIDSNARK_DIRECTORY || '../../rapidsnark/build'
+const proofOutputDirectory = process.env.PROOF_OUTPUT_DIR || './proof_output'
+const tallyBatchSize = Number(process.env.TALLY_BATCH_SIZE || 8)
+
let maciTransactionHash: string
const ALPHA_PRECISION = BigNumber.from(10).pow(18)
@@ -112,7 +115,7 @@ describe('End-to-end Tests', function () {
let poseidonLibraries: { [key: string]: string }
let userRegistry: Contract
let recipientRegistry: Contract
- let fundingRoundFactory: Contract
+ let clrfund: Contract
let token: Contract
let fundingRound: Contract
let maci: Contract
@@ -122,7 +125,11 @@ describe('End-to-end Tests', function () {
before(async () => {
params = await MaciParameters.fromConfig(circuit, circuitDirectory)
- poseidonLibraries = await deployPoseidonLibraries(deployer)
+ poseidonLibraries = await deployPoseidonLibraries({
+ ethers,
+ artifactsPath: config.paths.artifacts,
+ signer: deployer,
+ })
})
beforeEach(async () => {
@@ -138,22 +145,35 @@ describe('End-to-end Tests', function () {
] = await ethers.getSigners()
// Deploy funding round factory
- const maciFactory = await deployMaciFactory(deployer, poseidonLibraries)
+ const maciFactory = await deployMaciFactory({
+ libraries: poseidonLibraries,
+ signer: deployer,
+ ethers,
+ })
const setMaciTx = await maciFactory.setMaciParameters(
...params.asContractParam()
)
await setMaciTx.wait()
- fundingRoundFactory = await deployContractWithLinkedLibraries(
- deployer,
- 'ClrFund',
- poseidonLibraries
+ clrfund = await deployContract({
+ name: 'ClrFund',
+ signer: deployer,
+ ethers,
+ })
+
+ const roundFactory = await deployContract({
+ name: 'FundingRoundFactory',
+ libraries: poseidonLibraries,
+ signer: deployer,
+ ethers,
+ })
+
+ const initClrfundTx = await clrfund.init(
+ maciFactory.address,
+ roundFactory.address
)
- const initClrfundTx = await fundingRoundFactory.init(maciFactory.address)
await initClrfundTx.wait()
- const transferTx = await maciFactory.transferOwnership(
- fundingRoundFactory.address
- )
+ const transferTx = await maciFactory.transferOwnership(clrfund.address)
await transferTx.wait()
const SimpleUserRegistry = await ethers.getContractFactory(
@@ -161,15 +181,13 @@ describe('End-to-end Tests', function () {
deployer
)
userRegistry = await SimpleUserRegistry.deploy()
- await fundingRoundFactory.setUserRegistry(userRegistry.address)
+ await clrfund.setUserRegistry(userRegistry.address)
const SimpleRecipientRegistry = await ethers.getContractFactory(
'SimpleRecipientRegistry',
deployer
)
- recipientRegistry = await SimpleRecipientRegistry.deploy(
- fundingRoundFactory.address
- )
- await fundingRoundFactory.setRecipientRegistry(recipientRegistry.address)
+ recipientRegistry = await SimpleRecipientRegistry.deploy(clrfund.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
// Deploy ERC20 token contract
const Token = await ethers.getContractFactory('AnyOldERC20Token', deployer)
@@ -182,9 +200,9 @@ describe('End-to-end Tests', function () {
}
// Configure factory
- await fundingRoundFactory.setToken(token.address)
+ await clrfund.setToken(token.address)
coordinatorKeypair = new Keypair()
- await fundingRoundFactory.setCoordinator(
+ await clrfund.setCoordinator(
coordinator.address,
coordinatorKeypair.pubKey.asContractParam()
)
@@ -193,15 +211,13 @@ describe('End-to-end Tests', function () {
const poolContributionAmount = UNIT.mul(5)
await token
.connect(poolContributor1)
- .transfer(fundingRoundFactory.address, poolContributionAmount)
+ .transfer(clrfund.address, poolContributionAmount)
// Add additional funding source
- await fundingRoundFactory.addFundingSource(
- await poolContributor2.getAddress()
- )
+ await clrfund.addFundingSource(await poolContributor2.getAddress())
await token
.connect(poolContributor2)
- .approve(fundingRoundFactory.address, poolContributionAmount)
+ .approve(clrfund.address, poolContributionAmount)
// Add recipients
await recipientRegistry.addRecipient(
@@ -230,9 +246,9 @@ describe('End-to-end Tests', function () {
)
// Deploy new funding round and MACI
- const newRoundTx = await fundingRoundFactory.deployNewRound(roundDuration)
+ const newRoundTx = await clrfund.deployNewRound(roundDuration)
maciTransactionHash = newRoundTx.hash
- const fundingRoundAddress = await fundingRoundFactory.getCurrentRound()
+ const fundingRoundAddress = await clrfund.getCurrentRound()
fundingRound = await ethers.getContractAt(
'FundingRound',
fundingRoundAddress
@@ -299,20 +315,14 @@ describe('End-to-end Tests', function () {
const providerUrl = (provider as any)._hardhatNetwork.config.url
// Process messages and tally votes
- await mergeMessages({
- contract: maci.address,
- poll_id: pollId.toString(),
- num_queue_ops: DEFAULT_SR_QUEUE_OPS,
- })
-
- await mergeSignups({
- contract: maci.address,
- poll_id: pollId.toString(),
- num_queue_ops: DEFAULT_SR_QUEUE_OPS,
- })
+ await mergeMaciSubtrees(
+ maci.address,
+ pollId.toString(),
+ DEFAULT_SR_QUEUE_OPS
+ )
const random = Math.floor(Math.random() * 10 ** 8)
- const outputDir = path.join('.', 'proof_output', `${random}`)
+ const outputDir = path.join(proofOutputDirectory, `${random}`)
if (!existsSync(outputDir)) {
mkdirSync(outputDir, { recursive: true })
}
@@ -320,7 +330,7 @@ describe('End-to-end Tests', function () {
maciAddress: maci.address,
providerUrl,
pollId: pollId.toString(),
- serializedCoordinatorPrivKey: coordinatorKeypair.privKey.serialize(),
+ coordinatorMacisk: coordinatorKeypair.privKey.serialize(),
maciTxHash: maciTransactionHash,
rapidSnarkDirectory,
circuitType: circuit,
@@ -329,23 +339,11 @@ describe('End-to-end Tests', function () {
})
await genProofs(genProofArgs)
- // deploy the tally contract
- const verifierContract = await deployContract(coordinator, 'Verifier')
- const tallyContract = await deployContractWithLinkedLibraries(
- coordinator,
- 'Tally',
- poseidonLibraries,
- [verifierContract.address]
- )
- await fundingRound.connect(coordinator).setTally(tallyContract.address)
-
- // deploy the message processing contract
- const mpContract = await deployContractWithLinkedLibraries(
- coordinator,
- 'MessageProcessor',
- poseidonLibraries,
- [verifierContract.address]
- )
+ const { mpContract, tallyContract } = await deployMessageProcesorAndTally({
+ libraries: poseidonLibraries,
+ ethers,
+ signer: coordinator,
+ })
// Submit proofs to MACI contract
await proveOnChain({
@@ -353,25 +351,25 @@ describe('End-to-end Tests', function () {
poll_id: pollId.toString(),
mp: mpContract.address,
tally: tallyContract.address,
- subsidy: tallyContract.address, // TODO: make subsidy optional
+ //subsidy: tallyContract.address, // TODO: make subsidy optional
proof_dir: genProofArgs.output,
})
-
console.log('finished proveOnChain')
+
+ await fundingRound.connect(coordinator).setTally(tallyContract.address)
const tally = JSON.parse(readFileSync(genProofArgs.tally_file).toString())
const tallyHash = await getIpfsHash(tally)
await fundingRound.connect(coordinator).publishTallyHash(tallyHash)
console.log('Tally hash', tallyHash)
// add tally results to funding round
- const batchSize = Number(process.env.TALLY_BATCH_SIZE) || 8
const recipientTreeDepth = params.voteOptionTreeDepth
- console.log('Adding tally result on chain in batches of', batchSize)
+ console.log('Adding tally result on chain in batches of', tallyBatchSize)
await addTallyResultsBatch(
fundingRound.connect(coordinator),
recipientTreeDepth,
tally,
- batchSize
+ tallyBatchSize
)
console.log('Finished adding tally results')
@@ -388,7 +386,7 @@ describe('End-to-end Tests', function () {
)
// Finalize round
- await fundingRoundFactory.transferMatchingFunds(
+ await clrfund.transferMatchingFunds(
tally.totalSpentVoiceCredits.spent,
tally.totalSpentVoiceCredits.salt,
newResultCommitment.toString(),
diff --git a/contracts/package.json b/contracts/package.json
index a30a7a920..3f94b73c9 100644
--- a/contracts/package.json
+++ b/contracts/package.json
@@ -22,7 +22,7 @@
"clean": "rm -rf cache && rm -rf build"
},
"dependencies": {
- "@clrfund/maci-contracts": "^1.1.7",
+ "@clrfund/maci-contracts": "^1.1.9",
"@openzeppelin/contracts": "4.9.0",
"dotenv": "^8.2.0",
"solidity-rlp": "2.0.8"
@@ -33,7 +33,7 @@
"@clrfund/maci-cli": "^1.1.7",
"@ethereum-waffle/mock-contract": "^3.4.4",
"@kleros/gtcr-encoder": "^1.4.0",
- "@nomiclabs/hardhat-ethers": "^2.2.1",
+ "@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-etherscan": "^3.1.4",
"@nomiclabs/hardhat-ganache": "^2.0.1",
"@nomiclabs/hardhat-waffle": "^2.0.3",
@@ -47,12 +47,12 @@
"eslint-config-prettier": "^8.5.0",
"ethereum-waffle": "^3.4.4",
"ethers": "^5.7.2",
- "hardhat": "^2.12.5",
+ "hardhat": "^2.19.1",
"hardhat-contract-sizer": "^2.6.1",
"ipfs-only-hash": "^2.0.1",
"solhint": "^3.3.2",
"ts-generator": "^0.0.8",
- "ts-node": "^8.8.1",
+ "ts-node": "^10.9.1",
"typescript": "^4.9.3"
}
}
diff --git a/contracts/scripts/claim.ts b/contracts/scripts/claim.ts
deleted file mode 100644
index 1085d0bec..000000000
--- a/contracts/scripts/claim.ts
+++ /dev/null
@@ -1,47 +0,0 @@
-import fs from 'fs'
-import { ethers } from 'hardhat'
-
-import { getEventArg } from '../utils/contracts'
-import { getRecipientClaimData } from '../utils/maci'
-
-async function main() {
- const [, , , recipient1, recipient2] = await ethers.getSigners()
- const state = JSON.parse(fs.readFileSync('state.json').toString())
- const tally = JSON.parse(fs.readFileSync('tally.json').toString())
-
- const fundingRound = await ethers.getContractAt(
- 'FundingRound',
- state.fundingRound
- )
- const maciAddress = await fundingRound.maci()
- const maci = await ethers.getContractAt('MACI', maciAddress)
- const recipientTreeDepth = (await maci.treeDepths()).voteOptionTreeDepth
-
- // Claim funds
- for (const recipientIndex of [1, 2]) {
- const recipient = recipientIndex === 1 ? recipient1 : recipient2
- const recipientClaimData = getRecipientClaimData(
- recipientIndex,
- recipientTreeDepth,
- tally
- )
- const fundingRoundAsRecipient = fundingRound.connect(recipient)
- const claimTx = await fundingRoundAsRecipient.claimFunds(
- ...recipientClaimData
- )
- const claimedAmount = await getEventArg(
- claimTx,
- fundingRound,
- 'FundsClaimed',
- '_amount'
- )
- console.log(`Recipient ${recipientIndex} claimed ${claimedAmount} tokens.`)
- }
-}
-
-main()
- .then(() => process.exit(0))
- .catch((error) => {
- console.error(error)
- process.exit(1)
- })
diff --git a/contracts/scripts/contribute.ts b/contracts/scripts/contribute.ts
deleted file mode 100644
index 2aef9b2a6..000000000
--- a/contracts/scripts/contribute.ts
+++ /dev/null
@@ -1,66 +0,0 @@
-import fs from 'fs'
-import { ethers } from 'hardhat'
-import { Keypair } from '@clrfund/common'
-
-import { UNIT } from '../utils/constants'
-import { getEventArg } from '../utils/contracts'
-
-async function main() {
- const [, , , , , , , , , , , , contributor1, contributor2] =
- await ethers.getSigners()
- const state = JSON.parse(fs.readFileSync('state.json').toString())
- const fundingRound = await ethers.getContractAt(
- 'FundingRound',
- state.fundingRound
- )
- const tokenAddress = await fundingRound.nativeToken()
- const token = await ethers.getContractAt('AnyOldERC20Token', tokenAddress)
- const maciAddress = await fundingRound.maci()
- const maci = await ethers.getContractAt('MACI', maciAddress)
-
- const contributionAmount = UNIT.mul(16).div(10)
- state.contributors = {}
-
- for (const contributor of [contributor1, contributor2]) {
- const contributorAddress = await contributor.getAddress()
- const contributorKeypair = new Keypair()
- const tokenAsContributor = token.connect(contributor)
- await tokenAsContributor.approve(fundingRound.address, contributionAmount)
- const fundingRoundAsContributor = fundingRound.connect(contributor)
- const contributionTx = await fundingRoundAsContributor.contribute(
- contributorKeypair.pubKey.asContractParam(),
- contributionAmount
- )
- const stateIndex = await getEventArg(
- contributionTx,
- maci,
- 'SignUp',
- '_stateIndex'
- )
- const voiceCredits = await getEventArg(
- contributionTx,
- maci,
- 'SignUp',
- '_voiceCreditBalance'
- )
- state.contributors[contributorAddress] = {
- privKey: contributorKeypair.privKey.serialize(),
- pubKey: contributorKeypair.pubKey.serialize(),
- stateIndex: parseInt(stateIndex),
- voiceCredits: voiceCredits.toString(),
- }
- console.log(
- `Contributor ${contributorAddress} registered. State index: ${stateIndex}. Voice credits: ${voiceCredits.toString()}.`
- )
- }
-
- // Update state file
- fs.writeFileSync('state.json', JSON.stringify(state))
-}
-
-main()
- .then(() => process.exit(0))
- .catch((error) => {
- console.error(error)
- process.exit(1)
- })
diff --git a/contracts/scripts/deploy.ts b/contracts/scripts/deploy.ts
deleted file mode 100644
index e036e62fe..000000000
--- a/contracts/scripts/deploy.ts
+++ /dev/null
@@ -1,142 +0,0 @@
-import { ethers } from 'hardhat'
-import { Contract, Wallet } from 'ethers'
-
-import { UNIT } from '../utils/constants'
-import {
- deployMaciFactory,
- deployUserRegistry,
- getBrightIdParams,
-} from '../utils/deployment'
-import { Keypair, PrivKey } from '@clrfund/common'
-
-// Number.MAX_SAFE_INTEGER - 1
-const challengePeriodSeconds = 9007199254740990
-
-/**
- * Set the coordinator address and maci public key in the funding round factory
- *
- * @param fundingRoundFactory funding round factory contract
- * @param coordinatorAddress
- * @param MaciPrivateKey
- */
-async function setCoordinator(
- fundingRoundFactory: Contract,
- coordinatorAddress: string,
- coordinatorKey?: string
-) {
- // Generate or use the passed in coordinator key
- const privKey = coordinatorKey
- ? PrivKey.unserialize(coordinatorKey)
- : undefined
- const keypair = new Keypair(privKey)
- const coordinatorPubKey = keypair.pubKey
- const serializedCoordinatorPrivKey = keypair.privKey.serialize()
- const serializedCoordinatorPubKey = keypair.pubKey.serialize()
- const setCoordinatorTx = await fundingRoundFactory.setCoordinator(
- coordinatorAddress,
- coordinatorPubKey.asContractParam()
- )
- await setCoordinatorTx.wait()
- console.log('coordinator address:', coordinatorAddress)
- console.log('serializedCoordinatorPrivKey: ', serializedCoordinatorPrivKey)
- console.log('serializedCoordinatorPubKey: ', serializedCoordinatorPubKey)
-}
-
-async function main() {
- const [deployer] = await ethers.getSigners()
- console.log(`Deploying from address: ${deployer.address}`)
-
- const circuit = 'prod'
- const maciFactory = await deployMaciFactory(deployer, circuit)
- await maciFactory.deployTransaction.wait()
- console.log(`MACIFactory deployed: ${maciFactory.address}`)
-
- const FundingRoundFactory = await ethers.getContractFactory(
- 'FundingRoundFactory',
- deployer
- )
- const fundingRoundFactory = await FundingRoundFactory.deploy(
- maciFactory.address
- )
- await fundingRoundFactory.deployTransaction.wait()
- console.log(`FundingRoundFactory deployed: ${fundingRoundFactory.address}`)
-
- const transferOwnershipTx = await maciFactory.transferOwnership(
- fundingRoundFactory.address
- )
- await transferOwnershipTx.wait()
-
- const userRegistryType = process.env.USER_REGISTRY_TYPE || 'simple'
- const brightidParams = getBrightIdParams(userRegistryType)
- const userRegistry: Contract = await deployUserRegistry(
- userRegistryType,
- deployer,
- brightidParams
- )
- console.log(
- `User registry (${userRegistryType}) deployed: ${userRegistry.address}`
- )
-
- const setUserRegistryTx = await fundingRoundFactory.setUserRegistry(
- userRegistry.address
- )
- await setUserRegistryTx.wait()
-
- const recipientRegistryType = process.env.RECIPIENT_REGISTRY_TYPE || 'simple'
- let recipientRegistry: Contract
- if (recipientRegistryType === 'simple') {
- const SimpleRecipientRegistry = await ethers.getContractFactory(
- 'SimpleRecipientRegistry',
- deployer
- )
- recipientRegistry = await SimpleRecipientRegistry.deploy(
- fundingRoundFactory.address
- )
- } else if (recipientRegistryType === 'optimistic') {
- const OptimisticRecipientRegistry = await ethers.getContractFactory(
- 'OptimisticRecipientRegistry',
- deployer
- )
- recipientRegistry = await OptimisticRecipientRegistry.deploy(
- UNIT.div(1000),
- challengePeriodSeconds,
- fundingRoundFactory.address
- )
- } else {
- throw new Error('unsupported recipient registry type')
- }
- await recipientRegistry.deployTransaction.wait()
- console.log(`Recipient registry deployed: ${recipientRegistry.address}`)
-
- const setRecipientRegistryTx = await fundingRoundFactory.setRecipientRegistry(
- recipientRegistry.address
- )
- await setRecipientRegistryTx.wait()
-
- if (process.env.NATIVE_TOKEN_ADDRESS) {
- const setTokenTx = await fundingRoundFactory.setToken(
- process.env.NATIVE_TOKEN_ADDRESS
- )
- await setTokenTx.wait()
- console.log('Set token', process.env.NATIVE_TOKEN_ADDRESS)
- }
-
- const coordinatorAddress = process.env.COORDINATOR_ETH_PK
- ? new Wallet(process.env.COORDINATOR_ETH_PK).address
- : await deployer.getAddress()
-
- await setCoordinator(
- fundingRoundFactory,
- coordinatorAddress,
- process.env.COORDINATOR_PK
- )
-
- console.log(`Deployment complete!`)
-}
-
-main()
- .then(() => process.exit(0))
- .catch((error) => {
- console.error(error)
- process.exit(1)
- })
diff --git a/contracts/scripts/deployUserRegistry.ts b/contracts/scripts/deployUserRegistry.ts
deleted file mode 100644
index 2373d5451..000000000
--- a/contracts/scripts/deployUserRegistry.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { ethers } from 'hardhat'
-import { deployUserRegistry, getBrightIdParams } from '../utils/deployment'
-
-async function main() {
- console.log('*******************')
- console.log('Deploying a user registry!')
- console.log('*******************')
- const [deployer] = await ethers.getSigners()
- console.log('deployer.address: ', deployer.address)
-
- const fundingRoundFactoryAddress = process.env.FACTORY_ADDRESS
-
- if (!fundingRoundFactoryAddress) {
- throw new Error('Environment variable FACTORY_ADDRESS is not setup')
- }
- const fundingRoundFactory = await ethers.getContractAt(
- 'FundingRoundFactory',
- fundingRoundFactoryAddress
- )
- console.log('funding round factory address ', fundingRoundFactory.address)
-
- const userRegistryType = process.env.USER_REGISTRY_TYPE || 'simple'
- const brightidParams = getBrightIdParams(userRegistryType)
- const userRegistry = await deployUserRegistry(
- userRegistryType,
- deployer,
- brightidParams
- )
- console.log(
- `deployed ${userRegistryType} user registry at ${userRegistry.address}`
- )
-
- const setUserRegistryTx = await fundingRoundFactory.setUserRegistry(
- userRegistry.address
- )
- await setUserRegistryTx.wait()
- console.log(
- 'set user registry in funding round factory at tx hash',
- setUserRegistryTx.hash
- )
-
- console.log('*******************')
- console.log('Deploy complete!')
- console.log('*******************')
-}
-
-main()
- .then(() => process.exit(0))
- .catch((error) => {
- console.error(error)
- process.exit(1)
- })
diff --git a/contracts/scripts/finalize.ts b/contracts/scripts/finalize.ts
deleted file mode 100644
index 12f544aad..000000000
--- a/contracts/scripts/finalize.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import fs from 'fs'
-import { Wallet } from 'ethers'
-import { ethers, network } from 'hardhat'
-
-async function main() {
- let factoryAddress, coordinator
- if (network.name === 'localhost') {
- const state = JSON.parse(fs.readFileSync('state.json').toString())
- factoryAddress = state.factory
-
- const signers = await ethers.getSigners()
- coordinator = signers[0]
- } else {
- factoryAddress = process.env.FACTORY_ADDRESS || ''
- // default to the first account
- const coordinatorEthPrivKey =
- process.env.COORDINATOR_ETH_PK ||
- '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
- coordinator = new Wallet(coordinatorEthPrivKey, ethers.provider)
- }
-
- const tally = JSON.parse(fs.readFileSync('tally.json').toString())
- const factory = await ethers.getContractAt(
- 'FundingRoundFactory',
- factoryAddress,
- coordinator
- )
- console.log('Funding round factory address', factory.address)
-
- const currentRoundAddress = await factory.getCurrentRound()
- const fundingRound = await ethers.getContractAt(
- 'FundingRound',
- currentRoundAddress,
- coordinator
- )
- console.log('Current round', fundingRound.address)
-
- const totalSpent = parseInt(tally.totalVoiceCredits.spent)
- const totalSpentSalt = tally.totalVoiceCredits.salt
- const tx = await factory.transferMatchingFunds(totalSpent, totalSpentSalt)
- const receipt = await tx.wait()
- console.log(
- 'Round finalized, totals verified. Gas used:',
- receipt.gasUsed.toString()
- )
-}
-
-main()
- .then(() => process.exit(0))
- .catch((error) => {
- console.error(error)
- process.exit(1)
- })
diff --git a/contracts/scripts/newRound.ts b/contracts/scripts/newRound.ts
deleted file mode 100644
index 3cf0d6a43..000000000
--- a/contracts/scripts/newRound.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-import { ethers } from 'hardhat'
-import { utils, constants } from 'ethers'
-
-async function main() {
- console.log('*******************')
- console.log('Start a new funding round!')
- console.log('*******************')
- const [deployer] = await ethers.getSigners()
- console.log('deployer.address: ', deployer.address)
-
- const fundingRoundFactoryAddress = process.env.FACTORY_ADDRESS
- const userRegistryType = process.env.USER_REGISTRY_TYPE
- const brightIdSponsor = process.env.BRIGHTID_SPONSOR
- const brightIdVerifier = process.env.BRIGHTID_VERIFIER_ADDR
-
- if (!fundingRoundFactoryAddress) {
- throw new Error('Environment variable FACTORY_ADDRESS is not setup')
- }
-
- if (userRegistryType === 'brightid') {
- if (!brightIdSponsor) {
- throw new Error('Environment variable BRIGHTID_SPONSOR is not setup')
- }
- if (!brightIdVerifier) {
- throw new Error(
- 'Environment variable BRIGHTID_VERIFIER_ADDR is not setup'
- )
- }
- }
-
- const factory = await ethers.getContractAt(
- 'FundingRoundFactory',
- fundingRoundFactoryAddress
- )
- console.log('funding round factory address ', factory.address)
-
- // check if the current round is finalized before starting a new round to avoid revert
- const currentRoundAddress = await factory.getCurrentRound()
- if (currentRoundAddress !== constants.AddressZero) {
- const currentRound = await ethers.getContractAt(
- 'FundingRound',
- currentRoundAddress
- )
- const isFinalized = await currentRound.isFinalized()
- if (!isFinalized) {
- throw new Error(
- 'Cannot start a new round as the current round is not finalized'
- )
- }
- }
-
- // deploy a new BrightId user registry for each new round
- // to force users to link with BrightId every round
- if (userRegistryType === 'brightid') {
- const BrightIdUserRegistry = await ethers.getContractFactory(
- 'BrightIdUserRegistry',
- deployer
- )
-
- const userRegistry = await BrightIdUserRegistry.deploy(
- utils.formatBytes32String(process.env.BRIGHTID_CONTEXT || 'clr.fund'),
- brightIdVerifier,
- brightIdSponsor
- )
- console.log('BrightId user registry address: ', userRegistry.address)
- await userRegistry.deployTransaction.wait()
-
- const setUserRegistryTx = await factory.setUserRegistry(
- userRegistry.address
- )
- await setUserRegistryTx.wait()
- console.log('Set user registry in factory', setUserRegistryTx.hash)
- }
-
- const tx = await factory.deployNewRound()
- console.log('Deployed new round, tx hash: ', tx.hash)
- await tx.wait()
- console.log('New funding round address: ', await factory.getCurrentRound())
-
- console.log('*******************')
- console.log('Script complete!')
- console.log('*******************')
-}
-
-main()
- .then(() => process.exit(0))
- .catch((error) => {
- console.error(error)
- process.exit(1)
- })
diff --git a/contracts/scripts/tally.ts b/contracts/scripts/tally.ts
new file mode 100644
index 000000000..d94868c12
--- /dev/null
+++ b/contracts/scripts/tally.ts
@@ -0,0 +1,235 @@
+/**
+ * Tally votes for the specified funding round. This task can be rerun by
+ * passing in additional parameters: --maci-logs, --maci-state-file
+ *
+ * Make sure to set the following environment variables in the .env file
+ * if not running test using the localhost network
+ * 1) COORDINATOR_ETH_PK - coordinator's wallet private key to interact with contracts
+ * 2) COORDINATOR_PK - coordinator's MACI private key to decrypt messages
+ *
+ * Sample usage:
+ *
+ * yarn hardhat tally --round-address
--start-block --network
+ *
+ * To rerun:
+ *
+ * yarn hardhat tally --round-address --network \
+ * --maci-logs --maci-state-file
+ */
+import { ethers, network, config } from 'hardhat'
+import { Contract, Signer } from 'ethers'
+
+import { DEFAULT_SR_QUEUE_OPS } from '../utils/constants'
+import { getIpfsHash } from '../utils/ipfs'
+import { JSONFile } from '../utils/JSONFile'
+import {
+ deployContract,
+ deployPoseidonLibraries,
+ deployMessageProcesorAndTally,
+} from '../utils/deployment'
+import {
+ getGenProofArgs,
+ genProofs,
+ proveOnChain,
+ addTallyResultsBatch,
+ mergeMaciSubtrees,
+} from '../utils/maci'
+import { getTalyFilePath } from '../utils/misc'
+
+/**
+ * Read variables from the environment file needed
+ * to run the tally script
+ *
+ * @returns data used to run the tally script
+ */
+function readFromEnvironment(): {
+ clrfund: string
+ batchSize: number
+ circuit: string
+ circuitDirectory: string
+ maciTransactionHash?: string
+ rapidSnarkDirectory?: string
+ outputDir: string
+ stateFile?: string
+ coordinatorMacisk: string
+ numQueueOps: number
+} {
+ if (!process.env.CLRFUND) {
+ console.log('process env', process.env)
+ throw Error('Env. variable CLRFUND not set')
+ }
+
+ if (!process.env.CIRCUIT_DIRECTORY) {
+ throw Error('Env. variable CIRCUIT_DIRECTORY not set')
+ }
+
+ if (!process.env.COORDINATOR_MACISK) {
+ throw Error('Env. variable COORDINATOR_MACISK not set')
+ }
+
+ return {
+ clrfund: process.env.CLRFUND || '',
+ batchSize: Number(process.env.BATCH_SIZE || '20'),
+ circuit: process.env.CIRCUIT_TYPE || 'micro',
+ circuitDirectory: process.env.CIRCUIT_DIRECTORY || '',
+ maciTransactionHash: process.env.MACI_TRANSACTION_HASH,
+ rapidSnarkDirectory: process.env.RAPIDSNARK_DIRECTORY,
+ outputDir: process.env.OUTPUT_DIR || './output',
+ stateFile: process.env.STATE_FILE,
+ coordinatorMacisk: process.env.COORDINATOR_MACISK || '',
+ numQueueOps: Number(process.env.NUM_QUEUE_OPS || DEFAULT_SR_QUEUE_OPS),
+ }
+}
+
+/**
+ * Main tally logic
+ */
+async function main() {
+ const {
+ clrfund,
+ batchSize,
+ stateFile,
+ outputDir,
+ circuit,
+ circuitDirectory,
+ rapidSnarkDirectory,
+ maciTransactionHash,
+ coordinatorMacisk,
+ numQueueOps,
+ } = readFromEnvironment()
+
+ const [coordinator] = await ethers.getSigners()
+ console.log('Coordinator address: ', coordinator.address)
+
+ const providerUrl = (network.config as any).url
+ console.log('providerUrl', providerUrl)
+
+ let clrfundContract: Contract
+ try {
+ clrfundContract = await ethers.getContractAt(
+ 'ClrFund',
+ clrfund,
+ coordinator
+ )
+ } catch (e) {
+ console.error('Error accessing ClrFund Contract at', clrfund)
+ throw e
+ }
+
+ const fundingRound = await clrfundContract.getCurrentRound()
+ const fundingRoundContract = await ethers.getContractAt(
+ 'FundingRound',
+ fundingRound,
+ coordinator
+ )
+ console.log('Funding round contract', fundingRoundContract.address)
+
+ const publishedTallyHash = await fundingRoundContract.tallyHash()
+ console.log('publishedTallyHash', publishedTallyHash)
+
+ let tally
+ if (!publishedTallyHash) {
+ const pollIdBN = await fundingRoundContract.pollId()
+ const pollId = pollIdBN.toString()
+ console.log('PollId', pollId)
+
+ const maciAddress = await fundingRoundContract.maci()
+ console.log('MACI address', maciAddress)
+
+ // Generate proof and tally file
+ const genProofArgs = getGenProofArgs({
+ maciAddress,
+ providerUrl,
+ pollId,
+ coordinatorMacisk,
+ maciTxHash: maciTransactionHash,
+ rapidSnarkDirectory,
+ circuitType: circuit,
+ circuitDirectory,
+ outputDir,
+ })
+ console.log('genProofsArg', genProofArgs)
+
+ await mergeMaciSubtrees(maciAddress, pollId, numQueueOps)
+ console.log('Completed tree merge')
+
+ await genProofs(genProofArgs)
+ console.log('Completed genProofs')
+
+ tally = JSONFile.read(genProofArgs.tally_file)
+ if (stateFile) {
+ // Save tally file in the state
+ JSONFile.update(stateFile, { tallyFile: genProofArgs.tally_file })
+ }
+
+ // deploy the MessageProcessor and Tally contracts used by proveOnChain
+ const { mpContract, tallyContract } = await deployMessageProcesorAndTally({
+ artifactsPath: config.paths.artifacts,
+ ethers,
+ signer: coordinator,
+ })
+ console.log('MessageProcessor', mpContract.address)
+ console.log('Tally Contract', tallyContract.address)
+
+ try {
+ // Submit proofs to MACI contract
+ await proveOnChain({
+ contract: maciAddress,
+ poll_id: pollId,
+ mp: mpContract.address,
+ tally: tallyContract.address,
+ //subsidy: tallyContractAddress, // TODO: make subsidy optional
+ proof_dir: outputDir,
+ })
+ } catch (e) {
+ console.error('proveOnChain failed')
+ throw e
+ }
+
+ // set the Tally contract address for verifying tally result on chain
+ const setTallyTx = await fundingRoundContract.setTally(
+ tallyContract.address
+ )
+ await setTallyTx.wait()
+ console.log('Tally contract set in funding round')
+
+ // Publish tally hash
+ const tallyHash = await getIpfsHash(tally)
+ await fundingRoundContract.publishTallyHash(tallyHash)
+ console.log(`Tally hash is ${tallyHash}`)
+ } else {
+ // read the tally.json file
+ console.log(`Tally hash is ${publishedTallyHash}`)
+ try {
+ console.log(`Reading tally.json file...`)
+ const tallyFile = getTalyFilePath(outputDir)
+ tally = JSONFile.read(tallyFile)
+ } catch (err) {
+ console.log('Failed to get tally file', publishedTallyHash)
+ throw err
+ }
+ }
+
+ // Submit results to the funding round contract
+ const startIndex = await fundingRoundContract.totalTallyResults()
+ const total = tally.results.tally.length
+ console.log('Uploading tally results in batches of', batchSize)
+ const addTallyGas = await addTallyResultsBatch(
+ fundingRoundContract,
+ 3,
+ tally,
+ batchSize,
+ startIndex.toNumber(),
+ (processed: number) => {
+ console.log(`Processed ${processed} / ${total}`)
+ }
+ )
+ console.log('Tally results uploaded. Gas used:', addTallyGas.toString())
+}
+
+main()
+ .then(() => process.exit(0))
+ .catch((error) => {
+ console.error(error)
+ process.exit(1)
+ })
diff --git a/contracts/scripts/vote.ts b/contracts/scripts/vote.ts
deleted file mode 100644
index 11d51c272..000000000
--- a/contracts/scripts/vote.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import fs from 'fs'
-import { ethers } from 'hardhat'
-import { BigNumber } from 'ethers'
-import { PrivKey, Keypair } from '@clrfund/common'
-
-import { createMessage } from '../utils/maci'
-
-async function main() {
- const [, , , , , , , , , , , , contributor1, contributor2] =
- await ethers.getSigners()
- const state = JSON.parse(fs.readFileSync('state.json').toString())
- const coordinatorKeyPair = new Keypair(
- PrivKey.unserialize(state.coordinatorPrivKey)
- )
-
- for (const contributor of [contributor1, contributor2]) {
- const contributorAddress = await contributor.getAddress()
- const contributorData = state.contributors[contributorAddress]
- const contributorKeyPair = new Keypair(
- PrivKey.unserialize(contributorData.privKey)
- )
- const messages = []
- const encPubKeys = []
- let nonce = 1
- // Change key
- const newContributorKeypair = new Keypair()
- const [message, encPubKey] = createMessage(
- contributorData.stateIndex,
- contributorKeyPair,
- newContributorKeypair,
- coordinatorKeyPair.pubKey,
- null,
- null,
- nonce
- )
- messages.push(message.asContractParam())
- encPubKeys.push(encPubKey.asContractParam())
- nonce += 1
- // Vote
- for (const recipientIndex of [1, 2]) {
- const votes = BigNumber.from(contributorData.voiceCredits).div(4)
- const [message, encPubKey] = createMessage(
- contributorData.stateIndex,
- newContributorKeypair,
- null,
- coordinatorKeyPair.pubKey,
- recipientIndex,
- votes,
- nonce
- )
- messages.push(message.asContractParam())
- encPubKeys.push(encPubKey.asContractParam())
- nonce += 1
- }
-
- const fundingRoundAsContributor = await ethers.getContractAt(
- 'FundingRound',
- state.fundingRound,
- contributor
- )
- await fundingRoundAsContributor.submitMessageBatch(
- messages.reverse(),
- encPubKeys.reverse()
- )
- console.log(`Contributor ${contributorAddress} voted.`)
- }
-}
-
-main()
- .then(() => process.exit(0))
- .catch((error) => {
- console.error(error)
- process.exit(1)
- })
diff --git a/contracts/sh/runScriptTests.sh b/contracts/sh/runScriptTests.sh
new file mode 100755
index 000000000..c3dfccd42
--- /dev/null
+++ b/contracts/sh/runScriptTests.sh
@@ -0,0 +1,91 @@
+#!/bin/bash
+set -e
+
+#
+# Run the hardhat scripts/tasks to simulate e2e testing
+#
+
+# Test settings
+NOW=$(date +%s)
+OUTPUT_DIR="./proof_output/${NOW}"
+CIRCUIT=micro
+NETWORK=localhost
+CIRCUIT_DIRECTORY=${CIRCUIT_DIRECTORY:-"./snark-params"}
+STATE_FILE=${OUTPUT_DIR}/state.json
+
+# 20 mins
+ROUND_DURATION=1800
+
+mkdir -p ${OUTPUT_DIR}
+
+# A helper to extract field value from the JSON state file
+# The pattern "field": "value" must be on 1 line
+# Usage: extract 'clrfund'
+function extract() {
+ val=$(cat "${STATE_FILE}" | grep "${1}" | grep -o "[^:]*$" | grep -o '[^",]*')
+ echo ${val}
+}
+
+# create a ClrFund deployer
+yarn hardhat new-deployer \
+ --directory "${CIRCUIT_DIRECTORY}" \
+ --state-file "${STATE_FILE}" \
+ --network "${NETWORK}"
+DEPLOYER=$(extract 'deployer')
+
+# create a new maci key for the coordinator
+MACI_KEYPAIR=$(yarn hardhat new-maci-key)
+MACI_SECRET_KEY=$(echo "${MACI_KEYPAIR}" | grep -o "macisk.*$")
+
+# create a new instance of ClrFund
+yarn hardhat new-clrfund --deployer ${DEPLOYER} \
+ --user-type simple \
+ --recipient-type simple \
+ --coordinator-macisk "${MACI_SECRET_KEY}" \
+ --state-file "${STATE_FILE}" \
+ --network "${NETWORK}"
+CLRFUND=$(extract 'clrfund')
+
+# deploy a new funding round
+yarn hardhat new-round \
+ --clrfund ${CLRFUND} \
+ --state-file "${STATE_FILE}" \
+ --duration "${ROUND_DURATION}" \
+ --network "${NETWORK}"
+FUNDING_ROUND=$(extract 'fundingRound')
+
+yarn hardhat add-contributors --clrfund ${CLRFUND} --network "${NETWORK}"
+yarn hardhat add-recipients --clrfund ${CLRFUND} --network "${NETWORK}"
+
+yarn hardhat contribute --state-file "${STATE_FILE}" --network "${NETWORK}"
+yarn hardhat vote \
+ --coordinator-macisk "${MACI_SECRET_KEY}" \
+ --state-file "${STATE_FILE}" \
+ --network "${NETWORK}"
+yarn hardhat time-travel ${ROUND_DURATION} --network "${NETWORK}"
+
+# run the tally script
+export CIRCUIT=micro
+export CIRCUIT_DIRECTORY="${CIRCUIT_DIRECTORY}"
+export CLRFUND="${CLRFUND}"
+export STATE_FILE="${STATE_FILE}"
+export TALLY_BATCH_SIZE=10
+export PROOF_OUTPUT_DIR="${PROOF_OUTPUT_DIR}"
+export COORDINATOR_MACISK="${MACI_SECRET_KEY}"
+export MACI_TRANSACTION_HASH=$(extract 'maciTxHash')
+export OUTPUT_DIR="${OUTPUT_DIR}"
+export NODE_OPTIONS=--max-old-space-size=4096
+yarn hardhat run scripts/tally.ts --network "${NETWORK}"
+
+# finalize the round
+TALLY_FILE=$(extract 'tallyFile')
+yarn hardhat finalize \
+ --clrfund "${CLRFUND}" \
+ --tally-file "${TALLY_FILE}" \
+ --network "${NETWORK}"
+
+# claim funds
+yarn hardhat claim \
+ --funding-round ${FUNDING_ROUND} \
+ --network "${NETWORK}"
+
diff --git a/contracts/tasks/addContributors.ts b/contracts/tasks/addContributors.ts
new file mode 100644
index 000000000..2e4bee422
--- /dev/null
+++ b/contracts/tasks/addContributors.ts
@@ -0,0 +1,41 @@
+/**
+ * Add contributors for testing purposes
+ *
+ * Sample usage:
+ *
+ * yarn hardhat add-contributors --network \
+ * --state-file
+ *
+ */
+
+import { task } from 'hardhat/config'
+
+task('add-contributors', 'Add test contributors')
+ .addParam('clrfund', 'The ClrFund contract address')
+ .setAction(async ({ clrfund }, { ethers }) => {
+ const [signer, , , , , , , , , , , , contributor1, contributor2] =
+ await ethers.getSigners()
+ console.log('Adding contributors by', signer.address)
+
+ const clrfundContract = await ethers.getContractAt(
+ 'ClrFund',
+ clrfund,
+ signer
+ )
+ const userRegistryAddress = await clrfundContract.userRegistry()
+ console.log('User registry address', userRegistryAddress)
+
+ const userRegistry = await ethers.getContractAt(
+ 'SimpleUserRegistry',
+ userRegistryAddress,
+ signer
+ )
+ const users = [contributor1, contributor2]
+ let addUserTx
+ for (const account of users) {
+ addUserTx = await userRegistry.addUser(account.getAddress())
+ addUserTx.wait()
+ }
+
+ console.log(`Added ${users.length} contributors`)
+ })
diff --git a/contracts/tasks/addRecipients.ts b/contracts/tasks/addRecipients.ts
new file mode 100644
index 000000000..0a42110ae
--- /dev/null
+++ b/contracts/tasks/addRecipients.ts
@@ -0,0 +1,45 @@
+/**
+ * Add recipients for testing purposes
+ *
+ * Sample usage:
+ *
+ * yarn hardhat add-recipients --network --clrfund
+ *
+ */
+
+import { task } from 'hardhat/config'
+
+task('add-recipients', 'Add test recipients')
+ .addParam('clrfund', 'The ClrFund contract address')
+ .setAction(async ({ clrfund }, { ethers }) => {
+ const [signer, ...recipients] = await ethers.getSigners()
+ console.log('Add recipients by', signer.address)
+
+ const clrfundContract = await ethers.getContractAt(
+ 'ClrFund',
+ clrfund,
+ signer
+ )
+ const recipientRegistryAddress = await clrfundContract.recipientRegistry()
+ console.log('Recipient registry', recipientRegistryAddress)
+
+ const recipientRegistry = await ethers.getContractAt(
+ 'SimpleRecipientRegistry',
+ recipientRegistryAddress,
+ signer
+ )
+
+ for (let i = 6; i < 10; i++) {
+ const recipient = recipients[i]
+ const addRecipientTx = await recipientRegistry.addRecipient(
+ recipient.address,
+ JSON.stringify({
+ name: `recipient ${i}`,
+ description: `recipient ${i}`,
+ })
+ )
+ addRecipientTx.wait()
+ }
+
+ console.log('Added test recipients')
+ })
diff --git a/contracts/tasks/cancelRound.ts b/contracts/tasks/cancelRound.ts
index f32aeabbe..f1cb010d5 100644
--- a/contracts/tasks/cancelRound.ts
+++ b/contracts/tasks/cancelRound.ts
@@ -1,17 +1,17 @@
import { task } from 'hardhat/config'
task('cancel-round', 'Cancel the current round')
- .addParam('factory', 'The funding round factory contract address')
- .setAction(async ({ factory }, { ethers }) => {
+ .addParam('clrfund', 'The ClrFund contract address')
+ .setAction(async ({ clrfund }, { ethers }) => {
const [deployer] = await ethers.getSigners()
console.log('deployer', deployer.address)
- const fundingRoundFactory = await ethers.getContractAt(
- 'FundingRoundFactory',
- factory,
+ const clrfundContract = await ethers.getContractAt(
+ 'ClrFund',
+ clrfund,
deployer
)
- const cancelTx = await fundingRoundFactory.cancelCurrentRound()
+ const cancelTx = await clrfundContract.cancelCurrentRound()
await cancelTx.wait()
console.log('Cancel transaction hash: ', cancelTx.hash)
})
diff --git a/contracts/tasks/claim.ts b/contracts/tasks/claim.ts
new file mode 100644
index 000000000..258e6d46b
--- /dev/null
+++ b/contracts/tasks/claim.ts
@@ -0,0 +1,56 @@
+/**
+ * Claim funds. This script is mainly used by e2e testing
+ *
+ * Sample usage:
+ * yarn hardhat claim --funding-round --network
+ */
+
+import { task } from 'hardhat/config'
+import { getEventArg } from '../utils/contracts'
+import { getRecipientClaimData } from '@clrfund/common'
+import { JSONFile } from '../utils/JSONFile'
+import { getTalyFilePath } from '../utils/misc'
+
+task('claim', 'Claim funnds for test recipients')
+ .addParam('fundingRound', 'The funding round contract address')
+ .addParam('tallyDirectory', 'The tally file directory')
+ .setAction(async ({ fundingRound, tallyDirectory }, { ethers }) => {
+ const [, , recipient0, recipient1, recipient2] = await ethers.getSigners()
+ const tallyFile = getTalyFilePath(tallyDirectory)
+ const tally = JSONFile.read(tallyFile)
+
+ const fundingRoundContract = await ethers.getContractAt(
+ 'FundingRound',
+ fundingRound
+ )
+ const pollAddress = await fundingRoundContract.poll()
+ console.log('pollAddress', pollAddress)
+
+ const poll = await ethers.getContractAt('Poll', pollAddress)
+ const recipientTreeDepth = (await poll.treeDepths()).voteOptionTreeDepth
+
+ // Claim funds
+ const recipients = [recipient0, recipient1, recipient2]
+ for (const recipientIndex of [1, 2]) {
+ const recipientClaimData = getRecipientClaimData(
+ recipientIndex,
+ recipientTreeDepth,
+ tally
+ )
+ const fundingRoundAsRecipient = fundingRoundContract.connect(
+ recipients[recipientIndex]
+ )
+ const claimTx = await fundingRoundAsRecipient.claimFunds(
+ ...recipientClaimData
+ )
+ const claimedAmount = await getEventArg(
+ claimTx,
+ fundingRoundAsRecipient,
+ 'FundsClaimed',
+ '_amount'
+ )
+ console.log(
+ `Recipient ${recipientIndex} claimed ${claimedAmount} tokens.`
+ )
+ }
+ })
diff --git a/contracts/tasks/contribute.ts b/contracts/tasks/contribute.ts
new file mode 100644
index 000000000..7417ecc78
--- /dev/null
+++ b/contracts/tasks/contribute.ts
@@ -0,0 +1,76 @@
+/**
+ * Contribute to a funding round. This script is mainly used by e2e testing
+ * All the input used by the script comes from the state.json file
+ *
+ * Sample usage:
+ * yarn hardhat contribute --state-file --network
+ */
+
+import { task } from 'hardhat/config'
+import { JSONFile } from '../utils/JSONFile'
+import { Keypair } from '@clrfund/common'
+
+import { UNIT } from '../utils/constants'
+import { getEventArg } from '../utils/contracts'
+
+task('contribute', 'Contribute to a funding round')
+ .addParam('stateFile', 'The file to store the state information')
+ .setAction(async ({ stateFile }, { ethers }) => {
+ const [, , , , , , , , , , , , contributor1, contributor2] =
+ await ethers.getSigners()
+
+ const state = JSONFile.read(stateFile)
+ const fundingRound = await ethers.getContractAt(
+ 'FundingRound',
+ state.fundingRound
+ )
+ const tokenAddress = await fundingRound.nativeToken()
+ const token = await ethers.getContractAt('AnyOldERC20Token', tokenAddress)
+ const maciAddress = await fundingRound.maci()
+ const maci = await ethers.getContractAt('MACI', maciAddress)
+
+ const contributionAmount = UNIT.mul(16).div(10)
+
+ state.contributors = {}
+ for (const contributor of [contributor1, contributor2]) {
+ const contributorAddress = await contributor.getAddress()
+
+ // transfer token to contributor first
+ await token.transfer(contributorAddress, contributionAmount)
+
+ const contributorKeypair = new Keypair()
+ const tokenAsContributor = token.connect(contributor)
+ await tokenAsContributor.approve(fundingRound.address, contributionAmount)
+
+ const fundingRoundAsContributor = fundingRound.connect(contributor)
+ const contributionTx = await fundingRoundAsContributor.contribute(
+ contributorKeypair.pubKey.asContractParam(),
+ contributionAmount
+ )
+ const stateIndex = await getEventArg(
+ contributionTx,
+ maci,
+ 'SignUp',
+ '_stateIndex'
+ )
+ const voiceCredits = await getEventArg(
+ contributionTx,
+ maci,
+ 'SignUp',
+ '_voiceCreditBalance'
+ )
+ console.log('saving states')
+ state.contributors[contributorAddress] = {
+ privKey: contributorKeypair.privKey.serialize(),
+ pubKey: contributorKeypair.pubKey.serialize(),
+ stateIndex: parseInt(stateIndex),
+ voiceCredits: voiceCredits.toString(),
+ }
+ console.log(
+ `Contributor ${contributorAddress} registered. State index: ${stateIndex}. Voice credits: ${voiceCredits.toString()}.`
+ )
+ }
+
+ // Update state file
+ JSONFile.update(stateFile, state)
+ })
diff --git a/contracts/tasks/finalize.ts b/contracts/tasks/finalize.ts
new file mode 100644
index 000000000..62a061093
--- /dev/null
+++ b/contracts/tasks/finalize.ts
@@ -0,0 +1,65 @@
+/**
+ * Finalize a funding round
+ *
+ * Sample usage:
+ * yarn hardhat finalize \
+ * --funding-round --network
+ */
+
+import { task } from 'hardhat/config'
+import { JSONFile } from '../utils/JSONFile'
+import { genTallyResultCommitment } from '@clrfund/common'
+
+task('finalize', 'Finalize a funding round')
+ .addParam('clrfund', 'The ClrFund contract address')
+ .addParam('tallyFile', 'The tally file path')
+ .setAction(async ({ clrfund, tallyFile }, { ethers }) => {
+ const tally = JSONFile.read(tallyFile)
+ if (!tally.maci) {
+ throw Error('Bad tally file ' + tallyFile)
+ }
+
+ const clrfundContract = await ethers.getContractAt('ClrFund', clrfund)
+ console.log('ClrFund address', clrfund)
+
+ const currentRoundAddress = await clrfundContract.getCurrentRound()
+ const fundingRound = await ethers.getContractAt(
+ 'FundingRound',
+ currentRoundAddress
+ )
+ console.log('Current round', fundingRound.address)
+
+ const pollAddress = await fundingRound.poll()
+ const pollContract = await ethers.getContractAt('Poll', pollAddress)
+ console.log('Poll', pollAddress)
+
+ const treeDepths = await pollContract.treeDepths()
+ console.log('voteOptionTreeDepth', treeDepths.voteOptionTreeDepth)
+
+ const totalSpent = parseInt(tally.totalSpentVoiceCredits.spent)
+ const totalSpentSalt = tally.totalSpentVoiceCredits.salt
+
+ const resultsCommitment = genTallyResultCommitment(
+ tally.results.tally.map((x: string) => BigInt(x)),
+ tally.results.salt,
+ treeDepths.voteOptionTreeDepth
+ )
+
+ const perVOVoiceCreditCommitment = genTallyResultCommitment(
+ tally.perVOSpentVoiceCredits.tally.map((x: string) => BigInt(x)),
+ tally.perVOSpentVoiceCredits.salt,
+ treeDepths.voteOptionTreeDepth
+ )
+
+ const tx = await clrfundContract.transferMatchingFunds(
+ totalSpent,
+ totalSpentSalt,
+ resultsCommitment,
+ perVOVoiceCreditCommitment
+ )
+ const receipt = await tx.wait()
+ console.log(
+ 'Round finalized, totals verified. Gas used:',
+ receipt.gasUsed.toString()
+ )
+ })
diff --git a/contracts/tasks/index.ts b/contracts/tasks/index.ts
index 1988492ab..12beb4e12 100644
--- a/contracts/tasks/index.ts
+++ b/contracts/tasks/index.ts
@@ -1,20 +1,35 @@
+import './newDeployer'
+import './newClrFund'
+import './newMaciKey'
+import './newRound'
+import './setToken'
+import './setCoordinator'
+import './setUserRegistry'
+import './setRecipientRegistry'
+import './setMaciParameters'
+import './setPollFactory'
+import './cancelRound'
+import './addContributors'
+import './addRecipients'
+import './contribute'
+import './vote'
+import './timeTravel'
+import './finalize'
+import './claim'
+
+import './verifyAll'
import './verifyMaciFactory'
-import './verifyRoundFactory'
-//import './verifyRound'
-//import './verifyMaci'
-//import './verifyRecipientRegistry'
-//import './verifyUserRegistry'
-//import './verifyAll'
-//import './cancelRound'
-//import './evmIncreaseTime'
-//import './auditTally'
-//import './exportRound'
-//import './mergeAllocations'
-//import './setDurations'
-//import './deploySponsor'
-//import './loadUsers'
-// TODO: make tally script work with MACI v1
-//import './tally'
-//import './findStorageSlot'
-//import './setStorageRoot'
-//import './loadMerkleUsers'
+import './verifyRound'
+import './verifyMaci'
+import './verifyRecipientRegistry'
+import './verifyUserRegistry'
+import './auditTally'
+import './exportRound'
+import './mergeAllocations'
+import './deploySponsor'
+import './loadUsers'
+import './findStorageSlot'
+import './setStorageRoot'
+import './loadMerkleUsers'
+
+import './pubkey'
diff --git a/contracts/tasks/newClrFund.ts b/contracts/tasks/newClrFund.ts
new file mode 100644
index 000000000..54a5c18ca
--- /dev/null
+++ b/contracts/tasks/newClrFund.ts
@@ -0,0 +1,144 @@
+/**
+ * Create a new instance of the ClrFund contract.
+ * If the coordinator ETH address is not provided, use the signer address
+ * If the coordinator MACI secret key is not provided, create a random one
+ *
+ * Sample usage:
+ *
+ * yarn hardhat new-clrfund --network \
+ * --deployer \
+ * --token \
+ * [--coordinator ] \
+ * [--coordinator-macisk ] \
+ * [--user-type ] \
+ * [--recipient-type ]
+ *
+ *
+ * If user registry address and recipient registry address are not provided,
+ * the registry types become mandatory as well as the other parameters needed
+ * to deploy the registries
+ *
+ * If token is not provided, a new ERC20 token will be created
+ */
+
+import { task } from 'hardhat/config'
+import { getEventArg } from '../utils/contracts'
+import { challengePeriodSeconds } from '../utils/deployment'
+import { JSONFile } from '../utils/JSONFile'
+
+task('new-clrfund', 'Deploy a new ClrFund instance')
+ .addParam('deployer', 'ClrFund deployer contract address')
+ .addOptionalParam('token', 'The token address')
+ .addOptionalParam('coordinator', 'The coordinator ETH address')
+ .addOptionalParam(
+ 'coordinatorMacisk',
+ 'The coordinator MACI serialized secret key'
+ )
+ .addOptionalParam(
+ 'userType',
+ 'The user registry type, e.g brightid, simple, merkle, snapshot'
+ )
+ .addOptionalParam('userRegistry', 'The user registry contract address')
+ .addOptionalParam('context', 'The BrightId context')
+ .addOptionalParam('verifier', 'The BrightId verifier address')
+ .addOptionalParam('sponsor', 'The BrightId sponsor contract address')
+ .addOptionalParam('recipientType', 'The recipient registry type')
+ .addOptionalParam('recipientRegistry', 'The recipient registry address')
+ .addOptionalParam(
+ 'deposit',
+ 'The deposit for optimistic recipient registry',
+ '0.01'
+ )
+ .addOptionalParam(
+ 'challengePeriod',
+ 'The challenge period for optimistic recipient registry',
+ challengePeriodSeconds
+ )
+ .addOptionalParam('stateFile', 'The state file to save the clrfund address')
+ .setAction(
+ async (
+ {
+ deployer,
+ token,
+ coordinator,
+ coordinatorMacisk,
+ userType,
+ userRegistry,
+ context,
+ verifier,
+ sponsor,
+ recipientType,
+ recipientRegistry,
+ deposit,
+ challengePeriod,
+ stateFile,
+ },
+ { run, ethers }
+ ) => {
+ const [signer] = await ethers.getSigners()
+ console.log(`Deploying from address: ${signer.address}`)
+
+ const clrfundDeployer = await ethers.getContractAt(
+ 'ClrFundDeployer',
+ deployer
+ )
+ console.log('ClrFundDeployer:', clrfundDeployer.address)
+
+ const tx = await clrfundDeployer.deployClrFund()
+ const receipt = await tx.wait()
+
+ let clrfund: string
+ try {
+ clrfund = await getEventArg(
+ tx,
+ clrfundDeployer,
+ 'NewInstance',
+ 'clrfund'
+ )
+ console.log('ClrFund: ', clrfund)
+ } catch (e) {
+ console.log('receipt', receipt)
+ throw new Error(
+ 'Unable to get clrfund address after deployment. ' +
+ (e as Error).message
+ )
+ }
+
+ // set coordinator, use the coordinator address if available,
+ // otherwise use the signer address
+ // If the maci secret key is not provided, it will create a new key
+ const coordinatorAddress = coordinator ?? signer.address
+ await run('set-coordinator', {
+ clrfund,
+ coordinator: coordinatorAddress,
+ coordinatorMacisk,
+ stateFile,
+ })
+
+ // set token
+ await run('set-token', { clrfund, token })
+
+ // set user registry
+ await run('set-user-registry', {
+ clrfund,
+ type: userType,
+ registry: userRegistry,
+ context,
+ verifier,
+ sponsor,
+ })
+
+ // set recipient registry
+ await run('set-recipient-registry', {
+ clrfund,
+ type: recipientType,
+ registry: recipientRegistry,
+ deposit,
+ challengePeriod,
+ })
+
+ if (stateFile) {
+ JSONFile.update(stateFile, { clrfund })
+ }
+ }
+ )
diff --git a/contracts/tasks/newDeployer.ts b/contracts/tasks/newDeployer.ts
new file mode 100644
index 000000000..d14f499e2
--- /dev/null
+++ b/contracts/tasks/newDeployer.ts
@@ -0,0 +1,75 @@
+/**
+ * Create a new instance of the ClrFundDeployer
+ *
+ * Sample usage:
+ *
+ * yarn hardhat new-deployer --network
+ *
+ */
+
+import { task } from 'hardhat/config'
+import {
+ deployContract,
+ deployPoseidonLibraries,
+ deployMaciFactory,
+} from '../utils/deployment'
+import { DEFAULT_CIRCUIT } from '../utils/circuits'
+import { JSONFile } from '../utils/JSONFile'
+
+task('new-deployer', 'Create the ClrFund deployer and its dependent contracts')
+ .addParam('circuit', 'The circuit type', DEFAULT_CIRCUIT)
+ .addParam('directory', 'The zkeys directory')
+ .addParam('stateFile', 'The file to save the deployer contract address')
+ .setAction(
+ async ({ circuit, directory, stateFile }, { ethers, config, run }) => {
+ const [signer] = await ethers.getSigners()
+ console.log(`Deploying from address: ${signer.address}`)
+
+ const libraries = await deployPoseidonLibraries({
+ artifactsPath: config.paths.artifacts,
+ signer,
+ ethers,
+ })
+ console.log('Deployed Poseidons', libraries)
+
+ const maciFactory = await deployMaciFactory({ libraries, ethers })
+ console.log('Deployed MaciFactory at', maciFactory.address)
+
+ await run('set-maci-parameters', {
+ maciFactory: maciFactory.address,
+ circuit,
+ directory,
+ })
+
+ const clrfundTemplate = await deployContract({
+ name: 'ClrFund',
+ ethers,
+ })
+ console.log('Deployed clrfundTemplate at', clrfundTemplate.address)
+
+ const fundingRoundFactory = await deployContract({
+ name: 'FundingRoundFactory',
+ libraries,
+ ethers,
+ })
+ console.log(
+ 'Deployed FundingRoundFactory at',
+ fundingRoundFactory.address
+ )
+
+ const clrfundDeployer = await deployContract({
+ name: 'ClrFundDeployer',
+ ethers,
+ contractArgs: [
+ clrfundTemplate.address,
+ maciFactory.address,
+ fundingRoundFactory.address,
+ ],
+ })
+ console.log('Deployed ClrfundDeployer at', clrfundDeployer.address)
+
+ if (stateFile) {
+ JSONFile.update(stateFile, { deployer: clrfundDeployer.address })
+ }
+ }
+ )
diff --git a/contracts/tasks/newMaciKey.ts b/contracts/tasks/newMaciKey.ts
new file mode 100644
index 000000000..ff8152e25
--- /dev/null
+++ b/contracts/tasks/newMaciKey.ts
@@ -0,0 +1,19 @@
+/**
+ * Create a new MACI key pair
+ *
+ * Sample usage:
+ *
+ * yarn hardhat new-maci-key
+ */
+
+import { task } from 'hardhat/config'
+import { Keypair } from '@clrfund/maci-domainobjs'
+
+task('new-maci-key', 'Create a random maci key pair').setAction(async () => {
+ const keypair = new Keypair()
+ const SecretKey = keypair.privKey.serialize()
+ const PublicKey = keypair.pubKey.serialize()
+
+ console.log(`SecretKey: ${SecretKey}`)
+ console.log(`PublicKey: ${PublicKey}`)
+})
diff --git a/contracts/tasks/newRound.ts b/contracts/tasks/newRound.ts
new file mode 100644
index 000000000..c58ff2b50
--- /dev/null
+++ b/contracts/tasks/newRound.ts
@@ -0,0 +1,77 @@
+/**
+ * Create a new instance of the ClrFundDeployer
+ *
+ * Sample usage:
+ *
+ * yarn hardhat new-round \
+ * --network \
+ * --clrfund \
+ * --duration
+ *
+ */
+import { task, types } from 'hardhat/config'
+import { JSONFile } from '../utils/JSONFile'
+
+task('new-round', 'Deploy a new funding round contract')
+ .addParam('clrfund', 'ClrFund contract address')
+ .addParam('duration', 'The funding round duration in seconds')
+ .addOptionalParam(
+ 'newBrightid',
+ 'Create a new BrightId user registry',
+ false,
+ types.boolean
+ )
+ .addOptionalParam('context', 'BrightId context')
+ .addOptionalParam('verifier', 'BrightId verifier')
+ .addOptionalParam('sponsor', 'BrightId sponsor')
+ .addOptionalParam('stateFile', 'Save the state information in state file')
+ .setAction(
+ async (
+ { clrfund, duration, newBrightid, context, verifier, sponsor, stateFile },
+ { ethers, run }
+ ) => {
+ const [signer] = await ethers.getSigners()
+ console.log(`Deploying from address: ${signer.address}`)
+
+ const clrfundContract = await ethers.getContractAt('ClrFund', clrfund)
+
+ // check if the current round is finalized before starting a new round to avoid revert
+ const currentRoundAddress = await clrfundContract.getCurrentRound()
+ if (currentRoundAddress !== ethers.constants.AddressZero) {
+ const currentRound = await ethers.getContractAt(
+ 'FundingRound',
+ currentRoundAddress
+ )
+ const isFinalized = await currentRound.isFinalized()
+ if (!isFinalized) {
+ throw new Error(
+ 'Cannot start a new round as the current round is not finalized'
+ )
+ }
+ }
+
+ if (newBrightid) {
+ await run('set-user-registry', {
+ clrfund,
+ type: 'brightid',
+ sponsor,
+ verifier,
+ context,
+ })
+ }
+
+ const tx = await clrfundContract.deployNewRound(duration)
+ await tx.wait()
+ const fundingRound = await clrfundContract.getCurrentRound()
+ console.log('New funding round address: ', fundingRound)
+
+ if (stateFile) {
+ const pollId = 0
+ const state = { fundingRound, pollId, maciTxHash: tx.hash }
+ JSONFile.update(stateFile, state)
+ }
+ console.log('*******************')
+ console.log('Script complete!')
+ console.log('*******************')
+ }
+ )
diff --git a/contracts/tasks/pubkey.ts b/contracts/tasks/pubkey.ts
new file mode 100644
index 000000000..592bfd0f4
--- /dev/null
+++ b/contracts/tasks/pubkey.ts
@@ -0,0 +1,30 @@
+/**
+ * Print the serialized MACI public key given either the secret key or
+ * the x and y values of the public key
+ *
+ * Usage: hardhat pubkey --macisk
+ */
+import { utils } from 'ethers'
+import { task } from 'hardhat/config'
+import { PubKey, PrivKey, Keypair } from '@clrfund/maci-domainobjs'
+
+task('pubkey', 'Get the serialized MACI public key')
+ .addOptionalParam('x', 'MACI public key x')
+ .addOptionalParam('y', 'MACI public key y')
+ .addOptionalParam('macisk', 'MACI secret key')
+ .setAction(async ({ x, y, macisk }) => {
+ if (macisk) {
+ const keypair = new Keypair(PrivKey.unserialize(macisk))
+ console.log(`Public Key: ${keypair.pubKey.serialize()}`)
+ } else {
+ if (!x || !y) {
+ console.error('Must provide either macisk or x y values')
+ return
+ }
+ const pubKey = new PubKey([BigInt(x), BigInt(y)])
+ console.log(`Public Key: ${pubKey.serialize()}`)
+
+ const id = utils.id(x + '.' + y)
+ console.log(`Subgraph id: ${id}`)
+ }
+ })
diff --git a/contracts/tasks/setCoordinator.ts b/contracts/tasks/setCoordinator.ts
new file mode 100644
index 000000000..6d259b535
--- /dev/null
+++ b/contracts/tasks/setCoordinator.ts
@@ -0,0 +1,68 @@
+/**
+ * Set the coordinator in ClrFund, create the MACI key if not provided
+ *
+ * Sample usage:
+ *
+ * yarn hardhat set-coordinator --network \
+ * --clrfund \
+ * --coordinator \
+ * [--coordinator-macisk ]
+ */
+
+import { task } from 'hardhat/config'
+import { PrivKey, Keypair } from '@clrfund/maci-domainobjs'
+import { Contract } from 'ethers'
+
+/**
+ * Set the coordinator address and maci public key in the funding round factory
+ *
+ * @param fundingRoundFactory funding round factory contract
+ * @param coordinatorAddress
+ * @param MaciPrivateKey
+ */
+async function setCoordinator({
+ clrfundContract,
+ coordinatorAddress,
+ coordinatorMacisk,
+}: {
+ clrfundContract: Contract
+ coordinatorAddress: string
+ coordinatorMacisk?: string
+ stateFile?: string
+}) {
+ // Generate or use the passed in coordinator key
+ const privKey = coordinatorMacisk
+ ? PrivKey.unserialize(coordinatorMacisk)
+ : undefined
+
+ const keypair = new Keypair(privKey)
+ const coordinatorPubKey = keypair.pubKey
+ const SecretKey = keypair.privKey.serialize()
+ const PublicKey = keypair.pubKey.serialize()
+
+ const setCoordinatorTx = await clrfundContract.setCoordinator(
+ coordinatorAddress,
+ coordinatorPubKey.asContractParam()
+ )
+ await setCoordinatorTx.wait()
+
+ console.log(`Coordinator address: ${coordinatorAddress}`)
+ console.log(`SecretKey: ${SecretKey}`)
+ console.log(`PublicKey: ${PublicKey}`)
+}
+
+task('set-coordinator', 'Set the coordinator address and maci key')
+ .addParam('clrfund', 'The funding round factory contract address')
+ .addParam('coordinator', 'The coordinator ETH address')
+ .addOptionalParam('coordinatorMacisk', 'The coordinator maci secret key')
+ .setAction(
+ async ({ clrfund, coordinator, coordinatorMacisk }, { ethers }) => {
+ const clrfundContract = await ethers.getContractAt('ClrFund', clrfund)
+
+ await setCoordinator({
+ clrfundContract,
+ coordinatorAddress: coordinator,
+ coordinatorMacisk,
+ })
+ }
+ )
diff --git a/contracts/tasks/setDurations.ts b/contracts/tasks/setDurations.ts
deleted file mode 100644
index 29567f812..000000000
--- a/contracts/tasks/setDurations.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { task, types } from 'hardhat/config'
-import { MaciParameters } from '../utils/maci'
-
-task('set-durations', 'Set the signup and voting durations for future rounds')
- .addParam('factory', 'The funding round factory contract address')
- .addParam('signup', 'Sign up duration in minutes', 60, types.int)
- .addParam('voting', 'Voting duration in minutes', 10, types.int)
- .setAction(async ({ factory, signup, voting }, { ethers }) => {
- const signUpDuration = signup * 60
- const votingDuration = voting * 60
-
- const fundingRoundFactory = await ethers.getContractAt(
- 'FundingRoundFactory',
- factory
- )
-
- const maciFactoryAddress = await fundingRoundFactory.maciFactory()
- const maciFactory = await ethers.getContractAt(
- 'MACIFactory',
- maciFactoryAddress
- )
- const maciParameters = await MaciParameters.read(maciFactory)
- maciParameters.update({
- signUpDuration,
- votingDuration,
- })
- const setMaciParametersTx = await fundingRoundFactory.setMaciParameters(
- ...maciParameters.values()
- )
- await setMaciParametersTx.wait()
-
- const newParams = await MaciParameters.read(maciFactory)
- console.log('New durations set', newParams)
- })
diff --git a/contracts/tasks/setMaciParameters.ts b/contracts/tasks/setMaciParameters.ts
new file mode 100644
index 000000000..ad4a3678a
--- /dev/null
+++ b/contracts/tasks/setMaciParameters.ts
@@ -0,0 +1,33 @@
+/**
+ * Set the zkeys parameters in MACI factory
+ * Sample usage:
+ *
+ * yarn hardhat set-maci-parameters \
+ * --circuit \
+ * --maci-factory \
+ * --network
+ *
+ * See utils/circuits.ts for the circuit type value
+ */
+
+import { task } from 'hardhat/config'
+import { DEFAULT_CIRCUIT } from '../utils/circuits'
+import { MaciParameters } from '../utils/maciParameters'
+
+task('set-maci-parameters', 'Set the token in ClrFund')
+ .addParam('maciFactory', 'The MACIFactory contract address')
+ .addParam('circuit', 'The circuit type', DEFAULT_CIRCUIT)
+ .addParam('directory', 'The zkeys directory')
+ .setAction(async ({ maciFactory, circuit, directory }, { ethers }) => {
+ const factory = await ethers.getContractAt('MACIFactory', maciFactory)
+
+ const maciParameters = await MaciParameters.fromConfig(circuit, directory)
+ const setMaciTx = await factory.setMaciParameters(
+ ...maciParameters.asContractParam()
+ )
+ console.log('Set MACI parameters at ', setMaciTx.hash)
+ await setMaciTx.wait()
+
+ const newParameters = await MaciParameters.fromContract(factory)
+ console.log(newParameters)
+ })
diff --git a/contracts/tasks/setPollFactory.ts b/contracts/tasks/setPollFactory.ts
new file mode 100644
index 000000000..921872f6a
--- /dev/null
+++ b/contracts/tasks/setPollFactory.ts
@@ -0,0 +1,39 @@
+/**
+ * Set the Poll factory in the MACI factory
+ * Usage:
+ * hardhat set-poll-factory \
+ * --maci-factory \
+ * [--poll-factory ] \
+ * --network
+ */
+import { task } from 'hardhat/config'
+import { deployPollFactory } from '../utils/deployment'
+
+task(
+ 'set-poll-factory',
+ 'Set (create if non-existent) the Poll factory address in the MACI factory'
+)
+ .addParam('maciFactory', 'The MACI factory contract address')
+ .addOptionalParam('pollFactory', 'The poll factory contract address')
+ .setAction(async ({ maciFactory, pollFactory }, { ethers, config }) => {
+ const maciFactoryContract = await ethers.getContractAt(
+ 'MACIFactory',
+ maciFactory
+ )
+
+ let pollFactoryAddress = pollFactory
+ if (!pollFactoryAddress) {
+ const [signer] = await ethers.getSigners()
+ const pollFactoryContract = await deployPollFactory({
+ signer,
+ ethers,
+ artifactPath: config.paths.artifacts,
+ })
+ pollFactoryAddress = pollFactoryContract.address
+ }
+
+ const tx = await maciFactoryContract.setPollFactory(pollFactoryAddress)
+ await tx.wait()
+
+ console.log('Set poll factory at tx', tx.hash)
+ })
diff --git a/contracts/tasks/setRecipientRegistry.ts b/contracts/tasks/setRecipientRegistry.ts
new file mode 100644
index 000000000..e92553933
--- /dev/null
+++ b/contracts/tasks/setRecipientRegistry.ts
@@ -0,0 +1,137 @@
+/**
+ * Set the recipient registry in the ClrFund contract.
+ *
+ * Sample usage:
+ *
+ * yarn hardhat set-recipient-registry --network \
+ * --clrfund \
+ * [--type ] \
+ * [--registry ] \
+ * [--context ] \
+ * [--verifier ] \
+ * [--sponsor ]
+ *
+ * Valid user registry types are simple, brightid, merkle, storage
+ *
+ * Verifier is the brightid node verifier address.
+ * Clrfund's brightId node is in the ethSigningAddress field from https://brightid.clr.fund
+ *
+ */
+
+import { task } from 'hardhat/config'
+import { BigNumber, Contract, utils } from 'ethers'
+import { HardhatEthersHelpers } from '@nomiclabs/hardhat-ethers/types'
+import {
+ deployRecipientRegistry,
+ challengePeriodSeconds,
+} from '../utils/deployment'
+
+async function getDepositInUnits(
+ clrfundContract: Contract,
+ ethers: HardhatEthersHelpers,
+ deposit: string
+): Promise {
+ let depositInUnits = BigNumber.from(0)
+ try {
+ const token = await clrfundContract.nativeToken()
+ const tokenContract = await ethers.getContractAt('ERC20', token)
+ const decimals = await tokenContract.decimals()
+ depositInUnits = utils.parseUnits(deposit, decimals)
+ } catch (e) {
+ console.log('Error formatting deposit amount ' + (e as Error).message)
+ console.log('Set deposit to 0')
+ }
+
+ return depositInUnits
+}
+
+/**
+ * Set the token address in the ClrFund contract
+ *
+ * @param clrfundContract ClrFund contract
+ * @param registryType The user registry type, e.g brightid, simple, merkle, snapshot
+ * @param registryAddress The user registry address to set in ClrFund
+ * @param ethers the hardhat ethers handle
+ */
+async function setRecipientRegistry({
+ clrfundContract,
+ registryType,
+ registryAddress,
+ deposit,
+ challengePeriod,
+ ethers,
+}: {
+ clrfundContract: Contract
+ registryType?: string
+ registryAddress?: string
+ deposit: string
+ challengePeriod: string
+ ethers: HardhatEthersHelpers
+}) {
+ let recipientRegistryAddress = registryAddress
+ if (!recipientRegistryAddress) {
+ const recipientRegistryType = registryType || ''
+ const [signer] = await ethers.getSigners()
+ console.log(`Deploying recipient registry by: ${signer.address}`)
+
+ const controller = clrfundContract.address
+ const depositInUnits = await getDepositInUnits(
+ clrfundContract,
+ ethers,
+ deposit
+ )
+ const registry = await deployRecipientRegistry({
+ type: recipientRegistryType,
+ controller,
+ deposit: depositInUnits,
+ challengePeriod,
+ ethers,
+ })
+ recipientRegistryAddress = registry.address
+ }
+
+ const tx = await clrfundContract.setRecipientRegistry(
+ recipientRegistryAddress
+ )
+ await tx.wait()
+
+ console.log(
+ `Recipient registry (${registryType}): ${recipientRegistryAddress}`
+ )
+ console.log(`Recipient registry set at tx: ${tx.hash}`)
+}
+
+task('set-recipient-registry', 'Set the recipient registry in ClrFund')
+ .addParam('clrfund', 'The ClrFund contract address')
+ .addOptionalParam(
+ 'type',
+ 'The recipient registry type, e.g simple, optimistic'
+ )
+ .addOptionalParam('registry', 'The user registry contract address')
+ .addOptionalParam(
+ 'deposit',
+ 'The base deposit for the optimistic registry',
+ '0.001'
+ )
+ .addOptionalParam(
+ 'challengePeriod',
+ 'The challenge period in seconds',
+ challengePeriodSeconds
+ )
+ .setAction(
+ async (
+ { clrfund, type, registry, deposit, challengePeriod },
+ { ethers }
+ ) => {
+ const clrfundContract = await ethers.getContractAt('ClrFund', clrfund)
+
+ await setRecipientRegistry({
+ clrfundContract: clrfundContract,
+ registryType: type,
+ registryAddress: registry,
+ deposit,
+ challengePeriod,
+ ethers,
+ })
+ }
+ )
diff --git a/contracts/tasks/setToken.ts b/contracts/tasks/setToken.ts
new file mode 100644
index 000000000..f4096d175
--- /dev/null
+++ b/contracts/tasks/setToken.ts
@@ -0,0 +1,51 @@
+/**
+ * Set the native token in the ClrFund contract
+ * Sample usage:
+ *
+ * yarn hardhat set-token --token --clrfund --network arbitrum-goerli
+ */
+
+import { task } from 'hardhat/config'
+import { Contract, BigNumber } from 'ethers'
+import { deployContract } from '../utils/deployment'
+import { UNIT } from '../utils/constants'
+
+/**
+ * Set the token address in the ClrFund contract
+ *
+ * @param clrfundContract ClrFund contract
+ * @param tokenAddress The token address to set in ClrFund
+ */
+async function setToken(clrfundContract: Contract, tokenAddress: string) {
+ const tx = await clrfundContract.setToken(tokenAddress)
+ await tx.wait()
+
+ console.log(`Token set at tx: ${tx.hash}`)
+}
+
+task('set-token', 'Set the token in ClrFund')
+ .addParam('clrfund', 'The ClrFund contract address')
+ .addOptionalParam('token', 'The token address')
+ .addOptionalParam('tokenAmount', 'Initial token amount', '1000')
+ .setAction(async ({ clrfund, token, tokenAmount }, { ethers }) => {
+ const [signer] = await ethers.getSigners()
+ const clrfundContract = await ethers.getContractAt(
+ 'ClrFund',
+ clrfund,
+ signer
+ )
+ console.log('Setting token by', signer.address)
+
+ let tokenAddress: string = token || ''
+ if (!tokenAddress) {
+ const initialTokenSupply = BigNumber.from(tokenAmount).mul(UNIT)
+ const tokenContract = await deployContract({
+ name: 'AnyOldERC20Token',
+ contractArgs: [initialTokenSupply],
+ ethers,
+ })
+ tokenAddress = tokenContract.address
+ console.log('New token address', tokenAddress)
+ }
+ await setToken(clrfundContract, tokenAddress)
+ })
diff --git a/contracts/tasks/setUserRegistry.ts b/contracts/tasks/setUserRegistry.ts
new file mode 100644
index 000000000..cc6db87b7
--- /dev/null
+++ b/contracts/tasks/setUserRegistry.ts
@@ -0,0 +1,115 @@
+/**
+ * Set the user registry in the ClrFund contract.
+ *
+ * Sample usage:
+ *
+ * yarn hardhat set-user-registry --network \
+ * --clrfund \
+ * [--type ] \
+ * [--registry ] \
+ * [--context ] \
+ * [--verifier ] \
+ * [--sponsor ]
+ *
+ * Valid user registry types are simple, brightid, merkle, storage
+ *
+ * Verifier is the brightid node verifier address.
+ * Clrfund's brightId node is in the ethSigningAddress field from https://brightid.clr.fund
+ *
+ * Context is the bright app id
+ * The context value can be found here: https://apps.brightid.org/#nodes
+ */
+
+import { task } from 'hardhat/config'
+import { Contract } from 'ethers'
+import { HardhatEthersHelpers } from '@nomiclabs/hardhat-ethers/types'
+import { BrightIdParams, deployUserRegistry } from '../utils/deployment'
+/**
+ * Set the token address in the ClrFund contract
+ *
+ * @param clrfundContract ClrFund contract
+ * @param registryType The user registry type, e.g brightid, simple, merkle, snapshot
+ * @param registryAddress The user registry address to set in ClrFund
+ */
+async function setUserRegistry({
+ clrfundContract,
+ registryType,
+ registryAddress,
+ brightIdParams,
+ ethers,
+}: {
+ clrfundContract: Contract
+ registryType?: string
+ registryAddress?: string
+ brightIdParams?: BrightIdParams
+ ethers: HardhatEthersHelpers
+}) {
+ let userRegistryAddress = registryAddress
+ if (!userRegistryAddress) {
+ const userRegistryType = registryType || ''
+ const [signer] = await ethers.getSigners()
+ console.log(`Deploying a user registry by: ${signer.address}`)
+
+ const registry = await deployUserRegistry(
+ userRegistryType,
+ ethers,
+ brightIdParams
+ )
+ userRegistryAddress = registry.address
+ }
+
+ const tx = await clrfundContract.setUserRegistry(userRegistryAddress)
+ await tx.wait()
+
+ console.log(`User registry (${registryType}): ${userRegistryAddress}`)
+ console.log(`User registry set at tx ${tx.hash}`)
+}
+
+task('set-user-registry', 'Set the user registry in ClrFund')
+ .addParam('clrfund', 'The ClrFund contract address')
+ .addOptionalParam(
+ 'type',
+ 'The user registry type, e.g brightid, simple, merkle, snapshot'
+ )
+ .addOptionalParam('registry', 'The user registry contract address')
+ .addOptionalParam('context', 'The BrightId context')
+ .addOptionalParam('verifier', 'The BrightId verifier address')
+ .addOptionalParam('sponsor', 'The BrightId sponsor contract address')
+ .setAction(
+ async (
+ { clrfund, type, registry, context, verifier, sponsor },
+ { ethers }
+ ) => {
+ const clrfundContract = await ethers.getContractAt('ClrFund', clrfund)
+
+ let brightIdParams: BrightIdParams | undefined = undefined
+
+ if (type === 'brightid') {
+ if (!context) {
+ throw Error('BrightId context is required')
+ }
+
+ if (!verifier) {
+ throw Error('BrightId node verifier address is required')
+ }
+
+ if (!sponsor) {
+ throw Error('BrightId sponsor contract address is required')
+ }
+
+ brightIdParams = {
+ context,
+ verifierAddress: verifier,
+ sponsor,
+ }
+ }
+
+ await setUserRegistry({
+ clrfundContract: clrfundContract,
+ registryType: type,
+ registryAddress: registry,
+ brightIdParams,
+ ethers,
+ })
+ }
+ )
diff --git a/contracts/tasks/tally.ts b/contracts/tasks/tally.ts
deleted file mode 100644
index a058b853e..000000000
--- a/contracts/tasks/tally.ts
+++ /dev/null
@@ -1,257 +0,0 @@
-import { task, types } from 'hardhat/config'
-import fs from 'fs'
-import { Contract, Wallet } from 'ethers'
-import { genProofs, proveOnChain } from 'maci-cli'
-
-import { getIpfsHash } from '../utils/ipfs'
-import { addTallyResultsBatch } from '../utils/maci'
-
-/**
- * Tally votes for the specified funding round. This task can be rerun by
- * passing in additional parameters: --maci-logs, --maci-state-file
- *
- * Make sure to set the following environment variables in the .env file
- * if not running test using the localhost network
- * 1) COORDINATOR_ETH_PK - coordinator's wallet private key to interact with contracts
- * 2) COORDINATOR_PK - coordinator's MACI private key to decrypt messages
- *
- * Sample usage:
- *
- * yarn hardhat tally --round-address --start-block --network
- *
- * To rerun:
- *
- * yarn hardhat tally --round-address --network \
- * --maci-logs --maci-state-file
- */
-
-type TallyArgs = {
- fundingRound: Contract
- coordinatorMaciPrivKey: string
- coordinator: Wallet
- startBlock: number
- numBlocksPerRequest: number
- batchSize: number
- logsFile: string
- maciStateFile: string
- providerUrl: string
- voteOptionTreeDepth: number
- shouldFetchLogs: boolean
-}
-
-async function main(args: TallyArgs) {
- const {
- fundingRound,
- coordinatorMaciPrivKey,
- coordinator,
- batchSize,
- logsFile,
- maciStateFile,
- providerUrl,
- voteOptionTreeDepth,
- shouldFetchLogs,
- startBlock,
- numBlocksPerRequest,
- } = args
-
- console.log('funding round address', fundingRound.address)
- const maciAddress = await fundingRound.maci()
- console.log('maci address', maciAddress)
-
- const publishedTallyHash = await fundingRound.tallyHash()
- console.log('publishedTallyHash', publishedTallyHash)
-
- let tally
- if (!publishedTallyHash) {
- const maciAddress = await fundingRound.maci()
- console.log('maci address', maciAddress)
-
- /* TODO: fix this, fetchLog is not available in v1
- if (shouldFetchLogs) {
- // Fetch Maci logs
- console.log('Fetching MACI logs from block', startBlock)
- try {
- await fetchLogs({
- contract: maciAddress,
- eth_provider: providerUrl,
- privkey: coordinatorMaciPrivKey,
- start_block: startBlock,
- num_blocks_per_request: numBlocksPerRequest,
- output: logsFile,
- })
- console.log('MACI logs generated at', logsFile)
- } catch (err) {
- console.log('Failed to fetchLogs', err)
- throw err
- }
- }*/
-
- // Process messages and tally votes
- const results = await genProofs({
- contract: maciAddress,
- eth_provider: providerUrl,
- privkey: coordinatorMaciPrivKey,
- tally_file: 'tally.json',
- output: 'proofs.json',
- logs_file: logsFile,
- macistate: maciStateFile,
- })
- if (!results) {
- throw new Error('generation of proofs failed')
- }
- const { proofs } = results
- tally = results.tally
-
- // Submit proofs to MACI contract
- await proveOnChain({
- contract: maciAddress,
- eth_privkey: coordinator.privateKey,
- eth_provider: providerUrl,
- privkey: coordinatorMaciPrivKey,
- proof_file: proofs,
- })
-
- // Publish tally hash
- const tallyHash = await getIpfsHash(tally)
- await fundingRound.publishTallyHash(tallyHash)
- console.log(`Tally hash is ${tallyHash}`)
- } else {
- // read the tally.json file
- console.log(`Tally hash is ${publishedTallyHash}`)
- try {
- console.log(`Reading tally.json file...`)
- const tallyStr = fs.readFileSync('tally.json').toString()
- tally = JSON.parse(tallyStr)
- } catch (err) {
- console.log('Failed to get tally file', publishedTallyHash, err)
- throw err
- }
- }
-
- // Submit results to the funding round contract
- const startIndex = await fundingRound.totalTallyResults()
- const total = tally.results.tally.length
- console.log('Uploading tally results in batches of', batchSize)
- const addTallyGas = await addTallyResultsBatch(
- fundingRound,
- voteOptionTreeDepth,
- tally,
- batchSize,
- startIndex.toNumber(),
- (processed: number) => {
- console.log(`Processed ${processed} / ${total}`)
- }
- )
- console.log('Tally results uploaded. Gas used:', addTallyGas.toString())
-}
-
-task('tally', 'Tally votes for the current round')
- .addParam(
- 'roundAddress',
- 'The funding round contract address',
- '',
- types.string
- )
- .addParam(
- 'batchSize',
- 'Number of tally result to submit on chain per batch',
- 20,
- types.int
- )
- .addParam(
- 'numBlocksPerRequest',
- 'The number of blocks to fetch for each get log request',
- 200000,
- types.int
- )
- .addParam(
- 'startBlock',
- 'The first block containing the MACI events',
- 0,
- types.int
- )
- .addOptionalParam('maciLogs', 'The file path containing the MACI logs')
- .addOptionalParam(
- 'maciStateFile',
- 'The MACI state file, genProof will continue from it last run'
- )
- .setAction(
- async (
- {
- roundAddress,
- maciLogs,
- maciStateFile,
- batchSize,
- startBlock,
- numBlocksPerRequest,
- },
- { ethers, network }
- ) => {
- let fundingRoundAddress = roundAddress
- let coordinatorMaciPrivKey = process.env.COORDINATOR_PK || ''
- let coordinatorEthPrivKey =
- process.env.COORDINATOR_ETH_PK || process.env.WALLET_PRIVATE_KEY || ''
- const providerUrl = (network.config as any).url
-
- if (network.name === 'localhost') {
- const stateStr = fs.readFileSync('state.json').toString()
- const state = JSON.parse(stateStr)
- fundingRoundAddress = state.fundingRound
- coordinatorMaciPrivKey = state.coordinatorPrivKey
- // default to the first account
- coordinatorEthPrivKey = coordinatorEthPrivKey
- ? coordinatorEthPrivKey
- : '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'
- } else {
- if (!coordinatorEthPrivKey) {
- throw Error(
- `Please set the environment variable COORDINATOR_ETH_PK, the coordinator's wallet private key`
- )
- }
-
- if (!coordinatorMaciPrivKey) {
- throw Error(
- `Please set the environment variable COORDINATOR_PK, the coordinator's MACI private key`
- )
- }
- }
-
- if (!fundingRoundAddress) {
- throw Error(`The '--round-address' parameter is required`)
- }
-
- console.log('Funding round address: ', fundingRoundAddress)
- const coordinator = new Wallet(coordinatorEthPrivKey, ethers.provider)
- console.log('Coordinator address: ', coordinator.address)
-
- const fundingRound = await ethers.getContractAt(
- 'FundingRound',
- fundingRoundAddress,
- coordinator
- )
-
- const maciAddress = await fundingRound.maci()
- const maci = await ethers.getContractAt('MACI', maciAddress, coordinator)
- const [, , voteOptionTreeDepth] = await maci.treeDepths()
- console.log('Vote option tree depth', voteOptionTreeDepth)
-
- const timeMs = new Date().getTime()
- const logsFile = maciLogs ? maciLogs : `maci_logs_${timeMs}.json`
-
- await main({
- fundingRound,
- coordinatorMaciPrivKey,
- coordinator,
- startBlock,
- numBlocksPerRequest,
- batchSize,
- voteOptionTreeDepth: Number(voteOptionTreeDepth),
- logsFile,
- providerUrl,
- shouldFetchLogs: !maciLogs,
- maciStateFile: maciStateFile
- ? maciStateFile
- : `maci_state_${timeMs}.json`,
- })
- }
- )
diff --git a/contracts/tasks/evmIncreaseTime.ts b/contracts/tasks/timeTravel.ts
similarity index 73%
rename from contracts/tasks/evmIncreaseTime.ts
rename to contracts/tasks/timeTravel.ts
index 7ee995fcf..6854dade3 100644
--- a/contracts/tasks/evmIncreaseTime.ts
+++ b/contracts/tasks/timeTravel.ts
@@ -1,9 +1,9 @@
import { task, types } from 'hardhat/config'
-task('evm-increase-time', 'Increase block timestamp by seconds')
+task('time-travel', 'Travel to block timestamp in seconds')
.addPositionalParam(
'seconds',
- 'The number of seconds to increase',
+ 'The number of seconds to travel to',
undefined,
types.int,
false
diff --git a/contracts/tasks/verifyAll.ts b/contracts/tasks/verifyAll.ts
index bef27e87c..2b9da8ac3 100644
--- a/contracts/tasks/verifyAll.ts
+++ b/contracts/tasks/verifyAll.ts
@@ -8,22 +8,41 @@ type Result = {
status: string
}
-async function verifyMaciFactory(factory: Contract, run: any): Promise {
+async function verifyDeployer(deployer: Contract, run: any): Promise {
try {
- const address = await factory.maciFactory()
+ const { address } = deployer
+ const constructorArguments = await Promise.all([
+ deployer.clrfundTemplate(),
+ deployer.maciFactory(),
+ deployer.roundFactory(),
+ ])
+
+ await run('verify:verify', { address, constructorArguments })
+ return SUCCESS
+ } catch (error) {
+ return (error as Error).message
+ }
+}
+
+async function verifyMaciFactory(
+ deployer: Contract,
+ run: any
+): Promise {
+ try {
+ const address = await deployer.maciFactory()
await run('verify-maci-factory', { address })
return SUCCESS
} catch (error) {
- return error.message
+ return (error as Error).message
}
}
-async function verifyRoundFactory(address: string, run: any): Promise {
+async function verifyClrFund(clrfund: Contract, run: any): Promise {
try {
- await run('verify-round-factory', { address })
+ await run('verify', { address: clrfund.address })
return SUCCESS
} catch (error) {
- return error.message
+ return (error as Error).message
}
}
@@ -36,7 +55,7 @@ async function verifyRecipientRegistry(
await run('verify-recipient-registry', { address })
return SUCCESS
} catch (error) {
- return error.message
+ return (error as Error).message
}
}
@@ -49,7 +68,7 @@ async function verifyUserRegistry(
await run('verify-user-registry', { address })
return SUCCESS
} catch (error) {
- return error.message
+ return (error as Error).message
}
}
@@ -58,7 +77,7 @@ async function verifyRound(address: string, run: any): Promise {
await run('verify-round', { address })
return SUCCESS
} catch (error) {
- return error.message
+ return (error as Error).message
}
}
@@ -67,54 +86,58 @@ async function verifyMaci(maciAddress: string, run: any): Promise {
await run('verify-maci', { maciAddress })
return SUCCESS
} catch (error) {
- return error.message
+ return (error as Error).message
}
}
-async function verifyStateTreeVerifier(
- maciAddress: string,
- run: any,
- ethers: any
-): Promise {
+async function verifyTally(tally: Contract, run: any): Promise {
try {
- const rawAddress = await ethers.provider.getStorageAt(maciAddress, 1)
- const address = ethers.utils.hexDataSlice(rawAddress, 12)
- await run('verify:verify', { address })
+ const constructorArguments = await Promise.all([tally.verifier()])
+ await run('verify:verify', { address: tally.address, constructorArguments })
return SUCCESS
} catch (error) {
- return error.message
+ return (error as Error).message
}
}
-async function verifyTallyVerifier(
- maciAddress: string,
- run: any,
- ethers: any
-): Promise {
+async function verifyPoll(pollContract: Contract, run: any): Promise {
try {
- const rawAddress = await ethers.provider.getStorageAt(maciAddress, 2)
- const address = ethers.utils.hexDataSlice(rawAddress, 12)
- await run('verify:verify', { address })
+ const constructorArguments = await Promise.all([
+ pollContract.duration(),
+ pollContract.maxValues(),
+ pollContract.treeDepths(),
+ pollContract.batchSizes(),
+ pollContract.coordinatorPubKey(),
+ pollContract.extContracts(),
+ ])
+ const { address } = pollContract
+ await run('verify:verify', { address, constructorArguments })
return SUCCESS
} catch (error) {
- return error.message
+ return (error as Error).message
}
}
-async function verifySponsor(address: string, run: any): Promise {
+async function verifyContract(
+ name: string,
+ address: string,
+ run: any,
+ results: Result[]
+) {
+ let result = SUCCESS
try {
await run('verify:verify', { address })
- return SUCCESS
} catch (error) {
- return error.message
+ result = (error as Error).message
}
+ results.push({ name, status: result })
}
async function getBrightIdSponsor(
- factory: Contract,
+ clrfund: Contract,
ethers: any
): Promise {
- const userRegistryAddress = await factory.userRegistry()
+ const userRegistryAddress = await clrfund.userRegistry()
const userRegistry = await ethers.getContractAt(
'BrightIdUserRegistry',
userRegistryAddress
@@ -131,42 +154,89 @@ async function getBrightIdSponsor(
* Verifies all the contracts created for clrfund app
*/
task('verify-all', 'Verify all clrfund contracts')
- .addPositionalParam('address', 'Funding round factory contract address')
- .setAction(async ({ address }, { run, ethers }) => {
- const factory = await ethers.getContractAt('FundingRoundFactory', address)
- const roundAddress = await factory.getCurrentRound()
+ .addParam('deployer', 'ClrFundDeployer contract address')
+ .addOptionalParam('clrfund', 'ClrFund contract address')
+ .setAction(async ({ deployer, clrfund }, { run, ethers }) => {
+ const deployerContract = await ethers.getContractAt(
+ 'ClrFundDeployer',
+ deployer
+ )
+ const maciFactoryAddress = await deployerContract.maciFactory()
+ const maciFactory = await ethers.getContractAt(
+ 'MACIFactory',
+ maciFactoryAddress
+ )
const results: Result[] = []
- let status = await verifyMaciFactory(factory, run)
+ let status = await verifyDeployer(deployerContract, run)
+ results.push({ name: 'ClrFund Deployer', status })
+ status = await verifyMaciFactory(deployerContract, run)
results.push({ name: 'Maci facotry', status })
- status = await verifyRoundFactory(address, run)
- results.push({ name: 'Funding round factory', status })
- status = await verifyRecipientRegistry(factory, run)
- results.push({ name: 'Recipient registry', status })
- status = await verifyUserRegistry(factory, run)
- results.push({ name: 'User factory', status })
-
- const sponsor = await getBrightIdSponsor(factory, ethers)
- if (sponsor) {
- status = await verifySponsor(sponsor, run)
- results.push({ name: 'BrightId sponsor', status })
- }
-
- if (roundAddress !== ethers.constants.AddressZero) {
- const round = await ethers.getContractAt('FundingRound', roundAddress)
- const maciAddress = await round.maci()
- status = await verifyRound(roundAddress, run)
- results.push({ name: 'Funding round', status })
- status = await verifyMaci(maciAddress, run)
- results.push({ name: 'MACI', status })
- status = await verifyStateTreeVerifier(maciAddress, run, ethers)
- results.push({ name: 'BatchUpdateStateTreeVerifier', status })
-
- status = await verifyTallyVerifier(maciAddress, run, ethers)
- results.push({ name: 'QuadVoteTallyVerifier', status })
+ if (clrfund) {
+ const clrfundContract = await ethers.getContractAt('ClrFund', clrfund)
+ status = await verifyClrFund(clrfundContract, run)
+ results.push({ name: 'ClrFund', status })
+ status = await verifyRecipientRegistry(clrfundContract, run)
+ results.push({ name: 'Recipient registry', status })
+ status = await verifyUserRegistry(clrfundContract, run)
+ results.push({ name: 'User factory', status })
+ const sponsor = await getBrightIdSponsor(clrfundContract, ethers)
+ if (sponsor) {
+ await verifyContract('Sponsor', sponsor, run, results)
+ }
+
+ const roundAddress = await clrfundContract.getCurrentRound()
+ if (roundAddress !== ethers.constants.AddressZero) {
+ const round = await ethers.getContractAt('FundingRound', roundAddress)
+ const maciAddress = await round.maci()
+ status = await verifyRound(roundAddress, run)
+ results.push({ name: 'Funding round', status })
+ status = await verifyMaci(maciAddress, run)
+ results.push({ name: 'MACI', status })
+
+ const poll = await round.poll()
+ if (poll !== ethers.constants.AddressZero) {
+ const pollContract = await ethers.getContractAt('Poll', poll)
+ status = await verifyPoll(pollContract, run)
+ results.push({ name: 'Poll', status })
+ }
+
+ const tally = await round.tally()
+ if (tally !== ethers.constants.AddressZero) {
+ const tallyContract = await ethers.getContractAt('Tally', tally)
+ status = await verifyTally(tallyContract, run)
+ results.push({ name: 'Tally', status })
+ }
+
+ await verifyContract(
+ 'TopupToken',
+ await round.topupToken(),
+ run,
+ results
+ )
+ }
}
+ await verifyContract(
+ 'clrfundTemplate',
+ await deployerContract.clrfundTemplate(),
+ run,
+ results
+ )
+ await verifyContract(
+ 'VkRegistry',
+ await maciFactory.vkRegistry(),
+ run,
+ results
+ )
+ await verifyContract(
+ 'PollFactory',
+ await maciFactory.pollFactory(),
+ run,
+ results
+ )
+
results.forEach(({ name, status }, i) => {
const color = status === SUCCESS ? '32' : '31'
console.log(`${i} ${name}: \x1b[%sm%s\x1b[0m`, color, status)
diff --git a/contracts/tasks/verifyMaciFactory.ts b/contracts/tasks/verifyMaciFactory.ts
index 31761119f..54fdcf86f 100644
--- a/contracts/tasks/verifyMaciFactory.ts
+++ b/contracts/tasks/verifyMaciFactory.ts
@@ -1,53 +1,12 @@
import { task } from 'hardhat/config'
import { Contract } from 'ethers'
-type ProvidedArgs = {
- signupDuration?: string
- votingDuration?: string
-}
-
-async function getConstructorArguments(
- maciFactory: Contract,
- provided: ProvidedArgs = {}
-): Promise {
- const signupPromise = provided.signupDuration
- ? Promise.resolve(provided.signupDuration)
- : maciFactory.signUpDuration()
-
- const votingPromise = provided.votingDuration
- ? Promise.resolve(provided.votingDuration)
- : maciFactory.votingDuration()
-
- const [
- treeDepths,
- batchSizes,
- batchUstVerifier,
- qvtVerifier,
- signUpDuration,
- votingDuration,
- ] = await Promise.all([
- maciFactory.treeDepths(),
- maciFactory.batchSizes(),
- maciFactory.batchUstVerifier(),
- maciFactory.qvtVerifier(),
- signupPromise,
- votingPromise,
+async function getConstructorArguments(maciFactory: Contract): Promise {
+ const result = await Promise.all([
+ maciFactory.vkRegistry(),
+ maciFactory.pollFactory(),
])
-
- const [stateTreeDepth, messageTreeDepth, voteOptionTreeDepth] = treeDepths
- const [tallyBatchSize, messageBatchSize] = batchSizes
-
- return [
- stateTreeDepth,
- messageTreeDepth,
- voteOptionTreeDepth,
- tallyBatchSize,
- messageBatchSize,
- batchUstVerifier,
- qvtVerifier,
- signUpDuration,
- votingDuration,
- ]
+ return result
}
/**
@@ -57,21 +16,14 @@ async function getConstructorArguments(
*/
task('verify-maci-factory', 'Verify a MACI factory contract')
.addParam('address', 'MACI factory contract address')
- .addOptionalParam('signupDuration', 'Signup duration in seconds')
- .addOptionalParam('votingDuration', 'Voting duration in seconds')
- .setAction(
- async ({ address, signupDuration, votingDuration }, { run, ethers }) => {
- const maciFactory = await ethers.getContractAt('MACIFactory', address)
+ .setAction(async ({ address }, { run, ethers }) => {
+ const maciFactory = await ethers.getContractAt('MACIFactory', address)
- const constructorArguments = await getConstructorArguments(maciFactory, {
- signupDuration,
- votingDuration,
- })
- console.log('Constructor arguments', constructorArguments)
+ const constructorArguments = await getConstructorArguments(maciFactory)
+ console.log('Constructor arguments', constructorArguments)
- await run('verify:verify', {
- address,
- constructorArguments,
- })
- }
- )
+ await run('verify:verify', {
+ address,
+ constructorArguments,
+ })
+ })
diff --git a/contracts/tasks/verifyRoundFactory.ts b/contracts/tasks/verifyRoundFactory.ts
deleted file mode 100644
index ccc768361..000000000
--- a/contracts/tasks/verifyRoundFactory.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { task } from 'hardhat/config'
-
-task('verify-round-factory', 'Verify a funding round factory contract')
- .addPositionalParam('address', 'Funding round factory contract address')
- .setAction(async ({ address }, { run, ethers }) => {
- const fundingRoundFactory = await ethers.getContractAt(
- 'FundingRoundFactory',
- address
- )
- const maciFactoryAddress = await fundingRoundFactory.maciFactory()
-
- const constructorArguments = [maciFactoryAddress]
-
- console.log('Constructor arguments', constructorArguments)
-
- await run('verify:verify', {
- address,
- constructorArguments,
- })
- })
diff --git a/contracts/tasks/vote.ts b/contracts/tasks/vote.ts
new file mode 100644
index 000000000..0e423b032
--- /dev/null
+++ b/contracts/tasks/vote.ts
@@ -0,0 +1,84 @@
+/**
+ * Contribute to a funding round. This script is mainly used by e2e testing
+ * All the input used by the script comes from the state.json file
+ *
+ * Sample usage:
+ * yarn hardhat contribute \
+ * --coordinator-macisk \
+ * --state-file
+ * --network
+ */
+
+import { task } from 'hardhat/config'
+import { JSONFile } from '../utils/JSONFile'
+import { PrivKey, Keypair, createMessage } from '@clrfund/common'
+import { BigNumber } from 'ethers'
+
+task('vote', 'Cast votes for test users')
+ .addParam('coordinatorMacisk', 'The coordinator MACI secret key')
+ .addParam('stateFile', 'The file to store the state information')
+ .setAction(async ({ coordinatorMacisk, stateFile }, { ethers }) => {
+ const [, , , , , , , , , , , , contributor1, contributor2] =
+ await ethers.getSigners()
+
+ const state = JSONFile.read(stateFile)
+ const coordinatorKeyPair = new Keypair(
+ PrivKey.unserialize(coordinatorMacisk)
+ )
+
+ const pollId = state.pollId
+ for (const contributor of [contributor1, contributor2]) {
+ const contributorAddress = await contributor.getAddress()
+ const contributorData = state.contributors[contributorAddress]
+ const contributorKeyPair = new Keypair(
+ PrivKey.unserialize(contributorData.privKey)
+ )
+
+ const messages: { msgType: any; data: string[] }[] = []
+ const encPubKeys: any[] = []
+ let nonce = 1
+ // Change key
+ const newContributorKeypair = new Keypair()
+ const [message, encPubKey] = createMessage(
+ contributorData.stateIndex,
+ contributorKeyPair,
+ newContributorKeypair,
+ coordinatorKeyPair.pubKey,
+ null,
+ null,
+ nonce,
+ pollId
+ )
+ messages.push(message.asContractParam())
+ encPubKeys.push(encPubKey.asContractParam())
+ nonce += 1
+ // Vote
+ for (const recipientIndex of [1, 2]) {
+ const votes = BigNumber.from(contributorData.voiceCredits).div(4)
+ const [message, encPubKey] = createMessage(
+ contributorData.stateIndex,
+ newContributorKeypair,
+ null,
+ coordinatorKeyPair.pubKey,
+ recipientIndex,
+ votes,
+ nonce,
+ pollId
+ )
+ messages.push(message.asContractParam())
+ encPubKeys.push(encPubKey.asContractParam())
+ nonce += 1
+ }
+
+ const fundingRoundAsContributor = await ethers.getContractAt(
+ 'FundingRound',
+ state.fundingRound,
+ contributor
+ )
+ await fundingRoundAsContributor.submitMessageBatch(
+ messages.reverse(),
+ encPubKeys.reverse()
+ )
+ console.log(`Contributor ${contributorAddress} voted.`)
+ }
+ })
diff --git a/contracts/tests/deployer.ts b/contracts/tests/deployer.ts
index e86b06356..1f708fade 100644
--- a/contracts/tests/deployer.ts
+++ b/contracts/tests/deployer.ts
@@ -1,7 +1,7 @@
-import { ethers, waffle } from 'hardhat'
+import { ethers, waffle, config } from 'hardhat'
import { use, expect } from 'chai'
import { solidity } from 'ethereum-waffle'
-import { Signer, Contract, ContractTransaction } from 'ethers'
+import { Signer, Contract, ContractTransaction, constants } from 'ethers'
import { genRandomSalt } from 'maci-crypto'
import { Keypair } from '@clrfund/common'
@@ -9,29 +9,37 @@ import { ZERO_ADDRESS, UNIT } from '../utils/constants'
import { getGasUsage, getEventArg } from '../utils/contracts'
import {
deployContract,
- deployContractWithLinkedLibraries,
- deployMaciFactory,
deployPoseidonLibraries,
+ deployMaciFactory,
} from '../utils/deployment'
-import { MaciParameters } from '../utils/maci'
+import { MaciParameters } from '../utils/maciParameters'
+import { DEFAULT_CIRCUIT } from '../utils/circuits'
use(solidity)
const roundDuration = 10000
-const circuit = 'micro'
+const circuit = DEFAULT_CIRCUIT
async function setRoundTally(
clrfund: Contract,
coordinator: Signer
): Promise {
- const libraries = await deployPoseidonLibraries(coordinator)
- const verifier = await deployContract(coordinator, 'MockVerifier')
- const tally = await deployContractWithLinkedLibraries(
- coordinator,
- 'Tally',
+ const libraries = await deployPoseidonLibraries({
+ artifactsPath: config.paths.artifacts,
+ ethers,
+ })
+ const verifier = await deployContract({
+ name: 'MockVerifier',
+ ethers,
+ signer: coordinator,
+ })
+ const tally = await deployContract({
+ name: 'Tally',
libraries,
- [verifier.address]
- )
+ contractArgs: [verifier.address],
+ signer: coordinator,
+ ethers,
+ })
const roundAddress = await clrfund.getCurrentRound()
const round = await ethers.getContractAt(
'FundingRound',
@@ -49,7 +57,7 @@ describe('Clr fund deployer', () => {
let userRegistry: Contract
let recipientRegistry: Contract
let factoryTemplate: Contract
- let factory: Contract
+ let clrfund: Contract
let clrFundDeployer: Contract
let token: Contract
const coordinatorPubKey = new Keypair().pubKey.asContractParam()
@@ -57,35 +65,55 @@ describe('Clr fund deployer', () => {
beforeEach(async () => {
if (!poseidonContracts) {
- poseidonContracts = await deployPoseidonLibraries(deployer)
+ poseidonContracts = await deployPoseidonLibraries({
+ artifactsPath: config.paths.artifacts,
+ ethers,
+ })
}
- maciFactory = await deployMaciFactory(deployer, poseidonContracts)
+
+ maciFactory = await deployMaciFactory({
+ libraries: poseidonContracts,
+ signer: deployer,
+ ethers,
+ })
const params = MaciParameters.mock(circuit)
await maciFactory.setMaciParameters(...params.asContractParam())
- factoryTemplate = await deployContractWithLinkedLibraries(
- deployer,
- 'ClrFund',
- poseidonContracts
- )
+ factoryTemplate = await deployContract({
+ name: 'ClrFund',
+ ethers,
+ signer: deployer,
+ })
expect(factoryTemplate.address).to.properAddress
expect(await getGasUsage(factoryTemplate.deployTransaction)).lessThan(
5400000
)
- clrFundDeployer = await deployContract(deployer, 'ClrFundDeployer', [
- factoryTemplate.address,
- ])
+ const roundFactory = await deployContract({
+ name: 'FundingRoundFactory',
+ libraries: poseidonContracts,
+ ethers,
+ })
+ expect(await getGasUsage(roundFactory.deployTransaction)).lessThan(4000000)
+
+ clrFundDeployer = await deployContract({
+ name: 'ClrFundDeployer',
+ contractArgs: [
+ factoryTemplate.address,
+ maciFactory.address,
+ roundFactory.address,
+ ],
+ ethers,
+ signer: deployer,
+ })
expect(clrFundDeployer.address).to.properAddress
expect(await getGasUsage(clrFundDeployer.deployTransaction)).lessThan(
5400000
)
- const newInstanceTx = await clrFundDeployer.deployClrFund(
- maciFactory.address
- )
+ const newInstanceTx = await clrFundDeployer.deployClrFund()
const instanceAddress = await getEventArg(
newInstanceTx,
clrFundDeployer,
@@ -93,7 +121,7 @@ describe('Clr fund deployer', () => {
'clrfund'
)
- factory = await ethers.getContractAt('ClrFund', instanceAddress, deployer)
+ clrfund = await ethers.getContractAt('ClrFund', instanceAddress, deployer)
const SimpleUserRegistry = await ethers.getContractFactory(
'SimpleUserRegistry',
@@ -104,7 +132,7 @@ describe('Clr fund deployer', () => {
'SimpleRecipientRegistry',
deployer
)
- recipientRegistry = await SimpleRecipientRegistry.deploy(factory.address)
+ recipientRegistry = await SimpleRecipientRegistry.deploy(clrfund.address)
// Deploy token contract and transfer tokens to contributor
@@ -116,85 +144,86 @@ describe('Clr fund deployer', () => {
})
it('can only be initialized once', async () => {
- await expect(factory.init(maciFactory.address)).to.be.revertedWith(
- 'Initializable: contract is already initialized'
- )
+ const dummyRoundFactory = constants.AddressZero
+ await expect(
+ clrfund.init(maciFactory.address, dummyRoundFactory)
+ ).to.be.revertedWith('Initializable: contract is already initialized')
})
it('can register with the subgraph', async () => {
await expect(
clrFundDeployer.registerInstance(
- factory.address,
+ clrfund.address,
'{name:dead,title:beef}'
)
)
.to.emit(clrFundDeployer, 'Register')
- .withArgs(factory.address, '{name:dead,title:beef}')
+ .withArgs(clrfund.address, '{name:dead,title:beef}')
})
it('cannot register with the subgraph twice', async () => {
await expect(
clrFundDeployer.registerInstance(
- factory.address,
+ clrfund.address,
'{name:dead,title:beef}'
)
)
.to.emit(clrFundDeployer, 'Register')
- .withArgs(factory.address, '{name:dead,title:beef}')
+ .withArgs(clrfund.address, '{name:dead,title:beef}')
await expect(
clrFundDeployer.registerInstance(
- factory.address,
+ clrfund.address,
'{name:dead,title:beef}'
)
).to.be.revertedWith('ClrFundAlreadyRegistered')
})
- it('initializes factory', async () => {
- expect(await factory.coordinator()).to.equal(ZERO_ADDRESS)
- expect(await factory.nativeToken()).to.equal(ZERO_ADDRESS)
- expect(await factory.maciFactory()).to.equal(maciFactory.address)
- expect(await factory.userRegistry()).to.equal(ZERO_ADDRESS)
- expect(await factory.recipientRegistry()).to.equal(ZERO_ADDRESS)
+ it('initializes clrfund', async () => {
+ expect(await clrfund.coordinator()).to.equal(ZERO_ADDRESS)
+ expect(await clrfund.nativeToken()).to.equal(ZERO_ADDRESS)
+ expect(await clrfund.maciFactory()).to.equal(maciFactory.address)
+ expect(await clrfund.userRegistry()).to.equal(ZERO_ADDRESS)
+ expect(await clrfund.recipientRegistry()).to.equal(ZERO_ADDRESS)
})
it('transfers ownership to another address', async () => {
- await expect(factory.transferOwnership(coordinator.address))
- .to.emit(factory, 'OwnershipTransferred')
+ await expect(clrfund.transferOwnership(coordinator.address))
+ .to.emit(clrfund, 'OwnershipTransferred')
.withArgs(deployer.address, coordinator.address)
})
describe('changing user registry', () => {
it('allows owner to set user registry', async () => {
- await factory.setUserRegistry(userRegistry.address)
- expect(await factory.userRegistry()).to.equal(userRegistry.address)
+ await clrfund.setUserRegistry(userRegistry.address)
+ expect(await clrfund.userRegistry()).to.equal(userRegistry.address)
})
it('allows only owner to set user registry', async () => {
await expect(
- factory.connect(contributor).setUserRegistry(userRegistry.address)
+ clrfund.connect(contributor).setUserRegistry(userRegistry.address)
).to.be.revertedWith('Ownable: caller is not the owner')
})
it('allows owner to change recipient registry', async () => {
- await factory.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
const SimpleUserRegistry = await ethers.getContractFactory(
'SimpleUserRegistry',
deployer
)
const anotherUserRegistry = await SimpleUserRegistry.deploy()
- await factory.setUserRegistry(anotherUserRegistry.address)
- expect(await factory.userRegistry()).to.equal(anotherUserRegistry.address)
+ await clrfund.setUserRegistry(anotherUserRegistry.address)
+ expect(await clrfund.userRegistry()).to.equal(anotherUserRegistry.address)
})
})
describe('changing recipient registry', () => {
it('allows owner to set recipient registry', async () => {
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
- await factory.setRecipientRegistry(recipientRegistry.address)
- expect(await factory.recipientRegistry()).to.equal(
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ expect(await clrfund.recipientRegistry()).to.equal(
recipientRegistry.address
)
- expect(await recipientRegistry.controller()).to.equal(factory.address)
+ expect(await recipientRegistry.controller()).to.equal(clrfund.address)
const params = MaciParameters.mock(circuit)
expect(await recipientRegistry.maxRecipients()).to.equal(
5 ** params.voteOptionTreeDepth
@@ -203,23 +232,23 @@ describe('Clr fund deployer', () => {
it('allows only owner to set recipient registry', async () => {
await expect(
- factory
+ clrfund
.connect(contributor)
.setRecipientRegistry(recipientRegistry.address)
).to.be.revertedWith('Ownable: caller is not the owner')
})
it('allows owner to change recipient registry', async () => {
- await factory.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
const SimpleRecipientRegistry = await ethers.getContractFactory(
'SimpleRecipientRegistry',
deployer
)
const anotherRecipientRegistry = await SimpleRecipientRegistry.deploy(
- factory.address
+ clrfund.address
)
- await factory.setRecipientRegistry(anotherRecipientRegistry.address)
- expect(await factory.recipientRegistry()).to.equal(
+ await clrfund.setRecipientRegistry(anotherRecipientRegistry.address)
+ expect(await clrfund.recipientRegistry()).to.equal(
anotherRecipientRegistry.address
)
})
@@ -227,71 +256,71 @@ describe('Clr fund deployer', () => {
describe('managing funding sources', () => {
it('allows owner to add funding source', async () => {
- await expect(factory.addFundingSource(contributor.address))
- .to.emit(factory, 'FundingSourceAdded')
+ await expect(clrfund.addFundingSource(contributor.address))
+ .to.emit(clrfund, 'FundingSourceAdded')
.withArgs(contributor.address)
})
it('allows only owner to add funding source', async () => {
await expect(
- factory.connect(contributor).addFundingSource(contributor.address)
+ clrfund.connect(contributor).addFundingSource(contributor.address)
).to.be.revertedWith('Ownable: caller is not the owner')
})
it('reverts if funding source is already added', async () => {
- await factory.addFundingSource(contributor.address)
+ await clrfund.addFundingSource(contributor.address)
await expect(
- factory.addFundingSource(contributor.address)
+ clrfund.addFundingSource(contributor.address)
).to.be.revertedWith('FundingSourceAlreadyAdded')
})
it('allows owner to remove funding source', async () => {
- await factory.addFundingSource(contributor.address)
- await expect(factory.removeFundingSource(contributor.address))
- .to.emit(factory, 'FundingSourceRemoved')
+ await clrfund.addFundingSource(contributor.address)
+ await expect(clrfund.removeFundingSource(contributor.address))
+ .to.emit(clrfund, 'FundingSourceRemoved')
.withArgs(contributor.address)
})
it('allows only owner to remove funding source', async () => {
- await factory.addFundingSource(contributor.address)
+ await clrfund.addFundingSource(contributor.address)
await expect(
- factory.connect(contributor).removeFundingSource(contributor.address)
+ clrfund.connect(contributor).removeFundingSource(contributor.address)
).to.be.revertedWith('Ownable: caller is not the owner')
})
it('reverts if funding source is already removed', async () => {
- await factory.addFundingSource(contributor.address)
- await factory.removeFundingSource(contributor.address)
+ await clrfund.addFundingSource(contributor.address)
+ await clrfund.removeFundingSource(contributor.address)
await expect(
- factory.removeFundingSource(contributor.address)
+ clrfund.removeFundingSource(contributor.address)
).to.be.revertedWith('FundingSourceNotFound')
})
})
it('allows direct contributions to the matching pool', async () => {
const contributionAmount = UNIT.mul(10)
- await factory.setToken(token.address)
+ await clrfund.setToken(token.address)
await expect(
- token.connect(contributor).transfer(factory.address, contributionAmount)
+ token.connect(contributor).transfer(clrfund.address, contributionAmount)
)
.to.emit(token, 'Transfer')
- .withArgs(contributor.address, factory.address, contributionAmount)
- expect(await token.balanceOf(factory.address)).to.equal(contributionAmount)
+ .withArgs(contributor.address, clrfund.address, contributionAmount)
+ expect(await token.balanceOf(clrfund.address)).to.equal(contributionAmount)
})
describe('deploying funding round', () => {
it('deploys funding round', async () => {
- await factory.setUserRegistry(userRegistry.address)
- await factory.setRecipientRegistry(recipientRegistry.address)
- await factory.setToken(token.address)
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
- const deployed = factory.deployNewRound(roundDuration)
- await expect(deployed).to.emit(factory, 'RoundStarted')
+ await clrfund.setUserRegistry(userRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setToken(token.address)
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
+ const deployed = clrfund.deployNewRound(roundDuration)
+ await expect(deployed).to.emit(clrfund, 'RoundStarted')
const deployTx = await deployed
// TODO: fix gas usage for deployNewRound()
expect(await getGasUsage(deployTx)).lessThan(20000000)
- const fundingRoundAddress = await factory.getCurrentRound()
+ const fundingRoundAddress = await clrfund.getCurrentRound()
expect(fundingRoundAddress).to.properAddress
expect(fundingRoundAddress).to.not.equal(ZERO_ADDRESS)
@@ -299,7 +328,7 @@ describe('Clr fund deployer', () => {
'FundingRound',
fundingRoundAddress
)
- expect(await fundingRound.owner()).to.equal(factory.address)
+ expect(await fundingRound.owner()).to.equal(clrfund.address)
expect(await fundingRound.nativeToken()).to.equal(token.address)
const maciAddress = await getEventArg(
@@ -324,79 +353,79 @@ describe('Clr fund deployer', () => {
})
it('reverts if user registry is not set', async () => {
- await factory.setRecipientRegistry(recipientRegistry.address)
- await factory.setToken(token.address)
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setToken(token.address)
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
- await expect(factory.deployNewRound(roundDuration)).to.be.revertedWith(
+ await expect(clrfund.deployNewRound(roundDuration)).to.be.revertedWith(
'NoUserRegistry'
)
})
it('reverts if recipient registry is not set', async () => {
- await factory.setUserRegistry(userRegistry.address)
- await factory.setToken(token.address)
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
+ await clrfund.setUserRegistry(userRegistry.address)
+ await clrfund.setToken(token.address)
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
- await expect(factory.deployNewRound(roundDuration)).to.be.revertedWith(
+ await expect(clrfund.deployNewRound(roundDuration)).to.be.revertedWith(
'NoRecipientRegistry'
)
})
it('reverts if native token is not set', async () => {
- await factory.setUserRegistry(userRegistry.address)
- await factory.setRecipientRegistry(recipientRegistry.address)
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
+ await clrfund.setUserRegistry(userRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
- await expect(factory.deployNewRound(roundDuration)).to.be.revertedWith(
+ await expect(clrfund.deployNewRound(roundDuration)).to.be.revertedWith(
'NoToken'
)
})
it('reverts if coordinator is not set', async () => {
- await factory.setUserRegistry(userRegistry.address)
- await factory.setRecipientRegistry(recipientRegistry.address)
- await factory.setToken(token.address)
- await expect(factory.deployNewRound(roundDuration)).to.be.revertedWith(
+ await clrfund.setUserRegistry(userRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setToken(token.address)
+ await expect(clrfund.deployNewRound(roundDuration)).to.be.revertedWith(
'NoCoordinator'
)
})
it('reverts if current round is not finalized', async () => {
- await factory.setUserRegistry(userRegistry.address)
- await factory.setRecipientRegistry(recipientRegistry.address)
- await factory.setToken(token.address)
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
+ await clrfund.setUserRegistry(userRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setToken(token.address)
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
- await factory.deployNewRound(roundDuration)
- await expect(factory.deployNewRound(roundDuration)).to.be.revertedWith(
+ await clrfund.deployNewRound(roundDuration)
+ await expect(clrfund.deployNewRound(roundDuration)).to.be.revertedWith(
'NotFinalized'
)
})
it('deploys new funding round after previous round has been finalized', async () => {
- await factory.setUserRegistry(userRegistry.address)
- await factory.setRecipientRegistry(recipientRegistry.address)
- await factory.setToken(token.address)
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
-
- await factory.deployNewRound(roundDuration)
- await factory.cancelCurrentRound()
- await expect(factory.deployNewRound(roundDuration)).to.emit(
- factory,
+ await clrfund.setUserRegistry(userRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setToken(token.address)
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
+
+ await clrfund.deployNewRound(roundDuration)
+ await clrfund.cancelCurrentRound()
+ await expect(clrfund.deployNewRound(roundDuration)).to.emit(
+ clrfund,
'RoundStarted'
)
})
it('only owner can deploy funding round', async () => {
- await factory.setUserRegistry(userRegistry.address)
- await factory.setRecipientRegistry(recipientRegistry.address)
- await factory.setToken(token.address)
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
+ await clrfund.setUserRegistry(userRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setToken(token.address)
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
- const factoryAsContributor = factory.connect(contributor)
+ const clrfundAsContributor = clrfund.connect(contributor)
await expect(
- factoryAsContributor.deployNewRound(roundDuration)
+ clrfundAsContributor.deployNewRound(roundDuration)
).to.be.revertedWith('Ownable: caller is not the owner')
})
})
@@ -409,28 +438,28 @@ describe('Clr fund deployer', () => {
const perVOVoiceCreditCommitment = genRandomSalt().toString()
beforeEach(async () => {
- await factory.setUserRegistry(userRegistry.address)
- await factory.setRecipientRegistry(recipientRegistry.address)
- await factory.setToken(token.address)
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
+ await clrfund.setUserRegistry(userRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setToken(token.address)
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
})
it('returns the amount of available matching funding', async () => {
- await factory.addFundingSource(deployer.address)
- await factory.addFundingSource(contributor.address)
+ await clrfund.addFundingSource(deployer.address)
+ await clrfund.addFundingSource(contributor.address)
// Allowance is more than available balance
- await token.connect(deployer).approve(factory.address, contributionAmount)
+ await token.connect(deployer).approve(clrfund.address, contributionAmount)
// Allowance is less than available balance
await token
.connect(contributor)
- .approve(factory.address, contributionAmount)
+ .approve(clrfund.address, contributionAmount)
// Direct contribution
await token
.connect(contributor)
- .transfer(factory.address, contributionAmount)
+ .transfer(clrfund.address, contributionAmount)
- await factory.deployNewRound(roundDuration)
- expect(await factory.getMatchingFunds(token.address)).to.equal(
+ await clrfund.deployNewRound(roundDuration)
+ expect(await clrfund.getMatchingFunds(token.address)).to.equal(
contributionAmount.mul(2)
)
})
@@ -438,12 +467,12 @@ describe('Clr fund deployer', () => {
it('allows owner to finalize round', async () => {
await token
.connect(contributor)
- .transfer(factory.address, contributionAmount)
- await factory.deployNewRound(roundDuration)
+ .transfer(clrfund.address, contributionAmount)
+ await clrfund.deployNewRound(roundDuration)
await provider.send('evm_increaseTime', [roundDuration])
- await setRoundTally(factory, coordinator)
+ await setRoundTally(clrfund, coordinator)
await expect(
- factory.transferMatchingFunds(
+ clrfund.transferMatchingFunds(
totalSpent,
totalSpentSalt,
resultsCommitment,
@@ -453,11 +482,11 @@ describe('Clr fund deployer', () => {
})
it('allows owner to finalize round even without matching funds', async () => {
- await factory.deployNewRound(roundDuration)
+ await clrfund.deployNewRound(roundDuration)
await provider.send('evm_increaseTime', [roundDuration])
- await setRoundTally(factory, coordinator)
+ await setRoundTally(clrfund, coordinator)
await expect(
- factory.transferMatchingFunds(
+ clrfund.transferMatchingFunds(
totalSpent,
totalSpentSalt,
resultsCommitment,
@@ -467,14 +496,14 @@ describe('Clr fund deployer', () => {
})
it('pulls funds from funding source', async () => {
- await factory.addFundingSource(contributor.address)
- token.connect(contributor).approve(factory.address, contributionAmount)
- await factory.addFundingSource(deployer.address) // Doesn't have tokens
- await factory.deployNewRound(roundDuration)
+ await clrfund.addFundingSource(contributor.address)
+ token.connect(contributor).approve(clrfund.address, contributionAmount)
+ await clrfund.addFundingSource(deployer.address) // Doesn't have tokens
+ await clrfund.deployNewRound(roundDuration)
await provider.send('evm_increaseTime', [roundDuration])
- await setRoundTally(factory, coordinator)
+ await setRoundTally(clrfund, coordinator)
await expect(
- factory.transferMatchingFunds(
+ clrfund.transferMatchingFunds(
totalSpent,
totalSpentSalt,
resultsCommitment,
@@ -484,15 +513,15 @@ describe('Clr fund deployer', () => {
})
it('pulls funds from funding source if allowance is greater than balance', async () => {
- await factory.addFundingSource(contributor.address)
+ await clrfund.addFundingSource(contributor.address)
token
.connect(contributor)
- .approve(factory.address, contributionAmount.mul(2))
- await factory.deployNewRound(roundDuration)
+ .approve(clrfund.address, contributionAmount.mul(2))
+ await clrfund.deployNewRound(roundDuration)
await provider.send('evm_increaseTime', [roundDuration])
- await setRoundTally(factory, coordinator)
+ await setRoundTally(clrfund, coordinator)
await expect(
- factory.transferMatchingFunds(
+ clrfund.transferMatchingFunds(
totalSpent,
totalSpentSalt,
resultsCommitment,
@@ -502,11 +531,11 @@ describe('Clr fund deployer', () => {
})
it('allows only owner to finalize round', async () => {
- await factory.deployNewRound(roundDuration)
+ await clrfund.deployNewRound(roundDuration)
await provider.send('evm_increaseTime', [roundDuration])
- await setRoundTally(factory, coordinator)
+ await setRoundTally(clrfund, coordinator)
await expect(
- factory
+ clrfund
.connect(contributor)
.transferMatchingFunds(
totalSpent,
@@ -519,7 +548,7 @@ describe('Clr fund deployer', () => {
it('reverts if round has not been deployed', async () => {
await expect(
- factory.transferMatchingFunds(
+ clrfund.transferMatchingFunds(
totalSpent,
totalSpentSalt,
resultsCommitment,
@@ -531,72 +560,72 @@ describe('Clr fund deployer', () => {
describe('cancelling round', () => {
beforeEach(async () => {
- await factory.setUserRegistry(userRegistry.address)
- await factory.setRecipientRegistry(recipientRegistry.address)
- await factory.setToken(token.address)
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
+ await clrfund.setUserRegistry(userRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setToken(token.address)
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
})
it('allows owner to cancel round', async () => {
- await factory.deployNewRound(roundDuration)
- const fundingRoundAddress = await factory.getCurrentRound()
+ await clrfund.deployNewRound(roundDuration)
+ const fundingRoundAddress = await clrfund.getCurrentRound()
const fundingRound = await ethers.getContractAt(
'FundingRound',
fundingRoundAddress
)
- await expect(factory.cancelCurrentRound())
- .to.emit(factory, 'RoundFinalized')
+ await expect(clrfund.cancelCurrentRound())
+ .to.emit(clrfund, 'RoundFinalized')
.withArgs(fundingRoundAddress)
expect(await fundingRound.isCancelled()).to.equal(true)
})
it('allows only owner to cancel round', async () => {
- await factory.deployNewRound(roundDuration)
+ await clrfund.deployNewRound(roundDuration)
await expect(
- factory.connect(contributor).cancelCurrentRound()
+ clrfund.connect(contributor).cancelCurrentRound()
).to.be.revertedWith('Ownable: caller is not the owner')
})
it('reverts if round has not been deployed', async () => {
- await expect(factory.cancelCurrentRound()).to.be.revertedWith(
+ await expect(clrfund.cancelCurrentRound()).to.be.revertedWith(
'NoCurrentRound'
)
})
it('reverts if round is finalized', async () => {
- await factory.deployNewRound(roundDuration)
- await factory.cancelCurrentRound()
- await expect(factory.cancelCurrentRound()).to.be.revertedWith(
+ await clrfund.deployNewRound(roundDuration)
+ await clrfund.cancelCurrentRound()
+ await expect(clrfund.cancelCurrentRound()).to.be.revertedWith(
'AlreadyFinalized'
)
})
})
it('allows owner to set native token', async () => {
- await expect(factory.setToken(token.address))
- .to.emit(factory, 'TokenChanged')
+ await expect(clrfund.setToken(token.address))
+ .to.emit(clrfund, 'TokenChanged')
.withArgs(token.address)
- expect(await factory.nativeToken()).to.equal(token.address)
+ expect(await clrfund.nativeToken()).to.equal(token.address)
})
it('only owner can set native token', async () => {
- const factoryAsContributor = factory.connect(contributor)
+ const clrfundAsContributor = clrfund.connect(contributor)
await expect(
- factoryAsContributor.setToken(token.address)
+ clrfundAsContributor.setToken(token.address)
).to.be.revertedWith('Ownable: caller is not the owner')
})
it('allows owner to change coordinator', async () => {
- await expect(factory.setCoordinator(coordinator.address, coordinatorPubKey))
- .to.emit(factory, 'CoordinatorChanged')
+ await expect(clrfund.setCoordinator(coordinator.address, coordinatorPubKey))
+ .to.emit(clrfund, 'CoordinatorChanged')
.withArgs(coordinator.address)
- expect(await factory.coordinator()).to.eq(coordinator.address)
+ expect(await clrfund.coordinator()).to.eq(coordinator.address)
})
it('allows only the owner to set a new coordinator', async () => {
- const factoryAsContributor = factory.connect(contributor)
+ const clrfundAsContributor = clrfund.connect(contributor)
await expect(
- factoryAsContributor.setCoordinator(
+ clrfundAsContributor.setCoordinator(
coordinator.address,
coordinatorPubKey
)
@@ -604,34 +633,34 @@ describe('Clr fund deployer', () => {
})
it('allows coordinator to call coordinatorQuit and sets coordinator to null', async () => {
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
- const factoryAsCoordinator = factory.connect(coordinator)
- await expect(factoryAsCoordinator.coordinatorQuit())
- .to.emit(factory, 'CoordinatorChanged')
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
+ const clrfundAsCoordinator = clrfund.connect(coordinator)
+ await expect(clrfundAsCoordinator.coordinatorQuit())
+ .to.emit(clrfund, 'CoordinatorChanged')
.withArgs(ZERO_ADDRESS)
- expect(await factory.coordinator()).to.equal(ZERO_ADDRESS)
+ expect(await clrfund.coordinator()).to.equal(ZERO_ADDRESS)
})
it('only coordinator can call coordinatorQuit', async () => {
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
- await expect(factory.coordinatorQuit()).to.be.revertedWith('NotAuthorized')
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
+ await expect(clrfund.coordinatorQuit()).to.be.revertedWith('NotAuthorized')
})
it('should cancel current round when coordinator quits', async () => {
- await factory.setUserRegistry(userRegistry.address)
- await factory.setRecipientRegistry(recipientRegistry.address)
- await factory.setToken(token.address)
- await factory.setCoordinator(coordinator.address, coordinatorPubKey)
- await factory.deployNewRound(roundDuration)
- const fundingRoundAddress = await factory.getCurrentRound()
+ await clrfund.setUserRegistry(userRegistry.address)
+ await clrfund.setRecipientRegistry(recipientRegistry.address)
+ await clrfund.setToken(token.address)
+ await clrfund.setCoordinator(coordinator.address, coordinatorPubKey)
+ await clrfund.deployNewRound(roundDuration)
+ const fundingRoundAddress = await clrfund.getCurrentRound()
const fundingRound = await ethers.getContractAt(
'FundingRound',
fundingRoundAddress
)
- const factoryAsCoordinator = factory.connect(coordinator)
- await expect(factoryAsCoordinator.coordinatorQuit())
- .to.emit(factory, 'RoundFinalized')
+ const clrfundAsCoordinator = clrfund.connect(coordinator)
+ await expect(clrfundAsCoordinator.coordinatorQuit())
+ .to.emit(clrfund, 'RoundFinalized')
.withArgs(fundingRoundAddress)
expect(await fundingRound.isCancelled()).to.equal(true)
})
diff --git a/contracts/tests/maciFactory.ts b/contracts/tests/maciFactory.ts
index b43a589bc..f3baa4c2d 100644
--- a/contracts/tests/maciFactory.ts
+++ b/contracts/tests/maciFactory.ts
@@ -1,4 +1,4 @@
-import { waffle, artifacts, ethers } from 'hardhat'
+import { waffle, artifacts, ethers, config } from 'hardhat'
import { Contract } from 'ethers'
import { use, expect } from 'chai'
import { solidity } from 'ethereum-waffle'
@@ -7,7 +7,8 @@ import { Keypair } from '@clrfund/common'
import { getEventArg, getGasUsage } from '../utils/contracts'
import { deployMaciFactory, deployPoseidonLibraries } from '../utils/deployment'
-import { MaciParameters } from '../utils/maci'
+import { MaciParameters } from '../utils/maciParameters'
+import { DEFAULT_CIRCUIT } from '../utils/circuits'
use(solidity)
@@ -26,12 +27,20 @@ describe('MACI factory', () => {
beforeEach(async () => {
if (!poseidonContracts) {
- poseidonContracts = await deployPoseidonLibraries(deployer)
+ poseidonContracts = await deployPoseidonLibraries({
+ artifactsPath: config.paths.artifacts,
+ ethers,
+ signer: deployer,
+ })
}
- maciFactory = await deployMaciFactory(deployer, poseidonContracts)
+ maciFactory = await deployMaciFactory({
+ ethers,
+ signer: deployer,
+ libraries: poseidonContracts,
+ })
expect(await getGasUsage(maciFactory.deployTransaction)).lessThan(5600000)
- maciParameters = MaciParameters.mock('micro')
+ maciParameters = MaciParameters.mock(DEFAULT_CIRCUIT)
const SignUpGatekeeperArtifact =
await artifacts.readArtifact('SignUpGatekeeper')
@@ -68,17 +77,6 @@ describe('MACI factory', () => {
expect(messageTreeDepth).to.equal(maciParameters.messageTreeDepth)
})
- it('does not allow to decrease the vote option tree depth', async () => {
- await expect(
- maciFactory.setMaciParameters(...maciParameters.asContractParam())
- ).to.emit(maciFactory, 'MaciParametersChanged')
-
- maciParameters.voteOptionTreeDepth = 1
- await expect(
- maciFactory.setMaciParameters(...maciParameters.asContractParam())
- ).to.be.revertedWith('CannotDecreaseVoteOptionDepth')
- })
-
it('allows only owner to set MACI parameters', async () => {
const coordinatorMaciFactory = maciFactory.connect(coordinator)
await expect(
diff --git a/contracts/tests/recipientRegistry.ts b/contracts/tests/recipientRegistry.ts
index 180a8bca6..398d747c1 100644
--- a/contracts/tests/recipientRegistry.ts
+++ b/contracts/tests/recipientRegistry.ts
@@ -551,11 +551,12 @@ describe('Optimistic recipient registry', () => {
}
beforeEach(async () => {
- registry = await deployContract(deployer, 'OptimisticRecipientRegistry', [
- baseDeposit,
- challengePeriodDuration,
- controller.address,
- ])
+ registry = await deployContract({
+ name: 'OptimisticRecipientRegistry',
+ contractArgs: [baseDeposit, challengePeriodDuration, controller.address],
+ ethers,
+ signer: deployer,
+ })
})
it('initializes correctly', async () => {
@@ -981,11 +982,16 @@ describe('Optimistic recipient registry', () => {
'_recipientId'
)
- const anotherRegistry = await deployContract(
- deployer,
- 'OptimisticRecipientRegistry',
- [baseDeposit, challengePeriodDuration, controller.address]
- )
+ const anotherRegistry = await deployContract({
+ name: 'OptimisticRecipientRegistry',
+ contractArgs: [
+ baseDeposit,
+ challengePeriodDuration,
+ controller.address,
+ ],
+ ethers,
+ signer: deployer,
+ })
const txTwo = await anotherRegistry.addRecipient(
recipientAddress,
metadata,
diff --git a/contracts/tests/round.ts b/contracts/tests/round.ts
index ed61cbc2c..ff822b871 100644
--- a/contracts/tests/round.ts
+++ b/contracts/tests/round.ts
@@ -1,4 +1,4 @@
-import { ethers, waffle, artifacts } from 'hardhat'
+import { ethers, waffle, artifacts, config } from 'hardhat'
import { use, expect } from 'chai'
import { solidity } from 'ethereum-waffle'
import { deployMockContract } from '@ethereum-waffle/mock-contract'
@@ -15,9 +15,9 @@ import {
} from '../utils/constants'
import { getEventArg, getGasUsage } from '../utils/contracts'
import {
+ deployContract,
deployPoseidonLibraries,
deployMaciFactory,
- deployContractWithLinkedLibraries,
} from '../utils/deployment'
import {
bnSqrt,
@@ -25,9 +25,10 @@ import {
addTallyResultsBatch,
getRecipientClaimData,
getRecipientTallyResultsBatch,
- MaciParameters,
} from '../utils/maci'
import { sha256 } from 'ethers/lib/utils'
+import { MaciParameters } from '../utils/maciParameters'
+import { DEFAULT_CIRCUIT } from '../utils/circuits'
use(solidity)
@@ -134,21 +135,30 @@ describe('Funding Round', () => {
IRecipientRegistryArtifact.abi
)
- const libraries = await deployPoseidonLibraries(deployer)
- fundingRound = await deployContractWithLinkedLibraries(
- deployer,
- 'FundingRound',
+ const libraries = await deployPoseidonLibraries({
+ artifactsPath: config.paths.artifacts,
+ ethers,
+ signer: deployer,
+ })
+ fundingRound = await deployContract({
+ name: 'FundingRound',
libraries,
- [
+ contractArgs: [
token.address,
userRegistry.address,
recipientRegistry.address,
coordinator.address,
- ]
- )
- const maciFactory = await deployMaciFactory(deployer, libraries)
+ ],
+ ethers,
+ signer: deployer,
+ })
+ const maciFactory = await deployMaciFactory({
+ ethers,
+ signer: deployer,
+ libraries,
+ })
- const maciParams = MaciParameters.mock('micro')
+ const maciParams = MaciParameters.mock(DEFAULT_CIRCUIT)
await maciFactory.setMaciParameters(...maciParams.asContractParam())
const maciDeployed = await maciFactory.deployMaci(
diff --git a/contracts/tsconfig.json b/contracts/tsconfig.json
index f5597e526..b178c1bd5 100644
--- a/contracts/tsconfig.json
+++ b/contracts/tsconfig.json
@@ -1,6 +1,6 @@
{
"compilerOptions": {
- "target": "es2018",
+ "target": "es2020",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
diff --git a/contracts/utils/JSONFile.ts b/contracts/utils/JSONFile.ts
new file mode 100644
index 000000000..cf1a1eb95
--- /dev/null
+++ b/contracts/utils/JSONFile.ts
@@ -0,0 +1,27 @@
+import fs from 'fs'
+
+export class JSONFile {
+ /**
+ * Read the content of the JSON file
+ *
+ * @param path The path of the JSON file
+ * @returns
+ */
+ static read(path: string) {
+ try {
+ return JSON.parse(fs.readFileSync(path).toString())
+ } catch {
+ return {}
+ }
+ }
+
+ /**
+ * Update the JSON file with the data
+ * @param path The path of the file
+ * @param data The new data to add to the JSON content
+ */
+ static update(path: string, data: any) {
+ const state = JSONFile.read(path)
+ fs.writeFileSync(path, JSON.stringify({ ...state, ...data }, null, 2))
+ }
+}
diff --git a/contracts/utils/circuits.ts b/contracts/utils/circuits.ts
index c12108426..2d1a56691 100644
--- a/contracts/utils/circuits.ts
+++ b/contracts/utils/circuits.ts
@@ -4,6 +4,8 @@
const TREE_ARITY = 5
+export const DEFAULT_CIRCUIT = 'micro'
+
export const CIRCUITS: { [name: string]: any } = {
micro: {
processMessagesZkey: 'processmessages_6-8-2-3_final.zkey',
diff --git a/contracts/utils/constants.ts b/contracts/utils/constants.ts
index c7777989e..ed588f0e7 100644
--- a/contracts/utils/constants.ts
+++ b/contracts/utils/constants.ts
@@ -5,6 +5,7 @@ export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
export const UNIT = BigNumber.from(10).pow(BigNumber.from(18))
export const VOICE_CREDIT_FACTOR = BigNumber.from(10).pow(4 + 18 - 9)
export const ALPHA_PRECISION = BigNumber.from(10).pow(18)
+export const DEFAULT_SR_QUEUE_OPS = 4
export enum RecipientState {
Registered = 'Registered',
diff --git a/contracts/utils/deployment.ts b/contracts/utils/deployment.ts
index 8c5ee48d8..611013a11 100644
--- a/contracts/utils/deployment.ts
+++ b/contracts/utils/deployment.ts
@@ -1,17 +1,16 @@
-import { ethers, config } from 'hardhat'
-import { Signer, Contract, utils } from 'ethers'
+import { Signer, Contract, utils, BigNumber } from 'ethers'
import { link } from 'ethereum-waffle'
import path from 'path'
-import {
- mergeMessages,
- mergeSignups,
- genProofs,
- proveOnChain,
-} from '@clrfund/maci-cli'
import { readFileSync } from 'fs'
-import { MaciParameters } from './maci'
+import { HardhatEthersHelpers } from '@nomiclabs/hardhat-ethers/types'
+// Number.MAX_SAFE_INTEGER - 1
+export const challengePeriodSeconds = '9007199254740990'
+
+export type Libraries = { [name: string]: string }
+
+// Mapping of the user registry type and the contract name
const userRegistryNames: Record = {
simple: 'SimpleUserRegistry',
brightid: 'BrightIdUserRegistry',
@@ -19,44 +18,20 @@ const userRegistryNames: Record = {
merkle: 'MerkleUserRegistry',
}
+// Mapping of recipient registry type to the contract name
+const recipientRegistries: Record = {
+ simple: 'SimpleRecipientRegistry',
+ optimistic: 'OptimisticRecipientRegistry',
+}
+
+// BrightId contract deployment parameters
export interface BrightIdParams {
context: string
verifierAddress: string
sponsor: string
}
-/**
- * Return the brightid user registry contructor parameter values
- * @param userRegistryType user registry type
- * @returns BrightIdParams or null
- */
-export function getBrightIdParams(
- userRegistryType: string
-): BrightIdParams | null {
- if (userRegistryType === 'brightid') {
- const verifierAddress = process.env.BRIGHTID_VERIFIER_ADDR
- const sponsor = process.env.BRIGHTID_SPONSOR
- if (!verifierAddress) {
- throw new Error('Missing environment variable BRIGHTID_VERIFIER_ADDR')
- }
- if (!sponsor) {
- throw new Error('Missing environment variable BRIGHTID_SPONSOR')
- }
-
- return {
- context: process.env.BRIGHTID_CONTEXT || 'clr.fund',
- verifierAddress,
- sponsor,
- }
- } else {
- return null
- }
-}
-
-export function linkBytecode(
- bytecode: string,
- libraries: { [name: string]: string }
-): string {
+export function linkBytecode(bytecode: string, libraries: Libraries): string {
// Workarounds for https://github.com/nomiclabs/buidler/issues/611
const linkable = { evm: { bytecode: { object: bytecode } } }
for (const [libraryName, libraryAddress] of Object.entries(libraries)) {
@@ -68,7 +43,7 @@ export function linkBytecode(
type PoseidonName = 'PoseidonT3' | 'PoseidonT4' | 'PoseidonT5' | 'PoseidonT6'
/**
- * Deploy the PoseidonT3 or PoseidonT6 contracts. These 2 contracts
+ * Deploy the Poseidon contracts. These contracts
* have a custom artifact location that the hardhat library cannot
* retrieve using the standard getContractFactory() function, so, we manually
* read the artifact content and pass to the getContractFactory function
@@ -78,95 +53,85 @@ type PoseidonName = 'PoseidonT3' | 'PoseidonT4' | 'PoseidonT5' | 'PoseidonT6'
* only has the library interface. If the wrong bytecode is used to deploy the contract,
* the hash functions will always return 0.
*
- * @param account the account that deploys the contract
- * @param contractName PoseidonT3 or PoseidonT6
+ * @param name PoseidonT3, PoseidonT4, PoseidonT5, PoseidonT6
+ * @param ethers
+ * @param signer the account that deploys the contract
* @returns contract object
*/
-export async function deployPoseidon(
- account: Signer,
- contractName: PoseidonName
-): Promise {
+export async function deployPoseidon({
+ name,
+ artifactsPath,
+ ethers,
+ signer,
+}: {
+ name: PoseidonName
+ artifactsPath: string
+ ethers: HardhatEthersHelpers
+ signer?: Signer
+}): Promise {
const artifact = JSON.parse(
- readFileSync(
- path.join(config.paths.artifacts, `${contractName}.json`)
- ).toString()
+ readFileSync(path.join(artifactsPath, `${name}.json`)).toString()
)
const Poseidon = await ethers.getContractFactory(
artifact.abi,
artifact.bytecode,
- account
+ signer
)
return Poseidon.deploy()
}
-export async function deployContractWithLinkedLibraries(
- signer: Signer,
- contractName: string,
- libraries: { [name: string]: string },
- contractArgs: any[] = []
-): Promise {
- const contractFactory = await ethers.getContractFactory(contractName, {
+export type deployContractOptions = {
+ name: string
+ libraries?: Libraries
+ contractArgs?: any[]
+ // hardhat ethers handle
+ ethers: HardhatEthersHelpers
+ // if signer is not provided, use the default signer from ethers
+ signer?: Signer
+}
+
+export async function deployContract({
+ name,
+ libraries,
+ contractArgs = [],
+ ethers,
+ signer,
+}: deployContractOptions): Promise {
+ const contractFactory = await ethers.getContractFactory(name, {
signer,
libraries,
})
- const contract = await contractFactory.deploy(...contractArgs)
- return await contract.deployed()
-}
-export async function deployContract(
- account: Signer,
- contractName: string,
- contractArgs: any[] = []
-): Promise {
- const contractFactory = await ethers.getContractFactory(contractName, account)
const contract = await contractFactory.deploy(...contractArgs)
return await contract.deployed()
}
-export async function deployMaciFactory(
- account: Signer,
- poseidonContracts: { [name: string]: string }
-): Promise {
- const pollFactoryCreator = await deployContractWithLinkedLibraries(
- account,
- 'PollFactoryCreator',
- { ...poseidonContracts }
- )
-
- const vkRegistry = await deployContract(account, 'VkRegistry')
- const MACIFactory = await ethers.getContractFactory('MACIFactory', {
- signer: account,
- libraries: {
- ...poseidonContracts,
- PollFactoryCreator: pollFactoryCreator.address,
- },
- })
-
- const maciFactory = await MACIFactory.deploy(vkRegistry.address)
- await maciFactory.deployTransaction.wait()
-
- const transferTx = await vkRegistry.transferOwnership(maciFactory.address)
- await transferTx.wait()
-
- return maciFactory
-}
-
+/**
+ * Deploy a user registry
+ * @param userRegistryType user registry type, e.g. brightid, simple, etc
+ * @param ethers Hardhat ethers handle
+ * @param brightid Brightid parameters for the BrightID user registry
+ * @returns the newly deployed user registry contract
+ */
export async function deployUserRegistry(
userRegistryType: string,
- deployer: Signer,
- brightid: BrightIdParams | null
+ ethers: HardhatEthersHelpers,
+ brightid?: BrightIdParams
): Promise {
let userRegistry: Contract
- if (userRegistryType === 'brightid') {
+ const [signer] = await ethers.getSigners()
+
+ const lowercaseType = (userRegistryType || '').toLowerCase()
+ if (lowercaseType === 'brightid') {
if (!brightid) {
throw new Error('Missing BrightId parameter')
}
const BrightIdUserRegistry = await ethers.getContractFactory(
'BrightIdUserRegistry',
- deployer
+ signer
)
userRegistry = await BrightIdUserRegistry.deploy(
@@ -175,14 +140,14 @@ export async function deployUserRegistry(
brightid.sponsor
)
} else {
- const userRegistryName = userRegistryNames[userRegistryType]
+ const userRegistryName = userRegistryNames[lowercaseType]
if (!userRegistryName) {
- throw new Error('unsupported user registry type: ' + userRegistryType)
+ throw new Error('unsupported user registry type: ' + lowercaseType)
}
const UserRegistry = await ethers.getContractFactory(
userRegistryName,
- deployer
+ signer
)
userRegistry = await UserRegistry.deploy()
}
@@ -191,19 +156,98 @@ export async function deployUserRegistry(
return userRegistry
}
+/**
+ * Deploy a recipient registry
+ * @param type recipient registry type, e.g. simple, optimistic, etc
+ * @param controller the controller address of the registry
+ * @param ethers Hardhat ethers handle
+ * @returns the newly deployed registry contract
+ */
+export async function deployRecipientRegistry({
+ type,
+ controller,
+ deposit,
+ challengePeriod,
+ ethers,
+ signer,
+}: {
+ type: string
+ controller: string
+ deposit?: BigNumber
+ challengePeriod?: string
+ ethers: HardhatEthersHelpers
+ signer?: Signer
+}): Promise {
+ const lowercaseType = (type || '').toLowerCase()
+ const registryName = recipientRegistries[lowercaseType]
+ if (!registryName) {
+ throw new Error('Unsupported recipient registry type: ' + type)
+ }
+
+ if (lowercaseType === 'optimistic') {
+ if (!deposit) {
+ throw new Error('Missing base deposit amount')
+ }
+ if (!challengePeriod) {
+ throw new Error('Missing challenge period')
+ }
+ }
+
+ const args =
+ lowercaseType === 'simple'
+ ? [controller]
+ : [deposit, challengePeriod, controller]
+
+ const factory = await ethers.getContractFactory(registryName, signer)
+ const recipientRegistry = await factory.deploy(...args)
+
+ return await recipientRegistry.deployed()
+}
+
/**
* Deploy all the poseidon contracts
*
* @param signer The signer for the deployment transaction
+ * @param ethers Hardhat ethers handle
+ * @param artifactsPath Contract artifacts path
* @returns the deployed poseidon contracts
*/
-export async function deployPoseidonLibraries(
- signer: Signer
-): Promise<{ [name: string]: string }> {
- const PoseidonT3Contract = await deployPoseidon(signer, 'PoseidonT3')
- const PoseidonT4Contract = await deployPoseidon(signer, 'PoseidonT4')
- const PoseidonT5Contract = await deployPoseidon(signer, 'PoseidonT5')
- const PoseidonT6Contract = await deployPoseidon(signer, 'PoseidonT6')
+export async function deployPoseidonLibraries({
+ signer,
+ ethers,
+ artifactsPath,
+}: {
+ signer?: Signer
+ ethers: HardhatEthersHelpers
+ artifactsPath: string
+}): Promise<{ [name: string]: string }> {
+ const PoseidonT3Contract = await deployPoseidon({
+ name: 'PoseidonT3',
+ artifactsPath,
+ ethers,
+ signer,
+ })
+
+ const PoseidonT4Contract = await deployPoseidon({
+ name: 'PoseidonT4',
+ artifactsPath,
+ ethers,
+ signer,
+ })
+
+ const PoseidonT5Contract = await deployPoseidon({
+ name: 'PoseidonT5',
+ artifactsPath,
+ signer,
+ ethers,
+ })
+
+ const PoseidonT6Contract = await deployPoseidon({
+ name: 'PoseidonT6',
+ artifactsPath,
+ ethers,
+ signer,
+ })
const libraries = {
PoseidonT3: PoseidonT3Contract.address,
@@ -214,4 +258,149 @@ export async function deployPoseidonLibraries(
return libraries
}
-export { mergeMessages, mergeSignups, proveOnChain, genProofs }
+/**
+ * Deploy the poll factory
+ * @param signer Contract creator
+ * @param ethers Hardhat ethers handle
+ * @param libraries Poseidon libraries
+ * @param artifactPath Poseidon contract artifacts path
+ *
+ */
+export async function deployPollFactory({
+ signer,
+ ethers,
+ libraries,
+ artifactsPath,
+}: {
+ signer: Signer
+ ethers: HardhatEthersHelpers
+ libraries?: Libraries
+ artifactsPath?: string
+}): Promise {
+ let poseidonLibraries = libraries
+ if (!libraries) {
+ if (!artifactsPath) {
+ throw Error('Failed to dpeloy PollFactory, artifact path is missing')
+ }
+ poseidonLibraries = await deployPoseidonLibraries({
+ artifactsPath: artifactsPath || '',
+ ethers,
+ signer,
+ })
+ }
+
+ return deployContract({
+ name: 'PollFactory',
+ libraries: poseidonLibraries,
+ signer,
+ ethers,
+ })
+}
+
+/**
+ * Deploy the contracts needed to run the proveOnChain script.
+ * If the poseidon contracts are not provided, it will create them
+ * using the byte codes in the artifactsPath
+ *
+ * libraries - poseidon libraries
+ * artifactsPath - path that contacts the poseidon abi and bytecode
+ *
+ * @returns the MessageProcessor and Tally contracts
+ */
+export async function deployMessageProcesorAndTally({
+ artifactsPath,
+ libraries,
+ ethers,
+ signer,
+}: {
+ libraries?: Libraries
+ artifactsPath?: string
+ signer?: Signer
+ ethers: HardhatEthersHelpers
+}): Promise<{
+ mpContract: Contract
+ tallyContract: Contract
+}> {
+ if (!libraries) {
+ if (!artifactsPath) {
+ throw Error('Need the artifacts path to create the poseidon contracts')
+ }
+ libraries = await deployPoseidonLibraries({
+ artifactsPath,
+ ethers,
+ signer,
+ })
+ }
+
+ const verifierContract = await deployContract({
+ name: 'Verifier',
+ signer,
+ ethers,
+ })
+ const tallyContract = await deployContract({
+ name: 'Tally',
+ contractArgs: [verifierContract.address],
+ libraries,
+ ethers,
+ signer,
+ })
+
+ // deploy the message processing contract
+ const mpContract = await deployContract({
+ name: 'MessageProcessor',
+ contractArgs: [verifierContract.address],
+ signer,
+ libraries,
+ ethers,
+ })
+
+ return {
+ mpContract,
+ tallyContract,
+ }
+}
+
+/**
+ * Deploy an instance of MACI factory
+ *
+ * libraries - poseidon contracts
+ * ethers - hardhat ethers handle
+ * signer - if signer is not provided, use default signer in ethers
+ *
+ * @returns MACI factory contract
+ */
+export async function deployMaciFactory({
+ libraries,
+ ethers,
+ signer,
+}: {
+ libraries: Libraries
+ ethers: HardhatEthersHelpers
+ signer?: Signer
+}): Promise {
+ const pollFactory = await deployContract({
+ name: 'PollFactory',
+ libraries,
+ ethers,
+ signer,
+ })
+
+ const vkRegistry = await deployContract({
+ name: 'VkRegistry',
+ ethers,
+ signer,
+ })
+
+ const maciFactory = await deployContract({
+ name: 'MACIFactory',
+ libraries,
+ contractArgs: [vkRegistry.address, pollFactory.address],
+ ethers,
+ signer,
+ })
+
+ const transferTx = await vkRegistry.transferOwnership(maciFactory.address)
+ await transferTx.wait()
+
+ return maciFactory
+}
diff --git a/contracts/utils/maci.ts b/contracts/utils/maci.ts
index d5bdc359a..2447ec55f 100644
--- a/contracts/utils/maci.ts
+++ b/contracts/utils/maci.ts
@@ -8,15 +8,26 @@ import {
hash3,
hashLeftRight,
LEAVES_PER_NODE,
+ genTallyResultCommitment,
} from '@clrfund/common'
import * as os from 'os'
+import {
+ mergeMessages,
+ mergeSignups,
+ genProofs,
+ proveOnChain,
+} from '@clrfund/maci-cli'
-import { genTallyResultCommitment } from '@clrfund/common'
-import { VerifyingKey } from 'maci-domainobjs'
-import { extractVk } from '@clrfund/maci-circuits'
+import { getTalyFilePath } from './misc'
import { CIRCUITS } from './circuits'
import path from 'path'
+interface TallyResult {
+ recipientIndex: number
+ result: string
+ proof: any[]
+}
+
export interface ZkFiles {
processZkFile: string
processWitness: string
@@ -28,158 +39,11 @@ export interface ZkFiles {
export const isOsArm = os.arch().includes('arm')
-/**
- * Get the zkey file path
- * @param name zkey file name
- * @returns zkey file path
- */
-export function getCircuitFiles(circuit: string, directory: string): ZkFiles {
- const params = CIRCUITS[circuit]
- return {
- processZkFile: path.join(directory, params.processMessagesZkey),
- processWitness: path.join(directory, params.processWitness),
- processWasm: path.join(directory, params.processWasm),
- tallyZkFile: path.join(directory, params.tallyVotesZkey),
- tallyWitness: path.join(directory, params.tallyWitness),
- tallyWasm: path.join(directory, params.tallyWasm),
- }
-}
-
-export class MaciParameters {
- stateTreeDepth: number
- intStateTreeDepth: number
- messageTreeSubDepth: number
- messageTreeDepth: number
- voteOptionTreeDepth: number
- maxMessages: number
- maxVoteOptions: number
- messageBatchSize: number
- processVk: VerifyingKey
- tallyVk: VerifyingKey
-
- constructor(parameters: { [name: string]: any } = {}) {
- this.stateTreeDepth = parameters.stateTreeDepth
- this.intStateTreeDepth = parameters.intStateTreeDepth
- this.messageTreeSubDepth = parameters.messageTreeSubDepth
- this.messageTreeDepth = parameters.messageTreeDepth
- this.voteOptionTreeDepth = parameters.voteOptionTreeDepth
- this.maxMessages = parameters.maxMessages
- this.maxVoteOptions = parameters.maxVoteOptions
- this.messageBatchSize = parameters.messageBatchSize
- this.processVk = parameters.processVk
- this.tallyVk = parameters.tallyVk
- }
-
- asContractParam(): any[] {
- return [
- this.stateTreeDepth,
- {
- intStateTreeDepth: this.intStateTreeDepth,
- messageTreeSubDepth: this.messageTreeSubDepth,
- messageTreeDepth: this.messageTreeDepth,
- voteOptionTreeDepth: this.voteOptionTreeDepth,
- },
- { maxMessages: this.maxMessages, maxVoteOptions: this.maxVoteOptions },
- this.messageBatchSize,
- this.processVk.asContractParam(),
- this.tallyVk.asContractParam(),
- ]
- }
-
- static async fromConfig(
- circuit: string,
- directory: string
- ): Promise {
- const params = CIRCUITS[circuit]
- const { processZkFile, tallyZkFile } = getCircuitFiles(circuit, directory)
- const processVk: VerifyingKey = VerifyingKey.fromObj(
- await extractVk(processZkFile)
- )
- const tallyVk: VerifyingKey = VerifyingKey.fromObj(
- await extractVk(tallyZkFile)
- )
-
- return new MaciParameters({
- ...params.maxValues,
- ...params.treeDepths,
- ...params.batchSizes,
- processVk,
- tallyVk,
- })
- }
-
- static async fromContract(maciFactory: Contract): Promise {
- const stateTreeDepth = await maciFactory.stateTreeDepth()
- const {
- intStateTreeDepth,
- messageTreeSubDepth,
- messageTreeDepth,
- voteOptionTreeDepth,
- } = await maciFactory.treeDepths()
- const { maxMessages, maxVoteOptions } = await maciFactory.maxValues()
- const messageBatchSize = await maciFactory.messageBatchSize()
- const vkRegistry = await maciFactory.vkRegistry()
-
- const processVk = await vkRegistry.getProcessVk(
- stateTreeDepth,
- messageTreeDepth,
- voteOptionTreeDepth,
- messageBatchSize
- )
-
- const tallyVk = await vkRegistry.getTallyVk(
- stateTreeDepth,
- intStateTreeDepth,
- voteOptionTreeDepth
- )
-
- return new MaciParameters({
- stateTreeDepth,
- intStateTreeDepth,
- messageTreeSubDepth,
- messageTreeDepth,
- voteOptionTreeDepth,
- maxMessages,
- maxVoteOptions,
- messageBatchSize,
- processVk: VerifyingKey.fromContract(processVk),
- tallyVk: VerifyingKey.fromContract(tallyVk),
- })
- }
-
- static mock(circuit: string): MaciParameters {
- const processVk = VerifyingKey.fromObj({
- vk_alpha_1: [1, 2],
- vk_beta_2: [
- [1, 2],
- [1, 2],
- ],
- vk_gamma_2: [
- [1, 2],
- [1, 2],
- ],
- vk_delta_2: [
- [1, 2],
- [1, 2],
- ],
- IC: [[1, 2]],
- })
- const params = CIRCUITS[circuit]
- return new MaciParameters({
- ...params.maxValues,
- ...params.treeDepths,
- ...params.batchSizes,
- processVk,
- tallyVk: processVk.copy(),
- })
- }
-}
-
export function getRecipientTallyResult(
recipientIndex: number,
recipientTreeDepth: number,
tally: any
-): { recipientIndex: number; result: string; proof: any[] } {
+): TallyResult {
// Create proof for tally result
const result = tally.results.tally[recipientIndex]
const resultTree = new IncrementalQuinTree(
@@ -210,7 +74,7 @@ export function getRecipientTallyResultsBatch(
throw new Error('Recipient index out of bound')
}
- const tallyData = []
+ const tallyData: TallyResult[] = []
const lastIndex =
recipientStartIndex + batchSize > tallyCount
? tallyCount
@@ -295,18 +159,36 @@ export async function addTallyResultsBatch(
return totalGasUsed
}
+/**
+ * Get the zkey file path
+ * @param name zkey file name
+ * @returns zkey file path
+ */
+export function getCircuitFiles(circuit: string, directory: string): ZkFiles {
+ const params = CIRCUITS[circuit]
+ return {
+ processZkFile: path.join(directory, params.processMessagesZkey),
+ processWitness: path.join(directory, params.processWitness),
+ processWasm: path.join(directory, params.processWasm),
+ tallyZkFile: path.join(directory, params.tallyVotesZkey),
+ tallyWitness: path.join(directory, params.tallyWitness),
+ tallyWasm: path.join(directory, params.tallyWasm),
+ }
+}
+
/* Input to getGenProofArgs() */
type getGenProofArgsInput = {
maciAddress: string
providerUrl: string
pollId: string
- serializedCoordinatorPrivKey: string
+ // coordinator's MACI serialized secret key
+ coordinatorMacisk: string
// the transaction hash of the creation of the MACI contract
maciTxHash?: string
// the key get zkeys file mapping, see utils/circuits.ts
circuitType: string
circuitDirectory: string
- rapidSnarkDirectory: string
+ rapidSnarkDirectory?: string
// where the proof will be produced
outputDir: string
}
@@ -339,16 +221,16 @@ export function getGenProofArgs(
maciAddress,
providerUrl,
pollId,
- serializedCoordinatorPrivKey,
+ coordinatorMacisk,
maciTxHash,
circuitType,
circuitDirectory,
rapidSnarkDirectory,
outputDir,
} = args
- const tallyFile = path.join(outputDir, `tally.json`)
+ const tallyFile = getTalyFilePath(outputDir)
const maciStateFile = path.join(outputDir, `macistate`)
- const rapidSnarkExe = path.join(rapidSnarkDirectory, 'prover')
+ const rapidSnarkExe = path.join(rapidSnarkDirectory || '', 'prover')
const {
processZkFile,
@@ -371,7 +253,7 @@ export function getGenProofArgs(
tally_wasm: tallyWasm,
transaction_hash: maciTxHash,
output: outputDir,
- privkey: serializedCoordinatorPrivKey,
+ privkey: coordinatorMacisk,
macistate: maciStateFile,
}
: {
@@ -386,9 +268,35 @@ export function getGenProofArgs(
tally_zkey: tallyZkFile,
transaction_hash: maciTxHash,
output: outputDir,
- privkey: serializedCoordinatorPrivKey,
+ privkey: coordinatorMacisk,
macistate: maciStateFile,
}
}
-export { createMessage, getRecipientClaimData, bnSqrt }
+/**
+ * Merge MACI message and signups subtrees
+ * Must merge the subtrees before calling genProofs
+ *
+ * @param maciAddress MACI contract address
+ * @param pollId Poll id
+ * @param numOperations Number of operations to perform for the merge
+ */
+export async function mergeMaciSubtrees(
+ maciAddress: string,
+ pollId: string,
+ numOperations: number
+) {
+ await mergeMessages({
+ contract: maciAddress,
+ poll_id: pollId,
+ num_queue_ops: numOperations,
+ })
+
+ await mergeSignups({
+ contract: maciAddress,
+ poll_id: pollId,
+ num_queue_ops: numOperations,
+ })
+}
+
+export { createMessage, getRecipientClaimData, bnSqrt, proveOnChain, genProofs }
diff --git a/contracts/utils/maciParameters.ts b/contracts/utils/maciParameters.ts
new file mode 100644
index 000000000..6f169b10b
--- /dev/null
+++ b/contracts/utils/maciParameters.ts
@@ -0,0 +1,146 @@
+import { Contract } from 'ethers'
+
+import { VerifyingKey } from 'maci-domainobjs'
+import { extractVk } from '@clrfund/maci-circuits'
+import { CIRCUITS } from './circuits'
+import path from 'path'
+
+export interface ZkFiles {
+ processZkFile: string
+ processWitness: string
+ processWasm: string
+ tallyZkFile: string
+ tallyWitness: string
+ tallyWasm: string
+}
+
+/**
+ * Get the zkey file path
+ * @param name zkey file name
+ * @returns zkey file path
+ */
+export function getCircuitFiles(circuit: string, directory: string): ZkFiles {
+ const params = CIRCUITS[circuit]
+ return {
+ processZkFile: path.join(directory, params.processMessagesZkey),
+ processWitness: path.join(directory, params.processWitness),
+ processWasm: path.join(directory, params.processWasm),
+ tallyZkFile: path.join(directory, params.tallyVotesZkey),
+ tallyWitness: path.join(directory, params.tallyWitness),
+ tallyWasm: path.join(directory, params.tallyWasm),
+ }
+}
+
+export class MaciParameters {
+ stateTreeDepth: number
+ intStateTreeDepth: number
+ messageTreeSubDepth: number
+ messageTreeDepth: number
+ voteOptionTreeDepth: number
+ maxMessages: number
+ maxVoteOptions: number
+ messageBatchSize: number
+ processVk: VerifyingKey
+ tallyVk: VerifyingKey
+
+ constructor(parameters: { [name: string]: any } = {}) {
+ this.stateTreeDepth = parameters.stateTreeDepth
+ this.intStateTreeDepth = parameters.intStateTreeDepth
+ this.messageTreeSubDepth = parameters.messageTreeSubDepth
+ this.messageTreeDepth = parameters.messageTreeDepth
+ this.voteOptionTreeDepth = parameters.voteOptionTreeDepth
+ this.maxMessages = parameters.maxMessages
+ this.maxVoteOptions = parameters.maxVoteOptions
+ this.messageBatchSize = parameters.messageBatchSize
+ this.processVk = parameters.processVk
+ this.tallyVk = parameters.tallyVk
+ }
+
+ asContractParam(): any[] {
+ return [
+ this.stateTreeDepth,
+ {
+ intStateTreeDepth: this.intStateTreeDepth,
+ messageTreeSubDepth: this.messageTreeSubDepth,
+ messageTreeDepth: this.messageTreeDepth,
+ voteOptionTreeDepth: this.voteOptionTreeDepth,
+ },
+ { maxMessages: this.maxMessages, maxVoteOptions: this.maxVoteOptions },
+ this.messageBatchSize,
+ this.processVk.asContractParam(),
+ this.tallyVk.asContractParam(),
+ ]
+ }
+
+ static async fromConfig(
+ circuit: string,
+ directory: string
+ ): Promise {
+ const params = CIRCUITS[circuit]
+ const { processZkFile, tallyZkFile } = getCircuitFiles(circuit, directory)
+ const processVk: VerifyingKey = VerifyingKey.fromObj(
+ await extractVk(processZkFile)
+ )
+ const tallyVk: VerifyingKey = VerifyingKey.fromObj(
+ await extractVk(tallyZkFile)
+ )
+
+ return new MaciParameters({
+ ...params.maxValues,
+ ...params.treeDepths,
+ ...params.batchSizes,
+ processVk,
+ tallyVk,
+ })
+ }
+
+ static async fromContract(maciFactory: Contract): Promise {
+ const stateTreeDepth = await maciFactory.stateTreeDepth()
+ const {
+ intStateTreeDepth,
+ messageTreeSubDepth,
+ messageTreeDepth,
+ voteOptionTreeDepth,
+ } = await maciFactory.treeDepths()
+ const { maxMessages, maxVoteOptions } = await maciFactory.maxValues()
+ const messageBatchSize = await maciFactory.messageBatchSize()
+
+ return new MaciParameters({
+ stateTreeDepth,
+ intStateTreeDepth,
+ messageTreeSubDepth,
+ messageTreeDepth,
+ voteOptionTreeDepth,
+ maxMessages,
+ maxVoteOptions,
+ messageBatchSize,
+ })
+ }
+
+ static mock(circuit: string): MaciParameters {
+ const processVk = VerifyingKey.fromObj({
+ vk_alpha_1: [1, 2],
+ vk_beta_2: [
+ [1, 2],
+ [1, 2],
+ ],
+ vk_gamma_2: [
+ [1, 2],
+ [1, 2],
+ ],
+ vk_delta_2: [
+ [1, 2],
+ [1, 2],
+ ],
+ IC: [[1, 2]],
+ })
+ const params = CIRCUITS[circuit]
+ return new MaciParameters({
+ ...params.maxValues,
+ ...params.treeDepths,
+ ...params.batchSizes,
+ processVk,
+ tallyVk: processVk.copy(),
+ })
+ }
+}
diff --git a/contracts/utils/misc.ts b/contracts/utils/misc.ts
new file mode 100644
index 000000000..6eafc1586
--- /dev/null
+++ b/contracts/utils/misc.ts
@@ -0,0 +1,11 @@
+import path from 'path'
+
+/**
+ * Get the tally file path
+ *
+ * @param outputDir The output directory
+ * @returns The tally file path
+ */
+export function getTalyFilePath(outputDir: string) {
+ return path.join(outputDir, 'tally.json')
+}
diff --git a/yarn.lock b/yarn.lock
index d825f089b..6e53fe0c1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -55,12 +55,12 @@
dependencies:
node-fetch "^2.6.1"
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.22.13":
- version "7.22.13"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e"
- integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.4.tgz#03ae5af150be94392cb5c7ccd97db5a19a5da6aa"
+ integrity sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==
dependencies:
- "@babel/highlight" "^7.22.13"
+ "@babel/highlight" "^7.23.4"
chalk "^2.4.2"
"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.9":
@@ -89,12 +89,12 @@
json5 "^2.2.3"
semver "^6.3.1"
-"@babel/generator@^7.14.0", "@babel/generator@^7.18.13", "@babel/generator@^7.23.3":
- version "7.23.3"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.3.tgz#86e6e83d95903fbe7613f448613b8b319f330a8e"
- integrity sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==
+"@babel/generator@^7.14.0", "@babel/generator@^7.18.13", "@babel/generator@^7.23.3", "@babel/generator@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.4.tgz#4a41377d8566ec18f807f42962a7f3551de83d1c"
+ integrity sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==
dependencies:
- "@babel/types" "^7.23.3"
+ "@babel/types" "^7.23.4"
"@jridgewell/gen-mapping" "^0.3.2"
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
@@ -219,10 +219,10 @@
dependencies:
"@babel/types" "^7.22.5"
-"@babel/helper-string-parser@^7.22.5":
- version "7.22.5"
- resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f"
- integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==
+"@babel/helper-string-parser@^7.22.5", "@babel/helper-string-parser@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83"
+ integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==
"@babel/helper-validator-identifier@^7.22.19", "@babel/helper-validator-identifier@^7.22.20":
version "7.22.20"
@@ -235,27 +235,27 @@
integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==
"@babel/helpers@^7.23.2":
- version "7.23.2"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.2.tgz#2832549a6e37d484286e15ba36a5330483cac767"
- integrity sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.4.tgz#7d2cfb969aa43222032193accd7329851facf3c1"
+ integrity sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==
dependencies:
"@babel/template" "^7.22.15"
- "@babel/traverse" "^7.23.2"
- "@babel/types" "^7.23.0"
+ "@babel/traverse" "^7.23.4"
+ "@babel/types" "^7.23.4"
-"@babel/highlight@^7.22.13":
- version "7.22.20"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54"
- integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==
+"@babel/highlight@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b"
+ integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==
dependencies:
"@babel/helper-validator-identifier" "^7.22.20"
chalk "^2.4.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.14.0", "@babel/parser@^7.16.8", "@babel/parser@^7.21.8", "@babel/parser@^7.22.15", "@babel/parser@^7.22.5", "@babel/parser@^7.23.0", "@babel/parser@^7.23.3":
- version "7.23.3"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.3.tgz#0ce0be31a4ca4f1884b5786057cadcb6c3be58f9"
- integrity sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==
+"@babel/parser@^7.14.0", "@babel/parser@^7.16.8", "@babel/parser@^7.21.8", "@babel/parser@^7.22.15", "@babel/parser@^7.22.5", "@babel/parser@^7.23.0", "@babel/parser@^7.23.3", "@babel/parser@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.4.tgz#409fbe690c333bb70187e2de4021e1e47a026661"
+ integrity sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==
"@babel/plugin-proposal-class-properties@^7.0.0":
version "7.18.6"
@@ -297,7 +297,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
-"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.22.5":
+"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.23.3":
version "7.23.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473"
integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==
@@ -326,9 +326,9 @@
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-transform-block-scoping@^7.0.0":
- version "7.23.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.3.tgz#e99a3ff08f58edd28a8ed82481df76925a4ffca7"
- integrity sha512-QPZxHrThbQia7UdvfpaRRlq/J9ciz1J4go0k+lPBXbgaNeY7IQrBj/9ceWjvMMI07/ZBzHl/F0R/2K0qH7jCVw==
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz#b2d38589531c6c80fbe25e6b58e763622d2d3cf5"
+ integrity sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==
dependencies:
"@babel/helper-plugin-utils" "^7.22.5"
@@ -439,15 +439,15 @@
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/plugin-transform-react-jsx@^7.0.0":
- version "7.22.15"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz#7e6266d88705d7c49f11c98db8b9464531289cd6"
- integrity sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz#393f99185110cea87184ea47bcb4a7b0c2e39312"
+ integrity sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==
dependencies:
"@babel/helper-annotate-as-pure" "^7.22.5"
"@babel/helper-module-imports" "^7.22.15"
"@babel/helper-plugin-utils" "^7.22.5"
- "@babel/plugin-syntax-jsx" "^7.22.5"
- "@babel/types" "^7.22.15"
+ "@babel/plugin-syntax-jsx" "^7.23.3"
+ "@babel/types" "^7.23.4"
"@babel/plugin-transform-shorthand-properties@^7.0.0":
version "7.23.3"
@@ -472,9 +472,9 @@
"@babel/helper-plugin-utils" "^7.22.5"
"@babel/runtime@^7.0.0":
- version "7.23.2"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885"
- integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.4.tgz#36fa1d2b36db873d25ec631dcc4923fdc1cf2e2e"
+ integrity sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==
dependencies:
regenerator-runtime "^0.14.0"
@@ -487,19 +487,19 @@
"@babel/parser" "^7.22.15"
"@babel/types" "^7.22.15"
-"@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.23.2", "@babel/traverse@^7.23.3":
- version "7.23.3"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.3.tgz#26ee5f252e725aa7aca3474aa5b324eaf7908b5b"
- integrity sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==
+"@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.23.3", "@babel/traverse@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.4.tgz#c2790f7edf106d059a0098770fe70801417f3f85"
+ integrity sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==
dependencies:
- "@babel/code-frame" "^7.22.13"
- "@babel/generator" "^7.23.3"
+ "@babel/code-frame" "^7.23.4"
+ "@babel/generator" "^7.23.4"
"@babel/helper-environment-visitor" "^7.22.20"
"@babel/helper-function-name" "^7.23.0"
"@babel/helper-hoist-variables" "^7.22.5"
"@babel/helper-split-export-declaration" "^7.22.6"
- "@babel/parser" "^7.23.3"
- "@babel/types" "^7.23.3"
+ "@babel/parser" "^7.23.4"
+ "@babel/types" "^7.23.4"
debug "^4.1.0"
globals "^11.1.0"
@@ -512,21 +512,21 @@
"@babel/helper-validator-identifier" "^7.22.19"
to-fast-properties "^2.0.0"
-"@babel/types@7.23.0":
- version "7.23.0"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb"
- integrity sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==
+"@babel/types@7.23.3":
+ version "7.23.3"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.3.tgz#d5ea892c07f2ec371ac704420f4dcdb07b5f9598"
+ integrity sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==
dependencies:
"@babel/helper-string-parser" "^7.22.5"
"@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"
-"@babel/types@^7.0.0", "@babel/types@^7.16.8", "@babel/types@^7.18.13", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.3":
- version "7.23.3"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.3.tgz#d5ea892c07f2ec371ac704420f4dcdb07b5f9598"
- integrity sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==
+"@babel/types@^7.0.0", "@babel/types@^7.16.8", "@babel/types@^7.18.13", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.3", "@babel/types@^7.23.4":
+ version "7.23.4"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.4.tgz#7206a1810fc512a7f7f7d4dace4cb4c1c9dbfb8e"
+ integrity sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==
dependencies:
- "@babel/helper-string-parser" "^7.22.5"
+ "@babel/helper-string-parser" "^7.23.4"
"@babel/helper-validator-identifier" "^7.22.20"
to-fast-properties "^2.0.0"
@@ -562,9 +562,9 @@
"@bugsnag/node" "^7.19.0"
"@bugsnag/js@^7.0.0", "@bugsnag/js@^7.20.0":
- version "7.21.0"
- resolved "https://registry.yarnpkg.com/@bugsnag/js/-/js-7.21.0.tgz#0a8a9a61a43cf9b552dc70341ed49ee9da46a8f3"
- integrity sha512-fFTR7cRBSlLtwa1wPTse92igZUEX2V95KyGGCXq2qb2F2w6hJ6oJDxA0BMPS8qqsciYXRjbfn8HX+TFgO1oErg==
+ version "7.22.2"
+ resolved "https://registry.yarnpkg.com/@bugsnag/js/-/js-7.22.2.tgz#4cd91c77e9e4657b8a952fad34eee40382753c81"
+ integrity sha512-HgKzjkwzMQKyokIFnyRMChONxM9AoR24Sk76tWcqIdFagE0bhnTgSn3qYT2bRVNODtWyQHiW6qjOOpgOM3Mjlw==
dependencies:
"@bugsnag/browser" "^7.21.0"
"@bugsnag/node" "^7.19.0"
@@ -660,10 +660,10 @@
xmlhttprequest "1.8.0"
zkey-manager "^0.1.1"
-"@clrfund/maci-contracts@^1.1.7":
- version "1.1.7"
- resolved "https://registry.yarnpkg.com/@clrfund/maci-contracts/-/maci-contracts-1.1.7.tgz#8a35678cf76607c480ff164a70154c7bdc8b8c3c"
- integrity sha512-m68HH6KEP64WBWhJmUdiwk3kKSLfC+sIpE+vp4awBkCstFaEEgGQNEdikxKo2rFFSGpn7XPegb6oCeDXQvWxgg==
+"@clrfund/maci-contracts@^1.1.7", "@clrfund/maci-contracts@^1.1.9":
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/@clrfund/maci-contracts/-/maci-contracts-1.1.9.tgz#baaa07c586d7851bfdefe6124fe048f0140c53f8"
+ integrity sha512-X6JQApedLX+LHsLz2bl1FdtMht8jP4pAhhGUSTJyW8mpwksKYINQt/EsJuaD2RPoyC2arp/VhpvSh5FHtZ2X2w==
dependencies:
"@clrfund/maci-core" "^1.1.7"
"@clrfund/maci-crypto" "^1.1.7"
@@ -767,10 +767,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.4.tgz#74752a09301b8c6b9a415fbda9fb71406a62a7b7"
integrity sha512-mRsi2vJsk4Bx/AFsNBqOH2fqedxn5L/moT58xgg51DjX1la64Z3Npicut2VbhvDFO26qjWtPMsVxCd80YTFVeg==
-"@esbuild/android-arm64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.5.tgz#276c5f99604054d3dbb733577e09adae944baa90"
- integrity sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ==
+"@esbuild/android-arm64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.6.tgz#13d98a34bbbde4237867cc232307a20ded139b6f"
+ integrity sha512-KQ/hbe9SJvIJ4sR+2PcZ41IBV+LPJyYp6V1K1P1xcMRup9iYsBoQn4MzE3mhMLOld27Au2eDcLlIREeKGUXpHQ==
"@esbuild/android-arm@0.18.20":
version "0.18.20"
@@ -782,10 +782,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.4.tgz#c27363e1e280e577d9b5c8fa7c7a3be2a8d79bf5"
integrity sha512-uBIbiYMeSsy2U0XQoOGVVcpIktjLMEKa7ryz2RLr7L/vTnANNEsPVAh4xOv7ondGz6ac1zVb0F8Jx20rQikffQ==
-"@esbuild/android-arm@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.5.tgz#4a3cbf14758166abaae8ba9c01a80e68342a4eec"
- integrity sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA==
+"@esbuild/android-arm@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.6.tgz#68898d949672c56f10451f540fd92301dc713fb3"
+ integrity sha512-muPzBqXJKCbMYoNbb1JpZh/ynl0xS6/+pLjrofcR3Nad82SbsCogYzUE6Aq9QT3cLP0jR/IVK/NHC9b90mSHtg==
"@esbuild/android-x64@0.18.20":
version "0.18.20"
@@ -797,10 +797,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.4.tgz#6c9ee03d1488973d928618100048b75b147e0426"
integrity sha512-4iPufZ1TMOD3oBlGFqHXBpa3KFT46aLl6Vy7gwed0ZSYgHaZ/mihbYb4t7Z9etjkC9Al3ZYIoOaHrU60gcMy7g==
-"@esbuild/android-x64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.5.tgz#21a3d11cd4613d2d3c5ccb9e746c254eb9265b0a"
- integrity sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA==
+"@esbuild/android-x64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.6.tgz#51a0ab83680dedc6dd1ae26133def26b178ed3a1"
+ integrity sha512-VVJVZQ7p5BBOKoNxd0Ly3xUM78Y4DyOoFKdkdAe2m11jbh0LEU4bPles4e/72EMl4tapko8o915UalN/5zhspg==
"@esbuild/darwin-arm64@0.18.20":
version "0.18.20"
@@ -812,10 +812,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.4.tgz#64e2ee945e5932cd49812caa80e8896e937e2f8b"
integrity sha512-Lviw8EzxsVQKpbS+rSt6/6zjn9ashUZ7Tbuvc2YENgRl0yZTktGlachZ9KMJUsVjZEGFVu336kl5lBgDN6PmpA==
-"@esbuild/darwin-arm64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.5.tgz#714cb839f467d6a67b151ee8255886498e2b9bf6"
- integrity sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw==
+"@esbuild/darwin-arm64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.6.tgz#2883f14197111febb118c0463c080930a30883e5"
+ integrity sha512-91LoRp/uZAKx6ESNspL3I46ypwzdqyDLXZH7x2QYCLgtnaU08+AXEbabY2yExIz03/am0DivsTtbdxzGejfXpA==
"@esbuild/darwin-x64@0.18.20":
version "0.18.20"
@@ -827,10 +827,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.4.tgz#d8e26e1b965df284692e4d1263ba69a49b39ac7a"
integrity sha512-YHbSFlLgDwglFn0lAO3Zsdrife9jcQXQhgRp77YiTDja23FrC2uwnhXMNkAucthsf+Psr7sTwYEryxz6FPAVqw==
-"@esbuild/darwin-x64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.5.tgz#2c553e97a6d2b4ae76a884e35e6cbab85a990bbf"
- integrity sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA==
+"@esbuild/darwin-x64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.6.tgz#400bf20f9a35a7d68a17f5898c0f9ecb099f062b"
+ integrity sha512-QCGHw770ubjBU1J3ZkFJh671MFajGTYMZumPs9E/rqU52md6lIil97BR0CbPq6U+vTh3xnTNDHKRdR8ggHnmxQ==
"@esbuild/freebsd-arm64@0.18.20":
version "0.18.20"
@@ -842,10 +842,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.4.tgz#29751a41b242e0a456d89713b228f1da4f45582f"
integrity sha512-vz59ijyrTG22Hshaj620e5yhs2dU1WJy723ofc+KUgxVCM6zxQESmWdMuVmUzxtGqtj5heHyB44PjV/HKsEmuQ==
-"@esbuild/freebsd-arm64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.5.tgz#d554f556718adb31917a0da24277bf84b6ee87f3"
- integrity sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ==
+"@esbuild/freebsd-arm64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.6.tgz#8af07bd848afa2470b8a2339b203ce29a721152b"
+ integrity sha512-J53d0jGsDcLzWk9d9SPmlyF+wzVxjXpOH7jVW5ae7PvrDst4kiAz6sX+E8btz0GB6oH12zC+aHRD945jdjF2Vg==
"@esbuild/freebsd-x64@0.18.20":
version "0.18.20"
@@ -857,10 +857,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.4.tgz#873edc0f73e83a82432460ea59bf568c1e90b268"
integrity sha512-3sRbQ6W5kAiVQRBWREGJNd1YE7OgzS0AmOGjDmX/qZZecq8NFlQsQH0IfXjjmD0XtUYqr64e0EKNFjMUlPL3Cw==
-"@esbuild/freebsd-x64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.5.tgz#288f7358a3bb15d99e73c65c9adaa3dabb497432"
- integrity sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ==
+"@esbuild/freebsd-x64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.6.tgz#ae0230860e27df204a616671e028ff8fdffa009a"
+ integrity sha512-hn9qvkjHSIB5Z9JgCCjED6YYVGCNpqB7dEGavBdG6EjBD8S/UcNUIlGcB35NCkMETkdYwfZSvD9VoDJX6VeUVA==
"@esbuild/linux-arm64@0.18.20":
version "0.18.20"
@@ -872,10 +872,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.4.tgz#659f2fa988d448dbf5010b5cc583be757cc1b914"
integrity sha512-ZWmWORaPbsPwmyu7eIEATFlaqm0QGt+joRE9sKcnVUG3oBbr/KYdNE2TnkzdQwX6EDRdg/x8Q4EZQTXoClUqqA==
-"@esbuild/linux-arm64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.5.tgz#95933ae86325c93cb6b5e8333d22120ecfdc901b"
- integrity sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA==
+"@esbuild/linux-arm64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.6.tgz#3042bc423a978deab44a72244b863f743fd9fda1"
+ integrity sha512-HQCOrk9XlH3KngASLaBfHpcoYEGUt829A9MyxaI8RMkfRA8SakG6YQEITAuwmtzFdEu5GU4eyhKcpv27dFaOBg==
"@esbuild/linux-arm@0.18.20":
version "0.18.20"
@@ -887,10 +887,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.4.tgz#d5b13a7ec1f1c655ce05c8d319b3950797baee55"
integrity sha512-z/4ArqOo9EImzTi4b6Vq+pthLnepFzJ92BnofU1jgNlcVb+UqynVFdoXMCFreTK7FdhqAzH0vmdwW5373Hm9pg==
-"@esbuild/linux-arm@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.5.tgz#0acef93aa3e0579e46d33b666627bddb06636664"
- integrity sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ==
+"@esbuild/linux-arm@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.6.tgz#50a537de609315979509120b0181882978294db1"
+ integrity sha512-G8IR5zFgpXad/Zp7gr7ZyTKyqZuThU6z1JjmRyN1vSF8j0bOlGzUwFSMTbctLAdd7QHpeyu0cRiuKrqK1ZTwvQ==
"@esbuild/linux-ia32@0.18.20":
version "0.18.20"
@@ -902,10 +902,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.4.tgz#878cd8bf24c9847c77acdb5dd1b2ef6e4fa27a82"
integrity sha512-EGc4vYM7i1GRUIMqRZNCTzJh25MHePYsnQfKDexD8uPTCm9mK56NIL04LUfX2aaJ+C9vyEp2fJ7jbqFEYgO9lQ==
-"@esbuild/linux-ia32@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.5.tgz#b6e5c9e80b42131cbd6b1ddaa48c92835f1ed67f"
- integrity sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ==
+"@esbuild/linux-ia32@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.6.tgz#f99c48b597facf9cbf8e1a2522ce379b2ad7b0c4"
+ integrity sha512-22eOR08zL/OXkmEhxOfshfOGo8P69k8oKHkwkDrUlcB12S/sw/+COM4PhAPT0cAYW/gpqY2uXp3TpjQVJitz7w==
"@esbuild/linux-loong64@0.18.20":
version "0.18.20"
@@ -917,10 +917,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.4.tgz#df890499f6e566b7de3aa2361be6df2b8d5fa015"
integrity sha512-WVhIKO26kmm8lPmNrUikxSpXcgd6HDog0cx12BUfA2PkmURHSgx9G6vA19lrlQOMw+UjMZ+l3PpbtzffCxFDRg==
-"@esbuild/linux-loong64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.5.tgz#e5f0cf95a180158b01ff5f417da796a1c09dfbea"
- integrity sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw==
+"@esbuild/linux-loong64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.6.tgz#9fe79be31ce305564aa62da190f38e199d6d26b7"
+ integrity sha512-82RvaYAh/SUJyjWA8jDpyZCHQjmEggL//sC7F3VKYcBMumQjUL3C5WDl/tJpEiKtt7XrWmgjaLkrk205zfvwTA==
"@esbuild/linux-mips64el@0.18.20":
version "0.18.20"
@@ -932,10 +932,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.4.tgz#76eae4e88d2ce9f4f1b457e93892e802851b6807"
integrity sha512-keYY+Hlj5w86hNp5JJPuZNbvW4jql7c1eXdBUHIJGTeN/+0QFutU3GrS+c27L+NTmzi73yhtojHk+lr2+502Mw==
-"@esbuild/linux-mips64el@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.5.tgz#ae36fb86c7d5f641f3a0c8472e83dcb6ea36a408"
- integrity sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg==
+"@esbuild/linux-mips64el@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.6.tgz#5a922dad90fc8a83fd0631c136b46128153ffb6f"
+ integrity sha512-8tvnwyYJpR618vboIv2l8tK2SuK/RqUIGMfMENkeDGo3hsEIrpGldMGYFcWxWeEILe5Fi72zoXLmhZ7PR23oQA==
"@esbuild/linux-ppc64@0.18.20":
version "0.18.20"
@@ -947,10 +947,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.4.tgz#c49032f4abbcfa3f747b543a106931fe3dce41ff"
integrity sha512-tQ92n0WMXyEsCH4m32S21fND8VxNiVazUbU4IUGVXQpWiaAxOBvtOtbEt3cXIV3GEBydYsY8pyeRMJx9kn3rvw==
-"@esbuild/linux-ppc64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.5.tgz#7960cb1666f0340ddd9eef7b26dcea3835d472d0"
- integrity sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q==
+"@esbuild/linux-ppc64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.6.tgz#a7fccf924824999b301546843adb4f51051965e8"
+ integrity sha512-Qt+D7xiPajxVNk5tQiEJwhmarNnLPdjXAoA5uWMpbfStZB0+YU6a3CtbWYSy+sgAsnyx4IGZjWsTzBzrvg/fMA==
"@esbuild/linux-riscv64@0.18.20":
version "0.18.20"
@@ -962,10 +962,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.4.tgz#0f815a090772138503ee0465a747e16865bf94b1"
integrity sha512-tRRBey6fG9tqGH6V75xH3lFPpj9E8BH+N+zjSUCnFOX93kEzqS0WdyJHkta/mmJHn7MBaa++9P4ARiU4ykjhig==
-"@esbuild/linux-riscv64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.5.tgz#32207df26af60a3a9feea1783fc21b9817bade19"
- integrity sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag==
+"@esbuild/linux-riscv64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.6.tgz#41d2db11550662d6c03902d9d8d26b0ed5bb8d55"
+ integrity sha512-lxRdk0iJ9CWYDH1Wpnnnc640ajF4RmQ+w6oHFZmAIYu577meE9Ka/DCtpOrwr9McMY11ocbp4jirgGgCi7Ls/g==
"@esbuild/linux-s390x@0.18.20":
version "0.18.20"
@@ -977,10 +977,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.4.tgz#8d2cca20cd4e7c311fde8701d9f1042664f8b92b"
integrity sha512-152aLpQqKZYhThiJ+uAM4PcuLCAOxDsCekIbnGzPKVBRUDlgaaAfaUl5NYkB1hgY6WN4sPkejxKlANgVcGl9Qg==
-"@esbuild/linux-s390x@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.5.tgz#b38d5681db89a3723862dfa792812397b1510a7d"
- integrity sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw==
+"@esbuild/linux-s390x@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.6.tgz#d7a843a2620e73c5c9d65c482e2fbddc7e0f7753"
+ integrity sha512-MopyYV39vnfuykHanRWHGRcRC3AwU7b0QY4TI8ISLfAGfK+tMkXyFuyT1epw/lM0pflQlS53JoD22yN83DHZgA==
"@esbuild/linux-x64@0.18.20":
version "0.18.20"
@@ -992,10 +992,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.4.tgz#f618bec2655de49bff91c588777e37b5e3169d4a"
integrity sha512-Mi4aNA3rz1BNFtB7aGadMD0MavmzuuXNTaYL6/uiYIs08U7YMPETpgNn5oue3ICr+inKwItOwSsJDYkrE9ekVg==
-"@esbuild/linux-x64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.5.tgz#46feba2ad041a241379d150f415b472fe3885075"
- integrity sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A==
+"@esbuild/linux-x64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.6.tgz#d3f20f0c2bdaa1b9ed1c0df7db034771e7aa5234"
+ integrity sha512-UWcieaBzsN8WYbzFF5Jq7QULETPcQvlX7KL4xWGIB54OknXJjBO37sPqk7N82WU13JGWvmDzFBi1weVBajPovg==
"@esbuild/netbsd-x64@0.18.20":
version "0.18.20"
@@ -1007,10 +1007,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.4.tgz#7889744ca4d60f1538d62382b95e90a49687cef2"
integrity sha512-9+Wxx1i5N/CYo505CTT7T+ix4lVzEdz0uCoYGxM5JDVlP2YdDC1Bdz+Khv6IbqmisT0Si928eAxbmGkcbiuM/A==
-"@esbuild/netbsd-x64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.5.tgz#3b5c1fb068f26bfc681d31f682adf1bea4ef0702"
- integrity sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g==
+"@esbuild/netbsd-x64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.6.tgz#6108d7270599ee37cd57bb14e4516a83541885d5"
+ integrity sha512-EpWiLX0fzvZn1wxtLxZrEW+oQED9Pwpnh+w4Ffv8ZLuMhUoqR9q9rL4+qHW8F4Mg5oQEKxAoT0G+8JYNqCiR6g==
"@esbuild/openbsd-x64@0.18.20":
version "0.18.20"
@@ -1022,10 +1022,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.4.tgz#c3e436eb9271a423d2e8436fcb120e3fd90e2b01"
integrity sha512-MFsHleM5/rWRW9EivFssop+OulYVUoVcqkyOkjiynKBCGBj9Lihl7kh9IzrreDyXa4sNkquei5/DTP4uCk25xw==
-"@esbuild/openbsd-x64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.5.tgz#ca6830316ca68056c5c88a875f103ad3235e00db"
- integrity sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA==
+"@esbuild/openbsd-x64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.6.tgz#b1b5aaa2c9028e90a2bef6774a9c67451f53f164"
+ integrity sha512-fFqTVEktM1PGs2sLKH4M5mhAVEzGpeZJuasAMRnvDZNCV0Cjvm1Hu35moL2vC0DOrAQjNTvj4zWrol/lwQ8Deg==
"@esbuild/sunos-x64@0.18.20":
version "0.18.20"
@@ -1037,10 +1037,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.4.tgz#f63f5841ba8c8c1a1c840d073afc99b53e8ce740"
integrity sha512-6Xq8SpK46yLvrGxjp6HftkDwPP49puU4OF0hEL4dTxqCbfx09LyrbUj/D7tmIRMj5D5FCUPksBbxyQhp8tmHzw==
-"@esbuild/sunos-x64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.5.tgz#9efc4eb9539a7be7d5a05ada52ee43cda0d8e2dd"
- integrity sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg==
+"@esbuild/sunos-x64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.6.tgz#b51b648cea77c62b1934a4fdcfee7aaa9de174cb"
+ integrity sha512-M+XIAnBpaNvaVAhbe3uBXtgWyWynSdlww/JNZws0FlMPSBy+EpatPXNIlKAdtbFVII9OpX91ZfMb17TU3JKTBA==
"@esbuild/win32-arm64@0.18.20":
version "0.18.20"
@@ -1052,10 +1052,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.4.tgz#80be69cec92da4da7781cf7a8351b95cc5a236b0"
integrity sha512-PkIl7Jq4mP6ke7QKwyg4fD4Xvn8PXisagV/+HntWoDEdmerB2LTukRZg728Yd1Fj+LuEX75t/hKXE2Ppk8Hh1w==
-"@esbuild/win32-arm64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.5.tgz#29f8184afa7a02a956ebda4ed638099f4b8ff198"
- integrity sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg==
+"@esbuild/win32-arm64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.6.tgz#34e5665f239047c302c8d153406c87db22afd58a"
+ integrity sha512-2DchFXn7vp/B6Tc2eKdTsLzE0ygqKkNUhUBCNtMx2Llk4POIVMUq5rUYjdcedFlGLeRe1uLCpVvCmE+G8XYybA==
"@esbuild/win32-ia32@0.18.20":
version "0.18.20"
@@ -1067,10 +1067,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.4.tgz#15dc0ed83d2794872b05d8edc4a358fecf97eb54"
integrity sha512-ga676Hnvw7/ycdKB53qPusvsKdwrWzEyJ+AtItHGoARszIqvjffTwaaW3b2L6l90i7MO9i+dlAW415INuRhSGg==
-"@esbuild/win32-ia32@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.5.tgz#f3de07afb292ecad651ae4bb8727789de2d95b05"
- integrity sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw==
+"@esbuild/win32-ia32@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.6.tgz#f7aaebe325e67f44c0a738e80a98221504677b4a"
+ integrity sha512-PBo/HPDQllyWdjwAVX+Gl2hH0dfBydL97BAH/grHKC8fubqp02aL4S63otZ25q3sBdINtOBbz1qTZQfXbP4VBg==
"@esbuild/win32-x64@0.18.20":
version "0.18.20"
@@ -1082,10 +1082,10 @@
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.4.tgz#d46a6e220a717f31f39ae80f49477cc3220be0f0"
integrity sha512-HP0GDNla1T3ZL8Ko/SHAS2GgtjOg+VmWnnYLhuTksr++EnduYB0f3Y2LzHsUwb2iQ13JGoY6G3R8h6Du/WG6uA==
-"@esbuild/win32-x64@0.19.5":
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.5.tgz#faad84c41ba12e3a0acb52571df9bff37bee75f6"
- integrity sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw==
+"@esbuild/win32-x64@0.19.6":
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.6.tgz#7134e5dea1f5943b013e96fc34f9638a5f3d7e3e"
+ integrity sha512-OE7yIdbDif2kKfrGa+V0vx/B3FJv2L4KnIiLlvtibPyO9UkgO3rzYE0HhpREo2vmJ1Ixq1zwm9/0er+3VOSZJA==
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
@@ -1119,10 +1119,10 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.48.0.tgz#642633964e217905436033a2bd08bf322849b7fb"
integrity sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==
-"@eslint/js@8.53.0":
- version "8.53.0"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d"
- integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==
+"@eslint/js@8.54.0":
+ version "8.54.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.54.0.tgz#4fab9a2ff7860082c304f750e94acd644cf984cf"
+ integrity sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==
"@ethereum-waffle/chai@^3.4.4":
version "3.4.4"
@@ -2749,11 +2749,11 @@
semver "^7.3.8"
"@netlify/functions-utils@^5.2.37":
- version "5.2.40"
- resolved "https://registry.yarnpkg.com/@netlify/functions-utils/-/functions-utils-5.2.40.tgz#093d6acc512c5dd0b5814ab4402d916ff5a44fb6"
- integrity sha512-5mx23k4WW9R2WvBDa9mVCz0n3CAUUVbyoa7zOOjVRj2wuZAqnP9gTQa/g4Uhg3GvDxp90kHlDe5Amfc2K4j3MQ==
+ version "5.2.41"
+ resolved "https://registry.yarnpkg.com/@netlify/functions-utils/-/functions-utils-5.2.41.tgz#88bd31d0e8754724c1fffd5f687b3e78215e0d09"
+ integrity sha512-rvp11NquyVQ4d5rK6W6cP4M3iKyuOATqfEGlC7jLUZjMeNp4bQ5gPb5RaqqG5MHPY0KmdELMGGGgUxmCbh+Qxw==
dependencies:
- "@netlify/zip-it-and-ship-it" "9.26.1"
+ "@netlify/zip-it-and-ship-it" "9.26.2"
cpy "^9.0.0"
path-exists "^5.0.0"
@@ -2869,9 +2869,9 @@
execa "^6.0.0"
"@netlify/serverless-functions-api@^1.10.1", "@netlify/serverless-functions-api@^1.12.0":
- version "1.12.0"
- resolved "https://registry.yarnpkg.com/@netlify/serverless-functions-api/-/serverless-functions-api-1.12.0.tgz#b8ba310e6fdac9bf1f0e974856eb60f97d294e4d"
- integrity sha512-LJt2gHzLQMgJLsLG9Chbu2Pxxi7Yzbj3Xcd9QlThvUlD7kf4nAr3lzzRJMZqo77rVNmfQX11W1uvGMSlduiKeA==
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/@netlify/serverless-functions-api/-/serverless-functions-api-1.12.1.tgz#fb926f62377d84719c70f9a4493f3d04d6f6e7dc"
+ integrity sha512-+G9cTltqfH54dF4dLqoEOV2P4qTIY8dM9blUVqg+NtVTXyuadzgpHqtffhVeyeLytVnTx1238kWJUe+sV3bnlg==
dependencies:
"@netlify/node-cookies" "^0.1.0"
urlpattern-polyfill "8.0.2"
@@ -2914,13 +2914,13 @@
urlpattern-polyfill "8.0.2"
yargs "^17.0.0"
-"@netlify/zip-it-and-ship-it@9.26.1":
- version "9.26.1"
- resolved "https://registry.yarnpkg.com/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-9.26.1.tgz#fbd4380c25a1bc62fb4e138310fa1eba89033de1"
- integrity sha512-1hJcNIqXU7y5TgAACaRZp4vu3Bknl2pD6Aq3WOdY4T1zuB/SyKOn8Im6wwYElpc4n5LDGIOPyJlLDNo+DOwoWA==
+"@netlify/zip-it-and-ship-it@9.26.2":
+ version "9.26.2"
+ resolved "https://registry.yarnpkg.com/@netlify/zip-it-and-ship-it/-/zip-it-and-ship-it-9.26.2.tgz#e531499922ed4e46fc5af603c5db2528ac3f6452"
+ integrity sha512-tsQbSfgOTEfZmSnUbCJiHDVyYDRN1gQQEWjAmJ90YI60ZloT4j7B4HlBt0gshU9pPCiDxoHhQMCk5pHg7//CSw==
dependencies:
"@babel/parser" "^7.22.5"
- "@babel/types" "7.23.0"
+ "@babel/types" "7.23.3"
"@netlify/binary-info" "^1.0.0"
"@netlify/serverless-functions-api" "^1.12.0"
"@vercel/nft" "^0.23.0"
@@ -2928,7 +2928,7 @@
common-path-prefix "^3.0.0"
cp-file "^10.0.0"
es-module-lexer "^1.0.0"
- esbuild "0.19.5"
+ esbuild "0.19.6"
execa "^6.0.0"
filter-obj "^5.0.0"
find-up "^6.0.0"
@@ -3211,7 +3211,7 @@
"@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.1"
"@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.1"
-"@nomiclabs/hardhat-ethers@^2.0.0", "@nomiclabs/hardhat-ethers@^2.0.2", "@nomiclabs/hardhat-ethers@^2.2.1":
+"@nomiclabs/hardhat-ethers@^2.0.0", "@nomiclabs/hardhat-ethers@^2.0.2", "@nomiclabs/hardhat-ethers@^2.2.3":
version "2.2.3"
resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz#b41053e360c31a32c2640c9a45ee981a7e603fe0"
integrity sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==
@@ -4483,9 +4483,9 @@
"@types/chai" "*"
"@types/chai@*", "@types/chai@^4.2.11", "@types/chai@^4.3.4":
- version "4.3.10"
- resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.10.tgz#2ad2959d1767edee5b0e4efb1a0cd2b500747317"
- integrity sha512-of+ICnbqjmFCiixUnqRulbylyXQrPqIGf/B3Jax1wIF3DvSheysQxAWvqHhZiW3IQrycvokcLcFQlveGp+vyNg==
+ version "4.3.11"
+ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c"
+ integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==
"@types/cli-progress@^3.11.0":
version "3.11.5"
@@ -4589,9 +4589,9 @@
integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==
"@types/luxon@^3.1.0":
- version "3.3.4"
- resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.3.4.tgz#cda5c0709a0c4c01ba059c40e62d76610479049a"
- integrity sha512-H9OXxv4EzJwE75aTPKpiGXJq+y4LFxjpsdgKwSmr503P5DkWc3AG7VAFYrFNVvqemT5DfgZJV9itYhqBHSGujA==
+ version "3.3.5"
+ resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.3.5.tgz#ffdcec196994998dbef6284523b3ac88a9e6c45f"
+ integrity sha512-1cyf6Ge/94zlaWIZA2ei1pE6SZ8xpad2hXaYa5JEFiaUH0YS494CZwyi4MXNpXD9oEuv6ZH0Bmh0e7F9sPhmZA==
"@types/minimatch@^3.0.4":
version "3.0.5"
@@ -4624,9 +4624,9 @@
form-data "^4.0.0"
"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0":
- version "20.9.1"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.1.tgz#9d578c610ce1e984adda087f685ace940954fe19"
- integrity sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==
+ version "20.9.3"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.9.3.tgz#e089e1634436f676ff299596c9531bd2b59fffc6"
+ integrity sha512-nk5wXLAXGBKfrhLB0cyHGbSqopS+nz0BUgZkUQqSHSSgdee0kssp1IAqlQOu333bW+gMNs2QREx7iynm19Abxw==
dependencies:
undici-types "~5.26.4"
@@ -4724,9 +4724,9 @@
"@types/node" "*"
"@types/semver@^7.3.12":
- version "7.5.5"
- resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.5.tgz#deed5ab7019756c9c90ea86139106b0346223f35"
- integrity sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==
+ version "7.5.6"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339"
+ integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==
"@types/triple-beam@^1.3.2":
version "1.3.5"
@@ -4734,9 +4734,9 @@
integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==
"@types/trusted-types@^2.0.2":
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.6.tgz#d12451beaeb9c3838f12024580dc500b7e88b0ad"
- integrity sha512-HYtNooPvUY9WAVRBr4u+4Qa9fYD1ze2IUlAD3HoA6oehn1taGwBx3Oa52U4mTslTS+GAExKpaFu39Y5xUEwfjg==
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11"
+ integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==
"@types/web-bluetooth@^0.0.16":
version "0.0.16"
@@ -4756,9 +4756,9 @@
"@types/node" "*"
"@types/ws@^8.0.0":
- version "8.5.9"
- resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.9.tgz#384c489f99c83225a53f01ebc3eddf3b8e202a8c"
- integrity sha512-jbdrY0a8lxfdTp/+r7Z4CkycbOFN8WX+IOchLJr3juT/xzbJ8URyTVSJ/hvNdadTgM1mnedb47n+Y31GsFnQlg==
+ version "8.5.10"
+ resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787"
+ integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==
dependencies:
"@types/node" "*"
@@ -4768,9 +4768,9 @@
integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==
"@types/yargs@^16.0.0":
- version "16.0.8"
- resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.8.tgz#0d57a5a491d85ae75d372a32e657b1779b86c65d"
- integrity sha512-1GwLEkmFafeb/HbE6pC7tFlgYSQ4Iqh2qlWCq8xN+Qfaiaxr2PcLfuhfRFRYqI6XJyeFoLYyKnhFbNsst9FMtQ==
+ version "16.0.9"
+ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.9.tgz#ba506215e45f7707e6cbcaf386981155b7ab956e"
+ integrity sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA==
dependencies:
"@types/yargs-parser" "*"
@@ -6965,9 +6965,9 @@ bfj@^7.0.2:
tryer "^1.0.1"
big-integer@^1.6.42, big-integer@^1.6.48:
- version "1.6.51"
- resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
- integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==
+ version "1.6.52"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85"
+ integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==
bigint-crypto-utils@^3.0.23:
version "3.3.0"
@@ -7644,9 +7644,9 @@ camelcase@^7.0.1:
integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==
caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541:
- version "1.0.30001562"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001562.tgz#9d16c5fd7e9c592c4cd5e304bc0f75b0008b2759"
- integrity sha512-kfte3Hym//51EdX4239i+Rmp20EsLIYGdPkERegTgU19hQWCRhsRFGKHTliUlsry53tv17K7n077Kqa0WJU4ng==
+ version "1.0.30001563"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001563.tgz#aa68a64188903e98f36eb9c56e48fba0c1fe2a32"
+ integrity sha512-na2WUmOxnwIZtwnFI2CZ/3er0wdNzU7hN+cPYz/z2ajHThnkWjNBOpEPP4n+4r2WPM847JaMotaJE3bnfzjyKw==
capital-case@^1.0.4:
version "1.0.4"
@@ -8015,9 +8015,9 @@ circomlibjs@^0.1.7:
ffjavascript "^0.2.45"
citty@^0.1.3, citty@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/citty/-/citty-0.1.4.tgz#91091be06ae4951dffa42fd443de7fe72245f2e0"
- integrity sha512-Q3bK1huLxzQrvj7hImJ7Z1vKYJRPQCDnd0EjXfHMidcjecGOMuLrmuQmtWmFkuKLcMThlGh1yCKG8IEc6VeNXQ==
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/citty/-/citty-0.1.5.tgz#fe37ceae5dc764af75eb2fece99d2bf527ea4e50"
+ integrity sha512-AS7n5NSc0OQVMV9v6wt3ByujNIrne0/cTjiC2MYqhvao57VNfiuVksTSr2p17nVOhEr2KtqiAkGwHcgMC/qUuQ==
dependencies:
consola "^3.2.3"
@@ -8589,9 +8589,9 @@ copy-template-dir@1.4.0:
run-parallel "^1.1.4"
core-js-pure@^3.0.1:
- version "3.33.2"
- resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.33.2.tgz#644830db2507ef84d068a70980ccd99c275f5fa6"
- integrity sha512-a8zeCdyVk7uF2elKIGz67AjcXOxjRbwOLz8SbklEso1V+2DoW4OkAMZN9S9GBgvZIaqQi/OemFX4OiSoQEmg1Q==
+ version "3.33.3"
+ resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.33.3.tgz#cbf9180ac4c4653823d784862bfb5c77eac0bf98"
+ integrity sha512-taJ00IDOP+XYQEA2dAe4ESkmHt1fL8wzYDo3mRWQey8uO9UojlBFMneA65kMyxfYP7106c6LzWaq7/haDT6BCQ==
core-js@^2.4.0, core-js@^2.5.0:
version "2.6.12"
@@ -9163,7 +9163,7 @@ defined@~1.0.1:
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf"
integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==
-defu@^6.1.2:
+defu@^6.1.2, defu@^6.1.3:
version "6.1.3"
resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.3.tgz#6d7f56bc61668e844f9f593ace66fd67ef1205fd"
integrity sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==
@@ -9540,9 +9540,9 @@ electron-fetch@^1.7.2:
encoding "^0.1.13"
electron-to-chromium@^1.3.47, electron-to-chromium@^1.4.535:
- version "1.4.587"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.587.tgz#d8b864f21338b60798d447a3d83b90753f701d07"
- integrity sha512-RyJX0q/zOkAoefZhB9XHghGeATVP0Q3mwA253XD/zj2OeXc+JZB9pCaEv6R578JUYaWM9PRhye0kXvd/V1cQ3Q==
+ version "1.4.590"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.590.tgz#85a428fbabb77265a4804040837ed4f2538e3300"
+ integrity sha512-hohItzsQcG7/FBsviCYMtQwUSWvVF7NVqPOnJCErWsAshsP/CR2LAXdmq276RbESNdhxiAq5/vRo1g2pxGXVww==
elegant-spinner@^1.0.1:
version "1.0.1"
@@ -9867,33 +9867,33 @@ esbuild@0.19.4:
"@esbuild/win32-ia32" "0.19.4"
"@esbuild/win32-x64" "0.19.4"
-esbuild@0.19.5:
- version "0.19.5"
- resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.5.tgz#53a0e19dfbf61ba6c827d51a80813cf071239a8c"
- integrity sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==
+esbuild@0.19.6:
+ version "0.19.6"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.6.tgz#baa0e8b6b9e655c54ffd57f1772e44677a7931cc"
+ integrity sha512-Xl7dntjA2OEIvpr9j0DVxxnog2fyTGnyVoQXAMQI6eR3mf9zCQds7VIKUDCotDgE/p4ncTgeRqgX8t5d6oP4Gw==
optionalDependencies:
- "@esbuild/android-arm" "0.19.5"
- "@esbuild/android-arm64" "0.19.5"
- "@esbuild/android-x64" "0.19.5"
- "@esbuild/darwin-arm64" "0.19.5"
- "@esbuild/darwin-x64" "0.19.5"
- "@esbuild/freebsd-arm64" "0.19.5"
- "@esbuild/freebsd-x64" "0.19.5"
- "@esbuild/linux-arm" "0.19.5"
- "@esbuild/linux-arm64" "0.19.5"
- "@esbuild/linux-ia32" "0.19.5"
- "@esbuild/linux-loong64" "0.19.5"
- "@esbuild/linux-mips64el" "0.19.5"
- "@esbuild/linux-ppc64" "0.19.5"
- "@esbuild/linux-riscv64" "0.19.5"
- "@esbuild/linux-s390x" "0.19.5"
- "@esbuild/linux-x64" "0.19.5"
- "@esbuild/netbsd-x64" "0.19.5"
- "@esbuild/openbsd-x64" "0.19.5"
- "@esbuild/sunos-x64" "0.19.5"
- "@esbuild/win32-arm64" "0.19.5"
- "@esbuild/win32-ia32" "0.19.5"
- "@esbuild/win32-x64" "0.19.5"
+ "@esbuild/android-arm" "0.19.6"
+ "@esbuild/android-arm64" "0.19.6"
+ "@esbuild/android-x64" "0.19.6"
+ "@esbuild/darwin-arm64" "0.19.6"
+ "@esbuild/darwin-x64" "0.19.6"
+ "@esbuild/freebsd-arm64" "0.19.6"
+ "@esbuild/freebsd-x64" "0.19.6"
+ "@esbuild/linux-arm" "0.19.6"
+ "@esbuild/linux-arm64" "0.19.6"
+ "@esbuild/linux-ia32" "0.19.6"
+ "@esbuild/linux-loong64" "0.19.6"
+ "@esbuild/linux-mips64el" "0.19.6"
+ "@esbuild/linux-ppc64" "0.19.6"
+ "@esbuild/linux-riscv64" "0.19.6"
+ "@esbuild/linux-s390x" "0.19.6"
+ "@esbuild/linux-x64" "0.19.6"
+ "@esbuild/netbsd-x64" "0.19.6"
+ "@esbuild/openbsd-x64" "0.19.6"
+ "@esbuild/sunos-x64" "0.19.6"
+ "@esbuild/win32-arm64" "0.19.6"
+ "@esbuild/win32-ia32" "0.19.6"
+ "@esbuild/win32-x64" "0.19.6"
esbuild@^0.18.10:
version "0.18.20"
@@ -10083,14 +10083,14 @@ eslint@8.48.0:
text-table "^0.2.0"
eslint@^8.28.0, eslint@^8.31.0:
- version "8.53.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.53.0.tgz#14f2c8244298fcae1f46945459577413ba2697ce"
- integrity sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==
+ version "8.54.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.54.0.tgz#588e0dd4388af91a2e8fa37ea64924074c783537"
+ integrity sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
"@eslint-community/regexpp" "^4.6.1"
"@eslint/eslintrc" "^2.1.3"
- "@eslint/js" "8.53.0"
+ "@eslint/js" "8.54.0"
"@humanwhocodes/config-array" "^0.11.13"
"@humanwhocodes/module-importer" "^1.0.1"
"@nodelib/fs.walk" "^1.2.8"
@@ -12310,16 +12310,16 @@ gtoken@^5.0.4:
jws "^4.0.0"
h3@^1.8.1, h3@^1.8.2:
- version "1.8.2"
- resolved "https://registry.yarnpkg.com/h3/-/h3-1.8.2.tgz#69ea8ca0285c1bb268cd08b9a7017e02939f88b7"
- integrity sha512-1Ca0orJJlCaiFY68BvzQtP2lKLk46kcLAxVM8JgYbtm2cUg6IY7pjpYgWMwUvDO9QI30N5JAukOKoT8KD3Q0PQ==
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/h3/-/h3-1.9.0.tgz#c5f512a93026df9837db6f30c9ef51135dd46752"
+ integrity sha512-+F3ZqrNV/CFXXfZ2lXBINHi+rM4Xw3CDC5z2CDK3NMPocjonKipGLLDSkrqY9DOrioZNPTIdDMWfQKm//3X2DA==
dependencies:
cookie-es "^1.0.0"
- defu "^6.1.2"
- destr "^2.0.1"
- iron-webcrypto "^0.10.1"
+ defu "^6.1.3"
+ destr "^2.0.2"
+ iron-webcrypto "^1.0.0"
radix3 "^1.1.0"
- ufo "^1.3.0"
+ ufo "^1.3.2"
uncrypto "^0.1.3"
unenv "^1.7.4"
@@ -12362,7 +12362,7 @@ hardhat-contract-sizer@^2.10.0, hardhat-contract-sizer@^2.6.1:
cli-table3 "^0.6.0"
strip-ansi "^6.0.0"
-hardhat@^2.12.5, hardhat@^2.12.6:
+hardhat@^2.12.6, hardhat@^2.19.1:
version "2.19.1"
resolved "https://registry.yarnpkg.com/hardhat/-/hardhat-2.19.1.tgz#5e09e8070ecfc6109ba9d3a4a117ec2b0643032a"
integrity sha512-bsWa63g1GB78ZyMN08WLhFElLPA+J+pShuKD1BFO2+88g3l+BL3R07vj9deIi9dMbssxgE714Gof1dBEDGqnCw==
@@ -13333,10 +13333,10 @@ ipld@^0.25.3:
multicodec "^1.0.0"
typical "^6.0.0"
-iron-webcrypto@^0.10.1:
- version "0.10.1"
- resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-0.10.1.tgz#cab8636a468685533a8521bfd7f06b19b7174809"
- integrity sha512-QGOS8MRMnj/UiOa+aMIgfyHcvkhqNUsUxb1XzskENvbo+rEfp6TOwqd1KPuDzXC4OnGHcMSVxDGRoilqB8ViqA==
+iron-webcrypto@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.0.0.tgz#e3b689c0c61b434a0a4cb82d0aeabbc8b672a867"
+ integrity sha512-anOK1Mktt8U1Xi7fCM3RELTuYbnFikQY5VtrDj7kPgpejV7d43tWKhzgioO0zpkazLEL/j/iayRqnJhrGfqUsg==
is-absolute@^1.0.0:
version "1.0.0"
@@ -14779,11 +14779,16 @@ light-my-request@^5.6.1:
process-warning "^2.0.0"
set-cookie-parser "^2.4.1"
-lilconfig@^2.0.5, lilconfig@^2.1.0:
+lilconfig@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
+lilconfig@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.0.0.tgz#f8067feb033b5b74dab4602a5f5029420be749bc"
+ integrity sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==
+
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
@@ -15302,11 +15307,9 @@ lru-cache@5.1.1, lru-cache@^5.1.1:
yallist "^3.0.2"
lru-cache@^10.0.2, "lru-cache@^9.1.1 || ^10.0.0":
- version "10.0.2"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.2.tgz#34504678cc3266b09b8dfd6fab4e1515258271b7"
- integrity sha512-Yj9mA8fPiVgOUpByoTZO5pNrcl5Yk37FcSHsUINpAsaBIEZIuqcCclDZJCVxqQShDsmYX8QG63svJiTbOATZwg==
- dependencies:
- semver "^7.3.5"
+ version "10.0.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.3.tgz#b40014d7d2d16d94130b87297a04a1f24874ae7c"
+ integrity sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==
lru-cache@^3.2.0:
version "3.2.0"
@@ -16537,9 +16540,9 @@ node-forge@^1.3.1:
integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==
node-gyp-build@^4.2.0, node-gyp-build@^4.2.2, node-gyp-build@^4.3.0:
- version "4.6.1"
- resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.1.tgz#24b6d075e5e391b8d5539d98c7fc5c210cac8a3e"
- integrity sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.7.0.tgz#749f0033590b2a89ac8edb5e0775f95f5ae86d15"
+ integrity sha512-PbZERfeFdrHQOOXiAKOY0VPbykZy90ndPKk0d+CFDegTKmWp1VgOTz2xACVbr1BjCWxrQp68CXtvNsveFhqDJg==
node-gyp-build@~4.1.0:
version "4.1.1"
@@ -17765,12 +17768,12 @@ postcss-js@^4.0.1:
camelcase-css "^2.0.1"
postcss-load-config@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.1.tgz#152383f481c2758274404e4962743191d73875bd"
- integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3"
+ integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==
dependencies:
- lilconfig "^2.0.5"
- yaml "^2.1.1"
+ lilconfig "^3.0.0"
+ yaml "^2.3.4"
postcss-nested@^6.0.1:
version "6.0.1"
@@ -17915,9 +17918,9 @@ process-warning@^1.0.0:
integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==
process-warning@^2.0.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-2.3.0.tgz#02ccba12fd55c05879cb7ddab31b6a20af2fe4d9"
- integrity sha512-N6mp1+2jpQr3oCFMz6SeHRGbv6Slb20bRhj4v3xR99HqNToAcOe1MFOp4tytyzOfJn+QtN8Rf7U/h2KAn4kC6g==
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-2.3.1.tgz#0caf992272c439f45dd416e1407ee25a3d4c778a"
+ integrity sha512-JjBvFEn7MwFbzUDa2SRtKJSsyO0LlER4V/FmwLMhBlXNbGgGxdyFCxIdMDLerWUycsVUyaoM9QFLvppFy4IWaQ==
process@^0.10.0:
version "0.10.1"
@@ -19657,7 +19660,7 @@ source-map-support@0.5.12:
buffer-from "^1.0.0"
source-map "^0.6.0"
-source-map-support@0.5.21, source-map-support@^0.5.11, source-map-support@^0.5.13, source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.20, source-map-support@^0.5.21:
+source-map-support@0.5.21, source-map-support@^0.5.11, source-map-support@^0.5.13, source-map-support@^0.5.19, source-map-support@^0.5.20, source-map-support@^0.5.21:
version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
@@ -20804,17 +20807,6 @@ ts-node@^10.9.1:
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"
-ts-node@^8.8.1:
- version "8.10.2"
- resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d"
- integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==
- dependencies:
- arg "^4.1.0"
- diff "^4.0.1"
- make-error "^1.1.1"
- source-map-support "^0.5.17"
- yn "3.1.1"
-
tslib@1.14.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
@@ -21026,9 +21018,9 @@ typescript@^4.2.3, typescript@^4.9.3:
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
typescript@^5.0.0, typescript@^5.0.4:
- version "5.2.2"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
- integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.2.tgz#00d1c7c1c46928c5845c1ee8d0cc2791031d4c43"
+ integrity sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==
typewise-core@^1.2, typewise-core@^1.2.0:
version "1.2.0"
@@ -21067,7 +21059,7 @@ uc.micro@^1.0.1, uc.micro@^1.0.5:
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
-ufo@^1.3.0, ufo@^1.3.1:
+ufo@^1.3.0, ufo@^1.3.1, ufo@^1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.2.tgz#c7d719d0628a1c80c006d2240e0d169f6e3c0496"
integrity sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==
@@ -22774,7 +22766,7 @@ yaml@1.10.2, yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
-yaml@^2.1.1, yaml@^2.1.3:
+yaml@^2.1.3, yaml@^2.3.4:
version "2.3.4"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2"
integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==