logo
bg_imgbg_imgbg_imgbg_img
exclamation mark iconReport an issue

If you notice some outdated information please let us know!

close icon
Name
Email
Your message
arrow-left

Inverse Finance

24%

Previous versions

Process Quality Review (0.8)

Inverse Finance

Final score:24%
Date:10 Feb 2022
Audit Process:version 0.8
Author:Nick
PQR Score:49%

-25%(Penalty)

FAIL

Protocol Website:

Hack History

Date:15 Jun 2022
Details: Inverse lost $1.2 million to a floash loan attack. This is foreseeable. The TVL loss is minor at below 10%. At the moment, there is no plans for repayment though this may change soon. We will monitor the situation. This puts the penalty at 25%.
Reference Linklink
Date:02 Apr 2022
Details: On April 2nd, 2022, Inverse Finance was exploited for $15.6M via a complex mix of oracle and blockchain manipulations. Firstly, the exploiter withdrew 900 ETH from Tornado Cash. Secondly, the exploiter manipulated the TWAP (oracle) of both INV/ETH and DOLA/INV pools on SushiSwap by providing high liquidity (500 ETH) to the low-liquidity INV/ETH pool. Providing high liquidity to the low-liquidity pool massively inflated the price of INV, which the Keeper TWAP happily reported. Normally, this tactic alone would not result in the TWAP reporting an inflated price into the next block. However, this is where the second part of the exploit comes in. Following the attacker's 500 ETH deposit into the INV/ETH pool, the exploiter used the remaining previously dispersed 400 ETH (1.5 ETH dispersed amongst 241 addresses, while also deploying 5 different contracts with only 1 being real) to spam the network with transactions. This spamming greatly confused arbitrage bots and MEV searches because they did not know which transaction to kill. Therefore, the inflated price of the Sushiswap INV/ETH pair successfully made it to the next block, and became the in-effect price. Finally, the exploiter took his price-inflated INV to Anchor, where they subsequently withdrew INV-backed loans. Stolen assets through this loan include: 1,588 ETH, 94 WBTC, 39 YFI and 3,999,669 DOLA. In total, $15.6M. By converting the DOLA to ETH, the exploiter also successfully manipulated the DOLA/USD peg which further inhibited the arbitrageurs' efforts. This is a major TVL loss but an unforseen attack vector. A repayment plan is in place. 10% penalty.
Reference Linklink

Scoring Appendix

The final review score is indicated as a percentage. The percentage is calculated as Achieved Points due to MAX Possible Points. For each element the answer can be either Yes/No or a percentage. For a detailed breakdown of the individual weights of each question, please consult this document.

The blockchain used by this protocol
Ethereum
#QuestionAnswer
82%
1.100%
2.70%
3.Yes
4.70%
5.50
94%
6.Yes
7.Yes
8.100%
9.60%
20%
10.0%
11.0%
12.Yes
13.0%
14.No
15.Yes
17%
16.20%
17.0%
71%
18.100%
19.0%
20.100%
21.100%
22.90%
23.0%
24.100%
25.100%
25%
26.50%
27.No
28.No
Total:49%

Very simply, the audit looks for the following declarations from the developer's site. With these declarations, it is reasonable to trust the smart contracts.

  • Here is my smart contract on the blockchain
  • You can see it matches a software repository used to develop the code
  • Here is the documentation that explains what my smart contract does
  • Here are the tests I ran to verify my smart contract
  • Here are the audit(s) performed to review my code by third party experts

This report is for informational purposes only and does not constitute investment advice of any kind, nor does it constitute an offer to provide investment advisory or other services. Nothing in this report shall be considered a solicitation or offer to buy or sell any security, token, future, option or other financial instrument or to offer or provide any investment advice or service to any person in any jurisdiction. Nothing contained in this report constitutes investment advice or offers any opinion with respect to the suitability of any security, and the views expressed in this report should not be taken as advice to buy, sell or hold any security. The information in this report should not be relied upon for the purpose of investing. In preparing the information contained in this report, we have not taken into account the investment needs, objectives and financial circumstances of any particular investor. This information has no regard to the specific investment objectives, financial situation and particular needs of any specific recipient of this information and investments discussed may not be suitable for all investors.

