Contract Name:
GDAODelegator
Contract Source Code:
pragma solidity 0.5.17;
contract GDAOGovernanceStorage {
/// @notice A record of each accounts delegate
mapping (address => address) internal _delegates;
/// @notice A checkpoint for marking number of votes from a given block
struct Checkpoint {
uint32 fromBlock;
uint256 votes;
}
/// @notice A record of votes checkpoints for each account, by index
mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
/// @notice The number of checkpoints for each account
mapping (address => uint32) public numCheckpoints;
/// @notice The EIP-712 typehash for the contract's domain
bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
/// @notice The EIP-712 typehash for the delegation struct used by the contract
bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
/// @notice A record of states for signing / validating signatures
mapping (address => uint) public nonces;
}
// SPDX-License-Identifier: MIT
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// Storage for a GDAO token
contract GDAOTokenStorage {
using SafeMath for uint256;
/**
* @dev Guard variable for re-entrancy checks. Not currently used
*/
bool internal _notEntered;
/**
* @notice EIP-20 token name for this token
*/
string public name;
/**
* @notice EIP-20 token symbol for this token
*/
string public symbol;
/**
* @notice EIP-20 token decimals for this token
*/
uint8 public decimals;
/**
* @notice Governor for this contract
*/
address public gov;
/**
* @notice Pending governance for this contract
*/
address public pendingGov;
/**
* @notice Total supply of GDAOs
*/
uint256 internal _totalSupply;
uint256 internal _cap;
address[] internal _minters;
mapping (address => uint256) internal _minterIndex;
mapping (address => uint256) internal _gdaoBalances;
mapping (address => mapping (address => uint256)) internal _allowedFragments;
}
contract GDAOTokenInterface is GDAOTokenStorage, GDAOGovernanceStorage {
/// @notice An event thats emitted when an account changes its delegate
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
/// @notice An event thats emitted when a delegate account's vote balance changes
event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
/*** Gov Events ***/
/**
* @notice Event emitted when pendingGov is changed
*/
event NewPendingGov(address oldPendingGov, address newPendingGov);
/**
* @notice Event emitted when gov is changed
*/
event NewGov(address oldGov, address newGov);
/* - ERC20 Events - */
/**
* @notice EIP20 Transfer event
*/
event Transfer(address indexed from, address indexed to, uint amount);
/**
* @notice EIP20 Approval event
*/
event Approval(address indexed owner, address indexed spender, uint amount);
/* - Extra Events - */
/**
* @notice Tokens minted event
*/
event Mint(address to, uint256 amount);
event AddMinter(address minter);
event RemoveMinter(address minter);
/**
* @notice Tokens burned event
*/
event Burn(address who, uint256 amount);
event NewCap(uint256 oldCap, uint256 newCap);
// Public functions
function totalSupply() external view returns (uint256);
function transfer(address to, uint256 value) external returns(bool);
function transferFrom(address from, address to, uint256 value) external returns(bool);
function balanceOf(address who) external view returns(uint256);
function allowance(address owner_, address spender) external view returns(uint256);
function approve(address spender, uint256 value) external returns (bool);
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
function burn(uint256 amount) external returns (bool);
function cap() external view returns (uint256);
function minterCount() external view returns (uint256);
function getMinter(uint256 idx) external view returns (address);
/* - Governance Functions - */
function getPriorVotes(address account, uint blockNumber) external view returns (uint256);
function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) external;
function delegate(address delegatee) external;
function delegates(address delegator) external view returns (address);
function getCurrentVotes(address account) external view returns (uint256);
/* - Permissioned/Governance functions - */
function mint(address to, uint256 amount) external returns (bool);
function _setPendingGov(address pendingGov_) external;
function _acceptGov() external;
function setCap(uint256 ncap) external returns (bool);
function addMinter(address minter) external returns (bool);
function removeMinter(address minter) external returns (bool);
}
contract GDAOGovernanceToken is GDAOTokenInterface {
/// @notice An event thats emitted when an account changes its delegate
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
/// @notice An event thats emitted when a delegate account's vote balance changes
event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
/**
* @notice Delegate votes from `msg.sender` to `delegatee`
* @param delegator The address to get delegatee for
*/
function delegates(address delegator)
external
view
returns (address)
{
return _delegates[delegator];
}
/**
* @notice Delegate votes from `msg.sender` to `delegatee`
* @param delegatee The address to delegate votes to
*/
function delegate(address delegatee) external {
return _delegate(msg.sender, delegatee);
}
/**
* @notice Delegates votes from signatory to `delegatee`
* @param delegatee The address to delegate votes to
* @param nonce The contract state required to match the signature
* @param expiry The time at which to expire the signature
* @param v The recovery byte of the signature
* @param r Half of the ECDSA signature pair
* @param s Half of the ECDSA signature pair
*/
function delegateBySig(
address delegatee,
uint nonce,
uint expiry,
uint8 v,
bytes32 r,
bytes32 s
)
external
{
bytes32 domainSeparator = keccak256(
abi.encode(
DOMAIN_TYPEHASH,
keccak256(bytes(name)),
getChainId(),
address(this)
)
);
bytes32 structHash = keccak256(
abi.encode(
DELEGATION_TYPEHASH,
delegatee,
nonce,
expiry
)
);
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
domainSeparator,
structHash
)
);
address signatory = ecrecover(digest, v, r, s);
require(signatory != address(0), "GDAO::delegateBySig: invalid signature");
require(nonce == nonces[signatory]++, "GDAO::delegateBySig: invalid nonce");
require(now <= expiry, "GDAO::delegateBySig: signature expired");
return _delegate(signatory, delegatee);
}
/**
* @notice Gets the current votes balance for `account`
* @param account The address to get votes balance
* @return The number of current votes for `account`
*/
function getCurrentVotes(address account)
external
view
returns (uint256)
{
uint32 nCheckpoints = numCheckpoints[account];
return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
}
/**
* @notice Determine the prior number of votes for an account as of a block number
* @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
* @param account The address of the account to check
* @param blockNumber The block number to get the vote balance at
* @return The number of votes the account had as of the given block
*/
function getPriorVotes(address account, uint blockNumber)
external
view
returns (uint256)
{
require(blockNumber < block.number, "GDAO::getPriorVotes: not yet determined");
uint32 nCheckpoints = numCheckpoints[account];
if (nCheckpoints == 0) {
return 0;
}
// First check most recent balance
if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
return checkpoints[account][nCheckpoints - 1].votes;
}
// Next check implicit zero balance
if (checkpoints[account][0].fromBlock > blockNumber) {
return 0;
}
uint32 lower = 0;
uint32 upper = nCheckpoints - 1;
while (upper > lower) {
uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
Checkpoint memory cp = checkpoints[account][center];
if (cp.fromBlock == blockNumber) {
return cp.votes;
} else if (cp.fromBlock < blockNumber) {
lower = center;
} else {
upper = center - 1;
}
}
return checkpoints[account][lower].votes;
}
function _delegate(address delegator, address delegatee)
internal
{
address currentDelegate = _delegates[delegator];
uint256 delegatorBalance = _gdaoBalances[delegator]; // balance of underlying GDAOs;
_delegates[delegator] = delegatee;
emit DelegateChanged(delegator, currentDelegate, delegatee);
_moveDelegates(currentDelegate, delegatee, delegatorBalance);
}
function _moveDelegates(address srcRep, address dstRep, uint256 amount) internal {
if (srcRep != dstRep && amount > 0) {
if (srcRep != address(0)) {
// decrease old representative
uint32 srcRepNum = numCheckpoints[srcRep];
uint256 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
uint256 srcRepNew = srcRepOld.sub(amount);
_writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
}
if (dstRep != address(0)) {
// increase new representative
uint32 dstRepNum = numCheckpoints[dstRep];
uint256 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
uint256 dstRepNew = dstRepOld.add(amount);
_writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
}
}
}
function _writeCheckpoint(
address delegatee,
uint32 nCheckpoints,
uint256 oldVotes,
uint256 newVotes
)
internal
{
uint32 blockNumber = safe32(block.number, "GDAO::_writeCheckpoint: block number exceeds 32 bits");
if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
} else {
checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
numCheckpoints[delegatee] = nCheckpoints + 1;
}
emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
}
function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
require(n < 2**32, errorMessage);
return uint32(n);
}
function getChainId() internal pure returns (uint) {
uint256 chainId;
assembly { chainId := chainid() }
return chainId;
}
}
contract GDAOToken is GDAOGovernanceToken {
// Modifiers
modifier onlyGov() {
require(msg.sender == gov);
_;
}
modifier onlyMinter() {
require(_minterIndex[msg.sender] != 0 || msg.sender == gov, "not minter");
_;
}
modifier validRecipient(address to) {
require(to != address(0x0));
require(to != address(this));
_;
}
function initialize(
string memory name_,
string memory symbol_,
uint8 decimals_
)
public
{
name = name_;
symbol = symbol_;
decimals = decimals_;
_cap = 10000000 * 10 ** uint256(decimals_);
}
/**
* @notice Computes the current totalSupply
*/
function totalSupply()
external
view
returns (uint256)
{
return _totalSupply;
}
function cap()
external
view
returns (uint256)
{
return _cap;
}
function setCap(uint256 ncap)
external
onlyGov
returns (bool)
{
require(ncap >= _totalSupply, "Invalid cap");
uint256 oldCap = _cap;
_cap = ncap;
emit NewCap(oldCap, ncap);
return true;
}
/**
* Add minter
* @param minter minter
*/
function addMinter(address minter)
external
onlyGov
returns (bool)
{
if (_minterIndex[minter] != 0) {
return false;
} else {
_minters.push(minter);
_minterIndex[minter] = _minters.length;
emit AddMinter(minter);
return true;
}
}
/**
* Remove minter
* @param minter minter
*/
function removeMinter(address minter)
external
onlyGov
returns (bool)
{
uint256 minterIdx = _minterIndex[minter];
if (minterIdx != 0) {
uint256 toDelIdx = minterIdx - 1;
uint256 lastIdx = _minters.length - 1;
address lastMinter = _minters[lastIdx];
_minters[toDelIdx] = lastMinter;
_minterIndex[lastMinter] = toDelIdx + 1;
_minters.pop();
delete _minterIndex[minter];
emit RemoveMinter(minter);
return true;
} else {
return false;
}
}
function minterCount()
external
view
returns (uint256)
{
return _minters.length;
}
function getMinter(uint256 idx)
external
view
returns (address)
{
return _minters[idx];
}
/**
* @notice Mints new tokens, increasing totalSupply, and a users balance.
* @dev Limited to onlyMinter modifier
*/
function mint(address to, uint256 amount)
external
onlyMinter
returns (bool)
{
_mint(to, amount);
return true;
}
function _mint(address to, uint256 amount)
internal
{
require(to != address(0), "Mint to the zero address");
// increase totalSupply
_totalSupply = _totalSupply.add(amount);
require(_totalSupply <= _cap, "Cap exceeded");
// add balance
_gdaoBalances[to] = _gdaoBalances[to].add(amount);
emit Transfer(address(0), to, amount);
// add delegates to the minter
_moveDelegates(address(0), _delegates[to], amount);
emit Mint(to, amount);
}
/**
* @notice Burns tokens, decreasing totalSupply, and a users balance.
*/
function burn(uint256 amount)
external
returns (bool)
{
_burn(msg.sender, amount);
return true;
}
function _burn(address who, uint256 amount)
internal
{
// decrease totalSupply
_totalSupply = _totalSupply.sub(amount);
// decrease cap
_cap = _cap.sub(amount);
// sub balance
_gdaoBalances[who] = _gdaoBalances[who].sub(amount);
emit Transfer(who, address(0), amount);
// sub delegates
_moveDelegates(_delegates[who], address(0), amount);
emit Burn(who, amount);
}
/* - ERC20 functionality - */
/**
* @dev Transfer tokens to a specified address.
* @param to The address to transfer to.
* @param value The amount to be transferred.
* @return True on success, false otherwise.
*/
function transfer(address to, uint256 value)
external
validRecipient(to)
returns (bool)
{
// sub from balance of sender
_gdaoBalances[msg.sender] = _gdaoBalances[msg.sender].sub(value);
// add to balance of receiver
_gdaoBalances[to] = _gdaoBalances[to].add(value);
emit Transfer(msg.sender, to, value);
_moveDelegates(_delegates[msg.sender], _delegates[to], value);
return true;
}
/**
* @dev Transfer tokens from one address to another.
* @param from The address you want to send tokens from.
* @param to The address you want to transfer to.
* @param value The amount of tokens to be transferred.
*/
function transferFrom(address from, address to, uint256 value)
external
validRecipient(to)
returns (bool)
{
// decrease allowance
_allowedFragments[from][msg.sender] = _allowedFragments[from][msg.sender].sub(value);
// sub from from
_gdaoBalances[from] = _gdaoBalances[from].sub(value);
_gdaoBalances[to] = _gdaoBalances[to].add(value);
emit Transfer(from, to, value);
_moveDelegates(_delegates[from], _delegates[to], value);
return true;
}
/**
* @param who The address to query.
* @return The balance of the specified address.
*/
function balanceOf(address who)
external
view
returns (uint256)
{
return _gdaoBalances[who];
}
/**
* @dev Function to check the amount of tokens that an owner has allowed to a spender.
* @param owner_ The address which owns the funds.
* @param spender The address which will spend the funds.
* @return The number of tokens still available for the spender.
*/
function allowance(address owner_, address spender)
external
view
returns (uint256)
{
return _allowedFragments[owner_][spender];
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of
* msg.sender. This method is included for ERC20 compatibility.
* increaseAllowance and decreaseAllowance should be used instead.
* Changing an allowance with this method brings the risk that someone may transfer both
* the old and the new allowance - if they are both greater than zero - if a transfer
* transaction is mined before the later approve() call is mined.
*
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
*/
function approve(address spender, uint256 value)
external
returns (bool)
{
_allowedFragments[msg.sender][spender] = value;
emit Approval(msg.sender, spender, value);
return true;
}
/**
* @dev Increase the amount of tokens that an owner has allowed to a spender.
* This method should be used instead of approve() to avoid the double approval vulnerability
* described above.
* @param spender The address which will spend the funds.
* @param addedValue The amount of tokens to increase the allowance by.
*/
function increaseAllowance(address spender, uint256 addedValue)
external
returns (bool)
{
_allowedFragments[msg.sender][spender] =
_allowedFragments[msg.sender][spender].add(addedValue);
emit Approval(msg.sender, spender, _allowedFragments[msg.sender][spender]);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner has allowed to a spender.
*
* @param spender The address which will spend the funds.
* @param subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseAllowance(address spender, uint256 subtractedValue)
external
returns (bool)
{
uint256 oldValue = _allowedFragments[msg.sender][spender];
if (subtractedValue >= oldValue) {
_allowedFragments[msg.sender][spender] = 0;
} else {
_allowedFragments[msg.sender][spender] = oldValue.sub(subtractedValue);
}
emit Approval(msg.sender, spender, _allowedFragments[msg.sender][spender]);
return true;
}
/* - Governance Functions - */
/** @notice sets the pendingGov
* @param pendingGov_ The address of the governor to use for authentication.
*/
function _setPendingGov(address pendingGov_)
external
onlyGov
{
address oldPendingGov = pendingGov;
pendingGov = pendingGov_;
emit NewPendingGov(oldPendingGov, pendingGov_);
}
/** @notice lets msg.sender accept governance
*
*/
function _acceptGov()
external
{
require(msg.sender == pendingGov, "!pending");
address oldGov = gov;
gov = pendingGov;
pendingGov = address(0);
emit NewGov(oldGov, gov);
}
}
contract GDAO is GDAOToken {
/**
* @notice Initialize the new money market
* @param name_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
*/
function initialize(
string memory name_,
string memory symbol_,
uint8 decimals_,
address initial_owner,
uint256 initSupply_
)
public
{
require(initSupply_ >= 0, "0 init supply");
super.initialize(name_, symbol_, decimals_);
_mint(initial_owner, initSupply_);
}
}
contract GDAODelegationStorage {
/**
* @notice Implementation address for this contract
*/
address public implementation;
}
contract GDAODelegatorInterface is GDAODelegationStorage {
/**
* @notice Emitted when implementation is changed
*/
event NewImplementation(address oldImplementation, address newImplementation);
/**
* @notice Called by the gov to update the implementation of the delegator
* @param implementation_ The address of the new implementation for delegation
* @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation
* @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation
*/
function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) public;
}
contract GDAODelegateInterface is GDAODelegationStorage {
/**
* @notice Called by the delegator on a delegate to initialize it for duty
* @dev Should revert if any issues arise which make it unfit for delegation
* @param data The encoded bytes data for any initialization
*/
function _becomeImplementation(bytes memory data) public;
/**
* @notice Called by the delegator on a delegate to forfeit its responsibility
*/
function _resignImplementation() public;
}
contract GDAODelegate is GDAO, GDAODelegateInterface {
/**
* @notice Construct an empty delegate
*/
constructor() public {}
/**
* @notice Called by the delegator on a delegate to initialize it for duty
* @param data The encoded bytes data for any initialization
*/
function _becomeImplementation(bytes memory data) public {
// Shh -- currently unused
data;
// Shh -- we don't ever want this hook to be marked pure
if (false) {
implementation = address(0);
}
require(msg.sender == gov, "only the gov may call _becomeImplementation");
}
/**
* @notice Called by the delegator on a delegate to forfeit its responsibility
*/
function _resignImplementation() public {
// Shh -- we don't ever want this hook to be marked pure
if (false) {
implementation = address(0);
}
require(msg.sender == gov, "only the gov may call _resignImplementation");
}
}
pragma solidity 0.5.17;
import "./GDAODelegate.sol";
contract GDAODelegator is GDAOTokenInterface, GDAODelegatorInterface {
/**
* @notice Construct a new GDAO
* @param name_ ERC-20 name of this token
* @param symbol_ ERC-20 symbol of this token
* @param decimals_ ERC-20 decimal precision of this token
* @param initSupply_ Initial token amount
* @param implementation_ The address of the implementation the contract delegates to
* @param becomeImplementationData The encoded args for becomeImplementation
*/
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_,
uint256 initSupply_,
address implementation_,
bytes memory becomeImplementationData
)
public
{
// Creator of the contract is gov during initialization
gov = msg.sender;
// First delegate gets to initialize the delegator (i.e. storage contract)
delegateTo(
implementation_,
abi.encodeWithSignature(
"initialize(string,string,uint8,address,uint256)",
name_,
symbol_,
decimals_,
msg.sender,
initSupply_
)
);
// New implementations always get set via the settor (post-initialize)
_setImplementation(implementation_, false, becomeImplementationData);
}
/**
* @notice Called by the gov to update the implementation of the delegator
* @param implementation_ The address of the new implementation for delegation
* @param allowResign Flag to indicate whether to call _resignImplementation on the old implementation
* @param becomeImplementationData The encoded bytes data to be passed to _becomeImplementation
*/
function _setImplementation(address implementation_, bool allowResign, bytes memory becomeImplementationData) public {
require(msg.sender == gov, "GDAODelegator::_setImplementation: Caller must be gov");
if (allowResign) {
delegateToImplementation(abi.encodeWithSignature("_resignImplementation()"));
}
address oldImplementation = implementation;
implementation = implementation_;
delegateToImplementation(abi.encodeWithSignature("_becomeImplementation(bytes)", becomeImplementationData));
emit NewImplementation(oldImplementation, implementation);
}
/**
* @notice Sender supplies assets into the market and receives cTokens in exchange
* @dev Accrues interest whether or not the operation succeeds, unless reverted
* @param mintAmount The amount of the underlying asset to supply
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function mint(address to, uint256 mintAmount)
external
returns (bool)
{
to; mintAmount; // Shh
delegateAndReturn();
}
/**
* @notice Burns tokens, decreasing totalSupply, and a users balance.
*/
function burn(uint256 amount)
external
returns (bool)
{
amount;
delegateAndReturn();
}
/**
* @notice Transfer `amount` tokens from `msg.sender` to `dst`
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transfer(address dst, uint256 amount)
external
returns (bool)
{
dst; amount; // Shh
delegateAndReturn();
}
/**
* @notice Transfer `amount` tokens from `src` to `dst`
* @param src The address of the source account
* @param dst The address of the destination account
* @param amount The number of tokens to transfer
* @return Whether or not the transfer succeeded
*/
function transferFrom(
address src,
address dst,
uint256 amount
)
external
returns (bool)
{
src; dst; amount; // Shh
delegateAndReturn();
}
/**
* @notice Approve `spender` to transfer up to `amount` from `src`
* @dev This will overwrite the approval amount for `spender`
* and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve)
* @param spender The address of the account which may transfer tokens
* @param amount The number of tokens that are approved (-1 means infinite)
* @return Whether or not the approval succeeded
*/
function approve(
address spender,
uint256 amount
)
external
returns (bool)
{
spender; amount; // Shh
delegateAndReturn();
}
/**
* @dev Increase the amount of tokens that an owner has allowed to a spender.
* This method should be used instead of approve() to avoid the double approval vulnerability
* described above.
* @param spender The address which will spend the funds.
* @param addedValue The amount of tokens to increase the allowance by.
*/
function increaseAllowance(
address spender,
uint256 addedValue
)
external
returns (bool)
{
spender; addedValue; // Shh
delegateAndReturn();
}
function totalSupply()
external
view
returns (uint256)
{
delegateToViewAndReturn();
}
function cap()
external
view
returns (uint256)
{
delegateToViewAndReturn();
}
function setCap(uint256 ncap)
external
returns (bool)
{
ncap;
delegateAndReturn();
}
/**
* Add minter
* @param minter minter
*/
function addMinter(address minter)
external
returns (bool)
{
minter;
delegateAndReturn();
}
/**
* Remove minter
* @param minter minter
*/
function removeMinter(address minter)
external
returns (bool)
{
minter;
delegateAndReturn();
}
function minterCount()
external
view
returns (uint256)
{
delegateToViewAndReturn();
}
function getMinter(uint256 idx)
external
view
returns (address)
{
idx;
delegateToViewAndReturn();
}
/**
* @dev Decrease the amount of tokens that an owner has allowed to a spender.
*
* @param spender The address which will spend the funds.
* @param subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseAllowance(
address spender,
uint256 subtractedValue
)
external
returns (bool)
{
spender; subtractedValue; // Shh
delegateAndReturn();
}
/**
* @notice Get the current allowance from `owner` for `spender`
* @param owner The address of the account which owns the tokens to be spent
* @param spender The address of the account which may transfer tokens
* @return The number of tokens allowed to be spent (-1 means infinite)
*/
function allowance(
address owner,
address spender
)
external
view
returns (uint256)
{
owner; spender; // Shh
delegateToViewAndReturn();
}
/**
* @notice Get the current allowance from `owner` for `spender`
* @param delegator The address of the account which has designated a delegate
* @return Address of delegatee
*/
function delegates(
address delegator
)
external
view
returns (address)
{
delegator; // Shh
delegateToViewAndReturn();
}
/**
* @notice Get the token balance of the `owner`
* @param owner The address of the account to query
* @return The number of tokens owned by `owner`
*/
function balanceOf(address owner)
external
view
returns (uint256)
{
owner; // Shh
delegateToViewAndReturn();
}
/*** Gov Functions ***/
/**
* @notice Begins transfer of gov rights. The newPendingGov must call `_acceptGov` to finalize the transfer.
* @dev Gov function to begin change of gov. The newPendingGov must call `_acceptGov` to finalize the transfer.
* @param newPendingGov New pending gov.
*/
function _setPendingGov(address newPendingGov)
external
{
newPendingGov; // Shh
delegateAndReturn();
}
/**
* @notice Accepts transfer of gov rights. msg.sender must be pendingGov
* @dev Gov function for pending gov to accept role and update gov
* @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
*/
function _acceptGov()
external
{
delegateAndReturn();
}
function getPriorVotes(address account, uint blockNumber)
external
view
returns (uint256)
{
account; blockNumber;
delegateToViewAndReturn();
}
function delegateBySig(
address delegatee,
uint nonce,
uint expiry,
uint8 v,
bytes32 r,
bytes32 s
)
external
{
delegatee; nonce; expiry; v; r; s;
delegateAndReturn();
}
function delegate(address delegatee)
external
{
delegatee;
delegateAndReturn();
}
function getCurrentVotes(address account)
external
view
returns (uint256)
{
account;
delegateToViewAndReturn();
}
/**
* @notice Internal method to delegate execution to another contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* @param callee The contract to delegatecall
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateTo(address callee, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returnData) = callee.delegatecall(data);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize)
}
}
return returnData;
}
/**
* @notice Delegates execution to the implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateToImplementation(bytes memory data) public returns (bytes memory) {
return delegateTo(implementation, data);
}
/**
* @notice Delegates execution to an implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
* There are an additional 2 prefix uints from the wrapper returndata, which we ignore since we make an extra hop.
* @param data The raw data to delegatecall
* @return The returned bytes from the delegatecall
*/
function delegateToViewImplementation(bytes memory data) public view returns (bytes memory) {
(bool success, bytes memory returnData) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", data));
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize)
}
}
return abi.decode(returnData, (bytes));
}
function delegateToViewAndReturn() private view returns (bytes memory) {
(bool success, ) = address(this).staticcall(abi.encodeWithSignature("delegateToImplementation(bytes)", msg.data));
assembly {
let free_mem_ptr := mload(0x40)
returndatacopy(free_mem_ptr, 0, returndatasize)
switch success
case 0 { revert(free_mem_ptr, returndatasize) }
default { return(add(free_mem_ptr, 0x40), returndatasize) }
}
}
function delegateAndReturn() private returns (bytes memory) {
(bool success, ) = implementation.delegatecall(msg.data);
assembly {
let free_mem_ptr := mload(0x40)
returndatacopy(free_mem_ptr, 0, returndatasize)
switch success
case 0 { revert(free_mem_ptr, returndatasize) }
default { return(free_mem_ptr, returndatasize) }
}
}
/**
* @notice Delegates execution to an implementation contract
* @dev It returns to the external caller whatever the implementation returns or forwards reverts
*/
function () external payable {
require(msg.value == 0,"GDAODelegator:fallback: cannot send value to fallback");
// delegate all other functions to current implementation
delegateAndReturn();
}
}