# ShareholdersAgreement

<table data-header-hidden><thead><tr><th width="142">标题</th><th>内容</th></tr></thead><tbody><tr><td>Name</td><td>ShareholdersAgreement</td></tr><tr><td><strong>Address</strong></td><td><a href="https://arbiscan.io/address/0x7e9b4729de8f143dcbab40e96d0113cfadd1c37c">0x7e9b4729dE8F143DCBAB40e96d0113cFAdD1c37c</a></td></tr><tr><td>Dependent Contract</td><td>IShareholdersAgreement, <a href="../components/sigpage">SigPage</a>, <a href="../libraries/enumerableset">EnumerableSet</a>, <a href="../libraries/docsrepo">DocsRepo</a>, <a href="../components/sigpage">ISigPage</a></td></tr></tbody></table>

### **API**：

### Source Code:

<details>

<summary>ShareholdersAgreement</summary>

```solidity
// 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 "./IShareholdersAgreement.sol";
import "../../common/components/SigPage.sol";

contract ShareholdersAgreement is IShareholdersAgreement, SigPage {
    using EnumerableSet for EnumerableSet.UintSet;    

    TermsRepo private _terms;
    RulesRepo private _rules;

    //####################
    //##    modifier    ##
    //####################

    modifier titleExist(uint256 title) {
        require(
            hasTitle(title),
            "SHA.mf.TE: title not exist"
        );
        _;
    }

    //##################
    //##  Write I/O   ##
    //##################

    function createTerm(uint title, uint version)
        external
        onlyGC
    {
        address gc = msg.sender;

        uint typeOfDoc = title > 3 ? 21 + title : 22 + title;

        bytes32 snOfDoc = bytes32((typeOfDoc << 224) + uint224(version << 192));

        DocsRepo.Doc memory doc = _rc.createDoc(snOfDoc, gc);        

        IAccessControl(doc.body).init(
            address(this),
            address(this),
            address(_rc),
            address(_gk)
        );

        IAccessControl(doc.body).setRoleAdmin(bytes32("Attorneys"), gc);

        _terms.terms[title] = doc.body;
        _terms.seqList.add(title);
    }

    function removeTerm(uint title) external onlyAttorney {
        if (_terms.seqList.remove(title)) {
            delete _terms.terms[title];
        }
    }

    // ==== Rules ====
    
    function addRule(bytes32 rule) external onlyAttorney {
        _addRule(rule);
    }

    function _addRule(bytes32 rule) private {
        uint seqOfRule = uint16(uint(rule) >> 240);

        _rules.rules[seqOfRule] = rule;
        _rules.seqList.add(seqOfRule);
    }


    function removeRule(uint256 seq) external onlyAttorney {
        if (_rules.seqList.remove(seq)) {
            delete _rules.rules[seq];
        }
    }

    function initDefaultRules() external onlyDK {

        bytes32[] memory rules = new bytes32[](15);        

        // DefualtGovernanceRule
        rules[0]  = bytes32(uint(0x000000000003e800000d0503e8003213880500241388000000000000140101f4));

        // DefaultVotingRules
        rules[1]  = bytes32(uint(0x00010c010100001a0b000001000f08070e010100000000000000000000000000));
        rules[2]  = bytes32(uint(0x00020c020100001388000100010f08070e010107000000000000000000000000));
        rules[3]  = bytes32(uint(0x00030c030100000000000101000008070e010107000000000000000000000000));
        rules[4]  = bytes32(uint(0x00040c040100001a0b000001000f08070e010100000000000000000000000000));
        rules[5]  = bytes32(uint(0x00050c050100001388000100010f08070e010100000000000000000000000000));
        rules[6]  = bytes32(uint(0x00060c060100001a0b000001000f08070e010100000000000000000000000000));
        rules[7]  = bytes32(uint(0x00070c070100001a0b000001000f08070e010100000000000000000000000000));
        rules[8]  = bytes32(uint(0x00080c080100001a0b000001000000001d010100000000000000000000000000));
        rules[9]  = bytes32(uint(0x00090c090100001388010000000000001d010100000000000000000000000000));
        rules[10] = bytes32(uint(0x000a0c0a0100001a0b010000000000001d010100000000000000000000000000));
        rules[11] = bytes32(uint(0x000b0c0b02138800000100000000000009010100000000000000000000000000));
        rules[12] = bytes32(uint(0x000c0c0c021a0b00000100000000000009010100000000000000000000000000));

        // DefaultFirstRefusalRules
        rules[13] = bytes32(uint(0x0200020101010100000000000000000000000000000000000000000000000000));
        rules[14] = bytes32(uint(0x0201020202010100000000000000000000000000000000000000000000000000));

        uint len = 15;
        while (len > 0) {
            _addRule(rules[len - 1]);
            len--;
        }

    }

    // ==== Finalize SHA ====

    function finalizeSHA() external {

        uint[] memory titles = getTitles();
        uint len = titles.length;

        while (len > 0) {
            IAccessControl(_terms.terms[titles[len-1]]).lockContents();
            len --;
        }

        lockContents();
    }
    

    //################
    //##    Read    ##
    //################

    // ==== Terms ====

    function hasTitle(uint256 title) public view returns (bool) {
        return _terms.seqList.contains(title);
    }

    function qtyOfTerms() external view returns (uint256) {
        return _terms.seqList.length();
    }

    function getTitles() public view returns (uint256[] memory) {
        return _terms.seqList.values();
    }

    function getTerm(uint256 title) external view titleExist(title) returns (address) {
        return _terms.terms[title];
    }

    // ==== Rules ====
    
    function hasRule(uint256 seq) external view returns (bool) {
        return _rules.seqList.contains(seq);
    }

    function qtyOfRules() external view returns (uint256) {
        return _rules.seqList.length();
    }

    function getRules() external view returns (uint256[] memory) {
        return _rules.seqList.values();
    }

    function getRule(uint256 seq) external view returns (bytes32) {
        return _rules.rules[seq];
    }
}
```