Any views expressed in this report by us were prepared based upon the information available to us at the time such views were written. The views expressed within this report are limited to DeFiSafety and the author and do not reflect those of any additional or third party and are strictly based upon DeFiSafety, its authors, interpretations and evaluation of relevant data. Changed or additional information could cause such views to change. All information is subject to possible correction. Information may quickly become unreliable for various reasons, including changes in market conditions or economic circumstances.

This completed report is copyright (c) DeFiSafety 2021. Permission is given to copy in whole, retaining this copyright label.

Smart Contracts & Team

82%

This section looks at the code deployed on the relevant chain that gets reviewed and its corresponding software repository. The document explaining these questions is here.

1. Are the smart contract addresses easy to find?(%)

Answer: 100%

Smart contracts are easy to find.

Percentage Score Guidance:
100%
Clearly labelled and on website, documents or repository, quick to find
70%
Clearly labelled and on website, docs or repo but takes a bit of looking
40%
Addresses in mainnet.json, in discord or sub graph, etc
20%
Address found but labeling not clear or easy to find
0%
Executing addresses could not be found

2. How active is the primary contract? (%)

Answer: 70%

The primary deployer contract is relatively active at more than 10 transactions a week.

Percentage Score Guidance:
100%
More than 10 transactions a day
70%
More than 10 transactions a week
40%
More than 10 transactions a month
10%
Less than 10 transactions a month
0%
No activity

3. Does the protocol have a public software repository? (Y/N)

Answer: Yes

Inverse has a GitHub.

Score Guidance:
Yes
There is a public software repository with the code at a minimum, but also normally test and scripts. Even if the repository was created just to hold the files and has just 1 transaction.
No
For teams with private repositories.

4. Is there a development history visible? (%)

Answer: 70%

At 92 commits and three branches, Inverse is just a few commits away from letting users turn their development history inside out

Percentage Score Guidance:
100%
Any one of 100+ commits, 10+branches
70%
Any one of 70+ commits, 7+branches
50%
Any one of 50+ commits, 5+branches
30%
Any one of 30+ commits, 3+branches
0%
Less than 2 branches or less than 30 commits

5. Is the team public (not anonymous)? (Y/N)

Answer: 50

One public GitHub contributor was found, and he confirms that he works at Inverse. Other public members were not found. 50%

Score Guidance:
100%
At least two names can be easily found in the protocol's website, documentation or medium. These are then confirmed by the personal websites of the individuals / their linkedin / twitter.
50%
At least one public name can be found to be working on the protocol.
0%
No public team members could be found.

Documentation

94%

The difference between this and the old link is solely the link.    This section looks at the software documentation. The document explaining these questions is here.

6. Is there a whitepaper? (Y/N)

Answer: Yes

Inverse has a whitepaper.

7. Is the protocol's software architecture documented? (Y/N)

Answer: Yes

There is software architecture documentation at https://docs.inverse.finance/user-guides/anchor-lending-and-borrowing/developer-guide.

Score Guidance:
Yes
The documents identify software architecture and contract interaction through any of the following: diagrams, arrows, specific reference to software functions or a written explanation on how smart contracts interact.
No
Protocols receive a "no" if none of these are included.

8. Does the software documentation fully cover the deployed contracts' source code? (%)

Answer: 100%

Software function documentation is covers by all contracts.

Percentage Score Guidance:
100%
All contracts and functions documented
80%
Only the major functions documented
79 - 1%
Estimate of the level of software documentation
0%
No software documentation

9. Is it possible to trace the documented software to its implementation in the protocol's source code? (%)

Answer: 60%

There is no traceability in Inverse documentation. The documentation lists the functions, and there is strong association with the code.

Percentage Score Guidance:
100%
Clear explicit traceability between code and documentation at a requirement level for all code
60%
Clear association between code and documents via non explicit traceability
40%
Documentation lists all the functions and describes their functions
0%
No connection between documentation and code

Testing

20%

10. Has the protocol tested their deployed code? (%)

Answer: 0%

At a 15% TtC, this protocol has not documented sufficient testing.

Percentage Score Guidance:
100%
TtC > 120% Both unit and system test visible
80%
TtC > 80% Both unit and system test visible
40%
TtC < 80% Some tests visible
0%
No tests obvious

11. How covered is the protocol's code? (%)

Answer: 0%

No code coverage report was found.

Percentage Score Guidance:
100%
Documented full coverage
99 - 51%
Value of test coverage from documented results
50%
No indication of code coverage but clearly there is a complete set of tests
30%
Some tests evident but not complete
0%
No test for coverage seen

