📋Lock Up
Contract Template of Lock-Up Terms
Name
LockUp
Dependent Contract
ILockUp, AccessControl, ArrayUtils, BallotsBox, DealsRepo, EnumerableSet, ISigPage
API:
Source Code:
LockUp
// SPDX-License-Identifier: UNLICENSED
/* *
* Copyright (c) 2021-2023 LI LI @ JINGTIAN & GONGCHENG.
*
* This WORK is licensed under ComBoox SoftWare License 1.0, a copy of which
* can be obtained at:
* [https://github.com/paul-lee-attorney/comboox]
*
* THIS WORK IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
* WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. IN NO
* EVENT SHALL ANY CONTRIBUTOR BE LIABLE TO YOU FOR ANY DAMAGES.
*
* YOU ARE PROHIBITED FROM DEPLOYING THE SMART CONTRACTS OF THIS WORK, IN WHOLE
* OR IN PART, FOR WHATEVER PURPOSE, ON ANY BLOCKCHAIN NETWORK THAT HAS ONE OR
* MORE NODES THAT ARE OUT OF YOUR CONTROL.
* */
pragma solidity ^0.8.8;
import "../../../common/access/AccessControl.sol";
import "./ILockUp.sol";
contract LockUp is ILockUp, AccessControl {
using ArrayUtils for uint256[];
using EnumerableSet for EnumerableSet.UintSet;
// 基准日条件未成就时,按“2105-09-19”设定到期日
uint48 constant _REMOTE_FUTURE = 4282732800;
// lockers[0].keyHolders: ssnList;
// seqOfShare => Locker
mapping(uint256 => Locker) private _lockers;
// ################
// ## Write I/O ##
// ################
function setLocker(uint256 seqOfShare, uint dueDate) external onlyAttorney {
_lockers[seqOfShare].dueDate = uint48(dueDate) == 0 ? _REMOTE_FUTURE : uint48(dueDate);
_lockers[0].keyHolders.add(seqOfShare);
}
function delLocker(uint256 seqOfShare) external onlyAttorney {
if (_lockers[0].keyHolders.remove(seqOfShare)) {
delete _lockers[seqOfShare];
}
}
function addKeyholder(uint256 seqOfShare, uint256 keyholder) external onlyAttorney {
require(seqOfShare != 0, "LU.addKeyholder: zero seqOfShare");
_lockers[seqOfShare].keyHolders.add(keyholder);
}
function removeKeyholder(uint256 seqOfShare, uint256 keyholder) external onlyAttorney {
require(seqOfShare != 0, "LU.removeKeyholder: zero seqOfShare");
_lockers[seqOfShare].keyHolders.remove(keyholder);
}
// ###############
// ## Read ##
// ###############
function isLocked(uint256 seqOfShare) public view returns (bool) {
return _lockers[0].keyHolders.contains(seqOfShare);
}
function getLocker(uint256 seqOfShare)
external
view
returns (uint48 dueDate, uint256[] memory keyHolders)
{
dueDate = _lockers[seqOfShare].dueDate;
keyHolders = _lockers[seqOfShare].keyHolders.values();
}
function lockedShares() external view returns (uint256[] memory) {
return _lockers[0].keyHolders.values();
}
// ################
// ## Term ##
// ################
function isTriggered(DealsRepo.Deal memory deal) external view returns (bool) {
if (
deal.head.typeOfDeal > 1 &&
isLocked(deal.head.seqOfShare) &&
_lockers[deal.head.seqOfShare].dueDate >= deal.head.closingDeadline
) return true;
return false;
}
function _isExempted(uint256 seqOfShare, uint256[] memory agreedParties)
private
view
returns (bool)
{
if (!isLocked(seqOfShare)) return true;
Locker storage locker = _lockers[seqOfShare];
uint256[] memory holders = locker.keyHolders.values();
uint256 len = holders.length;
if (len > agreedParties.length) {
return false;
} else {
return holders.fullyCoveredBy(agreedParties);
}
}
function isExempted(address ia, DealsRepo.Deal memory deal) external view returns (bool) {
uint seqOfMotion = _gk.getROA().getHeadOfFile(ia).seqOfMotion;
uint256[] memory parties = ISigPage(ia).getParties();
BallotsBox.Case memory consentCase = _gk.getGMM().getCaseOfAttitude(seqOfMotion, 1);
uint256[] memory supporters =
consentCase.voters.combine(consentCase.principals).merge(parties);
return _isExempted(deal.head.seqOfShare, supporters);
}
}
ILockUp
// SPDX-License-Identifier: UNLICENSED
/* *
* Copyright (c) 2021-2023 LI LI @ JINGTIAN & GONGCHENG.
*
* This WORK is licensed under ComBoox SoftWare License 1.0, a copy of which
* can be obtained at:
* [https://github.com/paul-lee-attorney/comboox]
*
* THIS WORK IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
* WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. IN NO
* EVENT SHALL ANY CONTRIBUTOR BE LIABLE TO YOU FOR ANY DAMAGES.
*
* YOU ARE PROHIBITED FROM DEPLOYING THE SMART CONTRACTS OF THIS WORK, IN WHOLE
* OR IN PART, FOR WHATEVER PURPOSE, ON ANY BLOCKCHAIN NETWORK THAT HAS ONE OR
* MORE NODES THAT ARE OUT OF YOUR CONTROL.
* */
pragma solidity ^0.8.8;
import "../../../../lib/ArrayUtils.sol";
import "../../../../lib/BallotsBox.sol";
import "../../../../lib/DealsRepo.sol";
import "../../../../lib/EnumerableSet.sol";
import "../../../common/components/ISigPage.sol";
interface ILockUp {
// 股票锁定柜
struct Locker {
uint48 dueDate;
EnumerableSet.UintSet keyHolders;
}
// ################
// ## Write ##
// ################
function setLocker(uint256 seqOfShare, uint dueDate) external;
function delLocker(uint256 seqOfShare) external;
function addKeyholder(uint256 seqOfShare, uint256 keyholder) external;
function removeKeyholder(uint256 seqOfShare, uint256 keyholder) external;
// ################
// ## 查询接口 ##
// ################
function isLocked(uint256 seqOfShare) external view returns (bool);
function getLocker(uint256 seqOfShare)
external
view
returns (uint48 dueDate, uint256[] memory keyHolders);
function lockedShares() external view returns (uint256[] memory);
function isTriggered(DealsRepo.Deal memory deal) external view returns (bool);
function isExempted(address ia, DealsRepo.Deal memory deal) external view returns (bool);
}