Skip to content

Commit e1d4c3d

Browse files
Gas Optimization Bounty submission #3 (#455)
* Edition Stake Optimizations (#423) * Update StakingCondition struct * Update `Staker` struct * Remove staked array and ERC1155 ownership/approval * gas report * Minor edits + yarn gas * lint * reset foundry.toml * update gas report to ensure accuracy --------- Co-authored-by: nkrishang <62195808+nkrishang@users.noreply.github.com> * re-add stakers array * Target gas report --------- Co-authored-by: WhiteOakKong <92236155+WhiteOakKong@users.noreply.github.com>
1 parent 4b0ff81 commit e1d4c3d

File tree

8 files changed

+163
-163
lines changed

8 files changed

+163
-163
lines changed

contracts/base/Staking1155Base.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ contract Staking1155Base is ContractMetadata, Multicall, Ownable, Staking1155, E
5555
uint256 private rewardTokenBalance;
5656

5757
constructor(
58+
uint80 _defaultTimeUnit,
5859
address _defaultAdmin,
59-
uint256 _defaultTimeUnit,
6060
uint256 _defaultRewardsPerUnitTime,
6161
address _stakingToken,
6262
address _rewardToken,

contracts/extension/Staking1155.sol

Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
2121
uint8 internal isStaking = 1;
2222

2323
///@dev Next staking condition Id. Tracks number of conditon updates so far.
24-
uint256 private nextDefaultConditionId;
24+
uint64 private nextDefaultConditionId;
2525

2626
///@dev List of token-ids ever staked.
2727
uint256[] public indexedTokens;
@@ -30,16 +30,16 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
3030
mapping(uint256 => bool) public isIndexed;
3131

3232
///@dev Mapping from default condition-id to default condition.
33-
mapping(uint256 => StakingCondition) private defaultCondition;
33+
mapping(uint64 => StakingCondition) private defaultCondition;
3434

3535
///@dev Mapping from token-id to next staking condition Id for the token. Tracks number of conditon updates so far.
36-
mapping(uint256 => uint256) private nextConditionId;
36+
mapping(uint256 => uint64) private nextConditionId;
3737

3838
///@dev Mapping from token-id and staker address to Staker struct. See {struct IStaking1155.Staker}.
3939
mapping(uint256 => mapping(address => Staker)) public stakers;
4040

4141
///@dev Mapping from token-id and condition Id to staking condition. See {struct IStaking1155.StakingCondition}
42-
mapping(uint256 => mapping(uint256 => StakingCondition)) private stakingConditions;
42+
mapping(uint256 => mapping(uint64 => StakingCondition)) private stakingConditions;
4343

4444
/// @dev Mapping from token-id to list of accounts that have staked that token-id.
4545
mapping(uint256 => address[]) public stakersArray;
@@ -61,7 +61,7 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
6161
* @param _tokenId ERC1155 token-id to stake.
6262
* @param _amount Amount to stake.
6363
*/
64-
function stake(uint256 _tokenId, uint256 _amount) external nonReentrant {
64+
function stake(uint256 _tokenId, uint64 _amount) external nonReentrant {
6565
_stake(_tokenId, _amount);
6666
}
6767

@@ -73,7 +73,7 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
7373
* @param _tokenId ERC1155 token-id to withdraw.
7474
* @param _amount Amount to withdraw.
7575
*/
76-
function withdraw(uint256 _tokenId, uint256 _amount) external nonReentrant {
76+
function withdraw(uint256 _tokenId, uint64 _amount) external nonReentrant {
7777
_withdraw(_tokenId, _amount);
7878
}
7979

@@ -99,12 +99,12 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
9999
* @param _tokenId ERC1155 token Id.
100100
* @param _timeUnit New time unit.
101101
*/
102-
function setTimeUnit(uint256 _tokenId, uint256 _timeUnit) external virtual {
102+
function setTimeUnit(uint256 _tokenId, uint80 _timeUnit) external virtual {
103103
if (!_canSetStakeConditions()) {
104104
revert("Not authorized");
105105
}
106106

107-
uint256 _nextConditionId = nextConditionId[_tokenId];
107+
uint64 _nextConditionId = nextConditionId[_tokenId];
108108
StakingCondition memory condition = _nextConditionId == 0
109109
? defaultCondition[nextDefaultConditionId - 1]
110110
: stakingConditions[_tokenId][_nextConditionId - 1];
@@ -130,7 +130,7 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
130130
revert("Not authorized");
131131
}
132132

133-
uint256 _nextConditionId = nextConditionId[_tokenId];
133+
uint64 _nextConditionId = nextConditionId[_tokenId];
134134
StakingCondition memory condition = _nextConditionId == 0
135135
? defaultCondition[nextDefaultConditionId - 1]
136136
: stakingConditions[_tokenId][_nextConditionId - 1];
@@ -149,7 +149,7 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
149149
*
150150
* @param _defaultTimeUnit New time unit.
151151
*/
152-
function setDefaultTimeUnit(uint256 _defaultTimeUnit) external virtual {
152+
function setDefaultTimeUnit(uint80 _defaultTimeUnit) external virtual {
153153
if (!_canSetStakeConditions()) {
154154
revert("Not authorized");
155155
}
@@ -242,13 +242,13 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
242242
}
243243

244244
function getTimeUnit(uint256 _tokenId) public view returns (uint256 _timeUnit) {
245-
uint256 _nextConditionId = nextConditionId[_tokenId];
245+
uint64 _nextConditionId = nextConditionId[_tokenId];
246246
require(_nextConditionId != 0, "Time unit not set. Check default time unit.");
247247
_timeUnit = stakingConditions[_tokenId][_nextConditionId - 1].timeUnit;
248248
}
249249

250250
function getRewardsPerUnitTime(uint256 _tokenId) public view returns (uint256 _rewardsPerUnitTime) {
251-
uint256 _nextConditionId = nextConditionId[_tokenId];
251+
uint64 _nextConditionId = nextConditionId[_tokenId];
252252
require(_nextConditionId != 0, "Rewards not set. Check default rewards.");
253253
_rewardsPerUnitTime = stakingConditions[_tokenId][_nextConditionId - 1].rewardsPerUnitTime;
254254
}
@@ -266,29 +266,25 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
266266
//////////////////////////////////////////////////////////////*/
267267

268268
/// @dev Staking logic. Override to add custom logic.
269-
function _stake(uint256 _tokenId, uint256 _amount) internal virtual {
269+
function _stake(uint256 _tokenId, uint64 _amount) internal virtual {
270270
require(_amount != 0, "Staking 0 tokens");
271-
address _stakingToken = stakingToken;
272271

273272
if (stakers[_tokenId][_stakeMsgSender()].amountStaked > 0) {
274273
_updateUnclaimedRewardsForStaker(_tokenId, _stakeMsgSender());
275274
} else {
276275
stakersArray[_tokenId].push(_stakeMsgSender());
277-
stakers[_tokenId][_stakeMsgSender()].timeOfLastUpdate = block.timestamp;
276+
stakers[_tokenId][_stakeMsgSender()].timeOfLastUpdate = uint80(block.timestamp);
278277

279-
uint256 _conditionId = nextConditionId[_tokenId];
280-
stakers[_tokenId][_stakeMsgSender()].conditionIdOflastUpdate = _conditionId == 0
281-
? nextDefaultConditionId - 1
282-
: _conditionId - 1;
278+
uint64 _conditionId = nextConditionId[_tokenId];
279+
unchecked {
280+
stakers[_tokenId][_stakeMsgSender()].conditionIdOflastUpdate = _conditionId == 0
281+
? nextDefaultConditionId - 1
282+
: _conditionId - 1;
283+
}
283284
}
284285

285-
require(
286-
IERC1155(_stakingToken).balanceOf(_stakeMsgSender(), _tokenId) >= _amount &&
287-
IERC1155(_stakingToken).isApprovedForAll(_stakeMsgSender(), address(this)),
288-
"Not balance or approved"
289-
);
290286
isStaking = 2;
291-
IERC1155(_stakingToken).safeTransferFrom(_stakeMsgSender(), address(this), _tokenId, _amount, "");
287+
IERC1155(stakingToken).safeTransferFrom(_stakeMsgSender(), address(this), _tokenId, _amount, "");
292288
isStaking = 1;
293289
// stakerAddress[_tokenIds[i]] = _stakeMsgSender();
294290
stakers[_tokenId][_stakeMsgSender()].amountStaked += _amount;
@@ -302,7 +298,7 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
302298
}
303299

304300
/// @dev Withdraw logic. Override to add custom logic.
305-
function _withdraw(uint256 _tokenId, uint256 _amount) internal virtual {
301+
function _withdraw(uint256 _tokenId, uint64 _amount) internal virtual {
306302
uint256 _amountStaked = stakers[_tokenId][_stakeMsgSender()].amountStaked;
307303
require(_amount != 0, "Withdrawing 0 tokens");
308304
require(_amountStaked >= _amount, "Withdrawing more than staked");
@@ -333,13 +329,16 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
333329

334330
require(rewards != 0, "No rewards");
335331

336-
stakers[_tokenId][_stakeMsgSender()].timeOfLastUpdate = block.timestamp;
332+
stakers[_tokenId][_stakeMsgSender()].timeOfLastUpdate = uint80(block.timestamp);
337333
stakers[_tokenId][_stakeMsgSender()].unclaimedRewards = 0;
338334

339-
uint256 _conditionId = nextConditionId[_tokenId];
340-
stakers[_tokenId][_stakeMsgSender()].conditionIdOflastUpdate = _conditionId == 0
341-
? nextDefaultConditionId - 1
342-
: _conditionId - 1;
335+
uint64 _conditionId = nextConditionId[_tokenId];
336+
337+
unchecked {
338+
stakers[_tokenId][_stakeMsgSender()].conditionIdOflastUpdate = _conditionId == 0
339+
? nextDefaultConditionId - 1
340+
: _conditionId - 1;
341+
}
343342

344343
_mintRewards(_stakeMsgSender(), rewards);
345344

@@ -359,25 +358,27 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
359358
function _updateUnclaimedRewardsForStaker(uint256 _tokenId, address _staker) internal virtual {
360359
uint256 rewards = _calculateRewards(_tokenId, _staker);
361360
stakers[_tokenId][_staker].unclaimedRewards += rewards;
362-
stakers[_tokenId][_staker].timeOfLastUpdate = block.timestamp;
361+
stakers[_tokenId][_staker].timeOfLastUpdate = uint80(block.timestamp);
363362

364-
uint256 _conditionId = nextConditionId[_tokenId];
365-
stakers[_tokenId][_staker].conditionIdOflastUpdate = _conditionId == 0
366-
? nextDefaultConditionId - 1
367-
: _conditionId - 1;
363+
uint64 _conditionId = nextConditionId[_tokenId];
364+
unchecked {
365+
stakers[_tokenId][_staker].conditionIdOflastUpdate = _conditionId == 0
366+
? nextDefaultConditionId - 1
367+
: _conditionId - 1;
368+
}
368369
}
369370

370371
/// @dev Set staking conditions, for a token-Id.
371372
function _setStakingCondition(
372373
uint256 _tokenId,
373-
uint256 _timeUnit,
374+
uint80 _timeUnit,
374375
uint256 _rewardsPerUnitTime
375376
) internal virtual {
376377
require(_timeUnit != 0, "time-unit can't be 0");
377-
uint256 conditionId = nextConditionId[_tokenId];
378+
uint64 conditionId = nextConditionId[_tokenId];
378379

379380
if (conditionId == 0) {
380-
uint256 _nextDefaultConditionId = nextDefaultConditionId;
381+
uint64 _nextDefaultConditionId = nextDefaultConditionId;
381382
for (; conditionId < _nextDefaultConditionId; conditionId += 1) {
382383
StakingCondition memory _defaultCondition = defaultCondition[conditionId];
383384

@@ -390,46 +391,46 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
390391
}
391392
}
392393

393-
stakingConditions[_tokenId][conditionId - 1].endTimestamp = block.timestamp;
394+
stakingConditions[_tokenId][conditionId - 1].endTimestamp = uint80(block.timestamp);
394395

395396
stakingConditions[_tokenId][conditionId] = StakingCondition({
396397
timeUnit: _timeUnit,
397398
rewardsPerUnitTime: _rewardsPerUnitTime,
398-
startTimestamp: block.timestamp,
399+
startTimestamp: uint80(block.timestamp),
399400
endTimestamp: 0
400401
});
401402

402403
nextConditionId[_tokenId] = conditionId + 1;
403404
}
404405

405406
/// @dev Set default staking conditions.
406-
function _setDefaultStakingCondition(uint256 _timeUnit, uint256 _rewardsPerUnitTime) internal virtual {
407+
function _setDefaultStakingCondition(uint80 _timeUnit, uint256 _rewardsPerUnitTime) internal virtual {
407408
require(_timeUnit != 0, "time-unit can't be 0");
408-
uint256 conditionId = nextDefaultConditionId;
409+
uint64 conditionId = nextDefaultConditionId;
409410
nextDefaultConditionId += 1;
410411

411412
defaultCondition[conditionId] = StakingCondition({
412413
timeUnit: _timeUnit,
413414
rewardsPerUnitTime: _rewardsPerUnitTime,
414-
startTimestamp: block.timestamp,
415+
startTimestamp: uint80(block.timestamp),
415416
endTimestamp: 0
416417
});
417418

418419
if (conditionId > 0) {
419-
defaultCondition[conditionId - 1].endTimestamp = block.timestamp;
420+
defaultCondition[conditionId - 1].endTimestamp = uint80(block.timestamp);
420421
}
421422
}
422423

423424
/// @dev Reward calculation logic. Override to implement custom logic.
424425
function _calculateRewards(uint256 _tokenId, address _staker) internal view virtual returns (uint256 _rewards) {
425426
Staker memory staker = stakers[_tokenId][_staker];
426-
uint256 _stakerConditionId = staker.conditionIdOflastUpdate;
427-
uint256 _nextConditionId = nextConditionId[_tokenId];
427+
uint64 _stakerConditionId = staker.conditionIdOflastUpdate;
428+
uint64 _nextConditionId = nextConditionId[_tokenId];
428429

429430
if (_nextConditionId == 0) {
430431
_nextConditionId = nextDefaultConditionId;
431432

432-
for (uint256 i = _stakerConditionId; i < _nextConditionId; i += 1) {
433+
for (uint64 i = _stakerConditionId; i < _nextConditionId; i += 1) {
433434
StakingCondition memory condition = defaultCondition[i];
434435

435436
uint256 startTime = i != _stakerConditionId ? condition.startTimestamp : staker.timeOfLastUpdate;
@@ -447,7 +448,7 @@ abstract contract Staking1155 is ReentrancyGuard, IStaking1155 {
447448
_rewards = noOverflowProduct && noOverflowSum ? rewardsSum : _rewards;
448449
}
449450
} else {
450-
for (uint256 i = _stakerConditionId; i < _nextConditionId; i += 1) {
451+
for (uint64 i = _stakerConditionId; i < _nextConditionId; i += 1) {
451452
StakingCondition memory condition = stakingConditions[_tokenId][i];
452453

453454
uint256 startTime = i != _stakerConditionId ? condition.startTimestamp : staker.timeOfLastUpdate;

0 commit comments

Comments
 (0)