Contract 0x38064F40B20347d58b326E767791A6f79cdEddCe 3

 
 
Txn Hash
Method
Block
From
To
Value
0x1ee8f998ee25c04e8cef732374fd018b36d6c915c4bdd67aeaf4bfe10a28aceaSummon Moloch(pending)2022-09-25 2:24:424 days 13 hrs ago0x21f5f86a51f7559b7df5fc51199c13703a79cd1a IN 0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether(Pending)(Pending)
0xf06e7b06be4dd1898c82a0dca7fe6f3520a47f3ce68caf4d7c496e23e9dd41c3Summon Moloch156090112022-09-25 7:51:594 days 7 hrs ago0xcea8d76065c6974c541ffff57e984f4f675c70d8 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00265425 6.56834208
0xaf3b2de67cfefe6aed1298976021e94b4b1ff76f944c5b1428bc65ca6bb6b74eSummon Moloch156089862022-09-25 7:46:594 days 8 hrs ago0xcea8d76065c6974c541ffff57e984f4f675c70d8 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00278017 6.26106987
0x3e8d5fb8c56e0ddc0ec1a583e682add29c06d53f18a879d30b23369007e0efc8Summon Moloch156073782022-09-25 2:24:114 days 13 hrs ago0xea3a2249173e01808dafc61008af10d79523abb2 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00258568 5.73998885
0x1a2f9880a688eacc7aede8cbb26b39d3eb93b86f4201ca3aa7f55ab0bece993bSummon Moloch156029632022-09-24 11:37:115 days 4 hrs agoENS Name stylianou.eth IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00376683 5.87571118
0x40a36b131abcc683a3d96126279662d117fd40aa22477d19eaa168be904d063bSummon Moloch156018932022-09-24 8:02:115 days 7 hrs ago0xe4376e143c9d7466be6d35c1d470c1376d0e04db IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00390801 7.20463204
0x8313da98c4167e43070b52f0b1fb781fb6a2553197429c4e7e67d28bd3c4e8f3Summon Moloch156011512022-09-24 5:32:595 days 10 hrs ago0xcea8d76065c6974c541ffff57e984f4f675c70d8 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00270163 6.08418323
0xc918583dba83b9fc1bfcbca67a729aeb4fcc50dd451ba80dd7263faeef5c15afSummon Moloch155907592022-09-22 18:46:116 days 21 hrs agoENS Name 0xblockboy.eth IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.0046416 10.45308425
0x8d43e2d9dd8412201f9b8338f043bb61914576ba78c6bb9bf8b76d90c9ae66acSummon Moloch155861912022-09-22 3:25:597 days 12 hrs ago0xcea8d76065c6974c541ffff57e984f4f675c70d8 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00313567 6.96054955
0xebb2a28cf465167e5af8660acb9f34ee39a79b897eec333196f9cd8d74a5e7c8Summon Moloch155847742022-09-21 22:39:237 days 17 hrs ago0x86d2784835053ed8bbbcbb8effb6b0e1df9a1881 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00606326 13.65471559
0x6e3862999314de84289f2ee0f1bf748472ffe28b56c9f8cf3576bc4bf214d5a3Summon Moloch155643892022-09-19 1:47:5910 days 13 hrs agoENS Name ronrivers.eth IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00482747 10.87225202
0x01830471d260facfa787b82467371e9bf1f39505a3a678db16e8b398e8ee3fe4Summon Moloch155607012022-09-18 13:22:2311 days 2 hrs ago0xe4376e143c9d7466be6d35c1d470c1376d0e04db IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00532252 6.35092601
0xe7bd052237cf025843ac40bd43cac53a936bd63507b5f22b2a1b21ed01689c2dSummon Moloch155605652022-09-18 12:54:5911 days 2 hrs ago0xe4376e143c9d7466be6d35c1d470c1376d0e04db IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00647292 7.72360465
0xd4cb94bc2131b651b661712d2c0529ac4eeab65802f04c7b04e93475642ad0cdSummon Moloch155540822022-09-17 15:06:1112 days 41 mins ago0xe4376e143c9d7466be6d35c1d470c1376d0e04db IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00918382 10.958284
0x0eea483f44ab543bab1a32684b3b17798034b10c80a17ddee5e20982abe94c6eSummon Moloch155539282022-09-17 14:35:2312 days 1 hr ago0xe4376e143c9d7466be6d35c1d470c1376d0e04db IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00294263 6.62692526
0x6f29f9fefbf0b8de4147b37018131d715c83ba62828338081c0a20642572b019Summon Moloch155489672022-09-16 21:52:3512 days 17 hrs ago0xc95dd89124ff61f6799c8e5d808b1cb11885e5b0 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.0066913 15.06990031
0x5b3f9a70b17901c4bacfb742ea4659211e0d006f968414af04d919cda380b812Summon Moloch154522362022-09-01 10:04:5128 days 5 hrs ago0xce03dd06ec6690375d50fbe939b8db44165700d9 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00650412 14.64793714
0xed6909ac3654e204a677ebadb3c2e48dadbc2b06f3988cebe762d514eb56237cSummon Moloch154383832022-08-30 4:55:0630 days 10 hrs ago0x8f33387bdccbf54e8f2f79b70fbc8cee4461ddae IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00528885 11.91070691
0x9f59685ae5937d065c7405f905eb873891f5d57e597a3b3a4b551584d17b868bSummon Moloch154383812022-08-30 4:54:1830 days 10 hrs ago0x8f33387bdccbf54e8f2f79b70fbc8cee4461ddae IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00484485 10.91079883
0x064b9ab4e1e0862a5bb15411dd305f490490049b74ce74330367abd6745eba3cSummon Moloch154241282022-08-27 22:12:4832 days 17 hrs agoENS Name here-foundation.eth IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00468211 8.62981235
0xbba1f4c1223ca003677653ddeb2f8fa5bbe23c0a9183ab3fa9a1d8743a9ed525Summon Moloch154219502022-08-27 13:58:0033 days 1 hr ago0xa2a996e664c6a0da7f4db97b0686a5ab02bb64b9 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00509832 11.4813082
0xf341b654d7cbfda8d83ff6e1befbfb666a969a4a3beb5bf4546e671a2534ec05Summon Moloch154127602022-08-26 2:33:5234 days 13 hrs ago0x407a14f3ee266bc6c5d0a83be89741e0c6a0918e IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00451766 10.17395378
0x04817d02b2687093b2a8aa407ce5d2553aa37fbb037b73494de8daa1385a573dSummon Moloch153516002022-08-16 9:33:3644 days 6 hrs ago0x7421698e7e607d399e5a5d7a727886d39a6432f3 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00384098 8.65005684
0xaa506cb08a10285d7c2b2458f1e873cd09d71981b32a3ba8627d904c86eb0f11Summon Moloch153495682022-08-16 1:52:1144 days 13 hrs ago0x8435d0a8f19f748cba91863b70eb986895ee4b49 IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00578653 13.03150742
0xf4fe517537e6ea172bb699cea13b2d985780821b363b67a2ad12c46091e98309Summon Moloch153404122022-08-14 14:53:3246 days 54 mins ago0xb171ddf2c5f3fba6b065f835e7b82f714148effd IN  0x38064f40b20347d58b326e767791a6f79cdeddce0 Ether0.00668464 11.22767754
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0xf06e7b06be4dd1898c82a0dca7fe6f3520a47f3ce68caf4d7c496e23e9dd41c3156090112022-09-25 7:51:594 days 7 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xaf3b2de67cfefe6aed1298976021e94b4b1ff76f944c5b1428bc65ca6bb6b74e156089862022-09-25 7:46:594 days 8 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x3e8d5fb8c56e0ddc0ec1a583e682add29c06d53f18a879d30b23369007e0efc8156073782022-09-25 2:24:114 days 13 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x1a2f9880a688eacc7aede8cbb26b39d3eb93b86f4201ca3aa7f55ab0bece993b156029632022-09-24 11:37:115 days 4 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x40a36b131abcc683a3d96126279662d117fd40aa22477d19eaa168be904d063b156018932022-09-24 8:02:115 days 7 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x8313da98c4167e43070b52f0b1fb781fb6a2553197429c4e7e67d28bd3c4e8f3156011512022-09-24 5:32:595 days 10 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xc918583dba83b9fc1bfcbca67a729aeb4fcc50dd451ba80dd7263faeef5c15af155907592022-09-22 18:46:116 days 21 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x8d43e2d9dd8412201f9b8338f043bb61914576ba78c6bb9bf8b76d90c9ae66ac155861912022-09-22 3:25:597 days 12 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xebb2a28cf465167e5af8660acb9f34ee39a79b897eec333196f9cd8d74a5e7c8155847742022-09-21 22:39:237 days 17 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x6e3862999314de84289f2ee0f1bf748472ffe28b56c9f8cf3576bc4bf214d5a3155643892022-09-19 1:47:5910 days 13 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x01830471d260facfa787b82467371e9bf1f39505a3a678db16e8b398e8ee3fe4155607012022-09-18 13:22:2311 days 2 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xe7bd052237cf025843ac40bd43cac53a936bd63507b5f22b2a1b21ed01689c2d155605652022-09-18 12:54:5911 days 2 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xd4cb94bc2131b651b661712d2c0529ac4eeab65802f04c7b04e93475642ad0cd155540822022-09-17 15:06:1112 days 41 mins ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x0eea483f44ab543bab1a32684b3b17798034b10c80a17ddee5e20982abe94c6e155539282022-09-17 14:35:2312 days 1 hr ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x6f29f9fefbf0b8de4147b37018131d715c83ba62828338081c0a20642572b019155489672022-09-16 21:52:3512 days 17 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x5b3f9a70b17901c4bacfb742ea4659211e0d006f968414af04d919cda380b812154522362022-09-01 10:04:5128 days 5 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xed6909ac3654e204a677ebadb3c2e48dadbc2b06f3988cebe762d514eb56237c154383832022-08-30 4:55:0630 days 10 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x9f59685ae5937d065c7405f905eb873891f5d57e597a3b3a4b551584d17b868b154383812022-08-30 4:54:1830 days 10 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x064b9ab4e1e0862a5bb15411dd305f490490049b74ce74330367abd6745eba3c154241282022-08-27 22:12:4832 days 17 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xbba1f4c1223ca003677653ddeb2f8fa5bbe23c0a9183ab3fa9a1d8743a9ed525154219502022-08-27 13:58:0033 days 1 hr ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xf341b654d7cbfda8d83ff6e1befbfb666a969a4a3beb5bf4546e671a2534ec05154127602022-08-26 2:33:5234 days 13 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0x04817d02b2687093b2a8aa407ce5d2553aa37fbb037b73494de8daa1385a573d153516002022-08-16 9:33:3644 days 6 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xaa506cb08a10285d7c2b2458f1e873cd09d71981b32a3ba8627d904c86eb0f11153495682022-08-16 1:52:1144 days 13 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xf4fe517537e6ea172bb699cea13b2d985780821b363b67a2ad12c46091e98309153404122022-08-14 14:53:3246 days 54 mins ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
0xc66edba80a372c66f4dd7d703bfc3811733c0646c1d501a1d70340cb26a43ad9153400802022-08-14 13:41:1246 days 2 hrs ago 0x38064f40b20347d58b326e767791a6f79cdeddce  Contract Creation0 Ether
[ Download CSV Export 
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
MolochSummoner

Compiler Version
v0.5.3+commit.10d17f24

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity)

