Merge remote-tracking branch 'upstream/master' into add_donor_on_donate
This commit is contained in:
commit
cea412426d
|
@ -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"
|
|
@ -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
|
@ -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
|
@ -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
|
||||
/////////////
|
||||
|
|
|
@ -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
|
||||
/////////////
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
/////////////
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "liquidpledging",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.7",
|
||||
"description": "Liquid Pledging Smart Contract",
|
||||
"main": "index.js",
|
||||
"directories": {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue