Unverified Commit 6c1a6340 by Hadrien Croubois Committed by GitHub

Add Governor contracts (#2672)

Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
parent f88e5552
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* `ERC2771Context`: use private variable from storage to store the forwarder address. Fixes issues where `_msgSender()` was not callable from constructors. ([#2754](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2754)) * `ERC2771Context`: use private variable from storage to store the forwarder address. Fixes issues where `_msgSender()` was not callable from constructors. ([#2754](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2754))
* `EnumerableSet`: add `values()` functions that returns an array containing all values in a single call. ([#2768](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2768)) * `EnumerableSet`: add `values()` functions that returns an array containing all values in a single call. ([#2768](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2768))
* `Governor`: added a modular system of `Governor` contracts based on `GovernorAlpha` and `GovernorBravo`. ([#2672](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2672))
## 4.2.0 (2021-06-30) ## 4.2.0 (2021-06-30)
...@@ -18,7 +19,7 @@ ...@@ -18,7 +19,7 @@
* `ERC1155Supply`: add a new `ERC1155` extension that keeps track of the totalSupply of each tokenId. ([#2593](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2593)) * `ERC1155Supply`: add a new `ERC1155` extension that keeps track of the totalSupply of each tokenId. ([#2593](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2593))
* `BitMaps`: add a new `BitMaps` library that provides a storage efficient datastructure for `uint256` to `bool` mapping with contiguous keys. ([#2710](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2710)) * `BitMaps`: add a new `BitMaps` library that provides a storage efficient datastructure for `uint256` to `bool` mapping with contiguous keys. ([#2710](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2710))
### Breaking Changes ### Breaking Changes
* `ERC20FlashMint` is no longer a Draft ERC. ([#2673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2673))) * `ERC20FlashMint` is no longer a Draft ERC. ([#2673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2673)))
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/cryptography/ECDSA.sol";
import "../utils/cryptography/draft-EIP712.sol";
import "../utils/introspection/ERC165.sol";
import "../utils/math/SafeCast.sol";
import "../utils/Address.sol";
import "../utils/Context.sol";
import "../utils/Timers.sol";
import "./IGovernor.sol";
/**
* @dev Core of the governance system, designed to be extended though various modules.
*
* This contract is abstract and requiers several function to be implemented in various modules:
*
* - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote}
* - A voting module must implement {getVotes}
* - Additionanly, the {votingPeriod} must also be implemented
*
* _Available since v4.3._
*/
abstract contract Governor is Context, ERC165, EIP712, IGovernor {
using SafeCast for uint256;
using Timers for Timers.BlockNumber;
bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,uint8 support)");
struct ProposalCore {
Timers.BlockNumber voteStart;
Timers.BlockNumber voteEnd;
bool executed;
bool canceled;
}
string private _name;
mapping(uint256 => ProposalCore) private _proposals;
/**
* @dev Restrict access to governor executing address. Some module might override the _executor function to make
* sure this modifier is consistant with the execution model.
*/
modifier onlyGovernance() {
require(_msgSender() == _executor(), "Governor: onlyGovernance");
_;
}
/**
* @dev Sets the value for {name} and {version}
*/
constructor(string memory name_) EIP712(name_, version()) {
_name = name_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IGovernor).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IGovernor-name}.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev See {IGovernor-version}.
*/
function version() public view virtual override returns (string memory) {
return "1";
}
/**
* @dev See {IGovernor-hashProposal}.
*
* The proposal id is produced by hashing the RLC encoded `targets` array, the `values` array, the `calldatas` array
* and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id
* can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in
* advance, before the proposal is submitted.
*
* Note that the chainId and the governor address are not part of the proposal id computation. Consequently, the
* same proposal (with same operation and same description) will have the same id if submitted on multiple governors
* accross multiple networks. This also means that in order to execute the same operation twice (on the same
* governor) the proposer will have to change the description in order to avoid proposal id conflicts.
*/
function hashProposal(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public pure virtual override returns (uint256) {
return uint256(keccak256(abi.encode(targets, values, calldatas, descriptionHash)));
}
/**
* @dev See {IGovernor-state}.
*/
function state(uint256 proposalId) public view virtual override returns (ProposalState) {
ProposalCore memory proposal = _proposals[proposalId];
if (proposal.executed) {
return ProposalState.Executed;
} else if (proposal.canceled) {
return ProposalState.Canceled;
} else if (proposal.voteStart.isPending()) {
return ProposalState.Pending;
} else if (proposal.voteEnd.isPending()) {
return ProposalState.Active;
} else if (proposal.voteEnd.isExpired()) {
return
_quorumReached(proposalId) && _voteSucceeded(proposalId)
? ProposalState.Succeeded
: ProposalState.Defeated;
} else {
revert("Governor: unknown proposal id");
}
}
/**
* @dev See {IGovernor-proposalSnapshot}.
*/
function proposalSnapshot(uint256 proposalId) public view virtual override returns (uint256) {
return _proposals[proposalId].voteStart.getDeadline();
}
/**
* @dev See {IGovernor-proposalDeadline}.
*/
function proposalDeadline(uint256 proposalId) public view virtual override returns (uint256) {
return _proposals[proposalId].voteEnd.getDeadline();
}
/**
* @dev See {IGovernor-votingDelay}
*/
function votingDelay() public view virtual override returns (uint256);
/**
* @dev See {IGovernor-votingPeriod}
*/
function votingPeriod() public view virtual override returns (uint256);
/**
* @dev See {IGovernor-quorum}
*/
function quorum(uint256 blockNumber) public view virtual override returns (uint256);
/**
* @dev See {IGovernor-getVotes}
*/
function getVotes(address account, uint256 blockNumber) public view virtual override returns (uint256);
/**
* @dev Amount of votes already casted passes the threshold limit.
*/
function _quorumReached(uint256 proposalId) internal view virtual returns (bool);
/**
* @dev Is the proposal successful or not.
*/
function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool);
/**
* @dev Register a vote with a given support and voting weight.
*
* Note: Support is generic and can represent various things depending on the voting system used.
*/
function _countVote(
uint256 proposalId,
address account,
uint8 support,
uint256 weight
) internal virtual;
/**
* @dev See {IGovernor-propose}.
*/
function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description
) public virtual override returns (uint256) {
uint256 proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description)));
require(targets.length == values.length, "Governor: invalid proposal length");
require(targets.length == calldatas.length, "Governor: invalid proposal length");
require(targets.length > 0, "Governor: empty proposal");
ProposalCore storage proposal = _proposals[proposalId];
require(proposal.voteStart.isUnset(), "Governor: proposal already exists");
uint64 snapshot = block.number.toUint64() + votingDelay().toUint64();
uint64 deadline = snapshot + votingPeriod().toUint64();
proposal.voteStart.setDeadline(snapshot);
proposal.voteEnd.setDeadline(deadline);
emit ProposalCreated(
proposalId,
_msgSender(),
targets,
values,
new string[](targets.length),
calldatas,
snapshot,
deadline,
description
);
return proposalId;
}
/**
* @dev See {IGovernor-execute}.
*/
function execute(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public payable virtual override returns (uint256) {
uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash);
ProposalState status = state(proposalId);
require(
status == ProposalState.Succeeded || status == ProposalState.Queued,
"Governor: proposal not successful"
);
_proposals[proposalId].executed = true;
emit ProposalExecuted(proposalId);
_execute(proposalId, targets, values, calldatas, descriptionHash);
return proposalId;
}
/**
* @dev Internal execution mechanism. Can be overriden to implement different execution mechanism
*/
function _execute(
uint256, /* proposalId */
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 /*descriptionHash*/
) internal virtual {
string memory errorMessage = "Governor: call reverted without message";
for (uint256 i = 0; i < targets.length; ++i) {
(bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]);
Address.verifyCallResult(success, returndata, errorMessage);
}
}
/**
* @dev Internal cancel mechanism: locks up the proposal timer, preventing it from being re-submitted. Marks it as
* canceled to allow distinguishing it from executed proposals.
*
* Emits a {IGovernor-ProposalCanceled} event.
*/
function _cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal virtual returns (uint256) {
uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash);
ProposalState status = state(proposalId);
require(
status != ProposalState.Canceled && status != ProposalState.Expired && status != ProposalState.Executed,
"Governor: proposal not active"
);
_proposals[proposalId].canceled = true;
emit ProposalCanceled(proposalId);
return proposalId;
}
/**
* @dev See {IGovernor-castVote}.
*/
function castVote(uint256 proposalId, uint8 support) public virtual override returns (uint256) {
address voter = _msgSender();
return _castVote(proposalId, voter, support, "");
}
/**
* @dev See {IGovernor-castVoteWithReason}.
*/
function castVoteWithReason(
uint256 proposalId,
uint8 support,
string calldata reason
) public virtual override returns (uint256) {
address voter = _msgSender();
return _castVote(proposalId, voter, support, reason);
}
/**
* @dev See {IGovernor-castVoteBySig}.
*/
function castVoteBySig(
uint256 proposalId,
uint8 support,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override returns (uint256) {
address voter = ECDSA.recover(
_hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support))),
v,
r,
s
);
return _castVote(proposalId, voter, support, "");
}
/**
* @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been casted yet, retrieve
* voting weight using {IGovernor-getVotes} and call the {_countVote} internal function.
*
* Emits a {IGovernor-VoteCast} event.
*/
function _castVote(
uint256 proposalId,
address account,
uint8 support,
string memory reason
) internal virtual returns (uint256) {
ProposalCore storage proposal = _proposals[proposalId];
require(state(proposalId) == ProposalState.Active, "Governor: vote not currently active");
uint256 weight = getVotes(account, proposal.voteStart.getDeadline());
_countVote(proposalId, account, support, weight);
emit VoteCast(account, proposalId, support, weight, reason);
return weight;
}
/**
* @dev Address through which the governor executes action. Will be overloaded by module that execute actions
* through another contract such as a timelock.
*/
function _executor() internal view virtual returns (address) {
return address(this);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/introspection/ERC165.sol";
/**
* @dev Interface of the {Governor} core.
*
* _Available since v4.3._
*/
interface IGovernor is IERC165 {
enum ProposalState {
Pending,
Active,
Canceled,
Defeated,
Succeeded,
Queued,
Expired,
Executed
}
/**
* @dev Emitted when a proposal is created.
*/
event ProposalCreated(
uint256 proposalId,
address proposer,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
uint256 startBlock,
uint256 endBlock,
string description
);
/**
* @dev Emitted when a proposal is canceled.
*/
event ProposalCanceled(uint256 proposalId);
/**
* @dev Emitted when a proposal is executed.
*/
event ProposalExecuted(uint256 proposalId);
/**
* @dev Emitted when a vote is casted.
*
* Note: `support` values should be seen as buckets. There interpretation depends on the voting module used.
*/
event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason);
/**
* @notice module:core
* @dev Name of the governor instance (used in building the ERC712 domain separator).
*/
function name() external view returns (string memory);
/**
* @notice module:core
* @dev Version of the governor instance (used in building the ERC712 domain separator). Default: "1"
*/
function version() external view returns (string memory);
/**
* @notice module:voting
* @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to
* be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of
* key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`.
*
* There are 2 standard keys: `support` and `quorum`.
*
* - `support=bravo` refers to the vote options 0 = For, 1 = Against, 2 = Abstain, as in `GovernorBravo`.
* - `quorum=bravo` means that only For votes are counted towards quorum.
* - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum.
*
* NOTE: The string can be decoded by the standard
* https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`]
* JavaScript class.
*/
// solhint-disable-next-line func-name-mixedcase
function COUNTING_MODE() external pure returns (string memory);
/**
* @notice module:core
* @dev Hashing function used to (re)build the proposal id from the proposal details..
*/
function hashProposal(
address[] calldata targets,
uint256[] calldata values,
bytes[] calldata calldatas,
bytes32 descriptionHash
) external pure returns (uint256);
/**
* @notice module:core
* @dev Current state of a proposal, following Compound's convention
*/
function state(uint256 proposalId) external view returns (ProposalState);
/**
* @notice module:core
* @dev block number used to retrieve user's votes and quorum.
*/
function proposalSnapshot(uint256 proposalId) external view returns (uint256);
/**
* @notice module:core
* @dev timestamp at which votes close.
*/
function proposalDeadline(uint256 proposalId) external view returns (uint256);
/**
* @notice module:user-config
* @dev delay, in number of block, between the proposal is created and the vote starts. This can be increassed to
* leave time for users to buy voting power, of delegate it, before the voting of a proposal starts.
*/
function votingDelay() external view returns (uint256);
/**
* @notice module:user-config
* @dev delay, in number of blocks, between the vote start and vote ends.
*
* Note: the {votingDelay} can delay the start of the vote. This must be considered when setting the voting
* duration compared to the voting delay.
*/
function votingPeriod() external view returns (uint256);
/**
* @notice module:user-config
* @dev Minimum number of casted voted requiered for a proposal to be successful.
*
* Note: The `blockNumber` parameter corresponds to the snaphot used for counting vote. This allows to scale the
* quroum depending on values such as the totalSupply of a token at this block (see {ERC20Votes}).
*/
function quorum(uint256 blockNumber) external view returns (uint256);
/**
* @notice module:reputation
* @dev Voting power of an `account` at a specific `blockNumber`.
*
* Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or
* multiple), {ERC20Votes} tokens.
*/
function getVotes(address account, uint256 blockNumber) external view returns (uint256);
/**
* @notice module:voting
* @dev Returns weither `account` has casted a vote on `proposalId`.
*/
function hasVoted(uint256 proposalId, address account) external view returns (bool);
/**
* @dev Create a new proposal. Vote start {IGovernor-votingDelay} blocks after the proposal is created and ends
* {IGovernor-votingPeriod} blocks after the voting starts.
*
* Emits a {ProposalCreated} event.
*/
function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description
) external returns (uint256 proposalId);
/**
* @dev Execute a successful proposal. This requiers the quorum to be reached, the vote to be successful, and the
* deadline to be reached.
*
* Emits a {ProposalExecuted} event.
*
* Note: some module can modify the requierements for execution, for example by adding an additional timelock.
*/
function execute(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) external payable returns (uint256 proposalId);
/**
* @dev Cast a vote
*
* Emits a {VoteCast} event.
*/
function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance);
/**
* @dev Cast a with a reason
*
* Emits a {VoteCast} event.
*/
function castVoteWithReason(
uint256 proposalId,
uint8 support,
string calldata reason
) external returns (uint256 balance);
/**
* @dev Cast a vote using the user cryptographic signature.
*
* Emits a {VoteCast} event.
*/
function castVoteBySig(
uint256 proposalId,
uint8 support,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint256 balance);
}
...@@ -3,10 +3,64 @@ ...@@ -3,10 +3,64 @@
[.readme-notice] [.readme-notice]
NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/governance NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/governance
This directory includes primitives for on-chain governance. We currently only offer the {TimelockController} contract, that can be used as a component in a governance system to introduce a delay between a proposal and its execution. This directory includes primitives for on-chain governance.
== Governor
The {Governor} contract provides primitive to set an on-chain voting system similar to https://compound.finance/docs/governance[Compound's Governor Alpha & Bravo].
Similarly to our other contracts, it is customizable through inheritance and comes with extensions:
* {GovernorTimelockControl}: A {Governor} extension that performs executions through a {TimelockController}. This requires a successful proposal to be queued before then can be executed. The {TimelockController} will enforce a delay between the queueing and the execution. With this module, proposals are executed by the external {TimelockController} contract, which would have to hold the assets that are being governed.
* {GovernorTimelockCompound}: A {Governor} extension that performs executions through a compound https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[`Timelock`]. This requires a successful proposal to be queued before then can be executed. The `Timelock` will enforce a delay between the queueing and the execution. With this module, proposals are executed by the external `Timelock` contract, which would have to hold the assets that are being governed.
* {GovernorCountingSimple}: A simple voting mechanism for {Governor} with support 3 vote options: Against, For and Abstain.
* {GovernorVotes}: Binding to extract voting weight from an {ERC20Votes} token.
* {GovernorVotesQuorumFraction}: Binding to extract voting weight from an {ERC20Votes} token and set the quorum as a fraction of the (snapshoted) total token supply.
* {GovernorVotesComp}: Binding to extract voting weight from a Comp or {ERC20VotesComp} token.
In addition to modules, the {Governor} requires a few virtual functions to be implemented to your particular specifications:
* <<Governor-votingOffset-,`votingOffset()`>>: Delay (number of blocks), between the proposal, is submitted and the snapshot block used for voting. This can be used to enforce a delay after a proposal is published for users to buy tokens, or delegate their votes (default: 0).
* <<Governor-votingDuration-,`votingDuration()`>>: Delay (in seconds), between the proposal, is submitted and the vote ends.
* <<Governor-quorum-uint256-,`quorum(uint256 blockNumber)`>>: Quorum required for a proposal to be successful. This function includes a `blockNumber` argument so the quorum can adapt through time, for example, to follow a token's `totalSupply`.
Note: Function of the {Governor} contract does NOT include access control. If you want to restrict access (for example to require a minimum balance to submit a proposal), you should add these checks by overloading the particular functions. For security reasons, the {Governor-_cancel} method is internal, and you will have to expose it (which the right access control mechanism) yourself if this is a mechanism you need.
Events emitted by the {Governor} contract are compatible with Compound's `GovernorBravo`. Additionnaly, function compatibility can be added using the {GovernorCompatibilityBravo} compatibility layer. This layer includes a voting system but does not include token bindings. This layer also requiers a timelock module (either {GovernorTimelockControl} or {GovernorTimelockCompound}).
=== Core
{{IGovernor}}
{{Governor}}
=== Extensions
{{GovernorTimelockControl}}
{{GovernorTimelockCompound}}
{{GovernorCountingSimple}}
{{GovernorVotes}}
{{GovernorVotesQuorumFraction}}
{{GovernorVotesComp}}
=== Compatibility
{{GovernorCompatibilityBravo}}
== Timelock == Timelock
In a governance systems, the {TimelockController} contract is in carge of introducing a delay between a proposal and its execution. It can be used with or without a {Governor}.
{{TimelockController}} {{TimelockController}}
[[timelock-terminology]] [[timelock-terminology]]
...@@ -27,7 +81,7 @@ This directory includes primitives for on-chain governance. We currently only of ...@@ -27,7 +81,7 @@ This directory includes primitives for on-chain governance. We currently only of
[[timelock-operation]] [[timelock-operation]]
==== Operation structure ==== Operation structure
Operation executed by the xref:api:governance.adoc#TimelockController[`TimelockControler`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations. Operation executed by the xref:api:governance.adoc#TimelockController[`TimelockController`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations.
Both operations contain: Both operations contain:
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../../utils/Counters.sol";
import "../../utils/math/SafeCast.sol";
import "../extensions/IGovernorTimelock.sol";
import "../Governor.sol";
import "./IGovernorCompatibilityBravo.sol";
/**
* @dev Compatibility layer that implements GovernorBravo compatibility on to of {Governor}.
*
* This compatibility layer includes a voting system and requires a {IGovernorTimelock} compatible module to be added
* through inheritance. It does not include token bindings, not does it include any variable upgrade patterns.
*
* _Available since v4.3._
*/
abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorCompatibilityBravo, Governor {
using Counters for Counters.Counter;
using Timers for Timers.BlockNumber;
enum VoteType {
Against,
For,
Abstain
}
struct ProposalDetails {
address proposer;
address[] targets;
uint256[] values;
string[] signatures;
bytes[] calldatas;
uint256 forVotes;
uint256 againstVotes;
uint256 abstainVotes;
mapping(address => Receipt) receipts;
bytes32 descriptionHash;
}
mapping(uint256 => ProposalDetails) private _proposalDetails;
// public for hooking
function proposalThreshold() public view virtual override returns (uint256);
// public for hooking
function proposalEta(uint256 proposalId) public view virtual override returns (uint256);
// public for hooking
function queue(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public virtual override returns (uint256);
// solhint-disable-next-line func-name-mixedcase
function COUNTING_MODE() public pure virtual override returns (string memory) {
return "support=bravo&quorum=bravo";
}
// ============================================== Proposal lifecycle ==============================================
/**
* @dev See {IGovernor-propose}.
*/
function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description
) public virtual override(IGovernor, Governor) returns (uint256) {
return propose(targets, values, new string[](calldatas.length), calldatas, description);
}
/**
* @dev See {IGovernorCompatibilityBravo-propose}.
*/
function propose(
address[] memory targets,
uint256[] memory values,
string[] memory signatures,
bytes[] memory calldatas,
string memory description
) public virtual override returns (uint256) {
require(
getVotes(msg.sender, block.number - 1) >= proposalThreshold(),
"GovernorCompatibilityBravo: proposer votes below proposal threshold"
);
uint256 proposalId = super.propose(targets, values, _encodeCalldata(signatures, calldatas), description);
_storeProposal(proposalId, _msgSender(), targets, values, signatures, calldatas, description);
return proposalId;
}
/**
* @dev See {IGovernorCompatibilityBravo-queue}.
*/
function queue(uint256 proposalId) public virtual override {
ProposalDetails storage details = _proposalDetails[proposalId];
queue(
details.targets,
details.values,
_encodeCalldata(details.signatures, details.calldatas),
details.descriptionHash
);
}
/**
* @dev See {IGovernorCompatibilityBravo-execute}.
*/
function execute(uint256 proposalId) public payable virtual override {
ProposalDetails storage details = _proposalDetails[proposalId];
execute(
details.targets,
details.values,
_encodeCalldata(details.signatures, details.calldatas),
details.descriptionHash
);
}
/**
* @dev Encodes calldatas with optional function signature.
*/
function _encodeCalldata(string[] memory signatures, bytes[] memory calldatas)
private
pure
returns (bytes[] memory)
{
bytes[] memory fullcalldatas = new bytes[](calldatas.length);
for (uint256 i = 0; i < signatures.length; ++i) {
fullcalldatas[i] = bytes(signatures[i]).length == 0
? calldatas[i]
: abi.encodePacked(bytes4(keccak256(bytes(signatures[i]))), calldatas[i]);
}
return fullcalldatas;
}
/**
* @dev Store proposal metadata for later lookup
*/
function _storeProposal(
uint256 proposalId,
address proposer,
address[] memory targets,
uint256[] memory values,
string[] memory signatures,
bytes[] memory calldatas,
string memory description
) private {
ProposalDetails storage details = _proposalDetails[proposalId];
details.proposer = proposer;
details.targets = targets;
details.values = values;
details.signatures = signatures;
details.calldatas = calldatas;
details.descriptionHash = keccak256(bytes(description));
}
// ==================================================== Views =====================================================
/**
* @dev See {IGovernorCompatibilityBravo-proposals}.
*/
function proposals(uint256 proposalId)
public
view
virtual
override
returns (
uint256 id,
address proposer,
uint256 eta,
uint256 startBlock,
uint256 endBlock,
uint256 forVotes,
uint256 againstVotes,
uint256 abstainVotes,
bool canceled,
bool executed
)
{
id = proposalId;
eta = proposalEta(proposalId);
startBlock = proposalSnapshot(proposalId);
endBlock = proposalDeadline(proposalId);
ProposalDetails storage details = _proposalDetails[proposalId];
proposer = details.proposer;
forVotes = details.forVotes;
againstVotes = details.againstVotes;
abstainVotes = details.abstainVotes;
ProposalState status = state(proposalId);
canceled = status == ProposalState.Canceled;
executed = status == ProposalState.Executed;
}
/**
* @dev See {IGovernorCompatibilityBravo-getActions}.
*/
function getActions(uint256 proposalId)
public
view
virtual
override
returns (
address[] memory targets,
uint256[] memory values,
string[] memory signatures,
bytes[] memory calldatas
)
{
ProposalDetails storage details = _proposalDetails[proposalId];
return (details.targets, details.values, details.signatures, details.calldatas);
}
/**
* @dev See {IGovernorCompatibilityBravo-getReceipt}.
*/
function getReceipt(uint256 proposalId, address voter) public view virtual override returns (Receipt memory) {
return _proposalDetails[proposalId].receipts[voter];
}
/**
* @dev See {IGovernorCompatibilityBravo-quorumVotes}.
*/
function quorumVotes() public view virtual override returns (uint256) {
return quorum(block.number - 1);
}
// ==================================================== Voting ====================================================
/**
* @dev See {IGovernor-hasVoted}.
*/
function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) {
return _proposalDetails[proposalId].receipts[account].hasVoted;
}
/**
* @dev See {Governor-_quorumReached}. In this module, only forVotes count toward the quorum.
*/
function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) {
ProposalDetails storage details = _proposalDetails[proposalId];
return quorum(proposalSnapshot(proposalId)) < details.forVotes;
}
/**
* @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be scritly over the againstVotes.
*/
function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) {
ProposalDetails storage details = _proposalDetails[proposalId];
return details.forVotes > details.againstVotes;
}
/**
* @dev See {Governor-_countVote}. In this module, the support follows Governor Bravo.
*/
function _countVote(
uint256 proposalId,
address account,
uint8 support,
uint256 weight
) internal virtual override {
ProposalDetails storage details = _proposalDetails[proposalId];
Receipt storage receipt = details.receipts[account];
require(!receipt.hasVoted, "GovernorCompatibilityBravo: vote already casted");
receipt.hasVoted = true;
receipt.support = support;
receipt.votes = SafeCast.toUint96(weight);
if (support == uint8(VoteType.Against)) {
details.againstVotes += weight;
} else if (support == uint8(VoteType.For)) {
details.forVotes += weight;
} else if (support == uint8(VoteType.Abstain)) {
details.abstainVotes += weight;
} else {
revert("GovernorCompatibilityBravo: invalid vote type");
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../IGovernor.sol";
/**
* @dev Interface extension that adds missing functions to the {Governor} core to provide `GovernorBravo` compatibility.
*
* _Available since v4.3._
*/
interface IGovernorCompatibilityBravo is IGovernor {
/**
* @dev Proposal structure from Compound Governor Bravo. Not actually used by the compatibility layer, as
* {{proposal}} returns a very different structure.
*/
struct Proposal {
uint256 id;
address proposer;
uint256 eta;
address[] targets;
uint256[] values;
string[] signatures;
bytes[] calldatas;
uint256 startBlock;
uint256 endBlock;
uint256 forVotes;
uint256 againstVotes;
uint256 abstainVotes;
bool canceled;
bool executed;
mapping(address => Receipt) receipts;
}
/**
* @dev Receipt structure from Compound Governor Bravo
*/
struct Receipt {
bool hasVoted;
uint8 support;
uint96 votes;
}
/**
* @dev Part of the Governor Bravo's interface.
*/
function quorumVotes() external view returns (uint256);
/**
* @dev Part of the Governor Bravo's interface: _"The official record of all proposals ever proposed"_.
*/
function proposals(uint256)
external
view
returns (
uint256 id,
address proposer,
uint256 eta,
uint256 startBlock,
uint256 endBlock,
uint256 forVotes,
uint256 againstVotes,
uint256 abstainVotes,
bool canceled,
bool executed
);
/**
* @dev Part of the Governor Bravo's interface: _"Function used to propose a new proposal"_.
*/
function propose(
address[] memory targets,
uint256[] memory values,
string[] memory signatures,
bytes[] memory calldatas,
string memory description
) external returns (uint256);
/**
* @dev Part of the Governor Bravo's interface: _"Queues a proposal of state succeeded"_.
*/
function queue(uint256 proposalId) external;
/**
* @dev Part of the Governor Bravo's interface: _"Executes a queued proposal if eta has passed"_.
*/
function execute(uint256 proposalId) external payable;
/**
* @dev Part of the Governor Bravo's interface: _"Gets actions of a proposal"_.
*/
function getActions(uint256 proposalId)
external
view
returns (
address[] memory targets,
uint256[] memory values,
string[] memory signatures,
bytes[] memory calldatas
);
/**
* @dev Part of the Governor Bravo's interface: _"Gets the receipt for a voter on a given proposal"_.
*/
function getReceipt(uint256 proposalId, address voter) external view returns (Receipt memory);
/**
* @dev Part of the Governor Bravo's interface: _"The number of votes required in order for a voter to become a proposer"_.
*/
function proposalThreshold() external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../Governor.sol";
/**
* @dev Extension of {Governor} for simple, 3 options, vote counting.
*
* _Available since v4.3._
*/
abstract contract GovernorCountingSimple is Governor {
/**
* @dev Supported vote types. Matches Governor Bravo ordering.
*/
enum VoteType {
Against,
For,
Abstain
}
struct ProposalVote {
uint256 againstVotes;
uint256 forVotes;
uint256 abstainVotes;
mapping(address => bool) hasVoted;
}
mapping(uint256 => ProposalVote) private _proposalVotes;
/**
* @dev See {IGovernor-COUNTING_MODE}.
*/
// solhint-disable-next-line func-name-mixedcase
function COUNTING_MODE() public pure virtual override returns (string memory) {
return "support=bravo&quorum=for,abstain";
}
/**
* @dev See {IGovernor-hasVoted}.
*/
function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) {
return _proposalVotes[proposalId].hasVoted[account];
}
/**
* @dev Accessor to the internal vote counts.
*/
function proposalVotes(uint256 proposalId)
public
view
virtual
returns (
uint256 againstVotes,
uint256 forVotes,
uint256 abstainVotes
)
{
ProposalVote storage proposalvote = _proposalVotes[proposalId];
return (proposalvote.againstVotes, proposalvote.forVotes, proposalvote.abstainVotes);
}
/**
* @dev See {Governor-_quorumReached}.
*/
function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) {
ProposalVote storage proposalvote = _proposalVotes[proposalId];
return
quorum(proposalSnapshot(proposalId)) <=
proposalvote.againstVotes + proposalvote.forVotes + proposalvote.abstainVotes;
}
/**
* @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be scritly over the againstVotes.
*/
function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) {
ProposalVote storage proposalvote = _proposalVotes[proposalId];
return proposalvote.forVotes > proposalvote.againstVotes;
}
/**
* @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo).
*/
function _countVote(
uint256 proposalId,
address account,
uint8 support,
uint256 weight
) internal virtual override {
ProposalVote storage proposalvote = _proposalVotes[proposalId];
require(!proposalvote.hasVoted[account], "GovernorVotingSimple: vote already casted");
proposalvote.hasVoted[account] = true;
if (support == uint8(VoteType.Against)) {
proposalvote.againstVotes += weight;
} else if (support == uint8(VoteType.For)) {
proposalvote.forVotes += weight;
} else if (support == uint8(VoteType.Abstain)) {
proposalvote.abstainVotes += weight;
} else {
revert("GovernorVotingSimple: invalid value for enum VoteType");
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IGovernorTimelock.sol";
import "../Governor.sol";
import "../../utils/math/SafeCast.sol";
/**
* https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[Compound's timelock] interface
*/
interface ICompoundTimelock {
receive() external payable;
// solhint-disable-next-line func-name-mixedcase
function GRACE_PERIOD() external view returns (uint256);
// solhint-disable-next-line func-name-mixedcase
function MINIMUM_DELAY() external view returns (uint256);
// solhint-disable-next-line func-name-mixedcase
function MAXIMUM_DELAY() external view returns (uint256);
function admin() external view returns (address);
function pendingAdmin() external view returns (address);
function delay() external view returns (uint256);
function queuedTransactions(bytes32) external view returns (bool);
function setDelay(uint256) external;
function acceptAdmin() external;
function setPendingAdmin(address) external;
function queueTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 eta
) external returns (bytes32);
function cancelTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 eta
) external;
function executeTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 eta
) external payable returns (bytes memory);
}
/**
* @dev Extension of {Governor} that binds the execution process to a Compound Timelock. This adds a delay, enforced by
* the external timelock to all successful proposal (in addition to the voting duration). The {Governor} needs to be
* the admin of the timelock for any operation to be performed. A public, unrestricted,
* {GovernorTimelockCompound-__acceptAdmin} is available to accept ownership of the timelock.
*
* Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus,
* the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be
* inaccessible.
*
* _Available since v4.3._
*/
abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor {
using SafeCast for uint256;
using Timers for Timers.Timestamp;
struct ProposalTimelock {
Timers.Timestamp timer;
}
ICompoundTimelock private _timelock;
mapping(uint256 => ProposalTimelock) private _proposalTimelocks;
/**
* @dev Emitted when the timelock controller used for proposal execution is modified.
*/
event TimelockChange(address oldTimelock, address newTimelock);
/**
* @dev Set the timelock.
*/
constructor(ICompoundTimelock timelockAddress) {
_updateTimelock(timelockAddress);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, Governor) returns (bool) {
return interfaceId == type(IGovernorTimelock).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Overriden version of the {Governor-state} function with added support for the `Queued` and `Expired` status.
*/
function state(uint256 proposalId) public view virtual override(IGovernor, Governor) returns (ProposalState) {
ProposalState status = super.state(proposalId);
if (status != ProposalState.Succeeded) {
return status;
}
uint256 eta = proposalEta(proposalId);
if (eta == 0) {
return status;
} else if (block.timestamp >= eta + _timelock.GRACE_PERIOD()) {
return ProposalState.Expired;
} else {
return ProposalState.Queued;
}
}
/**
* @dev Public accessor to check the address of the timelock
*/
function timelock() public view virtual override returns (address) {
return address(_timelock);
}
/**
* @dev Public accessor to check the eta of a queued proposal
*/
function proposalEta(uint256 proposalId) public view virtual override returns (uint256) {
return _proposalTimelocks[proposalId].timer.getDeadline();
}
/**
* @dev Function to queue a proposal to the timelock.
*/
function queue(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public virtual override returns (uint256) {
uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash);
require(state(proposalId) == ProposalState.Succeeded, "Governor: proposal not successful");
uint256 eta = block.timestamp + _timelock.delay();
_proposalTimelocks[proposalId].timer.setDeadline(eta.toUint64());
for (uint256 i = 0; i < targets.length; ++i) {
require(
!_timelock.queuedTransactions(keccak256(abi.encode(targets[i], values[i], "", calldatas[i], eta))),
"GovernorTimelockCompound: identical proposal action already queued"
);
_timelock.queueTransaction(targets[i], values[i], "", calldatas[i], eta);
}
emit ProposalQueued(proposalId, eta);
return proposalId;
}
/**
* @dev Overriden execute function that run the already queued proposal through the timelock.
*/
function _execute(
uint256 proposalId,
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 /*descriptionHash*/
) internal virtual override {
uint256 eta = proposalEta(proposalId);
require(eta > 0, "GovernorTimelockCompound: proposal not yet queued");
for (uint256 i = 0; i < targets.length; ++i) {
_timelock.executeTransaction{value: values[i]}(targets[i], values[i], "", calldatas[i], eta);
}
}
/**
* @dev Overriden version of the {Governor-_cancel} function to cancel the timelocked proposal if it as already
* been queued.
*/
function _cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal virtual override returns (uint256) {
uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash);
uint256 eta = proposalEta(proposalId);
if (eta > 0) {
for (uint256 i = 0; i < targets.length; ++i) {
_timelock.cancelTransaction(targets[i], values[i], "", calldatas[i], eta);
}
_proposalTimelocks[proposalId].timer.reset();
}
return proposalId;
}
/**
* @dev Address through which the governor executes action. In this case, the timelock.
*/
function _executor() internal view virtual override returns (address) {
return address(_timelock);
}
/**
* @dev Accept admin right over the timelock.
*/
// solhint-disable-next-line private-vars-leading-underscore
function __acceptAdmin() public {
_timelock.acceptAdmin();
}
/**
* @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates
* must be proposed, scheduled and executed using the {Governor} workflow.
*
* For security reason, the timelock must be handed over to another admin before setting up a new one. The two
* operations (hand over the timelock) and do the update can be batched in a single proposal.
*
* Note that if the timelock admin has been handed over in a previous operation, we refuse updates made through the
* timelock if admin of the timelock has already been accepted and the operation is executed outside the scope of
* governance.
*/
function updateTimelock(ICompoundTimelock newTimelock) external virtual onlyGovernance {
_updateTimelock(newTimelock);
}
function _updateTimelock(ICompoundTimelock newTimelock) private {
emit TimelockChange(address(_timelock), address(newTimelock));
_timelock = newTimelock;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IGovernorTimelock.sol";
import "../Governor.sol";
import "../TimelockController.sol";
/**
* @dev Extension of {Governor} that binds the execution process to an instance of {TimelockController}. This adds a
* delay, enforced by the {TimelockController} to all successful proposal (in addition to the voting duration). The
* {Governor} needs the proposer (an ideally the executor) roles for the {Governor} to work properly.
*
* Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus,
* the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be
* inaccessible.
*
* _Available since v4.3._
*/
abstract contract GovernorTimelockControl is IGovernorTimelock, Governor {
TimelockController private _timelock;
mapping(uint256 => bytes32) private _timelockIds;
/**
* @dev Emitted when the timelock controller used for proposal execution is modified.
*/
event TimelockChange(address oldTimelock, address newTimelock);
/**
* @dev Set the timelock.
*/
constructor(TimelockController timelockAddress) {
_updateTimelock(timelockAddress);
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, Governor) returns (bool) {
return interfaceId == type(IGovernorTimelock).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Overriden version of the {Governor-state} function with added support for the `Queued` status.
*/
function state(uint256 proposalId) public view virtual override(IGovernor, Governor) returns (ProposalState) {
ProposalState status = super.state(proposalId);
if (status != ProposalState.Succeeded) {
return status;
}
// core tracks execution, so we just have to check if successful proposal have been queued.
bytes32 queueid = _timelockIds[proposalId];
if (queueid == bytes32(0)) {
return status;
} else if (_timelock.isOperationDone(queueid)) {
return ProposalState.Executed;
} else {
return ProposalState.Queued;
}
}
/**
* @dev Public accessor to check the address of the timelock
*/
function timelock() public view virtual override returns (address) {
return address(_timelock);
}
/**
* @dev Public accessor to check the eta of a queued proposal
*/
function proposalEta(uint256 proposalId) public view virtual override returns (uint256) {
uint256 eta = _timelock.getTimestamp(_timelockIds[proposalId]);
return eta == 1 ? 0 : eta; // _DONE_TIMESTAMP (1) should be replaced with a 0 value
}
/**
* @dev Function to queue a proposal to the timelock.
*/
function queue(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public virtual override returns (uint256) {
uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash);
require(state(proposalId) == ProposalState.Succeeded, "Governor: proposal not successful");
uint256 delay = _timelock.getMinDelay();
_timelockIds[proposalId] = _timelock.hashOperationBatch(targets, values, calldatas, 0, descriptionHash);
_timelock.scheduleBatch(targets, values, calldatas, 0, descriptionHash, delay);
emit ProposalQueued(proposalId, block.timestamp + delay);
return proposalId;
}
/**
* @dev Overriden execute function that run the already queued proposal through the timelock.
*/
function _execute(
uint256, /* proposalId */
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal virtual override {
_timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, descriptionHash);
}
/**
* @dev Overriden version of the {Governor-_cancel} function to cancel the timelocked proposal if it as already
* been queued.
*/
function _cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal virtual override returns (uint256) {
uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash);
if (_timelockIds[proposalId] != 0) {
_timelock.cancel(_timelockIds[proposalId]);
delete _timelockIds[proposalId];
}
return proposalId;
}
/**
* @dev Address through which the governor executes action. In this case, the timelock.
*/
function _executor() internal view virtual override returns (address) {
return address(_timelock);
}
/**
* @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates
* must be proposed, scheduled and executed using the {Governor} workflow.
*/
function updateTimelock(TimelockController newTimelock) external virtual onlyGovernance {
_updateTimelock(newTimelock);
}
function _updateTimelock(TimelockController newTimelock) private {
emit TimelockChange(address(_timelock), address(newTimelock));
_timelock = newTimelock;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../Governor.sol";
import "../../token/ERC20/extensions/ERC20Votes.sol";
import "../../utils/math/Math.sol";
/**
* @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token.
*
* _Available since v4.3._
*/
abstract contract GovernorVotes is Governor {
ERC20Votes public immutable token;
constructor(ERC20Votes tokenAddress) {
token = tokenAddress;
}
/**
* Read the voting weight from the token's built in snapshot mechanism (see {IGovernor-getVotes}).
*/
function getVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
return token.getPastVotes(account, blockNumber);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../Governor.sol";
import "../../token/ERC20/extensions/ERC20VotesComp.sol";
/**
* @dev Extension of {Governor} for voting weight extraction from a Comp token.
*
* _Available since v4.3._
*/
abstract contract GovernorVotesComp is Governor {
ERC20VotesComp public immutable token;
constructor(ERC20VotesComp token_) {
token = token_;
}
/**
* Read the voting weight from the token's built in snapshot mechanism (see {IGovernor-getVotes}).
*/
function getVotes(address account, uint256 blockNumber) public view virtual override returns (uint256) {
return token.getPriorVotes(account, blockNumber);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./GovernorVotes.sol";
/**
* @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a
* fraction of the total supply.
*
* _Available since v4.3._
*/
abstract contract GovernorVotesQuorumFraction is GovernorVotes {
uint256 private _quorumNumerator;
event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator);
constructor(uint256 quorumNumeratorValue) {
_updateQuorumNumerator(quorumNumeratorValue);
}
function quorumNumerator() public view virtual returns (uint256) {
return _quorumNumerator;
}
function quorumDenominator() public view virtual returns (uint256) {
return 100;
}
function quorum(uint256 blockNumber) public view virtual override returns (uint256) {
return (token.getPastTotalSupply(blockNumber) * quorumNumerator()) / quorumDenominator();
}
function updateQuorumNumerator(uint256 newQuorumNumerator) external virtual onlyGovernance {
_updateQuorumNumerator(newQuorumNumerator);
}
function _updateQuorumNumerator(uint256 newQuorumNumerator) internal virtual {
require(
newQuorumNumerator <= quorumDenominator(),
"GovernorVotesQuorumFraction: quorumNumerator over quorumDenominator"
);
uint256 oldQuorumNumerator = _quorumNumerator;
_quorumNumerator = newQuorumNumerator;
emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../IGovernor.sol";
/**
* @dev Extension of the {IGovernor} for timelock supporting modules.
*
* _Available since v4.3._
*/
interface IGovernorTimelock is IGovernor {
event ProposalQueued(uint256 proposalId, uint256 eta);
function timelock() external view returns (address);
function proposalEta(uint256 proposalId) external view returns (uint256);
function queue(
address[] calldata targets,
uint256[] calldata values,
bytes[] calldata calldatas,
bytes32 descriptionHash
) external returns (uint256 proposalId);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../governance/Governor.sol";
import "../governance/extensions/GovernorCountingSimple.sol";
import "../governance/extensions/GovernorVotesComp.sol";
contract GovernorCompMock is Governor, GovernorVotesComp, GovernorCountingSimple {
uint256 immutable _votingDelay;
uint256 immutable _votingPeriod;
constructor(
string memory name_,
ERC20VotesComp token_,
uint256 votingDelay_,
uint256 votingPeriod_
) Governor(name_) GovernorVotesComp(token_) {
_votingDelay = votingDelay_;
_votingPeriod = votingPeriod_;
}
receive() external payable {}
function votingDelay() public view override returns (uint256) {
return _votingDelay;
}
function votingPeriod() public view override returns (uint256) {
return _votingPeriod;
}
function quorum(uint256) public pure override returns (uint256) {
return 0;
}
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 salt
) public returns (uint256 proposalId) {
return _cancel(targets, values, calldatas, salt);
}
function getVotes(address account, uint256 blockNumber)
public
view
virtual
override(Governor, GovernorVotesComp)
returns (uint256)
{
return super.getVotes(account, blockNumber);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../governance/compatibility/GovernorCompatibilityBravo.sol";
import "../governance/extensions/GovernorVotesComp.sol";
import "../governance/extensions/GovernorTimelockCompound.sol";
contract GovernorCompatibilityBravoMock is GovernorCompatibilityBravo, GovernorTimelockCompound, GovernorVotesComp {
uint256 immutable _votingDelay;
uint256 immutable _votingPeriod;
uint256 immutable _proposalThreshold;
constructor(
string memory name_,
ERC20VotesComp token_,
uint256 votingDelay_,
uint256 votingPeriod_,
uint256 proposalThreshold_,
ICompoundTimelock timelock_
) Governor(name_) GovernorVotesComp(token_) GovernorTimelockCompound(timelock_) {
_votingDelay = votingDelay_;
_votingPeriod = votingPeriod_;
_proposalThreshold = proposalThreshold_;
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(IERC165, Governor, GovernorTimelockCompound)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
function votingDelay() public view override(IGovernor, Governor) returns (uint256) {
return _votingDelay;
}
function votingPeriod() public view override(IGovernor, Governor) returns (uint256) {
return _votingPeriod;
}
function proposalThreshold() public view virtual override returns (uint256) {
return _proposalThreshold;
}
function quorum(uint256) public pure override(IGovernor, Governor) returns (uint256) {
return 0;
}
function state(uint256 proposalId)
public
view
virtual
override(IGovernor, Governor, GovernorTimelockCompound)
returns (ProposalState)
{
return super.state(proposalId);
}
function proposalEta(uint256 proposalId)
public
view
virtual
override(GovernorCompatibilityBravo, GovernorTimelockCompound)
returns (uint256)
{
return super.proposalEta(proposalId);
}
function propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description
) public virtual override(IGovernor, Governor, GovernorCompatibilityBravo) returns (uint256) {
return super.propose(targets, values, calldatas, description);
}
function queue(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 salt
) public virtual override(GovernorCompatibilityBravo, GovernorTimelockCompound) returns (uint256) {
return super.queue(targets, values, calldatas, salt);
}
function execute(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 salt
) public payable virtual override(IGovernor, Governor) returns (uint256) {
return super.execute(targets, values, calldatas, salt);
}
function _execute(
uint256 proposalId,
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal virtual override(Governor, GovernorTimelockCompound) {
super._execute(proposalId, targets, values, calldatas, descriptionHash);
}
/**
* @notice WARNING: this is for mock purposes only. Ability to the _cancel function should be restricted for live
* deployments.
*/
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 salt
) public returns (uint256 proposalId) {
return _cancel(targets, values, calldatas, salt);
}
function _cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 salt
) internal virtual override(Governor, GovernorTimelockCompound) returns (uint256 proposalId) {
return super._cancel(targets, values, calldatas, salt);
}
function getVotes(address account, uint256 blockNumber)
public
view
virtual
override(IGovernor, GovernorVotesComp)
returns (uint256)
{
return super.getVotes(account, blockNumber);
}
function _executor() internal view virtual override(Governor, GovernorTimelockCompound) returns (address) {
return super._executor();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../governance/Governor.sol";
import "../governance/extensions/GovernorCountingSimple.sol";
import "../governance/extensions/GovernorVotesQuorumFraction.sol";
contract GovernorMock is Governor, GovernorVotesQuorumFraction, GovernorCountingSimple {
uint256 immutable _votingDelay;
uint256 immutable _votingPeriod;
constructor(
string memory name_,
ERC20Votes token_,
uint256 votingDelay_,
uint256 votingPeriod_,
uint256 quorumNumerator_
) Governor(name_) GovernorVotes(token_) GovernorVotesQuorumFraction(quorumNumerator_) {
_votingDelay = votingDelay_;
_votingPeriod = votingPeriod_;
}
receive() external payable {}
function votingDelay() public view override returns (uint256) {
return _votingDelay;
}
function votingPeriod() public view override returns (uint256) {
return _votingPeriod;
}
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 salt
) public returns (uint256 proposalId) {
return _cancel(targets, values, calldatas, salt);
}
function getVotes(address account, uint256 blockNumber)
public
view
virtual
override(Governor, GovernorVotes)
returns (uint256)
{
return super.getVotes(account, blockNumber);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../governance/extensions/GovernorTimelockCompound.sol";
import "../governance/extensions/GovernorCountingSimple.sol";
import "../governance/extensions/GovernorVotesQuorumFraction.sol";
contract GovernorTimelockCompoundMock is GovernorTimelockCompound, GovernorVotesQuorumFraction, GovernorCountingSimple {
uint256 immutable _votingDelay;
uint256 immutable _votingPeriod;
constructor(
string memory name_,
ERC20Votes token_,
uint256 votingDelay_,
uint256 votingPeriod_,
ICompoundTimelock timelock_,
uint256 quorumNumerator_
)
Governor(name_)
GovernorTimelockCompound(timelock_)
GovernorVotes(token_)
GovernorVotesQuorumFraction(quorumNumerator_)
{
_votingDelay = votingDelay_;
_votingPeriod = votingPeriod_;
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(Governor, GovernorTimelockCompound)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
function votingDelay() public view override(IGovernor, Governor) returns (uint256) {
return _votingDelay;
}
function votingPeriod() public view override(IGovernor, Governor) returns (uint256) {
return _votingPeriod;
}
function quorum(uint256 blockNumber)
public
view
override(IGovernor, Governor, GovernorVotesQuorumFraction)
returns (uint256)
{
return super.quorum(blockNumber);
}
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 salt
) public returns (uint256 proposalId) {
return _cancel(targets, values, calldatas, salt);
}
/**
* Overriding nightmare
*/
function state(uint256 proposalId)
public
view
virtual
override(Governor, GovernorTimelockCompound)
returns (ProposalState)
{
return super.state(proposalId);
}
function _execute(
uint256 proposalId,
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal virtual override(Governor, GovernorTimelockCompound) {
super._execute(proposalId, targets, values, calldatas, descriptionHash);
}
function _cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 salt
) internal virtual override(Governor, GovernorTimelockCompound) returns (uint256 proposalId) {
return super._cancel(targets, values, calldatas, salt);
}
function getVotes(address account, uint256 blockNumber)
public
view
virtual
override(IGovernor, Governor, GovernorVotes)
returns (uint256)
{
return super.getVotes(account, blockNumber);
}
function _executor() internal view virtual override(Governor, GovernorTimelockCompound) returns (address) {
return super._executor();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../governance/extensions/GovernorTimelockControl.sol";
import "../governance/extensions/GovernorCountingSimple.sol";
import "../governance/extensions/GovernorVotesQuorumFraction.sol";
contract GovernorTimelockControlMock is GovernorTimelockControl, GovernorVotesQuorumFraction, GovernorCountingSimple {
uint256 immutable _votingDelay;
uint256 immutable _votingPeriod;
constructor(
string memory name_,
ERC20Votes token_,
uint256 votingDelay_,
uint256 votingPeriod_,
TimelockController timelock_,
uint256 quorumNumerator_
)
Governor(name_)
GovernorTimelockControl(timelock_)
GovernorVotes(token_)
GovernorVotesQuorumFraction(quorumNumerator_)
{
_votingDelay = votingDelay_;
_votingPeriod = votingPeriod_;
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(Governor, GovernorTimelockControl)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
function votingDelay() public view override(IGovernor, Governor) returns (uint256) {
return _votingDelay;
}
function votingPeriod() public view override(IGovernor, Governor) returns (uint256) {
return _votingPeriod;
}
function quorum(uint256 blockNumber)
public
view
override(IGovernor, Governor, GovernorVotesQuorumFraction)
returns (uint256)
{
return super.quorum(blockNumber);
}
function cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) public returns (uint256 proposalId) {
return _cancel(targets, values, calldatas, descriptionHash);
}
/**
* Overriding nightmare
*/
function state(uint256 proposalId)
public
view
virtual
override(Governor, GovernorTimelockControl)
returns (ProposalState)
{
return super.state(proposalId);
}
function _execute(
uint256 proposalId,
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal virtual override(Governor, GovernorTimelockControl) {
super._execute(proposalId, targets, values, calldatas, descriptionHash);
}
function _cancel(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
bytes32 descriptionHash
) internal virtual override(Governor, GovernorTimelockControl) returns (uint256 proposalId) {
return super._cancel(targets, values, calldatas, descriptionHash);
}
function getVotes(address account, uint256 blockNumber)
public
view
virtual
override(IGovernor, Governor, GovernorVotes)
returns (uint256)
{
return super.getVotes(account, blockNumber);
}
function _executor() internal view virtual override(Governor, GovernorTimelockControl) returns (address) {
return super._executor();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/Timers.sol";
contract TimersBlockNumberImpl {
using Timers for Timers.BlockNumber;
Timers.BlockNumber private _timer;
function getDeadline() public view returns (uint64) {
return _timer.getDeadline();
}
function setDeadline(uint64 timestamp) public {
_timer.setDeadline(timestamp);
}
function reset() public {
_timer.reset();
}
function isUnset() public view returns (bool) {
return _timer.isUnset();
}
function isStarted() public view returns (bool) {
return _timer.isStarted();
}
function isPending() public view returns (bool) {
return _timer.isPending();
}
function isExpired() public view returns (bool) {
return _timer.isExpired();
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/Timers.sol";
contract TimersTimestampImpl {
using Timers for Timers.Timestamp;
Timers.Timestamp private _timer;
function getDeadline() public view returns (uint64) {
return _timer.getDeadline();
}
function setDeadline(uint64 timestamp) public {
_timer.setDeadline(timestamp);
}
function reset() public {
_timer.reset();
}
function isUnset() public view returns (bool) {
return _timer.isUnset();
}
function isStarted() public view returns (bool) {
return _timer.isStarted();
}
function isPending() public view returns (bool) {
return _timer.isPending();
}
function isExpired() public view returns (bool) {
return _timer.isExpired();
}
}
// SPDX-License-Identifier: BSD-3-Clause
// solhint-disable private-vars-leading-underscore
/**
* Copyright 2020 Compound Labs, Inc.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
pragma solidity ^0.8.0;
contract CompTimelock {
event NewAdmin(address indexed newAdmin);
event NewPendingAdmin(address indexed newPendingAdmin);
event NewDelay(uint256 indexed newDelay);
event CancelTransaction(
bytes32 indexed txHash,
address indexed target,
uint256 value,
string signature,
bytes data,
uint256 eta
);
event ExecuteTransaction(
bytes32 indexed txHash,
address indexed target,
uint256 value,
string signature,
bytes data,
uint256 eta
);
event QueueTransaction(
bytes32 indexed txHash,
address indexed target,
uint256 value,
string signature,
bytes data,
uint256 eta
);
uint256 public constant GRACE_PERIOD = 14 days;
uint256 public constant MINIMUM_DELAY = 2 days;
uint256 public constant MAXIMUM_DELAY = 30 days;
address public admin;
address public pendingAdmin;
uint256 public delay;
mapping(bytes32 => bool) public queuedTransactions;
constructor(address admin_, uint256 delay_) {
require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay.");
require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay.");
admin = admin_;
delay = delay_;
}
receive() external payable {}
function setDelay(uint256 delay_) public {
require(msg.sender == address(this), "Timelock::setDelay: Call must come from Timelock.");
require(delay_ >= MINIMUM_DELAY, "Timelock::setDelay: Delay must exceed minimum delay.");
require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay.");
delay = delay_;
emit NewDelay(delay);
}
function acceptAdmin() public {
require(msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin.");
admin = msg.sender;
pendingAdmin = address(0);
emit NewAdmin(admin);
}
function setPendingAdmin(address pendingAdmin_) public {
require(msg.sender == address(this), "Timelock::setPendingAdmin: Call must come from Timelock.");
pendingAdmin = pendingAdmin_;
emit NewPendingAdmin(pendingAdmin);
}
function queueTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 eta
) public returns (bytes32) {
require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin.");
require(
eta >= getBlockTimestamp() + delay,
"Timelock::queueTransaction: Estimated execution block must satisfy delay."
);
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
queuedTransactions[txHash] = true;
emit QueueTransaction(txHash, target, value, signature, data, eta);
return txHash;
}
function cancelTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 eta
) public {
require(msg.sender == admin, "Timelock::cancelTransaction: Call must come from admin.");
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
queuedTransactions[txHash] = false;
emit CancelTransaction(txHash, target, value, signature, data, eta);
}
function executeTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 eta
) public payable returns (bytes memory) {
require(msg.sender == admin, "Timelock::executeTransaction: Call must come from admin.");
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued.");
require(getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock.");
require(getBlockTimestamp() <= eta + GRACE_PERIOD, "Timelock::executeTransaction: Transaction is stale.");
queuedTransactions[txHash] = false;
bytes memory callData;
if (bytes(signature).length == 0) {
callData = data;
} else {
callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);
}
// solium-disable-next-line security/no-call-value
(bool success, bytes memory returnData) = target.call{value: value}(callData);
require(success, "Timelock::executeTransaction: Transaction execution reverted.");
emit ExecuteTransaction(txHash, target, value, signature, data, eta);
return returnData;
}
function getBlockTimestamp() internal view returns (uint256) {
// solium-disable-next-line security/no-block-members
return block.timestamp;
}
}
...@@ -53,7 +53,7 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { ...@@ -53,7 +53,7 @@ abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender {
* supported. * supported.
* @param amount The amount of tokens to be loaned. * @param amount The amount of tokens to be loaned.
* @param data An arbitrary datafield that is passed to the receiver. * @param data An arbitrary datafield that is passed to the receiver.
* @return `true` is the flash loan was successfull. * @return `true` is the flash loan was successful.
*/ */
function flashLoan( function flashLoan(
IERC3156FlashBorrower receiver, IERC3156FlashBorrower receiver,
......
...@@ -129,7 +129,7 @@ library Address { ...@@ -129,7 +129,7 @@ library Address {
require(isContract(target), "Address: call to non-contract"); require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data); (bool success, bytes memory returndata) = target.call{value: value}(data);
return _verifyCallResult(success, returndata, errorMessage); return verifyCallResult(success, returndata, errorMessage);
} }
/** /**
...@@ -156,7 +156,7 @@ library Address { ...@@ -156,7 +156,7 @@ library Address {
require(isContract(target), "Address: static call to non-contract"); require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data); (bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage); return verifyCallResult(success, returndata, errorMessage);
} }
/** /**
...@@ -183,14 +183,20 @@ library Address { ...@@ -183,14 +183,20 @@ library Address {
require(isContract(target), "Address: delegate call to non-contract"); require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data); (bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage); return verifyCallResult(success, returndata, errorMessage);
} }
function _verifyCallResult( /**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success, bool success,
bytes memory returndata, bytes memory returndata,
string memory errorMessage string memory errorMessage
) private pure returns (bytes memory) { ) internal pure returns (bytes memory) {
if (success) { if (success) {
return returndata; return returndata;
} else { } else {
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Tooling for timepoints, timers and delays
*/
library Timers {
struct Timestamp {
uint64 _deadline;
}
function getDeadline(Timestamp memory timer) internal pure returns (uint64) {
return timer._deadline;
}
function setDeadline(Timestamp storage timer, uint64 timestamp) internal {
timer._deadline = timestamp;
}
function reset(Timestamp storage timer) internal {
timer._deadline = 0;
}
function isUnset(Timestamp memory timer) internal pure returns (bool) {
return timer._deadline == 0;
}
function isStarted(Timestamp memory timer) internal pure returns (bool) {
return timer._deadline > 0;
}
function isPending(Timestamp memory timer) internal view returns (bool) {
return timer._deadline > block.timestamp;
}
function isExpired(Timestamp memory timer) internal view returns (bool) {
return isStarted(timer) && timer._deadline <= block.timestamp;
}
struct BlockNumber {
uint64 _deadline;
}
function getDeadline(BlockNumber memory timer) internal pure returns (uint64) {
return timer._deadline;
}
function setDeadline(BlockNumber storage timer, uint64 timestamp) internal {
timer._deadline = timestamp;
}
function reset(BlockNumber storage timer) internal {
timer._deadline = 0;
}
function isUnset(BlockNumber memory timer) internal pure returns (bool) {
return timer._deadline == 0;
}
function isStarted(BlockNumber memory timer) internal pure returns (bool) {
return timer._deadline > 0;
}
function isPending(BlockNumber memory timer) internal view returns (bool) {
return timer._deadline > block.number;
}
function isExpired(BlockNumber memory timer) internal view returns (bool) {
return isStarted(timer) && timer._deadline <= block.number;
}
}
...@@ -23,6 +23,8 @@ for (const f of fs.readdirSync(path.join(__dirname, 'hardhat'))) { ...@@ -23,6 +23,8 @@ for (const f of fs.readdirSync(path.join(__dirname, 'hardhat'))) {
require(path.join(__dirname, 'hardhat', f)); require(path.join(__dirname, 'hardhat', f));
} }
const withOptimizations = argv.enableGasReport || argv.compileMode === 'production';
/** /**
* @type import('hardhat/config').HardhatUserConfig * @type import('hardhat/config').HardhatUserConfig
*/ */
...@@ -31,7 +33,7 @@ module.exports = { ...@@ -31,7 +33,7 @@ module.exports = {
version: '0.8.3', version: '0.8.3',
settings: { settings: {
optimizer: { optimizer: {
enabled: argv.enableGasReport || argv.compileMode === 'production', enabled: withOptimizations,
runs: 200, runs: 200,
}, },
}, },
...@@ -39,6 +41,7 @@ module.exports = { ...@@ -39,6 +41,7 @@ module.exports = {
networks: { networks: {
hardhat: { hardhat: {
blockGasLimit: 10000000, blockGasLimit: 10000000,
allowUnlimitedContractSize: !withOptimizations,
}, },
}, },
gasReporter: { gasReporter: {
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
"merkletreejs": "^0.2.13", "merkletreejs": "^0.2.13",
"micromatch": "^4.0.2", "micromatch": "^4.0.2",
"prettier": "^2.3.0", "prettier": "^2.3.0",
"prettier-plugin-solidity": "^1.0.0-beta.13", "prettier-plugin-solidity": "^1.0.0-beta.16",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"solhint": "^3.3.6", "solhint": "^3.3.6",
"solidity-ast": "^0.4.25", "solidity-ast": "^0.4.25",
...@@ -223,28 +223,28 @@ ...@@ -223,28 +223,28 @@
"dev": true "dev": true
}, },
"node_modules/@ethereumjs/block": { "node_modules/@ethereumjs/block": {
"version": "3.4.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/block/-/block-3.4.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/block/-/block-3.3.0.tgz",
"integrity": "sha512-umKAoTX32yXzErpIksPHodFc/5y8bmZMnOl6hWy5Vd8xId4+HKFUOyEiN16Y97zMwFRysRpcrR6wBejfqc6Bmg==", "integrity": "sha512-WoefY9Rs4W8vZTxG9qwntAlV61xsSv0NPoXmHO7x3SH16dwJQtU15YvahPCz4HEEXbu7GgGgNgu0pv8JY7VauA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@ethereumjs/common": "^2.4.0", "@ethereumjs/common": "^2.3.0",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.2.0",
"ethereumjs-util": "^7.1.0", "ethereumjs-util": "^7.0.10",
"merkle-patricia-tree": "^4.2.0" "merkle-patricia-tree": "^4.2.0"
} }
}, },
"node_modules/@ethereumjs/blockchain": { "node_modules/@ethereumjs/blockchain": {
"version": "5.4.0", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/blockchain/-/blockchain-5.4.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/blockchain/-/blockchain-5.3.1.tgz",
"integrity": "sha512-wAuKLaew6PL52kH8YPXO7PbjjKV12jivRSyHQehkESw4slSLLfYA6Jv7n5YxyT2ajD7KNMPVh7oyF/MU6HcOvg==", "integrity": "sha512-Sr39BoTOzmVSnuYzjiCIpgcBUFE5JWcMF0lYCvzrtx/5Lg1tnpZhw9yMQ6JfIomN421epg4oDz99DWlL9Aqz3g==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.3.0",
"@ethereumjs/common": "^2.4.0", "@ethereumjs/common": "^2.3.1",
"@ethereumjs/ethash": "^1.0.0", "@ethereumjs/ethash": "^1.0.0",
"debug": "^2.2.0", "debug": "^2.2.0",
"ethereumjs-util": "^7.1.0", "ethereumjs-util": "^7.0.10",
"level-mem": "^5.0.1", "level-mem": "^5.0.1",
"lru-cache": "^5.1.1", "lru-cache": "^5.1.1",
"rlp": "^2.2.4", "rlp": "^2.2.4",
...@@ -276,13 +276,13 @@ ...@@ -276,13 +276,13 @@
"dev": true "dev": true
}, },
"node_modules/@ethereumjs/common": { "node_modules/@ethereumjs/common": {
"version": "2.4.0", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.4.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.3.1.tgz",
"integrity": "sha512-UdkhFWzWcJCZVsj1O/H8/oqj/0RVYjLc1OhPjBrQdALAkQHpCp8xXI4WLnuGTADqTdJZww0NtgwG+TRPkXt27w==", "integrity": "sha512-V8hrULExoq0H4HFs3cCmdRGbgmipmlNzak6Xg34nHYfQyqkSdrCuflvYjyWmsNpI8GtrcZhzifAbgX/1C1Cjwg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"crc-32": "^1.2.0", "crc-32": "^1.2.0",
"ethereumjs-util": "^7.1.0" "ethereumjs-util": "^7.0.10"
} }
}, },
"node_modules/@ethereumjs/ethash": { "node_modules/@ethereumjs/ethash": {
...@@ -307,29 +307,29 @@ ...@@ -307,29 +307,29 @@
} }
}, },
"node_modules/@ethereumjs/tx": { "node_modules/@ethereumjs/tx": {
"version": "3.3.0", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.2.1.tgz",
"integrity": "sha512-yTwEj2lVzSMgE6Hjw9Oa1DZks/nKTWM8Wn4ykDNapBPua2f4nXO3qKnni86O6lgDj5fVNRqbDsD0yy7/XNGDEA==", "integrity": "sha512-i9V39OtKvwWos1uVNZxdVhd7zFOyzFLjgt69CoiOY0EmXugS0HjO3uxpLBSglDKFMRriuGqw6ddKEv+RP1UNEw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@ethereumjs/common": "^2.4.0", "@ethereumjs/common": "^2.3.1",
"ethereumjs-util": "^7.1.0" "ethereumjs-util": "^7.0.10"
} }
}, },
"node_modules/@ethereumjs/vm": { "node_modules/@ethereumjs/vm": {
"version": "5.5.0", "version": "5.4.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/vm/-/vm-5.5.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/vm/-/vm-5.4.1.tgz",
"integrity": "sha512-h6Kr6WqKUP8nVuEzCWPWEPrC63v7HFwt3gRuK7CJiyg9S0iWSBKUA/YVD4YgaSVACuxUfWaOBbwV5uGVupm5PQ==", "integrity": "sha512-cpQcg5CtjzXJBn8QNiobaiWckeN/ZQwsDHLYa9df2wBEUvzuEZgFWK48YEXSpx3CnUY9fNT/lgA9CzKdq8HTzQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.3.0",
"@ethereumjs/blockchain": "^5.4.0", "@ethereumjs/blockchain": "^5.3.0",
"@ethereumjs/common": "^2.4.0", "@ethereumjs/common": "^2.3.1",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.2.1",
"async-eventemitter": "^0.2.4", "async-eventemitter": "^0.2.4",
"core-js-pure": "^3.0.1", "core-js-pure": "^3.0.1",
"debug": "^2.2.0", "debug": "^2.2.0",
"ethereumjs-util": "^7.1.0", "ethereumjs-util": "^7.0.10",
"functional-red-black-tree": "^1.0.1", "functional-red-black-tree": "^1.0.1",
"mcl-wasm": "^0.7.1", "mcl-wasm": "^0.7.1",
"merkle-patricia-tree": "^4.2.0", "merkle-patricia-tree": "^4.2.0",
...@@ -1123,9 +1123,9 @@ ...@@ -1123,9 +1123,9 @@
} }
}, },
"node_modules/@nodelib/fs.walk": { "node_modules/@nodelib/fs.walk": {
"version": "1.2.8", "version": "1.2.7",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@nodelib/fs.scandir": "2.1.5", "@nodelib/fs.scandir": "2.1.5",
...@@ -1317,9 +1317,9 @@ ...@@ -1317,9 +1317,9 @@
} }
}, },
"node_modules/@oclif/errors": { "node_modules/@oclif/errors": {
"version": "1.3.5", "version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oclif/errors/-/errors-1.3.5.tgz", "resolved": "https://registry.npmjs.org/@oclif/errors/-/errors-1.3.4.tgz",
"integrity": "sha512-OivucXPH/eLLlOT7FkCMoZXiaVYf8I/w1eTAM1+gKzfhALwWTusxEx7wBmW0uzvkSg/9ovWLycPaBgJbM3LOCQ==", "integrity": "sha512-pJKXyEqwdfRTUdM8n5FIHiQQHg5ETM0Wlso8bF9GodczO40mF5Z3HufnYWJE7z8sGKxOeJCdbAVZbS8Y+d5GCw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"clean-stack": "^3.0.0", "clean-stack": "^3.0.0",
...@@ -1798,9 +1798,9 @@ ...@@ -1798,9 +1798,9 @@
} }
}, },
"node_modules/@openzeppelin/test-helpers": { "node_modules/@openzeppelin/test-helpers": {
"version": "0.5.12", "version": "0.5.11",
"resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.12.tgz", "resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.11.tgz",
"integrity": "sha512-ZPhLmMb8PLGImYLen7YsPnni22i1bXHzrSiY7XZ7cgwuKvk4MRBunzfZ4xGTn/p+1V2/a1XHsjMRDKn7AMVb3Q==", "integrity": "sha512-HkFpCjtTD8dk+wdYhsT07YbMGCE+Z4Wp5sBKXvPDF3Lynoc0H2KqZgCWV+qr2YZ0WW1oX/sXkKFrrKJ0caBTjw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@openzeppelin/contract-loader": "^0.6.2", "@openzeppelin/contract-loader": "^0.6.2",
...@@ -2028,15 +2028,15 @@ ...@@ -2028,15 +2028,15 @@
} }
}, },
"node_modules/@truffle/contract": { "node_modules/@truffle/contract": {
"version": "4.3.24", "version": "4.3.23",
"resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.3.24.tgz", "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.3.23.tgz",
"integrity": "sha512-cKijyDzJLRu96KWb/g7soHJkBXgY1HkmCeVhUun9iUJpA93w7StInCP+SPs0gd8Oj7GfcoYcCcnA38l/zJBEsQ==", "integrity": "sha512-YqoFmy6bFMcFnbC1OXNBF1MrhNGYf1JEvY65EsbNe3cjkgbFfk0wVwuDkSYqXBIyWAOQBkPL+GTq4ouvnjVlnw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@ensdomains/ensjs": "^2.0.1", "@ensdomains/ensjs": "^2.0.1",
"@truffle/blockchain-utils": "^0.0.31", "@truffle/blockchain-utils": "^0.0.31",
"@truffle/contract-schema": "^3.4.1", "@truffle/contract-schema": "^3.4.1",
"@truffle/debug-utils": "^5.1.4", "@truffle/debug-utils": "^5.1.3",
"@truffle/error": "^0.0.14", "@truffle/error": "^0.0.14",
"@truffle/interface-adapter": "^0.5.2", "@truffle/interface-adapter": "^0.5.2",
"bignumber.js": "^7.2.1", "bignumber.js": "^7.2.1",
...@@ -2066,9 +2066,9 @@ ...@@ -2066,9 +2066,9 @@
"dev": true "dev": true
}, },
"node_modules/@truffle/contract/node_modules/@truffle/codec": { "node_modules/@truffle/contract/node_modules/@truffle/codec": {
"version": "0.11.4", "version": "0.11.3",
"resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.11.4.tgz", "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.11.3.tgz",
"integrity": "sha512-NK/ah1aWQFhYYv8kVL382wB+JgSOnWWDdoeGOOMnA3iviRnV7k0JJV+C6uTmaLKOTNGTBNp4hlISLFeKKNnbXA==", "integrity": "sha512-LBunwP2ZQ0CygcbuLGsQS8Zm4+2kpVKBkvA/DOiCI4IaNxMie3LMFCBFEVrHUey2a07J4wn7WivrRY3dUdS9zQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"big.js": "^5.2.2", "big.js": "^5.2.2",
...@@ -2085,12 +2085,12 @@ ...@@ -2085,12 +2085,12 @@
} }
}, },
"node_modules/@truffle/contract/node_modules/@truffle/debug-utils": { "node_modules/@truffle/contract/node_modules/@truffle/debug-utils": {
"version": "5.1.4", "version": "5.1.3",
"resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-5.1.4.tgz", "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-5.1.3.tgz",
"integrity": "sha512-0LdtJzhOuAgEIP4xj3QsB7CKIzoAgRERKx5hYktId9pfm//9leo3luwN0aY8f919rWJynmnaXvE0lQZD3Pcu0Q==", "integrity": "sha512-++IPNmxBH/uwaVqZ+hokEDavN9r0TayU2o0/geHoBCwcC0eW5xr9zbciFxsgKQCCuBESi23eOflNuQUK1Awa5w==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@truffle/codec": "^0.11.4", "@truffle/codec": "^0.11.3",
"@trufflesuite/chromafi": "^2.2.2", "@trufflesuite/chromafi": "^2.2.2",
"bn.js": "^5.1.3", "bn.js": "^5.1.3",
"chalk": "^2.4.2", "chalk": "^2.4.2",
...@@ -2441,9 +2441,9 @@ ...@@ -2441,9 +2441,9 @@
} }
}, },
"node_modules/@types/abstract-leveldown": { "node_modules/@types/abstract-leveldown": {
"version": "5.0.2", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-5.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-5.0.1.tgz",
"integrity": "sha512-+jA1XXF3jsz+Z7FcuiNqgK53hTa/luglT2TyTpKPqoYbxVY+mCPF22Rm+q3KPBrMHJwNXFrTViHszBOfU4vftQ==", "integrity": "sha512-wYxU3kp5zItbxKmeRYCEplS2MW7DzyBnxPGj+GJVHZEUZiK/nn5Ei1sUFgURDh+X051+zsGe28iud3oHjrYWQQ==",
"dev": true "dev": true
}, },
"node_modules/@types/bignumber.js": { "node_modules/@types/bignumber.js": {
...@@ -2466,15 +2466,15 @@ ...@@ -2466,15 +2466,15 @@
} }
}, },
"node_modules/@types/chai": { "node_modules/@types/chai": {
"version": "4.2.21", "version": "4.2.19",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.21.tgz", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.19.tgz",
"integrity": "sha512-yd+9qKmJxm496BOV9CMNaey8TWsikaZOwMRwPHQIjcOJM9oV+fi9ZMNw3JsVnbEEbo2gRTDnGEBv8pjyn67hNg==", "integrity": "sha512-jRJgpRBuY+7izT7/WNXP/LsMO9YonsstuL+xuvycDyESpoDoIAsMd7suwpB4h9oEWB+ZlPTqJJ8EHomzNhwTPQ==",
"dev": true "dev": true
}, },
"node_modules/@types/concat-stream": { "node_modules/@types/concat-stream": {
"version": "1.6.1", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz",
"integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", "integrity": "sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0=",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
...@@ -2490,15 +2490,21 @@ ...@@ -2490,15 +2490,21 @@
} }
}, },
"node_modules/@types/glob": { "node_modules/@types/glob": {
"version": "7.1.4", "version": "7.1.3",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/minimatch": "*", "@types/minimatch": "*",
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
"dev": true
},
"node_modules/@types/level-errors": { "node_modules/@types/level-errors": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/level-errors/-/level-errors-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/level-errors/-/level-errors-3.0.0.tgz",
...@@ -2506,9 +2512,9 @@ ...@@ -2506,9 +2512,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/levelup": { "node_modules/@types/levelup": {
"version": "4.3.3", "version": "4.3.2",
"resolved": "https://registry.npmjs.org/@types/levelup/-/levelup-4.3.3.tgz", "resolved": "https://registry.npmjs.org/@types/levelup/-/levelup-4.3.2.tgz",
"integrity": "sha512-K+OTIjJcZHVlZQN1HmU64VtrC0jC3dXWQozuEIR9zVvltIk90zaGPM2AgT+fIkChpzHhFE3YnvFLCbLtzAmexA==", "integrity": "sha512-5Su1Dkl6nMjkXqUb2z72gbroG0WFLs+6nMH+wQt4GWIrDwR/IconLTojHtC0klLJODCJ64Cr6P5cWqVeuxAbSg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/abstract-leveldown": "*", "@types/abstract-leveldown": "*",
...@@ -2517,21 +2523,21 @@ ...@@ -2517,21 +2523,21 @@
} }
}, },
"node_modules/@types/lru-cache": { "node_modules/@types/lru-cache": {
"version": "5.1.1", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.0.tgz",
"integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", "integrity": "sha512-RaE0B+14ToE4l6UqdarKPnXwVDuigfFv+5j9Dze/Nqr23yyuqdNvzcZi3xB+3Agvi5R4EOgAksfv3lXX4vBt9w==",
"dev": true "dev": true
}, },
"node_modules/@types/minimatch": { "node_modules/@types/minimatch": {
"version": "3.0.5", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==",
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "12.20.16", "version": "12.20.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.16.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.15.tgz",
"integrity": "sha512-6CLxw83vQf6DKqXxMPwl8qpF8I7THFZuIwLt4TnNsumxkp1VsRZWT8txQxncT/Rl2UojTsFzWgDG4FRMwafrlA==", "integrity": "sha512-F6S4Chv4JicJmyrwlDkxUdGNSplsQdGwp1A0AJloEVDirWdZOAiRHhovDlsFkKUrquUXhz1imJhXHsf59auyAg==",
"dev": true "dev": true
}, },
"node_modules/@types/pbkdf2": { "node_modules/@types/pbkdf2": {
...@@ -2544,15 +2550,15 @@ ...@@ -2544,15 +2550,15 @@
} }
}, },
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.7", "version": "6.9.6",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz",
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==",
"dev": true "dev": true
}, },
"node_modules/@types/secp256k1": { "node_modules/@types/secp256k1": {
"version": "4.0.3", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.2.tgz",
"integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", "integrity": "sha512-QMg+9v0bbNJ2peLuHRWxzmy0HRJIG6gFZNhaRSp7S3ggSbCCxiqQB2/ybvhXyhHOCequpNkrx7OavNhrWOsW0A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
...@@ -2639,9 +2645,9 @@ ...@@ -2639,9 +2645,9 @@
} }
}, },
"node_modules/acorn-jsx": { "node_modules/acorn-jsx": {
"version": "5.3.2", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
"dev": true, "dev": true,
"peerDependencies": { "peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
...@@ -6245,9 +6251,9 @@ ...@@ -6245,9 +6251,9 @@
} }
}, },
"node_modules/ethereumjs-util": { "node_modules/ethereumjs-util": {
"version": "7.1.0", "version": "7.0.10",
"resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.0.tgz", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.0.10.tgz",
"integrity": "sha512-kR+vhu++mUDARrsMMhsjjzPduRVAeundLGXucGRHF3B4oEltOUspfgCVco4kckucj3FMlLaZHUl9n7/kdmr6Tw==", "integrity": "sha512-c/xThw6A+EAnej5Xk5kOzFzyoSnw0WX0tSlZ6pAsfGVvQj3TItaDg9b1+Fz1RJXA+y2YksKwQnuzgt1eY6LKzw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/bn.js": "^5.1.0", "@types/bn.js": "^5.1.0",
...@@ -6800,9 +6806,9 @@ ...@@ -6800,9 +6806,9 @@
"dev": true "dev": true
}, },
"node_modules/fast-glob": { "node_modules/fast-glob": {
"version": "3.2.7", "version": "3.2.6",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz",
"integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.stat": "^2.0.2",
...@@ -7200,7 +7206,6 @@ ...@@ -7200,7 +7206,6 @@
"integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
} }
...@@ -7209,15 +7214,13 @@ ...@@ -7209,15 +7214,13 @@
"version": "14.11.2", "version": "14.11.2",
"integrity": "sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==", "integrity": "sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/@types/pbkdf2": { "node_modules/ganache-cli/node_modules/@types/pbkdf2": {
"version": "3.1.0", "version": "3.1.0",
"integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
} }
...@@ -7227,7 +7230,6 @@ ...@@ -7227,7 +7230,6 @@
"integrity": "sha512-+ZjSA8ELlOp8SlKi0YLB2tz9d5iPNEmOBd+8Rz21wTMdaXQIa9b6TEnD6l5qKOCypE7FSyPyck12qZJxSDNoog==", "integrity": "sha512-+ZjSA8ELlOp8SlKi0YLB2tz9d5iPNEmOBd+8Rz21wTMdaXQIa9b6TEnD6l5qKOCypE7FSyPyck12qZJxSDNoog==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
} }
...@@ -7237,7 +7239,6 @@ ...@@ -7237,7 +7239,6 @@
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
...@@ -7247,7 +7248,6 @@ ...@@ -7247,7 +7248,6 @@
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"color-convert": "^1.9.0" "color-convert": "^1.9.0"
}, },
...@@ -7260,7 +7260,6 @@ ...@@ -7260,7 +7260,6 @@
"integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
...@@ -7269,29 +7268,25 @@ ...@@ -7269,29 +7268,25 @@
"version": "1.1.0", "version": "1.1.0",
"integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=", "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "CC0-1.0"
}, },
"node_modules/ganache-cli/node_modules/bn.js": { "node_modules/ganache-cli/node_modules/bn.js": {
"version": "4.11.9", "version": "4.11.9",
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/brorand": { "node_modules/ganache-cli/node_modules/brorand": {
"version": "1.1.0", "version": "1.1.0",
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/browserify-aes": { "node_modules/ganache-cli/node_modules/browserify-aes": {
"version": "1.2.0", "version": "1.2.0",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"buffer-xor": "^1.0.3", "buffer-xor": "^1.0.3",
"cipher-base": "^1.0.0", "cipher-base": "^1.0.0",
...@@ -7306,7 +7301,6 @@ ...@@ -7306,7 +7301,6 @@
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"base-x": "^3.0.2" "base-x": "^3.0.2"
} }
...@@ -7316,7 +7310,6 @@ ...@@ -7316,7 +7310,6 @@
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"bs58": "^4.0.0", "bs58": "^4.0.0",
"create-hash": "^1.1.0", "create-hash": "^1.1.0",
...@@ -7327,22 +7320,19 @@ ...@@ -7327,22 +7320,19 @@
"version": "1.1.1", "version": "1.1.1",
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/buffer-xor": { "node_modules/ganache-cli/node_modules/buffer-xor": {
"version": "1.0.3", "version": "1.0.3",
"integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/camelcase": { "node_modules/ganache-cli/node_modules/camelcase": {
"version": "5.3.1", "version": "5.3.1",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
...@@ -7352,7 +7342,6 @@ ...@@ -7352,7 +7342,6 @@
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"inherits": "^2.0.1", "inherits": "^2.0.1",
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
...@@ -7363,7 +7352,6 @@ ...@@ -7363,7 +7352,6 @@
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC",
"dependencies": { "dependencies": {
"string-width": "^3.1.0", "string-width": "^3.1.0",
"strip-ansi": "^5.2.0", "strip-ansi": "^5.2.0",
...@@ -7375,7 +7363,6 @@ ...@@ -7375,7 +7363,6 @@
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"color-name": "1.1.3" "color-name": "1.1.3"
} }
...@@ -7384,15 +7371,13 @@ ...@@ -7384,15 +7371,13 @@
"version": "1.1.3", "version": "1.1.3",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/create-hash": { "node_modules/ganache-cli/node_modules/create-hash": {
"version": "1.2.0", "version": "1.2.0",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"cipher-base": "^1.0.1", "cipher-base": "^1.0.1",
"inherits": "^2.0.1", "inherits": "^2.0.1",
...@@ -7406,7 +7391,6 @@ ...@@ -7406,7 +7391,6 @@
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"cipher-base": "^1.0.3", "cipher-base": "^1.0.3",
"create-hash": "^1.1.0", "create-hash": "^1.1.0",
...@@ -7421,7 +7405,6 @@ ...@@ -7421,7 +7405,6 @@
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"nice-try": "^1.0.4", "nice-try": "^1.0.4",
"path-key": "^2.0.1", "path-key": "^2.0.1",
...@@ -7438,7 +7421,6 @@ ...@@ -7438,7 +7421,6 @@
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
...@@ -7448,7 +7430,6 @@ ...@@ -7448,7 +7430,6 @@
"integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"bn.js": "^4.4.0", "bn.js": "^4.4.0",
"brorand": "^1.0.1", "brorand": "^1.0.1",
...@@ -7463,15 +7444,13 @@ ...@@ -7463,15 +7444,13 @@
"version": "7.0.3", "version": "7.0.3",
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/end-of-stream": { "node_modules/ganache-cli/node_modules/end-of-stream": {
"version": "1.4.4", "version": "1.4.4",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"once": "^1.4.0" "once": "^1.4.0"
} }
...@@ -7481,7 +7460,6 @@ ...@@ -7481,7 +7460,6 @@
"integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"@types/pbkdf2": "^3.0.0", "@types/pbkdf2": "^3.0.0",
"@types/secp256k1": "^4.0.1", "@types/secp256k1": "^4.0.1",
...@@ -7505,7 +7483,6 @@ ...@@ -7505,7 +7483,6 @@
"integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MPL-2.0",
"dependencies": { "dependencies": {
"@types/bn.js": "^4.11.3", "@types/bn.js": "^4.11.3",
"bn.js": "^4.11.0", "bn.js": "^4.11.0",
...@@ -7521,7 +7498,6 @@ ...@@ -7521,7 +7498,6 @@
"integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"is-hex-prefixed": "1.0.0", "is-hex-prefixed": "1.0.0",
"strip-hex-prefix": "1.0.0" "strip-hex-prefix": "1.0.0"
...@@ -7536,7 +7512,6 @@ ...@@ -7536,7 +7512,6 @@
"integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"md5.js": "^1.3.4", "md5.js": "^1.3.4",
"safe-buffer": "^5.1.1" "safe-buffer": "^5.1.1"
...@@ -7547,7 +7522,6 @@ ...@@ -7547,7 +7522,6 @@
"integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"cross-spawn": "^6.0.0", "cross-spawn": "^6.0.0",
"get-stream": "^4.0.0", "get-stream": "^4.0.0",
...@@ -7566,7 +7540,6 @@ ...@@ -7566,7 +7540,6 @@
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"locate-path": "^3.0.0" "locate-path": "^3.0.0"
}, },
...@@ -7579,7 +7552,6 @@ ...@@ -7579,7 +7552,6 @@
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC",
"engines": { "engines": {
"node": "6.* || 8.* || >= 10.*" "node": "6.* || 8.* || >= 10.*"
} }
...@@ -7589,7 +7561,6 @@ ...@@ -7589,7 +7561,6 @@
"integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"pump": "^3.0.0" "pump": "^3.0.0"
}, },
...@@ -7602,7 +7573,6 @@ ...@@ -7602,7 +7573,6 @@
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"inherits": "^2.0.4", "inherits": "^2.0.4",
"readable-stream": "^3.6.0", "readable-stream": "^3.6.0",
...@@ -7617,7 +7587,6 @@ ...@@ -7617,7 +7587,6 @@
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
"minimalistic-assert": "^1.0.1" "minimalistic-assert": "^1.0.1"
...@@ -7628,7 +7597,6 @@ ...@@ -7628,7 +7597,6 @@
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"hash.js": "^1.0.3", "hash.js": "^1.0.3",
"minimalistic-assert": "^1.0.0", "minimalistic-assert": "^1.0.0",
...@@ -7639,15 +7607,13 @@ ...@@ -7639,15 +7607,13 @@
"version": "2.0.4", "version": "2.0.4",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "ISC"
}, },
"node_modules/ganache-cli/node_modules/invert-kv": { "node_modules/ganache-cli/node_modules/invert-kv": {
"version": "2.0.0", "version": "2.0.0",
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
...@@ -7657,7 +7623,6 @@ ...@@ -7657,7 +7623,6 @@
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
...@@ -7667,7 +7632,6 @@ ...@@ -7667,7 +7632,6 @@
"integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=", "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6.5.0", "node": ">=6.5.0",
"npm": ">=3" "npm": ">=3"
...@@ -7678,7 +7642,6 @@ ...@@ -7678,7 +7642,6 @@
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
...@@ -7687,8 +7650,7 @@ ...@@ -7687,8 +7650,7 @@
"version": "2.0.0", "version": "2.0.0",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "ISC"
}, },
"node_modules/ganache-cli/node_modules/keccak": { "node_modules/ganache-cli/node_modules/keccak": {
"version": "3.0.1", "version": "3.0.1",
...@@ -7696,7 +7658,6 @@ ...@@ -7696,7 +7658,6 @@
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"node-addon-api": "^2.0.0", "node-addon-api": "^2.0.0",
"node-gyp-build": "^4.2.0" "node-gyp-build": "^4.2.0"
...@@ -7710,7 +7671,6 @@ ...@@ -7710,7 +7671,6 @@
"integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"invert-kv": "^2.0.0" "invert-kv": "^2.0.0"
}, },
...@@ -7723,7 +7683,6 @@ ...@@ -7723,7 +7683,6 @@
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"p-locate": "^3.0.0", "p-locate": "^3.0.0",
"path-exists": "^3.0.0" "path-exists": "^3.0.0"
...@@ -7737,7 +7696,6 @@ ...@@ -7737,7 +7696,6 @@
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"p-defer": "^1.0.0" "p-defer": "^1.0.0"
}, },
...@@ -7750,7 +7708,6 @@ ...@@ -7750,7 +7708,6 @@
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"hash-base": "^3.0.0", "hash-base": "^3.0.0",
"inherits": "^2.0.1", "inherits": "^2.0.1",
...@@ -7762,7 +7719,6 @@ ...@@ -7762,7 +7719,6 @@
"integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"map-age-cleaner": "^0.1.1", "map-age-cleaner": "^0.1.1",
"mimic-fn": "^2.0.0", "mimic-fn": "^2.0.0",
...@@ -7777,7 +7733,6 @@ ...@@ -7777,7 +7733,6 @@
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
...@@ -7786,36 +7741,31 @@ ...@@ -7786,36 +7741,31 @@
"version": "1.0.1", "version": "1.0.1",
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "ISC"
}, },
"node_modules/ganache-cli/node_modules/minimalistic-crypto-utils": { "node_modules/ganache-cli/node_modules/minimalistic-crypto-utils": {
"version": "1.0.1", "version": "1.0.1",
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/nice-try": { "node_modules/ganache-cli/node_modules/nice-try": {
"version": "1.0.5", "version": "1.0.5",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/node-addon-api": { "node_modules/ganache-cli/node_modules/node-addon-api": {
"version": "2.0.2", "version": "2.0.2",
"integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/node-gyp-build": { "node_modules/ganache-cli/node_modules/node-gyp-build": {
"version": "4.2.3", "version": "4.2.3",
"integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==", "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"bin": { "bin": {
"node-gyp-build": "bin.js", "node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js", "node-gyp-build-optional": "optional.js",
...@@ -7827,7 +7777,6 @@ ...@@ -7827,7 +7777,6 @@
"integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"path-key": "^2.0.0" "path-key": "^2.0.0"
}, },
...@@ -7840,7 +7789,6 @@ ...@@ -7840,7 +7789,6 @@
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC",
"dependencies": { "dependencies": {
"wrappy": "1" "wrappy": "1"
} }
...@@ -7850,7 +7798,6 @@ ...@@ -7850,7 +7798,6 @@
"integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"execa": "^1.0.0", "execa": "^1.0.0",
"lcid": "^2.0.0", "lcid": "^2.0.0",
...@@ -7865,7 +7812,6 @@ ...@@ -7865,7 +7812,6 @@
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
...@@ -7875,7 +7821,6 @@ ...@@ -7875,7 +7821,6 @@
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
...@@ -7885,7 +7830,6 @@ ...@@ -7885,7 +7830,6 @@
"integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
...@@ -7895,7 +7839,6 @@ ...@@ -7895,7 +7839,6 @@
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"p-try": "^2.0.0" "p-try": "^2.0.0"
}, },
...@@ -7911,7 +7854,6 @@ ...@@ -7911,7 +7854,6 @@
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"p-limit": "^2.0.0" "p-limit": "^2.0.0"
}, },
...@@ -7924,7 +7866,6 @@ ...@@ -7924,7 +7866,6 @@
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
...@@ -7934,7 +7875,6 @@ ...@@ -7934,7 +7875,6 @@
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
...@@ -7944,7 +7884,6 @@ ...@@ -7944,7 +7884,6 @@
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
...@@ -7954,7 +7893,6 @@ ...@@ -7954,7 +7893,6 @@
"integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"create-hash": "^1.1.2", "create-hash": "^1.1.2",
"create-hmac": "^1.1.4", "create-hmac": "^1.1.4",
...@@ -7971,7 +7909,6 @@ ...@@ -7971,7 +7909,6 @@
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"end-of-stream": "^1.1.0", "end-of-stream": "^1.1.0",
"once": "^1.3.1" "once": "^1.3.1"
...@@ -7982,7 +7919,6 @@ ...@@ -7982,7 +7919,6 @@
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"safe-buffer": "^5.1.0" "safe-buffer": "^5.1.0"
} }
...@@ -7992,7 +7928,6 @@ ...@@ -7992,7 +7928,6 @@
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"inherits": "^2.0.3", "inherits": "^2.0.3",
"string_decoder": "^1.1.1", "string_decoder": "^1.1.1",
...@@ -8007,7 +7942,6 @@ ...@@ -8007,7 +7942,6 @@
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
...@@ -8016,15 +7950,13 @@ ...@@ -8016,15 +7950,13 @@
"version": "2.0.0", "version": "2.0.0",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "ISC"
}, },
"node_modules/ganache-cli/node_modules/ripemd160": { "node_modules/ganache-cli/node_modules/ripemd160": {
"version": "2.0.2", "version": "2.0.2",
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"hash-base": "^3.0.0", "hash-base": "^3.0.0",
"inherits": "^2.0.1" "inherits": "^2.0.1"
...@@ -8035,7 +7967,6 @@ ...@@ -8035,7 +7967,6 @@
"integrity": "sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg==", "integrity": "sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MPL-2.0",
"dependencies": { "dependencies": {
"bn.js": "^4.11.1" "bn.js": "^4.11.1"
}, },
...@@ -8061,15 +7992,13 @@ ...@@ -8061,15 +7992,13 @@
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
], ],
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/scrypt-js": { "node_modules/ganache-cli/node_modules/scrypt-js": {
"version": "3.0.1", "version": "3.0.1",
"integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/secp256k1": { "node_modules/ganache-cli/node_modules/secp256k1": {
"version": "4.0.2", "version": "4.0.2",
...@@ -8077,7 +8006,6 @@ ...@@ -8077,7 +8006,6 @@
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"elliptic": "^6.5.2", "elliptic": "^6.5.2",
"node-addon-api": "^2.0.0", "node-addon-api": "^2.0.0",
...@@ -8092,7 +8020,6 @@ ...@@ -8092,7 +8020,6 @@
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC",
"bin": { "bin": {
"semver": "bin/semver" "semver": "bin/semver"
} }
...@@ -8101,22 +8028,19 @@ ...@@ -8101,22 +8028,19 @@
"version": "2.0.0", "version": "2.0.0",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "ISC"
}, },
"node_modules/ganache-cli/node_modules/setimmediate": { "node_modules/ganache-cli/node_modules/setimmediate": {
"version": "1.0.5", "version": "1.0.5",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/sha.js": { "node_modules/ganache-cli/node_modules/sha.js": {
"version": "2.4.11", "version": "2.4.11",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "(MIT AND BSD-3-Clause)",
"dependencies": { "dependencies": {
"inherits": "^2.0.1", "inherits": "^2.0.1",
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
...@@ -8130,7 +8054,6 @@ ...@@ -8130,7 +8054,6 @@
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"shebang-regex": "^1.0.0" "shebang-regex": "^1.0.0"
}, },
...@@ -8143,7 +8066,6 @@ ...@@ -8143,7 +8066,6 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
...@@ -8152,15 +8074,13 @@ ...@@ -8152,15 +8074,13 @@
"version": "3.0.3", "version": "3.0.3",
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "ISC"
}, },
"node_modules/ganache-cli/node_modules/source-map": { "node_modules/ganache-cli/node_modules/source-map": {
"version": "0.6.1", "version": "0.6.1",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "BSD-3-Clause",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
...@@ -8170,7 +8090,6 @@ ...@@ -8170,7 +8090,6 @@
"integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"buffer-from": "^1.0.0", "buffer-from": "^1.0.0",
"source-map": "^0.6.0" "source-map": "^0.6.0"
...@@ -8181,7 +8100,6 @@ ...@@ -8181,7 +8100,6 @@
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"safe-buffer": "~5.2.0" "safe-buffer": "~5.2.0"
} }
...@@ -8191,7 +8109,6 @@ ...@@ -8191,7 +8109,6 @@
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"emoji-regex": "^7.0.1", "emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0", "is-fullwidth-code-point": "^2.0.0",
...@@ -8206,7 +8123,6 @@ ...@@ -8206,7 +8123,6 @@
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ansi-regex": "^4.1.0" "ansi-regex": "^4.1.0"
}, },
...@@ -8219,7 +8135,6 @@ ...@@ -8219,7 +8135,6 @@
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
...@@ -8229,7 +8144,6 @@ ...@@ -8229,7 +8144,6 @@
"integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"is-hex-prefixed": "1.0.0" "is-hex-prefixed": "1.0.0"
}, },
...@@ -8242,15 +8156,13 @@ ...@@ -8242,15 +8156,13 @@
"version": "1.0.2", "version": "1.0.2",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "MIT"
}, },
"node_modules/ganache-cli/node_modules/which": { "node_modules/ganache-cli/node_modules/which": {
"version": "1.3.1", "version": "1.3.1",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC",
"dependencies": { "dependencies": {
"isexe": "^2.0.0" "isexe": "^2.0.0"
}, },
...@@ -8262,15 +8174,13 @@ ...@@ -8262,15 +8174,13 @@
"version": "2.0.0", "version": "2.0.0",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "ISC"
}, },
"node_modules/ganache-cli/node_modules/wrap-ansi": { "node_modules/ganache-cli/node_modules/wrap-ansi": {
"version": "5.1.0", "version": "5.1.0",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"ansi-styles": "^3.2.0", "ansi-styles": "^3.2.0",
"string-width": "^3.0.0", "string-width": "^3.0.0",
...@@ -8284,22 +8194,19 @@ ...@@ -8284,22 +8194,19 @@
"version": "1.0.2", "version": "1.0.2",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "ISC"
}, },
"node_modules/ganache-cli/node_modules/y18n": { "node_modules/ganache-cli/node_modules/y18n": {
"version": "4.0.0", "version": "4.0.0",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true
"license": "ISC"
}, },
"node_modules/ganache-cli/node_modules/yargs": { "node_modules/ganache-cli/node_modules/yargs": {
"version": "13.2.4", "version": "13.2.4",
"integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "MIT",
"dependencies": { "dependencies": {
"cliui": "^5.0.0", "cliui": "^5.0.0",
"find-up": "^3.0.0", "find-up": "^3.0.0",
...@@ -8319,7 +8226,6 @@ ...@@ -8319,7 +8226,6 @@
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"dev": true, "dev": true,
"inBundle": true, "inBundle": true,
"license": "ISC",
"dependencies": { "dependencies": {
"camelcase": "^5.0.0", "camelcase": "^5.0.0",
"decamelize": "^1.2.0" "decamelize": "^1.2.0"
...@@ -8627,16 +8533,16 @@ ...@@ -8627,16 +8533,16 @@
} }
}, },
"node_modules/hardhat": { "node_modules/hardhat": {
"version": "2.4.3", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.4.3.tgz", "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.4.1.tgz",
"integrity": "sha512-xgbnhEnmaKau8xT6wPJlzoyMLAZyxQoElACQQCyEeAY1DURpZbYwjIQUywmL/ZNv3QEl38Yqu/n8mPOc2HXyGA==", "integrity": "sha512-vwllrFypukeE/Q+4ZfWj7j7nUo4ncUhRpsAYUM0Ruuuk6pQlKmRa0A6c0kxRSvvVgQsMud6j+/weYhbMX1wPmQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.3.0",
"@ethereumjs/blockchain": "^5.4.0", "@ethereumjs/blockchain": "^5.3.0",
"@ethereumjs/common": "^2.4.0", "@ethereumjs/common": "^2.3.1",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.2.1",
"@ethereumjs/vm": "^5.5.0", "@ethereumjs/vm": "^5.3.2",
"@ethersproject/abi": "^5.1.2", "@ethersproject/abi": "^5.1.2",
"@sentry/node": "^5.18.1", "@sentry/node": "^5.18.1",
"@solidity-parser/parser": "^0.11.0", "@solidity-parser/parser": "^0.11.0",
...@@ -8654,7 +8560,7 @@ ...@@ -8654,7 +8560,7 @@
"eth-sig-util": "^2.5.2", "eth-sig-util": "^2.5.2",
"ethereum-cryptography": "^0.1.2", "ethereum-cryptography": "^0.1.2",
"ethereumjs-abi": "^0.6.8", "ethereumjs-abi": "^0.6.8",
"ethereumjs-util": "^7.1.0", "ethereumjs-util": "^7.0.10",
"find-up": "^2.1.0", "find-up": "^2.1.0",
"fp-ts": "1.19.3", "fp-ts": "1.19.3",
"fs-extra": "^7.0.1", "fs-extra": "^7.0.1",
...@@ -8971,9 +8877,9 @@ ...@@ -8971,9 +8877,9 @@
} }
}, },
"node_modules/hardhat/node_modules/ws": { "node_modules/hardhat/node_modules/ws": {
"version": "7.5.3", "version": "7.5.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.2.tgz",
"integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", "integrity": "sha512-lkF7AWRicoB9mAgjeKbGqVUekLnSNO4VjKVnuPHpQeOxZOErX6BPXwJk70nFslRCEEA8EVW7ZjKwXaP9N+1sKQ==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=8.3.0" "node": ">=8.3.0"
...@@ -9401,9 +9307,9 @@ ...@@ -9401,9 +9307,9 @@
"dev": true "dev": true
}, },
"node_modules/immutable": { "node_modules/immutable": {
"version": "4.0.0-rc.14", "version": "4.0.0-rc.12",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.14.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.12.tgz",
"integrity": "sha512-pfkvmRKJSoW7JFx0QeYlAmT+kNYvn5j0u7bnpNq4N2RCvHSTlLT208G8jgaquNe+Q8kCPHKOSpxJkyvLDpYq0w==", "integrity": "sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A==",
"dev": true "dev": true
}, },
"node_modules/import-fresh": { "node_modules/import-fresh": {
...@@ -13086,9 +12992,9 @@ ...@@ -13086,9 +12992,9 @@
} }
}, },
"node_modules/prettier-plugin-solidity": { "node_modules/prettier-plugin-solidity": {
"version": "1.0.0-beta.15", "version": "1.0.0-beta.16",
"resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.15.tgz", "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.16.tgz",
"integrity": "sha512-5+pM/Z1BgQN6xMCe/AfXmiVhoteaVgruVoGT8aa0zJMRiNOiK+SeaW2kOyzTI6sgg3QsUW58+ahf1hxlc/Adbw==", "integrity": "sha512-xVBcnoWpe52dNnCCbqPHC9ZrTWXcNfldf852ZD0DBcHDqVMwjHTAPEdfBVy6FczbFpVa8bmxQil+G5XkEz5WHA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@solidity-parser/parser": "^0.13.2", "@solidity-parser/parser": "^0.13.2",
...@@ -16423,29 +16329,27 @@ ...@@ -16423,29 +16329,27 @@
"dev": true "dev": true
}, },
"node_modules/tsconfig-paths": { "node_modules/tsconfig-paths": {
"version": "3.10.1", "version": "3.9.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
"integrity": "sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==", "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"json5": "^2.2.0", "@types/json5": "^0.0.29",
"json5": "^1.0.1",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"strip-bom": "^3.0.0" "strip-bom": "^3.0.0"
} }
}, },
"node_modules/tsconfig-paths/node_modules/json5": { "node_modules/tsconfig-paths/node_modules/json5": {
"version": "2.2.0", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"minimist": "^1.2.5" "minimist": "^1.2.0"
}, },
"bin": { "bin": {
"json5": "lib/cli.js" "json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
} }
}, },
"node_modules/tslib": { "node_modules/tslib": {
...@@ -19488,28 +19392,28 @@ ...@@ -19488,28 +19392,28 @@
"dev": true "dev": true
}, },
"@ethereumjs/block": { "@ethereumjs/block": {
"version": "3.4.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/@ethereumjs/block/-/block-3.4.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/block/-/block-3.3.0.tgz",
"integrity": "sha512-umKAoTX32yXzErpIksPHodFc/5y8bmZMnOl6hWy5Vd8xId4+HKFUOyEiN16Y97zMwFRysRpcrR6wBejfqc6Bmg==", "integrity": "sha512-WoefY9Rs4W8vZTxG9qwntAlV61xsSv0NPoXmHO7x3SH16dwJQtU15YvahPCz4HEEXbu7GgGgNgu0pv8JY7VauA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@ethereumjs/common": "^2.4.0", "@ethereumjs/common": "^2.3.0",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.2.0",
"ethereumjs-util": "^7.1.0", "ethereumjs-util": "^7.0.10",
"merkle-patricia-tree": "^4.2.0" "merkle-patricia-tree": "^4.2.0"
} }
}, },
"@ethereumjs/blockchain": { "@ethereumjs/blockchain": {
"version": "5.4.0", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/blockchain/-/blockchain-5.4.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/blockchain/-/blockchain-5.3.1.tgz",
"integrity": "sha512-wAuKLaew6PL52kH8YPXO7PbjjKV12jivRSyHQehkESw4slSLLfYA6Jv7n5YxyT2ajD7KNMPVh7oyF/MU6HcOvg==", "integrity": "sha512-Sr39BoTOzmVSnuYzjiCIpgcBUFE5JWcMF0lYCvzrtx/5Lg1tnpZhw9yMQ6JfIomN421epg4oDz99DWlL9Aqz3g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.3.0",
"@ethereumjs/common": "^2.4.0", "@ethereumjs/common": "^2.3.1",
"@ethereumjs/ethash": "^1.0.0", "@ethereumjs/ethash": "^1.0.0",
"debug": "^2.2.0", "debug": "^2.2.0",
"ethereumjs-util": "^7.1.0", "ethereumjs-util": "^7.0.10",
"level-mem": "^5.0.1", "level-mem": "^5.0.1",
"lru-cache": "^5.1.1", "lru-cache": "^5.1.1",
"rlp": "^2.2.4", "rlp": "^2.2.4",
...@@ -19543,13 +19447,13 @@ ...@@ -19543,13 +19447,13 @@
} }
}, },
"@ethereumjs/common": { "@ethereumjs/common": {
"version": "2.4.0", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.4.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.3.1.tgz",
"integrity": "sha512-UdkhFWzWcJCZVsj1O/H8/oqj/0RVYjLc1OhPjBrQdALAkQHpCp8xXI4WLnuGTADqTdJZww0NtgwG+TRPkXt27w==", "integrity": "sha512-V8hrULExoq0H4HFs3cCmdRGbgmipmlNzak6Xg34nHYfQyqkSdrCuflvYjyWmsNpI8GtrcZhzifAbgX/1C1Cjwg==",
"dev": true, "dev": true,
"requires": { "requires": {
"crc-32": "^1.2.0", "crc-32": "^1.2.0",
"ethereumjs-util": "^7.1.0" "ethereumjs-util": "^7.0.10"
} }
}, },
"@ethereumjs/ethash": { "@ethereumjs/ethash": {
...@@ -19576,29 +19480,29 @@ ...@@ -19576,29 +19480,29 @@
} }
}, },
"@ethereumjs/tx": { "@ethereumjs/tx": {
"version": "3.3.0", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.2.1.tgz",
"integrity": "sha512-yTwEj2lVzSMgE6Hjw9Oa1DZks/nKTWM8Wn4ykDNapBPua2f4nXO3qKnni86O6lgDj5fVNRqbDsD0yy7/XNGDEA==", "integrity": "sha512-i9V39OtKvwWos1uVNZxdVhd7zFOyzFLjgt69CoiOY0EmXugS0HjO3uxpLBSglDKFMRriuGqw6ddKEv+RP1UNEw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@ethereumjs/common": "^2.4.0", "@ethereumjs/common": "^2.3.1",
"ethereumjs-util": "^7.1.0" "ethereumjs-util": "^7.0.10"
} }
}, },
"@ethereumjs/vm": { "@ethereumjs/vm": {
"version": "5.5.0", "version": "5.4.1",
"resolved": "https://registry.npmjs.org/@ethereumjs/vm/-/vm-5.5.0.tgz", "resolved": "https://registry.npmjs.org/@ethereumjs/vm/-/vm-5.4.1.tgz",
"integrity": "sha512-h6Kr6WqKUP8nVuEzCWPWEPrC63v7HFwt3gRuK7CJiyg9S0iWSBKUA/YVD4YgaSVACuxUfWaOBbwV5uGVupm5PQ==", "integrity": "sha512-cpQcg5CtjzXJBn8QNiobaiWckeN/ZQwsDHLYa9df2wBEUvzuEZgFWK48YEXSpx3CnUY9fNT/lgA9CzKdq8HTzQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.3.0",
"@ethereumjs/blockchain": "^5.4.0", "@ethereumjs/blockchain": "^5.3.0",
"@ethereumjs/common": "^2.4.0", "@ethereumjs/common": "^2.3.1",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.2.1",
"async-eventemitter": "^0.2.4", "async-eventemitter": "^0.2.4",
"core-js-pure": "^3.0.1", "core-js-pure": "^3.0.1",
"debug": "^2.2.0", "debug": "^2.2.0",
"ethereumjs-util": "^7.1.0", "ethereumjs-util": "^7.0.10",
"functional-red-black-tree": "^1.0.1", "functional-red-black-tree": "^1.0.1",
"mcl-wasm": "^0.7.1", "mcl-wasm": "^0.7.1",
"merkle-patricia-tree": "^4.2.0", "merkle-patricia-tree": "^4.2.0",
...@@ -20082,9 +19986,9 @@ ...@@ -20082,9 +19986,9 @@
"dev": true "dev": true
}, },
"@nodelib/fs.walk": { "@nodelib/fs.walk": {
"version": "1.2.8", "version": "1.2.7",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@nodelib/fs.scandir": "2.1.5", "@nodelib/fs.scandir": "2.1.5",
...@@ -20233,9 +20137,9 @@ ...@@ -20233,9 +20137,9 @@
} }
}, },
"@oclif/errors": { "@oclif/errors": {
"version": "1.3.5", "version": "1.3.4",
"resolved": "https://registry.npmjs.org/@oclif/errors/-/errors-1.3.5.tgz", "resolved": "https://registry.npmjs.org/@oclif/errors/-/errors-1.3.4.tgz",
"integrity": "sha512-OivucXPH/eLLlOT7FkCMoZXiaVYf8I/w1eTAM1+gKzfhALwWTusxEx7wBmW0uzvkSg/9ovWLycPaBgJbM3LOCQ==", "integrity": "sha512-pJKXyEqwdfRTUdM8n5FIHiQQHg5ETM0Wlso8bF9GodczO40mF5Z3HufnYWJE7z8sGKxOeJCdbAVZbS8Y+d5GCw==",
"dev": true, "dev": true,
"requires": { "requires": {
"clean-stack": "^3.0.0", "clean-stack": "^3.0.0",
...@@ -20612,9 +20516,9 @@ ...@@ -20612,9 +20516,9 @@
} }
}, },
"@openzeppelin/test-helpers": { "@openzeppelin/test-helpers": {
"version": "0.5.12", "version": "0.5.11",
"resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.12.tgz", "resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.11.tgz",
"integrity": "sha512-ZPhLmMb8PLGImYLen7YsPnni22i1bXHzrSiY7XZ7cgwuKvk4MRBunzfZ4xGTn/p+1V2/a1XHsjMRDKn7AMVb3Q==", "integrity": "sha512-HkFpCjtTD8dk+wdYhsT07YbMGCE+Z4Wp5sBKXvPDF3Lynoc0H2KqZgCWV+qr2YZ0WW1oX/sXkKFrrKJ0caBTjw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@openzeppelin/contract-loader": "^0.6.2", "@openzeppelin/contract-loader": "^0.6.2",
...@@ -20823,15 +20727,15 @@ ...@@ -20823,15 +20727,15 @@
} }
}, },
"@truffle/contract": { "@truffle/contract": {
"version": "4.3.24", "version": "4.3.23",
"resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.3.24.tgz", "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.3.23.tgz",
"integrity": "sha512-cKijyDzJLRu96KWb/g7soHJkBXgY1HkmCeVhUun9iUJpA93w7StInCP+SPs0gd8Oj7GfcoYcCcnA38l/zJBEsQ==", "integrity": "sha512-YqoFmy6bFMcFnbC1OXNBF1MrhNGYf1JEvY65EsbNe3cjkgbFfk0wVwuDkSYqXBIyWAOQBkPL+GTq4ouvnjVlnw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@ensdomains/ensjs": "^2.0.1", "@ensdomains/ensjs": "^2.0.1",
"@truffle/blockchain-utils": "^0.0.31", "@truffle/blockchain-utils": "^0.0.31",
"@truffle/contract-schema": "^3.4.1", "@truffle/contract-schema": "^3.4.1",
"@truffle/debug-utils": "^5.1.4", "@truffle/debug-utils": "^5.1.3",
"@truffle/error": "^0.0.14", "@truffle/error": "^0.0.14",
"@truffle/interface-adapter": "^0.5.2", "@truffle/interface-adapter": "^0.5.2",
"bignumber.js": "^7.2.1", "bignumber.js": "^7.2.1",
...@@ -20850,9 +20754,9 @@ ...@@ -20850,9 +20754,9 @@
"dev": true "dev": true
}, },
"@truffle/codec": { "@truffle/codec": {
"version": "0.11.4", "version": "0.11.3",
"resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.11.4.tgz", "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.11.3.tgz",
"integrity": "sha512-NK/ah1aWQFhYYv8kVL382wB+JgSOnWWDdoeGOOMnA3iviRnV7k0JJV+C6uTmaLKOTNGTBNp4hlISLFeKKNnbXA==", "integrity": "sha512-LBunwP2ZQ0CygcbuLGsQS8Zm4+2kpVKBkvA/DOiCI4IaNxMie3LMFCBFEVrHUey2a07J4wn7WivrRY3dUdS9zQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"big.js": "^5.2.2", "big.js": "^5.2.2",
...@@ -20869,12 +20773,12 @@ ...@@ -20869,12 +20773,12 @@
} }
}, },
"@truffle/debug-utils": { "@truffle/debug-utils": {
"version": "5.1.4", "version": "5.1.3",
"resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-5.1.4.tgz", "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-5.1.3.tgz",
"integrity": "sha512-0LdtJzhOuAgEIP4xj3QsB7CKIzoAgRERKx5hYktId9pfm//9leo3luwN0aY8f919rWJynmnaXvE0lQZD3Pcu0Q==", "integrity": "sha512-++IPNmxBH/uwaVqZ+hokEDavN9r0TayU2o0/geHoBCwcC0eW5xr9zbciFxsgKQCCuBESi23eOflNuQUK1Awa5w==",
"dev": true, "dev": true,
"requires": { "requires": {
"@truffle/codec": "^0.11.4", "@truffle/codec": "^0.11.3",
"@trufflesuite/chromafi": "^2.2.2", "@trufflesuite/chromafi": "^2.2.2",
"bn.js": "^5.1.3", "bn.js": "^5.1.3",
"chalk": "^2.4.2", "chalk": "^2.4.2",
...@@ -21217,9 +21121,9 @@ ...@@ -21217,9 +21121,9 @@
} }
}, },
"@types/abstract-leveldown": { "@types/abstract-leveldown": {
"version": "5.0.2", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-5.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/abstract-leveldown/-/abstract-leveldown-5.0.1.tgz",
"integrity": "sha512-+jA1XXF3jsz+Z7FcuiNqgK53hTa/luglT2TyTpKPqoYbxVY+mCPF22Rm+q3KPBrMHJwNXFrTViHszBOfU4vftQ==", "integrity": "sha512-wYxU3kp5zItbxKmeRYCEplS2MW7DzyBnxPGj+GJVHZEUZiK/nn5Ei1sUFgURDh+X051+zsGe28iud3oHjrYWQQ==",
"dev": true "dev": true
}, },
"@types/bignumber.js": { "@types/bignumber.js": {
...@@ -21241,15 +21145,15 @@ ...@@ -21241,15 +21145,15 @@
} }
}, },
"@types/chai": { "@types/chai": {
"version": "4.2.21", "version": "4.2.19",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.21.tgz", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.19.tgz",
"integrity": "sha512-yd+9qKmJxm496BOV9CMNaey8TWsikaZOwMRwPHQIjcOJM9oV+fi9ZMNw3JsVnbEEbo2gRTDnGEBv8pjyn67hNg==", "integrity": "sha512-jRJgpRBuY+7izT7/WNXP/LsMO9YonsstuL+xuvycDyESpoDoIAsMd7suwpB4h9oEWB+ZlPTqJJ8EHomzNhwTPQ==",
"dev": true "dev": true
}, },
"@types/concat-stream": { "@types/concat-stream": {
"version": "1.6.1", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.0.tgz",
"integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", "integrity": "sha1-OU2+C7X+5Gs42JZzXoto7yOQ0A0=",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/node": "*" "@types/node": "*"
...@@ -21265,15 +21169,21 @@ ...@@ -21265,15 +21169,21 @@
} }
}, },
"@types/glob": { "@types/glob": {
"version": "7.1.4", "version": "7.1.3",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.4.tgz", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==", "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/minimatch": "*", "@types/minimatch": "*",
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=",
"dev": true
},
"@types/level-errors": { "@types/level-errors": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/level-errors/-/level-errors-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/level-errors/-/level-errors-3.0.0.tgz",
...@@ -21281,9 +21191,9 @@ ...@@ -21281,9 +21191,9 @@
"dev": true "dev": true
}, },
"@types/levelup": { "@types/levelup": {
"version": "4.3.3", "version": "4.3.2",
"resolved": "https://registry.npmjs.org/@types/levelup/-/levelup-4.3.3.tgz", "resolved": "https://registry.npmjs.org/@types/levelup/-/levelup-4.3.2.tgz",
"integrity": "sha512-K+OTIjJcZHVlZQN1HmU64VtrC0jC3dXWQozuEIR9zVvltIk90zaGPM2AgT+fIkChpzHhFE3YnvFLCbLtzAmexA==", "integrity": "sha512-5Su1Dkl6nMjkXqUb2z72gbroG0WFLs+6nMH+wQt4GWIrDwR/IconLTojHtC0klLJODCJ64Cr6P5cWqVeuxAbSg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/abstract-leveldown": "*", "@types/abstract-leveldown": "*",
...@@ -21292,21 +21202,21 @@ ...@@ -21292,21 +21202,21 @@
} }
}, },
"@types/lru-cache": { "@types/lru-cache": {
"version": "5.1.1", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.0.tgz",
"integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", "integrity": "sha512-RaE0B+14ToE4l6UqdarKPnXwVDuigfFv+5j9Dze/Nqr23yyuqdNvzcZi3xB+3Agvi5R4EOgAksfv3lXX4vBt9w==",
"dev": true "dev": true
}, },
"@types/minimatch": { "@types/minimatch": {
"version": "3.0.5", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==",
"dev": true "dev": true
}, },
"@types/node": { "@types/node": {
"version": "12.20.16", "version": "12.20.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.16.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.15.tgz",
"integrity": "sha512-6CLxw83vQf6DKqXxMPwl8qpF8I7THFZuIwLt4TnNsumxkp1VsRZWT8txQxncT/Rl2UojTsFzWgDG4FRMwafrlA==", "integrity": "sha512-F6S4Chv4JicJmyrwlDkxUdGNSplsQdGwp1A0AJloEVDirWdZOAiRHhovDlsFkKUrquUXhz1imJhXHsf59auyAg==",
"dev": true "dev": true
}, },
"@types/pbkdf2": { "@types/pbkdf2": {
...@@ -21319,15 +21229,15 @@ ...@@ -21319,15 +21229,15 @@
} }
}, },
"@types/qs": { "@types/qs": {
"version": "6.9.7", "version": "6.9.6",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz",
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==",
"dev": true "dev": true
}, },
"@types/secp256k1": { "@types/secp256k1": {
"version": "4.0.3", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.2.tgz",
"integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", "integrity": "sha512-QMg+9v0bbNJ2peLuHRWxzmy0HRJIG6gFZNhaRSp7S3ggSbCCxiqQB2/ybvhXyhHOCequpNkrx7OavNhrWOsW0A==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/node": "*" "@types/node": "*"
...@@ -21395,9 +21305,9 @@ ...@@ -21395,9 +21305,9 @@
} }
}, },
"acorn-jsx": { "acorn-jsx": {
"version": "5.3.2", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
"dev": true, "dev": true,
"requires": {} "requires": {}
}, },
...@@ -24374,9 +24284,9 @@ ...@@ -24374,9 +24284,9 @@
} }
}, },
"ethereumjs-util": { "ethereumjs-util": {
"version": "7.1.0", "version": "7.0.10",
"resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.0.tgz", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.0.10.tgz",
"integrity": "sha512-kR+vhu++mUDARrsMMhsjjzPduRVAeundLGXucGRHF3B4oEltOUspfgCVco4kckucj3FMlLaZHUl9n7/kdmr6Tw==", "integrity": "sha512-c/xThw6A+EAnej5Xk5kOzFzyoSnw0WX0tSlZ6pAsfGVvQj3TItaDg9b1+Fz1RJXA+y2YksKwQnuzgt1eY6LKzw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/bn.js": "^5.1.0", "@types/bn.js": "^5.1.0",
...@@ -24875,9 +24785,9 @@ ...@@ -24875,9 +24785,9 @@
"dev": true "dev": true
}, },
"fast-glob": { "fast-glob": {
"version": "3.2.7", "version": "3.2.6",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz",
"integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.stat": "^2.0.2",
...@@ -26274,16 +26184,16 @@ ...@@ -26274,16 +26184,16 @@
} }
}, },
"hardhat": { "hardhat": {
"version": "2.4.3", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.4.3.tgz", "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.4.1.tgz",
"integrity": "sha512-xgbnhEnmaKau8xT6wPJlzoyMLAZyxQoElACQQCyEeAY1DURpZbYwjIQUywmL/ZNv3QEl38Yqu/n8mPOc2HXyGA==", "integrity": "sha512-vwllrFypukeE/Q+4ZfWj7j7nUo4ncUhRpsAYUM0Ruuuk6pQlKmRa0A6c0kxRSvvVgQsMud6j+/weYhbMX1wPmQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@ethereumjs/block": "^3.4.0", "@ethereumjs/block": "^3.3.0",
"@ethereumjs/blockchain": "^5.4.0", "@ethereumjs/blockchain": "^5.3.0",
"@ethereumjs/common": "^2.4.0", "@ethereumjs/common": "^2.3.1",
"@ethereumjs/tx": "^3.3.0", "@ethereumjs/tx": "^3.2.1",
"@ethereumjs/vm": "^5.5.0", "@ethereumjs/vm": "^5.3.2",
"@ethersproject/abi": "^5.1.2", "@ethersproject/abi": "^5.1.2",
"@sentry/node": "^5.18.1", "@sentry/node": "^5.18.1",
"@solidity-parser/parser": "^0.11.0", "@solidity-parser/parser": "^0.11.0",
...@@ -26301,7 +26211,7 @@ ...@@ -26301,7 +26211,7 @@
"eth-sig-util": "^2.5.2", "eth-sig-util": "^2.5.2",
"ethereum-cryptography": "^0.1.2", "ethereum-cryptography": "^0.1.2",
"ethereumjs-abi": "^0.6.8", "ethereumjs-abi": "^0.6.8",
"ethereumjs-util": "^7.1.0", "ethereumjs-util": "^7.0.10",
"find-up": "^2.1.0", "find-up": "^2.1.0",
"fp-ts": "1.19.3", "fp-ts": "1.19.3",
"fs-extra": "^7.0.1", "fs-extra": "^7.0.1",
...@@ -26547,9 +26457,9 @@ ...@@ -26547,9 +26457,9 @@
"dev": true "dev": true
}, },
"ws": { "ws": {
"version": "7.5.3", "version": "7.5.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.3.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.2.tgz",
"integrity": "sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==", "integrity": "sha512-lkF7AWRicoB9mAgjeKbGqVUekLnSNO4VjKVnuPHpQeOxZOErX6BPXwJk70nFslRCEEA8EVW7ZjKwXaP9N+1sKQ==",
"dev": true, "dev": true,
"requires": {} "requires": {}
} }
...@@ -26887,9 +26797,9 @@ ...@@ -26887,9 +26797,9 @@
"dev": true "dev": true
}, },
"immutable": { "immutable": {
"version": "4.0.0-rc.14", "version": "4.0.0-rc.12",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.14.tgz", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.12.tgz",
"integrity": "sha512-pfkvmRKJSoW7JFx0QeYlAmT+kNYvn5j0u7bnpNq4N2RCvHSTlLT208G8jgaquNe+Q8kCPHKOSpxJkyvLDpYq0w==", "integrity": "sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A==",
"dev": true "dev": true
}, },
"import-fresh": { "import-fresh": {
...@@ -29859,9 +29769,9 @@ ...@@ -29859,9 +29769,9 @@
"dev": true "dev": true
}, },
"prettier-plugin-solidity": { "prettier-plugin-solidity": {
"version": "1.0.0-beta.15", "version": "1.0.0-beta.16",
"resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.15.tgz", "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.16.tgz",
"integrity": "sha512-5+pM/Z1BgQN6xMCe/AfXmiVhoteaVgruVoGT8aa0zJMRiNOiK+SeaW2kOyzTI6sgg3QsUW58+ahf1hxlc/Adbw==", "integrity": "sha512-xVBcnoWpe52dNnCCbqPHC9ZrTWXcNfldf852ZD0DBcHDqVMwjHTAPEdfBVy6FczbFpVa8bmxQil+G5XkEz5WHA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@solidity-parser/parser": "^0.13.2", "@solidity-parser/parser": "^0.13.2",
...@@ -32541,23 +32451,24 @@ ...@@ -32541,23 +32451,24 @@
"dev": true "dev": true
}, },
"tsconfig-paths": { "tsconfig-paths": {
"version": "3.10.1", "version": "3.9.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
"integrity": "sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==", "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==",
"dev": true, "dev": true,
"requires": { "requires": {
"json5": "^2.2.0", "@types/json5": "^0.0.29",
"json5": "^1.0.1",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"strip-bom": "^3.0.0" "strip-bom": "^3.0.0"
}, },
"dependencies": { "dependencies": {
"json5": { "json5": {
"version": "2.2.0", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
"dev": true, "dev": true,
"requires": { "requires": {
"minimist": "^1.2.5" "minimist": "^1.2.0"
} }
} }
} }
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
"merkletreejs": "^0.2.13", "merkletreejs": "^0.2.13",
"micromatch": "^4.0.2", "micromatch": "^4.0.2",
"prettier": "^2.3.0", "prettier": "^2.3.0",
"prettier-plugin-solidity": "^1.0.0-beta.13", "prettier-plugin-solidity": "^1.0.0-beta.16",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"solhint": "^3.3.6", "solhint": "^3.3.6",
"solidity-ast": "^0.4.25", "solidity-ast": "^0.4.25",
......
...@@ -21,16 +21,22 @@ for (const artifact of artifacts) { ...@@ -21,16 +21,22 @@ for (const artifact of artifacts) {
} }
} }
graphlib.alg.findCycles(graph).forEach(([ c1, c2 ]) => { /// graphlib.alg.findCycles will not find minimal cycles.
console.log(`Conflict between ${names[c1]} and ${names[c2]} detected in the following dependency chains:`); /// We are only interested int cycles of lengths 2 (needs proof)
linearized graph.nodes().forEach((x, i, nodes) => nodes
.filter(chain => chain.includes(parseInt(c1)) && chain.includes(parseInt(c2))) .slice(i + 1)
.forEach(chain => { .filter(y => graph.hasEdge(x, y) && graph.hasEdge(y, x))
const comp = chain.indexOf(c1) < chain.indexOf(c2) ? '>' : '<'; .map(y => {
console.log(`- ${names[c1]} ${comp} ${names[c2]}: ${chain.reverse().map(id => names[id]).join(', ')}`); console.log(`Conflict between ${names[x]} and ${names[y]} detected in the following dependency chains:`);
}); linearized
process.exitCode = 1; .filter(chain => chain.includes(parseInt(x)) && chain.includes(parseInt(y)))
}); .forEach(chain => {
const comp = chain.indexOf(parseInt(x)) < chain.indexOf(parseInt(y)) ? '>' : '<';
console.log(`- ${names[x]} ${comp} ${names[y]} in ${names[chain.find(Boolean)]}`);
// console.log(`- ${names[x]} ${comp} ${names[y]}: ${chain.reverse().map(id => names[id]).join(', ')}`);
});
process.exitCode = 1;
}));
} }
if (!process.exitCode) { if (!process.exitCode) {
......
const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers');
const ethSigUtil = require('eth-sig-util');
const Wallet = require('ethereumjs-wallet').default;
const Enums = require('../helpers/enums');
const { EIP712Domain } = require('../helpers/eip712');
const { fromRpcSig } = require('ethereumjs-util');
const {
runGovernorWorkflow,
} = require('./GovernorWorkflow.behavior');
const {
shouldSupportInterfaces,
} = require('../utils/introspection/SupportsInterface.behavior');
const Token = artifacts.require('ERC20VotesMock');
const Governor = artifacts.require('GovernorMock');
const CallReceiver = artifacts.require('CallReceiverMock');
contract('Governor', function (accounts) {
const [ owner, proposer, voter1, voter2, voter3, voter4 ] = accounts;
const name = 'OZ-Governor';
const version = '1';
const tokenName = 'MockToken';
const tokenSymbol = 'MTKN';
const tokenSupply = web3.utils.toWei('100');
beforeEach(async function () {
this.owner = owner;
this.token = await Token.new(tokenName, tokenSymbol);
this.mock = await Governor.new(name, this.token.address, 4, 16, 0);
this.receiver = await CallReceiver.new();
await this.token.mint(owner, tokenSupply);
await this.token.delegate(voter1, { from: voter1 });
await this.token.delegate(voter2, { from: voter2 });
await this.token.delegate(voter3, { from: voter3 });
await this.token.delegate(voter4, { from: voter4 });
});
shouldSupportInterfaces([
'ERC165',
'Governor',
]);
it('deployment check', async function () {
expect(await this.mock.name()).to.be.equal(name);
expect(await this.mock.token()).to.be.equal(this.token.address);
expect(await this.mock.votingDelay()).to.be.bignumber.equal('4');
expect(await this.mock.votingPeriod()).to.be.bignumber.equal('16');
expect(await this.mock.quorum(0)).to.be.bignumber.equal('0');
expect(await this.mock.COUNTING_MODE()).to.be.equal('support=bravo&quorum=for,abstain');
});
describe('scenario', function () {
describe('nominal', function () {
beforeEach(async function () {
this.value = web3.utils.toWei('1');
await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value: this.value });
expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(this.value);
expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal('0');
this.settings = {
proposal: [
[ this.receiver.address ],
[ this.value ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
proposer,
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For, reason: 'This is nice' },
{ voter: voter2, weight: web3.utils.toWei('10'), support: Enums.VoteType.For },
{ voter: voter3, weight: web3.utils.toWei('5'), support: Enums.VoteType.Against },
{ voter: voter4, weight: web3.utils.toWei('2'), support: Enums.VoteType.Abstain },
],
};
this.votingDelay = await this.mock.votingDelay();
this.votingPeriod = await this.mock.votingPeriod();
});
afterEach(async function () {
expect(await this.mock.hasVoted(this.id, owner)).to.be.equal(false);
expect(await this.mock.hasVoted(this.id, voter1)).to.be.equal(true);
expect(await this.mock.hasVoted(this.id, voter2)).to.be.equal(true);
await this.mock.proposalVotes(this.id).then(result => {
for (const [key, value] of Object.entries(Enums.VoteType)) {
expect(result[`${key.toLowerCase()}Votes`]).to.be.bignumber.equal(
Object.values(this.settings.voters).filter(({ support }) => support === value).reduce(
(acc, { weight }) => acc.add(new BN(weight)),
new BN('0'),
),
);
}
});
expectEvent(
this.receipts.propose,
'ProposalCreated',
{
proposalId: this.id,
proposer,
targets: this.settings.proposal[0],
// values: this.settings.proposal[1].map(value => new BN(value)),
signatures: this.settings.proposal[2].map(() => ''),
calldatas: this.settings.proposal[2],
startBlock: new BN(this.receipts.propose.blockNumber).add(this.votingDelay),
endBlock: new BN(this.receipts.propose.blockNumber).add(this.votingDelay).add(this.votingPeriod),
description: this.settings.proposal[3],
},
);
this.receipts.castVote.filter(Boolean).forEach(vote => {
const { voter } = vote.logs.find(Boolean).args;
expectEvent(
vote,
'VoteCast',
this.settings.voters.find(({ address }) => address === voter),
);
});
expectEvent(
this.receipts.execute,
'ProposalExecuted',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
this.receipts.execute.transactionHash,
this.receiver,
'MockFunctionCalled',
);
expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0');
expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(this.value);
});
runGovernorWorkflow();
});
describe('vote with signature', function () {
beforeEach(async function () {
const chainId = await web3.eth.getChainId();
// generate voter by signature wallet
const voterBySig = Wallet.generate();
this.voter = web3.utils.toChecksumAddress(voterBySig.getAddressString());
// use delegateBySig to enable vote delegation for this wallet
const { v, r, s } = fromRpcSig(ethSigUtil.signTypedMessage(
voterBySig.getPrivateKey(),
{
data: {
types: {
EIP712Domain,
Delegation: [
{ name: 'delegatee', type: 'address' },
{ name: 'nonce', type: 'uint256' },
{ name: 'expiry', type: 'uint256' },
],
},
domain: { name: tokenName, version: '1', chainId, verifyingContract: this.token.address },
primaryType: 'Delegation',
message: { delegatee: this.voter, nonce: 0, expiry: constants.MAX_UINT256 },
},
},
));
await this.token.delegateBySig(this.voter, 0, constants.MAX_UINT256, v, r, s);
// prepare signature for vote by signature
const signature = async (message) => {
return fromRpcSig(ethSigUtil.signTypedMessage(
voterBySig.getPrivateKey(),
{
data: {
types: {
EIP712Domain,
Ballot: [
{ name: 'proposalId', type: 'uint256' },
{ name: 'support', type: 'uint8' },
],
},
domain: { name, version, chainId, verifyingContract: this.mock.address },
primaryType: 'Ballot',
message,
},
},
));
};
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: this.voter, signature, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
],
};
});
afterEach(async function () {
expect(await this.mock.hasVoted(this.id, owner)).to.be.equal(false);
expect(await this.mock.hasVoted(this.id, voter1)).to.be.equal(false);
expect(await this.mock.hasVoted(this.id, voter2)).to.be.equal(false);
expect(await this.mock.hasVoted(this.id, this.voter)).to.be.equal(true);
await this.mock.proposalVotes(this.id).then(result => {
for (const [key, value] of Object.entries(Enums.VoteType)) {
expect(result[`${key.toLowerCase()}Votes`]).to.be.bignumber.equal(
Object.values(this.settings.voters).filter(({ support }) => support === value).reduce(
(acc, { weight }) => acc.add(new BN(weight)),
new BN('0'),
),
);
}
});
expectEvent(
this.receipts.propose,
'ProposalCreated',
{ proposalId: this.id },
);
expectEvent(
this.receipts.execute,
'ProposalExecuted',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
this.receipts.execute.transactionHash,
this.receiver,
'MockFunctionCalled',
);
});
runGovernorWorkflow();
});
describe('send ethers', function () {
beforeEach(async function () {
this.receiver = { address: web3.utils.toChecksumAddress(web3.utils.randomHex(20)) };
this.value = web3.utils.toWei('1');
await web3.eth.sendTransaction({ from: owner, to: this.mock.address, value: this.value });
expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(this.value);
expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal('0');
this.settings = {
proposal: [
[ this.receiver.address ],
[ this.value ],
[ '0x' ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
{ voter: voter2, weight: web3.utils.toWei('1'), support: Enums.VoteType.Abstain },
],
};
});
afterEach(async function () {
expectEvent(
this.receipts.propose,
'ProposalCreated',
{ proposalId: this.id },
);
expectEvent(
this.receipts.execute,
'ProposalExecuted',
{ proposalId: this.id },
);
expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal('0');
expect(await web3.eth.getBalance(this.receiver.address)).to.be.bignumber.equal(this.value);
});
runGovernorWorkflow();
});
describe('receiver revert without reason', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ 0 ],
[ this.receiver.contract.methods.mockFunctionRevertsNoReason().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
],
steps: {
execute: { error: 'Governor: call reverted without message' },
},
};
});
runGovernorWorkflow();
});
describe('receiver revert with reason', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ 0 ],
[ this.receiver.contract.methods.mockFunctionRevertsReason().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
],
steps: {
execute: { error: 'CallReceiverMock: reverting' },
},
};
});
runGovernorWorkflow();
});
describe('missing proposal', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{
voter: voter1,
weight: web3.utils.toWei('1'),
support: Enums.VoteType.For,
error: 'Governor: unknown proposal id',
},
{
voter: voter2,
weight: web3.utils.toWei('1'),
support: Enums.VoteType.Abstain,
error: 'Governor: unknown proposal id',
},
],
steps: {
propose: { enable: false },
wait: { enable: false },
execute: { error: 'Governor: unknown proposal id' },
},
};
});
runGovernorWorkflow();
});
describe('duplicate pending proposal', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
steps: {
wait: { enable: false },
execute: { enable: false },
},
};
});
afterEach(async function () {
await expectRevert(this.mock.propose(...this.settings.proposal), 'Governor: proposal already exists');
});
runGovernorWorkflow();
});
describe('duplicate executed proposal', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
{ voter: voter2, weight: web3.utils.toWei('1'), support: Enums.VoteType.Abstain },
],
};
});
afterEach(async function () {
await expectRevert(this.mock.propose(...this.settings.proposal), 'Governor: proposal already exists');
});
runGovernorWorkflow();
});
describe('Invalid vote type', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{
voter: voter1,
weight: web3.utils.toWei('1'),
support: new BN('255'),
error: 'GovernorVotingSimple: invalid value for enum VoteType',
},
],
steps: {
wait: { enable: false },
execute: { enable: false },
},
};
});
runGovernorWorkflow();
});
describe('double cast', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{
voter: voter1,
weight: web3.utils.toWei('1'),
support: Enums.VoteType.For,
},
{
voter: voter1,
weight: web3.utils.toWei('1'),
support: Enums.VoteType.For,
error: 'GovernorVotingSimple: vote already casted',
},
],
};
});
runGovernorWorkflow();
});
describe('quorum not reached', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('0'), support: Enums.VoteType.For },
],
steps: {
execute: { error: 'Governor: proposal not successful' },
},
};
});
runGovernorWorkflow();
});
describe('score not reached', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.Against },
],
steps: {
execute: { error: 'Governor: proposal not successful' },
},
};
});
runGovernorWorkflow();
});
describe('vote not over', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
],
steps: {
wait: { enable: false },
execute: { error: 'Governor: proposal not successful' },
},
};
});
runGovernorWorkflow();
});
});
describe('state', function () {
describe('Unset', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
steps: {
propose: { enable: false },
wait: { enable: false },
execute: { enable: false },
},
};
});
afterEach(async function () {
await expectRevert(this.mock.state(this.id), 'Governor: unknown proposal id');
});
runGovernorWorkflow();
});
describe('Pending & Active', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
steps: {
propose: { noadvance: true },
wait: { enable: false },
execute: { enable: false },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Pending);
await time.advanceBlockTo(this.snapshot);
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Active);
});
runGovernorWorkflow();
});
describe('Defeated', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
steps: {
execute: { enable: false },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Defeated);
});
runGovernorWorkflow();
});
describe('Succeeded', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
],
steps: {
execute: { enable: false },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded);
});
runGovernorWorkflow();
});
describe('Executed', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
],
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Executed);
});
runGovernorWorkflow();
});
});
describe('Cancel', function () {
describe('Before proposal', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
steps: {
propose: { enable: false },
wait: { enable: false },
execute: { enable: false },
},
};
});
afterEach(async function () {
await expectRevert(
this.mock.cancel(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: unknown proposal id',
);
});
runGovernorWorkflow();
});
describe('After proposal', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
steps: {
wait: { enable: false },
execute: { enable: false },
},
};
});
afterEach(async function () {
await this.mock.cancel(...this.settings.proposal.slice(0, -1), this.descriptionHash);
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled);
await expectRevert(
this.mock.castVote(this.id, new BN('100'), { from: voter1 }),
'Governor: vote not currently active',
);
});
runGovernorWorkflow();
});
describe('After vote', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
],
steps: {
wait: { enable: false },
execute: { enable: false },
},
};
});
afterEach(async function () {
await this.mock.cancel(...this.settings.proposal.slice(0, -1), this.descriptionHash);
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled);
await expectRevert(
this.mock.execute(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
});
runGovernorWorkflow();
});
describe('After deadline', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
],
steps: {
execute: { enable: false },
},
};
});
afterEach(async function () {
await this.mock.cancel(...this.settings.proposal.slice(0, -1), this.descriptionHash);
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled);
await expectRevert(
this.mock.execute(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
});
runGovernorWorkflow();
});
describe('After execution', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
],
};
});
afterEach(async function () {
await expectRevert(
this.mock.cancel(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not active',
);
});
runGovernorWorkflow();
});
});
describe('Proposal length', function () {
it('empty', async function () {
await expectRevert(
this.mock.propose(
[],
[],
[],
'<proposal description>',
),
'Governor: empty proposal',
);
});
it('missmatch #1', async function () {
await expectRevert(
this.mock.propose(
[ ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
),
'Governor: invalid proposal length',
);
});
it('missmatch #2', async function () {
await expectRevert(
this.mock.propose(
[ this.receiver.address ],
[ ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
),
'Governor: invalid proposal length',
);
});
it('missmatch #3', async function () {
await expectRevert(
this.mock.propose(
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ ],
'<proposal description>',
),
'Governor: invalid proposal length',
);
});
});
});
const { expectRevert, time } = require('@openzeppelin/test-helpers');
async function getReceiptOrRevert (promise, error = undefined) {
if (error) {
await expectRevert(promise, error);
return undefined;
} else {
const { receipt } = await promise;
return receipt;
}
}
function tryGet (obj, path = '') {
try {
return path.split('.').reduce((o, k) => o[k], obj);
} catch (_) {
return undefined;
}
}
function runGovernorWorkflow () {
beforeEach(async function () {
this.receipts = {};
this.descriptionHash = web3.utils.keccak256(this.settings.proposal.slice(-1).find(Boolean));
this.id = await this.mock.hashProposal(...this.settings.proposal.slice(0, -1), this.descriptionHash);
});
it('run', async function () {
// transfer tokens
if (tryGet(this.settings, 'voters')) {
for (const voter of this.settings.voters) {
if (voter.weight) {
await this.token.transfer(voter.voter, voter.weight, { from: this.settings.tokenHolder });
}
}
}
// propose
if (this.mock.propose && tryGet(this.settings, 'steps.propose.enable') !== false) {
this.receipts.propose = await getReceiptOrRevert(
this.mock.methods['propose(address[],uint256[],bytes[],string)'](
...this.settings.proposal,
{ from: this.settings.proposer },
),
tryGet(this.settings, 'steps.propose.error'),
);
if (tryGet(this.settings, 'steps.propose.error') === undefined) {
this.deadline = await this.mock.proposalDeadline(this.id);
this.snapshot = await this.mock.proposalSnapshot(this.id);
}
if (tryGet(this.settings, 'steps.propose.delay')) {
await time.increase(tryGet(this.settings, 'steps.propose.delay'));
}
if (
tryGet(this.settings, 'steps.propose.error') === undefined &&
tryGet(this.settings, 'steps.propose.noadvance') !== true
) {
await time.advanceBlockTo(this.snapshot);
}
}
// vote
if (tryGet(this.settings, 'voters')) {
this.receipts.castVote = [];
for (const voter of this.settings.voters) {
if (!voter.signature) {
this.receipts.castVote.push(
await getReceiptOrRevert(
voter.reason
? this.mock.castVoteWithReason(this.id, voter.support, voter.reason, { from: voter.voter })
: this.mock.castVote(this.id, voter.support, { from: voter.voter }),
voter.error,
),
);
} else {
const { v, r, s } = await voter.signature({ proposalId: this.id, support: voter.support });
this.receipts.castVote.push(
await getReceiptOrRevert(
this.mock.castVoteBySig(this.id, voter.support, v, r, s),
voter.error,
),
);
}
if (tryGet(voter, 'delay')) {
await time.increase(tryGet(voter, 'delay'));
}
}
}
// fast forward
if (tryGet(this.settings, 'steps.wait.enable') !== false) {
await time.advanceBlockTo(this.deadline);
}
// queue
if (this.mock.queue && tryGet(this.settings, 'steps.queue.enable') !== false) {
this.receipts.queue = await getReceiptOrRevert(
this.mock.methods['queue(address[],uint256[],bytes[],bytes32)'](
...this.settings.proposal.slice(0, -1),
this.descriptionHash,
{ from: this.settings.queuer },
),
tryGet(this.settings, 'steps.queue.error'),
);
this.eta = await this.mock.proposalEta(this.id);
if (tryGet(this.settings, 'steps.queue.delay')) {
await time.increase(tryGet(this.settings, 'steps.queue.delay'));
}
}
// execute
if (this.mock.execute && tryGet(this.settings, 'steps.execute.enable') !== false) {
this.receipts.execute = await getReceiptOrRevert(
this.mock.methods['execute(address[],uint256[],bytes[],bytes32)'](
...this.settings.proposal.slice(0, -1),
this.descriptionHash,
{ from: this.settings.executer },
),
tryGet(this.settings, 'steps.execute.error'),
);
if (tryGet(this.settings, 'steps.execute.delay')) {
await time.increase(tryGet(this.settings, 'steps.execute.delay'));
}
}
});
}
module.exports = {
runGovernorWorkflow,
};
const { BN, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers');
const Enums = require('../../helpers/enums');
const RLP = require('rlp');
const {
runGovernorWorkflow,
} = require('../GovernorWorkflow.behavior');
const Token = artifacts.require('ERC20VotesCompMock');
const Timelock = artifacts.require('CompTimelock');
const Governor = artifacts.require('GovernorCompatibilityBravoMock');
const CallReceiver = artifacts.require('CallReceiverMock');
async function getReceiptOrRevert (promise, error = undefined) {
if (error) {
await expectRevert(promise, error);
return undefined;
} else {
const { receipt } = await promise;
return receipt;
}
}
function tryGet (obj, path = '') {
try {
return path.split('.').reduce((o, k) => o[k], obj);
} catch (_) {
return undefined;
}
}
function makeContractAddress (creator, nonce) {
return web3.utils.toChecksumAddress(web3.utils.sha3(RLP.encode([creator, nonce])).slice(12).substring(14));
}
contract('GovernorCompatibilityBravo', function (accounts) {
const [ owner, proposer, voter1, voter2, voter3, voter4, other ] = accounts;
const name = 'OZ-Governor';
// const version = '1';
const tokenName = 'MockToken';
const tokenSymbol = 'MTKN';
const tokenSupply = web3.utils.toWei('100');
const proposalThreshold = web3.utils.toWei('10');
beforeEach(async function () {
const [ deployer ] = await web3.eth.getAccounts();
this.token = await Token.new(tokenName, tokenSymbol);
// Need to predict governance address to set it as timelock admin with a delayed transfer
const nonce = await web3.eth.getTransactionCount(deployer);
const predictGovernor = makeContractAddress(deployer, nonce + 1);
this.timelock = await Timelock.new(predictGovernor, 2 * 86400);
this.mock = await Governor.new(name, this.token.address, 4, 16, proposalThreshold, this.timelock.address);
this.receiver = await CallReceiver.new();
await this.token.mint(owner, tokenSupply);
await this.token.delegate(voter1, { from: voter1 });
await this.token.delegate(voter2, { from: voter2 });
await this.token.delegate(voter3, { from: voter3 });
await this.token.delegate(voter4, { from: voter4 });
await this.token.transfer(proposer, proposalThreshold, { from: owner });
await this.token.delegate(proposer, { from: proposer });
});
it('deployment check', async function () {
expect(await this.mock.name()).to.be.equal(name);
expect(await this.mock.token()).to.be.equal(this.token.address);
expect(await this.mock.votingDelay()).to.be.bignumber.equal('4');
expect(await this.mock.votingPeriod()).to.be.bignumber.equal('16');
expect(await this.mock.quorum(0)).to.be.bignumber.equal('0');
expect(await this.mock.quorumVotes()).to.be.bignumber.equal('0');
expect(await this.mock.COUNTING_MODE()).to.be.equal('support=bravo&quorum=bravo');
});
describe('nominal', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ], // targets
[ web3.utils.toWei('0') ], // values
[ this.receiver.contract.methods.mockFunction().encodeABI() ], // calldatas
'<proposal description>', // description
],
proposer,
tokenHolder: owner,
voters: [
{
voter: voter1,
weight: web3.utils.toWei('1'),
support: Enums.VoteType.Abstain,
},
{
voter: voter2,
weight: web3.utils.toWei('10'),
support: Enums.VoteType.For,
},
{
voter: voter3,
weight: web3.utils.toWei('5'),
support: Enums.VoteType.Against,
},
{
voter: voter4,
support: '100',
error: 'GovernorCompatibilityBravo: invalid vote type',
},
{
voter: voter1,
support: Enums.VoteType.For,
error: 'GovernorCompatibilityBravo: vote already casted',
skip: true,
},
],
steps: {
queue: { delay: 7 * 86400 },
},
};
this.votingDelay = await this.mock.votingDelay();
this.votingPeriod = await this.mock.votingPeriod();
this.receipts = {};
});
afterEach(async function () {
const proposal = await this.mock.proposals(this.id);
expect(proposal.id).to.be.bignumber.equal(this.id);
expect(proposal.proposer).to.be.equal(proposer);
expect(proposal.eta).to.be.bignumber.equal(this.eta);
expect(proposal.startBlock).to.be.bignumber.equal(this.snapshot);
expect(proposal.endBlock).to.be.bignumber.equal(this.deadline);
expect(proposal.canceled).to.be.equal(false);
expect(proposal.executed).to.be.equal(true);
for (const [key, value] of Object.entries(Enums.VoteType)) {
expect(proposal[`${key.toLowerCase()}Votes`]).to.be.bignumber.equal(
Object.values(this.settings.voters).filter(({ support }) => support === value).reduce(
(acc, { weight }) => acc.add(new BN(weight)),
new BN('0'),
),
);
}
const action = await this.mock.getActions(this.id);
expect(action.targets).to.be.deep.equal(this.settings.proposal[0]);
// expect(action.values).to.be.deep.equal(this.settings.proposal[1]);
expect(action.signatures).to.be.deep.equal(Array(this.settings.proposal[2].length).fill(''));
expect(action.calldatas).to.be.deep.equal(this.settings.proposal[2]);
for (const voter of this.settings.voters.filter(({ skip }) => !skip)) {
expect(await this.mock.hasVoted(this.id, voter.voter)).to.be.equal(voter.error === undefined);
const receipt = await this.mock.getReceipt(this.id, voter.voter);
expect(receipt.hasVoted).to.be.equal(voter.error === undefined);
expect(receipt.support).to.be.bignumber.equal(voter.error === undefined ? voter.support : '0');
expect(receipt.votes).to.be.bignumber.equal(voter.error === undefined ? voter.weight : '0');
}
expectEvent(
this.receipts.propose,
'ProposalCreated',
{
proposalId: this.id,
proposer,
targets: this.settings.proposal[0],
// values: this.settings.proposal[1].map(value => new BN(value)),
signatures: this.settings.proposal[2].map(() => ''),
calldatas: this.settings.proposal[2],
startBlock: new BN(this.receipts.propose.blockNumber).add(this.votingDelay),
endBlock: new BN(this.receipts.propose.blockNumber).add(this.votingDelay).add(this.votingPeriod),
description: this.settings.proposal[3],
},
);
this.receipts.castVote.filter(Boolean).forEach(vote => {
const { voter } = vote.logs.find(Boolean).args;
expectEvent(
vote,
'VoteCast',
this.settings.voters.find(({ address }) => address === voter),
);
});
expectEvent(
this.receipts.execute,
'ProposalExecuted',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
this.receipts.execute.transactionHash,
this.receiver,
'MockFunctionCalled',
);
});
runGovernorWorkflow();
});
describe('proposalThreshold not reached', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ], // targets
[ web3.utils.toWei('0') ], // values
[ this.receiver.contract.methods.mockFunction().encodeABI() ], // calldatas
'<proposal description>', // description
],
proposer: other,
steps: {
propose: { error: 'GovernorCompatibilityBravo: proposer votes below proposal threshold' },
wait: { enable: false },
queue: { enable: false },
execute: { enable: false },
},
};
});
runGovernorWorkflow();
});
describe('with compatibility interface', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ], // targets
[ web3.utils.toWei('0') ], // values
[ '' ], // signatures
[ this.receiver.contract.methods.mockFunction().encodeABI() ], // calldatas
'<proposal description>', // description
],
proposer,
tokenHolder: owner,
voters: [
{
voter: voter1,
weight: web3.utils.toWei('1'),
support: Enums.VoteType.Abstain,
},
{
voter: voter2,
weight: web3.utils.toWei('10'),
support: Enums.VoteType.For,
},
{
voter: voter3,
weight: web3.utils.toWei('5'),
support: Enums.VoteType.Against,
},
{
voter: voter4,
support: '100',
error: 'GovernorCompatibilityBravo: invalid vote type',
},
{
voter: voter1,
support: Enums.VoteType.For,
error: 'GovernorCompatibilityBravo: vote already casted',
skip: true,
},
],
steps: {
queue: { delay: 7 * 86400 },
},
};
this.votingDelay = await this.mock.votingDelay();
this.votingPeriod = await this.mock.votingPeriod();
this.receipts = {};
});
afterEach(async function () {
const proposal = await this.mock.proposals(this.id);
expect(proposal.id).to.be.bignumber.equal(this.id);
expect(proposal.proposer).to.be.equal(proposer);
expect(proposal.eta).to.be.bignumber.equal(this.eta);
expect(proposal.startBlock).to.be.bignumber.equal(this.snapshot);
expect(proposal.endBlock).to.be.bignumber.equal(this.deadline);
expect(proposal.canceled).to.be.equal(false);
expect(proposal.executed).to.be.equal(true);
for (const [key, value] of Object.entries(Enums.VoteType)) {
expect(proposal[`${key.toLowerCase()}Votes`]).to.be.bignumber.equal(
Object.values(this.settings.voters).filter(({ support }) => support === value).reduce(
(acc, { weight }) => acc.add(new BN(weight)),
new BN('0'),
),
);
}
const action = await this.mock.getActions(this.id);
expect(action.targets).to.be.deep.equal(this.settings.proposal[0]);
// expect(action.values).to.be.deep.equal(this.settings.proposal[1]);
expect(action.signatures).to.be.deep.equal(this.settings.proposal[2]);
expect(action.calldatas).to.be.deep.equal(this.settings.proposal[3]);
for (const voter of this.settings.voters.filter(({ skip }) => !skip)) {
expect(await this.mock.hasVoted(this.id, voter.voter)).to.be.equal(voter.error === undefined);
const receipt = await this.mock.getReceipt(this.id, voter.voter);
expect(receipt.hasVoted).to.be.equal(voter.error === undefined);
expect(receipt.support).to.be.bignumber.equal(voter.error === undefined ? voter.support : '0');
expect(receipt.votes).to.be.bignumber.equal(voter.error === undefined ? voter.weight : '0');
}
expectEvent(
this.receipts.propose,
'ProposalCreated',
{
proposalId: this.id,
proposer,
targets: this.settings.proposal[0],
// values: this.settings.proposal[1].map(value => new BN(value)),
signatures: this.settings.proposal[2],
calldatas: this.settings.proposal[3],
startBlock: new BN(this.receipts.propose.blockNumber).add(this.votingDelay),
endBlock: new BN(this.receipts.propose.blockNumber).add(this.votingDelay).add(this.votingPeriod),
description: this.settings.proposal[4],
},
);
this.receipts.castVote.filter(Boolean).forEach(vote => {
const { voter } = vote.logs.find(Boolean).args;
expectEvent(
vote,
'VoteCast',
this.settings.voters.find(({ address }) => address === voter),
);
});
expectEvent(
this.receipts.execute,
'ProposalExecuted',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
this.receipts.execute.transactionHash,
this.receiver,
'MockFunctionCalled',
);
});
it('run', async function () {
// transfer tokens
if (tryGet(this.settings, 'voters')) {
for (const voter of this.settings.voters) {
if (voter.weight) {
await this.token.transfer(voter.voter, voter.weight, { from: this.settings.tokenHolder });
}
}
}
// propose
if (this.mock.propose && tryGet(this.settings, 'steps.propose.enable') !== false) {
this.receipts.propose = await getReceiptOrRevert(
this.mock.methods['propose(address[],uint256[],string[],bytes[],string)'](
...this.settings.proposal,
{ from: this.settings.proposer },
),
tryGet(this.settings, 'steps.propose.error'),
);
if (tryGet(this.settings, 'steps.propose.error') === undefined) {
this.id = this.receipts.propose.logs.find(({ event }) => event === 'ProposalCreated').args.proposalId;
this.snapshot = await this.mock.proposalSnapshot(this.id);
this.deadline = await this.mock.proposalDeadline(this.id);
}
if (tryGet(this.settings, 'steps.propose.delay')) {
await time.increase(tryGet(this.settings, 'steps.propose.delay'));
}
if (
tryGet(this.settings, 'steps.propose.error') === undefined &&
tryGet(this.settings, 'steps.propose.noadvance') !== true
) {
await time.advanceBlockTo(this.snapshot);
}
}
// vote
if (tryGet(this.settings, 'voters')) {
this.receipts.castVote = [];
for (const voter of this.settings.voters) {
if (!voter.signature) {
this.receipts.castVote.push(
await getReceiptOrRevert(
this.mock.castVote(this.id, voter.support, { from: voter.voter }),
voter.error,
),
);
} else {
const { v, r, s } = await voter.signature({ proposalId: this.id, support: voter.support });
this.receipts.castVote.push(
await getReceiptOrRevert(
this.mock.castVoteBySig(this.id, voter.support, v, r, s),
voter.error,
),
);
}
if (tryGet(voter, 'delay')) {
await time.increase(tryGet(voter, 'delay'));
}
}
}
// fast forward
if (tryGet(this.settings, 'steps.wait.enable') !== false) {
await time.advanceBlockTo(this.deadline);
}
// queue
if (this.mock.queue && tryGet(this.settings, 'steps.queue.enable') !== false) {
this.receipts.queue = await getReceiptOrRevert(
this.mock.methods['queue(uint256)'](this.id, { from: this.settings.queuer }),
tryGet(this.settings, 'steps.queue.error'),
);
this.eta = await this.mock.proposalEta(this.id);
if (tryGet(this.settings, 'steps.queue.delay')) {
await time.increase(tryGet(this.settings, 'steps.queue.delay'));
}
}
// execute
if (this.mock.execute && tryGet(this.settings, 'steps.execute.enable') !== false) {
this.receipts.execute = await getReceiptOrRevert(
this.mock.methods['execute(uint256)'](this.id, { from: this.settings.executer }),
tryGet(this.settings, 'steps.execute.error'),
);
if (tryGet(this.settings, 'steps.execute.delay')) {
await time.increase(tryGet(this.settings, 'steps.execute.delay'));
}
}
});
});
});
const { BN, expectEvent } = require('@openzeppelin/test-helpers');
const Enums = require('../../helpers/enums');
const {
runGovernorWorkflow,
} = require('./../GovernorWorkflow.behavior');
const Token = artifacts.require('ERC20VotesCompMock');
const Governor = artifacts.require('GovernorCompMock');
const CallReceiver = artifacts.require('CallReceiverMock');
contract('GovernorComp', function (accounts) {
const [ owner, voter1, voter2, voter3, voter4 ] = accounts;
const name = 'OZ-Governor';
// const version = '1';
const tokenName = 'MockToken';
const tokenSymbol = 'MTKN';
const tokenSupply = web3.utils.toWei('100');
beforeEach(async function () {
this.owner = owner;
this.token = await Token.new(tokenName, tokenSymbol);
this.mock = await Governor.new(name, this.token.address, 4, 16);
this.receiver = await CallReceiver.new();
await this.token.mint(owner, tokenSupply);
await this.token.delegate(voter1, { from: voter1 });
await this.token.delegate(voter2, { from: voter2 });
await this.token.delegate(voter3, { from: voter3 });
await this.token.delegate(voter4, { from: voter4 });
});
it('deployment check', async function () {
expect(await this.mock.name()).to.be.equal(name);
expect(await this.mock.token()).to.be.equal(this.token.address);
expect(await this.mock.votingDelay()).to.be.bignumber.equal('4');
expect(await this.mock.votingPeriod()).to.be.bignumber.equal('16');
expect(await this.mock.quorum(0)).to.be.bignumber.equal('0');
});
describe('voting with comp token', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
{ voter: voter2, weight: web3.utils.toWei('10'), support: Enums.VoteType.For },
{ voter: voter3, weight: web3.utils.toWei('5'), support: Enums.VoteType.Against },
{ voter: voter4, weight: web3.utils.toWei('2'), support: Enums.VoteType.Abstain },
],
};
});
afterEach(async function () {
expect(await this.mock.hasVoted(this.id, owner)).to.be.equal(false);
expect(await this.mock.hasVoted(this.id, voter1)).to.be.equal(true);
expect(await this.mock.hasVoted(this.id, voter2)).to.be.equal(true);
expect(await this.mock.hasVoted(this.id, voter3)).to.be.equal(true);
expect(await this.mock.hasVoted(this.id, voter4)).to.be.equal(true);
this.receipts.castVote.filter(Boolean).forEach(vote => {
const { voter } = vote.logs.find(Boolean).args;
expectEvent(
vote,
'VoteCast',
this.settings.voters.find(({ address }) => address === voter),
);
});
await this.mock.proposalVotes(this.id).then(result => {
for (const [key, value] of Object.entries(Enums.VoteType)) {
expect(result[`${key.toLowerCase()}Votes`]).to.be.bignumber.equal(
Object.values(this.settings.voters).filter(({ support }) => support === value).reduce(
(acc, { weight }) => acc.add(new BN(weight)),
new BN('0'),
),
);
}
});
});
runGovernorWorkflow();
});
});
const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
const { expect } = require('chai');
const Enums = require('../../helpers/enums');
const RLP = require('rlp');
const {
runGovernorWorkflow,
} = require('../GovernorWorkflow.behavior');
const {
shouldSupportInterfaces,
} = require('../../utils/introspection/SupportsInterface.behavior');
const Token = artifacts.require('ERC20VotesMock');
const Timelock = artifacts.require('CompTimelock');
const Governor = artifacts.require('GovernorTimelockCompoundMock');
const CallReceiver = artifacts.require('CallReceiverMock');
function makeContractAddress (creator, nonce) {
return web3.utils.toChecksumAddress(web3.utils.sha3(RLP.encode([creator, nonce])).slice(12).substring(14));
}
contract('GovernorTimelockCompound', function (accounts) {
const [ admin, voter ] = accounts;
const name = 'OZ-Governor';
// const version = '1';
const tokenName = 'MockToken';
const tokenSymbol = 'MTKN';
const tokenSupply = web3.utils.toWei('100');
beforeEach(async function () {
const [ deployer ] = await web3.eth.getAccounts();
this.token = await Token.new(tokenName, tokenSymbol);
// Need to predict governance address to set it as timelock admin with a delayed transfer
const nonce = await web3.eth.getTransactionCount(deployer);
const predictGovernor = makeContractAddress(deployer, nonce + 1);
this.timelock = await Timelock.new(predictGovernor, 2 * 86400);
this.mock = await Governor.new(name, this.token.address, 4, 16, this.timelock.address, 0);
this.receiver = await CallReceiver.new();
await this.token.mint(voter, tokenSupply);
await this.token.delegate(voter, { from: voter });
});
shouldSupportInterfaces([
'ERC165',
'Governor',
'GovernorTimelock',
]);
it('post deployment check', async function () {
expect(await this.mock.name()).to.be.equal(name);
expect(await this.mock.token()).to.be.equal(this.token.address);
expect(await this.mock.votingDelay()).to.be.bignumber.equal('4');
expect(await this.mock.votingPeriod()).to.be.bignumber.equal('16');
expect(await this.mock.quorum(0)).to.be.bignumber.equal('0');
expect(await this.mock.timelock()).to.be.equal(this.timelock.address);
expect(await this.timelock.admin()).to.be.equal(this.mock.address);
});
describe('nominal', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 7 * 86400 },
},
};
});
afterEach(async function () {
expectEvent(
this.receipts.propose,
'ProposalCreated',
{ proposalId: this.id },
);
expectEvent(
this.receipts.queue,
'ProposalQueued',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
this.receipts.queue.transactionHash,
this.timelock,
'QueueTransaction',
{ eta: this.eta },
);
expectEvent(
this.receipts.execute,
'ProposalExecuted',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
this.receipts.execute.transactionHash,
this.timelock,
'ExecuteTransaction',
{ eta: this.eta },
);
await expectEvent.inTransaction(
this.receipts.execute.transactionHash,
this.receiver,
'MockFunctionCalled',
);
});
runGovernorWorkflow();
});
describe('not queued', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { enable: false },
execute: { error: 'GovernorTimelockCompound: proposal not yet queued' },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded);
});
runGovernorWorkflow();
});
describe('to early', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
execute: { error: 'Timelock::executeTransaction: Transaction hasn\'t surpassed time lock' },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Queued);
});
runGovernorWorkflow();
});
describe('to late', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 30 * 86400 },
execute: { error: 'Governor: proposal not successful' },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Expired);
});
runGovernorWorkflow();
});
describe('deplicated underlying call', function () {
beforeEach(async function () {
this.settings = {
proposal: [
Array(2).fill(this.token.address),
Array(2).fill(web3.utils.toWei('0')),
Array(2).fill(this.token.contract.methods.approve(this.receiver.address, constants.MAX_UINT256).encodeABI()),
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: {
error: 'GovernorTimelockCompound: identical proposal action already queued',
},
execute: {
error: 'GovernorTimelockCompound: proposal not yet queued',
},
},
};
});
runGovernorWorkflow();
});
describe('re-queue / re-execute', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 7 * 86400 },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Executed);
await expectRevert(
this.mock.queue(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
await expectRevert(
this.mock.execute(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
});
runGovernorWorkflow();
});
describe('cancel before queue prevents scheduling', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { enable: false },
execute: { enable: false },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded);
expectEvent(
await this.mock.cancel(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'ProposalCanceled',
{ proposalId: this.id },
);
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled);
await expectRevert(
this.mock.queue(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
});
runGovernorWorkflow();
});
describe('cancel after queue prevents executing', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 7 * 86400 },
execute: { enable: false },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Queued);
const receipt = await this.mock.cancel(...this.settings.proposal.slice(0, -1), this.descriptionHash);
expectEvent(
receipt,
'ProposalCanceled',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
receipt.receipt.transactionHash,
this.timelock,
'CancelTransaction',
);
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled);
await expectRevert(
this.mock.execute(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
});
runGovernorWorkflow();
});
describe('updateTimelock', function () {
beforeEach(async function () {
this.newTimelock = await Timelock.new(this.mock.address, 7 * 86400);
});
it('protected', async function () {
await expectRevert(
this.mock.updateTimelock(this.newTimelock.address),
'Governor: onlyGovernance',
);
});
describe('using workflow', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[
this.timelock.address,
this.mock.address,
],
[
web3.utils.toWei('0'),
web3.utils.toWei('0'),
],
[
this.timelock.contract.methods.setPendingAdmin(admin).encodeABI(),
this.mock.contract.methods.updateTimelock(this.newTimelock.address).encodeABI(),
],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 7 * 86400 },
},
};
});
afterEach(async function () {
expectEvent(
this.receipts.propose,
'ProposalCreated',
{ proposalId: this.id },
);
expectEvent(
this.receipts.execute,
'ProposalExecuted',
{ proposalId: this.id },
);
expectEvent(
this.receipts.execute,
'TimelockChange',
{ oldTimelock: this.timelock.address, newTimelock: this.newTimelock.address },
);
expect(await this.mock.timelock()).to.be.bignumber.equal(this.newTimelock.address);
});
runGovernorWorkflow();
});
});
describe('transfer timelock to new governor', function () {
beforeEach(async function () {
this.newGovernor = await Governor.new(name, this.token.address, 8, 32, this.timelock.address, 0);
});
describe('using workflow', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.timelock.address ],
[ web3.utils.toWei('0') ],
[ this.timelock.contract.methods.setPendingAdmin(this.newGovernor.address).encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 7 * 86400 },
},
};
});
afterEach(async function () {
expectEvent(
this.receipts.propose,
'ProposalCreated',
{ proposalId: this.id },
);
expectEvent(
this.receipts.execute,
'ProposalExecuted',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
this.receipts.execute.transactionHash,
this.timelock,
'NewPendingAdmin',
{ newPendingAdmin: this.newGovernor.address },
);
await this.newGovernor.__acceptAdmin();
expect(await this.timelock.admin()).to.be.bignumber.equal(this.newGovernor.address);
});
runGovernorWorkflow();
});
});
});
const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
const { expect } = require('chai');
const Enums = require('../../helpers/enums');
const {
runGovernorWorkflow,
} = require('../GovernorWorkflow.behavior');
const {
shouldSupportInterfaces,
} = require('../../utils/introspection/SupportsInterface.behavior');
const Token = artifacts.require('ERC20VotesMock');
const Timelock = artifacts.require('TimelockController');
const Governor = artifacts.require('GovernorTimelockControlMock');
const CallReceiver = artifacts.require('CallReceiverMock');
contract('GovernorTimelockControl', function (accounts) {
const [ voter ] = accounts;
const name = 'OZ-Governor';
// const version = '1';
const tokenName = 'MockToken';
const tokenSymbol = 'MTKN';
const tokenSupply = web3.utils.toWei('100');
beforeEach(async function () {
const [ deployer ] = await web3.eth.getAccounts();
this.token = await Token.new(tokenName, tokenSymbol);
this.timelock = await Timelock.new(3600, [], []);
this.mock = await Governor.new(name, this.token.address, 4, 16, this.timelock.address, 0);
this.receiver = await CallReceiver.new();
// normal setup: governor is proposer, everyone is executor, timelock is its own admin
await this.timelock.grantRole(await this.timelock.PROPOSER_ROLE(), this.mock.address);
await this.timelock.grantRole(await this.timelock.EXECUTOR_ROLE(), constants.ZERO_ADDRESS);
await this.timelock.revokeRole(await this.timelock.TIMELOCK_ADMIN_ROLE(), deployer);
await this.token.mint(voter, tokenSupply);
await this.token.delegate(voter, { from: voter });
});
shouldSupportInterfaces([
'ERC165',
'Governor',
'GovernorTimelock',
]);
it('post deployment check', async function () {
expect(await this.mock.name()).to.be.equal(name);
expect(await this.mock.token()).to.be.equal(this.token.address);
expect(await this.mock.votingDelay()).to.be.bignumber.equal('4');
expect(await this.mock.votingPeriod()).to.be.bignumber.equal('16');
expect(await this.mock.quorum(0)).to.be.bignumber.equal('0');
expect(await this.mock.timelock()).to.be.equal(this.timelock.address);
});
describe('nominal', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 3600 },
},
};
});
afterEach(async function () {
const timelockid = await this.timelock.hashOperationBatch(
...this.settings.proposal.slice(0, 3),
'0x0',
this.descriptionHash,
);
expectEvent(
this.receipts.propose,
'ProposalCreated',
{ proposalId: this.id },
);
expectEvent(
this.receipts.queue,
'ProposalQueued',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
this.receipts.queue.transactionHash,
this.timelock,
'CallScheduled',
{ id: timelockid },
);
expectEvent(
this.receipts.execute,
'ProposalExecuted',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
this.receipts.execute.transactionHash,
this.timelock,
'CallExecuted',
{ id: timelockid },
);
await expectEvent.inTransaction(
this.receipts.execute.transactionHash,
this.receiver,
'MockFunctionCalled',
);
});
runGovernorWorkflow();
});
describe('executed by other proposer', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 3600 },
execute: { enable: false },
},
};
});
afterEach(async function () {
await this.timelock.executeBatch(
...this.settings.proposal.slice(0, 3),
'0x0',
this.descriptionHash,
);
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Executed);
await expectRevert(
this.mock.execute(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
});
runGovernorWorkflow();
});
describe('not queued', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { enable: false },
execute: { error: 'TimelockController: operation is not ready' },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded);
});
runGovernorWorkflow();
});
describe('to early', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
execute: { error: 'TimelockController: operation is not ready' },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Queued);
});
runGovernorWorkflow();
});
describe('re-queue / re-execute', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 3600 },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Executed);
await expectRevert(
this.mock.queue(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
await expectRevert(
this.mock.execute(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
});
runGovernorWorkflow();
});
describe('cancel before queue prevents scheduling', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { enable: false },
execute: { enable: false },
},
};
});
afterEach(async function () {
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Succeeded);
expectEvent(
await this.mock.cancel(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'ProposalCanceled',
{ proposalId: this.id },
);
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled);
await expectRevert(
this.mock.queue(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
});
runGovernorWorkflow();
});
describe('cancel after queue prevents execution', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 3600 },
execute: { enable: false },
},
};
});
afterEach(async function () {
const timelockid = await this.timelock.hashOperationBatch(
...this.settings.proposal.slice(0, 3),
'0x0',
this.descriptionHash,
);
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Queued);
const receipt = await this.mock.cancel(...this.settings.proposal.slice(0, -1), this.descriptionHash);
expectEvent(
receipt,
'ProposalCanceled',
{ proposalId: this.id },
);
await expectEvent.inTransaction(
receipt.receipt.transactionHash,
this.timelock,
'Cancelled',
{ id: timelockid },
);
expect(await this.mock.state(this.id)).to.be.bignumber.equal(Enums.ProposalState.Canceled);
await expectRevert(
this.mock.execute(...this.settings.proposal.slice(0, -1), this.descriptionHash),
'Governor: proposal not successful',
);
});
runGovernorWorkflow();
});
describe('updateTimelock', function () {
beforeEach(async function () {
this.newTimelock = await Timelock.new(3600, [], []);
});
it('protected', async function () {
await expectRevert(
this.mock.updateTimelock(this.newTimelock.address),
'Governor: onlyGovernance',
);
});
describe('using workflow', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.mock.address ],
[ web3.utils.toWei('0') ],
[ this.mock.contract.methods.updateTimelock(this.newTimelock.address).encodeABI() ],
'<proposal description>',
],
voters: [
{ voter: voter, support: Enums.VoteType.For },
],
steps: {
queue: { delay: 3600 },
},
};
});
afterEach(async function () {
expectEvent(
this.receipts.propose,
'ProposalCreated',
{ proposalId: this.id },
);
expectEvent(
this.receipts.execute,
'ProposalExecuted',
{ proposalId: this.id },
);
expectEvent(
this.receipts.execute,
'TimelockChange',
{ oldTimelock: this.timelock.address, newTimelock: this.newTimelock.address },
);
expect(await this.mock.timelock()).to.be.bignumber.equal(this.newTimelock.address);
});
runGovernorWorkflow();
});
});
});
const { BN, expectEvent, time } = require('@openzeppelin/test-helpers');
const Enums = require('../../helpers/enums');
const {
runGovernorWorkflow,
} = require('./../GovernorWorkflow.behavior');
const Token = artifacts.require('ERC20VotesMock');
const Governor = artifacts.require('GovernorMock');
const CallReceiver = artifacts.require('CallReceiverMock');
contract('GovernorVotesQuorumFraction', function (accounts) {
const [ owner, voter1, voter2, voter3, voter4 ] = accounts;
const name = 'OZ-Governor';
// const version = '1';
const tokenName = 'MockToken';
const tokenSymbol = 'MTKN';
const tokenSupply = new BN(web3.utils.toWei('100'));
const ratio = new BN(8); // percents
const newRatio = new BN(6); // percents
beforeEach(async function () {
this.owner = owner;
this.token = await Token.new(tokenName, tokenSymbol);
this.mock = await Governor.new(name, this.token.address, 4, 16, ratio);
this.receiver = await CallReceiver.new();
await this.token.mint(owner, tokenSupply);
await this.token.delegate(voter1, { from: voter1 });
await this.token.delegate(voter2, { from: voter2 });
await this.token.delegate(voter3, { from: voter3 });
await this.token.delegate(voter4, { from: voter4 });
});
it('deployment check', async function () {
expect(await this.mock.name()).to.be.equal(name);
expect(await this.mock.token()).to.be.equal(this.token.address);
expect(await this.mock.votingDelay()).to.be.bignumber.equal('4');
expect(await this.mock.votingPeriod()).to.be.bignumber.equal('16');
expect(await this.mock.quorum(0)).to.be.bignumber.equal('0');
expect(await this.mock.quorumNumerator()).to.be.bignumber.equal(ratio);
expect(await this.mock.quorumDenominator()).to.be.bignumber.equal('100');
expect(await time.latestBlock().then(blockNumber => this.mock.quorum(blockNumber.subn(1))))
.to.be.bignumber.equal(tokenSupply.mul(ratio).divn(100));
});
describe('quroum not reached', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.receiver.address ],
[ web3.utils.toWei('0') ],
[ this.receiver.contract.methods.mockFunction().encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: web3.utils.toWei('1'), support: Enums.VoteType.For },
],
steps: {
execute: { error: 'Governor: proposal not successful' },
},
};
});
runGovernorWorkflow();
});
describe('update quorum ratio through proposal', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.mock.address ],
[ web3.utils.toWei('0') ],
[ this.mock.contract.methods.updateQuorumNumerator(newRatio).encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: tokenSupply, support: Enums.VoteType.For },
],
};
});
afterEach(async function () {
await expectEvent.inTransaction(
this.receipts.execute.transactionHash,
this.mock,
'QuorumNumeratorUpdated',
{
oldQuorumNumerator: ratio,
newQuorumNumerator: newRatio,
},
);
expect(await this.mock.quorumNumerator()).to.be.bignumber.equal(newRatio);
expect(await this.mock.quorumDenominator()).to.be.bignumber.equal('100');
expect(await time.latestBlock().then(blockNumber => this.mock.quorum(blockNumber.subn(1))))
.to.be.bignumber.equal(tokenSupply.mul(newRatio).divn(100));
});
runGovernorWorkflow();
});
describe('update quorum over the maximum', function () {
beforeEach(async function () {
this.settings = {
proposal: [
[ this.mock.address ],
[ web3.utils.toWei('0') ],
[ this.mock.contract.methods.updateQuorumNumerator(new BN(101)).encodeABI() ],
'<proposal description>',
],
tokenHolder: owner,
voters: [
{ voter: voter1, weight: tokenSupply, support: Enums.VoteType.For },
],
steps: {
execute: { error: 'GovernorVotesQuorumFraction: quorumNumerator over quorumDenominator' },
},
};
});
runGovernorWorkflow();
});
});
const { BN } = require('@openzeppelin/test-helpers');
function Enum (...options) {
return Object.fromEntries(options.map((key, i) => [ key, new BN(i) ]));
}
module.exports = {
Enum,
ProposalState: Enum(
'Pending',
'Active',
'Canceled',
'Defeated',
'Succeeded',
'Queued',
'Expired',
'Executed',
),
VoteType: Enum(
'Against',
'For',
'Abstain',
),
};
const { BN, time } = require('@openzeppelin/test-helpers');
const { expect } = require('chai');
const TimersBlockNumberImpl = artifacts.require('TimersBlockNumberImpl');
contract('TimersBlockNumber', function (accounts) {
beforeEach(async function () {
this.instance = await TimersBlockNumberImpl.new();
this.now = await web3.eth.getBlock('latest').then(({ number }) => number);
});
it('unset', async function () {
expect(await this.instance.getDeadline()).to.be.bignumber.equal('0');
expect(await this.instance.isUnset()).to.be.equal(true);
expect(await this.instance.isStarted()).to.be.equal(false);
expect(await this.instance.isPending()).to.be.equal(false);
expect(await this.instance.isExpired()).to.be.equal(false);
});
it('pending', async function () {
await this.instance.setDeadline(this.now + 3);
expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now + 3));
expect(await this.instance.isUnset()).to.be.equal(false);
expect(await this.instance.isStarted()).to.be.equal(true);
expect(await this.instance.isPending()).to.be.equal(true);
expect(await this.instance.isExpired()).to.be.equal(false);
});
it('expired', async function () {
await this.instance.setDeadline(this.now - 3);
expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now - 3));
expect(await this.instance.isUnset()).to.be.equal(false);
expect(await this.instance.isStarted()).to.be.equal(true);
expect(await this.instance.isPending()).to.be.equal(false);
expect(await this.instance.isExpired()).to.be.equal(true);
});
it('reset', async function () {
await this.instance.reset();
expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(0));
expect(await this.instance.isUnset()).to.be.equal(true);
expect(await this.instance.isStarted()).to.be.equal(false);
expect(await this.instance.isPending()).to.be.equal(false);
expect(await this.instance.isExpired()).to.be.equal(false);
});
it('fast forward', async function () {
await this.instance.setDeadline(this.now + 3);
expect(await this.instance.isPending()).to.be.equal(true);
expect(await this.instance.isExpired()).to.be.equal(false);
await time.advanceBlockTo(this.now + 3);
expect(await this.instance.isPending()).to.be.equal(false);
expect(await this.instance.isExpired()).to.be.equal(true);
});
});
const { BN, time } = require('@openzeppelin/test-helpers');
const { expect } = require('chai');
const TimersTimestampImpl = artifacts.require('TimersTimestampImpl');
contract('TimersTimestamp', function (accounts) {
beforeEach(async function () {
this.instance = await TimersTimestampImpl.new();
this.now = await web3.eth.getBlock('latest').then(({ timestamp }) => timestamp);
});
it('unset', async function () {
expect(await this.instance.getDeadline()).to.be.bignumber.equal('0');
expect(await this.instance.isUnset()).to.be.equal(true);
expect(await this.instance.isStarted()).to.be.equal(false);
expect(await this.instance.isPending()).to.be.equal(false);
expect(await this.instance.isExpired()).to.be.equal(false);
});
it('pending', async function () {
await this.instance.setDeadline(this.now + 100);
expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now + 100));
expect(await this.instance.isUnset()).to.be.equal(false);
expect(await this.instance.isStarted()).to.be.equal(true);
expect(await this.instance.isPending()).to.be.equal(true);
expect(await this.instance.isExpired()).to.be.equal(false);
});
it('expired', async function () {
await this.instance.setDeadline(this.now - 100);
expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now - 100));
expect(await this.instance.isUnset()).to.be.equal(false);
expect(await this.instance.isStarted()).to.be.equal(true);
expect(await this.instance.isPending()).to.be.equal(false);
expect(await this.instance.isExpired()).to.be.equal(true);
});
it('reset', async function () {
await this.instance.reset();
expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(0));
expect(await this.instance.isUnset()).to.be.equal(true);
expect(await this.instance.isStarted()).to.be.equal(false);
expect(await this.instance.isPending()).to.be.equal(false);
expect(await this.instance.isExpired()).to.be.equal(false);
});
it('fast forward', async function () {
await this.instance.setDeadline(this.now + 100);
expect(await this.instance.isPending()).to.be.equal(true);
expect(await this.instance.isExpired()).to.be.equal(false);
await time.increaseTo(this.now + 100);
expect(await this.instance.isPending()).to.be.equal(false);
expect(await this.instance.isExpired()).to.be.equal(true);
});
});
...@@ -50,6 +50,30 @@ const INTERFACES = { ...@@ -50,6 +50,30 @@ const INTERFACES = {
'getRoleMember(bytes32,uint256)', 'getRoleMember(bytes32,uint256)',
'getRoleMemberCount(bytes32)', 'getRoleMemberCount(bytes32)',
], ],
Governor: [
'name()',
'version()',
'COUNTING_MODE()',
'hashProposal(address[],uint256[],bytes[],bytes32)',
'state(uint256)',
'proposalSnapshot(uint256)',
'proposalDeadline(uint256)',
'votingDelay()',
'votingPeriod()',
'quorum(uint256)',
'getVotes(address,uint256)',
'hasVoted(uint256,address)',
'propose(address[],uint256[],bytes[],string)',
'execute(address[],uint256[],bytes[],bytes32)',
'castVote(uint256,uint8)',
'castVoteWithReason(uint256,uint8,string)',
'castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)',
],
GovernorTimelock: [
'timelock()',
'proposalEta(uint256)',
'queue(address[],uint256[],bytes[],bytes32)',
],
}; };
const INTERFACE_IDS = {}; const INTERFACE_IDS = {};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment