liquid-funding/contracts/LiquidPledgingBase.sol

600 lines
23 KiB
Solidity
Raw Normal View History

2017-06-06 17:40:14 +00:00
pragma solidity ^0.4.11;
/*
Copyright 2017, Jordi Baylina
2017-12-04 01:18:31 +00:00
Contributors: Adrià Massanet <adria@codecontext.io>, RJ Ewing, Griff
Green, Arthur Lunn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2017-06-06 17:40:14 +00:00
2017-09-13 12:41:08 +00:00
import "./ILiquidPledgingPlugin.sol";
2017-12-05 19:58:20 +00:00
import "giveth-common-contracts/contracts/Escapable.sol";
2017-09-13 12:41:08 +00:00
2017-12-04 01:18:31 +00:00
/// @dev This is an interface for `LPVault` which serves as a secure storage for
/// the ETH that backs the Pledges, only after `LiquidPledging` authorizes
/// payments can Pledges be converted for ETH
2017-12-05 20:42:59 +00:00
interface LPVault {
2018-01-15 22:36:17 +00:00
function authorizePayment(bytes32 _ref, address _dest, uint _amount) public;
function () public payable;
2017-07-13 17:12:45 +00:00
}
2017-06-06 17:40:14 +00:00
/// @dev `LiquidPledgingBase` is the base level contract used to carry out
2017-12-04 01:18:31 +00:00
/// liquidPledging's most basic functions, mostly handling and searching the
/// data structures
2017-12-05 19:58:20 +00:00
contract LiquidPledgingBase is Escapable {
2017-10-03 10:20:23 +00:00
// Limits inserted to prevent large loops that could prevent canceling
uint constant MAX_DELEGATES = 10;
2017-10-04 23:27:23 +00:00
uint constant MAX_SUBPROJECT_LEVEL = 20;
uint constant MAX_INTERPROJECT_LEVEL = 20;
2017-06-06 17:40:14 +00:00
2017-10-04 23:27:23 +00:00
enum PledgeAdminType { Giver, Delegate, Project }
2017-12-05 20:42:59 +00:00
enum PledgeState { Pledged, Paying, Paid }
2017-12-03 00:59:30 +00:00
/// @dev This struct defines the details of a `PledgeAdmin` which are
2017-12-04 01:18:31 +00:00
/// commonly referenced by their index in the `admins` array
2017-12-03 00:59:30 +00:00
/// and can own pledges and act as delegates
struct PledgeAdmin {
2017-10-04 23:27:23 +00:00
PledgeAdminType adminType; // Giver, Delegate or Project
address addr; // Account or contract address for admin
2017-10-03 10:20:23 +00:00
string name;
string url; // Can be IPFS hash
uint64 commitTime; // In seconds, used for Givers' & Delegates' vetos
2017-10-04 23:27:23 +00:00
uint64 parentProject; // Only for projects
bool canceled; //Always false except for canceled projects
/// @dev if the plugin is 0x0 then nothing happens, if its an address
// than that smart contract is called when appropriate
ILiquidPledgingPlugin plugin;
2017-06-06 17:40:14 +00:00
}
2017-10-03 12:42:21 +00:00
struct Pledge {
2017-06-06 17:40:14 +00:00
uint amount;
2017-10-04 08:24:35 +00:00
uint64 owner; // PledgeAdmin
uint64[] delegationChain; // List of delegates in order of authority
uint64 intendedProject; // Used when delegates are sending to projects
uint64 commitTime; // When the intendedProject will become the owner
uint64 oldPledge; // Points to the id that this Pledge was derived from
2017-12-05 20:42:59 +00:00
PledgeState pledgeState; // Pledged, Paying, Paid
2017-06-06 17:40:14 +00:00
}
2017-10-03 12:42:21 +00:00
Pledge[] pledges;
2017-10-04 08:24:35 +00:00
PledgeAdmin[] admins; //The list of pledgeAdmins 0 means there is no admin
2017-11-01 21:03:03 +00:00
LPVault public vault;
2017-06-06 17:40:14 +00:00
/// @dev this mapping allows you to search for a specific pledge's
/// index number by the hash of that pledge
mapping (bytes32 => uint64) hPledge2idx;
2017-11-16 23:15:32 +00:00
mapping (bytes32 => bool) pluginWhitelist;
2017-11-16 23:15:32 +00:00
bool public usePluginWhitelist = true;
2017-06-06 17:40:14 +00:00
/////////////
2017-06-06 17:40:14 +00:00
// Modifiers
/////////////
2017-06-06 17:40:14 +00:00
/// @dev The `vault`is the only addresses that can call a function with this
/// modifier
2017-06-06 17:40:14 +00:00
modifier onlyVault() {
2017-07-13 17:12:45 +00:00
require(msg.sender == address(vault));
2017-06-06 17:40:14 +00:00
_;
}
///////////////
2017-06-06 17:40:14 +00:00
// Constructor
///////////////
2017-06-06 17:40:14 +00:00
/// @notice The Constructor creates `LiquidPledgingBase` on the blockchain
/// @param _vault The vault where the ETH backing the pledges is stored
2017-12-05 19:58:20 +00:00
function LiquidPledgingBase(
address _vault,
address _escapeHatchCaller,
address _escapeHatchDestination
) Escapable(_escapeHatchCaller, _escapeHatchDestination) public {
2017-10-04 08:24:35 +00:00
admins.length = 1; // we reserve the 0 admin
2017-10-03 12:42:21 +00:00
pledges.length = 1; // we reserve the 0 pledge
vault = LPVault(_vault); // Assigns the specified vault
2017-06-06 17:40:14 +00:00
}
/////////////////////////
// PledgeAdmin functions
/////////////////////////
/// @notice Creates a Giver Admin with the `msg.sender` as the Admin address
/// @param name The name used to identify the Giver
/// @param url The link to the Giver's profile often an IPFS hash
/// @param commitTime The length of time in seconds the Giver has to
/// veto when the Giver's delegates Pledge funds to a project
/// @param plugin This is Giver's liquid pledge plugin allowing for
/// extended functionality
/// @return idGiver The id number used to reference this Admin
2017-10-28 08:27:47 +00:00
function addGiver(
string name,
string url,
uint64 commitTime,
ILiquidPledgingPlugin plugin
2018-01-15 22:36:17 +00:00
) public returns (uint64 idGiver) {
require(isValidPlugin(plugin)); // Plugin check
2017-10-04 08:24:35 +00:00
idGiver = uint64(admins.length);
2017-09-14 18:06:58 +00:00
2017-10-04 08:24:35 +00:00
admins.push(PledgeAdmin(
PledgeAdminType.Giver,
2017-06-06 17:40:14 +00:00
msg.sender,
name,
2017-10-04 09:40:26 +00:00
url,
2017-06-06 17:40:14 +00:00
commitTime,
0,
2017-09-13 12:41:08 +00:00
false,
plugin));
2017-09-28 15:49:10 +00:00
2017-10-03 10:20:23 +00:00
GiverAdded(idGiver);
2017-06-06 17:40:14 +00:00
}
2017-10-03 10:20:23 +00:00
event GiverAdded(uint64 indexed idGiver);
2017-06-06 17:40:14 +00:00
/// @notice Updates a Giver's info to change the address, name, url, or
/// commitTime, it cannot be used to change a plugin, and it must be called
/// by the current address of the Giver
/// @param idGiver This is the Admin id number used to specify the Giver
/// @param newAddr The new address that represents this Giver
/// @param newName The new name used to identify the Giver
/// @param newUrl The new link to the Giver's profile often an IPFS hash
/// @param newCommitTime Sets the length of time in seconds the Giver has to
/// veto when the Giver's delegates Pledge funds to a project
2017-10-03 10:20:23 +00:00
function updateGiver(
uint64 idGiver,
2017-06-06 17:40:14 +00:00
address newAddr,
string newName,
2017-10-04 09:40:26 +00:00
string newUrl,
2018-01-15 22:36:17 +00:00
uint64 newCommitTime) public
2017-06-06 17:40:14 +00:00
{
2017-10-04 08:24:35 +00:00
PledgeAdmin storage giver = findAdmin(idGiver);
require(giver.adminType == PledgeAdminType.Giver); // Must be a Giver
require(giver.addr == msg.sender); // Current addr had to send this tx
2017-10-03 10:20:23 +00:00
giver.addr = newAddr;
giver.name = newName;
2017-10-04 09:40:26 +00:00
giver.url = newUrl;
2017-10-03 10:20:23 +00:00
giver.commitTime = newCommitTime;
GiverUpdated(idGiver);
2017-06-06 17:40:14 +00:00
}
2017-10-03 10:20:23 +00:00
event GiverUpdated(uint64 indexed idGiver);
2017-06-06 17:40:14 +00:00
/// @notice Creates a Delegate Admin with the `msg.sender` as the Admin addr
/// @param name The name used to identify the Delegate
/// @param url The link to the Delegate's profile often an IPFS hash
2017-12-03 00:59:30 +00:00
/// @param commitTime Sets the length of time in seconds that this delegate
/// can be vetoed. Whenever this delegate is in a delegate chain the time
/// allowed to veto any event must be greater than or equal to this time.
/// @param plugin This is Delegate's liquid pledge plugin allowing for
/// extended functionality
/// @return idxDelegate The id number used to reference this Delegate within
/// the admins array
2017-10-27 19:09:55 +00:00
function addDelegate(
string name,
string url,
uint64 commitTime,
ILiquidPledgingPlugin plugin
2018-01-15 22:36:17 +00:00
) public returns (uint64 idDelegate) {
require(isValidPlugin(plugin)); // Plugin check
2017-12-03 01:43:16 +00:00
idDelegate = uint64(admins.length);
2017-09-14 18:06:58 +00:00
2017-10-04 08:24:35 +00:00
admins.push(PledgeAdmin(
PledgeAdminType.Delegate,
2017-06-06 17:40:14 +00:00
msg.sender,
name,
2017-10-04 09:40:26 +00:00
url,
2017-09-13 12:41:08 +00:00
commitTime,
2017-06-06 17:40:14 +00:00
0,
2017-09-13 12:41:08 +00:00
false,
plugin));
2017-06-06 17:40:14 +00:00
2017-12-03 01:43:16 +00:00
DelegateAdded(idDelegate);
2017-06-06 17:40:14 +00:00
}
2017-12-03 01:43:16 +00:00
event DelegateAdded(uint64 indexed idDelegate);
2017-06-06 17:40:14 +00:00
/// @notice Updates a Delegate's info to change the address, name, url, or
/// commitTime, it cannot be used to change a plugin, and it must be called
/// by the current address of the Delegate
2017-12-03 01:43:16 +00:00
/// @param idDelegate The Admin id number used to specify the Delegate
/// @param newAddr The new address that represents this Delegate
/// @param newName The new name used to identify the Delegate
/// @param newUrl The new link to the Delegate's profile often an IPFS hash
2017-12-03 00:59:30 +00:00
/// @param newCommitTime Sets the length of time in seconds that this
/// delegate can be vetoed. Whenever this delegate is in a delegate chain
/// the time allowed to veto any event must be greater than or equal to
/// this time.
2017-09-13 12:41:08 +00:00
function updateDelegate(
2017-12-03 01:43:16 +00:00
uint64 idDelegate,
2017-09-13 12:41:08 +00:00
address newAddr,
string newName,
2017-10-04 09:40:26 +00:00
string newUrl,
2018-01-15 22:36:17 +00:00
uint64 newCommitTime) public
{
2017-12-03 01:43:16 +00:00
PledgeAdmin storage delegate = findAdmin(idDelegate);
2017-10-04 08:24:35 +00:00
require(delegate.adminType == PledgeAdminType.Delegate);
require(delegate.addr == msg.sender);// Current addr had to send this tx
2017-06-06 17:40:14 +00:00
delegate.addr = newAddr;
delegate.name = newName;
2017-10-04 09:40:26 +00:00
delegate.url = newUrl;
2017-09-13 12:41:08 +00:00
delegate.commitTime = newCommitTime;
2017-12-03 01:43:16 +00:00
DelegateUpdated(idDelegate);
2017-06-06 17:40:14 +00:00
}
2017-12-03 01:43:16 +00:00
event DelegateUpdated(uint64 indexed idDelegate);
2017-06-06 17:40:14 +00:00
/// @notice Creates a Project Admin with the `msg.sender` as the Admin addr
/// @param name The name used to identify the Project
/// @param url The link to the Project's profile often an IPFS hash
/// @param projectAdmin The address for the trusted project manager
2017-12-03 00:59:30 +00:00
/// @param parentProject The Admin id number for the parent project or 0 if
/// there is no parentProject
/// @param commitTime Sets the length of time in seconds the Project has to
/// veto when the Project delegates to another Delegate and they pledge
/// those funds to a project
/// @param plugin This is Project's liquid pledge plugin allowing for
/// extended functionality
/// @return idProject The id number used to reference this Admin
2017-10-27 19:09:55 +00:00
function addProject(
string name,
string url,
address projectAdmin,
uint64 parentProject,
uint64 commitTime,
ILiquidPledgingPlugin plugin
2018-01-15 22:36:17 +00:00
) public returns (uint64 idProject)
{
2017-11-16 23:15:32 +00:00
require(isValidPlugin(plugin));
2017-10-04 23:27:23 +00:00
if (parentProject != 0) {
PledgeAdmin storage pa = findAdmin(parentProject);
require(pa.adminType == PledgeAdminType.Project);
require(getProjectLevel(pa) < MAX_SUBPROJECT_LEVEL);
}
2017-09-14 18:06:58 +00:00
2017-10-04 23:27:23 +00:00
idProject = uint64(admins.length);
2017-09-14 18:06:58 +00:00
2017-10-04 08:24:35 +00:00
admins.push(PledgeAdmin(
2017-10-04 23:27:23 +00:00
PledgeAdminType.Project,
projectAdmin,
2017-06-06 17:40:14 +00:00
name,
2017-10-04 09:40:26 +00:00
url,
2017-06-06 17:40:14 +00:00
commitTime,
2017-10-04 23:27:23 +00:00
parentProject,
2017-09-13 12:41:08 +00:00
false,
plugin));
2017-06-06 17:40:14 +00:00
2017-10-04 23:27:23 +00:00
ProjectAdded(idProject);
2017-06-06 17:40:14 +00:00
}
2017-10-04 23:27:23 +00:00
event ProjectAdded(uint64 indexed idProject);
2017-06-06 17:40:14 +00:00
/// @notice Updates a Project's info to change the address, name, url, or
/// commitTime, it cannot be used to change a plugin or a parentProject,
/// and it must be called by the current address of the Project
/// @param idProject The Admin id number used to specify the Project
/// @param newAddr The new address that represents this Project
/// @param newName The new name used to identify the Project
/// @param newUrl The new link to the Project's profile often an IPFS hash
/// @param newCommitTime Sets the length of time in seconds the Project has
/// to veto when the Project delegates to a Delegate and they pledge those
/// funds to a project
2017-10-04 23:27:23 +00:00
function updateProject(
uint64 idProject,
address newAddr,
string newName,
2017-10-04 09:40:26 +00:00
string newUrl,
2018-01-15 22:36:17 +00:00
uint64 newCommitTime) public
{
2017-10-04 23:27:23 +00:00
PledgeAdmin storage project = findAdmin(idProject);
require(project.adminType == PledgeAdminType.Project);
require(project.addr == msg.sender);
project.addr = newAddr;
project.name = newName;
project.url = newUrl;
project.commitTime = newCommitTime;
ProjectUpdated(idProject);
2017-06-06 17:40:14 +00:00
}
2017-10-04 23:27:23 +00:00
event ProjectUpdated(uint64 indexed idAdmin);
2017-06-06 17:40:14 +00:00
//////////
// Public constant functions
//////////
/// @notice A constant getter that returns the total number of pledges
/// @return The total number of Pledges in the system
2018-01-15 22:36:17 +00:00
function numberOfPledges() public constant returns (uint) {
2017-10-03 12:42:21 +00:00
return pledges.length - 1;
2017-06-06 17:40:14 +00:00
}
2017-10-27 19:09:55 +00:00
/// @notice A getter that returns the details of the specified pledge
/// @param idPledge the id number of the pledge being queried
/// @return the amount, owner, the number of delegates (but not the actual
/// delegates, the intendedProject (if any), the current commit time and
/// the previous pledge this pledge was derived from
2018-01-15 22:36:17 +00:00
function getPledge(uint64 idPledge) public constant returns(
2017-06-06 17:40:14 +00:00
uint amount,
uint64 owner,
uint64 nDelegates,
2017-10-04 23:27:23 +00:00
uint64 intendedProject,
2017-06-27 11:08:23 +00:00
uint64 commitTime,
2017-10-03 12:42:21 +00:00
uint64 oldPledge,
2017-12-05 20:42:59 +00:00
PledgeState pledgeState
2017-06-06 17:40:14 +00:00
) {
2017-12-05 20:47:38 +00:00
Pledge storage p = findPledge(idPledge);
amount = p.amount;
owner = p.owner;
nDelegates = uint64(p.delegationChain.length);
intendedProject = p.intendedProject;
commitTime = p.commitTime;
oldPledge = p.oldPledge;
pledgeState = p.pledgeState;
2017-06-06 17:40:14 +00:00
}
2017-10-27 19:09:55 +00:00
/// @notice Getter to find Delegate w/ the Pledge ID & the Delegate index
/// @param idPledge The id number representing the pledge being queried
/// @param idxDelegate The index number for the delegate in this Pledge
2018-01-15 22:36:17 +00:00
function getPledgeDelegate(uint64 idPledge, uint idxDelegate) public constant returns(
2017-11-10 18:54:44 +00:00
uint64 idDelegate,
2017-06-06 17:40:14 +00:00
address addr,
string name
) {
2017-12-05 20:47:38 +00:00
Pledge storage p = findPledge(idPledge);
idDelegate = p.delegationChain[idxDelegate - 1];
2017-11-10 18:54:44 +00:00
PledgeAdmin storage delegate = findAdmin(idDelegate);
2017-06-06 17:40:14 +00:00
addr = delegate.addr;
name = delegate.name;
}
2017-10-27 19:09:55 +00:00
/// @notice A constant getter used to check how many total Admins exist
/// @return The total number of admins (Givers, Delegates and Projects) .
2018-01-15 22:36:17 +00:00
function numberOfPledgeAdmins() public constant returns(uint) {
2017-10-04 08:24:35 +00:00
return admins.length - 1;
2017-06-06 17:40:14 +00:00
}
2017-10-27 19:09:55 +00:00
/// @notice A constant getter to check the details of a specified Admin
/// @return addr Account or contract address for admin
/// @return name Name of the pledgeAdmin
/// @return url The link to the Project's profile often an IPFS hash
/// @return commitTime The length of time in seconds the Admin has to veto
/// when the Admin delegates to a Delegate and that Delegate pledges those
/// funds to a project
2017-12-03 00:59:30 +00:00
/// @return parentProject The Admin id number for the parent project or 0
/// if there is no parentProject
/// @return canceled 0 for Delegates & Givers, true if a Project has been
/// canceled
/// @return plugin This is Project's liquidPledging plugin allowing for
/// extended functionality
2018-01-15 22:36:17 +00:00
function getPledgeAdmin(uint64 idAdmin) public constant returns (
2017-10-04 08:24:35 +00:00
PledgeAdminType adminType,
2017-06-06 17:40:14 +00:00
address addr,
string name,
2017-10-04 09:40:26 +00:00
string url,
2017-06-06 17:40:14 +00:00
uint64 commitTime,
2017-10-04 23:27:23 +00:00
uint64 parentProject,
2017-09-26 19:06:45 +00:00
bool canceled,
address plugin)
2017-06-06 17:40:14 +00:00
{
2017-10-04 08:24:35 +00:00
PledgeAdmin storage m = findAdmin(idAdmin);
adminType = m.adminType;
2017-06-06 17:40:14 +00:00
addr = m.addr;
name = m.name;
2017-10-04 09:40:26 +00:00
url = m.url;
2017-06-06 17:40:14 +00:00
commitTime = m.commitTime;
2017-10-04 23:27:23 +00:00
parentProject = m.parentProject;
2017-06-06 17:40:14 +00:00
canceled = m.canceled;
2017-09-26 19:26:26 +00:00
plugin = address(m.plugin);
2017-06-06 17:40:14 +00:00
}
////////
// Private methods
///////
/// @notice This creates a Pledge with an initial amount of 0 if one is not
/// created already; otherwise it finds the pledge with the specified
/// attributes; all pledges technically exist, if the pledge hasn't been
2017-10-28 08:27:47 +00:00
/// created in this system yet it simply isn't in the hash array
/// hPledge2idx[] yet
/// @param owner The owner of the pledge being looked up
/// @param delegationChain The list of delegates in order of authority
/// @param intendedProject The project this pledge will Fund after the
/// commitTime has passed
/// @param commitTime The length of time in seconds the Giver has to
/// veto when the Giver's delegates Pledge funds to a project
/// @param oldPledge This value is used to store the pledge the current
/// pledge was came from, and in the case a Project is canceled, the Pledge
/// will revert back to it's previous state
2017-12-05 20:42:59 +00:00
/// @param state The pledge state: Pledged, Paying, or state
/// @return The hPledge2idx index number
2017-10-04 10:55:46 +00:00
function findOrCreatePledge(
2017-06-06 17:40:14 +00:00
uint64 owner,
uint64[] delegationChain,
2017-10-04 23:27:23 +00:00
uint64 intendedProject,
2017-06-27 11:08:23 +00:00
uint64 commitTime,
2017-10-03 12:42:21 +00:00
uint64 oldPledge,
2017-12-05 20:42:59 +00:00
PledgeState state
2017-06-06 17:40:14 +00:00
) internal returns (uint64)
{
2018-01-15 22:36:17 +00:00
bytes32 hPledge = keccak256(
2017-12-05 20:42:59 +00:00
owner, delegationChain, intendedProject, commitTime, oldPledge, state);
2017-10-03 12:42:21 +00:00
uint64 idx = hPledge2idx[hPledge];
2017-06-06 17:40:14 +00:00
if (idx > 0) return idx;
2017-10-03 12:42:21 +00:00
idx = uint64(pledges.length);
hPledge2idx[hPledge] = idx;
pledges.push(Pledge(
2017-12-05 20:42:59 +00:00
0, owner, delegationChain, intendedProject, commitTime, oldPledge, state));
2017-06-06 17:40:14 +00:00
return idx;
}
/// @notice A getter to look up a Admin's details
/// @param idAdmin The id for the Admin to lookup
/// @return The PledgeAdmin struct for the specified Admin
2018-01-15 22:36:17 +00:00
function findAdmin(uint64 idAdmin) internal view returns (PledgeAdmin storage) {
2017-10-04 08:24:35 +00:00
require(idAdmin < admins.length);
return admins[idAdmin];
2017-06-06 17:40:14 +00:00
}
/// @notice A getter to look up a Pledge's details
/// @param idPledge The id for the Pledge to lookup
/// @return The PledgeA struct for the specified Pledge
2018-01-15 22:36:17 +00:00
function findPledge(uint64 idPledge) internal view returns (Pledge storage) {
2017-10-03 12:42:21 +00:00
require(idPledge < pledges.length);
return pledges[idPledge];
2017-06-06 17:40:14 +00:00
}
// a constant for when a delegate is requested that is not in the system
2017-07-09 17:04:02 +00:00
uint64 constant NOTFOUND = 0xFFFFFFFFFFFFFFFF;
/// @notice A getter that searches the delegationChain for the level of
/// authority a specific delegate has within a Pledge
2017-12-05 20:47:38 +00:00
/// @param p The Pledge that will be searched
2017-12-03 04:15:52 +00:00
/// @param idDelegate The specified delegate that's searched for
2017-12-03 00:59:30 +00:00
/// @return If the delegate chain contains the delegate with the
2017-12-03 04:15:52 +00:00
/// `admins` array index `idDelegate` this returns that delegates
2017-12-03 00:59:30 +00:00
/// corresponding index in the delegationChain. Otherwise it returns
2017-12-03 04:15:52 +00:00
/// the NOTFOUND constant
2018-01-15 22:36:17 +00:00
function getDelegateIdx(Pledge p, uint64 idDelegate) internal pure returns(uint64) {
2017-12-05 20:47:38 +00:00
for (uint i=0; i < p.delegationChain.length; i++) {
if (p.delegationChain[i] == idDelegate) return uint64(i);
2017-07-09 17:04:02 +00:00
}
return NOTFOUND;
}
/// @notice A getter to find how many old "parent" pledges a specific Pledge
/// had using a self-referential loop
2017-12-05 20:47:38 +00:00
/// @param p The Pledge being queried
/// @return The number of old "parent" pledges a specific Pledge had
2017-12-05 20:47:38 +00:00
function getPledgeLevel(Pledge p) internal returns(uint) {
if (p.oldPledge == 0) return 0;
Pledge storage oldN = findPledge(p.oldPledge);
return getPledgeLevel(oldN) + 1; // a loop lookup
2017-07-09 17:04:02 +00:00
}
/// @notice A getter to find the longest commitTime out of the owner and all
/// the delegates for a specified pledge
2017-12-05 20:47:38 +00:00
/// @param p The Pledge being queried
/// @return The maximum commitTime out of the owner and all the delegates
2018-01-15 22:36:17 +00:00
function maxCommitTime(Pledge p) internal view returns(uint commitTime) {
2017-12-05 20:47:38 +00:00
PledgeAdmin storage m = findAdmin(p.owner);
commitTime = m.commitTime; // start with the owner's commitTime
2017-09-13 12:41:08 +00:00
2017-12-05 20:47:38 +00:00
for (uint i=0; i<p.delegationChain.length; i++) {
m = findAdmin(p.delegationChain[i]);
// If a delegate's commitTime is longer, make it the new commitTime
2017-09-13 12:41:08 +00:00
if (m.commitTime > commitTime) commitTime = m.commitTime;
}
}
/// @notice A getter to find the level of authority a specific Project has
/// using a self-referential loop
/// @param m The Project being queried
/// @return The level of authority a specific Project has
2017-10-04 23:27:23 +00:00
function getProjectLevel(PledgeAdmin m) internal returns(uint) {
assert(m.adminType == PledgeAdminType.Project);
if (m.parentProject == 0) return(1);
PledgeAdmin storage parentNM = findAdmin(m.parentProject);
return getProjectLevel(parentNM) + 1;
}
/// @notice A getter to find if a specified Project has been canceled
/// @param projectId The Admin id number used to specify the Project
/// @return True if the Project has been canceled
2018-01-15 22:36:17 +00:00
function isProjectCanceled(uint64 projectId) public constant returns (bool) {
2017-10-04 23:27:23 +00:00
PledgeAdmin storage m = findAdmin(projectId);
2017-10-04 08:24:35 +00:00
if (m.adminType == PledgeAdminType.Giver) return false;
2017-10-04 23:27:23 +00:00
assert(m.adminType == PledgeAdminType.Project);
if (m.canceled) return true;
2017-10-04 23:27:23 +00:00
if (m.parentProject == 0) return false;
return isProjectCanceled(m.parentProject);
}
/// @notice A getter to find the oldest pledge that hasn't been canceled
/// @param idPledge The starting place to lookup the pledges
/// @return The oldest idPledge that hasn't been canceled (DUH!)
function getOldestPledgeNotCanceled(uint64 idPledge
) internal constant returns(uint64) {
2017-10-03 12:42:21 +00:00
if (idPledge == 0) return 0;
2017-12-05 20:47:38 +00:00
Pledge storage p = findPledge(idPledge);
PledgeAdmin storage admin = findAdmin(p.owner);
2017-10-04 08:24:35 +00:00
if (admin.adminType == PledgeAdminType.Giver) return idPledge;
2017-10-04 23:27:23 +00:00
assert(admin.adminType == PledgeAdminType.Project);
2017-12-05 20:47:38 +00:00
if (!isProjectCanceled(p.owner)) return idPledge;
2017-12-05 20:47:38 +00:00
return getOldestPledgeNotCanceled(p.oldPledge);
2017-06-06 17:40:14 +00:00
}
/// @notice A check to see if the msg.sender is the owner or the
/// plugin contract for a specific Admin
/// @param m The Admin being checked
2017-10-04 08:24:35 +00:00
function checkAdminOwner(PledgeAdmin m) internal constant {
require((msg.sender == m.addr) || (msg.sender == address(m.plugin)));
}
///////////////////////////
2017-11-16 23:15:32 +00:00
// Plugin Whitelist Methods
///////////////////////////
2017-11-16 23:15:32 +00:00
function addValidPlugin(bytes32 contractHash) external onlyOwner {
pluginWhitelist[contractHash] = true;
}
function removeValidPlugin(bytes32 contractHash) external onlyOwner {
pluginWhitelist[contractHash] = false;
}
function useWhitelist(bool useWhitelist) external onlyOwner {
usePluginWhitelist = useWhitelist;
}
2018-01-15 22:36:17 +00:00
function isValidPlugin(address addr) public view returns(bool) {
2017-11-16 23:15:32 +00:00
if (!usePluginWhitelist || addr == 0x0) return true;
bytes32 contractHash = getCodeHash(addr);
return pluginWhitelist[contractHash];
}
2018-01-15 22:36:17 +00:00
function getCodeHash(address addr) public view returns(bytes32) {
2017-11-16 23:15:32 +00:00
bytes memory o_code;
assembly {
// retrieve the size of the code, this needs assembly
let size := extcodesize(addr)
// allocate output byte array - this could also be done without assembly
// by using o_code = new bytes(size)
o_code := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
// store length in memory
mstore(o_code, size)
// actually retrieve the code, this needs assembly
extcodecopy(addr, add(o_code, 0x20), 0, size)
}
return keccak256(o_code);
}
2017-06-06 17:40:14 +00:00
}