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
pragma solidity ^0.4.11;
contract Vault {
function authorizePayment(bytes32 _ref, address _dest, uint _amount);
function () payable;
@ -24,6 +47,7 @@ contract LiquidPledgingBase {
uint64 commitTime; // Only used in donors and projects, its the precommitment time
uint64 parentProject; // Only for projects
bool canceled; // Only for project
ILiquidPledgingPlugin plugin; // Handler that is called when one call is affected.
}
struct Note {
@ -69,16 +93,20 @@ contract LiquidPledgingBase {
// 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(
NoteManagerType.Donor,
msg.sender,
name,
commitTime,
0,
false));
false,
plugin));
DonorAdded(uint64(managers.length-1));
DonorAdded(idDonor);
}
event DonorAdded(uint64 indexed idDonor);
@ -100,52 +128,71 @@ contract LiquidPledgingBase {
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(
NoteManagerType.Delegate,
msg.sender,
name,
commitTime,
0,
0,
false));
false,
plugin));
DeegateAdded(uint64(managers.length-1));
DeegateAdded(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);
require(delegate.managerType == NoteManagerType.Delegate);
require(delegate.addr == msg.sender);
delegate.addr = newAddr;
delegate.name = newName;
delegate.commitTime = newCommitTime;
DelegateUpdated(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) {
NoteManager storage pm = findManager(parentProject);
require(pm.managerType == NoteManagerType.Project);
require(pm.addr == msg.sender);
require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL);
}
idProject = uint64(managers.length);
managers.push(NoteManager(
NoteManagerType.Project,
projectManager,
name,
commitTime,
parentProject,
false));
false,
plugin));
ProjectAdded(uint64(managers.length-1));
ProjectAdded(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);
require(project.managerType == NoteManagerType.Project);
require(project.addr == msg.sender);
@ -274,6 +321,17 @@ contract LiquidPledgingBase {
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
// are not too many Projects that violate MAX_SUBPROJECT_LEVEL
@ -318,4 +376,11 @@ contract LiquidPledgingBase {
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
pragma solidity ^0.4.11;
contract Vault {
function authorizePayment(bytes32 _ref, address _dest, uint _amount);
function () payable;
@ -24,6 +47,7 @@ contract LiquidPledgingBase {
uint64 commitTime; // Only used in donors and projects, its the precommitment time
uint64 parentProject; // Only for projects
bool canceled; // Only for project
ILiquidPledgingPlugin plugin; // Handler that is called when one call is affected.
}
struct Note {
@ -69,16 +93,20 @@ contract LiquidPledgingBase {
// 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(
NoteManagerType.Donor,
msg.sender,
name,
commitTime,
0,
false));
false,
plugin));
DonorAdded(uint64(managers.length-1));
DonorAdded(idDonor);
}
event DonorAdded(uint64 indexed idDonor);
@ -100,52 +128,71 @@ contract LiquidPledgingBase {
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(
NoteManagerType.Delegate,
msg.sender,
name,
commitTime,
0,
0,
false));
false,
plugin));
DeegateAdded(uint64(managers.length-1));
DeegateAdded(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);
require(delegate.managerType == NoteManagerType.Delegate);
require(delegate.addr == msg.sender);
delegate.addr = newAddr;
delegate.name = newName;
delegate.commitTime = newCommitTime;
DelegateUpdated(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) {
NoteManager storage pm = findManager(parentProject);
require(pm.managerType == NoteManagerType.Project);
require(pm.addr == msg.sender);
require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL);
}
idProject = uint64(managers.length);
managers.push(NoteManager(
NoteManagerType.Project,
projectManager,
name,
commitTime,
parentProject,
false));
false,
plugin));
ProjectAdded(uint64(managers.length-1));
ProjectAdded(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);
require(project.managerType == NoteManagerType.Project);
require(project.addr == msg.sender);
@ -274,6 +321,17 @@ contract LiquidPledgingBase {
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
// are not too many Projects that violate MAX_SUBPROJECT_LEVEL
@ -318,6 +376,13 @@ contract LiquidPledgingBase {
return getOldestNoteNotCanceled(n.oldNote);
}
function checkManagerOwner(NoteManager m) internal constant {
require((msg.sender == m.addr) || (msg.sender == address(m.plugin)));
}
}
//File: contracts/LiquidPledging.sol
@ -348,8 +413,9 @@ contract LiquidPledging is LiquidPledgingBase {
function donate(uint64 idDonor, uint64 idReceiver) payable {// TODO change to `pledge()`
NoteManager storage sender = findManager(idDonor);
checkManagerOwner(sender);
require(sender.managerType == NoteManagerType.Donor);
require(sender.addr == msg.sender);
uint amount = msg.value;
@ -389,7 +455,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage receiver = findManager(idReceiver);
NoteManager storage sender = findManager(idSender);
require(sender.addr == msg.sender);
checkManagerOwner(sender);
require(n.paymentState == PaymentState.NotPaid);
// If the sender is the owner
@ -472,7 +538,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage owner = findManager(n.owner);
require(owner.addr == msg.sender);
checkManagerOwner(owner);
uint64 idNewNote = findNote(
n.owner,
@ -538,10 +604,23 @@ contract LiquidPledging is LiquidPledgingBase {
/// @param idProject Id of the projct that wants to be canceled.
function cancelProject(uint64 idProject) {
NoteManager storage project = findManager(idProject);
require(project.addr == msg.sender);
checkManagerOwner(project);
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
////////
@ -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
///////
@ -613,8 +700,6 @@ contract LiquidPledging is LiquidPledgingBase {
}
function transferOwnershipToDonor(uint64 idNote, uint amount, uint64 idReceiver) internal {
Note storage n = findNote(idNote);
uint64 toNote = findNote(
idReceiver,
new uint64[](0),
@ -670,18 +755,18 @@ contract LiquidPledging is LiquidPledgingBase {
require(getNoteLevel(n) < MAX_SUBPROJECT_LEVEL);
NoteManager storage owner = findManager(n.owner);
uint64 toNote = findNote(
n.owner,
n.delegationChain,
idReceiver,
uint64(getTime() + owner.commitTime),
uint64(getTime() + maxCommitTime(n)),
n.oldNote,
PaymentState.NotPaid);
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 (amount == 0) return;
Note storage nFrom = findNote(from);
@ -691,6 +776,7 @@ contract LiquidPledging is LiquidPledgingBase {
nTo.amount += 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
@ -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)
// #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.
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);
// 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;
}
/////////////
// 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
/////////////

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
pragma solidity ^0.4.11;
contract Vault {
function authorizePayment(bytes32 _ref, address _dest, uint _amount);
function () payable;
@ -24,6 +47,7 @@ contract LiquidPledgingBase {
uint64 commitTime; // Only used in donors and projects, its the precommitment time
uint64 parentProject; // Only for projects
bool canceled; // Only for project
ILiquidPledgingPlugin plugin; // Handler that is called when one call is affected.
}
struct Note {
@ -69,16 +93,20 @@ contract LiquidPledgingBase {
// 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(
NoteManagerType.Donor,
msg.sender,
name,
commitTime,
0,
false));
false,
plugin));
DonorAdded(uint64(managers.length-1));
DonorAdded(idDonor);
}
event DonorAdded(uint64 indexed idDonor);
@ -100,52 +128,71 @@ contract LiquidPledgingBase {
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(
NoteManagerType.Delegate,
msg.sender,
name,
commitTime,
0,
0,
false));
false,
plugin));
DeegateAdded(uint64(managers.length-1));
DeegateAdded(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);
require(delegate.managerType == NoteManagerType.Delegate);
require(delegate.addr == msg.sender);
delegate.addr = newAddr;
delegate.name = newName;
delegate.commitTime = newCommitTime;
DelegateUpdated(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) {
NoteManager storage pm = findManager(parentProject);
require(pm.managerType == NoteManagerType.Project);
require(pm.addr == msg.sender);
require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL);
}
idProject = uint64(managers.length);
managers.push(NoteManager(
NoteManagerType.Project,
projectManager,
name,
commitTime,
parentProject,
false));
false,
plugin));
ProjectAdded(uint64(managers.length-1));
ProjectAdded(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);
require(project.managerType == NoteManagerType.Project);
require(project.addr == msg.sender);
@ -274,6 +321,17 @@ contract LiquidPledgingBase {
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
// are not too many Projects that violate MAX_SUBPROJECT_LEVEL
@ -318,6 +376,13 @@ contract LiquidPledgingBase {
return getOldestNoteNotCanceled(n.oldNote);
}
function checkManagerOwner(NoteManager m) internal constant {
require((msg.sender == m.addr) || (msg.sender == address(m.plugin)));
}
}
//File: ./contracts/LiquidPledging.sol
@ -348,8 +413,9 @@ contract LiquidPledging is LiquidPledgingBase {
function donate(uint64 idDonor, uint64 idReceiver) payable {// TODO change to `pledge()`
NoteManager storage sender = findManager(idDonor);
checkManagerOwner(sender);
require(sender.managerType == NoteManagerType.Donor);
require(sender.addr == msg.sender);
uint amount = msg.value;
@ -389,7 +455,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage receiver = findManager(idReceiver);
NoteManager storage sender = findManager(idSender);
require(sender.addr == msg.sender);
checkManagerOwner(sender);
require(n.paymentState == PaymentState.NotPaid);
// If the sender is the owner
@ -472,7 +538,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage owner = findManager(n.owner);
require(owner.addr == msg.sender);
checkManagerOwner(owner);
uint64 idNewNote = findNote(
n.owner,
@ -538,10 +604,23 @@ contract LiquidPledging is LiquidPledgingBase {
/// @param idProject Id of the projct that wants to be canceled.
function cancelProject(uint64 idProject) {
NoteManager storage project = findManager(idProject);
require(project.addr == msg.sender);
checkManagerOwner(project);
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
////////
@ -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
///////
@ -613,8 +700,6 @@ contract LiquidPledging is LiquidPledgingBase {
}
function transferOwnershipToDonor(uint64 idNote, uint amount, uint64 idReceiver) internal {
Note storage n = findNote(idNote);
uint64 toNote = findNote(
idReceiver,
new uint64[](0),
@ -670,18 +755,18 @@ contract LiquidPledging is LiquidPledgingBase {
require(getNoteLevel(n) < MAX_SUBPROJECT_LEVEL);
NoteManager storage owner = findManager(n.owner);
uint64 toNote = findNote(
n.owner,
n.delegationChain,
idReceiver,
uint64(getTime() + owner.commitTime),
uint64(getTime() + maxCommitTime(n)),
n.oldNote,
PaymentState.NotPaid);
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 (amount == 0) return;
Note storage nFrom = findNote(from);
@ -691,6 +776,7 @@ contract LiquidPledging is LiquidPledgingBase {
nTo.amount += 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
@ -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)
// #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.
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);
// 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;
}
/////////////
// 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
/////////////

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);
checkManagerOwner(sender);
require(sender.managerType == NoteManagerType.Donor);
require(sender.addr == msg.sender);
uint amount = msg.value;
@ -70,7 +71,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage receiver = findManager(idReceiver);
NoteManager storage sender = findManager(idSender);
require(sender.addr == msg.sender);
checkManagerOwner(sender);
require(n.paymentState == PaymentState.NotPaid);
// If the sender is the owner
@ -153,7 +154,7 @@ contract LiquidPledging is LiquidPledgingBase {
NoteManager storage owner = findManager(n.owner);
require(owner.addr == msg.sender);
checkManagerOwner(owner);
uint64 idNewNote = findNote(
n.owner,
@ -219,10 +220,23 @@ contract LiquidPledging is LiquidPledgingBase {
/// @param idProject Id of the projct that wants to be canceled.
function cancelProject(uint64 idProject) {
NoteManager storage project = findManager(idProject);
require(project.addr == msg.sender);
checkManagerOwner(project);
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
////////
@ -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
///////
@ -294,8 +316,6 @@ contract LiquidPledging is LiquidPledgingBase {
}
function transferOwnershipToDonor(uint64 idNote, uint amount, uint64 idReceiver) internal {
Note storage n = findNote(idNote);
uint64 toNote = findNote(
idReceiver,
new uint64[](0),
@ -351,18 +371,18 @@ contract LiquidPledging is LiquidPledgingBase {
require(getNoteLevel(n) < MAX_SUBPROJECT_LEVEL);
NoteManager storage owner = findManager(n.owner);
uint64 toNote = findNote(
n.owner,
n.delegationChain,
idReceiver,
uint64(getTime() + owner.commitTime),
uint64(getTime() + maxCommitTime(n)),
n.oldNote,
PaymentState.NotPaid);
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 (amount == 0) return;
Note storage nFrom = findNote(from);
@ -372,6 +392,7 @@ contract LiquidPledging is LiquidPledgingBase {
nTo.amount += 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
@ -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)
// #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.
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);
// 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;
}
/////////////
// 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
/////////////

View File

@ -1,5 +1,7 @@
pragma solidity ^0.4.11;
import "./ILiquidPledgingPlugin.sol";
contract Vault {
function authorizePayment(bytes32 _ref, address _dest, uint _amount);
function () payable;
@ -22,6 +24,7 @@ contract LiquidPledgingBase {
uint64 commitTime; // Only used in donors and projects, its the precommitment time
uint64 parentProject; // Only for projects
bool canceled; // Only for project
ILiquidPledgingPlugin plugin; // Handler that is called when one call is affected.
}
struct Note {
@ -67,18 +70,20 @@ contract LiquidPledgingBase {
// 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(
NoteManagerType.Donor,
msg.sender,
name,
commitTime,
0,
false));
false,
plugin));
idManager = uint64(managers.length-1);
DonorAdded(idManager);
DonorAdded(idDonor);
}
event DonorAdded(uint64 indexed idDonor);
@ -100,52 +105,71 @@ contract LiquidPledgingBase {
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(
NoteManagerType.Delegate,
msg.sender,
name,
commitTime,
0,
0,
false));
false,
plugin));
DelegateAdded(uint64(managers.length-1));
DelegateAdded(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);
require(delegate.managerType == NoteManagerType.Delegate);
require(delegate.addr == msg.sender);
delegate.addr = newAddr;
delegate.name = newName;
delegate.commitTime = newCommitTime;
DelegateUpdated(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) {
NoteManager storage pm = findManager(parentProject);
require(pm.managerType == NoteManagerType.Project);
require(pm.addr == msg.sender);
require(getProjectLevel(pm) < MAX_SUBPROJECT_LEVEL);
}
idProject = uint64(managers.length);
managers.push(NoteManager(
NoteManagerType.Project,
projectManager,
name,
commitTime,
parentProject,
false));
false,
plugin));
ProjectAdded(uint64(managers.length-1));
ProjectAdded(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);
require(project.managerType == NoteManagerType.Project);
require(project.addr == msg.sender);
@ -274,6 +298,17 @@ contract LiquidPledgingBase {
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
// are not too many Projects that violate MAX_SUBPROJECT_LEVEL
@ -318,4 +353,11 @@ contract LiquidPledgingBase {
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;
/// @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() {
owner = msg.sender;
}
@ -22,13 +23,16 @@ contract Owned {
address public newOwner;
/// @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
/// an unowned neutral vault, however that cannot be undone
/// but after this function is called the current owner still has ownership
/// 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 {
newOwner = _newOwner;
}
/// @notice `newOwner` can accept ownership over this contract
function acceptOwnership() {
if (msg.sender == newOwner) {
owner = newOwner;

18
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "liquidpledging",
"version": "0.0.1",
"version": "0.0.5",
"lockfileVersion": 1,
"requires": true,
"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": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
@ -3623,6 +3615,14 @@
"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": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",

View File

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

View File

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