12. Does the protocol provide scripts and instructions to run their tests? (Y/N)

Answer: Yes

Scripts are provided at https://github.com/InverseFinance/inverse-protocol/tree/main/scripts.

Score Guidance:
Yes
Scripts and/or instructions to run tests are available in the testing suite
No
Scripts and/or instructions to run tests are not available in the testing suite

13. Is there a detailed report of the protocol's test results?(%)

Answer: 0%

There is no report.

Percentage Score Guidance:
100%
Detailed test report as described below
70%
GitHub code coverage report visible
0%
No test report evident

14. Has the protocol undergone Formal Verification? (Y/N)

Answer: No

No formal verification has taken place.

Score Guidance:
Yes
Formal Verification was performed and the report is readily available
No
Formal Verification was not performed and/or the report is not readily available.

15. Were the smart contracts deployed to a testnet? (Y/N)

Answer: Yes

There is evidence of Kovan testnet deployment at https://github.com/InverseFinance/vesting-contracts/blob/main/deployment/constants-kovan.json.

Score Guidance:
Yes
Protocol has proved their tesnet usage by providing the addresses
No
Protocol has not proved their testnet usage by providing the addresses

Security

17%

This section looks at the 3rd party software audits done. It is explained in this document.

16. Is the protocol sufficiently audited? (%)

Answer: 20%

No documented audits were found.

Percentage Score Guidance:
100%
Multiple Audits performed before deployment and the audit findings are public and implemented or not required
90%
Single audit performed before deployment and audit findings are public and implemented or not required
70%
Audit(s) performed after deployment and no changes required. The Audit report is public.
65%
Code is forked from an already audited protocol and a changelog is provided explaining why forked code was used and what changes were made. This changelog must justify why the changes made do not affect the audit.
50%
Audit(s) performed after deployment and changes are needed but not implemented.
30%
Audit(s) performed are low-quality and do not indicate proper due diligence.
20%
No audit performed
0%
Audit Performed after deployment, existence is public, report is not public OR smart contract address' not found.
Deduct 25% if the audited code is not available for comparison.

17. Is the bounty value acceptably high (%)

Answer: 0%

No bug bounty is offered.

Percentage Score Guidance:
100%
Bounty is 10% TVL or at least $1M AND active program (see below)
90%
Bounty is 5% TVL or at least 500k AND active program
80%
Bounty is 5% TVL or at least 500k
70%
Bounty is 100k or over AND active program
60%
Bounty is 100k or over
50%
Bounty is 50k or over AND active program
40%
Bounty is 50k or over
20%
Bug bounty program bounty is less than 50k
0%
No bug bounty program offered / the bug bounty program is dead
An active program means that a third party (such as Immunefi) is actively driving hackers to the site. An inactive program would be static mentions on the docs.

Admin Controls

71%

This section covers the documentation of special access controls for a DeFi protocol. The admin access controls are the contracts that allow updating contracts or coefficients in the protocol. Since these contracts can allow the protocol admins to "change the rules", complete disclosure of capabilities is vital for user's transparency. It is explained in this document.

18. Is the protocol's admin control information easy to find?

Answer: 100%

The admin control information is documented.

Percentage Score Guidance:
100%
Admin Controls are clearly labelled and on website, docs or repo, quick to find
70%
Admin Controls are clearly labelled and on website, docs or repo but takes a bit of looking
40%
Admin Control docs are in multiple places and not well labelled
20%
Admin Control docs are in multiple places and not labelled
0%
Admin Control information could not be found

19. Are relevant contracts clearly labelled as upgradeable or immutable? (%)

Answer: 0%

No relevant contracts are labelled.

Percentage Score Guidance:
100%
Both the contract documentation and the smart contract code state that the code is not upgradeable or immutable.
80%
All Contracts are clearly labelled as upgradeable (or not)
50%
Code is immutable but not mentioned anywhere in the documentation
0%
Admin control information could not be found

20. Is the type of smart contract ownership clearly indicated? (%)

Answer: 100%

The DAO is in control, and this is evident.

Percentage Score Guidance:
100%
The type of ownership is clearly indicated in their documentation. (OnlyOwner / MultiSig / etc)
50%
The type of ownership is indicated, but only in the code. (OnlyOwner / MultiSig / etc)
0%
Admin Control information could not be found

21. Are the protocol's smart contract change capabilities described? (%)

Answer: 100%

Full change capability is identified.