</details>

<details>

<summary>IShareholdersAgreement</summary>

```solidity
// 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/components/ISigPage.sol";
import "../../../lib/EnumerableSet.sol";
import "../../../lib/DocsRepo.sol";

interface IShareholdersAgreement is ISigPage {

    enum TitleOfTerm {
        ZeroPoint,
        AntiDilution,   // 1
        LockUp,         // 2
        DragAlong,      // 3
        TagAlong,       // 4
        Options         // 5
    }

    // ==== Rules ========

/*
    |  Seq  |        Type       |    Abb       |            Description                     |       
    |    0  |  GovernanceRule   |     GR       | Board Constitution and General Rules of GM | 
    |    1  |  VotingRuleOfGM   |     CI       | VR for Capital Increase                    |
    |    2  |                   |   SText      | VR for External Share Transfer             |
    |    3  |                   |   STint      | VR for Internal Share Transfer             |
    |    4  |                   |    1+3       | VR for CI & STint                          |
    |    5  |                   |    2+3       | VR for SText & STint                       |
    |    6  |                   |   1+2+3      | VR for CI & SText & STint                  |
    |    7  |                   |    1+2       | VR for CI & SText                          |
    |    8  |                   |   SHA        | VR for Update SHA                          |
    |    9  |                   |  O-Issue-GM  | VR for Ordinary Issues of GeneralMeeting   |
    |   10  |                   |  S-Issue-GM  | VR for Special Issues Of GeneralMeeting    |
    |   11  | VotingRuleOfBoard |     CI       | VR for Capital Increase                    |
    |   12  |                   |   SText      | VR for External Share Transfer             |
    |   13  |                   |   STint      | VR for Internal Share Transfer             |
    |   14  |                   |    1+3       | VR for CI & STint                          |
    |   15  |                   |    2+3       | VR for SText & STint                       |
    |   16  |                   |   1+2+3      | VR for CI & SText & STint                  |
    |   17  |                   |    1+2       | VR for CI & SText                          |
    |   18  |                   |   SHA        | VR for Update SHA                          |
    |   19  |                   |  O-Issue-B   | VR for Ordinary Issues Of Board            |
    |   20  |                   |  S-Issue-B   | VR for Special Issues Of Board             |
    |   21  | UnilateralDecision| UniDecPower  | UnilateralDicisionPowerWithoutVoting       |
    ...

    |  256  | PositionAllocateRule |   PA Rule   | Management Positions' Allocation Rules    |
    ...

    |  512  | FirstRefusalRule  |  FR for CI...| FR rule for Investment Deal                |
    ...

    |  768  | GroupUpdateOrder  |  GroupUpdate | Grouping Members as per their relationship |
    ...

    |  1024 | ListingRule       |  ListingRule | Listing Rule for Share Issue & Transfer    |
    ...

*/

    struct TermsRepo {
        // title => body
        mapping(uint256 => address) terms;
        EnumerableSet.UintSet seqList;
    }

    struct RulesRepo {
        // seq => rule
        mapping(uint256 => bytes32) rules;
        EnumerableSet.UintSet seqList;
    }

    //##################
    //##  Write I/O   ##
    //##################

    function createTerm(uint typeOfDoc, uint version) external;

    function removeTerm(uint typeOfDoc) external;

    function addRule(bytes32 rule) external;

    function removeRule(uint256 seq) external;

    function initDefaultRules() external;

    function finalizeSHA() external;

    //################
    //##    Read    ##
    //################

    // ==== Terms ====

    function hasTitle(uint256 title) external view returns (bool);

    function qtyOfTerms() external view returns (uint256);

    function getTitles() external view returns (uint256[] memory);

    function getTerm(uint256 title) external view returns (address);

    // ==== Rules ====
    
    function hasRule(uint256 seq) external view returns (bool);

    function qtyOfRules() external view returns (uint256);

    function getRules() external view returns (uint256[] memory);

    function getRule(uint256 seq) external view returns (bytes32);
}

```

</details>
