Contracts Done Not tested

This commit is contained in:
Jordi Baylina 2017-06-06 19:40:14 +02:00
commit 3f6c3ad398
4 changed files with 677 additions and 0 deletions

2
README.md Normal file
View File

@ -0,0 +1,2 @@
# Liquid Pledging

View File

@ -0,0 +1,66 @@
pragma solidity ^0.4.11;
contract ILiquidPledging {
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 numberOfManagers() constant returns(uint);
function getNoteManager(uint64 idManager) constant returns (
NoteManagerType managerType,
address addr,
string name,
uint64 commitTime,
address reviewer,
bool canceled);
function addDonor(string name, uint commitTime);
function updateDonor(uint64 idDonor, address newAddr, string newName, uint newCommitTime);
function addDelegate(string name);
function updateDelegate(uint64 idDelegate, address newAddr, string newName);
function addProject(string name, address canceler, uint commitTime) ;
function updateProject(uint64 idProject, address newAddr, string newName, uint 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,336 @@
pragma solidity ^0.4.11;
import "./LiquidPledgingBase.sol";
contract LiquidPledging is LiquidPledgingBase {
//////
// Constructor
//////
function LiquidPledging(address _vault) LiquidPledgingBase(_vault) {
}
function donate(uint64 idDonor, uint64 idReceiver) payable {
NoteManager sender = findManager(idDonor);
if (sender.managerType != NoteManagerType.Donor) throw;
if (sender.addr != msg.sender) throw;
uint amount = msg.value;
if (amount == 0) throw;
vault.transfer(amount);
uint64 idNote = findNote(
idDonor,
new uint64[](0),
0,
0,
0,
PaymentState.NotPaid);
doTransfer(0, idNote, amount);
transfer(idDonor, idNote, amount, idReceiver);
}
function transfer(uint64 idSender, uint64 idNote, uint amount, uint64 idReceiver) {
idNote = normalizeNote(idNote);
Note n = findNote(idNote);
NoteManager receiver = findManager(idReceiver);
NoteManager sender = findManager(idSender);
if (sender.addr != msg.sender) throw;
if (n.paymentState != PaymentState.NotPaid) throw;
// If the sender is the owner
if (n.owner == idSender) {
if ((receiver.managerType == NoteManagerType.Donor) ||
(receiver.managerType == NoteManagerType.Project)) {
transferOwnership(idNote, amount, idReceiver);
} else if (receiver.managerType == NoteManagerType.Delegate) {
appendDelegate(idNote, amount, idReceiver);
} else {
throw;
}
return;
}
// If the sender is a delegate
uint senderDIdx = getDelegateIdx(n, idSender);
if (senderDIdx != NOTFOUND) {
// If the receiver is another doner
if (receiver.managerType == NoteManagerType.Donor) {
// Only accept to change to the original donor to remove all delegates
if (n.owner == idReceiver) {
undelegate(idNote, amount, n.delegationChain.length);
} else {
throw;
}
return;
}
// If the receiver is another delegate
if (receiver.managerType == NoteManagerType.Delegate) {
uint receiverDIdx = getDelegateIdx(n, idReceiver);
// If the receiver is not in the delegate list
if (receiverDIdx == NOTFOUND) {
undelegate(idNote, amount, n.delegationChain.length - senderDIdx - 1);
appendDelegate(idNote, amount, idReceiver);
// If the receiver is after the delegate list and is not the next one.
// Canccel delegations an redelegate
} else if (receiverDIdx > senderDIdx) {
undelegate(idNote, amount, n.delegationChain.length - senderDIdx - 1);
appendDelegate(idNote, amount, idReceiver);
// If it's before the list cancel thelegations until him
} else if (receiverDIdx <= senderDIdx) {
undelegate(idNote, amount, n.delegationChain.length - receiverDIdx -1);
}
return;
}
// If the delegate chose a project to assign
if (receiver.managerType == NoteManagerType.Project) {
undelegate(idNote, amount, n.delegationChain.length - senderDIdx - 1);
proposeAssignProject(idNote, amount, idReceiver);
return;
}
}
throw; // It is not the owner nor any delegate.
}
function withdraw(uint64 idNote, uint amount) {
idNote = normalizeNote(idNote);
Note n = findNote(idNote);
if (n.paymentState != PaymentState.NotPaid) throw;
NoteManager owner = findManager(n.owner);
if (owner.addr != msg.sender) throw;
uint64 idNewNote = findNote(
n.owner,
n.delegationChain,
0,
0,
idNote,
PaymentState.Paying
);
doTransfer(idNote, idNewNote, amount);
vault.authorizePayment(bytes32(idNewNote), owner.addr, amount);
}
function confirmPayment(uint64 idNote, uint amount) onlyVault {
Note n = findNote(idNote);
if (n.paymentState != PaymentState.Paying) throw;
if (isProjectCanceled(n.owner)) throw;
uint64 idNewNote = findNote(
n.owner,
n.delegationChain,
0,
0,
idNote,
PaymentState.Paid
);
doTransfer(idNote, idNewNote, amount);
}
function cancelPayment(uint64 idNote, uint amount) onlyVault {
Note n = findNote(idNote);
if (n.paymentState != PaymentState.Paying) throw;
// When a payment is cacnceled, never is assigned to a project.
uint64 oldNote = findNote(
n.owner,
n.delegationChain,
0,
0,
idNote,
PaymentState.NotPaid
);
oldNote = normalizeNote(oldNote);
doTransfer(idNote, oldNote, amount);
}
function cancelProject(uint64 idProject) {
NoteManager project = findManager(idProject);
if ( (project.reviewer != msg.sender)
&&(project.addr != msg.sender))
throw;
project.canceled = true;
}
////////
// Multi note methods
////////
uint constant D64 = 0x10000000000000000;
function mTransfer(uint64 idSender, uint[] notesAmounts, uint64 idReceiver) {
for (uint i = 0; i < notesAmounts.length; i++ ) {
uint64 idNote = uint64( notesAmounts[i] & (D64-1) );
uint amount = notesAmounts[i] / D64;
transfer(idSender, idNote, amount, idReceiver);
}
}
function mWithdraw(uint[] notesAmounts) {
for (uint i = 0; i < notesAmounts.length; i++ ) {
uint64 idNote = uint64( notesAmounts[i] & (D64-1) );
uint amount = notesAmounts[i] / D64;
withdraw(idNote, amount);
}
}
function mConfirmPayment(uint[] notesAmounts) {
for (uint i = 0; i < notesAmounts.length; i++ ) {
uint64 idNote = uint64( notesAmounts[i] & (D64-1) );
uint amount = notesAmounts[i] / D64;
confirmPayment(idNote, amount);
}
}
function mCancelPayment(uint[] notesAmounts) {
for (uint i = 0; i < notesAmounts.length; i++ ) {
uint64 idNote = uint64( notesAmounts[i] & (D64-1) );
uint amount = notesAmounts[i] / D64;
cancelPayment(idNote, amount);
}
}
////////
// Private methods
///////
function transferOwnership(uint64 idNote, uint amount, uint64 idReceiver) internal {
Note n = findNote(idNote);
uint64 oldNote = findNote(
n.owner,
n.delegationChain,
0,
0,
n.oldNote,
PaymentState.NotPaid);
uint64 toNote = findNote(
idReceiver,
new uint64[](0),
0,
0,
oldNote,
PaymentState.NotPaid);
doTransfer(idNote, toNote, amount);
}
function appendDelegate(uint64 idNote, uint amount, uint64 idReceiver) internal {
Note n = findNote(idNote);
uint64[] memory newDelegationChain = new uint64[](n.delegationChain.length + 1);
for (uint i=0; i<n.delegationChain.length; i++) {
newDelegationChain[i] = n.delegationChain[i];
}
newDelegationChain[n.delegationChain.length] = idReceiver;
uint64 toNote = findNote(
n.owner,
newDelegationChain,
0,
0,
n.oldNote,
PaymentState.NotPaid);
doTransfer(idNote, toNote, amount);
}
/// @param q Unmber of undelegations
function undelegate(uint64 idNote, uint amount, uint q) internal {
Note n = findNote(idNote);
uint64[] memory newDelegationChain = new uint64[](n.delegationChain.length - q);
for (uint i=0; i<n.delegationChain.length - q; i++) {
newDelegationChain[i] = n.delegationChain[i];
}
uint64 toNote = findNote(
n.owner,
newDelegationChain,
0,
0,
n.oldNote,
PaymentState.NotPaid);
doTransfer(idNote, toNote, amount);
}
function proposeAssignProject(uint64 idNote, uint amount, uint64 idReceiver) internal {
Note n = findNote(idNote);
NoteManager owner = findManager(n.owner);
uint64 toNote = findNote(
n.owner,
n.delegationChain,
idReceiver,
uint64(now + owner.commitTime),
n.oldNote,
PaymentState.NotPaid);
doTransfer(idNote, toNote, amount);
}
function doTransfer(uint64 from, uint64 to, uint amount) internal {
Note nFrom = findNote(from);
Note nTo = findNote(to);
if (nFrom.amount < amount) throw;
nFrom.amount -= amount;
nTo.amount += amount;
Transfer(from, to, amount);
}
function normalizeNote(uint64 idNote) internal returns(uint64) {
Note n = findNote(idNote);
if (n.paymentState != PaymentState.NotPaid) return idNote;
// First send to a project if it's proposed and commited
if ((n.proposedProject > 0) && ( now > n.commmitTime)) {
uint64 oldNote = findNote(
n.owner,
n.delegationChain,
0,
0,
n.oldNote,
PaymentState.NotPaid);
uint64 toNote = findNote(
n.proposedProject,
new uint64[](0),
0,
0,
oldNote,
PaymentState.NotPaid);
doTransfer(idNote, toNote, n.amount);
}
toNote = getOldestNoteNotCanceled(idNote);
if (toNote != idNote) {
doTransfer(idNote, toNote, n.amount);
}
}
event Transfer(uint64 indexed from, uint64 indexed to, uint amount);
}

View File

@ -0,0 +1,273 @@
pragma solidity ^0.4.11;
import "./ILiquidPledging.sol";
contract Vault {
function authorizePayment(bytes32 ref, address dest, uint amount);
}
contract LiquidPledgingBase is ILiquidPledging {
struct NoteManager {
NoteManagerType managerType;
address addr;
string name;
uint64 commitTime; // Only used in donors and campaigns
address reviewer; // Only for project
bool canceled; // Only for project
}
struct Note {
uint amount;
uint64 owner;
uint64[] delegationChain;
uint64 proposedProject;
uint64 commmitTime; // At what time the upcoming time will become an owner.
uint64 oldNote;
PaymentState paymentState;
}
Note[] notes;
NoteManager[] managers;
Vault public vault;
mapping (bytes32 => uint64) hNote2ddx;
/////
// Modifiers
/////
modifier onlyVault() {
if (msg.sender != address(vault)) throw;
_;
}
//////
// Constructor
//////
function LiquidPledgingBase(address _vault) {
managers.length = 1;
notes.length = 1;
vault = Vault(_vault);
}
///////
// Managers functions
//////
function addDonor(string name, uint64 commitTime) {
managers.push(NoteManager(
NoteManagerType.Donor,
msg.sender,
name,
commitTime,
0x0,
false));
DonorAdded(uint64(managers.length-1));
}
event DonorAdded(uint64 indexed idMember);
function updateDonor(
uint64 idDonor,
address newAddr,
string newName,
uint64 newCommitTime)
{
NoteManager donor = findManager(idDonor);
if (donor.managerType != NoteManagerType.Donor) throw;
if (donor.addr != msg.sender) throw;
donor.addr = newAddr;
donor.name = newName;
donor.commitTime = newCommitTime;
DonorUpdated(idDonor);
}
event DonorUpdated(uint64 indexed idMember);
function addDelegate(string name) {
managers.push(NoteManager(
NoteManagerType.Delegate,
msg.sender,
name,
0,
0x0,
false));
DeegateAdded(uint64(managers.length-1));
}
event DeegateAdded(uint64 indexed idMember);
function updateDelegate(uint64 idDelegate, address newAddr, string newName) {
NoteManager delegate = findManager(idDelegate);
if (delegate.managerType != NoteManagerType.Delegate) throw;
if (delegate.addr != msg.sender) throw;
delegate.addr = newAddr;
delegate.name = newName;
DelegateUpdated(idDelegate);
}
event DelegateUpdated(uint64 indexed idMember);
function addProject(string name, address reviewer, uint64 commitTime) {
managers.push(NoteManager(
NoteManagerType.Project,
msg.sender,
name,
commitTime,
reviewer,
false));
ProjectAdded(uint64(managers.length-1));
}
event ProjectAdded(uint64 indexed idMember);
function updateProject(uint64 idProject, address newAddr, string newName, uint64 newCommitTime) {
NoteManager project = findManager(idProject);
if (project.managerType != NoteManagerType.Project) throw;
if (project.addr != msg.sender) throw;
project.addr = newAddr;
project.name = newName;
project.commitTime = newCommitTime;
ProjectUpdated(idProject);
}
function updateProjectCanceler(uint64 idProject, address newReviewer) {
NoteManager project = findManager(idProject);
if (project.managerType != NoteManagerType.Project) throw;
if (project.reviewer != msg.sender) throw;
project.reviewer = newReviewer;
ProjectUpdated(idProject);
}
event ProjectUpdated(uint64 indexed idMember);
//////////
// Public constant functions
//////////
function numberOfNotes() constant returns (uint) {
return notes.length - 1;
}
function getNote(uint64 idNote) constant returns(
uint amount,
uint64 owner,
uint64 nDelegates,
uint64 proposedProject,
uint64 commmitTime,
uint64 oldNote,
PaymentState paymentState
) {
Note n = findNote(idNote);
amount = n.amount;
owner = n.owner;
nDelegates = uint64(n.delegationChain.length);
proposedProject = n.proposedProject;
commmitTime = n.commmitTime;
oldNote = n.oldNote;
paymentState = n.paymentState;
}
function getNoteDelegate(uint64 idNote, uint idxDelegate) constant returns(
uint64 idDelegate,
address addr,
string name
) {
Note n = findNote(idNote);
idDelegate = n.delegationChain[idxDelegate];
NoteManager delegate = findManager(idDelegate);
addr = delegate.addr;
name = delegate.name;
}
function numberOfManagers() constant returns(uint) {
return managers.length - 1;
}
function getNoteManager(uint64 idManager) constant returns (
NoteManagerType managerType,
address addr,
string name,
uint64 commitTime,
address reviewer,
bool canceled)
{
NoteManager m = findManager(idManager);
managerType = m.managerType;
addr = m.addr;
name = m.name;
commitTime = m.commitTime;
reviewer = m.reviewer;
canceled = m.canceled;
}
////////
// Private methods
///////
function findNote(
uint64 owner,
uint64[] delegationChain,
uint64 proposedProject,
uint64 commmitTime,
uint64 oldNote,
PaymentState paid
) internal returns (uint64)
{
bytes32 hNote = sha3(owner, delegationChain, proposedProject, commmitTime, oldNote, paid);
uint64 idx = hNote2ddx[hNote];
if (idx > 0) return idx;
idx = uint64(notes.length);
notes.push(Note(0, owner, delegationChain, proposedProject, commmitTime, oldNote, paid));
return idx;
}
function findManager(uint64 idManager) internal returns (NoteManager storage) {
if (idManager >= managers.length) throw;
return managers[idManager];
}
function findNote(uint64 idNote) internal returns (Note storage) {
if (idNote >= notes.length) throw;
return notes[idNote];
}
function getOldestNoteNotCanceled(uint64 idProject) internal constant returns(uint64) {
if (idProject == 0) return 0;
Note n = findNote(idProject);
NoteManager owner = findManager(n.owner);
if (owner.managerType == NoteManagerType.Donor) return idProject;
uint64 parentProject = getOldestNoteNotCanceled(n.oldNote);
if (parentProject == n.oldNote) {
return idProject;
} else {
return parentProject;
}
}
function isProjectCanceled(uint64 idProject) internal constant returns(bool){
uint parentProject = getOldestNoteNotCanceled(idProject);
return (parentProject != idProject);
}
uint64 constant NOTFOUND = 0xFFFFFFFFFFFFFFFF;
function getDelegateIdx(Note n, uint64 idDelegate) internal returns(uint64) {
for (uint i=0; i<n.delegationChain.length; i++) {
if (n.delegationChain[i] == idDelegate) return uint64(i);
}
return NOTFOUND;
}
}