-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1888 from keep-network/locks-library
Stake locks extracted out of TokenStaking into a library This change allows us to save some bytecode space in TokenStaking for top-ups implementation. The contract size went down from `24926` to `22409` (-`2517` bytes). I have also introduced initTokenStaking function in `initContracts.js` to keep the details about `TokenStaking` library linking and deployment there and not pollute every unit test with the same logic. Last but not least, `LockUtils` library has been moved to sit next to `Locks` library.
- Loading branch information
Showing
37 changed files
with
317 additions
and
437 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
pragma solidity 0.5.17; | ||
|
||
import "openzeppelin-solidity/contracts/math/SafeMath.sol"; | ||
import "../../KeepRegistry.sol"; | ||
import "./LockUtils.sol"; | ||
|
||
library Locks { | ||
using SafeMath for uint256; | ||
using LockUtils for LockUtils.LockSet; | ||
|
||
event StakeLocked(address indexed operator, address lockCreator, uint256 until); | ||
event LockReleased(address indexed operator, address lockCreator); | ||
event ExpiredLockReleased(address indexed operator, address lockCreator); | ||
|
||
uint256 public constant maximumLockDuration = 86400 * 200; // 200 days in seconds | ||
|
||
struct Storage { | ||
// Locks placed on the operator. | ||
// `operatorLocks[operator]` returns all locks placed on the operator. | ||
// Each authorized operator contract can place one lock on an operator. | ||
mapping(address => LockUtils.LockSet) operatorLocks; | ||
} | ||
|
||
function lockStake( | ||
Storage storage self, | ||
address operator, | ||
uint256 duration | ||
) public { | ||
require(duration <= maximumLockDuration, "Lock duration too long"); | ||
self.operatorLocks[operator].setLock( | ||
msg.sender, | ||
uint96(block.timestamp.add(duration)) | ||
); | ||
emit StakeLocked(operator, msg.sender, block.timestamp.add(duration)); | ||
} | ||
|
||
function releaseLock( | ||
Storage storage self, | ||
address operator | ||
) public { | ||
self.operatorLocks[operator].releaseLock(msg.sender); | ||
emit LockReleased(operator, msg.sender); | ||
} | ||
|
||
function releaseExpiredLock( | ||
Storage storage self, | ||
address operator, | ||
address operatorContract, | ||
KeepRegistry registry | ||
) public { | ||
LockUtils.LockSet storage locks = self.operatorLocks[operator]; | ||
require( | ||
locks.contains(operatorContract), | ||
"No matching lock present" | ||
); | ||
bool expired = block.timestamp >= locks.getLockTime(operatorContract); | ||
bool disabled = !registry.isApprovedOperatorContract(operatorContract); | ||
require( | ||
expired || disabled, | ||
"Lock still active and valid" | ||
); | ||
locks.releaseLock(operatorContract); | ||
emit ExpiredLockReleased(operator, operatorContract); | ||
} | ||
|
||
function isStakeLocked( | ||
Storage storage self, | ||
address operator, | ||
KeepRegistry registry | ||
) public view returns (bool) { | ||
LockUtils.Lock[] storage _locks = self.operatorLocks[operator].locks; | ||
LockUtils.Lock memory lock; | ||
for (uint i = 0; i < _locks.length; i++) { | ||
lock = _locks[i]; | ||
if (block.timestamp < lock.expiresAt) { | ||
if (registry.isApprovedOperatorContract(lock.creator)) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
function isStakeReleased( | ||
Storage storage self, | ||
address operator, | ||
address operatorContract | ||
) public view returns (bool) { | ||
LockUtils.LockSet storage locks = self.operatorLocks[operator]; | ||
// `getLockTime` returns 0 if the lock doesn't exist, | ||
// thus we don't need to check for its presence separately. | ||
return block.timestamp >= locks.getLockTime(operatorContract); | ||
} | ||
|
||
function getLocks( | ||
Storage storage self, | ||
address operator | ||
) public view returns (address[] memory creators, uint256[] memory expirations) { | ||
uint256 lockCount = self.operatorLocks[operator].locks.length; | ||
creators = new address[](lockCount); | ||
expirations = new uint256[](lockCount); | ||
LockUtils.Lock memory lock; | ||
for (uint i = 0; i < lockCount; i++) { | ||
lock = self.operatorLocks[operator].locks[i]; | ||
creators[i] = lock.creator; | ||
expirations[i] = lock.expiresAt; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.