refactor PledgeAdmins to lib w/ EternalStorage
This commit is contained in:
parent
80a8e5a9b4
commit
80b8ffc2ef
|
@ -0,0 +1,92 @@
|
||||||
|
pragma solidity ^0.4.0;
|
||||||
|
|
||||||
|
// change to Escapable
|
||||||
|
import "node_modules/giveth-common-contracts/contracts/Owned.sol";
|
||||||
|
|
||||||
|
contract EternalStorage is Owned {
|
||||||
|
|
||||||
|
mapping(bytes32 => uint) UIntStorage;
|
||||||
|
mapping(bytes32 => int) IntStorage;
|
||||||
|
mapping(bytes32 => bool) BooleanStorage;
|
||||||
|
mapping(bytes32 => address) AddressStorage;
|
||||||
|
mapping(bytes32 => string) StringStorage;
|
||||||
|
mapping(bytes32 => bytes) BytesStorage;
|
||||||
|
mapping(bytes32 => bytes32) Bytes32Storage;
|
||||||
|
|
||||||
|
/// UInt Storage
|
||||||
|
|
||||||
|
function getUIntValue(bytes32 record) public view returns (uint) {
|
||||||
|
return UIntStorage[record];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setUIntValue(bytes32 record, uint value) public onlyOwner
|
||||||
|
{
|
||||||
|
UIntStorage[record] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Int Storage
|
||||||
|
|
||||||
|
function getIntValue(bytes32 record) public view returns (int){
|
||||||
|
return IntStorage[record];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setIntValue(bytes32 record, int value) public onlyOwner
|
||||||
|
{
|
||||||
|
IntStorage[record] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Address Storage
|
||||||
|
|
||||||
|
function getAddressValue(bytes32 record) public view returns (address){
|
||||||
|
return AddressStorage[record];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setAddressValue(bytes32 record, address value) public onlyOwner
|
||||||
|
{
|
||||||
|
AddressStorage[record] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// String Storage
|
||||||
|
|
||||||
|
function getStringValue(bytes32 record) public view returns (string){
|
||||||
|
return StringStorage[record];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStringValue(bytes32 record, string value) public onlyOwner
|
||||||
|
{
|
||||||
|
StringStorage[record] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bytes Storage
|
||||||
|
|
||||||
|
function getBytesValue(bytes32 record) public view returns (bytes){
|
||||||
|
return BytesStorage[record];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBytesValue(bytes32 record, bytes value) public onlyOwner
|
||||||
|
{
|
||||||
|
BytesStorage[record] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bytes Storage
|
||||||
|
|
||||||
|
function getBytes32Value(bytes32 record) public view returns (bytes32){
|
||||||
|
return Bytes32Storage[record];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBytes32Value(bytes32 record, bytes32 value) public onlyOwner
|
||||||
|
{
|
||||||
|
Bytes32Storage[record] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Boolean Storage
|
||||||
|
|
||||||
|
function getBooleanValue(bytes32 record) public view returns (bool){
|
||||||
|
return BooleanStorage[record];
|
||||||
|
}
|
||||||
|
|
||||||
|
function setBooleanValue(bytes32 record, bool value) public onlyOwner
|
||||||
|
{
|
||||||
|
BooleanStorage[record] = value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
pragma solidity ^0.4.0;
|
||||||
|
|
||||||
|
import "./EternalStorage.sol";
|
||||||
|
|
||||||
|
library EternallyPersistentLib {
|
||||||
|
|
||||||
|
// UInt
|
||||||
|
|
||||||
|
function stgObjectGetUInt(EternalStorage _storage, string class, uint id, string fieldName) public view returns (uint) {
|
||||||
|
bytes32 record = keccak256(class, id, fieldName);
|
||||||
|
return _storage.getUIntValue(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stgObjectSetUInt(EternalStorage _storage, string class, uint id, string fieldName, uint value) internal {
|
||||||
|
bytes32 record = keccak256(class, id, fieldName);
|
||||||
|
return _storage.setUIntValue(record, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boolean
|
||||||
|
|
||||||
|
function stgObjectGetBoolean(EternalStorage _storage, string class, uint id, string fieldName) public view returns (bool) {
|
||||||
|
bytes32 record = keccak256(class, id, fieldName);
|
||||||
|
return _storage.getBooleanValue(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stgObjectSetBoolean(EternalStorage _storage, string class, uint id, string fieldName, bool value) internal {
|
||||||
|
bytes32 record = keccak256(class, id, fieldName);
|
||||||
|
return _storage.setBooleanValue(record, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// string
|
||||||
|
|
||||||
|
function stgObjectGetString(EternalStorage _storage, string class, uint id, string fieldName) internal view returns (string) {
|
||||||
|
bytes32 record = keccak256(class, id, fieldName);
|
||||||
|
bytes4 sig = bytes4(keccak256("getStringValue(bytes32)"));
|
||||||
|
//Function signature
|
||||||
|
address a = address(_storage);
|
||||||
|
string memory s;
|
||||||
|
|
||||||
|
assembly {
|
||||||
|
let x := mload(0x40) //Find empty storage location using "free memory pointer"
|
||||||
|
mstore(x, sig) //Place signature at begining of empty storage
|
||||||
|
mstore(add(x, 0x04), record) //Place first argument directly next to signature
|
||||||
|
|
||||||
|
let success := call(//This is the critical change (Pop the top stack value)
|
||||||
|
5000, //5k gas
|
||||||
|
a, //To addr
|
||||||
|
0, //No value
|
||||||
|
x, //Inputs are stored at location x
|
||||||
|
0x24, //Inputs are 36 byes long
|
||||||
|
x, //Store output over input (saves space)
|
||||||
|
0x80) //Outputs are 32 bytes long
|
||||||
|
|
||||||
|
let strL := mload(add(x, 0x20)) // Load the length of the sring
|
||||||
|
|
||||||
|
jumpi(ask_more, gt(strL, 64))
|
||||||
|
|
||||||
|
mstore(0x40, add(x, add(strL, 0x40)))
|
||||||
|
|
||||||
|
s := add(x, 0x20)
|
||||||
|
// return(x, add(strL, 0x40))
|
||||||
|
ask_more :
|
||||||
|
mstore(x, sig) //Place signature at begining of empty storage
|
||||||
|
mstore(add(x, 0x04), record) //Place first argument directly next to signature
|
||||||
|
|
||||||
|
success := call(//This is the critical change (Pop the top stack value)
|
||||||
|
5000, //5k gas
|
||||||
|
a, //To addr
|
||||||
|
0, //No value
|
||||||
|
x, //Inputs are stored at location x
|
||||||
|
0x24, //Inputs are 36 byes long
|
||||||
|
x, //Store output over input (saves space)
|
||||||
|
add(0x40, strL)) //Outputs are 32 bytes long
|
||||||
|
|
||||||
|
mstore(0x40, add(x, add(strL, 0x40)))
|
||||||
|
s := add(x, 0x20)
|
||||||
|
|
||||||
|
// return(x, add(strL, 0x40))
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stgObjectSetString(EternalStorage _storage, string class, uint id, string fieldName, string value) internal {
|
||||||
|
bytes32 record = keccak256(class, id, fieldName);
|
||||||
|
return _storage.setStringValue(record, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// address
|
||||||
|
|
||||||
|
function stgObjectGetAddress(EternalStorage _storage, string class, uint id, string fieldName) public view returns (address) {
|
||||||
|
bytes32 record = keccak256(class, id, fieldName);
|
||||||
|
return _storage.getAddressValue(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stgObjectSetAddress(EternalStorage _storage, string class, uint id, string fieldName, address value) internal {
|
||||||
|
bytes32 record = keccak256(class, id, fieldName);
|
||||||
|
return _storage.setAddressValue(record, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bytes32
|
||||||
|
|
||||||
|
function stgObjectGetBytes32(EternalStorage _storage, string class, uint id, string fieldName) public view returns (bytes32) {
|
||||||
|
bytes32 record = keccak256(class, id, fieldName);
|
||||||
|
return _storage.getBytes32Value(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stgObjectSetBytes32(EternalStorage _storage, string class, uint id, string fieldName, bytes32 value) internal {
|
||||||
|
bytes32 record = keccak256(class, id, fieldName);
|
||||||
|
return _storage.setBytes32Value(record, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array
|
||||||
|
|
||||||
|
// function stgCollectionAddItem(bytes32 idArray, bytes32 idItem) internal returns (uint64) {
|
||||||
|
function stgCollectionAddItem(EternalStorage _storage, bytes32 idArray) internal returns (uint) {
|
||||||
|
|
||||||
|
uint length = _storage.getUIntValue(keccak256(idArray, "length"));
|
||||||
|
|
||||||
|
|
||||||
|
// Set the position in the array as a field so it can be deleted
|
||||||
|
// _storage.setUIntValue(keccak256(idArray, idItem, "_idx"), length);
|
||||||
|
|
||||||
|
// Add the object to the array
|
||||||
|
// _storage.setBytes32Value(keccak256(idArray, length), idItem);
|
||||||
|
|
||||||
|
|
||||||
|
// Increment the size of the array
|
||||||
|
length++;
|
||||||
|
_storage.setUIntValue(keccak256(idArray, "length"), length);
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// function stgCollectionRemoveItem(EternalStorage _storage, bytes32 idArray, bytes32 idItem) internal {
|
||||||
|
// uint idx = _storage.getUIntValue(keccak256(idArray, idItem, "_idx"));
|
||||||
|
//
|
||||||
|
// uint length = _storage.getUIntValue(keccak256(idArray, "length"));
|
||||||
|
// length --;
|
||||||
|
//
|
||||||
|
// // Move the last element ot the array to this place
|
||||||
|
// bytes32 lastId = _storage.getBytes32Value(keccak256(idArray, length));
|
||||||
|
// _storage.setBytes32Value(keccak256(idArray, idx), lastId);
|
||||||
|
// _storage.setUIntValue(keccak256(idArray, lastId, "_idx"), idx);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// // Decrement the length
|
||||||
|
// _storage.setUIntValue(keccak256(idArray, "length"), length);
|
||||||
|
//
|
||||||
|
// // Cleanup the last element of the array
|
||||||
|
// _storage.setBytes32Value(keccak256(idArray, length), 0);
|
||||||
|
//
|
||||||
|
// _storage.setUIntValue(keccak256(idArray, idItem, "_idx"), 0);
|
||||||
|
// }
|
||||||
|
|
||||||
|
function stgCollectionLength(EternalStorage _storage, bytes32 idArray) public view returns (uint) {
|
||||||
|
return _storage.getUIntValue(keccak256(idArray, "length"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function stgCollectionIdFromIdx(EternalStorage _storage, bytes32 idArray, uint idx) public view returns (bytes32) {
|
||||||
|
return _storage.getBytes32Value(keccak256(idArray, idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// bytes32 lastId;
|
||||||
|
|
||||||
|
// function stgGetNewId() internal returns (bytes32) {
|
||||||
|
// lastId = keccak256(lastId, now);
|
||||||
|
// return lastId;
|
||||||
|
// }
|
||||||
|
|
||||||
|
function stgUpgrade(EternalStorage _storage, address newContract) internal {
|
||||||
|
_storage.changeOwnership(newContract);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -38,13 +38,15 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// for `LiquidPledgingBase`
|
/// for `LiquidPledgingBase`
|
||||||
/// @param _vault The vault where ETH backing this pledge is stored
|
/// @param _vault The vault where ETH backing this pledge is stored
|
||||||
function LiquidPledging(
|
function LiquidPledging(
|
||||||
|
address _storage,
|
||||||
address _vault,
|
address _vault,
|
||||||
address _escapeHatchCaller,
|
address _escapeHatchCaller,
|
||||||
address _escapeHatchDestination
|
address _escapeHatchDestination
|
||||||
) LiquidPledgingBase(_vault, _escapeHatchCaller, _escapeHatchDestination) public {
|
) LiquidPledgingBase(_storage, _vault, _escapeHatchCaller, _escapeHatchDestination) public
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
event Name(string name);
|
||||||
/// @notice This is how value enters the system and how pledges are created;
|
/// @notice This is how value enters the system and how pledges are created;
|
||||||
/// the ether is sent to the vault, an pledge for the Giver is created (or
|
/// the ether is sent to the vault, an pledge for the Giver is created (or
|
||||||
/// found), the amount of ETH donated in wei is added to the `amount` in
|
/// found), the amount of ETH donated in wei is added to the `amount` in
|
||||||
|
@ -57,15 +59,23 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
if (idGiver == 0) {
|
if (idGiver == 0) {
|
||||||
|
|
||||||
// default to a 3 day (259200 seconds) commitTime
|
// default to a 3 day (259200 seconds) commitTime
|
||||||
idGiver = addGiver("", "", 259200, ILiquidPledgingPlugin(0x0));
|
idGiver = uint64(addGiver("", "", 259200, ILiquidPledgingPlugin(0x0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
PledgeAdmin storage sender = findAdmin(idGiver);
|
checkAdminOwner(idGiver);
|
||||||
checkAdminOwner(sender);
|
|
||||||
require(sender.adminType == PledgeAdminType.Giver);
|
PledgeAdmins.PledgeAdminType adminType = _storage.getAdminType(idGiver);
|
||||||
|
require(adminType == PledgeAdmins.PledgeAdminType.Giver);
|
||||||
|
|
||||||
|
Gas(msg.gas);
|
||||||
|
_storage.getAdmin(idGiver);
|
||||||
|
Gas(msg.gas);
|
||||||
|
return;
|
||||||
|
|
||||||
uint amount = msg.value;
|
uint amount = msg.value;
|
||||||
require(amount > 0);
|
require(amount > 0);
|
||||||
vault.transfer(amount); // Sends the `msg.value` (in wei) to the `vault`
|
vault.transfer(amount); // Sends the `msg.value` (in wei) to the `vault`
|
||||||
|
|
||||||
uint64 idPledge = findOrCreatePledge(
|
uint64 idPledge = findOrCreatePledge(
|
||||||
idGiver,
|
idGiver,
|
||||||
new uint64[](0), // Creates empty array for delegationChain
|
new uint64[](0), // Creates empty array for delegationChain
|
||||||
|
@ -99,24 +109,23 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
uint amount,
|
uint amount,
|
||||||
uint64 idReceiver
|
uint64 idReceiver
|
||||||
) public {
|
) public {
|
||||||
|
checkAdminOwner(idSender);
|
||||||
|
|
||||||
idPledge = normalizePledge(idPledge);
|
idPledge = normalizePledge(idPledge);
|
||||||
|
|
||||||
Pledge storage p = findPledge(idPledge);
|
Pledge storage p = findPledge(idPledge);
|
||||||
PledgeAdmin storage receiver = findAdmin(idReceiver);
|
PledgeAdmins.PledgeAdminType receiverAdminType = _storage.getAdminType(idReceiver);
|
||||||
PledgeAdmin storage sender = findAdmin(idSender);
|
|
||||||
|
|
||||||
checkAdminOwner(sender);
|
|
||||||
require(p.pledgeState == PledgeState.Pledged);
|
require(p.pledgeState == PledgeState.Pledged);
|
||||||
|
|
||||||
// If the sender is the owner of the Pledge
|
// If the sender is the owner of the Pledge
|
||||||
if (p.owner == idSender) {
|
if (p.owner == idSender) {
|
||||||
|
|
||||||
if (receiver.adminType == PledgeAdminType.Giver) {
|
if (receiverAdminType == PledgeAdmins.PledgeAdminType.Giver) {
|
||||||
transferOwnershipToGiver(idPledge, amount, idReceiver);
|
transferOwnershipToGiver(idPledge, amount, idReceiver);
|
||||||
} else if (receiver.adminType == PledgeAdminType.Project) {
|
} else if (receiverAdminType == PledgeAdmins.PledgeAdminType.Project) {
|
||||||
transferOwnershipToProject(idPledge, amount, idReceiver);
|
transferOwnershipToProject(idPledge, amount, idReceiver);
|
||||||
} else if (receiver.adminType == PledgeAdminType.Delegate) {
|
} else if (receiverAdminType == PledgeAdmins.PledgeAdminType.Delegate) {
|
||||||
|
|
||||||
uint recieverDIdx = getDelegateIdx(p, idReceiver);
|
uint recieverDIdx = getDelegateIdx(p, idReceiver);
|
||||||
if (p.intendedProject > 0 && recieverDIdx != NOTFOUND) {
|
if (p.intendedProject > 0 && recieverDIdx != NOTFOUND) {
|
||||||
|
@ -160,7 +169,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
if (senderDIdx != NOTFOUND) {
|
if (senderDIdx != NOTFOUND) {
|
||||||
|
|
||||||
// And the receiver is another Giver
|
// And the receiver is another Giver
|
||||||
if (receiver.adminType == PledgeAdminType.Giver) {
|
if (receiverAdminType == PledgeAdmins.PledgeAdminType.Giver) {
|
||||||
// Only transfer to the Giver who owns the pldege
|
// Only transfer to the Giver who owns the pldege
|
||||||
assert(p.owner == idReceiver);
|
assert(p.owner == idReceiver);
|
||||||
undelegate(idPledge, amount, p.delegationChain.length);
|
undelegate(idPledge, amount, p.delegationChain.length);
|
||||||
|
@ -168,7 +177,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// And the receiver is another Delegate
|
// And the receiver is another Delegate
|
||||||
if (receiver.adminType == PledgeAdminType.Delegate) {
|
if (receiverAdminType == PledgeAdmins.PledgeAdminType.Delegate) {
|
||||||
uint receiverDIdx = getDelegateIdx(p, idReceiver);
|
uint receiverDIdx = getDelegateIdx(p, idReceiver);
|
||||||
|
|
||||||
// And not in the delegationChain
|
// And not in the delegationChain
|
||||||
|
@ -206,7 +215,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
|
|
||||||
// And the receiver is a Project, all the delegates after the sender
|
// And the receiver is a Project, all the delegates after the sender
|
||||||
// are removed and the amount is pre-committed to the project
|
// are removed and the amount is pre-committed to the project
|
||||||
if (receiver.adminType == PledgeAdminType.Project) {
|
if (receiverAdminType == PledgeAdmins.PledgeAdminType.Project) {
|
||||||
idPledge = undelegate(
|
idPledge = undelegate(
|
||||||
idPledge,
|
idPledge,
|
||||||
amount,
|
amount,
|
||||||
|
@ -228,8 +237,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
idPledge = normalizePledge(idPledge); // Updates pledge info
|
idPledge = normalizePledge(idPledge); // Updates pledge info
|
||||||
Pledge storage p = findPledge(idPledge);
|
Pledge storage p = findPledge(idPledge);
|
||||||
require(p.pledgeState == PledgeState.Pledged);
|
require(p.pledgeState == PledgeState.Pledged);
|
||||||
PledgeAdmin storage owner = findAdmin(p.owner);
|
checkAdminOwner(p.owner);
|
||||||
checkAdminOwner(owner);
|
|
||||||
|
|
||||||
uint64 idNewPledge = findOrCreatePledge(
|
uint64 idNewPledge = findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
|
@ -242,7 +250,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
|
|
||||||
doTransfer(idPledge, idNewPledge, amount);
|
doTransfer(idPledge, idNewPledge, amount);
|
||||||
|
|
||||||
vault.authorizePayment(bytes32(idNewPledge), owner.addr, amount);
|
vault.authorizePayment(bytes32(idNewPledge), _storage.getAdminAddr(p.owner), amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice `onlyVault` Confirms a withdraw request changing the PledgeState
|
/// @notice `onlyVault` Confirms a withdraw request changing the PledgeState
|
||||||
|
@ -293,11 +301,8 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// @notice Changes the `project.canceled` flag to `true`; cannot be undone
|
/// @notice Changes the `project.canceled` flag to `true`; cannot be undone
|
||||||
/// @param idProject Id of the project that is to be canceled
|
/// @param idProject Id of the project that is to be canceled
|
||||||
function cancelProject(uint64 idProject) public {
|
function cancelProject(uint64 idProject) public {
|
||||||
PledgeAdmin storage project = findAdmin(idProject);
|
checkAdminOwner(idProject);
|
||||||
checkAdminOwner(project);
|
_storage.cancelProject(idProject);
|
||||||
project.canceled = true;
|
|
||||||
|
|
||||||
CancelProject(idProject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Transfers `amount` in `idPledge` back to the `oldPledge` that
|
/// @notice Transfers `amount` in `idPledge` back to the `oldPledge` that
|
||||||
|
@ -311,8 +316,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
Pledge storage p = findPledge(idPledge);
|
Pledge storage p = findPledge(idPledge);
|
||||||
require(p.oldPledge != 0);
|
require(p.oldPledge != 0);
|
||||||
|
|
||||||
PledgeAdmin storage m = findAdmin(p.owner);
|
checkAdminOwner(p.owner);
|
||||||
checkAdminOwner(m);
|
|
||||||
|
|
||||||
uint64 oldPledge = getOldestPledgeNotCanceled(p.oldPledge);
|
uint64 oldPledge = getOldestPledgeNotCanceled(p.oldPledge);
|
||||||
doTransfer(idPledge, oldPledge, amount);
|
doTransfer(idPledge, oldPledge, amount);
|
||||||
|
@ -422,7 +426,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
// Ensure that the pledge is not already at max pledge depth
|
// Ensure that the pledge is not already at max pledge depth
|
||||||
// and the project has not been canceled
|
// and the project has not been canceled
|
||||||
require(getPledgeLevel(p) < MAX_INTERPROJECT_LEVEL);
|
require(getPledgeLevel(p) < MAX_INTERPROJECT_LEVEL);
|
||||||
require(!isProjectCanceled(idReceiver));
|
require(!_storage.isProjectCanceled(idReceiver));
|
||||||
|
|
||||||
uint64 oldPledge = findOrCreatePledge(
|
uint64 oldPledge = findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
|
@ -548,7 +552,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
Pledge storage p = findPledge(idPledge);
|
Pledge storage p = findPledge(idPledge);
|
||||||
|
|
||||||
require(getPledgeLevel(p) < MAX_INTERPROJECT_LEVEL);
|
require(getPledgeLevel(p) < MAX_INTERPROJECT_LEVEL);
|
||||||
require(!isProjectCanceled(idReceiver));
|
require(!_storage.isProjectCanceled(idReceiver));
|
||||||
|
|
||||||
uint64 toPledge = findOrCreatePledge(
|
uint64 toPledge = findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
|
@ -568,6 +572,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// @param _amount The amount of value that will be transfered.
|
/// @param _amount The amount of value that will be transfered.
|
||||||
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);
|
uint amount = callPlugins(true, from, to, _amount);
|
||||||
|
// uint amount = _amount;
|
||||||
if (from == to) {
|
if (from == to) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -581,7 +586,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
nTo.amount += amount;
|
nTo.amount += amount;
|
||||||
|
|
||||||
Transfer(from, to, amount);
|
Transfer(from, to, amount);
|
||||||
callPlugins(false, from, to, amount);
|
// callPlugins(false, from, to, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Only affects pledges with the Pledged PledgeState for 2 things:
|
/// @notice Only affects pledges with the Pledged PledgeState for 2 things:
|
||||||
|
@ -671,13 +676,14 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
|
|
||||||
uint newAmount;
|
uint newAmount;
|
||||||
allowedAmount = amount;
|
allowedAmount = amount;
|
||||||
PledgeAdmin storage admin = findAdmin(adminId);
|
address plugin = _storage.getAdminPlugin(adminId); // this takes ~10000 gas
|
||||||
|
|
||||||
// Checks admin has a plugin assigned and a non-zero amount is requested
|
// Checks admin has a plugin assigned and a non-zero amount is requested
|
||||||
if ((address(admin.plugin) != 0) && (allowedAmount > 0)) {
|
if (plugin != 0 && allowedAmount > 0) {
|
||||||
// There are two seperate functions called in the plugin.
|
// There are two seperate functions called in the plugin.
|
||||||
// One is called before the transfer and one after
|
// One is called before the transfer and one after
|
||||||
if (before) {
|
if (before) {
|
||||||
newAmount = admin.plugin.beforeTransfer(
|
newAmount = ILiquidPledgingPlugin(plugin).beforeTransfer(
|
||||||
adminId,
|
adminId,
|
||||||
fromPledge,
|
fromPledge,
|
||||||
toPledge,
|
toPledge,
|
||||||
|
@ -687,7 +693,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
require(newAmount <= allowedAmount);
|
require(newAmount <= allowedAmount);
|
||||||
allowedAmount = newAmount;
|
allowedAmount = newAmount;
|
||||||
} else {
|
} else {
|
||||||
admin.plugin.afterTransfer(
|
ILiquidPledgingPlugin(plugin).afterTransfer(
|
||||||
adminId,
|
adminId,
|
||||||
fromPledge,
|
fromPledge,
|
||||||
toPledge,
|
toPledge,
|
||||||
|
@ -722,6 +728,10 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
allowedAmount = amount;
|
allowedAmount = amount;
|
||||||
Pledge storage p = findPledge(idPledge);
|
Pledge storage p = findPledge(idPledge);
|
||||||
|
|
||||||
|
// TODO I think we can remove these check b/c the admins array only grows, thus if adminId is out of index, it will just return 0x0 & skip the plugin call
|
||||||
|
// uint adminsSize = _storage.pledgeAdminsCount();
|
||||||
|
// require(adminsSize >= p.owner);
|
||||||
|
|
||||||
// Always call the plugin on the owner
|
// Always call the plugin on the owner
|
||||||
allowedAmount = callPlugin(
|
allowedAmount = callPlugin(
|
||||||
before,
|
before,
|
||||||
|
@ -734,6 +744,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
|
|
||||||
// Apply call plugin to all delegates
|
// Apply call plugin to all delegates
|
||||||
for (uint64 i=0; i<p.delegationChain.length; i++) {
|
for (uint64 i=0; i<p.delegationChain.length; i++) {
|
||||||
|
// require(adminsSize >= p.delegationChain[i]);
|
||||||
allowedAmount = callPlugin(
|
allowedAmount = callPlugin(
|
||||||
before,
|
before,
|
||||||
p.delegationChain[i],
|
p.delegationChain[i],
|
||||||
|
@ -748,6 +759,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
// either a transferring or receiving context based on offset
|
// either a transferring or receiving context based on offset
|
||||||
// on the intended project
|
// on the intended project
|
||||||
if (p.intendedProject > 0) {
|
if (p.intendedProject > 0) {
|
||||||
|
// require(adminsSize >= p.intendedProject);
|
||||||
allowedAmount = callPlugin(
|
allowedAmount = callPlugin(
|
||||||
before,
|
before,
|
||||||
p.intendedProject,
|
p.intendedProject,
|
||||||
|
@ -806,6 +818,6 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
|
|
||||||
// Event Delcerations
|
// Event Delcerations
|
||||||
event Transfer(uint64 indexed from, uint64 indexed to, uint amount);
|
event Transfer(uint64 indexed from, uint64 indexed to, uint amount);
|
||||||
event CancelProject(uint64 indexed idProject);
|
event CancelProject(uint indexed idProject);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ pragma solidity ^0.4.11;
|
||||||
|
|
||||||
import "./ILiquidPledgingPlugin.sol";
|
import "./ILiquidPledgingPlugin.sol";
|
||||||
import "giveth-common-contracts/contracts/Escapable.sol";
|
import "giveth-common-contracts/contracts/Escapable.sol";
|
||||||
|
import "./PledgeAdmins.sol";
|
||||||
|
import "./EternalStorage.sol";
|
||||||
|
|
||||||
/// @dev This is an interface for `LPVault` which serves as a secure storage for
|
/// @dev This is an interface for `LPVault` which serves as a secure storage for
|
||||||
/// the ETH that backs the Pledges, only after `LiquidPledging` authorizes
|
/// the ETH that backs the Pledges, only after `LiquidPledging` authorizes
|
||||||
|
@ -33,32 +35,15 @@ interface LPVault {
|
||||||
/// liquidPledging's most basic functions, mostly handling and searching the
|
/// liquidPledging's most basic functions, mostly handling and searching the
|
||||||
/// data structures
|
/// data structures
|
||||||
contract LiquidPledgingBase is Escapable {
|
contract LiquidPledgingBase is Escapable {
|
||||||
|
using PledgeAdmins for EternalStorage;
|
||||||
|
|
||||||
// Limits inserted to prevent large loops that could prevent canceling
|
// Limits inserted to prevent large loops that could prevent canceling
|
||||||
uint constant MAX_DELEGATES = 10;
|
uint constant MAX_DELEGATES = 10;
|
||||||
uint constant MAX_SUBPROJECT_LEVEL = 20;
|
uint constant MAX_SUBPROJECT_LEVEL = 20;
|
||||||
uint constant MAX_INTERPROJECT_LEVEL = 20;
|
uint constant MAX_INTERPROJECT_LEVEL = 20;
|
||||||
|
|
||||||
enum PledgeAdminType { Giver, Delegate, Project }
|
|
||||||
enum PledgeState { Pledged, Paying, Paid }
|
enum PledgeState { Pledged, Paying, Paid }
|
||||||
|
|
||||||
/// @dev This struct defines the details of a `PledgeAdmin` which are
|
|
||||||
/// commonly referenced by their index in the `admins` array
|
|
||||||
/// and can own pledges and act as delegates
|
|
||||||
struct PledgeAdmin {
|
|
||||||
PledgeAdminType adminType; // Giver, Delegate or Project
|
|
||||||
address addr; // Account or contract address for admin
|
|
||||||
string name;
|
|
||||||
string url; // Can be IPFS hash
|
|
||||||
uint64 commitTime; // In seconds, used for Givers' & Delegates' vetos
|
|
||||||
uint64 parentProject; // Only for projects
|
|
||||||
bool canceled; //Always false except for canceled projects
|
|
||||||
|
|
||||||
/// @dev if the plugin is 0x0 then nothing happens, if its an address
|
|
||||||
// than that smart contract is called when appropriate
|
|
||||||
ILiquidPledgingPlugin plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Pledge {
|
struct Pledge {
|
||||||
uint amount;
|
uint amount;
|
||||||
uint64 owner; // PledgeAdmin
|
uint64 owner; // PledgeAdmin
|
||||||
|
@ -69,17 +54,31 @@ contract LiquidPledgingBase is Escapable {
|
||||||
PledgeState pledgeState; // Pledged, Paying, Paid
|
PledgeState pledgeState; // Pledged, Paying, Paid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EternalStorage public _storage;
|
||||||
Pledge[] pledges;
|
Pledge[] pledges;
|
||||||
PledgeAdmin[] admins; //The list of pledgeAdmins 0 means there is no admin
|
|
||||||
LPVault public vault;
|
|
||||||
|
|
||||||
/// @dev this mapping allows you to search for a specific pledge's
|
/// @dev this mapping allows you to search for a specific pledge's
|
||||||
/// index number by the hash of that pledge
|
/// index number by the hash of that pledge
|
||||||
mapping (bytes32 => uint64) hPledge2idx;
|
mapping (bytes32 => uint64) hPledge2idx;
|
||||||
|
|
||||||
|
|
||||||
|
LPVault public vault;
|
||||||
|
|
||||||
mapping (bytes32 => bool) pluginWhitelist;
|
mapping (bytes32 => bool) pluginWhitelist;
|
||||||
|
|
||||||
bool public usePluginWhitelist = true;
|
bool public usePluginWhitelist = true;
|
||||||
|
|
||||||
|
// Duplicate Events from libs so they are added to the abi
|
||||||
|
event GiverAdded(uint indexed idGiver);
|
||||||
|
event GiverUpdated(uint indexed idGiver);
|
||||||
|
event DelegateAdded(uint indexed idDelegate);
|
||||||
|
event DelegateUpdated(uint indexed idDelegate);
|
||||||
|
event ProjectAdded(uint indexed idProject);
|
||||||
|
event ProjectUpdated(uint indexed idProject);
|
||||||
|
|
||||||
|
// for testing
|
||||||
|
event Gas(uint remainingGas);
|
||||||
|
|
||||||
/////////////
|
/////////////
|
||||||
// Modifiers
|
// Modifiers
|
||||||
/////////////
|
/////////////
|
||||||
|
@ -100,12 +99,12 @@ contract LiquidPledgingBase is Escapable {
|
||||||
/// @notice The Constructor creates `LiquidPledgingBase` on the blockchain
|
/// @notice The Constructor creates `LiquidPledgingBase` on the blockchain
|
||||||
/// @param _vault The vault where the ETH backing the pledges is stored
|
/// @param _vault The vault where the ETH backing the pledges is stored
|
||||||
function LiquidPledgingBase(
|
function LiquidPledgingBase(
|
||||||
|
address _storageAddr,
|
||||||
address _vault,
|
address _vault,
|
||||||
address _escapeHatchCaller,
|
address _escapeHatchCaller,
|
||||||
address _escapeHatchDestination
|
address _escapeHatchDestination
|
||||||
) Escapable(_escapeHatchCaller, _escapeHatchDestination) public {
|
) Escapable(_escapeHatchCaller, _escapeHatchDestination) public {
|
||||||
admins.length = 1; // we reserve the 0 admin
|
_storage = EternalStorage(_storageAddr);
|
||||||
pledges.length = 1; // we reserve the 0 pledge
|
|
||||||
vault = LPVault(_vault); // Assigns the specified vault
|
vault = LPVault(_vault); // Assigns the specified vault
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,146 +113,73 @@ contract LiquidPledgingBase is Escapable {
|
||||||
// PledgeAdmin functions
|
// PledgeAdmin functions
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
|
|
||||||
/// @notice Creates a Giver Admin with the `msg.sender` as the Admin address
|
|
||||||
/// @param name The name used to identify the Giver
|
|
||||||
/// @param url The link to the Giver's profile often an IPFS hash
|
|
||||||
/// @param commitTime The length of time in seconds the Giver has to
|
|
||||||
/// veto when the Giver's delegates Pledge funds to a project
|
|
||||||
/// @param plugin This is Giver's liquid pledge plugin allowing for
|
|
||||||
/// extended functionality
|
|
||||||
/// @return idGiver The id number used to reference this Admin
|
|
||||||
function addGiver(
|
function addGiver(
|
||||||
string name,
|
string name,
|
||||||
string url,
|
string url,
|
||||||
uint64 commitTime,
|
uint64 commitTime,
|
||||||
ILiquidPledgingPlugin plugin
|
ILiquidPledgingPlugin plugin
|
||||||
) public returns (uint64 idGiver) {
|
) public returns (uint idGiver) {
|
||||||
|
|
||||||
require(isValidPlugin(plugin)); // Plugin check
|
require(isValidPlugin(plugin)); // Plugin check
|
||||||
|
|
||||||
idGiver = uint64(admins.length);
|
return _storage.addGiver(
|
||||||
|
|
||||||
admins.push(PledgeAdmin(
|
|
||||||
PledgeAdminType.Giver,
|
|
||||||
msg.sender,
|
|
||||||
name,
|
name,
|
||||||
url,
|
url,
|
||||||
commitTime,
|
commitTime,
|
||||||
0,
|
plugin
|
||||||
false,
|
);
|
||||||
plugin));
|
|
||||||
|
|
||||||
GiverAdded(idGiver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event GiverAdded(uint64 indexed idGiver);
|
|
||||||
|
|
||||||
/// @notice Updates a Giver's info to change the address, name, url, or
|
|
||||||
/// commitTime, it cannot be used to change a plugin, and it must be called
|
|
||||||
/// by the current address of the Giver
|
|
||||||
/// @param idGiver This is the Admin id number used to specify the Giver
|
|
||||||
/// @param newAddr The new address that represents this Giver
|
|
||||||
/// @param newName The new name used to identify the Giver
|
|
||||||
/// @param newUrl The new link to the Giver's profile often an IPFS hash
|
|
||||||
/// @param newCommitTime Sets the length of time in seconds the Giver has to
|
|
||||||
/// veto when the Giver's delegates Pledge funds to a project
|
|
||||||
function updateGiver(
|
function updateGiver(
|
||||||
uint64 idGiver,
|
uint64 idGiver,
|
||||||
address newAddr,
|
address newAddr,
|
||||||
string newName,
|
string newName,
|
||||||
string newUrl,
|
string newUrl,
|
||||||
uint64 newCommitTime) public
|
uint64 newCommitTime
|
||||||
|
) public
|
||||||
{
|
{
|
||||||
PledgeAdmin storage giver = findAdmin(idGiver);
|
_storage.updateGiver(
|
||||||
require(giver.adminType == PledgeAdminType.Giver); // Must be a Giver
|
idGiver,
|
||||||
require(giver.addr == msg.sender); // Current addr had to send this tx
|
newAddr,
|
||||||
giver.addr = newAddr;
|
newName,
|
||||||
giver.name = newName;
|
newUrl,
|
||||||
giver.url = newUrl;
|
newCommitTime
|
||||||
giver.commitTime = newCommitTime;
|
);
|
||||||
GiverUpdated(idGiver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event GiverUpdated(uint64 indexed idGiver);
|
|
||||||
|
|
||||||
/// @notice Creates a Delegate Admin with the `msg.sender` as the Admin addr
|
|
||||||
/// @param name The name used to identify the Delegate
|
|
||||||
/// @param url The link to the Delegate's profile often an IPFS hash
|
|
||||||
/// @param commitTime Sets the length of time in seconds that this delegate
|
|
||||||
/// can be vetoed. Whenever this delegate is in a delegate chain the time
|
|
||||||
/// allowed to veto any event must be greater than or equal to this time.
|
|
||||||
/// @param plugin This is Delegate's liquid pledge plugin allowing for
|
|
||||||
/// extended functionality
|
|
||||||
/// @return idxDelegate The id number used to reference this Delegate within
|
|
||||||
/// the admins array
|
|
||||||
function addDelegate(
|
function addDelegate(
|
||||||
string name,
|
string name,
|
||||||
string url,
|
string url,
|
||||||
uint64 commitTime,
|
uint64 commitTime,
|
||||||
ILiquidPledgingPlugin plugin
|
ILiquidPledgingPlugin plugin
|
||||||
) public returns (uint64 idDelegate) {
|
) public returns (uint64 idDelegate)
|
||||||
|
{
|
||||||
require(isValidPlugin(plugin)); // Plugin check
|
require(isValidPlugin(plugin)); // Plugin check
|
||||||
|
|
||||||
idDelegate = uint64(admins.length);
|
return uint64(_storage.addDelegate(
|
||||||
|
|
||||||
admins.push(PledgeAdmin(
|
|
||||||
PledgeAdminType.Delegate,
|
|
||||||
msg.sender,
|
|
||||||
name,
|
name,
|
||||||
url,
|
url,
|
||||||
commitTime,
|
commitTime,
|
||||||
0,
|
plugin
|
||||||
false,
|
));
|
||||||
plugin));
|
|
||||||
|
|
||||||
DelegateAdded(idDelegate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event DelegateAdded(uint64 indexed idDelegate);
|
|
||||||
|
|
||||||
/// @notice Updates a Delegate's info to change the address, name, url, or
|
|
||||||
/// commitTime, it cannot be used to change a plugin, and it must be called
|
|
||||||
/// by the current address of the Delegate
|
|
||||||
/// @param idDelegate The Admin id number used to specify the Delegate
|
|
||||||
/// @param newAddr The new address that represents this Delegate
|
|
||||||
/// @param newName The new name used to identify the Delegate
|
|
||||||
/// @param newUrl The new link to the Delegate's profile often an IPFS hash
|
|
||||||
/// @param newCommitTime Sets the length of time in seconds that this
|
|
||||||
/// delegate can be vetoed. Whenever this delegate is in a delegate chain
|
|
||||||
/// the time allowed to veto any event must be greater than or equal to
|
|
||||||
/// this time.
|
|
||||||
function updateDelegate(
|
function updateDelegate(
|
||||||
uint64 idDelegate,
|
uint64 idDelegate,
|
||||||
address newAddr,
|
address newAddr,
|
||||||
string newName,
|
string newName,
|
||||||
string newUrl,
|
string newUrl,
|
||||||
uint64 newCommitTime) public
|
uint64 newCommitTime
|
||||||
|
) public
|
||||||
{
|
{
|
||||||
PledgeAdmin storage delegate = findAdmin(idDelegate);
|
_storage.updateDelegate(
|
||||||
require(delegate.adminType == PledgeAdminType.Delegate);
|
idDelegate,
|
||||||
require(delegate.addr == msg.sender);// Current addr had to send this tx
|
newAddr,
|
||||||
delegate.addr = newAddr;
|
newName,
|
||||||
delegate.name = newName;
|
newUrl,
|
||||||
delegate.url = newUrl;
|
newCommitTime
|
||||||
delegate.commitTime = newCommitTime;
|
);
|
||||||
DelegateUpdated(idDelegate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event DelegateUpdated(uint64 indexed idDelegate);
|
|
||||||
|
|
||||||
/// @notice Creates a Project Admin with the `msg.sender` as the Admin addr
|
|
||||||
/// @param name The name used to identify the Project
|
|
||||||
/// @param url The link to the Project's profile often an IPFS hash
|
|
||||||
/// @param projectAdmin The address for the trusted project manager
|
|
||||||
/// @param parentProject The Admin id number for the parent project or 0 if
|
|
||||||
/// there is no parentProject
|
|
||||||
/// @param commitTime Sets the length of time in seconds the Project has to
|
|
||||||
/// veto when the Project delegates to another Delegate and they pledge
|
|
||||||
/// those funds to a project
|
|
||||||
/// @param plugin This is Project's liquid pledge plugin allowing for
|
|
||||||
/// extended functionality
|
|
||||||
/// @return idProject The id number used to reference this Admin
|
|
||||||
function addProject(
|
function addProject(
|
||||||
string name,
|
string name,
|
||||||
string url,
|
string url,
|
||||||
|
@ -266,59 +192,37 @@ contract LiquidPledgingBase is Escapable {
|
||||||
require(isValidPlugin(plugin));
|
require(isValidPlugin(plugin));
|
||||||
|
|
||||||
if (parentProject != 0) {
|
if (parentProject != 0) {
|
||||||
PledgeAdmin storage pa = findAdmin(parentProject);
|
// getProjectLevel will check that parentProject has a `Project` adminType
|
||||||
require(pa.adminType == PledgeAdminType.Project);
|
require(_storage.getProjectLevel(parentProject) < MAX_SUBPROJECT_LEVEL);
|
||||||
require(getProjectLevel(pa) < MAX_SUBPROJECT_LEVEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
idProject = uint64(admins.length);
|
return uint64(_storage.addProject(
|
||||||
|
|
||||||
admins.push(PledgeAdmin(
|
|
||||||
PledgeAdminType.Project,
|
|
||||||
projectAdmin,
|
|
||||||
name,
|
name,
|
||||||
url,
|
url,
|
||||||
commitTime,
|
projectAdmin,
|
||||||
parentProject,
|
parentProject,
|
||||||
false,
|
commitTime,
|
||||||
plugin));
|
plugin
|
||||||
|
));
|
||||||
|
|
||||||
ProjectAdded(idProject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event ProjectAdded(uint64 indexed idProject);
|
|
||||||
|
|
||||||
|
|
||||||
/// @notice Updates a Project's info to change the address, name, url, or
|
|
||||||
/// commitTime, it cannot be used to change a plugin or a parentProject,
|
|
||||||
/// and it must be called by the current address of the Project
|
|
||||||
/// @param idProject The Admin id number used to specify the Project
|
|
||||||
/// @param newAddr The new address that represents this Project
|
|
||||||
/// @param newName The new name used to identify the Project
|
|
||||||
/// @param newUrl The new link to the Project's profile often an IPFS hash
|
|
||||||
/// @param newCommitTime Sets the length of time in seconds the Project has
|
|
||||||
/// to veto when the Project delegates to a Delegate and they pledge those
|
|
||||||
/// funds to a project
|
|
||||||
function updateProject(
|
function updateProject(
|
||||||
uint64 idProject,
|
uint64 idProject,
|
||||||
address newAddr,
|
address newAddr,
|
||||||
string newName,
|
string newName,
|
||||||
string newUrl,
|
string newUrl,
|
||||||
uint64 newCommitTime) public
|
uint64 newCommitTime
|
||||||
|
) public
|
||||||
{
|
{
|
||||||
PledgeAdmin storage project = findAdmin(idProject);
|
_storage.updateProject(
|
||||||
require(project.adminType == PledgeAdminType.Project);
|
idProject,
|
||||||
require(project.addr == msg.sender);
|
newAddr,
|
||||||
project.addr = newAddr;
|
newName,
|
||||||
project.name = newName;
|
newUrl,
|
||||||
project.url = newUrl;
|
newCommitTime
|
||||||
project.commitTime = newCommitTime;
|
);
|
||||||
ProjectUpdated(idProject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
event ProjectUpdated(uint64 indexed idAdmin);
|
|
||||||
|
|
||||||
|
|
||||||
//////////
|
//////////
|
||||||
// Public constant functions
|
// Public constant functions
|
||||||
|
@ -357,57 +261,37 @@ contract LiquidPledgingBase is Escapable {
|
||||||
/// @notice Getter to find Delegate w/ the Pledge ID & the Delegate index
|
/// @notice Getter to find Delegate w/ the Pledge ID & the Delegate index
|
||||||
/// @param idPledge The id number representing the pledge being queried
|
/// @param idPledge The id number representing the pledge being queried
|
||||||
/// @param idxDelegate The index number for the delegate in this Pledge
|
/// @param idxDelegate The index number for the delegate in this Pledge
|
||||||
function getPledgeDelegate(uint64 idPledge, uint idxDelegate) public constant returns(
|
function getPledgeDelegate(uint64 idPledge, uint idxDelegate) public view returns(
|
||||||
uint64 idDelegate,
|
uint64 idDelegate,
|
||||||
address addr,
|
address addr,
|
||||||
string name
|
string name
|
||||||
) {
|
) {
|
||||||
Pledge storage p = findPledge(idPledge);
|
Pledge storage p = findPledge(idPledge);
|
||||||
idDelegate = p.delegationChain[idxDelegate - 1];
|
idDelegate = p.delegationChain[idxDelegate - 1];
|
||||||
PledgeAdmin storage delegate = findAdmin(idDelegate);
|
require(_storage.pledgeAdminsCount() >= idxDelegate);
|
||||||
addr = delegate.addr;
|
addr = _storage.getAdminAddr(idDelegate);
|
||||||
name = delegate.name;
|
name = _storage.getAdminName(idDelegate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice A constant getter used to check how many total Admins exist
|
/// @notice A constant getter used to check how many total Admins exist
|
||||||
/// @return The total number of admins (Givers, Delegates and Projects) .
|
/// @return The total number of admins (Givers, Delegates and Projects) .
|
||||||
function numberOfPledgeAdmins() public constant returns(uint) {
|
// function numberOfPledgeAdmins() public constant returns(uint) {
|
||||||
return admins.length - 1;
|
// return _storage.pledgeAdminsCount();
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// @notice A constant getter to check the details of a specified Admin
|
// can use _storage.getAdmin(idAdmin);
|
||||||
/// @return addr Account or contract address for admin
|
// function getPledgeAdmin(uint64 idAdmin) public constant returns (
|
||||||
/// @return name Name of the pledgeAdmin
|
// PledgeAdmins.PledgeAdminType adminType,
|
||||||
/// @return url The link to the Project's profile often an IPFS hash
|
// address addr,
|
||||||
/// @return commitTime The length of time in seconds the Admin has to veto
|
// string name,
|
||||||
/// when the Admin delegates to a Delegate and that Delegate pledges those
|
// string url,
|
||||||
/// funds to a project
|
// uint64 commitTime,
|
||||||
/// @return parentProject The Admin id number for the parent project or 0
|
// uint64 parentProject,
|
||||||
/// if there is no parentProject
|
// bool canceled,
|
||||||
/// @return canceled 0 for Delegates & Givers, true if a Project has been
|
// address plugin)
|
||||||
/// canceled
|
// {
|
||||||
/// @return plugin This is Project's liquidPledging plugin allowing for
|
// (adminType, addr, name, url, commitTime, parentProject, canceled, plugin) = _storage.getAdmin(idAdmin);
|
||||||
/// extended functionality
|
// }
|
||||||
function getPledgeAdmin(uint64 idAdmin) public constant returns (
|
|
||||||
PledgeAdminType adminType,
|
|
||||||
address addr,
|
|
||||||
string name,
|
|
||||||
string url,
|
|
||||||
uint64 commitTime,
|
|
||||||
uint64 parentProject,
|
|
||||||
bool canceled,
|
|
||||||
address plugin)
|
|
||||||
{
|
|
||||||
PledgeAdmin storage m = findAdmin(idAdmin);
|
|
||||||
adminType = m.adminType;
|
|
||||||
addr = m.addr;
|
|
||||||
name = m.name;
|
|
||||||
url = m.url;
|
|
||||||
commitTime = m.commitTime;
|
|
||||||
parentProject = m.parentProject;
|
|
||||||
canceled = m.canceled;
|
|
||||||
plugin = address(m.plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////
|
////////
|
||||||
// Private methods
|
// Private methods
|
||||||
|
@ -449,14 +333,6 @@ contract LiquidPledgingBase is Escapable {
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice A getter to look up a Admin's details
|
|
||||||
/// @param idAdmin The id for the Admin to lookup
|
|
||||||
/// @return The PledgeAdmin struct for the specified Admin
|
|
||||||
function findAdmin(uint64 idAdmin) internal view returns (PledgeAdmin storage) {
|
|
||||||
require(idAdmin < admins.length);
|
|
||||||
return admins[idAdmin];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @notice A getter to look up a Pledge's details
|
/// @notice A getter to look up a Pledge's details
|
||||||
/// @param idPledge The id for the Pledge to lookup
|
/// @param idPledge The id for the Pledge to lookup
|
||||||
/// @return The PledgeA struct for the specified Pledge
|
/// @return The PledgeA struct for the specified Pledge
|
||||||
|
@ -498,53 +374,35 @@ contract LiquidPledgingBase is Escapable {
|
||||||
/// @param p The Pledge being queried
|
/// @param p The Pledge being queried
|
||||||
/// @return The maximum commitTime out of the owner and all the delegates
|
/// @return The maximum commitTime out of the owner and all the delegates
|
||||||
function maxCommitTime(Pledge p) internal view returns(uint commitTime) {
|
function maxCommitTime(Pledge p) internal view returns(uint commitTime) {
|
||||||
PledgeAdmin storage m = findAdmin(p.owner);
|
uint adminsSize = _storage.pledgeAdminsCount();
|
||||||
commitTime = m.commitTime; // start with the owner's commitTime
|
require(adminsSize >= p.owner);
|
||||||
|
|
||||||
|
commitTime = _storage.getAdminCommitTime(p.owner); // start with the owner's commitTime
|
||||||
|
|
||||||
for (uint i=0; i<p.delegationChain.length; i++) {
|
for (uint i=0; i<p.delegationChain.length; i++) {
|
||||||
m = findAdmin(p.delegationChain[i]);
|
require(adminsSize >= p.delegationChain[i]);
|
||||||
|
uint delegateCommitTime = _storage.getAdminCommitTime(p.delegationChain[i]);
|
||||||
|
|
||||||
// If a delegate's commitTime is longer, make it the new commitTime
|
// If a delegate's commitTime is longer, make it the new commitTime
|
||||||
if (m.commitTime > commitTime) commitTime = m.commitTime;
|
if (delegateCommitTime > commitTime) commitTime = delegateCommitTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice A getter to find the level of authority a specific Project has
|
|
||||||
/// using a self-referential loop
|
|
||||||
/// @param m The Project being queried
|
|
||||||
/// @return The level of authority a specific Project has
|
|
||||||
function getProjectLevel(PledgeAdmin m) internal returns(uint) {
|
|
||||||
assert(m.adminType == PledgeAdminType.Project);
|
|
||||||
if (m.parentProject == 0) return(1);
|
|
||||||
PledgeAdmin storage parentNM = findAdmin(m.parentProject);
|
|
||||||
return getProjectLevel(parentNM) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @notice A getter to find if a specified Project has been canceled
|
|
||||||
/// @param projectId The Admin id number used to specify the Project
|
|
||||||
/// @return True if the Project has been canceled
|
|
||||||
function isProjectCanceled(uint64 projectId) public constant returns (bool) {
|
|
||||||
PledgeAdmin storage m = findAdmin(projectId);
|
|
||||||
if (m.adminType == PledgeAdminType.Giver) return false;
|
|
||||||
assert(m.adminType == PledgeAdminType.Project);
|
|
||||||
if (m.canceled) return true;
|
|
||||||
if (m.parentProject == 0) return false;
|
|
||||||
return isProjectCanceled(m.parentProject);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @notice A getter to find the oldest pledge that hasn't been canceled
|
/// @notice A getter to find the oldest pledge that hasn't been canceled
|
||||||
/// @param idPledge The starting place to lookup the pledges
|
/// @param idPledge The starting place to lookup the pledges
|
||||||
/// @return The oldest idPledge that hasn't been canceled (DUH!)
|
/// @return The oldest idPledge that hasn't been canceled (DUH!)
|
||||||
function getOldestPledgeNotCanceled(uint64 idPledge
|
function getOldestPledgeNotCanceled(
|
||||||
) internal constant returns(uint64) {
|
uint64 idPledge
|
||||||
|
) internal constant returns(uint64)
|
||||||
|
{
|
||||||
if (idPledge == 0) return 0;
|
if (idPledge == 0) return 0;
|
||||||
Pledge storage p = findPledge(idPledge);
|
Pledge storage p = findPledge(idPledge);
|
||||||
PledgeAdmin storage admin = findAdmin(p.owner);
|
|
||||||
if (admin.adminType == PledgeAdminType.Giver) return idPledge;
|
|
||||||
|
|
||||||
assert(admin.adminType == PledgeAdminType.Project);
|
PledgeAdmins.PledgeAdminType adminType = _storage.getAdminType(p.owner);
|
||||||
|
if (adminType == PledgeAdmins.PledgeAdminType.Giver) return idPledge;
|
||||||
|
assert(adminType == PledgeAdmins.PledgeAdminType.Project);
|
||||||
|
|
||||||
if (!isProjectCanceled(p.owner)) return idPledge;
|
if (!_storage.isProjectCanceled(p.owner)) return idPledge;
|
||||||
|
|
||||||
return getOldestPledgeNotCanceled(p.oldPledge);
|
return getOldestPledgeNotCanceled(p.oldPledge);
|
||||||
}
|
}
|
||||||
|
@ -552,9 +410,14 @@ contract LiquidPledgingBase is Escapable {
|
||||||
/// @notice A check to see if the msg.sender is the owner or the
|
/// @notice A check to see if the msg.sender is the owner or the
|
||||||
/// plugin contract for a specific Admin
|
/// plugin contract for a specific Admin
|
||||||
/// @param m The Admin being checked
|
/// @param m The Admin being checked
|
||||||
function checkAdminOwner(PledgeAdmin m) internal constant {
|
function checkAdminOwner(PledgeAdmins.PledgeAdmin m) internal constant {
|
||||||
require((msg.sender == m.addr) || (msg.sender == address(m.plugin)));
|
require((msg.sender == m.addr) || (msg.sender == address(m.plugin)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkAdminOwner(uint idAdmin) internal constant {
|
||||||
|
require((msg.sender == _storage.getAdminPlugin(idAdmin)) || (msg.sender == _storage.getAdminAddr(idAdmin)));
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
// Plugin Whitelist Methods
|
// Plugin Whitelist Methods
|
||||||
///////////////////////////
|
///////////////////////////
|
||||||
|
|
|
@ -0,0 +1,411 @@
|
||||||
|
pragma solidity ^0.4.17;
|
||||||
|
|
||||||
|
import "./ILiquidPledgingPlugin.sol";
|
||||||
|
import "./EternallyPersistentLib.sol";
|
||||||
|
|
||||||
|
library PledgeAdmins {
|
||||||
|
using EternallyPersistentLib for EternalStorage;
|
||||||
|
|
||||||
|
//TODO we can pack some of these struct values, which should save space. TEST THIS
|
||||||
|
//TODO making functions public may lower deployment cost, but increase gas / tx costs. TEST THIS
|
||||||
|
//TODO is it cheaper to issue a storage check before updating? where should this be done? EternalStorage?
|
||||||
|
|
||||||
|
string constant class = "PledgeAdmins";
|
||||||
|
bytes32 constant admins = keccak256("pledgeAdmins");
|
||||||
|
|
||||||
|
enum PledgeAdminType { Giver, Delegate, Project }
|
||||||
|
|
||||||
|
/// @dev This struct defines the details of a `PledgeAdmin` which are
|
||||||
|
/// commonly referenced by their index in the `admins` array
|
||||||
|
/// and can own pledges and act as delegates
|
||||||
|
struct PledgeAdmin {
|
||||||
|
PledgeAdminType adminType; // Giver, Delegate or Project
|
||||||
|
address addr; // Account or contract address for admin
|
||||||
|
string name;
|
||||||
|
string url; // Can be IPFS hash
|
||||||
|
uint64 commitTime; // In seconds, used for Givers' & Delegates' vetos
|
||||||
|
uint64 parentProject; // Only for projects
|
||||||
|
bool canceled; //Always false except for canceled projects
|
||||||
|
|
||||||
|
/// @dev if the plugin is 0x0 then nothing happens, if its an address
|
||||||
|
// than that smart contract is called when appropriate
|
||||||
|
ILiquidPledgingPlugin plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PledgeAdmins[] admins;
|
||||||
|
|
||||||
|
// function PledgeAdmins(address _storage) EternallyPersistent(_storage) public {
|
||||||
|
// function setStorage(address _storage) internal {
|
||||||
|
// require(address(adminStorage == 0x0));
|
||||||
|
// adminStorage = EternallyPersistent(_storage);
|
||||||
|
// TODO maybe make an init method?
|
||||||
|
// admins.length = 1; // we reserve the 0 admin
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// @notice Creates a Giver Admin with the `msg.sender` as the Admin address
|
||||||
|
/// @param name The name used to identify the Giver
|
||||||
|
/// @param url The link to the Giver's profile often an IPFS hash
|
||||||
|
/// @param commitTime The length of time in seconds the Giver has to
|
||||||
|
/// veto when the Giver's delegates Pledge funds to a project
|
||||||
|
/// @param plugin This is Giver's liquid pledge plugin allowing for
|
||||||
|
/// extended functionality
|
||||||
|
/// @return idGiver The id number used to reference this Admin
|
||||||
|
function addGiver(
|
||||||
|
EternalStorage _storage,
|
||||||
|
string name,
|
||||||
|
string url,
|
||||||
|
uint commitTime,
|
||||||
|
ILiquidPledgingPlugin plugin
|
||||||
|
) internal returns (uint idGiver) {
|
||||||
|
// bytes32 idGuardian = bytes32(addrGuardian);
|
||||||
|
//
|
||||||
|
// if (guardian_exists(addrGuardian)) {
|
||||||
|
// _storage.stgObjectSetString( "Guardian", idGuardian, "name", name);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
idGiver = _storage.stgCollectionAddItem(admins);//, idGiver);
|
||||||
|
|
||||||
|
// Save the fields
|
||||||
|
_storage.stgObjectSetUInt(class, idGiver, "adminType", uint(PledgeAdminType.Giver));
|
||||||
|
_storage.stgObjectSetAddress(class, idGiver, "addr", msg.sender);
|
||||||
|
_storage.stgObjectSetString(class, idGiver, "name", name);
|
||||||
|
_storage.stgObjectSetString(class, idGiver, "url", url);
|
||||||
|
_storage.stgObjectSetUInt(class, idGiver, "commitTime", commitTime);
|
||||||
|
_storage.stgObjectSetAddress(class, idGiver, "plugin", address(plugin));
|
||||||
|
|
||||||
|
GiverAdded(idGiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
event GiverAdded(uint indexed idGiver);
|
||||||
|
|
||||||
|
/// @notice Updates a Giver's info to change the address, name, url, or
|
||||||
|
/// commitTime, it cannot be used to change a plugin, and it must be called
|
||||||
|
/// by the current address of the Giver
|
||||||
|
/// @param idGiver This is the Admin id number used to specify the Giver
|
||||||
|
/// @param newAddr The new address that represents this Giver
|
||||||
|
/// @param newName The new name used to identify the Giver
|
||||||
|
/// @param newUrl The new link to the Giver's profile often an IPFS hash
|
||||||
|
/// @param newCommitTime Sets the length of time in seconds the Giver has to
|
||||||
|
/// veto when the Giver's delegates Pledge funds to a project
|
||||||
|
function updateGiver(
|
||||||
|
EternalStorage _storage,
|
||||||
|
uint idGiver,
|
||||||
|
address newAddr,
|
||||||
|
string newName,
|
||||||
|
string newUrl,
|
||||||
|
uint64 newCommitTime
|
||||||
|
) public
|
||||||
|
{
|
||||||
|
require(getAdminType(_storage, idGiver) == PledgeAdminType.Giver); // Must be a Giver
|
||||||
|
require(getAdminAddr(_storage, idGiver) == msg.sender); // Current addr had to send this tx
|
||||||
|
|
||||||
|
// Save the fields
|
||||||
|
_storage.stgObjectSetAddress(class, idGiver, "addr", newAddr);
|
||||||
|
_storage.stgObjectSetString(class, idGiver, "name", newName);
|
||||||
|
_storage.stgObjectSetString(class, idGiver, "url", newUrl);
|
||||||
|
_storage.stgObjectSetUInt(class, idGiver, "commitTime", newCommitTime);
|
||||||
|
|
||||||
|
GiverUpdated(idGiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
event GiverUpdated(uint indexed idGiver);
|
||||||
|
|
||||||
|
/// @notice Creates a Delegate Admin with the `msg.sender` as the Admin addr
|
||||||
|
/// @param name The name used to identify the Delegate
|
||||||
|
/// @param url The link to the Delegate's profile often an IPFS hash
|
||||||
|
/// @param commitTime Sets the length of time in seconds that this delegate
|
||||||
|
/// can be vetoed. Whenever this delegate is in a delegate chain the time
|
||||||
|
/// allowed to veto any event must be greater than or equal to this time.
|
||||||
|
/// @param plugin This is Delegate's liquid pledge plugin allowing for
|
||||||
|
/// extended functionality
|
||||||
|
/// @return idxDelegate The id number used to reference this Delegate within
|
||||||
|
/// the admins array
|
||||||
|
function addDelegate(
|
||||||
|
EternalStorage _storage,
|
||||||
|
string name,
|
||||||
|
string url,
|
||||||
|
uint64 commitTime,
|
||||||
|
ILiquidPledgingPlugin plugin
|
||||||
|
) internal returns (uint idDelegate) {
|
||||||
|
idDelegate = _storage.stgCollectionAddItem(admins);//, idDelegate);
|
||||||
|
|
||||||
|
// Save the fields
|
||||||
|
_storage.stgObjectSetUInt(class, idDelegate, "adminType", uint(PledgeAdminType.Delegate));
|
||||||
|
_storage.stgObjectSetAddress(class, idDelegate, "addr", msg.sender);
|
||||||
|
_storage.stgObjectSetString(class, idDelegate, "name", name);
|
||||||
|
_storage.stgObjectSetString(class, idDelegate, "url", url);
|
||||||
|
_storage.stgObjectSetUInt(class, idDelegate, "commitTime", commitTime);
|
||||||
|
_storage.stgObjectSetAddress(class, idDelegate, "plugin", address(plugin));
|
||||||
|
|
||||||
|
DelegateAdded(idDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
event DelegateAdded(uint indexed idDelegate);
|
||||||
|
|
||||||
|
/// @notice Updates a Delegate's info to change the address, name, url, or
|
||||||
|
/// commitTime, it cannot be used to change a plugin, and it must be called
|
||||||
|
/// by the current address of the Delegate
|
||||||
|
/// @param idDelegate The Admin id number used to specify the Delegate
|
||||||
|
/// @param newAddr The new address that represents this Delegate
|
||||||
|
/// @param newName The new name used to identify the Delegate
|
||||||
|
/// @param newUrl The new link to the Delegate's profile often an IPFS hash
|
||||||
|
/// @param newCommitTime Sets the length of time in seconds that this
|
||||||
|
/// delegate can be vetoed. Whenever this delegate is in a delegate chain
|
||||||
|
/// the time allowed to veto any event must be greater than or equal to
|
||||||
|
/// this time.
|
||||||
|
function updateDelegate(
|
||||||
|
EternalStorage _storage,
|
||||||
|
uint idDelegate,
|
||||||
|
address newAddr,
|
||||||
|
string newName,
|
||||||
|
string newUrl,
|
||||||
|
uint64 newCommitTime
|
||||||
|
) public
|
||||||
|
{
|
||||||
|
require(getAdminType(_storage, idDelegate) == PledgeAdminType.Delegate);
|
||||||
|
require(getAdminAddr(_storage, idDelegate) == msg.sender); // Current addr had to send this tx
|
||||||
|
|
||||||
|
// Save the fields
|
||||||
|
_storage.stgObjectSetAddress(class, idDelegate, "addr", newAddr);
|
||||||
|
_storage.stgObjectSetString(class, idDelegate, "name", newName);
|
||||||
|
_storage.stgObjectSetString(class, idDelegate, "url", newUrl);
|
||||||
|
_storage.stgObjectSetUInt(class, idDelegate, "commitTime", newCommitTime);
|
||||||
|
|
||||||
|
DelegateUpdated(idDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
event DelegateUpdated(uint indexed idDelegate);
|
||||||
|
|
||||||
|
/// @notice Creates a Project Admin with the `msg.sender` as the Admin addr
|
||||||
|
/// @param name The name used to identify the Project
|
||||||
|
/// @param url The link to the Project's profile often an IPFS hash
|
||||||
|
/// @param projectAdmin The address for the trusted project manager
|
||||||
|
/// @param parentProject The Admin id number for the parent project or 0 if
|
||||||
|
/// there is no parentProject
|
||||||
|
/// @param commitTime Sets the length of time in seconds the Project has to
|
||||||
|
/// veto when the Project delegates to another Delegate and they pledge
|
||||||
|
/// those funds to a project
|
||||||
|
/// @param plugin This is Project's liquid pledge plugin allowing for
|
||||||
|
/// extended functionality
|
||||||
|
/// @return idProject The id number used to reference this Admin
|
||||||
|
function addProject(
|
||||||
|
EternalStorage _storage,
|
||||||
|
string name,
|
||||||
|
string url,
|
||||||
|
address projectAdmin,
|
||||||
|
uint64 parentProject,
|
||||||
|
uint64 commitTime,
|
||||||
|
ILiquidPledgingPlugin plugin
|
||||||
|
) internal returns (uint idProject) {
|
||||||
|
idProject = _storage.stgCollectionAddItem(admins);//, idProject);
|
||||||
|
|
||||||
|
// Save the fields
|
||||||
|
_storage.stgObjectSetUInt(class, idProject, "adminType", uint(PledgeAdminType.Project));
|
||||||
|
_storage.stgObjectSetAddress(class, idProject, "addr", projectAdmin);
|
||||||
|
_storage.stgObjectSetString(class, idProject, "name", name);
|
||||||
|
_storage.stgObjectSetString(class, idProject, "url", url);
|
||||||
|
|
||||||
|
// NOTICE: we do not verify that the parentProject has a `Project` adminType
|
||||||
|
// this is expected to be done by the calling method
|
||||||
|
_storage.stgObjectSetUInt(class, idProject, "parentProject", parentProject);
|
||||||
|
|
||||||
|
_storage.stgObjectSetUInt(class, idProject, "commitTime", commitTime);
|
||||||
|
_storage.stgObjectSetAddress(class, idProject, "plugin", address(plugin));
|
||||||
|
|
||||||
|
ProjectAdded(idProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
event ProjectAdded(uint indexed idProject);
|
||||||
|
|
||||||
|
/// @notice Updates a Project's info to change the address, name, url, or
|
||||||
|
/// commitTime, it cannot be used to change a plugin or a parentProject,
|
||||||
|
/// and it must be called by the current address of the Project
|
||||||
|
/// @param idProject The Admin id number used to specify the Project
|
||||||
|
/// @param newAddr The new address that represents this Project
|
||||||
|
/// @param newName The new name used to identify the Project
|
||||||
|
/// @param newUrl The new link to the Project's profile often an IPFS hash
|
||||||
|
/// @param newCommitTime Sets the length of time in seconds the Project has
|
||||||
|
/// to veto when the Project delegates to a Delegate and they pledge those
|
||||||
|
/// funds to a project
|
||||||
|
function updateProject(
|
||||||
|
EternalStorage _storage,
|
||||||
|
uint idProject,
|
||||||
|
address newAddr,
|
||||||
|
string newName,
|
||||||
|
string newUrl,
|
||||||
|
uint64 newCommitTime
|
||||||
|
) public
|
||||||
|
{
|
||||||
|
require(getAdminType(_storage, idProject) == PledgeAdminType.Project);
|
||||||
|
require(getAdminAddr(_storage, idProject) == msg.sender); // Current addr had to send this tx
|
||||||
|
|
||||||
|
// Save the fields
|
||||||
|
_storage.stgObjectSetAddress(class, idProject, "addr", newAddr);
|
||||||
|
_storage.stgObjectSetString(class, idProject, "name", newName);
|
||||||
|
_storage.stgObjectSetString(class, idProject, "url", newUrl);
|
||||||
|
_storage.stgObjectSetUInt(class, idProject, "commitTime", newCommitTime);
|
||||||
|
|
||||||
|
ProjectUpdated(idProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
event ProjectUpdated(uint indexed idAdmin);
|
||||||
|
|
||||||
|
function cancelProject(EternalStorage _storage, uint idProject) internal {
|
||||||
|
_storage.stgObjectSetBoolean(class, idProject, "canceled", true);
|
||||||
|
CancelProject(idProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @notice A getter to find if a specified Project has been canceled
|
||||||
|
/// @param projectId The Admin id number used to specify the Project
|
||||||
|
/// @return True if the Project has been canceled
|
||||||
|
function isProjectCanceled(EternalStorage _storage, uint projectId)
|
||||||
|
public constant returns (bool)
|
||||||
|
{
|
||||||
|
require(pledgeAdminsCount(_storage) >= projectId);
|
||||||
|
|
||||||
|
PledgeAdminType adminType = getAdminType(_storage, projectId);
|
||||||
|
|
||||||
|
if (adminType == PledgeAdminType.Giver) return false;
|
||||||
|
assert(adminType == PledgeAdminType.Project);
|
||||||
|
|
||||||
|
if (getAdminCanceled(_storage, projectId)) return true;
|
||||||
|
|
||||||
|
uint parentProject = getAdminParentProject(_storage, projectId);
|
||||||
|
if (parentProject == 0) return false;
|
||||||
|
|
||||||
|
return isProjectCanceled(_storage, parentProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
event CancelProject(uint indexed idProject);
|
||||||
|
|
||||||
|
/// @notice A constant getter used to check how many total Admins exist
|
||||||
|
/// @return The total number of admins (Givers, Delegates and Projects) .
|
||||||
|
//TODO I think using 'size' in both Pledges lib & PledgeAdmins lib will cause a conflict since they use the same storage contract
|
||||||
|
// function size(EternalStorage _storage) constant returns(uint) {
|
||||||
|
function pledgeAdminsCount(EternalStorage _storage) public constant returns(uint) {
|
||||||
|
return _storage.stgCollectionLength(admins);// - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @notice A constant getter to check the details of a specified Admin
|
||||||
|
/// @return addr Account or contract address for admin
|
||||||
|
/// @return name Name of the pledgeAdmin
|
||||||
|
/// @return url The link to the Project's profile often an IPFS hash
|
||||||
|
/// @return commitTime The length of time in seconds the Admin has to veto
|
||||||
|
/// when the Admin delegates to a Delegate and that Delegate pledges those
|
||||||
|
/// funds to a project
|
||||||
|
/// @return parentProject The Admin id number for the parent project or 0
|
||||||
|
/// if there is no parentProject
|
||||||
|
/// @return canceled 0 for Delegates & Givers, true if a Project has been
|
||||||
|
/// canceled
|
||||||
|
/// @return plugin This is Project's liquidPledging plugin allowing for
|
||||||
|
/// extended functionality
|
||||||
|
function getAdmin(EternalStorage _storage, uint idAdmin) internal view returns (
|
||||||
|
PledgeAdminType adminType,
|
||||||
|
address addr,
|
||||||
|
string name,
|
||||||
|
string url,
|
||||||
|
uint64 commitTime,
|
||||||
|
uint parentProject,
|
||||||
|
bool canceled,
|
||||||
|
address plugin
|
||||||
|
)
|
||||||
|
{
|
||||||
|
adminType = getAdminType(_storage, idAdmin);
|
||||||
|
addr = getAdminAddr(_storage, idAdmin);
|
||||||
|
name = getAdminName(_storage, idAdmin);
|
||||||
|
url = _storage.stgObjectGetString(class, idAdmin, "url");
|
||||||
|
commitTime = uint64(getAdminCommitTime(_storage, idAdmin));
|
||||||
|
|
||||||
|
// parentProject & canceled only belong to Project admins,
|
||||||
|
// so don't waste the gas to fetch the data
|
||||||
|
if (adminType == PledgeAdminType.Project) {
|
||||||
|
parentProject = getAdminParentProject(_storage, idAdmin);
|
||||||
|
canceled = getAdminCanceled(_storage, idAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin = getAdminPlugin(_storage, idAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @notice Find the level of authority a specific Project has
|
||||||
|
/// using a recursive loop
|
||||||
|
/// @param idProject The id of the Project being queried
|
||||||
|
/// @return The level of authority a specific Project has
|
||||||
|
function getProjectLevel(EternalStorage _storage, uint idProject) public returns(uint) {
|
||||||
|
assert(getAdminType(_storage, idProject) == PledgeAdminType.Project);
|
||||||
|
uint parentProject = getAdminParentProject(_storage, idProject);
|
||||||
|
if (parentProject == 0) return(1);
|
||||||
|
return getProjectLevel(_storage, parentProject) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//18,446,744,070,000,000,000 uint64
|
||||||
|
//1,516,144,546,228,000 uint56
|
||||||
|
|
||||||
|
////////
|
||||||
|
// Methods to fetch individual attributes of a PledgeAdmin
|
||||||
|
///////
|
||||||
|
|
||||||
|
// costs ~10k gas
|
||||||
|
function getAdminType(
|
||||||
|
EternalStorage _storage,
|
||||||
|
uint idAdmin
|
||||||
|
) public view returns (PledgeAdminType)
|
||||||
|
{
|
||||||
|
return PledgeAdminType(_storage.stgObjectGetUInt(class, idAdmin, "adminType"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// costs ~10k gas
|
||||||
|
function getAdminAddr(
|
||||||
|
EternalStorage _storage,
|
||||||
|
uint idAdmin
|
||||||
|
) public view returns (address)
|
||||||
|
{
|
||||||
|
return _storage.stgObjectGetAddress(class, idAdmin, "addr");
|
||||||
|
}
|
||||||
|
|
||||||
|
// costs ~8k gas
|
||||||
|
function getAdminName(
|
||||||
|
EternalStorage _storage,
|
||||||
|
uint idAdmin
|
||||||
|
) internal view returns (string)
|
||||||
|
{
|
||||||
|
return _storage.stgObjectGetString(class, idAdmin, "name");
|
||||||
|
}
|
||||||
|
|
||||||
|
// costs ~10k gas
|
||||||
|
function getAdminParentProject(
|
||||||
|
EternalStorage _storage,
|
||||||
|
uint idAdmin
|
||||||
|
) public view returns (uint)
|
||||||
|
{
|
||||||
|
return _storage.stgObjectGetUInt(class, idAdmin, "parentProject");
|
||||||
|
}
|
||||||
|
|
||||||
|
// costs ~10k gas
|
||||||
|
function getAdminCanceled(
|
||||||
|
EternalStorage _storage,
|
||||||
|
uint idAdmin
|
||||||
|
) public view returns (bool)
|
||||||
|
{
|
||||||
|
return _storage.stgObjectGetBoolean(class, idAdmin, "canceled");
|
||||||
|
}
|
||||||
|
|
||||||
|
// costs ~10k gas
|
||||||
|
function getAdminPlugin(
|
||||||
|
EternalStorage _storage,
|
||||||
|
uint idAdmin
|
||||||
|
) public view returns (address)
|
||||||
|
{
|
||||||
|
return _storage.stgObjectGetAddress(class, idAdmin, "plugin");
|
||||||
|
}
|
||||||
|
|
||||||
|
// costs ~10k gas
|
||||||
|
function getAdminCommitTime(
|
||||||
|
EternalStorage _storage,
|
||||||
|
uint idAdmin
|
||||||
|
) public view returns (uint)
|
||||||
|
{
|
||||||
|
return _storage.stgObjectGetUInt(class, idAdmin, "commitTime");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
const EternalStorageAbi = require('../build/EternalStorage.sol').EternalStorageAbi;
|
||||||
|
const EternalStorageCode = require('../build/EternalStorage.sol').EternalStorageByteCode;
|
||||||
|
const generateClass = require('eth-contract-class').default;
|
||||||
|
|
||||||
|
module.exports = generateClass(EternalStorageAbi, EternalStorageCode);
|
||||||
|
|
Loading…
Reference in New Issue