Percentage Score Guidance:
100%
The documentation covers the capabilities for change for all smart contracts
50%
The documentation covers the capabilities for change in some, but not all contracts
0%
The documentation does not cover the capabilities for change in any contract

22. Is the protocol's admin control information easy to understand? (%)

Answer: 90%

This information is in very straightforward language.

Percentage Score Guidance:
100%
All the contracts are immutable
90%
Description relates to investments safety in clear non-software language
30%
Description all in software-specific language
0%
No admin control information could be found

23. Is there sufficient Pause Control documentation? (%)

Answer: 0%

There is no pause control documentation.

Percentage Score Guidance:
100%
Pause control(s) are clearly documented and there is records of at least one test within 3 months
80%
Pause control(s) explained clearly but no evidence of regular tests
40%
Pause controls mentioned with no detail on capability or tests
0%
Pause control not documented or explained

24. Is there sufficient Timelock documentation? (%)

Answer: 100%

Although there is no timelock documentation, Inverse's DAO voting periods and delay queue effectively act as a Timelock. Information can be found at https://docs.inverse.finance/inverse-finance/governance/inverse-dao.

Percentage Score Guidance:
100%
Documentation identifies and explains why the protocol does not need a Timelock OR Timelock documentation identifies its duration, which contracts it applies to and justifies this time period.
60%
A Timelock is identified and its duration is specified
30%
A Timelock is identified
0%
No Timelock information was documented

25. Is the Timelock of an adequate length? (Y/N)

Answer: 100%

Inverse Protocol's "timelock" includes a 2-day lockup period post-vote.

Percentage Score Guidance:
100%
Timelock is between 48 hours to 1 week OR justification as to why no Timelock is needed / is outside this length.
50%
Timelock is less than 48 hours or greater than 1 week.
0%
No Timelock information was documented OR no timelock length was identified.

Oracles

25%

This section goes over the documentation that a protocol may or may not supply about their Oracle usage. Oracles are a fundamental part of DeFi as they are responsible for relaying tons of price data information to thousands of protocols using blockchain technology. Not only are they important for price feeds, but they are also an essential component of transaction verification and security. This is explained in this document.

26. Is the protocol's Oracle sufficiently documented? (%)

Answer: 50%

There is good oracle documentation.

Percentage Score Guidance:
100%
If it uses one, the Oracle is specified. The contracts dependent on the oracle are identified. Basic software functions are identified (if the protocol provides its own price feed data). Timeframe of price feeds are identified. OR The reason as to why the protocol does not use an Oracle is identified and explained.
75%
The Oracle documentation identifies both source and timeframe, but does not provide additional context regarding smart contracts.
50%
Only the Oracle source is identified.
0%
No oracle is named / no oracle information is documented.

27. Is front running mitigated by this protocol? (Y/N)

Answer: No

No front-running countermeasures are documented.

Score Guidance:
Yes
The protocol cannot be front run and there is an explanation as to why OR documented front running countermeasures are implemented.
No
The Oracle documentation identifies both source and timeframe, but does not provide additional context regarding smart contracts.

28. Can flashloan attacks be applied to the protocol, and if so, are those flashloan attack risks mitigated? (Y/N)

Answer: No

No flashloan countermeasures are documented.

Score Guidance:
Yes
The protocol's documentation includes information on how they mitigate the possibilities and extents of flash loan attacks.
No
The protocol's documentation does not include any information regarding the mitigation of flash loan attacks.

Appendices

