@@ -56,6 +56,7 @@ contract XanV1 is
5656    error UnlockedBalanceInsufficient  (address  sender , uint256  unlockedBalance , uint256  valueToLock );
5757    error LockedBalanceInsufficient  (address  sender , uint256  lockedBalance );
5858    error NoVotesToRevoke  (address  sender , address  proposedImpl );
59+ 
5960    error ImplementationZero  ();
6061    error ImplementationAlreadyProposed  (address  impl );
6162    error ImplementationRankNonExistent  (uint48  limit , uint48  rank );
@@ -67,10 +68,8 @@ contract XanV1 is
6768    error UpgradeCancellationInvalid  (address  impl , uint48  endTime );
6869    error UpgradeIsNotAllowedToBeScheduledTwice  (address  impl );
6970
70-     error MinLockedSupplyNotReached  ();
71-     error QuorumNowhereReached  ();
72-     error QuorumNotReached  (address  impl );
73-     error QuorumReached  (address  impl );
71+     error QuorumOrMinLockedSupplyNotReached  (address  impl );
72+     error QuorumAndMinLockedSupplyReached  (address  impl );
7473
7574    error DelayPeriodNotStarted  (uint48  endTime );
7675    error DelayPeriodNotEnded  (uint48  endTime );
@@ -192,16 +191,11 @@ contract XanV1 is
192191            revert  UpgradeAlreadyScheduled (votingData.scheduledImpl, votingData.scheduledEndTime);
193192        }
194193
195-         // Check if the minimal locked supply is reached. 
196-         if  (! _isMinLockedSupplyReached ()) {
197-             revert  MinLockedSupplyNotReached ();
198-         }
199- 
200194        // Check if the proposed implementation is the best ranked implementation 
201195        {
202-             address  bestRankedVoterBodyImpl =  votingData.ranking[ 0 ] ;
203-             if  (! _isQuorumReached (bestRankedVoterBodyImpl)) {
204-                 revert  QuorumNotReached (bestRankedVoterBodyImpl);
196+             address  bestRankedVoterBodyImpl =  votingData.implementationByRank ( 0 ) ;
197+             if  (! _isQuorumAndMinLockedSupplyReached (bestRankedVoterBodyImpl)) {
198+                 revert  QuorumOrMinLockedSupplyNotReached (bestRankedVoterBodyImpl);
205199            }
206200
207201            // Schedule the upgrade and emit the associated event. 
@@ -230,8 +224,14 @@ contract XanV1 is
230224
231225        // TODO! check min quorum 
232226
233-         // Check that the quorum for the new implementation is reached. 
234-         if  (_isQuorumReached (data.scheduledImpl) &&  data.scheduledImpl ==  data.ranking[0 ]) {
227+         // Revert the cancellation if the currently scheduled implementation still 
228+         // * meets the quorum and minimum locked supply for the 
229+         // * is the best ranked implementation 
230+         // and revert the cancellation if this is the case. 
231+         if  (
232+             _isQuorumAndMinLockedSupplyReached (data.scheduledImpl)
233+                 &&  (data.scheduledImpl ==  data.implementationByRank (0 ))
234+         ) {
235235            revert  UpgradeCancellationInvalid (data.scheduledImpl, data.scheduledEndTime);
236236        }
237237
@@ -243,26 +243,27 @@ contract XanV1 is
243243    }
244244
245245    /// @notice @inheritdoc IXanV1 
246-     function scheduleCouncilUpgrade  (address  proposedImpl ) external  override  onlyCouncil {
247-         // TODO! replace by `isAcceptedVoterBodyUpgrade`  
246+     function scheduleCouncilUpgrade  (address  impl ) external  override  onlyCouncil {
247+         // Check if a voter body upgrade could be scheduled.  
248248        {
249249            Voting.Data storage  votingData =  _getVotingData ();
250250
251-             address  bestRankedVoterBodyImpl =  votingData.ranking[ 0 ] ;
251+             address  bestRankedVoterBodyImpl =  votingData.implementationByRank ( 0 ) ;
252252
253-             if  (_isQuorumReached (bestRankedVoterBodyImpl)  &&   _isMinLockedSupplyReached ( )) {
254-                 revert  QuorumReached (bestRankedVoterBodyImpl);
253+             if  (_isQuorumAndMinLockedSupplyReached (bestRankedVoterBodyImpl)) {
254+                 revert  QuorumAndMinLockedSupplyReached (bestRankedVoterBodyImpl);
255255            }
256-             // TODO! add min quorum check 
257256        }
258257
259258        Council.Data storage  data =  _getCouncilData ();
260259
261-         if  (data.scheduledImpl ==  proposedImpl) {
262-             revert  ImplementationAlreadyProposed (proposedImpl);
260+         // Check if the council upgrade is already scheduled 
261+         if  (data.scheduledImpl !=  address (0 ) &&  data.scheduledEndTime !=  0 ) {
262+             revert  UpgradeAlreadyScheduled (data.scheduledImpl, data.scheduledEndTime);
263263        }
264264
265-         data.scheduledImpl =  proposedImpl;
265+         // Schedule the council upgrade 
266+         data.scheduledImpl =  impl;
266267        data.scheduledEndTime =  Time.timestamp () +  Parameters.DELAY_DURATION;
267268
268269        emit  CouncilUpgradeScheduled (data.scheduledImpl, data.scheduledEndTime);
@@ -276,14 +277,17 @@ contract XanV1 is
276277
277278    /// @notice @inheritdoc IXanV1 
278279    function vetoCouncilUpgrade  () external  override  {
279-         // Get the implementation with the most votes. 
280-         address  mostVotedImplementation =  _getVotingData ().ranking[0 ];
280+         // Get the best ranked implementation. 
281+         address  bestRankedImplementation =  _getVotingData ().implementationByRank (0 );
282+         if  (bestRankedImplementation ==  address (0 )) {
283+             revert  ImplementationRankNonExistent ({limit: 0 , rank: 0 });
284+         }
281285
282286        // Check if the most voted implementation has reached quorum. 
283-         if  (! _isQuorumReached (mostVotedImplementation )) {
287+         if  (! _isQuorumAndMinLockedSupplyReached (bestRankedImplementation )) {
284288            // The voter body has not reached quorum on any implementation. 
285-             // This means that vetoing the council is not possible . 
286-             revert  QuorumNowhereReached ( );
289+             // This means that vetoing the council is not allowed . 
290+             revert  QuorumOrMinLockedSupplyNotReached (bestRankedImplementation );
287291        }
288292
289293        emit  CouncilUpgradeVetoed ();
@@ -297,6 +301,16 @@ contract XanV1 is
297301        votes =  _getVotingData ().ballots[proposedImpl].vota[msg .sender ];
298302    }
299303
304+     /// @notice @inheritdoc IXanV1 
305+     function proposedImplementationByRank  (uint48  rank ) external  view  override  returns  (address  impl ) {
306+         Voting.Data storage  data =  _getVotingData ();
307+ 
308+         impl =  data.implementationByRank (rank);
309+         if  (impl ==  address (0 )) {
310+             revert  ImplementationRankNonExistent ({limit: data.implCount, rank: rank});
311+         }
312+     }
313+ 
300314    /// @notice @inheritdoc IXanV1 
301315    function lockedSupply  () public  view  override  returns  (uint256  locked ) {
302316        locked =  _getLockingData ().lockedSupply;
@@ -317,18 +331,6 @@ contract XanV1 is
317331        thisImplementation =  ERC1967Utils .getImplementation ();
318332    }
319333
320-     /// @notice @inheritdoc IXanV1 
321-     function proposedImplementationByRank  (uint48  rank ) public  view  override  returns  (address  rankedImplementation ) {
322-         Voting.Data storage  $ =  _getVotingData ();
323-         uint48  implCount =  $.implCount;
324- 
325-         if  (implCount ==  0  ||  rank >  implCount -  1 ) {
326-             revert  ImplementationRankNonExistent ({limit: implCount, rank: rank});
327-         }
328- 
329-         rankedImplementation =  $.ranking[rank];
330-     }
331- 
332334    /// @inheritdoc IXanV1 
333335    function scheduledVoterBodyUpgrade  () public  view  override  returns  (address  impl , uint48  endTime ) {
334336        Voting.Data storage  data =  _getVotingData ();
@@ -420,37 +422,26 @@ contract XanV1 is
420422            revert  UpgradeIsNotAllowedToBeScheduledTwice (newImpl);
421423        }
422424
423-         address  bestRankedVoterBodyImpl =  votingData.ranking[ 0 ] ;
425+         address  bestRankedVoterBodyImpl =  votingData.implementationByRank ( 0 ) ;
424426
425427        if  (isScheduledByVoterBody) {
426428            if  (newImpl !=  bestRankedVoterBodyImpl) {
427429                revert  ImplementationNotRankedBest ({expected: bestRankedVoterBodyImpl, actual: newImpl});
428430            }
429431
430-             if  (! _isMinLockedSupplyReached ()) {
431-                 revert  MinLockedSupplyNotReached ();
432-             }
433-             // TODO combine `_isMinLockedSupplyReached` with the check below? 
434-             // NOTE: It should not be possible to schedule an implementation without minLockedSupply 
435-             // Check that the quorum for the new implementation is reached. 
436-             if  (! _isQuorumReached (bestRankedVoterBodyImpl)) {
437-                 revert  QuorumNotReached (bestRankedVoterBodyImpl);
432+             if  (! _isQuorumAndMinLockedSupplyReached (bestRankedVoterBodyImpl)) {
433+                 revert  QuorumOrMinLockedSupplyNotReached (bestRankedVoterBodyImpl);
438434            }
439- 
440435            _checkDelayCriterion ({endTime: votingData.scheduledEndTime});
441-             //_checkVoterBodyUpgradeCriteria({bestRankedVoterBodyImpl: bestRankedVoterBodyImpl}); 
442436
443437            return ;
444438        }
445439
446440        if  (isScheduledByCouncil) {
447-             // there cannot be ANY accepted voter body upgrade 
448-             // TODO! 
449- 
450-             // Revert if the quorum is reached for the 
451-             if  (_isQuorumReached (bestRankedVoterBodyImpl) &&  _isMinLockedSupplyReached ()) {
452-                 // TODO! better error name 
453-                 revert  QuorumReached (bestRankedVoterBodyImpl);
441+             // Revert if the quorum and minimum locked supply is reached for best ranked implementation proposed by 
442+             // the voter body. 
443+             if  (_isQuorumAndMinLockedSupplyReached (bestRankedVoterBodyImpl)) {
444+                 revert  QuorumAndMinLockedSupplyReached (bestRankedVoterBodyImpl);
454445            }
455446
456447            _checkDelayCriterion ({endTime: councilData.scheduledEndTime});
@@ -468,17 +459,17 @@ contract XanV1 is
468459        }
469460    }
470461
471-     /// @notice Returns `true` if the quorum is reached for a given mplementation. 
462+     /// @notice Returns `true` if the quorum and minimum locked supply  is reached for a given mplementation. 
472463    /// @param impl The implementation to check the quorum criteria for. 
473-     /// @return isReached Whether the quorum is reached or not. 
474-     function _isQuorumReached   (address  impl ) internal  view  returns  (bool  isReached ) {
475-         isReached  =   totalVotes (impl) >  calculateQuorumThreshold (); 
476-     } 
477- 
478-     /// @notice Returns `true`  if the quorum is reached for a particular implementation. 
479-     /// @return isReached Whether the minimum locked supply is reached or not. 
480-     function  _isMinLockedSupplyReached ()  internal   view   returns  ( bool   isReached ) { 
481-         isReached =  lockedSupply ()  +   1   >  Parameters.MIN_LOCKED_SUPPLY ;
464+     /// @return isReached Whether the quorum and minimum locked supply  is reached or not. 
465+     function _isQuorumAndMinLockedSupplyReached   (address  impl ) internal  view  returns  (bool  isReached ) {
466+         if  ( totalVotes (impl) <  calculateQuorumThreshold ()  +   1 ) { 
467+              return  isReached  =   false ; 
468+         } 
469+          if  ( lockedSupply ()  <  Parameters.MIN_LOCKED_SUPPLY) { 
470+              return  isReached  =   false ; 
471+         } 
472+         isReached =  true ;
482473    }
483474
484475    /// @notice Checks if the delay period for a scheduled upgrade has ended and reverts with errors if not. 
0 commit comments