2017-08-26 19:46:34 +00:00
2017-09-13 12:41:08 +00:00
//File: contracts/ILiquidPledgingPlugin.sol
pragma solidity ^ 0 . 4 . 11 ;
contract ILiquidPledgingPlugin {
2017-10-03 11:37:45 +00:00
/// @notice Plugins are used (much like web hooks) to initiate an action
2017-10-03 10:08:47 +00:00
/// upon any donation, delegation, or transfer; this is an optional feature
/// and allows for extreme customization of the contract
2017-10-03 11:37:45 +00:00
/// @param context The situation that is triggering the plugin:
/// 0 -> Plugin for the owner transferring pledge to another party
2017-10-03 10:08:47 +00:00
/// 1 -> Plugin for the first delegate transferring pledge to another party
/// 2 -> Plugin for the second delegate transferring pledge to another party
2017-09-13 12:41:08 +00:00
/// ...
2017-10-04 23:27:23 +00:00
/// 255 -> Plugin for the intendedProject transferring pledge to another party
2017-09-13 12:41:08 +00:00
///
2017-10-03 10:08:47 +00:00
/// 256 -> Plugin for the owner receiving pledge to another party
/// 257 -> Plugin for the first delegate receiving pledge to another party
/// 258 -> Plugin for the second delegate receiving pledge to another party
2017-09-13 12:41:08 +00:00
/// ...
2017-10-04 23:27:23 +00:00
/// 511 -> Plugin for the intendedProject receiving pledge to another party
2017-10-03 10:08:47 +00:00
function beforeTransfer (
2017-10-04 10:55:46 +00:00
uint64 pledgeManager ,
uint64 pledgeFrom ,
uint64 pledgeTo ,
2017-10-03 10:08:47 +00:00
uint64 context ,
uint amount
) returns ( uint maxAllowed ) ;
function afterTransfer (
2017-10-04 10:55:46 +00:00
uint64 pledgeManager ,
uint64 pledgeFrom ,
uint64 pledgeTo ,
2017-10-03 10:08:47 +00:00
uint64 context ,
uint amount ) ;
2017-09-13 12:41:08 +00:00
}
2017-08-26 19:46:34 +00:00
//File: contracts/LiquidPledgingBase.sol
pragma solidity ^ 0 . 4 . 11 ;
2017-09-13 12:41:08 +00:00
2017-10-03 10:08:47 +00:00
/// @dev This is declares a few functions from `Vault` so that the
/// `LiquidPledgingBase` contract can interface with the `Vault` contract
2017-08-26 19:46:34 +00:00
contract Vault {
function authorizePayment ( bytes32 _ref , address _dest , uint _amount ) ;
function ( ) payable ;
}
contract LiquidPledgingBase {
2017-10-03 10:20:23 +00:00
// Limits inserted to prevent large loops that could prevent canceling
2017-08-26 19:46:34 +00:00
uint constant MAX_DELEGATES = 20 ;
2017-10-04 23:27:23 +00:00
uint constant MAX_SUBPROJECT_LEVEL = 20 ;
uint constant MAX_INTERPROJECT_LEVEL = 20 ;
2017-08-26 19:46:34 +00:00
2017-10-04 23:27:23 +00:00
enum PledgeAdminType { Giver , Delegate , Project }
2017-10-04 08:29:41 +00:00
enum PaymentState { Pledged , Paying , Paid } // TODO name change Pledged
2017-08-26 19:46:34 +00:00
2017-10-04 08:24:35 +00:00
/// @dev This struct defines the details of each the PledgeAdmin, these
/// PledgeAdmins can own pledges and act as delegates
struct PledgeAdmin { // TODO name change PledgeAdmin
2017-10-04 23:27:23 +00:00
PledgeAdminType adminType ; // Giver, Delegate or Project
2017-10-03 10:08:47 +00:00
address addr ; // account or contract address for admin
2017-10-03 10:20:23 +00:00
string name ;
2017-10-04 09:40:26 +00:00
string url ;
2017-10-03 10:08:47 +00:00
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
2017-10-03 10:08:47 +00:00
ILiquidPledgingPlugin plugin ; // if the plugin is 0x0 then nothing happens if its a contract address than that smart contract is called via the milestone contract
2017-08-26 19:46:34 +00:00
}
2017-10-03 12:42:21 +00:00
struct Pledge {
2017-08-26 19:46:34 +00:00
uint amount ;
2017-10-04 08:24:35 +00:00
uint64 owner ; // PledgeAdmin
2017-10-03 10:08:47 +00:00
uint64 [ ] delegationChain ; // list of index numbers
2017-10-04 23:27:23 +00:00
uint64 intendedProject ; // TODO change the name only used for when delegates are precommiting to a project
uint64 commitTime ; // When the intendedProject will become the owner
2017-10-03 12:42:21 +00:00
uint64 oldPledge ; // this points to the Pledge[] index that the Pledge was derived from
2017-08-26 19:46:34 +00:00
PaymentState paymentState ;
}
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-08-26 19:46:34 +00:00
Vault public vault ;
2017-10-03 12:42:21 +00:00
// this mapping allows you to search for a specific pledge's index number by the hash of that pledge
mapping ( bytes32 => uint64 ) hPledge2idx ; //TODO Fix typo
2017-08-26 19:46:34 +00:00
/////
// Modifiers
/////
modifier onlyVault ( ) {
require ( msg . sender == address ( vault ) ) ;
_ ;
}
//////
// Constructor
//////
2017-10-03 10:08:47 +00:00
/// @notice The Constructor creates the `LiquidPledgingBase` on the blockchain
/// @param _vault Where the ETH is stored that the pledges represent
2017-08-26 19:46:34 +00:00
function LiquidPledgingBase ( address _vault ) {
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
2017-08-26 19:46:34 +00:00
vault = Vault ( _vault ) ;
}
///////
2017-10-04 08:24:35 +00:00
// Adminss functions
2017-08-26 19:46:34 +00:00
//////
2017-10-03 10:20:23 +00:00
/// @notice Creates a giver.
2017-10-04 09:40:26 +00:00
function addGiver ( string name , string url , uint64 commitTime , ILiquidPledgingPlugin plugin
2017-10-03 10:20:23 +00:00
) returns ( uint64 idGiver ) {
2017-09-14 18:06:58 +00:00
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-08-26 19:46:34 +00:00
msg . sender ,
name ,
2017-10-04 09:40:26 +00:00
url ,
2017-08-26 19:46:34 +00:00
commitTime ,
0 ,
2017-09-13 12:41:08 +00:00
false ,
plugin ) ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 10:20:23 +00:00
GiverAdded ( idGiver ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 10:20:23 +00:00
event GiverAdded ( uint64 indexed idGiver ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 10:20:23 +00:00
///@notice Changes the address, name or commitTime associated with a specific giver
function updateGiver (
uint64 idGiver ,
2017-08-26 19:46:34 +00:00
address newAddr ,
string newName ,
2017-10-04 09:40:26 +00:00
string newUrl ,
2017-09-18 13:43:09 +00:00
uint64 newCommitTime )
2017-08-26 19:46:34 +00:00
{
2017-10-04 08:24:35 +00:00
PledgeAdmin storage giver = findAdmin ( idGiver ) ;
require ( giver . adminType == PledgeAdminType . Giver ) ; //Must be a Giver
2017-10-03 12:42:21 +00:00
require ( giver . addr == msg . sender ) ; //current addr had to originate 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-08-26 19:46:34 +00:00
}
2017-10-03 10:20:23 +00:00
event GiverUpdated ( uint64 indexed idGiver ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 10:08:47 +00:00
/// @notice Creates a new Delegate
2017-10-04 09:40:26 +00:00
function addDelegate ( string name , string url , uint64 commitTime , ILiquidPledgingPlugin plugin ) returns ( uint64 idDelegate ) { //TODO return index number
2017-09-14 18:06:58 +00:00
2017-10-04 08:24:35 +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-08-26 19:46:34 +00:00
msg . sender ,
name ,
2017-10-04 09:40:26 +00:00
url ,
2017-09-13 12:41:08 +00:00
commitTime ,
2017-08-26 19:46:34 +00:00
0 ,
2017-09-13 12:41:08 +00:00
false ,
plugin ) ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 10:08:47 +00:00
DelegateAdded ( idDelegate ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 10:08:47 +00:00
event DelegateAdded ( uint64 indexed idDelegate ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 10:08:47 +00:00
///@notice Changes the address, name or commitTime associated with a specific delegate
2017-09-13 12:41:08 +00:00
function updateDelegate (
uint64 idDelegate ,
address newAddr ,
string newName ,
2017-10-04 09:40:26 +00:00
string newUrl ,
2017-09-18 13:43:09 +00:00
uint64 newCommitTime ) {
2017-10-04 08:24:35 +00:00
PledgeAdmin storage delegate = findAdmin ( idDelegate ) ;
require ( delegate . adminType == PledgeAdminType . Delegate ) ;
2017-08-26 19:46:34 +00:00
require ( delegate . addr == msg . sender ) ;
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-08-26 19:46:34 +00:00
DelegateUpdated ( idDelegate ) ;
}
event DelegateUpdated ( uint64 indexed idDelegate ) ;
2017-10-04 23:27:23 +00:00
/// @notice Creates a new Project
function addProject ( string name , string url , address projectAdmin , uint64 parentProject , uint64 commitTime , ILiquidPledgingPlugin plugin ) returns ( uint64 idProject ) {
if ( parentProject != 0 ) {
PledgeAdmin storage pa = findAdmin ( parentProject ) ;
require ( pa . adminType == PledgeAdminType . Project ) ;
require ( getProjectLevel ( pa ) < MAX_SUBPROJECT_LEVEL ) ;
2017-08-26 19:46:34 +00:00
}
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-08-26 19:46:34 +00:00
name ,
2017-10-04 09:40:26 +00:00
url ,
2017-08-26 19:46:34 +00:00
commitTime ,
2017-10-04 23:27:23 +00:00
parentProject ,
2017-09-13 12:41:08 +00:00
false ,
plugin ) ) ;
2017-08-26 19:46:34 +00:00
2017-09-14 18:06:58 +00:00
2017-10-04 23:27:23 +00:00
ProjectAdded ( idProject ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-04 23:27:23 +00:00
event ProjectAdded ( uint64 indexed idProject ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 23:27:23 +00:00
///@notice Changes the address, name or commitTime associated with a specific Project
function updateProject (
uint64 idProject ,
2017-09-18 13:43:09 +00:00
address newAddr ,
string newName ,
2017-10-04 09:40:26 +00:00
string newUrl ,
2017-09-18 13:43:09 +00:00
uint64 newCommitTime )
{
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-08-26 19:46:34 +00:00
}
2017-10-04 23:27:23 +00:00
event ProjectUpdated ( uint64 indexed idAdmin ) ;
2017-08-26 19:46:34 +00:00
//////////
// Public constant functions
//////////
2017-10-03 12:42:21 +00:00
/// @notice Public constant that states how many pledgess are in the system
function numberOfPledges ( ) constant returns ( uint ) {
return pledges . length - 1 ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 12:42:21 +00:00
/// @notice Public constant that states the details of the specified Pledge
function getPledge ( uint64 idPledge ) constant returns (
2017-08-26 19:46:34 +00:00
uint amount ,
uint64 owner ,
uint64 nDelegates ,
2017-10-04 23:27:23 +00:00
uint64 intendedProject ,
2017-08-26 19:46:34 +00:00
uint64 commitTime ,
2017-10-03 12:42:21 +00:00
uint64 oldPledge ,
2017-08-26 19:46:34 +00:00
PaymentState paymentState
) {
2017-10-03 12:42:21 +00:00
Pledge storage n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
amount = n . amount ;
owner = n . owner ;
nDelegates = uint64 ( n . delegationChain . length ) ;
2017-10-04 23:27:23 +00:00
intendedProject = n . intendedProject ;
2017-08-26 19:46:34 +00:00
commitTime = n . commitTime ;
2017-10-03 12:42:21 +00:00
oldPledge = n . oldPledge ;
2017-08-26 19:46:34 +00:00
paymentState = n . paymentState ;
}
2017-10-03 10:08:47 +00:00
/// @notice Public constant that states the delegates one by one, because
/// an array cannot be returned
2017-10-03 12:42:21 +00:00
function getPledgeDelegate ( uint64 idPledge , uint idxDelegate ) constant returns (
2017-08-26 19:46:34 +00:00
uint64 idDelegate ,
address addr ,
string name
) {
2017-10-03 12:42:21 +00:00
Pledge storage n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
idDelegate = n . delegationChain [ idxDelegate - 1 ] ;
2017-10-04 08:24:35 +00:00
PledgeAdmin storage delegate = findAdmin ( idDelegate ) ;
2017-08-26 19:46:34 +00:00
addr = delegate . addr ;
name = delegate . name ;
}
2017-10-03 10:08:47 +00:00
/// @notice Public constant that states the number of admins in the system
2017-10-04 08:24:35 +00:00
function numberOfPledgeAdmins ( ) constant returns ( uint ) {
return admins . length - 1 ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 10:20:23 +00:00
/// @notice Public constant that states the details of the specified admin
2017-10-04 08:24:35 +00:00
function getPledgeAdmin ( uint64 idAdmin ) constant returns (
PledgeAdminType adminType ,
2017-08-26 19:46:34 +00:00
address addr ,
string name ,
2017-10-04 09:40:26 +00:00
string url ,
2017-08-26 19:46:34 +00:00
uint64 commitTime ,
2017-10-04 23:27:23 +00:00
uint64 parentProject ,
2017-10-03 10:08:47 +00:00
bool canceled ,
address plugin )
2017-08-26 19:46:34 +00:00
{
2017-10-04 08:24:35 +00:00
PledgeAdmin storage m = findAdmin ( idAdmin ) ;
adminType = m . adminType ;
2017-08-26 19:46:34 +00:00
addr = m . addr ;
name = m . name ;
2017-10-04 09:40:26 +00:00
url = m . url ;
2017-08-26 19:46:34 +00:00
commitTime = m . commitTime ;
2017-10-04 23:27:23 +00:00
parentProject = m . parentProject ;
2017-08-26 19:46:34 +00:00
canceled = m . canceled ;
2017-10-03 10:08:47 +00:00
plugin = address ( m . plugin ) ;
2017-08-26 19:46:34 +00:00
}
////////
// Private methods
///////
2017-10-03 12:42:21 +00:00
/// @notice All pledges technically exist... but if the pledge hasn't been
2017-10-03 10:08:47 +00:00
/// created in this system yet then it wouldn't be in the hash array
2017-10-03 12:42:21 +00:00
/// hPledge2idx[]; this creates a Pledge with and amount of 0 if one is not
2017-10-03 10:20:23 +00:00
/// created already...
2017-10-04 10:55:46 +00:00
function findOrCreatePledge (
2017-08-26 19:46:34 +00:00
uint64 owner ,
uint64 [ ] delegationChain ,
2017-10-04 23:27:23 +00:00
uint64 intendedProject ,
2017-08-26 19:46:34 +00:00
uint64 commitTime ,
2017-10-03 12:42:21 +00:00
uint64 oldPledge ,
2017-08-26 19:46:34 +00:00
PaymentState paid
) internal returns ( uint64 )
{
2017-10-04 23:27:23 +00:00
bytes32 hPledge = sha3 ( owner , delegationChain , intendedProject , commitTime , oldPledge , paid ) ;
2017-10-03 12:42:21 +00:00
uint64 idx = hPledge2idx [ hPledge ] ;
2017-08-26 19:46:34 +00:00
if ( idx > 0 ) return idx ;
2017-10-03 12:42:21 +00:00
idx = uint64 ( pledges . length ) ;
hPledge2idx [ hPledge ] = idx ;
2017-10-04 23:27:23 +00:00
pledges . push ( Pledge ( 0 , owner , delegationChain , intendedProject , commitTime , oldPledge , paid ) ) ;
2017-08-26 19:46:34 +00:00
return idx ;
}
2017-10-04 08:24:35 +00:00
function findAdmin ( uint64 idAdmin ) internal returns ( PledgeAdmin storage ) {
require ( idAdmin < admins . length ) ;
return admins [ idAdmin ] ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 12:42:21 +00:00
function findPledge ( uint64 idPledge ) internal returns ( Pledge storage ) {
require ( idPledge < pledges . length ) ;
return pledges [ idPledge ] ;
2017-08-26 19:46:34 +00:00
}
// a constant for the case that a delegate is requested that is not a delegate in the system
uint64 constant NOTFOUND = 0xFFFFFFFFFFFFFFFF ;
// helper function that searches the delegationChain fro a specific delegate and
2017-10-03 10:08:47 +00:00
// level of delegation returns their idx in the delegation chain which reflect their level of authority
2017-10-03 12:42:21 +00:00
function getDelegateIdx ( Pledge n , uint64 idDelegate ) internal returns ( uint64 ) {
2017-08-26 19:46:34 +00:00
for ( uint i = 0 ; i < n . delegationChain . length ; i ++ ) {
if ( n . delegationChain [ i ] == idDelegate ) return uint64 ( i ) ;
}
return NOTFOUND ;
}
2017-10-03 12:42:21 +00:00
// helper function that returns the pledge level solely to check that transfers
2017-10-04 23:27:23 +00:00
// between Projects not violate MAX_INTERPROJECT_LEVEL
2017-10-03 12:42:21 +00:00
function getPledgeLevel ( Pledge n ) internal returns ( uint ) {
if ( n . oldPledge == 0 ) return 0 ; //changed
Pledge storage oldN = findPledge ( n . oldPledge ) ;
return getPledgeLevel ( oldN ) + 1 ;
2017-08-26 19:46:34 +00:00
}
2017-09-13 12:41:08 +00:00
// helper function that returns the max commit time of the owner and all the
// delegates
2017-10-03 12:42:21 +00:00
function maxCommitTime ( Pledge n ) internal returns ( uint commitTime ) {
2017-10-04 08:24:35 +00:00
PledgeAdmin storage m = findAdmin ( n . owner ) ;
2017-09-13 12:41:08 +00:00
commitTime = m . commitTime ;
for ( uint i = 0 ; i < n . delegationChain . length ; i ++ ) {
2017-10-04 08:24:35 +00:00
m = findAdmin ( n . delegationChain [ i ] ) ;
2017-09-13 12:41:08 +00:00
if ( m . commitTime > commitTime ) commitTime = m . commitTime ;
}
}
2017-08-26 19:46:34 +00:00
2017-10-04 23:27:23 +00:00
// helper function that returns the project level solely to check that there
// are not too many Projects that violate MAX_SUBCAMPAIGNS_LEVEL
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 ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-04 23:27:23 +00:00
function isProjectCanceled ( uint64 projectId ) constant returns ( bool ) {
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 ) ;
2017-08-26 19:46:34 +00:00
if ( m . canceled ) return true ;
2017-10-04 23:27:23 +00:00
if ( m . parentProject == 0 ) return false ;
return isProjectCanceled ( m . parentProject ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-04 23:27:23 +00:00
// @notice A helper function for canceling projects
2017-10-03 12:42:21 +00:00
// @param idPledge the pledge that may or may not be canceled
function getOldestPledgeNotCanceled ( uint64 idPledge ) internal constant returns ( uint64 ) { //todo rename
if ( idPledge == 0 ) return 0 ;
Pledge storage n = findPledge ( idPledge ) ;
2017-10-04 08:24:35 +00:00
PledgeAdmin storage admin = findAdmin ( n . owner ) ;
if ( admin . adminType == PledgeAdminType . Giver ) return idPledge ;
2017-08-26 19:46:34 +00:00
2017-10-04 23:27:23 +00:00
assert ( admin . adminType == PledgeAdminType . Project ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 23:27:23 +00:00
if ( ! isProjectCanceled ( n . owner ) ) return idPledge ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
return getOldestPledgeNotCanceled ( n . oldPledge ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-04 08:24:35 +00:00
function checkAdminOwner ( PledgeAdmin m ) internal constant {
2017-09-18 13:43:09 +00:00
require ( ( msg . sender == m . addr ) || ( msg . sender == address ( m . plugin ) ) ) ;
}
2017-08-26 19:46:34 +00:00
}
//File: contracts/LiquidPledging.sol
pragma solidity ^ 0 . 4 . 11 ;
contract LiquidPledging is LiquidPledgingBase {
//////
// Constructor
//////
2017-10-03 10:08:47 +00:00
// This constructor also calls the constructor for `LiquidPledgingBase`
2017-08-26 19:46:34 +00:00
function LiquidPledging ( address _vault ) LiquidPledgingBase ( _vault ) {
}
2017-10-03 10:08:47 +00:00
/// @notice This is how value enters into the system which creates pledges;
/// the token of value goes into the vault and the amount in the pledge
/// relevant to this Giver without delegates is increased, and a normal
/// transfer is done to the idReceiver
2017-10-03 10:20:23 +00:00
/// @param idGiver Identifier of the giver thats donating.
/// @param idReceiver To whom it's transfered. Can be the same giver, another
2017-10-04 23:27:23 +00:00
/// giver, a delegate or a project
2017-10-03 10:08:47 +00:00
2017-10-03 10:20:23 +00:00
function donate ( uint64 idGiver , uint64 idReceiver ) payable {
if ( idGiver == 0 ) {
2017-10-04 09:40:26 +00:00
idGiver = addGiver ( ' ' , ' ' , 259200 , ILiquidPledgingPlugin ( 0x0 ) ) ; // default to 3 day commitTime
2017-10-03 10:08:47 +00:00
}
2017-10-04 08:24:35 +00:00
PledgeAdmin storage sender = findAdmin ( idGiver ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 08:24:35 +00:00
checkAdminOwner ( sender ) ;
2017-09-18 13:43:09 +00:00
2017-10-04 08:24:35 +00:00
require ( sender . adminType == PledgeAdminType . Giver ) ;
2017-08-26 19:46:34 +00:00
uint amount = msg . value ;
require ( amount > 0 ) ;
vault . transfer ( amount ) ; // transfers the baseToken to the Vault
2017-10-04 10:55:46 +00:00
uint64 idPledge = findOrCreatePledge (
2017-10-03 10:20:23 +00:00
idGiver ,
2017-10-03 10:08:47 +00:00
new uint64 [ ] ( 0 ) , //what is new?
2017-08-26 19:46:34 +00:00
0 ,
0 ,
0 ,
2017-10-04 08:29:41 +00:00
PaymentState . Pledged ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
Pledge storage nTo = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
nTo . amount += amount ;
2017-10-03 12:42:21 +00:00
Transfer ( 0 , idPledge , amount ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
transfer ( idGiver , idPledge , amount , idReceiver ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 12:42:21 +00:00
/// @notice Moves value between pledges
2017-10-04 23:27:23 +00:00
/// @param idSender ID of the giver, delegate or project admin that is transferring
2017-10-04 08:24:35 +00:00
/// the funds from Pledge to Pledge. This admin must have permissions to move the value
2017-10-03 12:42:21 +00:00
/// @param idPledge Id of the pledge that's moving the value
2017-08-26 19:46:34 +00:00
/// @param amount Quantity of value that's being moved
2017-10-03 10:20:23 +00:00
/// @param idReceiver Destination of the value, can be a giver sending to a giver or
2017-10-04 23:27:23 +00:00
/// a delegate, a delegate to another delegate or a project to precommit it to that project
2017-10-03 12:42:21 +00:00
function transfer ( uint64 idSender , uint64 idPledge , uint amount , uint64 idReceiver ) {
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
idPledge = normalizePledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
Pledge storage n = findPledge ( idPledge ) ;
2017-10-04 08:24:35 +00:00
PledgeAdmin storage receiver = findAdmin ( idReceiver ) ;
PledgeAdmin storage sender = findAdmin ( idSender ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 08:24:35 +00:00
checkAdminOwner ( sender ) ;
2017-10-04 08:29:41 +00:00
require ( n . paymentState == PaymentState . Pledged ) ;
2017-08-26 19:46:34 +00:00
// If the sender is the owner
if ( n . owner == idSender ) {
2017-10-04 08:24:35 +00:00
if ( receiver . adminType == PledgeAdminType . Giver ) {
2017-10-03 12:42:21 +00:00
transferOwnershipToGiver ( idPledge , amount , idReceiver ) ;
2017-10-04 23:27:23 +00:00
} else if ( receiver . adminType == PledgeAdminType . Project ) {
transferOwnershipToProject ( idPledge , amount , idReceiver ) ;
2017-10-04 08:24:35 +00:00
} else if ( receiver . adminType == PledgeAdminType . Delegate ) {
2017-10-06 10:07:25 +00:00
idPledge = undelegate ( idPledge , amount , n . delegationChain . length ) ;
2017-10-03 12:42:21 +00:00
appendDelegate ( idPledge , amount , idReceiver ) ;
2017-08-26 19:46:34 +00:00
} else {
assert ( false ) ;
}
return ;
}
// If the sender is a delegate
uint senderDIdx = getDelegateIdx ( n , idSender ) ;
if ( senderDIdx != NOTFOUND ) {
2017-10-03 10:20:23 +00:00
// If the receiver is another giver
2017-10-04 08:24:35 +00:00
if ( receiver . adminType == PledgeAdminType . Giver ) {
2017-10-03 10:20:23 +00:00
// Only accept to change to the original giver to remove all delegates
2017-08-26 19:46:34 +00:00
assert ( n . owner == idReceiver ) ;
2017-10-03 12:42:21 +00:00
undelegate ( idPledge , amount , n . delegationChain . length ) ;
2017-08-26 19:46:34 +00:00
return ;
}
// If the receiver is another delegate
2017-10-04 08:24:35 +00:00
if ( receiver . adminType == PledgeAdminType . Delegate ) {
2017-08-26 19:46:34 +00:00
uint receiverDIdx = getDelegateIdx ( n , idReceiver ) ;
// If the receiver is not in the delegate list
if ( receiverDIdx == NOTFOUND ) {
2017-10-06 10:07:25 +00:00
idPledge = undelegate ( idPledge , amount , n . delegationChain . length - senderDIdx - 1 ) ;
2017-10-03 12:42:21 +00:00
appendDelegate ( idPledge , amount , idReceiver ) ;
2017-08-26 19:46:34 +00:00
// If the receiver is already part of the delegate chain and is
// after the sender, then all of the other delegates after the sender are
// removed and the receiver is appended at the end of the delegation chain
} else if ( receiverDIdx > senderDIdx ) {
2017-10-06 10:07:25 +00:00
idPledge = undelegate ( idPledge , amount , n . delegationChain . length - senderDIdx - 1 ) ;
2017-10-03 12:42:21 +00:00
appendDelegate ( idPledge , amount , idReceiver ) ;
2017-08-26 19:46:34 +00:00
// If the receiver is already part of the delegate chain and is
// before the sender, then the sender and all of the other
// delegates after the RECEIVER are revomved from the chain,
// this is interesting because the delegate undelegates from the
// delegates that delegated to this delegate... game theory issues? should this be allowed
} else if ( receiverDIdx <= senderDIdx ) {
2017-10-03 12:42:21 +00:00
undelegate ( idPledge , amount , n . delegationChain . length - receiverDIdx - 1 ) ;
2017-08-26 19:46:34 +00:00
}
return ;
}
2017-10-04 23:27:23 +00:00
// If the delegate wants to support a project, they undelegate all
// the delegates after them in the chain and choose a project
if ( receiver . adminType == PledgeAdminType . Project ) {
2017-10-06 10:07:25 +00:00
idPledge = undelegate ( idPledge , amount , n . delegationChain . length - senderDIdx - 1 ) ;
2017-10-04 23:27:23 +00:00
proposeAssignProject ( idPledge , amount , idReceiver ) ;
2017-08-26 19:46:34 +00:00
return ;
}
}
assert ( false ) ; // It is not the owner nor any delegate.
}
/// @notice This method is used to withdraw value from the system. This can be used
2017-10-04 23:27:23 +00:00
/// by the givers to avoid committing the donation or by project admin to use
2017-08-26 19:46:34 +00:00
/// the Ether.
2017-10-03 12:42:21 +00:00
/// @param idPledge Id of the pledge that wants to be withdrawn.
2017-10-03 10:08:47 +00:00
/// @param amount Quantity of Ether that wants to be withdrawn.
2017-10-03 12:42:21 +00:00
function withdraw ( uint64 idPledge , uint amount ) {
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
idPledge = normalizePledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
Pledge storage n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 08:29:41 +00:00
require ( n . paymentState == PaymentState . Pledged ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 08:24:35 +00:00
PledgeAdmin storage owner = findAdmin ( n . owner ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 08:24:35 +00:00
checkAdminOwner ( owner ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 10:55:46 +00:00
uint64 idNewPledge = findOrCreatePledge (
2017-08-26 19:46:34 +00:00
n . owner ,
n . delegationChain ,
0 ,
0 ,
2017-10-03 12:42:21 +00:00
n . oldPledge ,
2017-08-26 19:46:34 +00:00
PaymentState . Paying
) ;
2017-10-03 12:42:21 +00:00
doTransfer ( idPledge , idNewPledge , amount ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
vault . authorizePayment ( bytes32 ( idNewPledge ) , owner . addr , amount ) ;
2017-08-26 19:46:34 +00:00
}
/// @notice Method called by the vault to confirm a payment.
2017-10-03 12:42:21 +00:00
/// @param idPledge Id of the pledge that wants to be withdrawn.
2017-10-03 10:08:47 +00:00
/// @param amount Quantity of Ether that wants to be withdrawn.
2017-10-03 12:42:21 +00:00
function confirmPayment ( uint64 idPledge , uint amount ) onlyVault {
Pledge storage n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
require ( n . paymentState == PaymentState . Paying ) ;
2017-10-04 23:27:23 +00:00
// Check the project is not canceled in the while.
2017-10-03 12:42:21 +00:00
require ( getOldestPledgeNotCanceled ( idPledge ) == idPledge ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 10:55:46 +00:00
uint64 idNewPledge = findOrCreatePledge (
2017-08-26 19:46:34 +00:00
n . owner ,
n . delegationChain ,
0 ,
0 ,
2017-10-03 12:42:21 +00:00
n . oldPledge ,
2017-08-26 19:46:34 +00:00
PaymentState . Paid
) ;
2017-10-03 12:42:21 +00:00
doTransfer ( idPledge , idNewPledge , amount ) ;
2017-08-26 19:46:34 +00:00
}
/// @notice Method called by the vault to cancel a payment.
2017-10-03 12:42:21 +00:00
/// @param idPledge Id of the pledge that wants to be canceled for withdraw.
2017-08-26 19:46:34 +00:00
/// @param amount Quantity of Ether that wants to be rolled back.
2017-10-03 12:42:21 +00:00
function cancelPayment ( uint64 idPledge , uint amount ) onlyVault {
Pledge storage n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
require ( n . paymentState == PaymentState . Paying ) ; //TODO change to revert
2017-10-04 23:27:23 +00:00
// When a payment is canceled, never is assigned to a project.
2017-10-04 10:55:46 +00:00
uint64 oldPledge = findOrCreatePledge (
2017-08-26 19:46:34 +00:00
n . owner ,
n . delegationChain ,
0 ,
0 ,
2017-10-03 12:42:21 +00:00
n . oldPledge ,
2017-10-04 08:29:41 +00:00
PaymentState . Pledged
2017-08-26 19:46:34 +00:00
) ;
2017-10-03 12:42:21 +00:00
oldPledge = normalizePledge ( oldPledge ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
doTransfer ( idPledge , oldPledge , amount ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-04 23:27:23 +00:00
/// @notice Method called to cancel this project.
/// @param idProject Id of the projct that wants to be canceled.
function cancelProject ( uint64 idProject ) {
PledgeAdmin storage project = findAdmin ( idProject ) ;
checkAdminOwner ( project ) ;
project . canceled = true ;
2017-10-03 10:08:47 +00:00
2017-10-04 23:27:23 +00:00
CancelProject ( idProject ) ;
2017-08-26 19:46:34 +00:00
}
2017-09-18 13:43:09 +00:00
2017-10-03 12:42:21 +00:00
function cancelPledge ( uint64 idPledge , uint amount ) {
idPledge = normalizePledge ( idPledge ) ;
2017-09-18 13:43:09 +00:00
2017-10-03 12:42:21 +00:00
Pledge storage n = findPledge ( idPledge ) ;
2017-09-18 13:43:09 +00:00
2017-10-04 08:24:35 +00:00
PledgeAdmin storage m = findAdmin ( n . owner ) ;
checkAdminOwner ( m ) ;
2017-09-18 13:43:09 +00:00
2017-10-03 12:42:21 +00:00
doTransfer ( idPledge , n . oldPledge , amount ) ;
2017-09-18 13:43:09 +00:00
}
2017-08-26 19:46:34 +00:00
////////
2017-10-03 12:42:21 +00:00
// Multi pledge methods
2017-08-26 19:46:34 +00:00
////////
2017-10-03 12:42:21 +00:00
// This set of functions makes moving a lot of pledges around much more
2017-08-26 19:46:34 +00:00
// efficient (saves gas) than calling these functions in series
uint constant D64 = 0x10000000000000000 ;
2017-10-03 12:42:21 +00:00
function mTransfer ( uint64 idSender , uint [ ] pledgesAmounts , uint64 idReceiver ) {
for ( uint i = 0 ; i < pledgesAmounts . length ; i ++ ) {
uint64 idPledge = uint64 ( pledgesAmounts [ i ] & ( D64 - 1 ) ) ;
uint amount = pledgesAmounts [ i ] / D64 ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
transfer ( idSender , idPledge , amount , idReceiver ) ;
2017-08-26 19:46:34 +00:00
}
}
2017-10-03 12:42:21 +00:00
function mWithdraw ( uint [ ] pledgesAmounts ) {
for ( uint i = 0 ; i < pledgesAmounts . length ; i ++ ) {
uint64 idPledge = uint64 ( pledgesAmounts [ i ] & ( D64 - 1 ) ) ;
uint amount = pledgesAmounts [ i ] / D64 ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
withdraw ( idPledge , amount ) ;
2017-08-26 19:46:34 +00:00
}
}
2017-10-03 12:42:21 +00:00
function mConfirmPayment ( uint [ ] pledgesAmounts ) {
for ( uint i = 0 ; i < pledgesAmounts . length ; i ++ ) {
uint64 idPledge = uint64 ( pledgesAmounts [ i ] & ( D64 - 1 ) ) ;
uint amount = pledgesAmounts [ i ] / D64 ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
confirmPayment ( idPledge , amount ) ;
2017-08-26 19:46:34 +00:00
}
}
2017-10-03 12:42:21 +00:00
function mCancelPayment ( uint [ ] pledgesAmounts ) {
for ( uint i = 0 ; i < pledgesAmounts . length ; i ++ ) {
uint64 idPledge = uint64 ( pledgesAmounts [ i ] & ( D64 - 1 ) ) ;
uint amount = pledgesAmounts [ i ] / D64 ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
cancelPayment ( idPledge , amount ) ;
2017-08-26 19:46:34 +00:00
}
}
2017-10-03 12:42:21 +00:00
function mNormalizePledge ( uint [ ] pledges ) returns ( uint64 ) {
for ( uint i = 0 ; i < pledges . length ; i ++ ) {
uint64 idPledge = uint64 ( pledges [ i ] & ( D64 - 1 ) ) ;
2017-09-18 14:23:17 +00:00
2017-10-03 12:42:21 +00:00
normalizePledge ( idPledge ) ;
2017-09-18 14:23:17 +00:00
}
}
2017-08-26 19:46:34 +00:00
////////
// Private methods
///////
// this function is obvious, but it can also be called to undelegate everyone
2017-10-03 10:08:47 +00:00
// by setting yourself as the idReceiver
2017-10-04 23:27:23 +00:00
function transferOwnershipToProject ( uint64 idPledge , uint amount , uint64 idReceiver ) internal {
2017-10-03 12:42:21 +00:00
Pledge storage n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 23:27:23 +00:00
require ( getPledgeLevel ( n ) < MAX_INTERPROJECT_LEVEL ) ;
require ( ! isProjectCanceled ( idReceiver ) ) ;
2017-10-04 12:30:09 +00:00
2017-10-04 10:55:46 +00:00
uint64 oldPledge = findOrCreatePledge (
2017-08-26 19:46:34 +00:00
n . owner ,
n . delegationChain ,
0 ,
0 ,
2017-10-03 12:42:21 +00:00
n . oldPledge ,
2017-10-04 08:29:41 +00:00
PaymentState . Pledged ) ;
2017-10-04 10:55:46 +00:00
uint64 toPledge = findOrCreatePledge (
2017-08-26 19:46:34 +00:00
idReceiver ,
new uint64 [ ] ( 0 ) ,
0 ,
0 ,
2017-10-03 12:42:21 +00:00
oldPledge ,
2017-10-04 08:29:41 +00:00
PaymentState . Pledged ) ;
2017-10-03 12:42:21 +00:00
doTransfer ( idPledge , toPledge , amount ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 12:42:21 +00:00
function transferOwnershipToGiver ( uint64 idPledge , uint amount , uint64 idReceiver ) internal {
2017-10-04 10:55:46 +00:00
uint64 toPledge = findOrCreatePledge (
2017-08-26 19:46:34 +00:00
idReceiver ,
new uint64 [ ] ( 0 ) ,
0 ,
0 ,
0 ,
2017-10-04 08:29:41 +00:00
PaymentState . Pledged ) ;
2017-10-03 12:42:21 +00:00
doTransfer ( idPledge , toPledge , amount ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 12:42:21 +00:00
function appendDelegate ( uint64 idPledge , uint amount , uint64 idReceiver ) internal {
Pledge storage n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
require ( n . delegationChain . length < MAX_DELEGATES ) ; //TODO change to revert and say the error
uint64 [ ] memory newDelegationChain = new uint64 [ ] ( n . delegationChain . length + 1 ) ;
for ( uint i = 0 ; i < n . delegationChain . length ; i ++ ) {
newDelegationChain [ i ] = n . delegationChain [ i ] ;
}
// Make the last item in the array the idReceiver
newDelegationChain [ n . delegationChain . length ] = idReceiver ;
2017-10-04 10:55:46 +00:00
uint64 toPledge = findOrCreatePledge (
2017-08-26 19:46:34 +00:00
n . owner ,
newDelegationChain ,
0 ,
0 ,
2017-10-03 12:42:21 +00:00
n . oldPledge ,
2017-10-04 08:29:41 +00:00
PaymentState . Pledged ) ;
2017-10-03 12:42:21 +00:00
doTransfer ( idPledge , toPledge , amount ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 10:08:47 +00:00
/// @param q Number of undelegations
2017-10-06 10:07:25 +00:00
function undelegate ( uint64 idPledge , uint amount , uint q ) internal returns ( uint64 ) {
2017-10-03 12:42:21 +00:00
Pledge storage n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
uint64 [ ] memory newDelegationChain = new uint64 [ ] ( n . delegationChain . length - q ) ;
for ( uint i = 0 ; i < n . delegationChain . length - q ; i ++ ) {
newDelegationChain [ i ] = n . delegationChain [ i ] ;
}
2017-10-04 10:55:46 +00:00
uint64 toPledge = findOrCreatePledge (
2017-08-26 19:46:34 +00:00
n . owner ,
newDelegationChain ,
0 ,
0 ,
2017-10-03 12:42:21 +00:00
n . oldPledge ,
2017-10-04 08:29:41 +00:00
PaymentState . Pledged ) ;
2017-10-03 12:42:21 +00:00
doTransfer ( idPledge , toPledge , amount ) ;
2017-10-06 10:07:25 +00:00
return toPledge ;
2017-08-26 19:46:34 +00:00
}
2017-10-04 23:27:23 +00:00
function proposeAssignProject ( uint64 idPledge , uint amount , uint64 idReceiver ) internal { // Todo rename
2017-10-03 12:42:21 +00:00
Pledge storage n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 23:27:23 +00:00
require ( getPledgeLevel ( n ) < MAX_SUBPROJECT_LEVEL ) ;
require ( ! isProjectCanceled ( idReceiver ) ) ;
2017-08-26 19:46:34 +00:00
2017-10-04 10:55:46 +00:00
uint64 toPledge = findOrCreatePledge (
2017-08-26 19:46:34 +00:00
n . owner ,
n . delegationChain ,
idReceiver ,
2017-09-13 12:41:08 +00:00
uint64 ( getTime ( ) + maxCommitTime ( n ) ) ,
2017-10-03 12:42:21 +00:00
n . oldPledge ,
2017-10-04 08:29:41 +00:00
PaymentState . Pledged ) ;
2017-10-03 12:42:21 +00:00
doTransfer ( idPledge , toPledge , amount ) ;
2017-08-26 19:46:34 +00:00
}
2017-09-13 12:41:08 +00:00
function doTransfer ( uint64 from , uint64 to , uint _amount ) internal {
2017-09-14 06:03:36 +00:00
uint amount = callPlugins ( true , from , to , _amount ) ;
2017-08-26 19:46:34 +00:00
if ( from == to ) return ;
if ( amount == 0 ) return ;
2017-10-03 12:42:21 +00:00
Pledge storage nFrom = findPledge ( from ) ;
Pledge storage nTo = findPledge ( to ) ;
2017-08-26 19:46:34 +00:00
require ( nFrom . amount >= amount ) ;
nFrom . amount -= amount ;
nTo . amount += amount ;
Transfer ( from , to , amount ) ;
2017-09-14 06:03:36 +00:00
callPlugins ( false , from , to , amount ) ;
2017-08-26 19:46:34 +00:00
}
// This function does 2 things, #1: it checks to make sure that the pledges are correct
2017-10-04 23:27:23 +00:00
// if the a pledged project has already been committed then it changes the owner
// to be the proposed project (Pledge that the UI will have to read the commit time and manually
2017-10-03 12:42:21 +00:00
// do what this function does to the pledge for the end user at the expiration of the commitTime)
2017-10-04 23:27:23 +00:00
// #2: It checks to make sure that if there has been a cancellation in the chain of projects,
2017-10-03 12:42:21 +00:00
// then it adjusts the pledge's owner appropriately.
// This call can be called from any body at any time on any pledge. In general it can be called
2017-10-03 10:08:47 +00:00
// to force the calls of the affected plugins, which also need to be predicted by the UI
2017-10-03 12:42:21 +00:00
function normalizePledge ( uint64 idPledge ) returns ( uint64 ) {
Pledge storage n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
2017-10-03 12:42:21 +00:00
// Check to make sure this pledge hasnt already been used or is in the process of being used
2017-10-04 08:29:41 +00:00
if ( n . paymentState != PaymentState . Pledged ) return idPledge ;
2017-08-26 19:46:34 +00:00
2017-10-04 23:27:23 +00:00
// First send to a project if it's proposed and commited
if ( ( n . intendedProject > 0 ) && ( getTime ( ) > n . commitTime ) ) {
2017-10-04 10:55:46 +00:00
uint64 oldPledge = findOrCreatePledge (
2017-08-26 19:46:34 +00:00
n . owner ,
n . delegationChain ,
0 ,
0 ,
2017-10-03 12:42:21 +00:00
n . oldPledge ,
2017-10-04 08:29:41 +00:00
PaymentState . Pledged ) ;
2017-10-04 10:55:46 +00:00
uint64 toPledge = findOrCreatePledge (
2017-10-04 23:27:23 +00:00
n . intendedProject ,
2017-08-26 19:46:34 +00:00
new uint64 [ ] ( 0 ) ,
0 ,
0 ,
2017-10-03 12:42:21 +00:00
oldPledge ,
2017-10-04 08:29:41 +00:00
PaymentState . Pledged ) ;
2017-10-03 12:42:21 +00:00
doTransfer ( idPledge , toPledge , n . amount ) ;
idPledge = toPledge ;
n = findPledge ( idPledge ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 12:42:21 +00:00
toPledge = getOldestPledgeNotCanceled ( idPledge ) ; // TODO toPledge is pledge defined
if ( toPledge != idPledge ) {
doTransfer ( idPledge , toPledge , n . amount ) ;
2017-08-26 19:46:34 +00:00
}
2017-10-03 12:42:21 +00:00
return toPledge ;
2017-08-26 19:46:34 +00:00
}
2017-09-13 12:41:08 +00:00
/////////////
// Plugins
/////////////
2017-10-04 08:24:35 +00:00
function callPlugin ( bool before , uint64 adminId , uint64 fromPledge , uint64 toPledge , uint64 context , uint amount ) internal returns ( uint allowedAmount ) {
2017-09-14 06:03:36 +00:00
uint newAmount ;
2017-09-13 12:41:08 +00:00
allowedAmount = amount ;
2017-10-04 08:24:35 +00:00
PledgeAdmin storage admin = findAdmin ( adminId ) ;
if ( ( address ( admin . plugin ) != 0 ) && ( allowedAmount > 0 ) ) {
2017-09-14 06:03:36 +00:00
if ( before ) {
2017-10-04 08:24:35 +00:00
newAmount = admin . plugin . beforeTransfer ( adminId , fromPledge , toPledge , context , amount ) ;
2017-09-14 06:03:36 +00:00
require ( newAmount <= allowedAmount ) ;
allowedAmount = newAmount ;
} else {
2017-10-04 08:24:35 +00:00
admin . plugin . afterTransfer ( adminId , fromPledge , toPledge , context , amount ) ;
2017-09-14 06:03:36 +00:00
}
2017-09-13 12:41:08 +00:00
}
}
2017-10-03 12:42:21 +00:00
function callPluginsPledge ( bool before , uint64 idPledge , uint64 fromPledge , uint64 toPledge , uint amount ) internal returns ( uint allowedAmount ) {
uint64 offset = idPledge == fromPledge ? 0 : 256 ;
2017-09-13 12:41:08 +00:00
allowedAmount = amount ;
2017-10-03 12:42:21 +00:00
Pledge storage n = findPledge ( idPledge ) ;
2017-09-13 12:41:08 +00:00
2017-10-03 12:42:21 +00:00
allowedAmount = callPlugin ( before , n . owner , fromPledge , toPledge , offset , allowedAmount ) ;
2017-09-13 12:41:08 +00:00
for ( uint64 i = 0 ; i < n . delegationChain . length ; i ++ ) {
2017-10-03 12:42:21 +00:00
allowedAmount = callPlugin ( before , n . delegationChain [ i ] , fromPledge , toPledge , offset + i + 1 , allowedAmount ) ;
2017-09-13 12:41:08 +00:00
}
2017-10-04 23:27:23 +00:00
if ( n . intendedProject > 0 ) {
allowedAmount = callPlugin ( before , n . intendedProject , fromPledge , toPledge , offset + 255 , allowedAmount ) ;
2017-09-13 12:41:08 +00:00
}
}
2017-10-03 12:42:21 +00:00
function callPlugins ( bool before , uint64 fromPledge , uint64 toPledge , uint amount ) internal returns ( uint allowedAmount ) {
2017-09-13 12:41:08 +00:00
allowedAmount = amount ;
2017-10-03 12:42:21 +00:00
allowedAmount = callPluginsPledge ( before , fromPledge , fromPledge , toPledge , allowedAmount ) ;
allowedAmount = callPluginsPledge ( before , toPledge , fromPledge , toPledge , allowedAmount ) ;
2017-09-13 12:41:08 +00:00
}
2017-08-26 19:46:34 +00:00
/////////////
// Test functions
/////////////
function getTime ( ) internal returns ( uint ) {
return now ;
}
event Transfer ( uint64 indexed from , uint64 indexed to , uint amount ) ;
2017-10-04 23:27:23 +00:00
event CancelProject ( uint64 indexed idProject ) ;
2017-08-26 19:46:34 +00:00
}
//File: ./contracts/LiquidPledgingMock.sol
pragma solidity ^ 0 . 4 . 11 ;
// @dev LiquidPledgingMock mocks current block number
contract LiquidPledgingMock is LiquidPledging {
uint public mock_time ;
function LiquidPledgingMock ( address _vault ) LiquidPledging ( _vault ) {
mock_time = now ;
}
function getTime ( ) internal returns ( uint ) {
return mock_time ;
}
function setMockedTime ( uint _t ) {
mock_time = _t ;
}
}