1pragma solidity ^0.5.16;
2pragma experimental ABIEncoderV2;
3
4interface InvInterface {
5    function getPriorVotes(address account, uint blockNumber) external view returns (uint96);
6    function totalSupply() external view returns (uint256);
7}
8
9interface XinvInterface {
10    function getPriorVotes(address account, uint blockNumber) external view returns (uint96);
11    function totalSupply() external view returns (uint256);
12    function exchangeRateCurrent() external returns (uint);
13}
14
15interface TimelockInterface {
16    function delay() external view returns (uint);
17    function GRACE_PERIOD() external view returns (uint);
18    function setDelay(uint256 delay_) external;
19    function acceptAdmin() external;
20    function setPendingAdmin(address pendingAdmin_) external;
21    function queuedTransactions(bytes32 hash) external view returns (bool);
22    function queueTransaction(address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta) external returns (bytes32);
23    function cancelTransaction(address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta) external;
24    function executeTransaction(address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta) external returns (bytes memory);
25}
26
27contract GovernorMills {
28    /// @notice The name of this contract
29    string public constant name = "Inverse Governor Mills";
30
31    /// @notice The maximum number of actions that can be included in a proposal
32    function proposalMaxOperations() public pure returns (uint) { return 20; } // 20 actions
33
34    /// @notice The delay before voting on a proposal may take place, once proposed
35    function votingDelay() public pure returns (uint) { return 1; } // 1 block
36
37    /// @notice The duration of voting on a proposal, in blocks
38    function votingPeriod() public pure returns (uint) { return 17280; } // ~3 days in blocks (assuming 15s blocks)
39
40    /// @notice The address of the Protocol Timelock
41    TimelockInterface public timelock;
42
43    /// @notice The address of the governance token A
44    InvInterface public inv;
45
46    /// @notice The address of the governance token B
47    XinvInterface public xinv;
48
49    /// @notice The total number of proposals
50    uint256 public proposalCount;
51
52    /// @notice The guardian
53    address public guardian;
54
55    /// @notice proposal threshold
56    uint256 public proposalThreshold = 1000 ether; // 1k INV
57
58    /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed
59    uint256 public quorumVotes = 4000 ether; // 4k INV
60
61    struct Proposal {
62        /// @notice Unique id for looking up a proposal
63        uint id;
64
65        /// @notice Creator of the proposal
66        address proposer;
67
68        /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds
69        uint eta;
70
71        /// @notice the ordered list of target addresses for calls to be made
72        address[] targets;
73
74        /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made
75        uint[] values;
76
77        /// @notice The ordered list of function signatures to be called
78        string[] signatures;
79
80        /// @notice The ordered list of calldata to be passed to each call
81        bytes[] calldatas;
82
83        /// @notice The block at which voting begins: holders must delegate their votes prior to this block
84        uint startBlock;
85
86        /// @notice The block at which voting ends: votes must be cast prior to this block
87        uint endBlock;
88
89        /// @notice Current number of votes in favor of this proposal
90        uint forVotes;
91
92        /// @notice Current number of votes in opposition to this proposal
93        uint againstVotes;
94
95        /// @notice Flag marking whether the proposal has been canceled
96        bool canceled;
97
98        /// @notice Flag marking whether the proposal has been executed
99        bool executed;
100
101        /// @notice Receipts of ballots for the entire set of voters
102        mapping (address => Receipt) receipts;
103    }
104
105    /// @notice Ballot receipt record for a voter
106    struct Receipt {
107        /// @notice Whether or not a vote has been cast
108        bool hasVoted;
109
110        /// @notice Whether or not the voter supports the proposal
111        bool support;
112
113        /// @notice The number of votes the voter had, which were cast
114        uint96 votes;
115    }
116
117    /// @notice Possible states that a proposal may be in
118    enum ProposalState {
119        Pending,
120        Active,
121        Canceled,
122        Defeated,
123        Succeeded,
124        Queued,
125        Expired,
126        Executed
127    }
128
129    /// @notice The official record of all proposals ever proposed
130    mapping (uint => Proposal) public proposals;
131
132    /// @notice The latest proposal for each proposer
133    mapping (address => uint) public latestProposalIds;
134
135    /// @notice Addresses that can propose without voting power
136    mapping (address => bool) public proposerWhitelist;
137
138    /// @notice proposal id => xinv.exchangeRateCurrent
139    mapping (uint => uint) public xinvExchangeRates;
140
141    /// @notice The EIP-712 typehash for the contract's domain
142    bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
143
144    /// @notice The EIP-712 typehash for the ballot struct used by the contract
145    bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,bool support)");
146
147    /// @notice An event emitted when a new proposal is created
148    event ProposalCreated(uint id, address proposer, address[] targets, uint[] values, string[] signatures, bytes[] calldatas, uint startBlock, uint endBlock, string description);
149
150    /// @notice An event emitted when a vote has been cast on a proposal
151    event VoteCast(address voter, uint proposalId, bool support, uint votes);
152
153    /// @notice An event emitted when a proposal has been canceled
154    event ProposalCanceled(uint id);
155
156    /// @notice An event emitted when a proposal has been queued in the Timelock
157    event ProposalQueued(uint id, uint eta);
158
159    /// @notice An event emitted when a proposal has been executed in the Timelock
160    event ProposalExecuted(uint id);
161
162    /// @notice An event emitted when a new guardian has been set
163    event NewGuardian(address guardian);
164
165    /// @notice An event emitted when proposal threshold is updated
166    event ProposalThresholdUpdated(uint256 oldThreshold, uint256 newThreshold);
167
168    /// @notice An event emitted when proposal quorum is updated
169    event QuorumUpdated(uint256 oldQuorum, uint256 newQuorum);
170
171    /// @notice An event emitted when an address is added or removed from the proposer whitelist
172    event ProposerWhitelistUpdated(address proposer, bool value);
173
174    constructor(TimelockInterface timelock_, InvInterface inv_, XinvInterface xinv_) public {
175        timelock = timelock_;
176        inv = inv_;
177        xinv = xinv_;
178        guardian = msg.sender;
179    }
180
181    function _getPriorVotes(address _proposer, uint256 _blockNumber, uint256 _exchangeRate) internal view returns (uint96) {
182        uint96 invPriorVotes = inv.getPriorVotes(_proposer, _blockNumber);
183        uint96 xinvPriorVotes = uint96(
184            (
185                uint256(
186                    xinv.getPriorVotes(_proposer, _blockNumber)
187                ) * _exchangeRate
188            ) / 1 ether
189        );
190        
191        return add96(invPriorVotes, xinvPriorVotes);
192    }
193
194    function setGuardian(address _newGuardian) public {
195        require(msg.sender == guardian, "GovernorMills::setGuardian: only guardian");
196        guardian = _newGuardian;
197        
198        emit NewGuardian(guardian);
199    }
200
201    /**
202     * @notice Add new pending admin to queue
203     * @param newPendingAdmin The new admin
204     * @param eta ETA
205     */
206    function __queueSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {
207        require(msg.sender == guardian, "GovernorMills::__queueSetTimelockPendingAdmin: only guardian");
208        timelock.queueTransaction(address(timelock), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta);
209    }
210
211    function __executeSetTimelockPendingAdmin(address newPendingAdmin, uint256 eta) public {
212        require(msg.sender == guardian, "GovernorMills::__executeSetTimelockPendingAdmin: only guardian");
213        timelock.executeTransaction(address(timelock), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta);
214    }
215
216    function propose(address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas, string memory description) public returns (uint) {
217        require(_getPriorVotes(msg.sender, sub256(block.number, 1), xinv.exchangeRateCurrent()) > proposalThreshold || proposerWhitelist[msg.sender], "GovernorMills::propose: proposer votes below proposal threshold");
218        require(targets.length == values.length && targets.length == signatures.length && targets.length == calldatas.length, "GovernorMills::propose: proposal function information arity mismatch");
219        require(targets.length != 0, "GovernorMills::propose: must provide actions");
220        require(targets.length <= proposalMaxOperations(), "GovernorMills::propose: too many actions");
221
222        uint latestProposalId = latestProposalIds[msg.sender];
223        if (latestProposalId != 0) {
224          ProposalState proposersLatestProposalState = state(latestProposalId);
225          require(proposersLatestProposalState != ProposalState.Active, "GovernorMills::propose: one live proposal per proposer, found an already active proposal");
226          require(proposersLatestProposalState != ProposalState.Pending, "GovernorMills::propose: one live proposal per proposer, found an already pending proposal");
227        }
228
229        uint startBlock = add256(block.number, votingDelay());
230        uint endBlock = add256(startBlock, votingPeriod());
231
232        proposalCount++;
233        Proposal memory newProposal = Proposal({
234            id: proposalCount,
235            proposer: msg.sender,
236            eta: 0,
237            targets: targets,
238            values: values,
239            signatures: signatures,
240            calldatas: calldatas,
241            startBlock: startBlock,
242            endBlock: endBlock,
243            forVotes: 0,
244            againstVotes: 0,
245            canceled: false,
246            executed: false
247        });
248
249        proposals[newProposal.id] = newProposal;
250        xinvExchangeRates[newProposal.id] = xinv.exchangeRateCurrent();
251        latestProposalIds[newProposal.proposer] = newProposal.id;
252
253        emit ProposalCreated(newProposal.id, msg.sender, targets, values, signatures, calldatas, startBlock, endBlock, description);
254        return newProposal.id;
255    }

JavaScript Tests

Language
Files
Lines
Blanks
Comments
Testing Code
Deployed Code
Complexity
JavaScript
1
99
14
2
83
544
0

Tests to Code: 83 / 544 = 15 %