/**
 *Submitted for verification at Etherscan.io on 2021-04-13
*/

pragma solidity 0.5.3;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor () internal {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

interface IERC20 {
    function transfer(address to, uint256 value) external returns (bool);

    function approve(address spender, uint256 value) external returns (bool);

    function transferFrom(address from, address to, uint256 value) external returns (bool);

    function totalSupply() external view returns (uint256);

    function balanceOf(address who) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    event Transfer(address indexed from, address indexed to, uint256 value);

    event Approval(address indexed owner, address indexed spender, uint256 value);
}

library SafeMath {
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b);

        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {

        require(b > 0);
        uint256 c = a / b;

        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a);
        uint256 c = a - b;

        return c;
    }

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a);

        return c;
    }
}

contract Moloch is ReentrancyGuard {
    using SafeMath for uint256;

    /***************
    GLOBAL CONSTANTS
    ***************/
    uint256 public periodDuration; // default = 17280 = 4.8 hours in seconds (5 periods per day)
    uint256 public votingPeriodLength; // default = 35 periods (7 days)
    uint256 public gracePeriodLength; // default = 35 periods (7 days)
    uint256 public proposalDeposit; // default = 10 ETH (~$1,000 worth of ETH at contract deployment)
    uint256 public dilutionBound; // default = 3 - maximum multiplier a YES voter will be obligated to pay in case of mass ragequit
    uint256 public processingReward; // default = 0.1 - amount of ETH to give to whoever processes a proposal
    uint256 public summoningTime; // needed to determine the current period
    bool private initialized; // internally tracks deployment under eip-1167 proxy pattern

    address public depositToken; // deposit token contract reference; default = wETH

    // HARD-CODED LIMITS
    // These numbers are quite arbitrary; they are small enough to avoid overflows when doing calculations
    // with periods or shares, yet big enough to not limit reasonable use cases.
    uint256 constant MAX_VOTING_PERIOD_LENGTH = 10**18; // maximum length of voting period
    uint256 constant MAX_GRACE_PERIOD_LENGTH = 10**18; // maximum length of grace period
    uint256 constant MAX_DILUTION_BOUND = 10**18; // maximum dilution bound
    uint256 constant MAX_NUMBER_OF_SHARES_AND_LOOT = 10**18; // maximum number of shares that can be minted
    uint256 constant MAX_TOKEN_WHITELIST_COUNT = 400; // maximum number of whitelisted tokens
    uint256 constant MAX_TOKEN_GUILDBANK_COUNT = 200; // maximum number of tokens with non-zero balance in guildbank

    // ***************
    // EVENTS
    // ***************
    event SummonComplete(address indexed summoner, address[] tokens, uint256 summoningTime, uint256 periodDuration, uint256 votingPeriodLength, uint256 gracePeriodLength, uint256 proposalDeposit, uint256 dilutionBound, uint256 processingReward);
    event SubmitProposal(address indexed applicant, uint256 sharesRequested, uint256 lootRequested, uint256 tributeOffered, address tributeToken, uint256 paymentRequested, address paymentToken, string details, bool[6] flags, uint256 proposalId, address indexed delegateKey, address indexed memberAddress);
    event SponsorProposal(address indexed delegateKey, address indexed memberAddress, uint256 proposalId, uint256 proposalIndex, uint256 startingPeriod);
    event SubmitVote(uint256 proposalId, uint256 indexed proposalIndex, address indexed delegateKey, address indexed memberAddress, uint8 uintVote);
    event ProcessProposal(uint256 indexed proposalIndex, uint256 indexed proposalId, bool didPass);
    event ProcessWhitelistProposal(uint256 indexed proposalIndex, uint256 indexed proposalId, bool didPass);
    event ProcessGuildKickProposal(uint256 indexed proposalIndex, uint256 indexed proposalId, bool didPass);
    event Ragequit(address indexed memberAddress, uint256 sharesToBurn, uint256 lootToBurn);
    event TokensCollected(address indexed token, uint256 amountToCollect);
    event CancelProposal(uint256 indexed proposalId, address applicantAddress);
    event UpdateDelegateKey(address indexed memberAddress, address newDelegateKey);
    event Withdraw(address indexed memberAddress, address token, uint256 amount);

    // *******************
    // INTERNAL ACCOUNTING
    // *******************
    uint256 public proposalCount = 0; // total proposals submitted
    uint256 public totalShares = 0; // total shares across all members
    uint256 public totalLoot = 0; // total loot across all members

    uint256 public totalGuildBankTokens = 0; // total tokens with non-zero balance in guild bank

    address public constant GUILD = address(0xdead);
    address public constant ESCROW = address(0xbeef);
    address public constant TOTAL = address(0xbabe);
    mapping (address => mapping(address => uint256)) public userTokenBalances; // userTokenBalances[userAddress][tokenAddress]

    enum Vote {
        Null, // default value, counted as abstention
        Yes,
        No
    }

    struct Member {
        address delegateKey; // the key responsible for submitting proposals and voting - defaults to member address unless updated
        uint256 shares; // the # of voting shares assigned to this member
        uint256 loot; // the loot amount available to this member (combined with shares on ragequit)
        bool exists; // always true once a member has been created
        uint256 highestIndexYesVote; // highest proposal index # on which the member voted YES
        uint256 jailed; // set to proposalIndex of a passing guild kick proposal for this member, prevents voting on and sponsoring proposals
    }

    struct Proposal {
        address applicant; // the applicant who wishes to become a member - this key will be used for withdrawals (doubles as guild kick target for gkick proposals)
        address proposer; // the account that submitted the proposal (can be non-member)
        address sponsor; // the member that sponsored the proposal (moving it into the queue)
        uint256 sharesRequested; // the # of shares the applicant is requesting
        uint256 lootRequested; // the amount of loot the applicant is requesting
        uint256 tributeOffered; // amount of tokens offered as tribute
        address tributeToken; // tribute token contract reference
        uint256 paymentRequested; // amount of tokens requested as payment
        address paymentToken; // payment token contract reference
        uint256 startingPeriod; // the period in which voting can start for this proposal
        uint256 yesVotes; // the total number of YES votes for this proposal
        uint256 noVotes; // the total number of NO votes for this proposal
        bool[6] flags; // [sponsored, processed, didPass, cancelled, whitelist, guildkick]
        string details; // proposal details - could be IPFS hash, plaintext, or JSON
        uint256 maxTotalSharesAndLootAtYesVote; // the maximum # of total shares encountered at a yes vote on this proposal
        mapping(address => Vote) votesByMember; // the votes on this proposal by each member
    }

    mapping(address => bool) public tokenWhitelist;
    address[] public approvedTokens;

    mapping(address => bool) public proposedToWhitelist;
    mapping(address => bool) public proposedToKick;

    mapping(address => Member) public members;
    mapping(address => address) public memberAddressByDelegateKey;
    address[] public memberList;


    mapping(uint256 => Proposal) public proposals;

    uint256[] public proposalQueue;

    modifier onlyMember {
        require(members[msg.sender].shares > 0 || members[msg.sender].loot > 0, "not a member");
        _;
    }

    modifier onlyShareholder {
        require(members[msg.sender].shares > 0, "not a shareholder");
        _;
    }

    modifier onlyDelegate {
        require(members[memberAddressByDelegateKey[msg.sender]].shares > 0, "not a delegate");
        _;
    }

    function init(
        address[] calldata _summoner,
        address[] calldata _approvedTokens,
        uint256 _periodDuration,
        uint256 _votingPeriodLength,
        uint256 _gracePeriodLength,
        uint256 _proposalDeposit,
        uint256 _dilutionBound,
        uint256 _processingReward,
        uint256[] calldata _summonerShares
    ) external {
        require(!initialized, "initialized");
        require(_summoner.length == _summonerShares.length, "summoner length mismatches summonerShares");
        require(_periodDuration > 0, "_periodDuration cannot be 0");
        require(_votingPeriodLength > 0, "_votingPeriodLength cannot be 0");
        require(_votingPeriodLength <= MAX_VOTING_PERIOD_LENGTH, "_votingPeriodLength exceeds limit");
        require(_gracePeriodLength <= MAX_GRACE_PERIOD_LENGTH, "_gracePeriodLength exceeds limit");
        require(_dilutionBound > 0, "_dilutionBound cannot be 0");
        require(_dilutionBound <= MAX_DILUTION_BOUND, "_dilutionBound exceeds limit");
        require(_approvedTokens.length > 0, "need at least one approved token");
        require(_approvedTokens.length <= MAX_TOKEN_WHITELIST_COUNT, "too many tokens");
        require(_proposalDeposit >= _processingReward, "_proposalDeposit cannot be smaller than _processingReward");
        
        depositToken = _approvedTokens[0];
      
        for (uint256 i = 0; i < _summoner.length; i++) {
            require(_summoner[i] != address(0), "summoner cannot be 0");
            members[_summoner[i]] = Member(_summoner[i], _summonerShares[i], 0, true, 0, 0);
            memberAddressByDelegateKey[_summoner[i]] = _summoner[i];
            totalShares = totalShares.add(_summonerShares[i]);
        }
        
        require(totalShares <= MAX_NUMBER_OF_SHARES_AND_LOOT, "too many shares requested");

        for (uint256 i = 0; i < _approvedTokens.length; i++) {
            require(_approvedTokens[i] != address(0), "_approvedToken cannot be 0");
            require(!tokenWhitelist[_approvedTokens[i]], "duplicate approved token");
            tokenWhitelist[_approvedTokens[i]] = true;
            approvedTokens.push(_approvedTokens[i]);
        }

        periodDuration = _periodDuration;
        votingPeriodLength = _votingPeriodLength;
        gracePeriodLength = _gracePeriodLength;
        proposalDeposit = _proposalDeposit;
        dilutionBound = _dilutionBound;
        processingReward = _processingReward;
        summoningTime = now;
        initialized = true;
    }

    /*****************
    PROPOSAL FUNCTIONS
    *****************/
    function submitProposal(
        address applicant,
        uint256 sharesRequested,
        uint256 lootRequested,
        uint256 tributeOffered,
        address tributeToken,
        uint256 paymentRequested,
        address paymentToken,
        string memory details
    ) public nonReentrant returns (uint256 proposalId) {
        require(sharesRequested.add(lootRequested) <= MAX_NUMBER_OF_SHARES_AND_LOOT, "too many shares requested");
        require(tokenWhitelist[tributeToken], "tributeToken is not whitelisted");
        require(tokenWhitelist[paymentToken], "payment is not whitelisted");
        require(applicant != address(0), "applicant cannot be 0");
        require(applicant != GUILD && applicant != ESCROW && applicant != TOTAL, "applicant address cannot be reserved");
        require(members[applicant].jailed == 0, "proposal applicant must not be jailed");

        if (tributeOffered > 0 && userTokenBalances[GUILD][tributeToken] == 0) {
            require(totalGuildBankTokens < MAX_TOKEN_GUILDBANK_COUNT, 'cannot submit more tribute proposals for new tokens - guildbank is full');
        }

        // collect tribute from proposer and store it in the Moloch until the proposal is processed
        require(IERC20(tributeToken).transferFrom(msg.sender, address(this), tributeOffered), "tribute token transfer failed");
        unsafeAddToBalance(ESCROW, tributeToken, tributeOffered);

        bool[6] memory flags; // [sponsored, processed, didPass, cancelled, whitelist, guildkick]

        _submitProposal(applicant, sharesRequested, lootRequested, tributeOffered, tributeToken, paymentRequested, paymentToken, details, flags);
        return proposalCount - 1; // return proposalId - contracts calling submit might want it
    }

    function submitWhitelistProposal(address tokenToWhitelist, string memory details) public nonReentrant returns (uint256 proposalId) {
        require(tokenToWhitelist != address(0), "must provide token address");
        require(!tokenWhitelist[tokenToWhitelist], "cannot already have whitelisted the token");
        require(approvedTokens.length < MAX_TOKEN_WHITELIST_COUNT, "cannot submit more whitelist proposals");

        bool[6] memory flags; // [sponsored, processed, didPass, cancelled, whitelist, guildkick]
        flags[4] = true; // whitelist

        _submitProposal(address(0), 0, 0, 0, tokenToWhitelist, 0, address(0), details, flags);
        return proposalCount - 1;
    }

    function submitGuildKickProposal(address memberToKick, string memory details) public nonReentrant returns (uint256 proposalId) {
        Member memory member = members[memberToKick];

        require(member.shares > 0 || member.loot > 0, "member must have at least one share or one loot");
        require(members[memberToKick].jailed == 0, "member must not already be jailed");

        bool[6] memory flags; // [sponsored, processed, didPass, cancelled, whitelist, guildkick]
        flags[5] = true; // guild kick

        _submitProposal(memberToKick, 0, 0, 0, address(0), 0, address(0), details, flags);
        return proposalCount - 1;
    }

    function _submitProposal(
        address applicant,
        uint256 sharesRequested,
        uint256 lootRequested,
        uint256 tributeOffered,
        address tributeToken,
        uint256 paymentRequested,
        address paymentToken,
        string memory details,
        bool[6] memory flags
    ) internal {
        Proposal memory proposal = Proposal({
            applicant : applicant,
            proposer : msg.sender,
            sponsor : address(0),
            sharesRequested : sharesRequested,
            lootRequested : lootRequested,
            tributeOffered : tributeOffered,
            tributeToken : tributeToken,
            paymentRequested : paymentRequested,
            paymentToken : paymentToken,
            startingPeriod : 0,
            yesVotes : 0,
            noVotes : 0,
            flags : flags,
            details : details,
            maxTotalSharesAndLootAtYesVote : 0
        });

        proposals[proposalCount] = proposal;
        address memberAddress = memberAddressByDelegateKey[msg.sender];
        // NOTE: argument order matters, avoid stack too deep
        emit SubmitProposal(applicant, sharesRequested, lootRequested, tributeOffered, tributeToken, paymentRequested, paymentToken, details, flags, proposalCount, msg.sender, memberAddress);
        proposalCount += 1;
    }

    function sponsorProposal(uint256 proposalId) public nonReentrant onlyDelegate {
        // collect proposal deposit from sponsor and store it in the Moloch until the proposal is processed
        require(IERC20(depositToken).transferFrom(msg.sender, address(this), proposalDeposit), "proposal deposit token transfer failed");
        unsafeAddToBalance(ESCROW, depositToken, proposalDeposit);

        Proposal storage proposal = proposals[proposalId];

        require(proposal.proposer != address(0), 'proposal must have been proposed');
        require(!proposal.flags[0], "proposal has already been sponsored");
        require(!proposal.flags[3], "proposal has been cancelled");
        require(members[proposal.applicant].jailed == 0, "proposal applicant must not be jailed");

        if (proposal.tributeOffered > 0 && userTokenBalances[GUILD][proposal.tributeToken] == 0) {
            require(totalGuildBankTokens < MAX_TOKEN_GUILDBANK_COUNT, 'cannot sponsor more tribute proposals for new tokens - guildbank is full');
        }

        // whitelist proposal
        if (proposal.flags[4]) {
            require(!tokenWhitelist[address(proposal.tributeToken)], "cannot already have whitelisted the token");
            require(!proposedToWhitelist[address(proposal.tributeToken)], 'already proposed to whitelist');
            require(approvedTokens.length < MAX_TOKEN_WHITELIST_COUNT, "cannot sponsor more whitelist proposals");
            proposedToWhitelist[address(proposal.tributeToken)] = true;

        // guild kick proposal
        } else if (proposal.flags[5]) {
            require(!proposedToKick[proposal.applicant], 'already proposed to kick');
            proposedToKick[proposal.applicant] = true;
        }

        // compute startingPeriod for proposal
        uint256 startingPeriod = max(
            getCurrentPeriod(),
            proposalQueue.length == 0 ? 0 : proposals[proposalQueue[proposalQueue.length.sub(1)]].startingPeriod
        ).add(1);

        proposal.startingPeriod = startingPeriod;

        address memberAddress = memberAddressByDelegateKey[msg.sender];
        proposal.sponsor = memberAddress;

        proposal.flags[0] = true; // sponsored

        // append proposal to the queue
        proposalQueue.push(proposalId);
        
        emit SponsorProposal(msg.sender, memberAddress, proposalId, proposalQueue.length.sub(1), startingPeriod);
    }

    // NOTE: In MolochV2 proposalIndex !== proposalId
    function submitVote(uint256 proposalIndex, uint8 uintVote) public nonReentrant onlyDelegate {
        address memberAddress = memberAddressByDelegateKey[msg.sender];
        Member storage member = members[memberAddress];

        require(proposalIndex < proposalQueue.length, "proposal does not exist");
        Proposal storage proposal = proposals[proposalQueue[proposalIndex]];

        require(uintVote < 3, "must be less than 3");
        Vote vote = Vote(uintVote);

        require(getCurrentPeriod() >= proposal.startingPeriod, "voting period has not started");
        require(!hasVotingPeriodExpired(proposal.startingPeriod), "proposal voting period has expired");
        require(proposal.votesByMember[memberAddress] == Vote.Null, "member has already voted");
        require(vote == Vote.Yes || vote == Vote.No, "vote must be either Yes or No");

        proposal.votesByMember[memberAddress] = vote;

        if (vote == Vote.Yes) {
            proposal.yesVotes = proposal.yesVotes.add(member.shares);

            // set highest index (latest) yes vote - must be processed for member to ragequit
            if (proposalIndex > member.highestIndexYesVote) {
                member.highestIndexYesVote = proposalIndex;
            }

            // set maximum of total shares encountered at a yes vote - used to bound dilution for yes voters
            if (totalShares.add(totalLoot) > proposal.maxTotalSharesAndLootAtYesVote) {
                proposal.maxTotalSharesAndLootAtYesVote = totalShares.add(totalLoot);
            }

        } else if (vote == Vote.No) {
            proposal.noVotes = proposal.noVotes.add(member.shares);
        }
     
        // NOTE: subgraph indexes by proposalId not proposalIndex since proposalIndex isn't set untill it's been sponsored but proposal is created on submission
        emit SubmitVote(proposalQueue[proposalIndex], proposalIndex, msg.sender, memberAddress, uintVote);
    }

    function processProposal(uint256 proposalIndex) public nonReentrant {
        _validateProposalForProcessing(proposalIndex);

        uint256 proposalId = proposalQueue[proposalIndex];
        Proposal storage proposal = proposals[proposalId];

        require(!proposal.flags[4] && !proposal.flags[5], "must be a standard proposal");

        proposal.flags[1] = true; // processed

        bool didPass = _didPass(proposalIndex);

        // Make the proposal fail if the new total number of shares and loot exceeds the limit
        if (totalShares.add(totalLoot).add(proposal.sharesRequested).add(proposal.lootRequested) > MAX_NUMBER_OF_SHARES_AND_LOOT) {
            didPass = false;
        }

        // Make the proposal fail if it is requesting more tokens as payment than the available guild bank balance
        if (proposal.paymentRequested > userTokenBalances[GUILD][proposal.paymentToken]) {
            didPass = false;
        }

        // Make the proposal fail if it would result in too many tokens with non-zero balance in guild bank
        if (proposal.tributeOffered > 0 && userTokenBalances[GUILD][proposal.tributeToken] == 0 && totalGuildBankTokens >= MAX_TOKEN_GUILDBANK_COUNT) {
           didPass = false;
        }

        // PROPOSAL PASSED
        if (didPass) {
            proposal.flags[2] = true; // didPass

            // if the applicant is already a member, add to their existing shares & loot
            if (members[proposal.applicant].exists) {
                members[proposal.applicant].shares = members[proposal.applicant].shares.add(proposal.sharesRequested);
                members[proposal.applicant].loot = members[proposal.applicant].loot.add(proposal.lootRequested);

            // the applicant is a new member, create a new record for them
            } else {
                // if the applicant address is already taken by a member's delegateKey, reset it to their member address
                if (members[memberAddressByDelegateKey[proposal.applicant]].exists) {
                    address memberToOverride = memberAddressByDelegateKey[proposal.applicant];
                    memberAddressByDelegateKey[memberToOverride] = memberToOverride;
                    members[memberToOverride].delegateKey = memberToOverride;
                }

                // use applicant address as delegateKey by default
                members[proposal.applicant] = Member(proposal.applicant, proposal.sharesRequested, proposal.lootRequested, true, 0, 0);
                memberAddressByDelegateKey[proposal.applicant] = proposal.applicant;
            }

            // mint new shares & loot
            totalShares = totalShares.add(proposal.sharesRequested);
            totalLoot = totalLoot.add(proposal.lootRequested);

            // if the proposal tribute is the first tokens of its kind to make it into the guild bank, increment total guild bank tokens
            if (userTokenBalances[GUILD][proposal.tributeToken] == 0 && proposal.tributeOffered > 0) {
                totalGuildBankTokens += 1;
            }

            unsafeInternalTransfer(ESCROW, GUILD, proposal.tributeToken, proposal.tributeOffered);
            unsafeInternalTransfer(GUILD, proposal.applicant, proposal.paymentToken, proposal.paymentRequested);

            // if the proposal spends 100% of guild bank balance for a token, decrement total guild bank tokens
            if (userTokenBalances[GUILD][proposal.paymentToken] == 0 && proposal.paymentRequested > 0) {
                totalGuildBankTokens -= 1;
            }

        // PROPOSAL FAILED
        } else {
            // return all tokens to the proposer (not the applicant, because funds come from proposer)
            unsafeInternalTransfer(ESCROW, proposal.proposer, proposal.tributeToken, proposal.tributeOffered);
        }

        _returnDeposit(proposal.sponsor);

        emit ProcessProposal(proposalIndex, proposalId, didPass);
    }

    function processWhitelistProposal(uint256 proposalIndex) public nonReentrant {
        _validateProposalForProcessing(proposalIndex);

        uint256 proposalId = proposalQueue[proposalIndex];
        Proposal storage proposal = proposals[proposalId];

        require(proposal.flags[4], "must be a whitelist proposal");

        proposal.flags[1] = true; // processed

        bool didPass = _didPass(proposalIndex);

        if (approvedTokens.length >= MAX_TOKEN_WHITELIST_COUNT) {
            didPass = false;
        }

        if (didPass) {
            proposal.flags[2] = true; // didPass

            tokenWhitelist[address(proposal.tributeToken)] = true;
            approvedTokens.push(proposal.tributeToken);
        }

        proposedToWhitelist[address(proposal.tributeToken)] = false;

        _returnDeposit(proposal.sponsor);

        emit ProcessWhitelistProposal(proposalIndex, proposalId, didPass);
    }

    function processGuildKickProposal(uint256 proposalIndex) public nonReentrant {
        _validateProposalForProcessing(proposalIndex);

        uint256 proposalId = proposalQueue[proposalIndex];
        Proposal storage proposal = proposals[proposalId];

        require(proposal.flags[5], "must be a guild kick proposal");

        proposal.flags[1] = true; // processed

        bool didPass = _didPass(proposalIndex);

        if (didPass) {
            proposal.flags[2] = true; // didPass
            Member storage member = members[proposal.applicant];
            member.jailed = proposalIndex;

            // transfer shares to loot
            member.loot = member.loot.add(member.shares);
            totalShares = totalShares.sub(member.shares);
            totalLoot = totalLoot.add(member.shares);
            member.shares = 0; // revoke all shares
        }

        proposedToKick[proposal.applicant] = false;

        _returnDeposit(proposal.sponsor);

        emit ProcessGuildKickProposal(proposalIndex, proposalId, didPass);
    }

    function _didPass(uint256 proposalIndex) internal returns (bool didPass) {
        Proposal memory proposal = proposals[proposalQueue[proposalIndex]];

        didPass = proposal.yesVotes > proposal.noVotes;

        // Make the proposal fail if the dilutionBound is exceeded
        if ((totalShares.add(totalLoot)).mul(dilutionBound) < proposal.maxTotalSharesAndLootAtYesVote) {
            didPass = false;
        }

        // Make the proposal fail if the applicant is jailed
        // - for standard proposals, we don't want the applicant to get any shares/loot/payment
        // - for guild kick proposals, we should never be able to propose to kick a jailed member (or have two kick proposals active), so it doesn't matter
        if (members[proposal.applicant].jailed != 0) {
            didPass = false;
        }

        return didPass;
    }

    function _validateProposalForProcessing(uint256 proposalIndex) internal view {
        require(proposalIndex < proposalQueue.length, "proposal does not exist");
        Proposal memory proposal = proposals[proposalQueue[proposalIndex]];

        require(getCurrentPeriod() >= proposal.startingPeriod.add(votingPeriodLength).add(gracePeriodLength), "proposal is not ready to be processed");
        require(proposal.flags[1] == false, "proposal has already been processed");
        require(proposalIndex == 0 || proposals[proposalQueue[proposalIndex.sub(1)]].flags[1], "previous proposal must be processed");
    }

    function _returnDeposit(address sponsor) internal {
        unsafeInternalTransfer(ESCROW, msg.sender, depositToken, processingReward);
        unsafeInternalTransfer(ESCROW, sponsor, depositToken, proposalDeposit.sub(processingReward));
    }

    function ragequit(uint256 sharesToBurn, uint256 lootToBurn) public nonReentrant onlyMember {
        _ragequit(msg.sender, sharesToBurn, lootToBurn);
    }

    function _ragequit(address memberAddress, uint256 sharesToBurn, uint256 lootToBurn) internal {
        uint256 initialTotalSharesAndLoot = totalShares.add(totalLoot);

        Member storage member = members[memberAddress];

        require(member.shares >= sharesToBurn, "insufficient shares");
        require(member.loot >= lootToBurn, "insufficient loot");

        require(canRagequit(member.highestIndexYesVote), "cannot ragequit until highest index proposal member voted YES on is processed");

        uint256 sharesAndLootToBurn = sharesToBurn.add(lootToBurn);

        // burn shares and loot
        member.shares = member.shares.sub(sharesToBurn);
        member.loot = member.loot.sub(lootToBurn);
        totalShares = totalShares.sub(sharesToBurn);
        totalLoot = totalLoot.sub(lootToBurn);

        for (uint256 i = 0; i < approvedTokens.length; i++) {
            uint256 amountToRagequit = fairShare(userTokenBalances[GUILD][approvedTokens[i]], sharesAndLootToBurn, initialTotalSharesAndLoot);
            if (amountToRagequit > 0) { // gas optimization to allow a higher maximum token limit
                // deliberately not using safemath here to keep overflows from preventing the function execution (which would break ragekicks)
                // if a token overflows, it is because the supply was artificially inflated to oblivion, so we probably don't care about it anyways
                userTokenBalances[GUILD][approvedTokens[i]] -= amountToRagequit;
                userTokenBalances[memberAddress][approvedTokens[i]] += amountToRagequit;
            }
        }

        emit Ragequit(msg.sender, sharesToBurn, lootToBurn);
    }

    function ragekick(address memberToKick) public nonReentrant {
        Member storage member = members[memberToKick];

        require(member.jailed != 0, "member must be in jail");
        require(member.loot > 0, "member must have some loot"); // note - should be impossible for jailed member to have shares
        require(canRagequit(member.highestIndexYesVote), "cannot ragequit until highest index proposal member voted YES on is processed");

        _ragequit(memberToKick, 0, member.loot);
    }

    function withdrawBalance(address token, uint256 amount) public nonReentrant {
        _withdrawBalance(token, amount);
    }

    function withdrawBalances(address[] memory tokens, uint256[] memory amounts, bool max) public nonReentrant {
        require(tokens.length == amounts.length, "tokens and amounts arrays must be matching lengths");

        for (uint256 i=0; i < tokens.length; i++) {
            uint256 withdrawAmount = amounts[i];
            if (max) { // withdraw the maximum balance
                withdrawAmount = userTokenBalances[msg.sender][tokens[i]];
            }

            _withdrawBalance(tokens[i], withdrawAmount);
        }
    }
    
    function _withdrawBalance(address token, uint256 amount) internal {
        require(userTokenBalances[msg.sender][token] >= amount, "insufficient balance");
        unsafeSubtractFromBalance(msg.sender, token, amount);
        require(IERC20(token).transfer(msg.sender, amount), "transfer failed");
        emit Withdraw(msg.sender, token, amount);
    }

    function collectTokens(address token) public onlyDelegate nonReentrant {
        uint256 amountToCollect = IERC20(token).balanceOf(address(this)).sub(userTokenBalances[TOTAL][token]);
        // only collect if 1) there are tokens to collect 2) token is whitelisted 3) token has non-zero balance
        require(amountToCollect > 0, 'no tokens to collect');
        require(tokenWhitelist[token], 'token to collect must be whitelisted');
        require(userTokenBalances[GUILD][token] > 0 || totalGuildBankTokens < MAX_TOKEN_GUILDBANK_COUNT, 'token to collect must have non-zero guild bank balance');
        
        if (userTokenBalances[GUILD][token] == 0){
            totalGuildBankTokens += 1;
        }
        
        unsafeAddToBalance(GUILD, token, amountToCollect);
        emit TokensCollected(token, amountToCollect);
    }

    // NOTE: requires that delegate key which sent the original proposal cancels, msg.sender == proposal.proposer
    function cancelProposal(uint256 proposalId) public nonReentrant {
        Proposal storage proposal = proposals[proposalId];
        require(!proposal.flags[0], "proposal has already been sponsored");
        require(!proposal.flags[3], "proposal has already been cancelled");
        require(msg.sender == proposal.proposer, "solely the proposer can cancel");

        proposal.flags[3] = true; // cancelled
        
        unsafeInternalTransfer(ESCROW, proposal.proposer, proposal.tributeToken, proposal.tributeOffered);
        emit CancelProposal(proposalId, msg.sender);
    }

    function updateDelegateKey(address newDelegateKey) public nonReentrant onlyShareholder {
        require(newDelegateKey != address(0), "newDelegateKey cannot be 0");

        // skip checks if member is setting the delegate key to their member address
        if (newDelegateKey != msg.sender) {
            require(!members[newDelegateKey].exists, "cannot overwrite existing members");
            require(!members[memberAddressByDelegateKey[newDelegateKey]].exists, "cannot overwrite existing delegate keys");
        }

        Member storage member = members[msg.sender];
        memberAddressByDelegateKey[member.delegateKey] = address(0);
        memberAddressByDelegateKey[newDelegateKey] = msg.sender;
        member.delegateKey = newDelegateKey;

        emit UpdateDelegateKey(msg.sender, newDelegateKey);
    }

    // can only ragequit if the latest proposal you voted YES on has been processed
    function canRagequit(uint256 highestIndexYesVote) public view returns (bool) {
        require(highestIndexYesVote < proposalQueue.length, "proposal does not exist");
        return proposals[proposalQueue[highestIndexYesVote]].flags[1];
    }

    function hasVotingPeriodExpired(uint256 startingPeriod) public view returns (bool) {
        return getCurrentPeriod() >= startingPeriod.add(votingPeriodLength);
    }

    /***************
    GETTER FUNCTIONS
    ***************/
    function max(uint256 x, uint256 y) internal pure returns (uint256) {
        return x >= y ? x : y;
    }

    function getCurrentPeriod() public view returns (uint256) {
        return now.sub(summoningTime).div(periodDuration);
    }

    function getProposalQueueLength() public view returns (uint256) {
        return proposalQueue.length;
    }

    function getProposalFlags(uint256 proposalId) public view returns (bool[6] memory) {
        return proposals[proposalId].flags;
    }

    function getUserTokenBalance(address user, address token) public view returns (uint256) {
        return userTokenBalances[user][token];
    }

    function getMemberProposalVote(address memberAddress, uint256 proposalIndex) public view returns (Vote) {
        require(members[memberAddress].exists, "member does not exist");
        require(proposalIndex < proposalQueue.length, "proposal does not exist");
        return proposals[proposalQueue[proposalIndex]].votesByMember[memberAddress];
    }

    function getTokenCount() public view returns (uint256) {
        return approvedTokens.length;
    }

    /***************
    HELPER FUNCTIONS
    ***************/
    function unsafeAddToBalance(address user, address token, uint256 amount) internal {
        userTokenBalances[user][token] += amount;
        userTokenBalances[TOTAL][token] += amount;
    }

    function unsafeSubtractFromBalance(address user, address token, uint256 amount) internal {
        userTokenBalances[user][token] -= amount;
        userTokenBalances[TOTAL][token] -= amount;
    }

    function unsafeInternalTransfer(address from, address to, address token, uint256 amount) internal {
        unsafeSubtractFromBalance(from, token, amount);
        unsafeAddToBalance(to, token, amount);
    }

    function fairShare(uint256 balance, uint256 shares, uint256 totalShares) internal pure returns (uint256) {
        require(totalShares != 0);

        if (balance == 0) { return 0; }

        uint256 prod = balance * shares;

        if (prod / balance == shares) { // no overflow in multiplication above?
            return prod / totalShares;
        }

        return (balance / totalShares) * shares;
    }
}

