Skip to content

Instantly share code, notes, and snippets.

@mcchan1
Created January 23, 2020 22:04
Show Gist options
  • Save mcchan1/090892474ebe020a5524ee5749612ab3 to your computer and use it in GitHub Desktop.
Save mcchan1/090892474ebe020a5524ee5749612ab3 to your computer and use it in GitHub Desktop.
take 4 adminFee
pragma solidity 0.5.3;
/*
adminFee = totalLoot+totalShares/adminFeeDenominator
if adminFeeDenominator is greater than or equal to 200, then adminFee will be less than or equal to .5%
-- allows LAO to reduce fees if desired, but not required to reduce .
Using OpenZeppelin's Ownable.sol contract to manage who is the service provider. It will be The LAO at launch.
withdrawAdminFee can direct an amount up to .5% of the assets under management (adminFee)
to any address (laoFund) after 90 days from the last time the function was called.
This function can only be called by the Owner.
HOW:
Summoner as agent and sole member will enter into agreement with LAO as service provider.
LAO will be the "Owner" under the Ownable.sol contract
Trust assumption: (upheld by valid legal documents under Delaware law): if Member's go through voting process to name
a service provider other than LAO, than LAO will step down and transfer Owner to the new named service provider.
LAO - will probably use OpenLaw relayer to automate call every 90 days to ensure adminFee is collected in a timely manner.
*/
//SERGEI - ABILITY TO TRANSFER SERVICE CONTRACT USING OpenZeppelin's OWNABLE.SOL
import "https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/ownership/Ownable.sol";
contract Moloch is ReentrancyGuard, Ownable {
using SafeMath for uint256;
//....REST IS SAME AS MOLOCH DAO CODE.
uint256 paymentPeriod = 90 days; //every quarter.
//uint256 paymentPeriod = 300 seconds; //remix test 5 min, use 90 days for real contract
//SERGEI - solution to call payment in a timely manner.
uint256 public lastPaymentTime = summoningTime;
function withdrawAdminFee (uint256 adminFeeDenominator, address laoFundAddress, address[] memory tokens) public onlyOwner nonReentrant {
//total up all shares and looot
uint256 initialTotalSharesAndLoot = totalShares.add(totalLoot);
//SERGEI - solution to incentivize timely payment.
require (now >= lastPaymentTime.add(paymentPeriod), "90 days have not passed since last withdrawal");
//SERGEI - reset lastPaymentTime : solution to incentivize payment call in a timely manner.
lastPaymentTime =now;
//check admin fee is less than .5%%
//if divide by => 200, admin fee will be .5% or less every 90 days.
//under consideration -- (shares * 5) / 1000 more readable then shares / 200 -- if hardcoding - Sergei.
require(adminFeeDenominator >= 199); //199 to get .5% - Heiko
//.05% or less of all assets
//uint256 adminFee = (totalLoot.add(totalShares)).div(adminFeeDenominator);
uint256 adminFee = initialTotalSharesAndLoot.div(adminFeeDenominator);
//HEIKO - loop borrowed from _ragequit, go through tokens, calculate fair share, credit to laoFundAddress
for (uint256 i = 0; i < tokens.length; i++) {
uint256 amountToRagequit = fairShare(userTokenBalances[GUILD][tokens[i]], adminFee, initialTotalSharesAndLoot);
// 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][tokens[i]] -= amountToRagequit;
userTokenBalances[laoFundAddress][tokens[i]] += amountToRagequit;
}
} //withdrawAdminFee end
}//k end
@HeikoFisch
Copy link

If we're doing the iteration over the tokens ourselves, shares are not needed anymore.
Also, we're currently making a few changes in and around the loop, so, for simplicity, here's a version of this function as I would write it.
I removed the comments. Of course, you can add them again, as you see fit.
Most importantly: The code is untested!

This version iterates over all whitelisted tokens. It is not impossible to write a more sophisticated version of this function that receives as input a list of tokens, so that some tokens can be excluded. However, there would be some subtle gas-related points to consider, so I suggest to stick to this version.

The final code is quite short and should be pretty self-explanatory, but if there are any questions, please feel free to ask.

contract Moloch is ReentrancyGuard, Ownable {
    using SafeMath for uint256;

    //....REST IS SAME AS MOLOCH DAO CODE. 

    uint256 constant paymentPeriod = 90 days;
    uint256 public lastPaymentTime = summoningTime;

    function withdrawAdminFee(uint256 adminFeeDenominator, address laoFundAddress) public nonReentrant onlyOwner {
        require(adminFeeDenominator >= 200);

        require (now >= lastPaymentTime.add(paymentPeriod), "90 days have not passed since last withdrawal");
        lastPaymentTime = now;

        for (uint256 i = 0; i < approvedTokens.length; i++) {
            address token = approvedTokens[i];
            uint256 amount = userTokenBalances[GUILD][token] / adminFeeDenominator;
            if (amount > 0) { // otherwise skip for efficiency
                unsafeInternalTransfer(GUILD, laoFundAddress, token, amount);
            }
        }
    }
}

@mcchan1
Copy link
Author

mcchan1 commented Jan 27, 2020

Without the laoFundAddress parameter... and having it transfer back to owner/msg.sender...

    using SafeMath for uint256;

    //....REST IS SAME AS MOLOCH DAO CODE. 

    uint256 constant paymentPeriod = 90 days;
    uint256 public lastPaymentTime = summoningTime;

// @param adminFeeDenoimnator must be >= 200. Greater than 200, will equal 0.5% or less of assets.  
//This results in Token Assets Under LAO/adminFeeDenominator

    function withdrawAdminFee(uint256 adminFeeDenominator) public nonReentrant onlyOwner {
        require(adminFeeDenominator >= 200);
        require (now >= lastPaymentTime.add(paymentPeriod), "90 days have not passed since last withdrawal");
        lastPaymentTime = now;

        for (uint256 i = 0; i < approvedTokens.length; i++) {
            address token = approvedTokens[i];
            uint256 amount = userTokenBalances[GUILD][token] / adminFeeDenominator;
            if (amount > 0) { // otherwise skip for efficiency
                unsafeInternalTransfer(GUILD, msg.sender, token, amount); //transfer tokens to msg.sender/Owner
            }
        }
    }
}```

@HeikoFisch
Copy link

The main change looks good to me.
But note that in the line uint256 amount = userTokenBalances[GUILD][token] / adminFeeDenominator; you changed the single / to //. The original version was correct, because this is intended to be a division.

@mcchan1
Copy link
Author

mcchan1 commented Jan 27, 2020

thank you... also if we want .5% which is more accurate: >=200 or >=199

@HeikoFisch
Copy link

In this version, it's >= 200, because you're not minting new shares/loot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment