Merge remote-tracking branch 'upstream/master' into add_donor_on_donate

This commit is contained in:
perissology 2017-09-28 08:50:57 -07:00
commit cea412426d
17 changed files with 614 additions and 274 deletions

View File

@ -0,0 +1,6 @@
/* This is an autogenerated file. DO NOT EDIT MANUALLY */
exports.ILiquidPledgingPluginAbi = [{"constant":false,"inputs":[{"name":"noteManager","type":"uint64"},{"name":"noteFrom","type":"uint64"},{"name":"noteTo","type":"uint64"},{"name":"context","type":"uint64"},{"name":"amount","type":"uint256"}],"name":"afterTransfer","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"noteManager","type":"uint64"},{"name":"noteFrom","type":"uint64"},{"name":"noteTo","type":"uint64"},{"name":"context","type":"uint64"},{"name":"amount","type":"uint256"}],"name":"beforeTransfer","outputs":[{"name":"maxAllowed","type":"uint256"}],"payable":false,"type":"function"}]
exports.ILiquidPledgingPluginByteCode = "0x"
exports._solcVersion = "0.4.15+commit.bbb8e64f.Emscripten.clang"
exports._sha256 = "0x0b78eb5f7fc9ad0a36150ca9c8750a9d2e1fc98fa75dbf9627f3abdd201119c4"

View File

@ -0,0 +1,21 @@
//File: ./contracts/ILiquidPledgingPlugin.sol
pragma solidity ^0.4.11;
contract ILiquidPledgingPlugin {
/// @param context In which context it is affected.
/// 0 -> owner from
/// 1 -> First delegate from
/// 2 -> Second delegate from
/// ...
/// 255 -> proposedProject from
///
/// 256 -> owner to
/// 257 -> First delegate to
/// 258 -> Second delegate to
/// ...
/// 511 -> proposedProject to
function beforeTransfer(uint64 noteManager, uint64 noteFrom, uint64 noteTo, uint64 context, uint amount) returns (uint maxAllowed);
function afterTransfer(uint64 noteManager, uint64 noteFrom, uint64 noteTo, uint64 context, uint amount);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,30 @@
//File: contracts/ILiquidPledgingPlugin.sol
pragma solidity ^0.4.11;
contract ILiquidPledgingPlugin {
/// @param context In which context it is affected.
/// 0 -> owner from
/// 1 -> First delegate from
/// 2 -> Second delegate from
/// ...
/// 255 -> proposedProject from
///
/// 256 -> owner to
/// 257 -> First delegate to
/// 258 -> Second delegate to
/// ...
/// 511 -> proposedProject to
function beforeTransfer(uint64 noteManager, uint64 noteFrom, uint64 noteTo, uint64 context, uint amount) returns (uint maxAllowed);
function afterTransfer(uint64 noteManager, uint64 noteFrom, uint64 noteTo, uint64 context, uint amount);
}
//File: ./contracts/LiquidPledgingBase.sol //File: ./contracts/LiquidPledgingBase.sol
pragma solidity ^0.4.11; pragma solidity ^0.4.11;
contract Vault { contract Vault {
function authorizePayment(bytes32 _ref, address _dest, uint _amount); function authorizePayment(bytes32 _ref, address _dest, uint _amount);
function () payable; function () payable;
@ -24,6 +47,7 @@ contract LiquidPledgingBase {
uint64 commitTime; // Only used in donors and projects, its the precommitment time uint64 commitTime; // Only used in donors and projects, its the precommitment time
uint64 parentProject; // Only for projects uint64 parentProject; // Only for projects
bool canceled; // Only for project bool canceled; // Only for project
ILiquidPledgingPlugin plugin; // Handler that is called when one call is affected.
} }
struct Note { struct Note {
@ -69,16 +93,20 @@ contract LiquidPledgingBase {
// Managers functions // Managers functions
////// //////
function addDonor(string name, uint64 commitTime) {//Todo return idManager function addDonor(string name, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idDonor) {//Todo return idManager
idDonor = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Donor, NoteManagerType.Donor,
msg.sender, msg.sender,
name, name,
commitTime, commitTime,
0, 0,
false)); false,
plugin));
DonorAdded(uint64(managers.length-1)); DonorAdded(idDonor);
} }
event DonorAdded(uint64 indexed idDonor); event DonorAdded(uint64 indexed idDonor);
@ -100,52 +128,71 @@ contract LiquidPledgingBase {
event DonorUpdated(uint64 indexed idDonor); event DonorUpdated(uint64 indexed idDonor);
function addDelegate(string name) { //TODO return index number function addDelegate(string name, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idDelegate) { //TODO return index number
idDelegate = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Delegate, NoteManagerType.Delegate,
msg.sender, msg.sender,
name, name,
commitTime,
0, 0,
0, false,
false)); plugin));
DeegateAdded(uint64(managers.length-1)); DeegateAdded(idDelegate);
} }
event DeegateAdded(uint64 indexed idDelegate); event DeegateAdded(uint64 indexed idDelegate);
function updateDelegate(uint64 idDelegate, address newAddr, string newName) { function updateDelegate(
uint64 idDelegate,
address newAddr,
string newName,
uint64 newCommitTime) {
NoteManager storage delegate = findManager(idDelegate); NoteManager storage delegate = findManager(idDelegate);
require(delegate.managerType == NoteManagerType.Delegate); require(delegate.managerType == NoteManagerType.Delegate);
require(delegate.addr == msg.sender); require(delegate.addr == msg.sender);
delegate.addr = newAddr; delegate.addr = newAddr;
delegate.name = newName; delegate.name = newName;
delegate.commitTime = newCommitTime;
DelegateUpdated(idDelegate); DelegateUpdated(idDelegate);
} }
event DelegateUpdated(uint64 indexed idDelegate); event DelegateUpdated(uint64 indexed idDelegate);
function addProject(string name, address projectManager, uint64 parentProject, uint64 commitTime) { function addProject(string name, address projectManager, uint64 parentProject, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idProject) {
if (parentProject != 0) { if (parentProject != 0) {
NoteManager storage pm = findManager(parentProject); NoteManager storage pm = findManager(parentProject);
require(pm.managerType == NoteManagerType.Project); require(pm.managerType == NoteManagerType.Project);
require(pm.addr == msg.sender); require(pm.addr == msg.sender);
require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL); require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL);
} }
idProject = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Project, NoteManagerType.Project,
projectManager, projectManager,
name, name,
commitTime, commitTime,
parentProject, parentProject,
false)); false,
plugin));
ProjectAdded(uint64(managers.length-1));
ProjectAdded(idProject);
} }
event ProjectAdded(uint64 indexed idProject); event ProjectAdded(uint64 indexed idProject);
function updateProject(uint64 idProject, address newAddr, string newName, uint64 newCommitTime) { function updateProject(
uint64 idProject,
address newAddr,
string newName,
uint64 newCommitTime)
{
NoteManager storage project = findManager(idProject); NoteManager storage project = findManager(idProject);
require(project.managerType == NoteManagerType.Project); require(project.managerType == NoteManagerType.Project);
require(project.addr == msg.sender); require(project.addr == msg.sender);
@ -274,6 +321,17 @@ contract LiquidPledgingBase {
return getNoteLevel(oldN) + 1; return getNoteLevel(oldN) + 1;
} }
// helper function that returns the max commit time of the owner and all the
// delegates
function maxCommitTime(Note n) internal returns(uint commitTime) {
NoteManager storage m = findManager(n.owner);
commitTime = m.commitTime;
for (uint i=0; i<n.delegationChain.length; i++) {
m = findManager(n.delegationChain[i]);
if (m.commitTime > commitTime) commitTime = m.commitTime;
}
}
// helper function that returns the project level solely to check that there // helper function that returns the project level solely to check that there
// are not too many Projects that violate MAX_SUBPROJECT_LEVEL // are not too many Projects that violate MAX_SUBPROJECT_LEVEL
@ -318,4 +376,11 @@ contract LiquidPledgingBase {
return getOldestNoteNotCanceled(n.oldNote); return getOldestNoteNotCanceled(n.oldNote);
} }
function checkManagerOwner(NoteManager m) internal constant {
require((msg.sender == m.addr) || (msg.sender == address(m.plugin)));
}
} }

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,30 @@
//File: contracts/ILiquidPledgingPlugin.sol
pragma solidity ^0.4.11;
contract ILiquidPledgingPlugin {
/// @param context In which context it is affected.
/// 0 -> owner from
/// 1 -> First delegate from
/// 2 -> Second delegate from
/// ...
/// 255 -> proposedProject from
///
/// 256 -> owner to
/// 257 -> First delegate to
/// 258 -> Second delegate to
/// ...
/// 511 -> proposedProject to
function beforeTransfer(uint64 noteManager, uint64 noteFrom, uint64 noteTo, uint64 context, uint amount) returns (uint maxAllowed);
function afterTransfer(uint64 noteManager, uint64 noteFrom, uint64 noteTo, uint64 context, uint amount);
}
//File: contracts/LiquidPledgingBase.sol //File: contracts/LiquidPledgingBase.sol
pragma solidity ^0.4.11; pragma solidity ^0.4.11;
contract Vault { contract Vault {
function authorizePayment(bytes32 _ref, address _dest, uint _amount); function authorizePayment(bytes32 _ref, address _dest, uint _amount);
function () payable; function () payable;
@ -24,6 +47,7 @@ contract LiquidPledgingBase {
uint64 commitTime; // Only used in donors and projects, its the precommitment time uint64 commitTime; // Only used in donors and projects, its the precommitment time
uint64 parentProject; // Only for projects uint64 parentProject; // Only for projects
bool canceled; // Only for project bool canceled; // Only for project
ILiquidPledgingPlugin plugin; // Handler that is called when one call is affected.
} }
struct Note { struct Note {
@ -69,16 +93,20 @@ contract LiquidPledgingBase {
// Managers functions // Managers functions
////// //////
function addDonor(string name, uint64 commitTime) {//Todo return idManager function addDonor(string name, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idDonor) {//Todo return idManager
idDonor = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Donor, NoteManagerType.Donor,
msg.sender, msg.sender,
name, name,
commitTime, commitTime,
0, 0,
false)); false,
plugin));
DonorAdded(uint64(managers.length-1)); DonorAdded(idDonor);
} }
event DonorAdded(uint64 indexed idDonor); event DonorAdded(uint64 indexed idDonor);
@ -100,52 +128,71 @@ contract LiquidPledgingBase {
event DonorUpdated(uint64 indexed idDonor); event DonorUpdated(uint64 indexed idDonor);
function addDelegate(string name) { //TODO return index number function addDelegate(string name, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idDelegate) { //TODO return index number
idDelegate = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Delegate, NoteManagerType.Delegate,
msg.sender, msg.sender,
name, name,
commitTime,
0, 0,
0, false,
false)); plugin));
DeegateAdded(uint64(managers.length-1)); DeegateAdded(idDelegate);
} }
event DeegateAdded(uint64 indexed idDelegate); event DeegateAdded(uint64 indexed idDelegate);
function updateDelegate(uint64 idDelegate, address newAddr, string newName) { function updateDelegate(
uint64 idDelegate,
address newAddr,
string newName,
uint64 newCommitTime) {
NoteManager storage delegate = findManager(idDelegate); NoteManager storage delegate = findManager(idDelegate);
require(delegate.managerType == NoteManagerType.Delegate); require(delegate.managerType == NoteManagerType.Delegate);
require(delegate.addr == msg.sender); require(delegate.addr == msg.sender);
delegate.addr = newAddr; delegate.addr = newAddr;
delegate.name = newName; delegate.name = newName;
delegate.commitTime = newCommitTime;
DelegateUpdated(idDelegate); DelegateUpdated(idDelegate);
} }
event DelegateUpdated(uint64 indexed idDelegate); event DelegateUpdated(uint64 indexed idDelegate);
function addProject(string name, address projectManager, uint64 parentProject, uint64 commitTime) { function addProject(string name, address projectManager, uint64 parentProject, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idProject) {
if (parentProject != 0) { if (parentProject != 0) {
NoteManager storage pm = findManager(parentProject); NoteManager storage pm = findManager(parentProject);
require(pm.managerType == NoteManagerType.Project); require(pm.managerType == NoteManagerType.Project);
require(pm.addr == msg.sender); require(pm.addr == msg.sender);
require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL); require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL);
} }
idProject = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Project, NoteManagerType.Project,
projectManager, projectManager,
name, name,
commitTime, commitTime,
parentProject, parentProject,
false)); false,
plugin));
ProjectAdded(uint64(managers.length-1));
ProjectAdded(idProject);
} }
event ProjectAdded(uint64 indexed idProject); event ProjectAdded(uint64 indexed idProject);
function updateProject(uint64 idProject, address newAddr, string newName, uint64 newCommitTime) { function updateProject(
uint64 idProject,
address newAddr,
string newName,
uint64 newCommitTime)
{
NoteManager storage project = findManager(idProject); NoteManager storage project = findManager(idProject);
require(project.managerType == NoteManagerType.Project); require(project.managerType == NoteManagerType.Project);
require(project.addr == msg.sender); require(project.addr == msg.sender);
@ -274,6 +321,17 @@ contract LiquidPledgingBase {
return getNoteLevel(oldN) + 1; return getNoteLevel(oldN) + 1;
} }
// helper function that returns the max commit time of the owner and all the
// delegates
function maxCommitTime(Note n) internal returns(uint commitTime) {
NoteManager storage m = findManager(n.owner);
commitTime = m.commitTime;
for (uint i=0; i<n.delegationChain.length; i++) {
m = findManager(n.delegationChain[i]);
if (m.commitTime > commitTime) commitTime = m.commitTime;
}
}
// helper function that returns the project level solely to check that there // helper function that returns the project level solely to check that there
// are not too many Projects that violate MAX_SUBPROJECT_LEVEL // are not too many Projects that violate MAX_SUBPROJECT_LEVEL
@ -318,6 +376,13 @@ contract LiquidPledgingBase {
return getOldestNoteNotCanceled(n.oldNote); return getOldestNoteNotCanceled(n.oldNote);
} }
function checkManagerOwner(NoteManager m) internal constant {
require((msg.sender == m.addr) || (msg.sender == address(m.plugin)));
}
} }
//File: contracts/LiquidPledging.sol //File: contracts/LiquidPledging.sol
@ -348,8 +413,9 @@ contract LiquidPledging is LiquidPledgingBase {
function donate(uint64 idDonor, uint64 idReceiver) payable {// TODO change to `pledge()` function donate(uint64 idDonor, uint64 idReceiver) payable {// TODO change to `pledge()`
NoteManager storage sender = findManager(idDonor); NoteManager storage sender = findManager(idDonor);
checkManagerOwner(sender);
require(sender.managerType == NoteManagerType.Donor); require(sender.managerType == NoteManagerType.Donor);
require(sender.addr == msg.sender);
uint amount = msg.value; uint amount = msg.value;
@ -389,7 +455,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage receiver = findManager(idReceiver); NoteManager storage receiver = findManager(idReceiver);
NoteManager storage sender = findManager(idSender); NoteManager storage sender = findManager(idSender);
require(sender.addr == msg.sender); checkManagerOwner(sender);
require(n.paymentState == PaymentState.NotPaid); require(n.paymentState == PaymentState.NotPaid);
// If the sender is the owner // If the sender is the owner
@ -472,7 +538,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage owner = findManager(n.owner); NoteManager storage owner = findManager(n.owner);
require(owner.addr == msg.sender); checkManagerOwner(owner);
uint64 idNewNote = findNote( uint64 idNewNote = findNote(
n.owner, n.owner,
@ -538,10 +604,23 @@ contract LiquidPledging is LiquidPledgingBase {
/// @param idProject Id of the projct that wants to be canceled. /// @param idProject Id of the projct that wants to be canceled.
function cancelProject(uint64 idProject) { function cancelProject(uint64 idProject) {
NoteManager storage project = findManager(idProject); NoteManager storage project = findManager(idProject);
require(project.addr == msg.sender); checkManagerOwner(project);
project.canceled = true; project.canceled = true;
} }
function cancelNote(uint64 idNote, uint amount) {
idNote = normalizeNote(idNote);
Note storage n = findNote(idNote);
NoteManager storage m = findManager(n.owner);
checkManagerOwner(m);
doTransfer(idNote, n.oldNote, amount);
}
//////// ////////
// Multi note methods // Multi note methods
//////// ////////
@ -585,6 +664,14 @@ contract LiquidPledging is LiquidPledgingBase {
} }
} }
function mNormalizeNote(uint[] notes) returns(uint64) {
for (uint i = 0; i < notes.length; i++ ) {
uint64 idNote = uint64( notes[i] & (D64-1) );
normalizeNote(idNote);
}
}
//////// ////////
// Private methods // Private methods
/////// ///////
@ -613,8 +700,6 @@ contract LiquidPledging is LiquidPledgingBase {
} }
function transferOwnershipToDonor(uint64 idNote, uint amount, uint64 idReceiver) internal { function transferOwnershipToDonor(uint64 idNote, uint amount, uint64 idReceiver) internal {
Note storage n = findNote(idNote);
uint64 toNote = findNote( uint64 toNote = findNote(
idReceiver, idReceiver,
new uint64[](0), new uint64[](0),
@ -670,18 +755,18 @@ contract LiquidPledging is LiquidPledgingBase {
require(getNoteLevel(n) < MAX_SUBPROJECT_LEVEL); require(getNoteLevel(n) < MAX_SUBPROJECT_LEVEL);
NoteManager storage owner = findManager(n.owner);
uint64 toNote = findNote( uint64 toNote = findNote(
n.owner, n.owner,
n.delegationChain, n.delegationChain,
idReceiver, idReceiver,
uint64(getTime() + owner.commitTime), uint64(getTime() + maxCommitTime(n)),
n.oldNote, n.oldNote,
PaymentState.NotPaid); PaymentState.NotPaid);
doTransfer(idNote, toNote, amount); doTransfer(idNote, toNote, amount);
} }
function doTransfer(uint64 from, uint64 to, uint amount) internal { function doTransfer(uint64 from, uint64 to, uint _amount) internal {
uint amount = callPlugins(true, from, to, _amount);
if (from == to) return; if (from == to) return;
if (amount == 0) return; if (amount == 0) return;
Note storage nFrom = findNote(from); Note storage nFrom = findNote(from);
@ -691,6 +776,7 @@ contract LiquidPledging is LiquidPledgingBase {
nTo.amount += amount; nTo.amount += amount;
Transfer(from, to, amount); Transfer(from, to, amount);
callPlugins(false, from, to, amount);
} }
// This function does 2 things, #1: it checks to make sure that the pledges are correct // This function does 2 things, #1: it checks to make sure that the pledges are correct
@ -699,7 +785,9 @@ contract LiquidPledging is LiquidPledgingBase {
// do what this function does to the note for the end user at the expiration of the committime) // do what this function does to the note for the end user at the expiration of the committime)
// #2: It checks to make sure that if there has been a cancellation in the chain of projects, // #2: It checks to make sure that if there has been a cancellation in the chain of projects,
// then it adjusts the note's owner appropriately. // then it adjusts the note's owner appropriately.
function normalizeNote(uint64 idNote) internal returns(uint64) { // This call can be called from any body at any time on any node. In general it can be called
// to froce the calls of the affected plugins.
function normalizeNote(uint64 idNote) returns(uint64) {
Note storage n = findNote(idNote); Note storage n = findNote(idNote);
// Check to make sure this note hasnt already been used or is in the process of being used // Check to make sure this note hasnt already been used or is in the process of being used
@ -734,6 +822,48 @@ contract LiquidPledging is LiquidPledgingBase {
return toNote; return toNote;
} }
/////////////
// Plugins
/////////////
function callPlugin(bool before, uint64 managerId, uint64 fromNote, uint64 toNote, uint64 context, uint amount) internal returns (uint allowedAmount) {
uint newAmount;
allowedAmount = amount;
NoteManager storage manager = findManager(managerId);
if ((address(manager.plugin) != 0) && (allowedAmount > 0)) {
if (before) {
newAmount = manager.plugin.beforeTransfer(managerId, fromNote, toNote, context, amount);
require(newAmount <= allowedAmount);
allowedAmount = newAmount;
} else {
manager.plugin.afterTransfer(managerId, fromNote, toNote, context, amount);
}
}
}
function callPluginsNote(bool before, uint64 idNote, uint64 fromNote, uint64 toNote, uint amount) internal returns (uint allowedAmount) {
uint64 offset = idNote == fromNote ? 0 : 256;
allowedAmount = amount;
Note storage n = findNote(idNote);
allowedAmount = callPlugin(before, n.owner, fromNote, toNote, offset, allowedAmount);
for (uint64 i=0; i<n.delegationChain.length; i++) {
allowedAmount = callPlugin(before, n.delegationChain[i], fromNote, toNote, offset + i+1, allowedAmount);
}
if (n.proposedProject > 0) {
allowedAmount = callPlugin(before, n.proposedProject, fromNote, toNote, offset + 255, allowedAmount);
}
}
function callPlugins(bool before, uint64 fromNote, uint64 toNote, uint amount) internal returns (uint allowedAmount) {
allowedAmount = amount;
allowedAmount = callPluginsNote(before, fromNote, fromNote, toNote, allowedAmount);
allowedAmount = callPluginsNote(before, toNote, fromNote, toNote, allowedAmount);
}
///////////// /////////////
// Test functions // Test functions
///////////// /////////////

View File

@ -1,7 +1,30 @@
//File: contracts/ILiquidPledgingPlugin.sol
pragma solidity ^0.4.11;
contract ILiquidPledgingPlugin {
/// @param context In which context it is affected.
/// 0 -> owner from
/// 1 -> First delegate from
/// 2 -> Second delegate from
/// ...
/// 255 -> proposedProject from
///
/// 256 -> owner to
/// 257 -> First delegate to
/// 258 -> Second delegate to
/// ...
/// 511 -> proposedProject to
function beforeTransfer(uint64 noteManager, uint64 noteFrom, uint64 noteTo, uint64 context, uint amount) returns (uint maxAllowed);
function afterTransfer(uint64 noteManager, uint64 noteFrom, uint64 noteTo, uint64 context, uint amount);
}
//File: contracts/LiquidPledgingBase.sol //File: contracts/LiquidPledgingBase.sol
pragma solidity ^0.4.11; pragma solidity ^0.4.11;
contract Vault { contract Vault {
function authorizePayment(bytes32 _ref, address _dest, uint _amount); function authorizePayment(bytes32 _ref, address _dest, uint _amount);
function () payable; function () payable;
@ -24,6 +47,7 @@ contract LiquidPledgingBase {
uint64 commitTime; // Only used in donors and projects, its the precommitment time uint64 commitTime; // Only used in donors and projects, its the precommitment time
uint64 parentProject; // Only for projects uint64 parentProject; // Only for projects
bool canceled; // Only for project bool canceled; // Only for project
ILiquidPledgingPlugin plugin; // Handler that is called when one call is affected.
} }
struct Note { struct Note {
@ -69,16 +93,20 @@ contract LiquidPledgingBase {
// Managers functions // Managers functions
////// //////
function addDonor(string name, uint64 commitTime) {//Todo return idManager function addDonor(string name, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idDonor) {//Todo return idManager
idDonor = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Donor, NoteManagerType.Donor,
msg.sender, msg.sender,
name, name,
commitTime, commitTime,
0, 0,
false)); false,
plugin));
DonorAdded(uint64(managers.length-1)); DonorAdded(idDonor);
} }
event DonorAdded(uint64 indexed idDonor); event DonorAdded(uint64 indexed idDonor);
@ -100,52 +128,71 @@ contract LiquidPledgingBase {
event DonorUpdated(uint64 indexed idDonor); event DonorUpdated(uint64 indexed idDonor);
function addDelegate(string name) { //TODO return index number function addDelegate(string name, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idDelegate) { //TODO return index number
idDelegate = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Delegate, NoteManagerType.Delegate,
msg.sender, msg.sender,
name, name,
commitTime,
0, 0,
0, false,
false)); plugin));
DeegateAdded(uint64(managers.length-1)); DeegateAdded(idDelegate);
} }
event DeegateAdded(uint64 indexed idDelegate); event DeegateAdded(uint64 indexed idDelegate);
function updateDelegate(uint64 idDelegate, address newAddr, string newName) { function updateDelegate(
uint64 idDelegate,
address newAddr,
string newName,
uint64 newCommitTime) {
NoteManager storage delegate = findManager(idDelegate); NoteManager storage delegate = findManager(idDelegate);
require(delegate.managerType == NoteManagerType.Delegate); require(delegate.managerType == NoteManagerType.Delegate);
require(delegate.addr == msg.sender); require(delegate.addr == msg.sender);
delegate.addr = newAddr; delegate.addr = newAddr;
delegate.name = newName; delegate.name = newName;
delegate.commitTime = newCommitTime;
DelegateUpdated(idDelegate); DelegateUpdated(idDelegate);
} }
event DelegateUpdated(uint64 indexed idDelegate); event DelegateUpdated(uint64 indexed idDelegate);
function addProject(string name, address projectManager, uint64 parentProject, uint64 commitTime) { function addProject(string name, address projectManager, uint64 parentProject, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idProject) {
if (parentProject != 0) { if (parentProject != 0) {
NoteManager storage pm = findManager(parentProject); NoteManager storage pm = findManager(parentProject);
require(pm.managerType == NoteManagerType.Project); require(pm.managerType == NoteManagerType.Project);
require(pm.addr == msg.sender); require(pm.addr == msg.sender);
require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL); require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL);
} }
idProject = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Project, NoteManagerType.Project,
projectManager, projectManager,
name, name,
commitTime, commitTime,
parentProject, parentProject,
false)); false,
plugin));
ProjectAdded(uint64(managers.length-1));
ProjectAdded(idProject);
} }
event ProjectAdded(uint64 indexed idProject); event ProjectAdded(uint64 indexed idProject);
function updateProject(uint64 idProject, address newAddr, string newName, uint64 newCommitTime) { function updateProject(
uint64 idProject,
address newAddr,
string newName,
uint64 newCommitTime)
{
NoteManager storage project = findManager(idProject); NoteManager storage project = findManager(idProject);
require(project.managerType == NoteManagerType.Project); require(project.managerType == NoteManagerType.Project);
require(project.addr == msg.sender); require(project.addr == msg.sender);
@ -274,6 +321,17 @@ contract LiquidPledgingBase {
return getNoteLevel(oldN) + 1; return getNoteLevel(oldN) + 1;
} }
// helper function that returns the max commit time of the owner and all the
// delegates
function maxCommitTime(Note n) internal returns(uint commitTime) {
NoteManager storage m = findManager(n.owner);
commitTime = m.commitTime;
for (uint i=0; i<n.delegationChain.length; i++) {
m = findManager(n.delegationChain[i]);
if (m.commitTime > commitTime) commitTime = m.commitTime;
}
}
// helper function that returns the project level solely to check that there // helper function that returns the project level solely to check that there
// are not too many Projects that violate MAX_SUBPROJECT_LEVEL // are not too many Projects that violate MAX_SUBPROJECT_LEVEL
@ -318,6 +376,13 @@ contract LiquidPledgingBase {
return getOldestNoteNotCanceled(n.oldNote); return getOldestNoteNotCanceled(n.oldNote);
} }
function checkManagerOwner(NoteManager m) internal constant {
require((msg.sender == m.addr) || (msg.sender == address(m.plugin)));
}
} }
//File: ./contracts/LiquidPledging.sol //File: ./contracts/LiquidPledging.sol
@ -348,8 +413,9 @@ contract LiquidPledging is LiquidPledgingBase {
function donate(uint64 idDonor, uint64 idReceiver) payable {// TODO change to `pledge()` function donate(uint64 idDonor, uint64 idReceiver) payable {// TODO change to `pledge()`
NoteManager storage sender = findManager(idDonor); NoteManager storage sender = findManager(idDonor);
checkManagerOwner(sender);
require(sender.managerType == NoteManagerType.Donor); require(sender.managerType == NoteManagerType.Donor);
require(sender.addr == msg.sender);
uint amount = msg.value; uint amount = msg.value;
@ -389,7 +455,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage receiver = findManager(idReceiver); NoteManager storage receiver = findManager(idReceiver);
NoteManager storage sender = findManager(idSender); NoteManager storage sender = findManager(idSender);
require(sender.addr == msg.sender); checkManagerOwner(sender);
require(n.paymentState == PaymentState.NotPaid); require(n.paymentState == PaymentState.NotPaid);
// If the sender is the owner // If the sender is the owner
@ -472,7 +538,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage owner = findManager(n.owner); NoteManager storage owner = findManager(n.owner);
require(owner.addr == msg.sender); checkManagerOwner(owner);
uint64 idNewNote = findNote( uint64 idNewNote = findNote(
n.owner, n.owner,
@ -538,10 +604,23 @@ contract LiquidPledging is LiquidPledgingBase {
/// @param idProject Id of the projct that wants to be canceled. /// @param idProject Id of the projct that wants to be canceled.
function cancelProject(uint64 idProject) { function cancelProject(uint64 idProject) {
NoteManager storage project = findManager(idProject); NoteManager storage project = findManager(idProject);
require(project.addr == msg.sender); checkManagerOwner(project);
project.canceled = true; project.canceled = true;
} }
function cancelNote(uint64 idNote, uint amount) {
idNote = normalizeNote(idNote);
Note storage n = findNote(idNote);
NoteManager storage m = findManager(n.owner);
checkManagerOwner(m);
doTransfer(idNote, n.oldNote, amount);
}
//////// ////////
// Multi note methods // Multi note methods
//////// ////////
@ -585,6 +664,14 @@ contract LiquidPledging is LiquidPledgingBase {
} }
} }
function mNormalizeNote(uint[] notes) returns(uint64) {
for (uint i = 0; i < notes.length; i++ ) {
uint64 idNote = uint64( notes[i] & (D64-1) );
normalizeNote(idNote);
}
}
//////// ////////
// Private methods // Private methods
/////// ///////
@ -613,8 +700,6 @@ contract LiquidPledging is LiquidPledgingBase {
} }
function transferOwnershipToDonor(uint64 idNote, uint amount, uint64 idReceiver) internal { function transferOwnershipToDonor(uint64 idNote, uint amount, uint64 idReceiver) internal {
Note storage n = findNote(idNote);
uint64 toNote = findNote( uint64 toNote = findNote(
idReceiver, idReceiver,
new uint64[](0), new uint64[](0),
@ -670,18 +755,18 @@ contract LiquidPledging is LiquidPledgingBase {
require(getNoteLevel(n) < MAX_SUBPROJECT_LEVEL); require(getNoteLevel(n) < MAX_SUBPROJECT_LEVEL);
NoteManager storage owner = findManager(n.owner);
uint64 toNote = findNote( uint64 toNote = findNote(
n.owner, n.owner,
n.delegationChain, n.delegationChain,
idReceiver, idReceiver,
uint64(getTime() + owner.commitTime), uint64(getTime() + maxCommitTime(n)),
n.oldNote, n.oldNote,
PaymentState.NotPaid); PaymentState.NotPaid);
doTransfer(idNote, toNote, amount); doTransfer(idNote, toNote, amount);
} }
function doTransfer(uint64 from, uint64 to, uint amount) internal { function doTransfer(uint64 from, uint64 to, uint _amount) internal {
uint amount = callPlugins(true, from, to, _amount);
if (from == to) return; if (from == to) return;
if (amount == 0) return; if (amount == 0) return;
Note storage nFrom = findNote(from); Note storage nFrom = findNote(from);
@ -691,6 +776,7 @@ contract LiquidPledging is LiquidPledgingBase {
nTo.amount += amount; nTo.amount += amount;
Transfer(from, to, amount); Transfer(from, to, amount);
callPlugins(false, from, to, amount);
} }
// This function does 2 things, #1: it checks to make sure that the pledges are correct // This function does 2 things, #1: it checks to make sure that the pledges are correct
@ -699,7 +785,9 @@ contract LiquidPledging is LiquidPledgingBase {
// do what this function does to the note for the end user at the expiration of the committime) // do what this function does to the note for the end user at the expiration of the committime)
// #2: It checks to make sure that if there has been a cancellation in the chain of projects, // #2: It checks to make sure that if there has been a cancellation in the chain of projects,
// then it adjusts the note's owner appropriately. // then it adjusts the note's owner appropriately.
function normalizeNote(uint64 idNote) internal returns(uint64) { // This call can be called from any body at any time on any node. In general it can be called
// to froce the calls of the affected plugins.
function normalizeNote(uint64 idNote) returns(uint64) {
Note storage n = findNote(idNote); Note storage n = findNote(idNote);
// Check to make sure this note hasnt already been used or is in the process of being used // Check to make sure this note hasnt already been used or is in the process of being used
@ -734,6 +822,48 @@ contract LiquidPledging is LiquidPledgingBase {
return toNote; return toNote;
} }
/////////////
// Plugins
/////////////
function callPlugin(bool before, uint64 managerId, uint64 fromNote, uint64 toNote, uint64 context, uint amount) internal returns (uint allowedAmount) {
uint newAmount;
allowedAmount = amount;
NoteManager storage manager = findManager(managerId);
if ((address(manager.plugin) != 0) && (allowedAmount > 0)) {
if (before) {
newAmount = manager.plugin.beforeTransfer(managerId, fromNote, toNote, context, amount);
require(newAmount <= allowedAmount);
allowedAmount = newAmount;
} else {
manager.plugin.afterTransfer(managerId, fromNote, toNote, context, amount);
}
}
}
function callPluginsNote(bool before, uint64 idNote, uint64 fromNote, uint64 toNote, uint amount) internal returns (uint allowedAmount) {
uint64 offset = idNote == fromNote ? 0 : 256;
allowedAmount = amount;
Note storage n = findNote(idNote);
allowedAmount = callPlugin(before, n.owner, fromNote, toNote, offset, allowedAmount);
for (uint64 i=0; i<n.delegationChain.length; i++) {
allowedAmount = callPlugin(before, n.delegationChain[i], fromNote, toNote, offset + i+1, allowedAmount);
}
if (n.proposedProject > 0) {
allowedAmount = callPlugin(before, n.proposedProject, fromNote, toNote, offset + 255, allowedAmount);
}
}
function callPlugins(bool before, uint64 fromNote, uint64 toNote, uint amount) internal returns (uint allowedAmount) {
allowedAmount = amount;
allowedAmount = callPluginsNote(before, fromNote, fromNote, toNote, allowedAmount);
allowedAmount = callPluginsNote(before, toNote, fromNote, toNote, allowedAmount);
}
///////////// /////////////
// Test functions // Test functions
///////////// /////////////

View File

@ -1,74 +0,0 @@
pragma solidity ^0.4.11;
contract ILiquidPledging {
// TODO: make this enum its own contract... or at least make it so that an owner
// can add a new NoteManagerType
enum NoteManagerType { Donor, Delegate, Project}
enum PaymentState {NotPaid, Paying, Paid}
function numberOfNotes() constant returns (uint);
function getNote(uint64 idNote) constant returns(
uint amount,
uint64 owner,
uint64 nDelegates,
uint64 proposedProject,
uint64 commmitTime,
uint64 oldNote,
PaymentState paymentState
);
function getNoteDelegate(uint64 idNote, uint idxDelegate) constant returns(
uint64 idDelegate,
address addr,
string name
);
function numberOfNoteManagers() constant returns(uint);
function getNoteManager(uint64 idManager) constant returns (
NoteManagerType managerType,
address addr,
string name,
uint64 commitTime,
address reviewer,
bool canceled);
event DonorAdded(uint64 indexed idMember);
function addDonor(string name, uint64 commitTime);
function updateDonor(
uint64 idDonor,
address newAddr,
string newName,
uint64 newCommitTime);
function addDelegate(string name);
function updateDelegate(uint64 idDelegate, address newAddr, string newName);
function addProject(string name, address canceler, uint64 commitTime) ;
function updateProject(uint64 idProject, address newAddr, string newName, uint64 newCommitTime);
function updateProjectCanceler(uint64 idProject, address newCanceler);
function donate(uint64 idDonor, uint64 idReceiver) payable;
/// @param idSender idDonor or idDelegate that executes the action
/// @param idReceiver idDonor or idCampaign that wants to be transfered.
/// @param note piece That wants to be transfered.
/// @param amount quantity of the state that wants to be transfered.
function transfer(uint64 idSender, uint64 note, uint amount, uint64 idReceiver);
function mTransfer(uint64 idSender, uint[] notesAmounts, uint64 idReceiver);
function withdraw(uint64 note, uint amount, string concept);
function mWithdraw(uint[] notesAmounts, string concept);
function confirmPayment(uint64 idNote, uint amount);
function mConfirmPayment(uint[] notesAmounts);
function cancelPayment(uint64 idNote, uint amount);
function mCancelPayment(uint[] notesAmounts);
function cancelProject(int64 idCampaign);
}

View File

@ -0,0 +1,19 @@
pragma solidity ^0.4.11;
contract ILiquidPledgingPlugin {
/// @param context In which context it is affected.
/// 0 -> owner from
/// 1 -> First delegate from
/// 2 -> Second delegate from
/// ...
/// 255 -> proposedProject from
///
/// 256 -> owner to
/// 257 -> First delegate to
/// 258 -> Second delegate to
/// ...
/// 511 -> proposedProject to
function beforeTransfer(uint64 noteManager, uint64 noteFrom, uint64 noteTo, uint64 context, uint amount) returns (uint maxAllowed);
function afterTransfer(uint64 noteManager, uint64 noteFrom, uint64 noteTo, uint64 context, uint amount);
}

View File

@ -1,74 +0,0 @@
contract LiquidPledgingInterface {
function addUser
function updateUser
function addCause
function deposit(uint64 user) payable;
function withdraw(uint64 user, uint64 idNote, uint amount);
function delegate(uint64 user, uint64 idNote, uint64 purpuse, uint amout);
function undelegate(uint64 user, uint64 idNote, uint amount);
function precommit(uint user, uint64 idNote, uint64 recipient, uint amount);
function unPrecommit(uint user, uint64 idNote, uint amount);
function transfer(uint64 user, uint64 idNote, uint64 recipient, uint amount);
}
owner project out
owner transfer invest withdrow
project uninvest detail spend
in deposit xx xx
Who owns
////
Liquid LiquidPledging
//////
Funding part
/////
Executive part
contract Project {
struct TokenOwnership {
address token;
uint purchaseBlock;
uint amount;
bytes32 ref;
}
Minime2Token public projectToken;
mapping(uint => Minime2Token) public pledgedTokens;
TokenOwnership[] public ownerships;
function pledge(address investor, uint amount, uint precommit);
function unpledge(address investor, uint amount);
function invest(address investor, uint amount);
function unInvest(address investor, uint amount);
function pay(address dest, uint amount, uint block) onlyProjectManager;
function receive(uint amount);
function payDividends(uint token, uint amount, uint payBlock);
}

View File

@ -29,8 +29,9 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage sender = findManager(idDonor); NoteManager storage sender = findManager(idDonor);
checkManagerOwner(sender);
require(sender.managerType == NoteManagerType.Donor); require(sender.managerType == NoteManagerType.Donor);
require(sender.addr == msg.sender);
uint amount = msg.value; uint amount = msg.value;
@ -70,7 +71,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage receiver = findManager(idReceiver); NoteManager storage receiver = findManager(idReceiver);
NoteManager storage sender = findManager(idSender); NoteManager storage sender = findManager(idSender);
require(sender.addr == msg.sender); checkManagerOwner(sender);
require(n.paymentState == PaymentState.NotPaid); require(n.paymentState == PaymentState.NotPaid);
// If the sender is the owner // If the sender is the owner
@ -153,7 +154,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage owner = findManager(n.owner); NoteManager storage owner = findManager(n.owner);
require(owner.addr == msg.sender); checkManagerOwner(owner);
uint64 idNewNote = findNote( uint64 idNewNote = findNote(
n.owner, n.owner,
@ -219,10 +220,23 @@ contract LiquidPledging is LiquidPledgingBase {
/// @param idProject Id of the projct that wants to be canceled. /// @param idProject Id of the projct that wants to be canceled.
function cancelProject(uint64 idProject) { function cancelProject(uint64 idProject) {
NoteManager storage project = findManager(idProject); NoteManager storage project = findManager(idProject);
require(project.addr == msg.sender); checkManagerOwner(project);
project.canceled = true; project.canceled = true;
} }
function cancelNote(uint64 idNote, uint amount) {
idNote = normalizeNote(idNote);
Note storage n = findNote(idNote);
NoteManager storage m = findManager(n.owner);
checkManagerOwner(m);
doTransfer(idNote, n.oldNote, amount);
}
//////// ////////
// Multi note methods // Multi note methods
//////// ////////
@ -266,6 +280,14 @@ contract LiquidPledging is LiquidPledgingBase {
} }
} }
function mNormalizeNote(uint[] notes) returns(uint64) {
for (uint i = 0; i < notes.length; i++ ) {
uint64 idNote = uint64( notes[i] & (D64-1) );
normalizeNote(idNote);
}
}
//////// ////////
// Private methods // Private methods
/////// ///////
@ -294,8 +316,6 @@ contract LiquidPledging is LiquidPledgingBase {
} }
function transferOwnershipToDonor(uint64 idNote, uint amount, uint64 idReceiver) internal { function transferOwnershipToDonor(uint64 idNote, uint amount, uint64 idReceiver) internal {
Note storage n = findNote(idNote);
uint64 toNote = findNote( uint64 toNote = findNote(
idReceiver, idReceiver,
new uint64[](0), new uint64[](0),
@ -351,18 +371,18 @@ contract LiquidPledging is LiquidPledgingBase {
require(getNoteLevel(n) < MAX_SUBPROJECT_LEVEL); require(getNoteLevel(n) < MAX_SUBPROJECT_LEVEL);
NoteManager storage owner = findManager(n.owner);
uint64 toNote = findNote( uint64 toNote = findNote(
n.owner, n.owner,
n.delegationChain, n.delegationChain,
idReceiver, idReceiver,
uint64(getTime() + owner.commitTime), uint64(getTime() + maxCommitTime(n)),
n.oldNote, n.oldNote,
PaymentState.NotPaid); PaymentState.NotPaid);
doTransfer(idNote, toNote, amount); doTransfer(idNote, toNote, amount);
} }
function doTransfer(uint64 from, uint64 to, uint amount) internal { function doTransfer(uint64 from, uint64 to, uint _amount) internal {
uint amount = callPlugins(true, from, to, _amount);
if (from == to) return; if (from == to) return;
if (amount == 0) return; if (amount == 0) return;
Note storage nFrom = findNote(from); Note storage nFrom = findNote(from);
@ -372,6 +392,7 @@ contract LiquidPledging is LiquidPledgingBase {
nTo.amount += amount; nTo.amount += amount;
Transfer(from, to, amount); Transfer(from, to, amount);
callPlugins(false, from, to, amount);
} }
// This function does 2 things, #1: it checks to make sure that the pledges are correct // This function does 2 things, #1: it checks to make sure that the pledges are correct
@ -380,7 +401,9 @@ contract LiquidPledging is LiquidPledgingBase {
// do what this function does to the note for the end user at the expiration of the committime) // do what this function does to the note for the end user at the expiration of the committime)
// #2: It checks to make sure that if there has been a cancellation in the chain of projects, // #2: It checks to make sure that if there has been a cancellation in the chain of projects,
// then it adjusts the note's owner appropriately. // then it adjusts the note's owner appropriately.
function normalizeNote(uint64 idNote) internal returns(uint64) { // This call can be called from any body at any time on any node. In general it can be called
// to froce the calls of the affected plugins.
function normalizeNote(uint64 idNote) returns(uint64) {
Note storage n = findNote(idNote); Note storage n = findNote(idNote);
// Check to make sure this note hasnt already been used or is in the process of being used // Check to make sure this note hasnt already been used or is in the process of being used
@ -415,6 +438,48 @@ contract LiquidPledging is LiquidPledgingBase {
return toNote; return toNote;
} }
/////////////
// Plugins
/////////////
function callPlugin(bool before, uint64 managerId, uint64 fromNote, uint64 toNote, uint64 context, uint amount) internal returns (uint allowedAmount) {
uint newAmount;
allowedAmount = amount;
NoteManager storage manager = findManager(managerId);
if ((address(manager.plugin) != 0) && (allowedAmount > 0)) {
if (before) {
newAmount = manager.plugin.beforeTransfer(managerId, fromNote, toNote, context, amount);
require(newAmount <= allowedAmount);
allowedAmount = newAmount;
} else {
manager.plugin.afterTransfer(managerId, fromNote, toNote, context, amount);
}
}
}
function callPluginsNote(bool before, uint64 idNote, uint64 fromNote, uint64 toNote, uint amount) internal returns (uint allowedAmount) {
uint64 offset = idNote == fromNote ? 0 : 256;
allowedAmount = amount;
Note storage n = findNote(idNote);
allowedAmount = callPlugin(before, n.owner, fromNote, toNote, offset, allowedAmount);
for (uint64 i=0; i<n.delegationChain.length; i++) {
allowedAmount = callPlugin(before, n.delegationChain[i], fromNote, toNote, offset + i+1, allowedAmount);
}
if (n.proposedProject > 0) {
allowedAmount = callPlugin(before, n.proposedProject, fromNote, toNote, offset + 255, allowedAmount);
}
}
function callPlugins(bool before, uint64 fromNote, uint64 toNote, uint amount) internal returns (uint allowedAmount) {
allowedAmount = amount;
allowedAmount = callPluginsNote(before, fromNote, fromNote, toNote, allowedAmount);
allowedAmount = callPluginsNote(before, toNote, fromNote, toNote, allowedAmount);
}
///////////// /////////////
// Test functions // Test functions
///////////// /////////////

View File

@ -1,5 +1,7 @@
pragma solidity ^0.4.11; pragma solidity ^0.4.11;
import "./ILiquidPledgingPlugin.sol";
contract Vault { contract Vault {
function authorizePayment(bytes32 _ref, address _dest, uint _amount); function authorizePayment(bytes32 _ref, address _dest, uint _amount);
function () payable; function () payable;
@ -22,6 +24,7 @@ contract LiquidPledgingBase {
uint64 commitTime; // Only used in donors and projects, its the precommitment time uint64 commitTime; // Only used in donors and projects, its the precommitment time
uint64 parentProject; // Only for projects uint64 parentProject; // Only for projects
bool canceled; // Only for project bool canceled; // Only for project
ILiquidPledgingPlugin plugin; // Handler that is called when one call is affected.
} }
struct Note { struct Note {
@ -67,18 +70,20 @@ contract LiquidPledgingBase {
// Managers functions // Managers functions
////// //////
function addDonor(string name, uint64 commitTime) returns (uint64 idManager) { function addDonor(string name, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idDonor) {
idDonor = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Donor, NoteManagerType.Donor,
msg.sender, msg.sender,
name, name,
commitTime, commitTime,
0, 0,
false)); false,
plugin));
idManager = uint64(managers.length-1); DonorAdded(idDonor);
DonorAdded(idManager);
} }
event DonorAdded(uint64 indexed idDonor); event DonorAdded(uint64 indexed idDonor);
@ -100,52 +105,71 @@ contract LiquidPledgingBase {
event DonorUpdated(uint64 indexed idDonor); event DonorUpdated(uint64 indexed idDonor);
function addDelegate(string name) { //TODO return index number function addDelegate(string name, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idDelegate) { //TODO return index number
idDelegate = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Delegate, NoteManagerType.Delegate,
msg.sender, msg.sender,
name, name,
commitTime,
0, 0,
0, false,
false)); plugin));
DelegateAdded(uint64(managers.length-1)); DelegateAdded(idDelegate);
} }
event DelegateAdded(uint64 indexed idDelegate); event DelegateAdded(uint64 indexed idDelegate);
function updateDelegate(uint64 idDelegate, address newAddr, string newName) { function updateDelegate(
uint64 idDelegate,
address newAddr,
string newName,
uint64 newCommitTime) {
NoteManager storage delegate = findManager(idDelegate); NoteManager storage delegate = findManager(idDelegate);
require(delegate.managerType == NoteManagerType.Delegate); require(delegate.managerType == NoteManagerType.Delegate);
require(delegate.addr == msg.sender); require(delegate.addr == msg.sender);
delegate.addr = newAddr; delegate.addr = newAddr;
delegate.name = newName; delegate.name = newName;
delegate.commitTime = newCommitTime;
DelegateUpdated(idDelegate); DelegateUpdated(idDelegate);
} }
event DelegateUpdated(uint64 indexed idDelegate); event DelegateUpdated(uint64 indexed idDelegate);
function addProject(string name, address projectManager, uint64 parentProject, uint64 commitTime) { function addProject(string name, address projectManager, uint64 parentProject, uint64 commitTime, ILiquidPledgingPlugin plugin) returns (uint64 idProject) {
if (parentProject != 0) { if (parentProject != 0) {
NoteManager storage pm = findManager(parentProject); NoteManager storage pm = findManager(parentProject);
require(pm.managerType == NoteManagerType.Project); require(pm.managerType == NoteManagerType.Project);
require(pm.addr == msg.sender); require(pm.addr == msg.sender);
require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL); require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL);
} }
idProject = uint64(managers.length);
managers.push(NoteManager( managers.push(NoteManager(
NoteManagerType.Project, NoteManagerType.Project,
projectManager, projectManager,
name, name,
commitTime, commitTime,
parentProject, parentProject,
false)); false,
plugin));
ProjectAdded(uint64(managers.length-1));
ProjectAdded(idProject);
} }
event ProjectAdded(uint64 indexed idProject); event ProjectAdded(uint64 indexed idProject);
function updateProject(uint64 idProject, address newAddr, string newName, uint64 newCommitTime) { function updateProject(
uint64 idProject,
address newAddr,
string newName,
uint64 newCommitTime)
{
NoteManager storage project = findManager(idProject); NoteManager storage project = findManager(idProject);
require(project.managerType == NoteManagerType.Project); require(project.managerType == NoteManagerType.Project);
require(project.addr == msg.sender); require(project.addr == msg.sender);
@ -274,6 +298,17 @@ contract LiquidPledgingBase {
return getNoteLevel(oldN) + 1; return getNoteLevel(oldN) + 1;
} }
// helper function that returns the max commit time of the owner and all the
// delegates
function maxCommitTime(Note n) internal returns(uint commitTime) {
NoteManager storage m = findManager(n.owner);
commitTime = m.commitTime;
for (uint i=0; i<n.delegationChain.length; i++) {
m = findManager(n.delegationChain[i]);
if (m.commitTime > commitTime) commitTime = m.commitTime;
}
}
// helper function that returns the project level solely to check that there // helper function that returns the project level solely to check that there
// are not too many Projects that violate MAX_SUBPROJECT_LEVEL // are not too many Projects that violate MAX_SUBPROJECT_LEVEL
@ -318,4 +353,11 @@ contract LiquidPledgingBase {
return getOldestNoteNotCanceled(n.oldNote); return getOldestNoteNotCanceled(n.oldNote);
} }
function checkManagerOwner(NoteManager m) internal constant {
require((msg.sender == m.addr) || (msg.sender == address(m.plugin)));
}
} }

View File

@ -14,7 +14,8 @@ contract Owned {
address public owner; address public owner;
/// @notice The Constructor assigns the message sender to be `owner` /// @notice The Constructor assigns the account deploying the contract to be
/// the `owner`
function Owned() { function Owned() {
owner = msg.sender; owner = msg.sender;
} }
@ -22,13 +23,16 @@ contract Owned {
address public newOwner; address public newOwner;
/// @notice `owner` can step down and assign some other address to this role /// @notice `owner` can step down and assign some other address to this role
/// @param _newOwner The address of the new owner. 0x0 can be used to create /// but after this function is called the current owner still has ownership
/// an unowned neutral vault, however that cannot be undone /// powers in this contract; change of ownership is a 2 step process
/// @param _newOwner The address of the new owner. A simple contract with
/// the abilitiy to accept ownership but the inability to do anything else
/// can be used to create an unowned contract to achieve decentralization
function changeOwner(address _newOwner) onlyOwner { function changeOwner(address _newOwner) onlyOwner {
newOwner = _newOwner; newOwner = _newOwner;
} }
/// @notice `newOwner` can accept ownership over this contract
function acceptOwnership() { function acceptOwnership() {
if (msg.sender == newOwner) { if (msg.sender == newOwner) {
owner = newOwner; owner = newOwner;

18
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "liquidpledging", "name": "liquidpledging",
"version": "0.0.1", "version": "0.0.5",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -3595,14 +3595,6 @@
} }
} }
}, },
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"requires": {
"safe-buffer": "5.1.1"
}
},
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
@ -3623,6 +3615,14 @@
"function-bind": "1.1.0" "function-bind": "1.1.0"
} }
}, },
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"requires": {
"safe-buffer": "5.1.1"
}
},
"stringstream": { "stringstream": {
"version": "0.0.5", "version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "liquidpledging", "name": "liquidpledging",
"version": "0.0.3", "version": "0.0.7",
"description": "Liquid Pledging Smart Contract", "description": "Liquid Pledging Smart Contract",
"main": "index.js", "main": "index.js",
"directories": { "directories": {

View File

@ -26,15 +26,15 @@ const printBalances = async(liquidPledging) => {
}; };
const readTest = async(liquidPledging) => { const readTest = async(liquidPledging) => {
t1 = await liquidPledging.test1(); const t1 = await liquidPledging.test1();
t2 = await liquidPledging.test2(); const t2 = await liquidPledging.test2();
t3 = await liquidPledging.test3(); const t3 = await liquidPledging.test3();
t4 = await liquidPledging.test4(); const t4 = await liquidPledging.test4();
console.log("t1: ", t1.toNumber()); console.log('t1: ', t1.toNumber());
console.log("t2: ", t2.toNumber()); console.log('t2: ', t2.toNumber());
console.log("t3: ", t3.toNumber()); console.log('t3: ', t3.toNumber());
console.log("t4: ", t4.toNumber()); console.log('t4: ', t4.toNumber());
} };
describe('LiquidPledging test', () => { describe('LiquidPledging test', () => {
let web3; let web3;
@ -49,7 +49,7 @@ describe('LiquidPledging test', () => {
let adminProject2a; let adminProject2a;
let delegate2; let delegate2;
before((done) => { before((done) => {
ethConnector.init('testrpc', { gasLimit: 4700000 }, () => { ethConnector.init('testrpc', { gasLimit: 5200000 }, () => {
web3 = ethConnector.web3; web3 = ethConnector.web3;
accounts = ethConnector.accounts; accounts = ethConnector.accounts;
donor1 = accounts[1]; donor1 = accounts[1];
@ -64,11 +64,11 @@ describe('LiquidPledging test', () => {
}); });
it('Should deploy LiquidPledging contract', async () => { it('Should deploy LiquidPledging contract', async () => {
vault = await Vault.new(web3); vault = await Vault.new(web3);
liquidPledging = await LiquidPledging.new(web3, vault.$address); liquidPledging = await LiquidPledging.new(web3, vault.$address, { gas: 5200000 });
await vault.setLiquidPledging(liquidPledging.$address); await vault.setLiquidPledging(liquidPledging.$address);
}).timeout(6000); }).timeout(6000);
it('Should create a donor', async () => { it('Should create a donor', async () => {
await liquidPledging.addDonor('Donor1', 86400, { from: donor1 }); await liquidPledging.addDonor('Donor1', 86400, 0, { from: donor1 });
const nManagers = await liquidPledging.numberOfNoteManagers(); const nManagers = await liquidPledging.numberOfNoteManagers();
assert.equal(nManagers, 1); assert.equal(nManagers, 1);
const res = await liquidPledging.getNoteManager(1); const res = await liquidPledging.getNoteManager(1);
@ -84,7 +84,7 @@ describe('LiquidPledging test', () => {
await liquidPledging.getNote(1); await liquidPledging.getNote(1);
}).timeout(6000); }).timeout(6000);
it('Should create a delegate', async () => { it('Should create a delegate', async () => {
await liquidPledging.addDelegate('Delegate1', { from: delegate1 }); await liquidPledging.addDelegate('Delegate1', 0, 0, { from: delegate1 });
const nManagers = await liquidPledging.numberOfNoteManagers(); const nManagers = await liquidPledging.numberOfNoteManagers();
assert.equal(nManagers, 2); assert.equal(nManagers, 2);
const res = await liquidPledging.getNoteManager(2); const res = await liquidPledging.getNoteManager(2);
@ -108,7 +108,7 @@ describe('LiquidPledging test', () => {
assert.equal(d[2], 'Delegate1'); assert.equal(d[2], 'Delegate1');
}).timeout(6000); }).timeout(6000);
it('Should create a 2 projects', async () => { it('Should create a 2 projects', async () => {
await liquidPledging.addProject('Project1', adminProject1, 0, 86400, { from: adminProject1 }); await liquidPledging.addProject('Project1', adminProject1, 0, 86400, 0, { from: adminProject1 });
const nManagers = await liquidPledging.numberOfNoteManagers(); const nManagers = await liquidPledging.numberOfNoteManagers();
assert.equal(nManagers, 3); assert.equal(nManagers, 3);
@ -120,7 +120,7 @@ describe('LiquidPledging test', () => {
assert.equal(res[4], 0); assert.equal(res[4], 0);
assert.equal(res[5], false); assert.equal(res[5], false);
await liquidPledging.addProject('Project2', adminProject2, 0, 86400, { from: adminProject2 }); await liquidPledging.addProject('Project2', adminProject2, 0, 86400, 0, { from: adminProject2 });
const nManagers2 = await liquidPledging.numberOfNoteManagers(); const nManagers2 = await liquidPledging.numberOfNoteManagers();
assert.equal(nManagers2, 4); assert.equal(nManagers2, 4);
@ -236,8 +236,8 @@ describe('LiquidPledging test', () => {
assert.equal(web3.fromWei(st.notes[4].amount).toNumber(), 0.12); assert.equal(web3.fromWei(st.notes[4].amount).toNumber(), 0.12);
}).timeout(6000); }).timeout(6000);
it('A subproject 2a and a delegate2 is created', async () => { it('A subproject 2a and a delegate2 is created', async () => {
await liquidPledging.addProject('Project2a', adminProject2a, 4, 86400, { from: adminProject2 }); await liquidPledging.addProject('Project2a', adminProject2a, 4, 86400, 0, { from: adminProject2 });
await liquidPledging.addDelegate('Delegate2', { from: delegate2 }); await liquidPledging.addDelegate('Delegate2', 0, 0, { from: delegate2 });
const nManagers = await liquidPledging.numberOfNoteManagers(); const nManagers = await liquidPledging.numberOfNoteManagers();
assert.equal(nManagers, 6); assert.equal(nManagers, 6);
}).timeout(6000); }).timeout(6000);