/*
The MIT License (MIT)
Copyright (c) 2018 Murray Software, LLC.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
contract CloneFactory { // implementation of eip-1167 - see https://eips.ethereum.org/EIPS/eip-1167
    function createClone(address target) internal returns (address result) {
        bytes20 targetBytes = bytes20(target);
        assembly {
            let clone := mload(0x40)
            mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(clone, 0x14), targetBytes)
            mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            result := create(0, clone, 0x37)
        }
    }
}

contract MolochSummoner is CloneFactory { 
    
    address public template;
    mapping (address => bool) public daos;
    uint daoIdx = 0;
    Moloch private moloch; // moloch contract
    
    constructor(address _template) public {
        template = _template;
    }
    
    event SummonComplete(address indexed moloch, address[] summoner, address[] tokens, uint256 summoningTime, uint256 periodDuration, uint256 votingPeriodLength, uint256 gracePeriodLength, uint256 proposalDeposit, uint256 dilutionBound, uint256 processingReward, uint256[] summonerShares);
    event Register(uint daoIdx, address moloch, string title, string http, uint version);
     
    function summonMoloch(
        address[] memory _summoner,
        address[] memory _approvedTokens,
        uint256 _periodDuration,
        uint256 _votingPeriodLength,
        uint256 _gracePeriodLength,
        uint256 _proposalDeposit,
        uint256 _dilutionBound,
        uint256 _processingReward,
        uint256[] memory _summonerShares
    ) public returns (address) {
        Moloch moloch = Moloch(createClone(template));
        
        moloch.init(
            _summoner,
            _approvedTokens,
            _periodDuration,
            _votingPeriodLength,
            _gracePeriodLength,
            _proposalDeposit,
            _dilutionBound,
            _processingReward,
            _summonerShares
        );
       
        emit SummonComplete(address(moloch), _summoner, _approvedTokens, now, _periodDuration, _votingPeriodLength, _gracePeriodLength, _proposalDeposit, _dilutionBound, _processingReward, _summonerShares);
        
        return address(moloch);
    }
    
    function registerDao(
        address _daoAdress,
        string memory _daoTitle,
        string memory _http,
        uint _version
      ) public returns (bool) {
          
      moloch = Moloch(_daoAdress);
      (,,,bool exists,,) = moloch.members(msg.sender);
    
      require(exists == true, "must be a member");
      require(daos[_daoAdress] == false, "dao metadata already registered");

      daos[_daoAdress] = true;
      
      daoIdx = daoIdx + 1;
      emit Register(daoIdx, _daoAdress, _daoTitle, _http, _version);
      return true;
      
    }
    
}

Contract Security Audit

Contract ABI

[{"constant":false,"inputs":[{"name":"_summoner","type":"address[]"},{"name":"_approvedTokens","type":"address[]"},{"name":"_periodDuration","type":"uint256"},{"name":"_votingPeriodLength","type":"uint256"},{"name":"_gracePeriodLength","type":"uint256"},{"name":"_proposalDeposit","type":"uint256"},{"name":"_dilutionBound","type":"uint256"},{"name":"_processingReward","type":"uint256"},{"name":"_summonerShares","type":"uint256[]"}],"name":"summonMoloch","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"template","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"daos","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_daoAdress","type":"address"},{"name":"_daoTitle","type":"string"},{"name":"_http","type":"string"},{"name":"_version","type":"uint256"}],"name":"registerDao","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_template","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"moloch","type":"address"},{"indexed":false,"name":"summoner","type":"address[]"},{"indexed":false,"name":"tokens","type":"address[]"},{"indexed":false,"name":"summoningTime","type":"uint256"},{"indexed":false,"name":"periodDuration","type":"uint256"},{"indexed":false,"name":"votingPeriodLength","type":"uint256"},{"indexed":false,"name":"gracePeriodLength","type":"uint256"},{"indexed":false,"name":"proposalDeposit","type":"uint256"},{"indexed":false,"name":"dilutionBound","type":"uint256"},{"indexed":false,"name":"processingReward","type":"uint256"},{"indexed":false,"name":"summonerShares","type":"uint256[]"}],"name":"SummonComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"daoIdx","type":"uint256"},{"indexed":false,"name":"moloch","type":"address"},{"indexed":false,"name":"title","type":"string"},{"indexed":false,"name":"http","type":"string"},{"indexed":false,"name":"version","type":"uint256"}],"name":"Register","type":"event"}]

6080604052600060025534801561001557600080fd5b50604051602080610af48339810180604052602081101561003557600080fd5b505160008054600160a060020a03909216600160a060020a0319909216919091179055610a8d806100676000396000f3fe608060405234801561001057600080fd5b5060043610610068577c0100000000000000000000000000000000000000000000000000000000600035046337c8d503811461006d5780636f2ddd9314610258578063c25f3cf614610260578063dfc35ad11461029a575b600080fd5b61023c600480360361012081101561008457600080fd5b81019060208101813564010000000081111561009f57600080fd5b8201836020820111156100b157600080fd5b803590602001918460208302840111640100000000831117156100d357600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561012357600080fd5b82018360208201111561013557600080fd5b8035906020019184602083028401116401000000008311171561015757600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929584359560208601359560408101359550606081013594506080810135935060a081013592919060e081019060c001356401000000008111156101ca57600080fd5b8201836020820111156101dc57600080fd5b803590602001918460208302840111640100000000831117156101fe57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506103d9945050505050565b60408051600160a060020a039092168252519081900360200190f35b61023c6106b8565b6102866004803603602081101561027657600080fd5b5035600160a060020a03166106c7565b604080519115158252519081900360200190f35b610286600480360360808110156102b057600080fd5b600160a060020a0382351691908101906040810160208201356401000000008111156102db57600080fd5b8201836020820111156102ed57600080fd5b8035906020019184600183028401116401000000008311171561030f57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929594936020810193503591505064010000000081111561036257600080fd5b82018360208201111561037457600080fd5b8035906020019184600183028401116401000000008311171561039657600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050913592506106dc915050565b6000805481906103f190600160a060020a03166109ee565b905080600160a060020a031663a91626198c8c8c8c8c8c8c8c8c6040518a63ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018080602001806020018a81526020018981526020018881526020018781526020018681526020018581526020018060200184810384528d818151815260200191508051906020019060200280838360005b838110156104a257818101518382015260200161048a565b5050505090500184810383528c818151815260200191508051906020019060200280838360005b838110156104e15781810151838201526020016104c9565b50505050905001848103825285818151815260200191508051906020019060200280838360005b83811015610520578181015183820152602001610508565b505050509050019c50505050505050505050505050600060405180830381600087803b15801561054f57600080fd5b505af1158015610563573d6000803e3d6000fd5b5050505080600160a060020a03167f099e0b09e056ad33e22e4d35de2e837a30ba249f33d912abb7e1e273bbf9d6508c8c428d8d8d8d8d8d8d6040518080602001806020018b81526020018a81526020018981526020018881526020018781526020018681526020018581526020018060200184810384528e818151815260200191508051906020019060200280838360005b8381101561060e5781810151838201526020016105f6565b5050505090500184810383528d818151815260200191508051906020019060200280838360005b8381101561064d578181015183820152602001610635565b50505050905001848103825285818151815260200191508051906020019060200280838360005b8381101561068c578181015183820152602001610674565b505050509050019d505050505050505050505050505060405180910390a29a9950505050505050505050565b600054600160a060020a031681565b60016020526000908152604090205460ff1681565b6003805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a038681169190911791829055604080517f08ae4b0c0000000000000000000000000000000000000000000000000000000081523360048201529051600093849316916308ae4b0c9160248083019260c0929190829003018186803b15801561076557600080fd5b505afa158015610779573d6000803e3d6000fd5b505050506040513d60c081101561078f57600080fd5b5060600151905060018115151461080757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f6d7573742062652061206d656d62657200000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a03861660009081526001602052604090205460ff161561088f57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f64616f206d6574616461746120616c7265616479207265676973746572656400604482015290519081900360640190fd5b600160a060020a0386166000818152600160208181526040808420805460ff19168417905560028054909301928390558051838152808301959095526080850188905260a09085018181528a519186019190915289517ffa01623ae7dadfb821d1e96adaf9e6dca0b6437e6c73dfe18af0d9ba73301d439593948c948c948c948c9492939092606085019260c086019290890191908190849084905b8381101561094357818101518382015260200161092b565b50505050905090810190601f1680156109705780820380516001836020036101000a031916815260200191505b50838103825285518152855160209182019187019080838360005b838110156109a357818101518382015260200161098b565b50505050905090810190601f1680156109d05780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a150600195945050505050565b6040517f3d602d80600a3d3981f3363d3d373d3d3d363d7300000000000000000000000081526c010000000000000000000000008202601482018190527f5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000602883015260009160378184f094935050505056fea165627a7a72305820e02af89d3a3773cb0fe386f869b62cef6a5caecf8aee4ab08e646f51e65c7262002900000000000000000000000044caea70c759f4fb6be864ab209ee1c745295c01

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000044caea70c759f4fb6be864ab209ee1c745295c01

-----Decoded View---------------
Arg [0] : _template (address): 0x44CaeA70c759f4fb6Be864ab209eE1c745295C01

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000044caea70c759f4fb6be864ab209ee1c745295c01


Deployed ByteCode Sourcemap

41218:2317:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;41218:2317:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;41899:1030;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;41899:1030:0;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;41899:1030:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;41899:1030:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;41899:1030:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;41899:1030:0;;;;;;;;-1:-1:-1;41899:1030:0;;-1:-1:-1;;21:11;5:28;;2:2;;;46:1;43;36:12;2:2;41899:1030:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;41899:1030:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;41899:1030:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;41899:1030:0;;;;;;;;;;;;;;;-1:-1:-1;41899:1030:0;;;;;-1:-1:-1;41899:1030:0;;;;;-1:-1:-1;41899:1030:0;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;41899:1030:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;41899:1030:0;;;;;;101:9:-1;95:2;81:12;77:21;67:8;63:36;60:51;39:11;25:12;22:29;11:108;8:2;;;132:1;129;122:12;8:2;41899:1030:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;41899:1030:0;;-1:-1:-1;41899:1030:0;;-1:-1:-1;;;;;41899:1030:0:i;:::-;;;;-1:-1:-1;;;;;41899:1030:0;;;;;;;;;;;;;;41272:23;;;:::i;41302:37::-;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;41302:37:0;-1:-1:-1;;;;;41302:37:0;;:::i;:::-;;;;;;;;;;;;;;;;;;42941:585;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;;;;;42941:585:0;;;;;;;;;;;;;;;21:11:-1;5:28;;2:2;;;46:1;43;36:12;2:2;42941:585:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42941:585:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;42941:585:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;42941:585:0;;;;;;;;-1:-1:-1;42941:585:0;;-1:-1:-1;;21:11;5:28;;2:2;;;46:1;43;36:12;2:2;42941:585:0;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;42941:585:0;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;42941:585:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;81:16;;74:27;;;;-1:-1;42941:585:0;;-1:-1:-1;;42941:585:0;;;-1:-1:-1;42941:585:0;;-1:-1:-1;;42941:585:0:i;41899:1030::-;42280:7;42335:8;;42280:7;;42323:21;;-1:-1:-1;;;;;42335:8:0;42323:11;:21::i;:::-;42300:45;;42366:6;-1:-1:-1;;;;;42366:11:0;;42392:9;42416:15;42446;42476:19;42510:18;42543:16;42574:14;42603:17;42635:15;42366:295;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;42366:295:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;42366:295:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;42366:295:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;42366:295:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;42366:295:0;;;;42709:6;-1:-1:-1;;;;;42686:192:0;;42718:9;42729:15;42746:3;42751:15;42768:19;42789:18;42809:16;42827:14;42843:17;42862:15;42686:192;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;42686:192:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;42686:192:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;42686:192:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;42914:6;41899:1030;-1:-1:-1;;;;;;;;;;41899:1030:0:o;41272:23::-;;;-1:-1:-1;;;;;41272:23:0;;:::o;41302:37::-;;;;;;;;;;;;;;;:::o;42941:585::-;43131:6;:27;;-1:-1:-1;;43131:27:0;-1:-1:-1;;;;;43131:27:0;;;;;;;;;;;43188:26;;;;;;43203:10;43188:26;;;;;;-1:-1:-1;;;;43188:6:0;;:14;;:26;;;;;;;;;;;;;;:6;:26;;;5:2:-1;;;;30:1;27;20:12;5:2;43188:26:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;43188:26:0;;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;-1:-1;43188:26:0;;;;-1:-1:-1;43247:4:0;43237:14;;;;43229:43;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;43289:16:0;;;;;;:4;:16;;;;;;;;:25;43281:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;43361:16:0;;;;;;43380:4;43361:16;;;;;;;;:23;;-1:-1:-1;;43361:23:0;;;;;43410:6;;;:10;;;43401:19;;;;43434:56;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;43410:10;;43366;;43463:9;;43474:5;;43481:8;;43434:56;;;;;;;;;;;;;;;;;;;;;;;8:100:-1;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;43434:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;43434:56:0;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;90:11;;;84:18;71:11;;;64:39;52:2;45:10;8:100;;;12:14;43434:56:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;43506:4:0;;42941:585;-1:-1:-1;;;;;42941:585:0:o;40717:494::-;40890:4;40884:11;40923:66;40909:81;;40821:15;;;41022:4;41011:16;;41004:37;;;41080:66;41073:4;41062:16;;41055:92;40772:14;;41188:4;40884:11;40772:14;41171:22;41161:32;40856:348;-1:-1:-1;;;;40856:348:0:o

Swarm Source

bzzr://e02af89d3a3773cb0fe386f869b62cef6a5caecf8aee4ab08e646f51e65c7262
Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.