@@ -44,47 +44,11 @@ contract L2ArbitrumToken is
4444 /// @notice The time at which the next mint is allowed - timestamp
4545 uint256 public nextMint;
4646
47- /// @dev History of the total amount of delegated tokens
48- /// The initial value is an estimate of the total delegation at the time of upgrade proposal creation.
49- /// Another proposal can be made later to update this value if needed.
50- Checkpoints.History private _totalDelegationHistory;
51-
52- /// @notice Called at proposal #1
53- /// @param initialTotalDelegation The initial total delegation at the time of upgrade proposal creation.
54- /// This is an estimate since it is chosen at proposal creation time and not effective until the proposal is executed.
55- function postUpgradeInit1 (uint256 initialTotalDelegation ) external onlyOwner {
56- _totalDelegationHistory.push (initialTotalDelegation);
57- }
58-
59- /// @notice Called at proposal #2
60- /// @param initialEstimationErrorAdjustment The amount the initialTotalDelegation was off by, negated. This is added to the current total delegation.
61- function postUpgradeInit2 (int256 initialEstimationErrorAdjustment ) external onlyOwner {
62- _totalDelegationHistory.push (
63- uint256 (int256 (_totalDelegationHistory.latest ()) + initialEstimationErrorAdjustment)
64- );
65- }
66-
67- /// @notice Get the current total delegation
68- /// @return The current total delegation
69- function getTotalDelegation ()
70- external
71- view
72- returns (uint256 )
73- {
74- return _totalDelegationHistory.latest ();
75- }
76-
77- /// @notice Get the total delegation at a specific block number
78- /// If the blockNumber is prior to the first checkpoint, returns 0
79- /// @param blockNumber The block number to get the total delegation at
80- /// @return The total delegation at the given block number
81- function getTotalDelegationAt (uint256 blockNumber )
82- external
83- view
84- returns (uint256 )
85- {
86- return _totalDelegationHistory.getAtBlock (blockNumber);
87- }
47+ /// @dev History of the change in total amount of delegated tokens
48+ /// Tracks the delta between total delegation at a given block and the anchor
49+ /// The anchor is set via setTotalDelegationAnchor as a standalone one-time operation
50+ Checkpoints.History private _totalDelegationDeltaHistory;
51+ uint256 private _totalDelegationAnchor;
8852
8953 constructor () {
9054 _disableInitializers ();
@@ -114,6 +78,11 @@ contract L2ArbitrumToken is
11478 _transferOwnership (_owner);
11579 }
11680
81+ function setTotalDelegationAnchor (uint256 totalDelegationAnchor ) external onlyOwner {
82+ require (_totalDelegationAnchor == 0 , "ARB: ANCHOR_ALREADY_SET " );
83+ _totalDelegationAnchor = totalDelegationAnchor;
84+ }
85+
11786 /// @notice Allows the owner to mint new tokens
11887 /// @dev Only allows minting below an inflation cap.
11988 /// Set to once per year, and a maximum of 2%.
@@ -129,12 +98,48 @@ contract L2ArbitrumToken is
12998 _mint (recipient, amount);
13099 }
131100
101+ /// @notice Get the current total delegation
102+ /// @dev If the anchor is unset, returns 0
103+ /// @return The current total delegation
104+ function getTotalDelegation () external view returns (uint256 ) {
105+ uint256 __totalDelegationAnchor = _totalDelegationAnchor;
106+ if (__totalDelegationAnchor == 0 ) {
107+ return 0 ;
108+ }
109+ return _adjustByAnchor (_totalDelegationDeltaHistory.latest (), __totalDelegationAnchor);
110+ }
111+
112+ /// @notice Get the total delegation at a specific block number
113+ /// @dev If the anchor is unset, or the block number is before the first checkpoint, returns 0
114+ /// @param blockNumber The block number to get the total delegation at
115+ /// @return The total delegation at the given block number
116+ function getTotalDelegationAt (uint256 blockNumber ) external view returns (uint256 ) {
117+ uint256 __totalDelegationAnchor = _totalDelegationAnchor;
118+ if (
119+ __totalDelegationAnchor == 0
120+ || blockNumber < _totalDelegationDeltaHistory._checkpoints[0 ]._blockNumber
121+ ) {
122+ return 0 ;
123+ }
124+ return _adjustByAnchor (
125+ _totalDelegationDeltaHistory.getAtBlock (blockNumber), __totalDelegationAnchor
126+ );
127+ }
132128
133- function _updateDelegationHistory (
134- address fromDelegate ,
135- address toDelegate ,
136- uint256 amount
137- ) internal {
129+ /// @dev Helper function to adjust a delegation delta checkpoint return value by an anchor
130+ /// The checkpoint return value is stored as a uint224, but we treat it as a signed int224.
131+ /// This is why the casting is a bit complex.
132+ function _adjustByAnchor (uint256 checkpointReturnValue , uint256 anchor )
133+ internal
134+ pure
135+ returns (uint256 )
136+ {
137+ return uint256 (int224 (uint224 (checkpointReturnValue)) + int256 (anchor));
138+ }
139+
140+ function _updateDelegationHistory (address fromDelegate , address toDelegate , uint256 amount )
141+ internal
142+ {
138143 if (fromDelegate != toDelegate) {
139144 int256 delta = 0 ;
140145 if (fromDelegate != address (0 )) {
@@ -144,32 +149,23 @@ contract L2ArbitrumToken is
144149 delta += int256 (amount);
145150 }
146151 if (delta != 0 ) {
147- _totalDelegationHistory.push (
148- uint256 (int256 (_totalDelegationHistory.latest ()) + delta)
149- );
152+ int224 latestDelta = int224 (uint224 (_totalDelegationDeltaHistory.latest ()));
153+ _totalDelegationDeltaHistory.push (uint256 (latestDelta + delta));
150154 }
151155 }
152156 }
153157
154158 function _delegate (address delegator , address delegatee ) internal virtual override {
155159 super ._delegate (delegator, delegatee);
156- _updateDelegationHistory (
157- delegates (delegator),
158- delegatee,
159- balanceOf (delegator)
160- );
160+ _updateDelegationHistory (delegates (delegator), delegatee, balanceOf (delegator));
161161 }
162162
163163 function _afterTokenTransfer (address from , address to , uint256 amount )
164164 internal
165165 override (ERC20Upgradeable , ERC20VotesUpgradeable )
166166 {
167167 super ._afterTokenTransfer (from, to, amount);
168- _updateDelegationHistory (
169- delegates (from),
170- delegates (to),
171- amount
172- );
168+ _updateDelegationHistory (delegates (from), delegates (to), amount);
173169 }
174170
175171 function _mint (address to , uint256 amount )
0 commit comments