Skip to content

Commit 014108a

Browse files
Fix last of Certora Informational Issues (#472)
* Hyperdrive._applyCheckpoint(): use a local storage variable cache for _checkpoints[_checkpointTime] * HyperdriveDataProvider.query(): use a local storage variable cache for _buffer[currentIndex] * HyperdriveLong._applyOpenLong(): use a local storage variable cache for _checkpoints[_checkpointTime] * HyperdriveShort._applyCloseShort(): use a local storage variable cache for _checkpoints[_checkpointTime] * HyperdriveTWAP.recordPrice(): use a local storage variable cache for _buffer[head] * ERC20Forwarder.permit(): Post-increment the nonce earlier * HyperdriveLP.redeemWithdrawalShares(): _withdrawPool.readyToWithdraw and _withdrawPool.proceeds should be cached * HyperdriveLong._applyOpenLong(): _marketState.longsOutstanding should be cached * HyperdriveLong._calculateOpenLong(): _marketState.shareReserves and _marketState.bondReserves should be cached * HyperdriveShort._applyOpenShort(): _marketState.shareReserves should be cached * ?: * fixed tests * yarn is annoying * lint * yarn again * cspell * codesize issues * codesize issues #2 * Update foundry.toml * Update foundry.toml * Update foundry.toml * rename
1 parent f424188 commit 014108a

8 files changed

Lines changed: 66 additions & 42 deletions

File tree

contracts/src/Hyperdrive.sol

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,15 @@ abstract contract Hyperdrive is
9090
uint256 _sharePrice
9191
) internal override returns (uint256 openSharePrice) {
9292
// Return early if the checkpoint has already been updated.
93-
if (
94-
_checkpoints[_checkpointTime].sharePrice != 0 ||
95-
_checkpointTime > block.timestamp
96-
) {
93+
IHyperdrive.Checkpoint storage checkpoint_ = _checkpoints[
94+
_checkpointTime
95+
];
96+
if (checkpoint_.sharePrice != 0 || _checkpointTime > block.timestamp) {
9797
return _checkpoints[_checkpointTime].sharePrice;
9898
}
9999

100100
// Create the share price checkpoint.
101-
_checkpoints[_checkpointTime].sharePrice = _sharePrice.toUint128();
101+
checkpoint_.sharePrice = _sharePrice.toUint128();
102102

103103
// Pay out the long withdrawal pool for longs that have matured.
104104
uint256 maturedLongsAmount = _totalSupply[
@@ -130,6 +130,6 @@ abstract contract Hyperdrive is
130130
);
131131
}
132132

133-
return _checkpoints[_checkpointTime].sharePrice;
133+
return checkpoint_.sharePrice;
134134
}
135135
}

contracts/src/HyperdriveDataProvider.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,9 @@ abstract contract HyperdriveDataProvider is
143143
while (currentIndex != head) {
144144
// If the timestamp of the current index has older data than the target
145145
// this is the newest data which is older than the target so we break
146-
if (uint256(_buffer[currentIndex].timestamp) <= targetTime) {
147-
oldData = _buffer[currentIndex];
146+
OracleData storage currentDataCache = _buffer[currentIndex];
147+
if (uint256(currentDataCache.timestamp) <= targetTime) {
148+
oldData = currentDataCache;
148149
break;
149150
}
150151
currentIndex = currentIndex == 0

contracts/src/HyperdriveLP.sol

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -321,22 +321,26 @@ abstract contract HyperdriveLP is HyperdriveTWAP {
321321
// to avoid unnecessary reverts. We exit early if the user has no shares
322322
// available to redeem.
323323
sharesRedeemed = _shares;
324-
if (sharesRedeemed > _withdrawPool.readyToWithdraw) {
325-
sharesRedeemed = _withdrawPool.readyToWithdraw;
324+
uint128 readyToWithdraw_ = _withdrawPool.readyToWithdraw;
325+
if (sharesRedeemed > readyToWithdraw_) {
326+
sharesRedeemed = readyToWithdraw_;
326327
}
327328
if (sharesRedeemed == 0) return (0, 0);
328329

329330
// We burn the shares from the user
330331
_burn(AssetId._WITHDRAWAL_SHARE_ASSET_ID, msg.sender, sharesRedeemed);
331332

332333
// The LP gets the pro-rata amount of the collected proceeds.
334+
uint128 proceeds_ = _withdrawPool.proceeds;
333335
uint256 shareProceeds = sharesRedeemed.mulDivDown(
334-
uint128(_withdrawPool.proceeds),
335-
uint128(_withdrawPool.readyToWithdraw)
336+
uint128(proceeds_),
337+
uint128(readyToWithdraw_)
336338
);
337339

338340
// Apply the update to the withdrawal pool.
339-
_withdrawPool.readyToWithdraw -= sharesRedeemed.toUint128();
341+
_withdrawPool.readyToWithdraw =
342+
readyToWithdraw_ -
343+
sharesRedeemed.toUint128();
340344
_withdrawPool.proceeds -= shareProceeds.toUint128();
341345

342346
// Withdraw for the user

contracts/src/HyperdriveLong.sol

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,13 @@ abstract contract HyperdriveLong is HyperdriveLP {
212212
uint256 _checkpointTime,
213213
uint256 _maturityTime
214214
) internal {
215+
uint128 longsOutstanding_ = _marketState.longsOutstanding;
215216
// Update the average maturity time of long positions.
216217
_marketState.longAverageMaturityTime = uint256(
217218
_marketState.longAverageMaturityTime
218219
)
219220
.updateWeightedAverage(
220-
uint256(_marketState.longsOutstanding),
221+
uint256(longsOutstanding_),
221222
_maturityTime * 1e18, // scale up to fixed point scale
222223
_bondProceeds,
223224
true
@@ -226,9 +227,10 @@ abstract contract HyperdriveLong is HyperdriveLP {
226227

227228
// Update the long share price of the checkpoint and the global long
228229
// open share price.
229-
_checkpoints[_checkpointTime].longSharePrice = uint256(
230-
_checkpoints[_checkpointTime].longSharePrice
231-
)
230+
IHyperdrive.Checkpoint storage checkpoint = _checkpoints[
231+
_checkpointTime
232+
];
233+
checkpoint.longSharePrice = uint256(checkpoint.longSharePrice)
232234
.updateWeightedAverage(
233235
uint256(
234236
_totalSupply[
@@ -247,7 +249,7 @@ abstract contract HyperdriveLong is HyperdriveLP {
247249
_marketState.longOpenSharePrice
248250
)
249251
.updateWeightedAverage(
250-
uint256(_marketState.longsOutstanding),
252+
uint256(longsOutstanding_),
251253
_sharePrice,
252254
_bondProceeds,
253255
true
@@ -258,14 +260,15 @@ abstract contract HyperdriveLong is HyperdriveLP {
258260
// longs outstanding.
259261
_marketState.shareReserves += _shareReservesDelta.toUint128();
260262
_marketState.bondReserves -= _bondReservesDelta.toUint128();
261-
_marketState.longsOutstanding += _bondProceeds.toUint128();
263+
longsOutstanding_ += _bondProceeds.toUint128();
264+
_marketState.longsOutstanding = longsOutstanding_;
262265

263266
// Since the base buffer may have increased relative to the base
264267
// reserves and the bond reserves decreased, we must ensure that the
265268
// base reserves are greater than the longsOutstanding.
266269
if (
267270
_sharePrice.mulDown(_marketState.shareReserves) <
268-
uint256(_marketState.longsOutstanding).divDown(_sharePrice) +
271+
uint256(longsOutstanding_).divDown(_sharePrice) +
269272
_minimumShareReserves
270273
) {
271274
revert IHyperdrive.BaseBufferExceedsShareReserves();
@@ -288,12 +291,16 @@ abstract contract HyperdriveLong is HyperdriveLP {
288291
uint256 _maturityTime,
289292
uint256 _sharePrice
290293
) internal {
294+
uint128 longsOutstanding_ = _marketState.longsOutstanding;
295+
uint128 longSharePrice_ = _checkpoints[
296+
_maturityTime - _positionDuration
297+
].longSharePrice;
291298
// Update the long average maturity time.
292299
_marketState.longAverageMaturityTime = uint256(
293300
_marketState.longAverageMaturityTime
294301
)
295302
.updateWeightedAverage(
296-
_marketState.longsOutstanding,
303+
longsOutstanding_,
297304
_maturityTime * 1e18, // scale up to fixed point scale
298305
_bondAmount,
299306
false
@@ -305,15 +312,17 @@ abstract contract HyperdriveLong is HyperdriveLP {
305312
_marketState.longOpenSharePrice
306313
)
307314
.updateWeightedAverage(
308-
_marketState.longsOutstanding,
309-
_checkpoints[_maturityTime - _positionDuration].longSharePrice,
315+
longsOutstanding_,
316+
longSharePrice_,
310317
_bondAmount,
311318
false
312319
)
313320
.toUint128();
314321

315322
// Reduce the amount of outstanding longs.
316-
_marketState.longsOutstanding -= _bondAmount.toUint128();
323+
_marketState.longsOutstanding =
324+
longsOutstanding_ -
325+
_bondAmount.toUint128();
317326

318327
// Apply the updates from the curve trade to the reserves.
319328
_marketState.shareReserves -= _shareReservesDelta.toUint128();
@@ -330,13 +339,10 @@ abstract contract HyperdriveLong is HyperdriveLP {
330339
AssetId._WITHDRAWAL_SHARE_ASSET_ID
331340
] - _withdrawPool.readyToWithdraw;
332341
if (withdrawalSharesOutstanding > 0) {
333-
uint256 openSharePrice = _checkpoints[
334-
_maturityTime - _positionDuration
335-
].longSharePrice;
336342
uint256 withdrawalProceeds = HyperdriveMath.calculateShortProceeds(
337343
_bondAmount,
338344
_shareProceeds,
339-
openSharePrice,
345+
longSharePrice_,
340346
_sharePrice,
341347
_sharePrice
342348
);

contracts/src/HyperdriveShort.sol

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -278,14 +278,16 @@ abstract contract HyperdriveShort is HyperdriveLP {
278278
// by the amount of bonds that were shorted. We don't need to add the
279279
// margin or pre-paid interest to the reserves because of the way that
280280
// the close short accounting works.
281-
_marketState.shareReserves -= _shareReservesDelta.toUint128();
281+
uint128 shareReserves_ = _marketState.shareReserves -
282+
_shareReservesDelta.toUint128();
283+
_marketState.shareReserves = shareReserves_;
282284
_marketState.bondReserves += _bondAmount.toUint128();
283285
_marketState.shortsOutstanding += _bondAmount.toUint128();
284286

285287
// Since the share reserves are reduced, we need to verify that the base
286288
// reserves are greater than or equal to the amount of longs outstanding.
287289
if (
288-
_sharePrice.mulDown(_marketState.shareReserves) <
290+
_sharePrice.mulDown(shareReserves_) <
289291
uint256(_marketState.longsOutstanding).divDown(_sharePrice) +
290292
_minimumShareReserves
291293
) {
@@ -309,12 +311,13 @@ abstract contract HyperdriveShort is HyperdriveLP {
309311
uint256 _maturityTime,
310312
uint256 _sharePrice
311313
) internal {
314+
uint128 shortsOutstanding_ = _marketState.shortsOutstanding;
312315
// Update the short average maturity time.
313316
_marketState.shortAverageMaturityTime = uint256(
314317
_marketState.shortAverageMaturityTime
315318
)
316319
.updateWeightedAverage(
317-
_marketState.shortsOutstanding,
320+
shortsOutstanding_,
318321
_maturityTime * 1e18, // scale up to fixed point scale
319322
_bondAmount,
320323
false
@@ -340,16 +343,24 @@ abstract contract HyperdriveShort is HyperdriveLP {
340343
// Remove a proportional amount of the checkpoints base volume from
341344
// the aggregates.
342345
uint256 checkpointTime = _maturityTime - _positionDuration;
343-
uint128 proportionalBaseVolume = uint256(
344-
_checkpoints[checkpointTime].shortBaseVolume
345-
).mulDown(_bondAmount.divDown(checkpointAmount)).toUint128();
346+
uint128 checkpointShortBaseVolume = _checkpoints[checkpointTime]
347+
.shortBaseVolume;
348+
IHyperdrive.Checkpoint storage checkpoint = _checkpoints[
349+
checkpointTime
350+
];
351+
uint128 proportionalBaseVolume = uint256(checkpointShortBaseVolume)
352+
.mulDown(_bondAmount.divDown(checkpointAmount))
353+
.toUint128();
346354
_marketState.shortBaseVolume -= proportionalBaseVolume;
347-
_checkpoints[checkpointTime]
348-
.shortBaseVolume -= proportionalBaseVolume;
355+
checkpoint.shortBaseVolume =
356+
checkpointShortBaseVolume -
357+
proportionalBaseVolume;
349358
}
350359

351360
// Decrease the amount of shorts outstanding.
352-
_marketState.shortsOutstanding -= _bondAmount.toUint128();
361+
_marketState.shortsOutstanding =
362+
shortsOutstanding_ -
363+
_bondAmount.toUint128();
353364

354365
// Apply the updates from the curve trade to the reserves.
355366
_marketState.shareReserves += _shareReservesDelta.toUint128();

contracts/src/HyperdriveTWAP.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ abstract contract HyperdriveTWAP is HyperdriveBase {
2929
}
3030

3131
// Load the current data from storage
32-
uint256 previousTime = uint256(_oracle.lastTimestamp);
33-
uint256 previousSum = uint256(_buffer[head].data);
32+
OracleData storage headData = _buffer[head];
33+
uint256 previousTime = uint256(headData.timestamp);
34+
uint256 previousSum = uint256(headData.data);
3435

3536
// Calculate sum
3637
uint256 delta = block.timestamp - previousTime;

contracts/src/token/ERC20Forwarder.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ contract ERC20Forwarder is IERC20 {
198198
// Require that the owner is not zero
199199
if (owner == address(0)) revert IHyperdrive.RestrictedZeroAddress();
200200

201+
uint256 nonce = nonces[owner];
201202
bytes32 structHash = keccak256(
202203
abi.encodePacked(
203204
"\x19\x01",
@@ -208,7 +209,7 @@ contract ERC20Forwarder is IERC20 {
208209
owner,
209210
spender,
210211
value,
211-
nonces[owner],
212+
nonce,
212213
deadline
213214
)
214215
)
@@ -220,7 +221,7 @@ contract ERC20Forwarder is IERC20 {
220221
if (signer != owner) revert IHyperdrive.InvalidSignature();
221222

222223
// Increment the signature nonce
223-
nonces[owner]++;
224+
nonces[owner] = nonce + 1;
224225
// Set the approval to the new value
225226
token.setApprovalBridge(tokenId, spender, value, owner);
226227
emit Approval(owner, spender, value);

foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ fs_permissions = [{ access = "write", path = "./artifacts/script_addresses.json"
2525
deny_warnings = true
2626
# optimizer settings
2727
optimizer = true
28-
optimizer_runs = 3500
28+
optimizer_runs = 1000
2929
# Enable via-ir
3030
via_ir = true
3131
# Enable gas-reporting for all contracts

0 commit comments

Comments
 (0)