first pass as AragonApp
This commit is contained in:
parent
6cdceb62cf
commit
369e6ae6cd
|
@ -0,0 +1,89 @@
|
||||||
|
pragma solidity ^0.4.15;
|
||||||
|
/*
|
||||||
|
Copyright 2016, Jordi Baylina
|
||||||
|
Contributor: Adrià Massanet <adria@codecontext.io>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// import "./Owned.sol";
|
||||||
|
import "giveth-common-contracts/contracts/ERC20.sol";
|
||||||
|
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||||
|
|
||||||
|
|
||||||
|
/// @dev `Escapable` is a base level contract built off of the `Owned`
|
||||||
|
/// contract; it creates an escape hatch function that can be called in an
|
||||||
|
/// emergency that will allow designated addresses to send any ether or tokens
|
||||||
|
/// held in the contract to an `escapeHatchDestination` as long as they were
|
||||||
|
/// not blacklisted
|
||||||
|
contract EscapableApp is AragonApp {
|
||||||
|
// warning whoever has this role can move all funds to the `escapeHatchDestination`
|
||||||
|
bytes32 constant public ESCAPE_HATCH_CALLER_ROLE = bytes32(1);
|
||||||
|
|
||||||
|
address public escapeHatchDestination;
|
||||||
|
mapping (address=>bool) private escapeBlacklist; // Token contract addresses
|
||||||
|
|
||||||
|
/// @param _escapeHatchDestination The address of a safe location (usu a
|
||||||
|
/// Multisig) to send the ether held in this contract; if a neutral address
|
||||||
|
/// is required, the WHG Multisig is an option:
|
||||||
|
/// 0x8Ff920020c8AD673661c8117f2855C384758C572
|
||||||
|
function initialize(address _escapeHatchDestination) onlyInit external {
|
||||||
|
initialized();
|
||||||
|
require(_escapeHatchDestination != 0x0);
|
||||||
|
|
||||||
|
escapeHatchDestination = _escapeHatchDestination;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @notice Creates the blacklist of tokens that are not able to be taken
|
||||||
|
/// out of the contract; can only be done at the deployment, and the logic
|
||||||
|
/// to add to the blacklist will be in the constructor of a child contract
|
||||||
|
/// @param _token the token contract address that is to be blacklisted
|
||||||
|
function blacklistEscapeToken(address _token) internal {
|
||||||
|
escapeBlacklist[_token] = true;
|
||||||
|
EscapeHatchBlackistedToken(_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @notice Checks to see if `_token` is in the blacklist of tokens
|
||||||
|
/// @param _token the token address being queried
|
||||||
|
/// @return False if `_token` is in the blacklist and can't be taken out of
|
||||||
|
/// the contract via the `escapeHatch()`
|
||||||
|
function isTokenEscapable(address _token) constant public returns (bool) {
|
||||||
|
return !escapeBlacklist[_token];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @notice The `escapeHatch()` should only be called as a last resort if a
|
||||||
|
/// security issue is uncovered or something unexpected happened
|
||||||
|
/// @param _token to transfer, use 0x0 for ether
|
||||||
|
function escapeHatch(address _token) public authP(ESCAPE_HATCH_CALLER_ROLE, arr(_token)) {
|
||||||
|
require(escapeBlacklist[_token]==false);
|
||||||
|
|
||||||
|
uint256 balance;
|
||||||
|
|
||||||
|
/// @dev Logic for ether
|
||||||
|
if (_token == 0x0) {
|
||||||
|
balance = this.balance;
|
||||||
|
escapeHatchDestination.transfer(balance);
|
||||||
|
EscapeHatchCalled(_token, balance);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/// @dev Logic for tokens
|
||||||
|
ERC20 token = ERC20(_token);
|
||||||
|
balance = token.balanceOf(this);
|
||||||
|
require(token.transfer(escapeHatchDestination, balance));
|
||||||
|
EscapeHatchCalled(_token, balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
event EscapeHatchBlackistedToken(address token);
|
||||||
|
event EscapeHatchCalled(address token, uint amount);
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
pragma solidity ^0.4.18;
|
||||||
|
|
||||||
|
import "@aragon/os/contracts/factory/DAOFactory.sol";
|
||||||
|
import "./LPVault.sol";
|
||||||
|
import "./LiquidPledging.sol";
|
||||||
|
|
||||||
|
contract LPFactory is DAOFactory {
|
||||||
|
address public vaultBase;
|
||||||
|
address public lpBase;
|
||||||
|
|
||||||
|
bytes32 constant public VAULT_APP_ID = keccak256("vault");
|
||||||
|
bytes32 constant public LP_APP_ID = keccak256("liquidPledging");
|
||||||
|
|
||||||
|
event DeployVault(address vault);
|
||||||
|
event DeployLiquidPledging(address liquidPledging);
|
||||||
|
|
||||||
|
function LPFactory(address _vaultBase, address _lpBase) public DAOFactory(0) {
|
||||||
|
require(_vaultBase != 0);
|
||||||
|
require(_lpBase != 0);
|
||||||
|
vaultBase = _vaultBase;
|
||||||
|
lpBase = _lpBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
function newLP(address _root, address _escapeHatchDestination) public {
|
||||||
|
Kernel kernel = newDAO(this);
|
||||||
|
ACL acl = ACL(kernel.acl());
|
||||||
|
|
||||||
|
bytes32 appManagerRole = kernel.APP_MANAGER_ROLE();
|
||||||
|
|
||||||
|
acl.createPermission(this, address(kernel), appManagerRole, this);
|
||||||
|
|
||||||
|
LPVault v = LPVault(kernel.newAppInstance(VAULT_APP_ID, vaultBase));
|
||||||
|
LiquidPledging lp = LiquidPledging(kernel.newAppInstance(LP_APP_ID, lpBase));
|
||||||
|
v.initialize(address(lp), _escapeHatchDestination);
|
||||||
|
lp.initialize(address(v), _escapeHatchDestination);
|
||||||
|
|
||||||
|
_setPermissions(_root, acl, kernel, v, lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _setPermissions(address _root, ACL acl, Kernel kernel, LPVault v, LiquidPledging lp) internal {
|
||||||
|
bytes32 appManagerRole = kernel.APP_MANAGER_ROLE();
|
||||||
|
bytes32 permRole = acl.CREATE_PERMISSIONS_ROLE();
|
||||||
|
bytes32 hatchCallerRole = v.ESCAPE_HATCH_CALLER_ROLE();
|
||||||
|
bytes32 authPaymentRole = v.AUTHORIZE_PAYMENT_ROLE();
|
||||||
|
bytes32 pledgeAdminRole = lp.PLEDGE_ADMIN_ROLE();
|
||||||
|
bytes32 pluginManagerRole = lp.PLUGIN_MANAGER_ROLE();
|
||||||
|
|
||||||
|
acl.createPermission(_root, address(v), hatchCallerRole, _root);
|
||||||
|
acl.createPermission(_root, address(lp), hatchCallerRole, _root);
|
||||||
|
acl.createPermission(_root, address(lp), pluginManagerRole, _root);
|
||||||
|
acl.createPermission(address(lp), address(v), authPaymentRole, _root);
|
||||||
|
acl.createPermission(0x0, address(lp), pledgeAdminRole, address(lp));
|
||||||
|
// TODO: set pledgeAdminRole manager to 0x0? maybe it doesn't matter b/c it can be recreated by _root anyways
|
||||||
|
|
||||||
|
acl.grantPermission(_root, address(kernel), appManagerRole);
|
||||||
|
acl.grantPermission(_root, address(acl), permRole);
|
||||||
|
acl.revokePermission(this, address(kernel), appManagerRole);
|
||||||
|
acl.revokePermission(this, address(acl), permRole);
|
||||||
|
|
||||||
|
acl.setPermissionManager(_root, address(kernel), appManagerRole);
|
||||||
|
acl.setPermissionManager(_root, address(acl), permRole);
|
||||||
|
|
||||||
|
DeployVault(address(v));
|
||||||
|
DeployLiquidPledging(address(lp));
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,28 +27,41 @@ pragma solidity ^0.4.11;
|
||||||
/// be a safe place to store funds equipped with optional variable time delays
|
/// be a safe place to store funds equipped with optional variable time delays
|
||||||
/// to allow for an optional escapeHatch to be implemented in case of issues;
|
/// to allow for an optional escapeHatch to be implemented in case of issues;
|
||||||
/// future versions of this contract will be enabled for tokens
|
/// future versions of this contract will be enabled for tokens
|
||||||
import "giveth-common-contracts/contracts/Escapable.sol";
|
import "./EscapableApp.sol";
|
||||||
|
|
||||||
/// @dev `LiquidPledging` is a basic interface to allow the `LPVault` contract
|
/// @dev `LiquidPledging` is a basic interface to allow the `LPVault` contract
|
||||||
/// to confirm and cancel payments in the `LiquidPledging` contract.
|
/// to confirm and cancel payments in the `LiquidPledging` contract.
|
||||||
contract LiquidPledging {
|
contract ILiquidPledging {
|
||||||
function confirmPayment(uint64 idPledge, uint amount) public;
|
function confirmPayment(uint64 idPledge, uint amount) public;
|
||||||
function cancelPayment(uint64 idPledge, uint amount) public;
|
function cancelPayment(uint64 idPledge, uint amount) public;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @dev `LPVault` is a higher level contract built off of the `Escapable`
|
/// @dev `LPVault` is a higher level contract built off of the `Escapable`
|
||||||
/// contract that holds funds for the liquid pledging system.
|
/// contract that holds funds for the liquid pledging system.
|
||||||
contract LPVault is Escapable {
|
contract LPVault is EscapableApp {
|
||||||
|
|
||||||
LiquidPledging public liquidPledging; // LiquidPledging contract's address
|
bytes32 constant public CONFIRM_PAYMENT_ROLE = bytes32(1);
|
||||||
bool public autoPay; // If false, payments will take 2 txs to be completed
|
bytes32 constant public CANCEL_PAYMENT_ROLE = bytes32(2);
|
||||||
|
bytes32 constant public AUTHORIZE_PAYMENT_ROLE = bytes32(3);
|
||||||
|
bytes32 constant public SET_AUTOPAY_ROLE = bytes32(4);
|
||||||
|
|
||||||
|
event AutoPaySet(bool autoPay);
|
||||||
|
event EscapeFundsCalled(address token, uint amount);
|
||||||
|
event ConfirmPayment(uint indexed idPayment, bytes32 indexed ref);
|
||||||
|
event CancelPayment(uint indexed idPayment, bytes32 indexed ref);
|
||||||
|
event AuthorizePayment(
|
||||||
|
uint indexed idPayment,
|
||||||
|
bytes32 indexed ref,
|
||||||
|
address indexed dest,
|
||||||
|
uint amount
|
||||||
|
);
|
||||||
|
|
||||||
enum PaymentStatus {
|
enum PaymentStatus {
|
||||||
Pending, // When the payment is awaiting confirmation
|
Pending, // When the payment is awaiting confirmation
|
||||||
Paid, // When the payment has been sent
|
Paid, // When the payment has been sent
|
||||||
Canceled // When the payment will never be sent
|
Canceled // When the payment will never be sent
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev `Payment` is a public structure that describes the details of
|
/// @dev `Payment` is a public structure that describes the details of
|
||||||
/// each payment the `ref` param makes it easy to track the movements of
|
/// each payment the `ref` param makes it easy to track the movements of
|
||||||
/// funds transparently by its connection to other `Payment` structs
|
/// funds transparently by its connection to other `Payment` structs
|
||||||
|
@ -59,13 +72,11 @@ contract LPVault is Escapable {
|
||||||
uint amount; // amount of ETH (in wei) to be sent
|
uint amount; // amount of ETH (in wei) to be sent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool public autoPay; // If false, payments will take 2 txs to be completed
|
||||||
|
|
||||||
// @dev An array that contains all the payments for this LPVault
|
// @dev An array that contains all the payments for this LPVault
|
||||||
Payment[] public payments;
|
Payment[] public payments;
|
||||||
|
ILiquidPledging public liquidPledging;
|
||||||
function LPVault(address _escapeHatchCaller, address _escapeHatchDestination)
|
|
||||||
Escapable(_escapeHatchCaller, _escapeHatchDestination) public
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev The attached `LiquidPledging` contract is the only address that can
|
/// @dev The attached `LiquidPledging` contract is the only address that can
|
||||||
/// call a function with this modifier
|
/// call a function with this modifier
|
||||||
|
@ -74,31 +85,39 @@ contract LPVault is Escapable {
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initialize(address _escapeHatchDestination) onlyInit external {
|
||||||
|
require(false); // overload the EscapableApp
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @param _liquidPledging
|
||||||
|
/// @param _escapeHatchDestination The address of a safe location (usu a
|
||||||
|
/// Multisig) to send the ether held in this contract; if a neutral address
|
||||||
|
/// is required, the WHG Multisig is an option:
|
||||||
|
/// 0x8Ff920020c8AD673661c8117f2855C384758C572
|
||||||
|
function initialize(address _liquidPledging, address _escapeHatchDestination) onlyInit external {
|
||||||
|
initialized();
|
||||||
|
require(_escapeHatchDestination != 0x0);
|
||||||
|
require(_liquidPledging != 0x0);
|
||||||
|
|
||||||
|
escapeHatchDestination = _escapeHatchDestination;
|
||||||
|
liquidPledging = ILiquidPledging(_liquidPledging);
|
||||||
|
}
|
||||||
|
|
||||||
/// @dev The fall back function allows ETH to be deposited into the LPVault
|
/// @dev The fall back function allows ETH to be deposited into the LPVault
|
||||||
/// through a simple send
|
/// through a simple send
|
||||||
function () public payable {}
|
function () public payable {}
|
||||||
|
|
||||||
/// @notice `onlyOwner` used to attach a specific liquidPledging instance
|
|
||||||
/// to this LPvault; keep in mind that once a liquidPledging contract is
|
|
||||||
/// attached it cannot be undone, this vault will be forever connected
|
|
||||||
/// @param _newLiquidPledging A full liquid pledging contract
|
|
||||||
function setLiquidPledging(address _newLiquidPledging) public onlyOwner {
|
|
||||||
require(address(liquidPledging) == 0x0);
|
|
||||||
liquidPledging = LiquidPledging(_newLiquidPledging);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @notice Used to decentralize, toggles whether the LPVault will
|
/// @notice Used to decentralize, toggles whether the LPVault will
|
||||||
/// automatically confirm a payment after the payment has been authorized
|
/// automatically confirm a payment after the payment has been authorized
|
||||||
/// @param _automatic If true, payments will confirm instantly, if false
|
/// @param _automatic If true, payments will confirm instantly, if false
|
||||||
/// the training wheels are put on and the owner must manually approve
|
/// the training wheels are put on and the owner must manually approve
|
||||||
/// every payment
|
/// every payment
|
||||||
function setAutopay(bool _automatic) public onlyOwner {
|
function setAutopay(bool _automatic) external authP(SET_AUTOPAY_ROLE, ar(_automatic)) {
|
||||||
autoPay = _automatic;
|
autoPay = _automatic;
|
||||||
AutoPaySet();
|
AutoPaySet(autoPay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice `onlyLiquidPledging` authorizes payments from this contract, if
|
/// @notice If `autoPay == true` the transfer happens automatically `else` the `owner`
|
||||||
/// `autoPay == true` the transfer happens automatically `else` the `owner`
|
|
||||||
/// must call `confirmPayment()` for a transfer to occur (training wheels);
|
/// must call `confirmPayment()` for a transfer to occur (training wheels);
|
||||||
/// either way, a new payment is added to `payments[]`
|
/// either way, a new payment is added to `payments[]`
|
||||||
/// @param _ref References the payment will normally be the pledgeID
|
/// @param _ref References the payment will normally be the pledgeID
|
||||||
|
@ -109,7 +128,7 @@ contract LPVault is Escapable {
|
||||||
bytes32 _ref,
|
bytes32 _ref,
|
||||||
address _dest,
|
address _dest,
|
||||||
uint _amount
|
uint _amount
|
||||||
) public onlyLiquidPledging returns (uint)
|
) external authP(AUTHORIZE_PAYMENT_ROLE, arr(_dest, _amount)) returns (uint)
|
||||||
{
|
{
|
||||||
uint idPayment = payments.length;
|
uint idPayment = payments.length;
|
||||||
payments.length ++;
|
payments.length ++;
|
||||||
|
@ -132,51 +151,20 @@ contract LPVault is Escapable {
|
||||||
/// this is generally used when `autopay` is `false` after a payment has
|
/// this is generally used when `autopay` is `false` after a payment has
|
||||||
/// has been authorized
|
/// has been authorized
|
||||||
/// @param _idPayment Array lookup for the payment.
|
/// @param _idPayment Array lookup for the payment.
|
||||||
function confirmPayment(uint _idPayment) public onlyOwner {
|
function confirmPayment(uint _idPayment) public {
|
||||||
doConfirmPayment(_idPayment);
|
doConfirmPayment(_idPayment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Transfers ETH according to the data held within the specified
|
|
||||||
/// payment id (internal function)
|
|
||||||
/// @param _idPayment id number for the payment about to be fulfilled
|
|
||||||
function doConfirmPayment(uint _idPayment) internal {
|
|
||||||
require(_idPayment < payments.length);
|
|
||||||
Payment storage p = payments[_idPayment];
|
|
||||||
require(p.state == PaymentStatus.Pending);
|
|
||||||
|
|
||||||
p.state = PaymentStatus.Paid;
|
|
||||||
liquidPledging.confirmPayment(uint64(p.ref), p.amount);
|
|
||||||
|
|
||||||
p.dest.transfer(p.amount); // Transfers ETH denominated in wei
|
|
||||||
|
|
||||||
ConfirmPayment(_idPayment, p.ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @notice When `autopay` is `false` and after a payment has been authorized
|
/// @notice When `autopay` is `false` and after a payment has been authorized
|
||||||
/// to allow the owner to cancel a payment instead of confirming it.
|
/// to allow the owner to cancel a payment instead of confirming it.
|
||||||
/// @param _idPayment Array lookup for the payment.
|
/// @param _idPayment Array lookup for the payment.
|
||||||
function cancelPayment(uint _idPayment) public onlyOwner {
|
function cancelPayment(uint _idPayment) public {
|
||||||
doCancelPayment(_idPayment);
|
doCancelPayment(_idPayment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Cancels a pending payment (internal function)
|
|
||||||
/// @param _idPayment id number for the payment
|
|
||||||
function doCancelPayment(uint _idPayment) internal {
|
|
||||||
require(_idPayment < payments.length);
|
|
||||||
Payment storage p = payments[_idPayment];
|
|
||||||
require(p.state == PaymentStatus.Pending);
|
|
||||||
|
|
||||||
p.state = PaymentStatus.Canceled;
|
|
||||||
|
|
||||||
liquidPledging.cancelPayment(uint64(p.ref), p.amount);
|
|
||||||
|
|
||||||
CancelPayment(_idPayment, p.ref);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @notice `onlyOwner` An efficient way to confirm multiple payments
|
/// @notice `onlyOwner` An efficient way to confirm multiple payments
|
||||||
/// @param _idPayments An array of multiple payment ids
|
/// @param _idPayments An array of multiple payment ids
|
||||||
function multiConfirm(uint[] _idPayments) public onlyOwner {
|
function multiConfirm(uint[] _idPayments) external {
|
||||||
for (uint i = 0; i < _idPayments.length; i++) {
|
for (uint i = 0; i < _idPayments.length; i++) {
|
||||||
doConfirmPayment(_idPayments[i]);
|
doConfirmPayment(_idPayments[i]);
|
||||||
}
|
}
|
||||||
|
@ -184,23 +172,18 @@ contract LPVault is Escapable {
|
||||||
|
|
||||||
/// @notice `onlyOwner` An efficient way to cancel multiple payments
|
/// @notice `onlyOwner` An efficient way to cancel multiple payments
|
||||||
/// @param _idPayments An array of multiple payment ids
|
/// @param _idPayments An array of multiple payment ids
|
||||||
function multiCancel(uint[] _idPayments) public onlyOwner {
|
function multiCancel(uint[] _idPayments) external {
|
||||||
for (uint i = 0; i < _idPayments.length; i++) {
|
for (uint i = 0; i < _idPayments.length; i++) {
|
||||||
doCancelPayment(_idPayments[i]);
|
doCancelPayment(_idPayments[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return The total number of payments that have ever been authorized
|
|
||||||
function nPayments() constant public returns (uint) {
|
|
||||||
return payments.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transfer eth or tokens to the escapeHatchDestination.
|
/// Transfer eth or tokens to the escapeHatchDestination.
|
||||||
/// Used as a safety mechanism to prevent the vault from holding too much value
|
/// Used as a safety mechanism to prevent the vault from holding too much value
|
||||||
/// before being thoroughly battle-tested.
|
/// before being thoroughly battle-tested.
|
||||||
/// @param _token to transfer, use 0x0 for ether
|
/// @param _token to transfer, use 0x0 for ether
|
||||||
/// @param _amount to transfer
|
/// @param _amount to transfer
|
||||||
function escapeFunds(address _token, uint _amount) public onlyOwner {
|
function escapeFunds(address _token, uint _amount) public authP(ESCAPE_HATCH_CALLER_ROLE, arr(_token)) {
|
||||||
/// @dev Logic for ether
|
/// @dev Logic for ether
|
||||||
if (_token == 0x0) {
|
if (_token == 0x0) {
|
||||||
require(this.balance >= _amount);
|
require(this.balance >= _amount);
|
||||||
|
@ -216,14 +199,48 @@ contract LPVault is Escapable {
|
||||||
EscapeFundsCalled(_token, _amount);
|
EscapeFundsCalled(_token, _amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
event AutoPaySet();
|
/// @return The total number of payments that have ever been authorized
|
||||||
event EscapeFundsCalled(address token, uint amount);
|
function nPayments() public view returns (uint) {
|
||||||
event ConfirmPayment(uint indexed idPayment, bytes32 indexed ref);
|
return payments.length;
|
||||||
event CancelPayment(uint indexed idPayment, bytes32 indexed ref);
|
}
|
||||||
event AuthorizePayment(
|
|
||||||
uint indexed idPayment,
|
/// @notice Transfers ETH according to the data held within the specified
|
||||||
bytes32 indexed ref,
|
/// payment id (internal function)
|
||||||
address indexed dest,
|
/// @param _idPayment id number for the payment about to be fulfilled
|
||||||
uint amount
|
function doConfirmPayment(uint _idPayment) internal {
|
||||||
);
|
require(_idPayment < payments.length);
|
||||||
|
Payment storage p = payments[_idPayment];
|
||||||
|
require(p.state == PaymentStatus.Pending);
|
||||||
|
require(canPerform(msg.sender, CONFIRM_PAYMENT_ROLE, arr(_idPayment, p.amount)));
|
||||||
|
|
||||||
|
p.state = PaymentStatus.Paid;
|
||||||
|
liquidPledging.confirmPayment(uint64(p.ref), p.amount);
|
||||||
|
|
||||||
|
p.dest.transfer(p.amount); // Transfers ETH denominated in wei
|
||||||
|
|
||||||
|
ConfirmPayment(_idPayment, p.ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @notice Cancels a pending payment (internal function)
|
||||||
|
/// @param _idPayment id number for the payment
|
||||||
|
function doCancelPayment(uint _idPayment) internal authP(CANCEL_PAYMENT_ROLE, arr(_idPayment)) {
|
||||||
|
require(_idPayment < payments.length);
|
||||||
|
Payment storage p = payments[_idPayment];
|
||||||
|
require(p.state == PaymentStatus.Pending);
|
||||||
|
|
||||||
|
p.state = PaymentStatus.Canceled;
|
||||||
|
|
||||||
|
liquidPledging.cancelPayment(uint64(p.ref), p.amount);
|
||||||
|
|
||||||
|
CancelPayment(_idPayment, p.ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ar(bool a) internal pure returns (uint256[] r) {
|
||||||
|
r = new uint256[](1);
|
||||||
|
uint _a;
|
||||||
|
assembly {
|
||||||
|
_a := a // forced casting
|
||||||
|
}
|
||||||
|
r[0] = _a;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,13 +36,8 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// LiquidPledgingBase contract
|
/// LiquidPledgingBase contract
|
||||||
/// @dev This constructor also calls the constructor
|
/// @dev This constructor also calls the constructor
|
||||||
/// for `LiquidPledgingBase`
|
/// for `LiquidPledgingBase`
|
||||||
/// @param _vault The vault where ETH backing this pledge is stored
|
function LiquidPledging()
|
||||||
function LiquidPledging(
|
LiquidPledgingBase() public
|
||||||
address _storage,
|
|
||||||
address _vault,
|
|
||||||
address _escapeHatchCaller,
|
|
||||||
address _escapeHatchDestination
|
|
||||||
) LiquidPledgingBase(_storage, _vault, _escapeHatchCaller, _escapeHatchDestination) public
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,23 +49,24 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// @param idGiver The id of the Giver donating; if 0, a new id is created
|
/// @param idGiver The id of the Giver donating; if 0, a new id is created
|
||||||
/// @param idReceiver The Admin receiving the donation; can be any Admin:
|
/// @param idReceiver The Admin receiving the donation; can be any Admin:
|
||||||
/// the Giver themselves, another Giver, a Delegate or a Project
|
/// the Giver themselves, another Giver, a Delegate or a Project
|
||||||
function donate(uint64 idGiver, uint64 idReceiver) public payable {
|
function donate(uint64 idGiver, uint64 idReceiver) authP(PLEDGE_ADMIN_ROLE, arr(uint(idGiver)))
|
||||||
|
public payable
|
||||||
|
{
|
||||||
|
// TODO: maybe need a separate role here to allow giver creation
|
||||||
if (idGiver == 0) {
|
if (idGiver == 0) {
|
||||||
|
|
||||||
// default to a 3 day (259200 seconds) commitTime
|
// default to a 3 day (259200 seconds) commitTime
|
||||||
idGiver = uint64(addGiver("", "", 259200, ILiquidPledgingPlugin(0x0)));
|
idGiver = uint64(addGiver("", "", 259200, ILiquidPledgingPlugin(0x0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
checkAdminOwner(idGiver);
|
PledgeAdmins.PledgeAdmin storage sender = _findAdmin(idGiver);
|
||||||
|
// _checkAdminOwner(sender);
|
||||||
PledgeAdminType adminType = getAdminType(idGiver);
|
require(sender.adminType == PledgeAdminType.Giver);
|
||||||
require(adminType == PledgeAdminType.Giver);
|
|
||||||
|
|
||||||
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`
|
||||||
|
|
||||||
Pledges.Pledge memory p = findOrCreatePledge(
|
uint64 idPledge = _findOrCreatePledge(
|
||||||
idGiver,
|
idGiver,
|
||||||
new uint64[](0), // Creates empty array for delegationChain
|
new uint64[](0), // Creates empty array for delegationChain
|
||||||
0,
|
0,
|
||||||
|
@ -79,13 +75,12 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
Pledges.PledgeState.Pledged
|
Pledges.PledgeState.Pledged
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Pledges.Pledge storage pTo = _findPledge(idPledge);
|
||||||
|
pTo.amount += amount;
|
||||||
|
|
||||||
p.amount += amount;
|
Transfer(0, idPledge, amount); // An event
|
||||||
setPledgeAmount(p.id, p.amount);
|
|
||||||
|
|
||||||
Transfer(0, p.id, amount); // An event
|
transfer(idGiver, idPledge, amount, idReceiver); // LP accounting
|
||||||
|
|
||||||
transfer(idGiver, uint64(p.id), amount, idReceiver); // LP accounting
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Transfers amounts between pledges for internal accounting
|
/// @notice Transfers amounts between pledges for internal accounting
|
||||||
|
@ -102,52 +97,53 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
uint64 idPledge,
|
uint64 idPledge,
|
||||||
uint amount,
|
uint amount,
|
||||||
uint64 idReceiver
|
uint64 idReceiver
|
||||||
) public
|
) authP(PLEDGE_ADMIN_ROLE, arr(uint(idSender), amount)) public
|
||||||
{
|
{
|
||||||
checkAdminOwner(idSender);
|
idPledge = normalizePledge(idPledge);
|
||||||
|
|
||||||
Pledges.Pledge memory p = normalizePledge(idPledge);
|
Pledges.Pledge storage p = _findPledge(idPledge);
|
||||||
|
PledgeAdmins.PledgeAdmin storage receiver = _findAdmin(idReceiver);
|
||||||
|
// PledgeAdmins.PledgeAdmin storage sender = _findAdmin(idSender);
|
||||||
|
|
||||||
PledgeAdminType receiverAdminType = getAdminType(idReceiver);
|
// _checkAdminOwner(sender);
|
||||||
|
require(p.pledgeState == PledgeState.Pledged);
|
||||||
require(p.pledgeState == Pledges.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 (receiverAdminType == PledgeAdminType.Giver) {
|
if (receiver.adminType == PledgeAdmins.PledgeAdminType.Giver) {
|
||||||
transferOwnershipToGiver(p, amount, idReceiver);
|
_transferOwnershipToGiver(idPledge, amount, idReceiver);
|
||||||
} else if (receiverAdminType == PledgeAdminType.Project) {
|
} else if (receiver.adminType == PledgeAdmins.PledgeAdminType.Project) {
|
||||||
transferOwnershipToProject(p, amount, idReceiver);
|
_transferOwnershipToProject(idPledge, amount, idReceiver);
|
||||||
} else if (receiverAdminType == PledgeAdminType.Delegate) {
|
} else if (receiver.adminType == 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) {
|
||||||
// if there is an intendedProject and the receiver is in the delegationChain,
|
// if there is an intendedProject and the receiver is in the delegationChain,
|
||||||
// then we want to preserve the delegationChain as this is a veto of the
|
// then we want to preserve the delegationChain as this is a veto of the
|
||||||
// intendedProject by the owner
|
// intendedProject by the owner
|
||||||
|
|
||||||
if (recieverDIdx == p.delegationChain.length - 1) {
|
if (recieverDIdx == p.delegationChain.length - 1) {
|
||||||
Pledges.Pledge memory toPledge = findOrCreatePledge(
|
uint64 toPledge = _findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
p.delegationChain,
|
p.delegationChain,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
p.oldPledge,
|
p.oldPledge,
|
||||||
Pledges.PledgeState.Pledged);
|
Pledges.PledgeState.Pledged);
|
||||||
doTransfer(p, toPledge, amount);
|
_doTransfer(idPledge, toPledge, amount);
|
||||||
} else {
|
} else {
|
||||||
undelegate(p, amount, p.delegationChain.length - receiverDIdx - 1);
|
_undelegate(idPledge, amount, p.delegationChain.length - receiverDIdx - 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// owner is not vetoing an intendedProject and is transferring the pledge to a delegate,
|
// owner is not vetoing an intendedProject and is transferring the pledge to a delegate,
|
||||||
// so we want to reset the delegationChain
|
// so we want to reset the delegationChain
|
||||||
p = undelegate(
|
idPledge = _undelegate(
|
||||||
p,
|
idPledge,
|
||||||
amount,
|
amount,
|
||||||
p.delegationChain.length
|
p.delegationChain.length
|
||||||
);
|
);
|
||||||
appendDelegate(p, amount, idReceiver);
|
_appendDelegate(idPledge, amount, idReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -159,47 +155,47 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the sender is a Delegate
|
// If the sender is a Delegate
|
||||||
uint senderDIdx = getDelegateIdx(p, idSender);
|
uint senderDIdx = _getDelegateIdx(p, idSender);
|
||||||
if (senderDIdx != NOTFOUND) {
|
if (senderDIdx != NOTFOUND) {
|
||||||
|
|
||||||
// And the receiver is another Giver
|
// And the receiver is another Giver
|
||||||
if (receiverAdminType == PledgeAdminType.Giver) {
|
if (receiver.adminType == 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(p, amount, p.delegationChain.length);
|
_undelegate(idPledge, amount, p.delegationChain.length);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// And the receiver is another Delegate
|
// And the receiver is another Delegate
|
||||||
if (receiverAdminType == PledgeAdminType.Delegate) {
|
if (receiver.adminType == PledgeAdmins.PledgeAdminType.Delegate) {
|
||||||
uint receiverDIdx = getDelegateIdx(p, idReceiver);
|
uint receiverDIdx = _getDelegateIdx(p, idReceiver);
|
||||||
|
|
||||||
// And not in the delegationChain
|
// And not in the delegationChain
|
||||||
if (receiverDIdx == NOTFOUND) {
|
if (receiverDIdx == NOTFOUND) {
|
||||||
p = undelegate(
|
idPledge = _undelegate(
|
||||||
p,
|
idPledge,
|
||||||
amount,
|
amount,
|
||||||
p.delegationChain.length - senderDIdx - 1
|
p.delegationChain.length - senderDIdx - 1
|
||||||
);
|
);
|
||||||
appendDelegate(p, amount, idReceiver);
|
_appendDelegate(idPledge, amount, idReceiver);
|
||||||
|
|
||||||
// And part of the delegationChain and is after the sender, then
|
// And part of the delegationChain and is after the sender, then
|
||||||
// all of the other delegates after the sender are removed and
|
// all of the other delegates after the sender are removed and
|
||||||
// the receiver is appended at the end of the delegationChain
|
// the receiver is appended at the end of the delegationChain
|
||||||
} else if (receiverDIdx > senderDIdx) {
|
} else if (receiverDIdx > senderDIdx) {
|
||||||
p = undelegate(
|
idPledge = _undelegate(
|
||||||
p,
|
idPledge,
|
||||||
amount,
|
amount,
|
||||||
p.delegationChain.length - senderDIdx - 1
|
p.delegationChain.length - senderDIdx - 1
|
||||||
);
|
);
|
||||||
appendDelegate(p, amount, idReceiver);
|
_appendDelegate(idPledge, amount, idReceiver);
|
||||||
|
|
||||||
// And is already part of the delegate chain but is before the
|
// And is already part of the delegate chain but is before the
|
||||||
// sender, then the sender and all of the other delegates after
|
// sender, then the sender and all of the other delegates after
|
||||||
// the RECEIVER are removed from the delegationChain
|
// the RECEIVER are removed from the delegationChain
|
||||||
} else if (receiverDIdx <= senderDIdx) {//TODO Check for Game Theory issues (from Arthur) this allows the sender to sort of go komakosi and remove himself and the delegates between himself and the receiver... should this authority be allowed?
|
} else if (receiverDIdx <= senderDIdx) {//TODO Check for Game Theory issues (from Arthur) this allows the sender to sort of go komakosi and remove himself and the delegates between himself and the receiver... should this authority be allowed?
|
||||||
undelegate(
|
_undelegate(
|
||||||
p,
|
idPledge,
|
||||||
amount,
|
amount,
|
||||||
p.delegationChain.length - receiverDIdx - 1
|
p.delegationChain.length - receiverDIdx - 1
|
||||||
);
|
);
|
||||||
|
@ -209,13 +205,13 @@ 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 (receiverAdminType == PledgeAdminType.Project) {
|
if (receiver.adminType == PledgeAdmins.PledgeAdminType.Project) {
|
||||||
p = undelegate(
|
idPledge = _undelegate(
|
||||||
p,
|
idPledge,
|
||||||
amount,
|
amount,
|
||||||
p.delegationChain.length - senderDIdx - 1
|
p.delegationChain.length - senderDIdx - 1
|
||||||
);
|
);
|
||||||
proposeAssignProject(p, amount, idReceiver);
|
_proposeAssignProject(idPledge, amount, idReceiver);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,13 +223,16 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// intendedProject
|
/// intendedProject
|
||||||
/// @param idPledge Id of the pledge that is to be redeemed into ether
|
/// @param idPledge Id of the pledge that is to be redeemed into ether
|
||||||
/// @param amount Quantity of ether (in wei) to be authorized
|
/// @param amount Quantity of ether (in wei) to be authorized
|
||||||
function withdraw(uint64 idPledge, uint amount) public {
|
function withdraw(uint64 idPledge, uint amount) authP(PLEDGE_ADMIN_ROLE, arr(uint(idPledge), amount)) public {
|
||||||
Pledges.Pledge memory p = normalizePledge(idPledge); // Updates pledge info
|
idPledge = normalizePledge(idPledge); // Updates pledge info
|
||||||
// = findPledge(idPledge);
|
|
||||||
require(p.pledgeState == Pledges.PledgeState.Pledged);
|
|
||||||
checkAdminOwner(p.owner);
|
|
||||||
|
|
||||||
Pledges.Pledge memory newPledge = findOrCreatePledge(
|
Pledges.Pledge storage p = _findPledge(idPledge);
|
||||||
|
require(p.pledgeState == PledgeState.Pledged);
|
||||||
|
|
||||||
|
PledgeAdmins.PledgeAdmin storage owner = _findAdmin(p.owner);
|
||||||
|
// _checkAdminOwner(owner);
|
||||||
|
|
||||||
|
uint64 idNewPledge = _findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
p.delegationChain,
|
p.delegationChain,
|
||||||
0,
|
0,
|
||||||
|
@ -242,9 +241,9 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
Pledges.PledgeState.Paying
|
Pledges.PledgeState.Paying
|
||||||
);
|
);
|
||||||
|
|
||||||
doTransfer(p, newPledge, amount);
|
_doTransfer(idPledge, idNewPledge, amount);
|
||||||
|
|
||||||
vault.authorizePayment(bytes32(newPledge.id), getAdminAddr(p.owner), amount);
|
vault.authorizePayment(bytes32(idNewPledge), owner.addr, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice `onlyVault` Confirms a withdraw request changing the Pledges.PledgeState
|
/// @notice `onlyVault` Confirms a withdraw request changing the Pledges.PledgeState
|
||||||
|
@ -253,11 +252,11 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// @param amount Quantity of ether (in wei) to be withdrawn
|
/// @param amount Quantity of ether (in wei) to be withdrawn
|
||||||
function confirmPayment(uint64 idPledge, uint amount) public onlyVault {
|
function confirmPayment(uint64 idPledge, uint amount) public onlyVault {
|
||||||
//TODO don't fetch entire pledge
|
//TODO don't fetch entire pledge
|
||||||
Pledges.Pledge memory p = findPledge(idPledge);
|
Pledges.Pledge storage p = _findPledge(idPledge);
|
||||||
|
|
||||||
require(p.pledgeState == Pledges.PledgeState.Paying);
|
require(p.pledgeState == Pledges.PledgeState.Paying);
|
||||||
|
|
||||||
Pledges.Pledge memory newPledge = findOrCreatePledge(
|
uint64 idNewPledge = _findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
p.delegationChain,
|
p.delegationChain,
|
||||||
0,
|
0,
|
||||||
|
@ -266,7 +265,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
Pledges.PledgeState.Paid
|
Pledges.PledgeState.Paid
|
||||||
);
|
);
|
||||||
|
|
||||||
doTransfer(p, newPledge, amount);
|
_doTransfer(idPledge, idNewPledge, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice `onlyVault` Cancels a withdraw request, changing the Pledges.PledgeState
|
/// @notice `onlyVault` Cancels a withdraw request, changing the Pledges.PledgeState
|
||||||
|
@ -274,12 +273,12 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// @param idPledge Id of the pledge that's withdraw is to be canceled
|
/// @param idPledge Id of the pledge that's withdraw is to be canceled
|
||||||
/// @param amount Quantity of ether (in wei) to be canceled
|
/// @param amount Quantity of ether (in wei) to be canceled
|
||||||
function cancelPayment(uint64 idPledge, uint amount) public onlyVault {
|
function cancelPayment(uint64 idPledge, uint amount) public onlyVault {
|
||||||
Pledges.Pledge memory p = findPledge(idPledge);
|
Pledges.Pledge storage p = _findPledge(idPledge);
|
||||||
|
|
||||||
require(p.pledgeState == Pledges.PledgeState.Paying);
|
require(p.pledgeState == Pledges.PledgeState.Paying);
|
||||||
|
|
||||||
// When a payment is canceled, never is assigned to a project.
|
// When a payment is canceled, never is assigned to a project.
|
||||||
Pledges.Pledge memory oldPledge = findOrCreatePledge(
|
uint64 idOldPledge = _findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
p.delegationChain,
|
p.delegationChain,
|
||||||
0,
|
0,
|
||||||
|
@ -288,17 +287,18 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
Pledges.PledgeState.Pledged
|
Pledges.PledgeState.Pledged
|
||||||
);
|
);
|
||||||
|
|
||||||
oldPledge = _normalizePledge(oldPledge);
|
idOldPledge = normalizePledge(idOldPledge);
|
||||||
|
|
||||||
doTransfer(p, oldPledge, amount);
|
_doTransfer(idPledge, idOldPledge, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @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) authP(PLEDGE_ADMIN_ROLE, arr(uint(idProject))) public {
|
||||||
checkAdminOwner(idProject);
|
PledgeAdmins.PledgeAdmin storage project = _findAdmin(idProject);
|
||||||
|
// _checkAdminOwner(project);
|
||||||
|
project.canceled = true;
|
||||||
|
|
||||||
_storage.stgObjectSetBoolean(PLEDGE_ADMIN, idProject, "canceled", true);
|
|
||||||
CancelProject(idProject);
|
CancelProject(idProject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,19 +307,17 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// @param idPledge Id of the pledge that is to be canceled
|
/// @param idPledge Id of the pledge that is to be canceled
|
||||||
/// @param amount Quantity of ether (in wei) to be transfered to the
|
/// @param amount Quantity of ether (in wei) to be transfered to the
|
||||||
/// `oldPledge`
|
/// `oldPledge`
|
||||||
function cancelPledge(uint64 idPledge, uint amount) public {
|
function cancelPledge(uint64 idPledge, uint amount) authP(PLEDGE_ADMIN_ROLE, arr(uint(idPledge))) public {
|
||||||
//TODO fetch idPledge? OR return Pledge from this call?
|
idPledge = normalizePledge(idPledge);
|
||||||
// idPledge = normalizePledge(idPledge);
|
|
||||||
|
|
||||||
// Pledges.Pledge memory p = findPledge(idPledge);
|
Pledges.Pledge storage p = _findPledge(idPledge);
|
||||||
Pledges.Pledge memory p = normalizePledge(idPledge);
|
|
||||||
require(p.oldPledge != 0);
|
require(p.oldPledge != 0);
|
||||||
|
|
||||||
checkAdminOwner(p.owner);
|
// PledgeAdmins.PledgeAdmin storage a = _findAdmin(p.owner);
|
||||||
|
// _checkAdminOwner(a);
|
||||||
|
|
||||||
uint64 oldPledgeId = getOldestPledgeNotCanceled(p.oldPledge);
|
uint64 oldPledge = _getOldestPledgeNotCanceled(p.oldPledge);
|
||||||
Pledges.Pledge memory oldPledge = findPledge(oldPledgeId);
|
_doTransfer(idPledge, oldPledge, amount);
|
||||||
doTransfer(p, oldPledge, amount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -414,21 +412,23 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// @notice `transferOwnershipToProject` allows for the transfer of
|
/// @notice `transferOwnershipToProject` allows for the transfer of
|
||||||
/// ownership to the project, but it can also be called by a project
|
/// ownership to the project, but it can also be called by a project
|
||||||
/// to un-delegate everyone by setting one's own id for the idReceiver
|
/// to un-delegate everyone by setting one's own id for the idReceiver
|
||||||
/// @param p the pledge to be transfered.
|
/// @param idPledge the id of the pledge to be transfered.
|
||||||
/// @param amount Quantity of value that's being transfered
|
/// @param amount Quantity of value that's being transfered
|
||||||
/// @param idReceiver The new owner of the project (or self to un-delegate)
|
/// @param idReceiver The new owner of the project (or self to un-delegate)
|
||||||
function transferOwnershipToProject(
|
function _transferOwnershipToProject(
|
||||||
Pledges.Pledge p,
|
uint64 idPledge,
|
||||||
uint amount,
|
uint amount,
|
||||||
uint64 idReceiver
|
uint64 idReceiver
|
||||||
) internal
|
) internal
|
||||||
{
|
{
|
||||||
|
Pledges.Pledge storage p = _findPledge(idPledge);
|
||||||
|
|
||||||
// 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.oldPledge) < MAX_INTERPROJECT_LEVEL);
|
require(_getPledgeLevel(p) < MAX_INTERPROJECT_LEVEL);
|
||||||
require(!isProjectCanceled(idReceiver));
|
require(!_isProjectCanceled(idReceiver));
|
||||||
|
|
||||||
Pledges.Pledge memory oldPledge = findOrCreatePledge(
|
uint64 oldPledge = _findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
p.delegationChain,
|
p.delegationChain,
|
||||||
0,
|
0,
|
||||||
|
@ -436,31 +436,31 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
p.oldPledge,
|
p.oldPledge,
|
||||||
Pledges.PledgeState.Pledged
|
Pledges.PledgeState.Pledged
|
||||||
);
|
);
|
||||||
Pledges.Pledge memory toPledge = findOrCreatePledge(
|
uint64 toPledge = _findOrCreatePledge(
|
||||||
idReceiver, // Set the new owner
|
idReceiver, // Set the new owner
|
||||||
new uint64[](0), // clear the delegation chain
|
new uint64[](0), // clear the delegation chain
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
uint64(oldPledge.id),
|
uint64(oldPledge),
|
||||||
Pledges.PledgeState.Pledged
|
Pledges.PledgeState.Pledged
|
||||||
);
|
);
|
||||||
doTransfer(p, toPledge, amount);
|
_doTransfer(idPledge, toPledge, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @notice `transferOwnershipToGiver` allows for the transfer of
|
/// @notice `transferOwnershipToGiver` allows for the transfer of
|
||||||
/// value back to the Giver, value is placed in a pledged state
|
/// value back to the Giver, value is placed in a pledged state
|
||||||
/// without being attached to a project, delegation chain, or time line.
|
/// without being attached to a project, delegation chain, or time line.
|
||||||
/// @param p the pledge to be transfered.
|
/// @param idPledge the id of the pledge to be transfered.
|
||||||
/// @param amount Quantity of value that's being transfered
|
/// @param amount Quantity of value that's being transfered
|
||||||
/// @param idReceiver The new owner of the pledge
|
/// @param idReceiver The new owner of the pledge
|
||||||
function transferOwnershipToGiver(
|
function _transferOwnershipToGiver(
|
||||||
Pledges.Pledge p,
|
uint64 idPledge,
|
||||||
uint amount,
|
uint amount,
|
||||||
uint64 idReceiver
|
uint64 idReceiver
|
||||||
) internal
|
) internal
|
||||||
{
|
{
|
||||||
Pledges.Pledge memory toPledge = findOrCreatePledge(
|
uint64 toPledge = _findOrCreatePledge(
|
||||||
idReceiver,
|
idReceiver,
|
||||||
new uint64[](0),
|
new uint64[](0),
|
||||||
0,
|
0,
|
||||||
|
@ -468,32 +468,34 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
0,
|
0,
|
||||||
Pledges.PledgeState.Pledged
|
Pledges.PledgeState.Pledged
|
||||||
);
|
);
|
||||||
doTransfer(p, toPledge, amount);
|
_doTransfer(idPledge, toPledge, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice `appendDelegate` allows for a delegate to be added onto the
|
/// @notice `appendDelegate` allows for a delegate to be added onto the
|
||||||
/// end of the delegate chain for a given Pledge.
|
/// end of the delegate chain for a given Pledge.
|
||||||
/// @param p the pledge thats delegate chain will be modified.
|
/// @param idPledge the id of the pledge thats delegate chain will be modified.
|
||||||
/// @param amount Quantity of value that's being chained.
|
/// @param amount Quantity of value that's being chained.
|
||||||
/// @param idReceiver The delegate to be added at the end of the chain
|
/// @param idReceiver The delegate to be added at the end of the chain
|
||||||
function appendDelegate(
|
function _appendDelegate(
|
||||||
Pledges.Pledge p,
|
uint64 idPledge,
|
||||||
uint amount,
|
uint amount,
|
||||||
uint64 idReceiver
|
uint64 idReceiver
|
||||||
) internal
|
) internal
|
||||||
{
|
{
|
||||||
|
Pledges.Pledge storage p = _findPledge(idPledge);
|
||||||
|
|
||||||
require(p.delegationChain.length < MAX_DELEGATES);
|
require(p.delegationChain.length < MAX_DELEGATES);
|
||||||
uint64[] memory newDelegationChain = new uint64[](
|
uint64[] memory newDelegationChain = new uint64[](
|
||||||
p.delegationChain.length + 1
|
p.delegationChain.length + 1
|
||||||
);
|
);
|
||||||
for (uint i = 0; i<p.delegationChain.length; i++) {
|
for (uint i = 0; i < p.delegationChain.length; i++) {
|
||||||
newDelegationChain[i] = p.delegationChain[i];
|
newDelegationChain[i] = p.delegationChain[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make the last item in the array the idReceiver
|
// Make the last item in the array the idReceiver
|
||||||
newDelegationChain[p.delegationChain.length] = idReceiver;
|
newDelegationChain[p.delegationChain.length] = idReceiver;
|
||||||
|
|
||||||
Pledges.Pledge memory toPledge = findOrCreatePledge(
|
uint64 toPledge = _findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
newDelegationChain,
|
newDelegationChain,
|
||||||
0,
|
0,
|
||||||
|
@ -501,21 +503,22 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
p.oldPledge,
|
p.oldPledge,
|
||||||
Pledges.PledgeState.Pledged
|
Pledges.PledgeState.Pledged
|
||||||
);
|
);
|
||||||
doTransfer(p, toPledge, amount);
|
_doTransfer(idPledge, toPledge, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice `appendDelegate` allows for a delegate to be added onto the
|
/// @notice `appendDelegate` allows for a delegate to be added onto the
|
||||||
/// end of the delegate chain for a given Pledge.
|
/// end of the delegate chain for a given Pledge.
|
||||||
/// @param p the pledge thats delegate chain will be modified.
|
/// @param idPledge the id of the pledge thats delegate chain will be modified.
|
||||||
/// @param amount Quantity of value that's shifted from delegates.
|
/// @param amount Quantity of value that's shifted from delegates.
|
||||||
/// @param q Number (or depth) of delegates to remove
|
/// @param q Number (or depth) of delegates to remove
|
||||||
/// @return toPledge The id for the pledge being adjusted or created
|
/// @return toPledge The id for the pledge being adjusted or created
|
||||||
function undelegate(
|
function _undelegate(
|
||||||
Pledges.Pledge p,
|
uint64 idPledge,
|
||||||
uint amount,
|
uint amount,
|
||||||
uint q
|
uint q
|
||||||
) internal returns (Pledges.Pledge)
|
) internal returns (uint64 toPledge)
|
||||||
{
|
{
|
||||||
|
Pledges.Pledge storage p = _findPledge(idPledge);
|
||||||
uint64[] memory newDelegationChain = new uint64[](
|
uint64[] memory newDelegationChain = new uint64[](
|
||||||
p.delegationChain.length - q
|
p.delegationChain.length - q
|
||||||
);
|
);
|
||||||
|
@ -523,7 +526,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
for (uint i = 0; i < p.delegationChain.length - q; i++) {
|
for (uint i = 0; i < p.delegationChain.length - q; i++) {
|
||||||
newDelegationChain[i] = p.delegationChain[i];
|
newDelegationChain[i] = p.delegationChain[i];
|
||||||
}
|
}
|
||||||
Pledges.Pledge memory toPledge = findOrCreatePledge(
|
toPledge = _findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
newDelegationChain,
|
newDelegationChain,
|
||||||
0,
|
0,
|
||||||
|
@ -531,60 +534,61 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
p.oldPledge,
|
p.oldPledge,
|
||||||
Pledges.PledgeState.Pledged
|
Pledges.PledgeState.Pledged
|
||||||
);
|
);
|
||||||
doTransfer(p, toPledge, amount);
|
_doTransfer(idPledge, toPledge, amount);
|
||||||
|
|
||||||
return toPledge;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice `proposeAssignProject` proposes the assignment of a pledge
|
/// @notice `proposeAssignProject` proposes the assignment of a pledge
|
||||||
/// to a specific project.
|
/// to a specific project.
|
||||||
/// @dev This function should potentially be named more specifically.
|
/// @dev This function should potentially be named more specifically.
|
||||||
/// @param p the pledge that will be assigned.
|
/// @param idPledge the id of the pledge that will be assigned.
|
||||||
/// @param amount Quantity of value this pledge leader would be assigned.
|
/// @param amount Quantity of value this pledge leader would be assigned.
|
||||||
/// @param idReceiver The project this pledge will potentially
|
/// @param idReceiver The project this pledge will potentially
|
||||||
/// be assigned to.
|
/// be assigned to.
|
||||||
function proposeAssignProject(
|
function _proposeAssignProject(
|
||||||
Pledges.Pledge p,
|
uint64 idPledge,
|
||||||
uint amount,
|
uint amount,
|
||||||
uint64 idReceiver
|
uint64 idReceiver
|
||||||
) internal
|
) internal
|
||||||
{
|
{
|
||||||
require(getPledgeLevel(p.oldPledge) < MAX_INTERPROJECT_LEVEL);
|
Pledges.Pledge storage p = _findPledge(idPledge);
|
||||||
require(!isProjectCanceled(idReceiver));
|
|
||||||
|
|
||||||
Pledges.Pledge memory toPledge = findOrCreatePledge(
|
require(_getPledgeLevel(p) < MAX_INTERPROJECT_LEVEL);
|
||||||
|
require(!_isProjectCanceled(idReceiver));
|
||||||
|
|
||||||
|
uint64 toPledge = _findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
p.delegationChain,
|
p.delegationChain,
|
||||||
idReceiver,
|
idReceiver,
|
||||||
uint64(getTime() + maxCommitTime(p)),
|
uint64(_getTime() + _maxCommitTime(p)),
|
||||||
p.oldPledge,
|
p.oldPledge,
|
||||||
Pledges.PledgeState.Pledged
|
Pledges.PledgeState.Pledged
|
||||||
);
|
);
|
||||||
doTransfer(p, toPledge, amount);
|
_doTransfer(idPledge, toPledge, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice `doTransfer` is designed to allow for pledge amounts to be
|
/// @notice `doTransfer` is designed to allow for pledge amounts to be
|
||||||
/// shifted around internally.
|
/// shifted around internally.
|
||||||
/// @param pFrom This is the pledge from which value will be transfered.
|
/// @param from This is the id of the pledge from which value will be transfered.
|
||||||
/// @param pTo This is the pledge that value will be transfered to.
|
/// @param to This is the id of the pledge that value will be transfered to.
|
||||||
/// @param _amount The amount of value that will be transfered.
|
/// @param _amount The amount of value that will be transfered.
|
||||||
function doTransfer(Pledges.Pledge pFrom, Pledges.Pledge pTo, uint _amount) internal {
|
function _doTransfer(uint64 from, uint64 to, uint _amount) internal {
|
||||||
uint amount = callPlugins(true, pFrom, pTo, _amount);
|
uint amount = _callPlugins(true, from, to, _amount);
|
||||||
if (pFrom.id == pTo.id) {
|
if (from == to) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (amount == 0) {
|
if (amount == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pledges.Pledge storage pFrom = _findPledge(from);
|
||||||
|
Pledges.Pledge storage pTo = _findPledge(to);
|
||||||
|
|
||||||
require(pFrom.amount >= amount);
|
require(pFrom.amount >= amount);
|
||||||
pFrom.amount -= amount;
|
pFrom.amount -= amount;
|
||||||
setPledgeAmount(pFrom.id, pFrom.amount);
|
|
||||||
pTo.amount += amount;
|
pTo.amount += amount;
|
||||||
setPledgeAmount(pTo.id, pTo.amount);
|
|
||||||
|
|
||||||
Transfer(pFrom.id, pTo.id, amount);
|
Transfer(from, to, amount);
|
||||||
callPlugins(false, pFrom, pTo, amount);
|
_callPlugins(false, from, to, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Only affects pledges with the Pledged Pledges.PledgeState for 2 things:
|
/// @notice Only affects pledges with the Pledged Pledges.PledgeState for 2 things:
|
||||||
|
@ -604,22 +608,18 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// plugins, which also need to be predicted by the UI
|
/// plugins, which also need to be predicted by the UI
|
||||||
/// @param idPledge This is the id of the pledge that will be normalized
|
/// @param idPledge This is the id of the pledge that will be normalized
|
||||||
/// @return The normalized Pledge!
|
/// @return The normalized Pledge!
|
||||||
function normalizePledge(uint64 idPledge) public returns(Pledges.Pledge) {
|
function normalizePledge(uint64 idPledge) public returns(uint64) {
|
||||||
Pledges.Pledge memory p = findPledge(idPledge);
|
Pledges.Pledge storage p = _findPledge(idPledge);
|
||||||
return _normalizePledge(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _normalizePledge(Pledges.Pledge p) internal returns(Pledges.Pledge) {
|
|
||||||
|
|
||||||
// Check to make sure this pledge hasn't already been used
|
// Check to make sure this pledge hasn't already been used
|
||||||
// or is in the process of being used
|
// or is in the process of being used
|
||||||
if (p.pledgeState != Pledges.PledgeState.Pledged) {
|
if (p.pledgeState != Pledges.PledgeState.Pledged) {
|
||||||
return p;
|
return idPledge;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First send to a project if it's proposed and committed
|
// First send to a project if it's proposed and committed
|
||||||
if ((p.intendedProject > 0) && ( getTime() > p.commitTime)) {
|
if ((p.intendedProject > 0) && ( _getTime() > p.commitTime)) {
|
||||||
Pledges.Pledge memory oldPledge = findOrCreatePledge(
|
uint64 oldPledge = _findOrCreatePledge(
|
||||||
p.owner,
|
p.owner,
|
||||||
p.delegationChain,
|
p.delegationChain,
|
||||||
0,
|
0,
|
||||||
|
@ -627,26 +627,25 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
p.oldPledge,
|
p.oldPledge,
|
||||||
Pledges.PledgeState.Pledged
|
Pledges.PledgeState.Pledged
|
||||||
);
|
);
|
||||||
Pledges.Pledge memory toPledge = findOrCreatePledge(
|
uint64 toPledge = _findOrCreatePledge(
|
||||||
p.intendedProject,
|
p.intendedProject,
|
||||||
new uint64[](0),
|
new uint64[](0),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
uint64(oldPledge.id),
|
oldPledge,
|
||||||
Pledges.PledgeState.Pledged
|
Pledges.PledgeState.Pledged
|
||||||
);
|
);
|
||||||
doTransfer(p, toPledge, p.amount);
|
_doTransfer(idPledge, toPledge, p.amount);
|
||||||
p = toPledge;
|
idPledge = toPledge;
|
||||||
|
p = _findPledge(idPledge);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 oldestPledgeId = getOldestPledgeNotCanceled(uint64(p.id));
|
toPledge = _getOldestPledgeNotCanceled(idPledge);
|
||||||
if (p.id != oldestPledgeId) {
|
if (toPledge != idPledge) {
|
||||||
toPledge = findPledge(oldestPledgeId);
|
_doTransfer(idPledge, toPledge, p.amount);
|
||||||
doTransfer(p, toPledge, p.amount);
|
|
||||||
p = toPledge;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return toPledge;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////
|
/////////////
|
||||||
|
@ -667,7 +666,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// @param context The situation that is triggering the plugin. See plugin
|
/// @param context The situation that is triggering the plugin. See plugin
|
||||||
/// for a full description of contexts.
|
/// for a full description of contexts.
|
||||||
/// @param amount The amount of value that is being transfered.
|
/// @param amount The amount of value that is being transfered.
|
||||||
function callPlugin(
|
function _callPlugin(
|
||||||
bool before,
|
bool before,
|
||||||
uint64 adminId,
|
uint64 adminId,
|
||||||
uint64 fromPledge,
|
uint64 fromPledge,
|
||||||
|
@ -678,14 +677,14 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
|
|
||||||
uint newAmount;
|
uint newAmount;
|
||||||
allowedAmount = amount;
|
allowedAmount = amount;
|
||||||
address plugin = getAdminPlugin(adminId);
|
PledgeAdmins.PledgeAdmin storage admin = _findAdmin(adminId);
|
||||||
|
|
||||||
// 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 (plugin != 0 && allowedAmount > 0) {
|
if (address(admin.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 = ILiquidPledgingPlugin(plugin).beforeTransfer(
|
newAmount = admin.plugin.beforeTransfer(
|
||||||
adminId,
|
adminId,
|
||||||
fromPledge,
|
fromPledge,
|
||||||
toPledge,
|
toPledge,
|
||||||
|
@ -695,7 +694,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
require(newAmount <= allowedAmount);
|
require(newAmount <= allowedAmount);
|
||||||
allowedAmount = newAmount;
|
allowedAmount = newAmount;
|
||||||
} else {
|
} else {
|
||||||
ILiquidPledgingPlugin(plugin).afterTransfer(
|
admin.plugin.afterTransfer(
|
||||||
adminId,
|
adminId,
|
||||||
fromPledge,
|
fromPledge,
|
||||||
toPledge,
|
toPledge,
|
||||||
|
@ -712,29 +711,26 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// on the `p` and `fromPledge` parameters.
|
/// on the `p` and `fromPledge` parameters.
|
||||||
/// @param before This toggle determines whether the plugin call is occuring
|
/// @param before This toggle determines whether the plugin call is occuring
|
||||||
/// before or after a transfer.
|
/// before or after a transfer.
|
||||||
/// @param p This is the pledge on which this plugin
|
/// @param idPledge This is the id of the pledge on which this plugin
|
||||||
/// is being called.
|
/// is being called.
|
||||||
/// @param fromPledge This is the Id from which value is being transfered.
|
/// @param fromPledge This is the Id from which value is being transfered.
|
||||||
/// @param toPledge This is the Id that value is being transfered to.
|
/// @param toPledge This is the Id that value is being transfered to.
|
||||||
/// @param amount The amount of value that is being transfered.
|
/// @param amount The amount of value that is being transfered.
|
||||||
function callPluginsPledge(
|
function _callPluginsPledge(
|
||||||
bool before,
|
bool before,
|
||||||
Pledges.Pledge p,
|
uint64 idPledge,
|
||||||
uint64 fromPledge,
|
uint64 fromPledge,
|
||||||
uint64 toPledge,
|
uint64 toPledge,
|
||||||
uint amount
|
uint amount
|
||||||
) internal returns (uint allowedAmount) {
|
) internal returns (uint allowedAmount) {
|
||||||
// Determine if callPlugin is being applied in a receiving
|
// Determine if callPlugin is being applied in a receiving
|
||||||
// or transferring context
|
// or transferring context
|
||||||
uint64 offset = p.id == fromPledge ? 0 : 256;
|
uint64 offset = idPledge == fromPledge ? 0 : 256;
|
||||||
allowedAmount = amount;
|
allowedAmount = amount;
|
||||||
|
Pledges.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 = 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,
|
||||||
p.owner,
|
p.owner,
|
||||||
fromPledge,
|
fromPledge,
|
||||||
|
@ -744,14 +740,13 @@ 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],
|
||||||
fromPledge,
|
fromPledge,
|
||||||
toPledge,
|
toPledge,
|
||||||
offset + i+1,
|
offset + i + 1,
|
||||||
allowedAmount
|
allowedAmount
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -760,8 +755,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,
|
||||||
fromPledge,
|
fromPledge,
|
||||||
|
@ -781,29 +775,29 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/// @param fromPledge This is the Id from which value is being transferred.
|
/// @param fromPledge This is the Id from which value is being transferred.
|
||||||
/// @param toPledge This is the Id that value is being transferred to.
|
/// @param toPledge This is the Id that value is being transferred to.
|
||||||
/// @param amount The amount of value that is being transferred.
|
/// @param amount The amount of value that is being transferred.
|
||||||
function callPlugins(
|
function _callPlugins(
|
||||||
bool before,
|
bool before,
|
||||||
Pledges.Pledge fromPledge,
|
uint64 fromPledge,
|
||||||
Pledges.Pledge toPledge,
|
uint64 toPledge,
|
||||||
uint amount
|
uint amount
|
||||||
) internal returns (uint allowedAmount) {
|
) internal returns (uint allowedAmount) {
|
||||||
allowedAmount = amount;
|
allowedAmount = amount;
|
||||||
|
|
||||||
// Call the pledges plugins in the transfer context
|
// Call the pledges plugins in the transfer context
|
||||||
allowedAmount = callPluginsPledge(
|
allowedAmount = _callPluginsPledge(
|
||||||
before,
|
before,
|
||||||
fromPledge,
|
fromPledge,
|
||||||
uint64(fromPledge.id),
|
fromPledge,
|
||||||
uint64(toPledge.id),
|
toPledge,
|
||||||
allowedAmount
|
allowedAmount
|
||||||
);
|
);
|
||||||
|
|
||||||
// Call the pledges plugins in the receive context
|
// Call the pledges plugins in the receive context
|
||||||
allowedAmount = callPluginsPledge(
|
allowedAmount = _callPluginsPledge(
|
||||||
before,
|
before,
|
||||||
toPledge,
|
toPledge,
|
||||||
uint64(fromPledge.id),
|
fromPledge,
|
||||||
uint64(toPledge.id),
|
toPledge,
|
||||||
allowedAmount
|
allowedAmount
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -813,7 +807,7 @@ contract LiquidPledging is LiquidPledgingBase {
|
||||||
/////////////
|
/////////////
|
||||||
|
|
||||||
/// @notice Basic helper function to return the current time
|
/// @notice Basic helper function to return the current time
|
||||||
function getTime() internal view returns (uint) {
|
function _getTime() internal view returns (uint) {
|
||||||
return now;
|
return now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,15 +20,15 @@ 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 "./EscapableApp.sol";
|
||||||
import "./PledgeAdmins.sol";
|
import "./PledgeAdmins.sol";
|
||||||
import "./Pledges.sol";
|
import "./Pledges.sol";
|
||||||
import "./LiquidPledgingStorage.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
|
||||||
/// payments can Pledges be converted for ETH
|
/// payments can Pledges be converted for ETH
|
||||||
interface LPVault {
|
interface ILPVault {
|
||||||
function authorizePayment(bytes32 _ref, address _dest, uint _amount) public;
|
function authorizePayment(bytes32 _ref, address _dest, uint _amount) public;
|
||||||
function () public payable;
|
function () public payable;
|
||||||
}
|
}
|
||||||
|
@ -36,11 +36,10 @@ interface LPVault {
|
||||||
/// @dev `LiquidPledgingBase` is the base level contract used to carry out
|
/// @dev `LiquidPledgingBase` is the base level contract used to carry out
|
||||||
/// 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 LiquidPledgingStorage, PledgeAdmins, Pledges, Escapable {
|
contract LiquidPledgingBase is PledgeAdmins, Pledges, EscapableApp {
|
||||||
|
|
||||||
LPVault public vault;
|
ILPVault public vault;
|
||||||
|
|
||||||
|
|
||||||
/////////////
|
/////////////
|
||||||
// Modifiers
|
// Modifiers
|
||||||
/////////////
|
/////////////
|
||||||
|
@ -57,21 +56,31 @@ contract LiquidPledgingBase is LiquidPledgingStorage, PledgeAdmins, Pledges, Esc
|
||||||
// Constructor
|
// Constructor
|
||||||
///////////////
|
///////////////
|
||||||
|
|
||||||
/// @notice The Constructor creates `LiquidPledgingBase` on the blockchain
|
function LiquidPledgingBase()
|
||||||
/// @param _vault The vault where the ETH backing the pledges is stored
|
PledgeAdmins()
|
||||||
function LiquidPledgingBase(
|
Pledges() public
|
||||||
address _storage,
|
|
||||||
address _vault,
|
|
||||||
address _escapeHatchCaller,
|
|
||||||
address _escapeHatchDestination
|
|
||||||
) LiquidPledgingStorage(_storage)
|
|
||||||
PledgeAdmins(_storage)
|
|
||||||
Pledges(_storage)
|
|
||||||
Escapable(_escapeHatchCaller, _escapeHatchDestination) public
|
|
||||||
{
|
{
|
||||||
vault = LPVault(_vault); // Assigns the specified vault
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initialize(address _escapeHatchDestination) onlyInit external {
|
||||||
|
require(false); // overload the EscapableApp
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @param _vault The vault where the ETH backing the pledges is stored
|
||||||
|
/// @param _escapeHatchDestination The address of a safe location (usu a
|
||||||
|
/// Multisig) to send the ether held in this contract; if a neutral address
|
||||||
|
/// is required, the WHG Multisig is an option:
|
||||||
|
/// 0x8Ff920020c8AD673661c8117f2855C384758C572
|
||||||
|
function initialize(address _vault, address _escapeHatchDestination) onlyInit external {
|
||||||
|
initialized();
|
||||||
|
require(_escapeHatchDestination != 0x0);
|
||||||
|
require(_vault != 0x0);
|
||||||
|
|
||||||
|
escapeHatchDestination = _escapeHatchDestination;
|
||||||
|
vault = ILPVault(_vault);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// Public constant functions
|
// Public constant functions
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
|
@ -79,14 +88,16 @@ contract LiquidPledgingBase is LiquidPledgingStorage, PledgeAdmins, Pledges, Esc
|
||||||
/// @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 getDelegate(uint idPledge, uint idxDelegate) public view returns(
|
function getPledgeDelegate(uint64 idPledge, uint64 idxDelegate) public view returns(
|
||||||
uint idDelegate,
|
uint64 idDelegate,
|
||||||
address addr,
|
address addr,
|
||||||
string name
|
string name
|
||||||
) {
|
) {
|
||||||
idDelegate = getPledgeDelegate(idPledge, idxDelegate);
|
Pledge storage p = _findPledge(idPledge);
|
||||||
addr = getAdminAddr(idDelegate);
|
idDelegate = p.delegationChain[idxDelegate - 1];
|
||||||
name = getAdminName(idDelegate);
|
PledgeAdmin storage delegate = _findAdmin(idDelegate);
|
||||||
|
addr = delegate.addr;
|
||||||
|
name = delegate.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
|
@ -95,28 +106,25 @@ contract LiquidPledgingBase is LiquidPledgingStorage, PledgeAdmins, Pledges, Esc
|
||||||
|
|
||||||
/// @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 idAdmin The id of the admin being checked
|
/// @param a The admin being checked
|
||||||
function checkAdminOwner(uint idAdmin) internal constant {
|
// function _checkAdminOwner(PledgeAdmin a) internal constant {
|
||||||
require(msg.sender == getAdminAddr(idAdmin) || msg.sender == getAdminPlugin(idAdmin));
|
// require(msg.sender == a.addr || msg.sender == address(a.plugin));
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// @notice A getter to find the longest commitTime out of the owner and all
|
/// @notice A getter to find the longest commitTime out of the owner and all
|
||||||
/// the delegates for a specified pledge
|
/// the delegates for a specified pledge
|
||||||
/// @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(uint64 commitTime) {
|
||||||
uint adminsSize = numberOfPledgeAdmins();
|
PledgeAdmin storage a = _findAdmin(p.owner);
|
||||||
require(adminsSize >= p.owner);
|
commitTime = a.commitTime; // start with the owner's commitTime
|
||||||
|
|
||||||
commitTime = 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++) {
|
||||||
require(adminsSize >= p.delegationChain[i]);
|
a = _findAdmin(p.delegationChain[i]);
|
||||||
uint delegateCommitTime = 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 (delegateCommitTime > commitTime) {
|
if (a.commitTime > commitTime) {
|
||||||
commitTime = delegateCommitTime;
|
commitTime = a.commitTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +132,7 @@ contract LiquidPledgingBase is LiquidPledgingStorage, PledgeAdmins, Pledges, Esc
|
||||||
/// @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(
|
function _getOldestPledgeNotCanceled(
|
||||||
uint64 idPledge
|
uint64 idPledge
|
||||||
) internal view returns(uint64)
|
) internal view returns(uint64)
|
||||||
{
|
{
|
||||||
|
@ -132,19 +140,18 @@ contract LiquidPledgingBase is LiquidPledgingStorage, PledgeAdmins, Pledges, Esc
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint owner = getPledgeOwner(idPledge);
|
Pledge storage p = _findPledge(idPledge);
|
||||||
|
PledgeAdmin storage admin = _findAdmin(p.owner);
|
||||||
PledgeAdminType adminType = getAdminType(owner);
|
|
||||||
if (adminType == PledgeAdminType.Giver) {
|
if (admin.adminType == PledgeAdminType.Giver) {
|
||||||
return idPledge;
|
|
||||||
}
|
|
||||||
assert(adminType == PledgeAdminType.Project);
|
|
||||||
|
|
||||||
if (!isProjectCanceled(owner)) {
|
|
||||||
return idPledge;
|
return idPledge;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 oldPledge = uint64(getPledgeOldPledge(idPledge));
|
assert(admin.adminType == PledgeAdminType.Project);
|
||||||
return getOldestPledgeNotCanceled(oldPledge);
|
if (!_isProjectCanceled(p.owner)) {
|
||||||
|
return idPledge;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _getOldestPledgeNotCanceled(p.oldPledge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,13 +28,7 @@ contract LiquidPledgingMock is LiquidPledging {
|
||||||
|
|
||||||
/// @dev `LiquidPledgingMock` creates a standard `LiquidPledging`
|
/// @dev `LiquidPledgingMock` creates a standard `LiquidPledging`
|
||||||
/// instance and sets the mocked time to the current blocktime.
|
/// instance and sets the mocked time to the current blocktime.
|
||||||
/// @param _vault The vault where ETH backing this pledge is stored
|
function LiquidPledgingMock() LiquidPledging() public {
|
||||||
function LiquidPledgingMock(
|
|
||||||
address _storage,
|
|
||||||
address _vault,
|
|
||||||
address _escapeHatchCaller,
|
|
||||||
address _escapeHatchDestination
|
|
||||||
) LiquidPledging(_storage, _vault, _escapeHatchCaller, _escapeHatchDestination) public {
|
|
||||||
mock_time = now;
|
mock_time = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,31 +19,33 @@ pragma solidity ^0.4.18;
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "giveth-common-contracts/contracts/Owned.sol";
|
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||||
|
|
||||||
/// NOTICE: This contract is not using EternalStorage. This is done to save gas. The pluginWhitelist
|
/// NOTICE: This contract is not using EternalStorage. This is done to save gas. The pluginWhitelist
|
||||||
/// should be fairly small, and would be trivial and relatively cheap to re-add all valid plugins
|
/// should be fairly small, and would be trivial and relatively cheap to re-add all valid plugins
|
||||||
/// when the LiquidPledging contract is upgraded
|
/// when the LiquidPledging contract is upgraded
|
||||||
contract LiquidPledgingPlugins is Owned {
|
contract LiquidPledgingPlugins is AragonApp {
|
||||||
|
|
||||||
|
bytes32 constant public PLUGIN_MANAGER_ROLE = keccak256("PLUGIN_MANAGER_ROLE");
|
||||||
|
|
||||||
mapping (bytes32 => bool) pluginWhitelist;
|
mapping (bytes32 => bool) pluginWhitelist;
|
||||||
bool public whitelistDisabled = false;
|
bool public whitelistDisabled = false;
|
||||||
|
|
||||||
function addValidPlugin(bytes32 contractHash) public onlyOwner {
|
function addValidPlugin(bytes32 contractHash) auth(PLUGIN_MANAGER_ROLE) public {
|
||||||
pluginWhitelist[contractHash] = true;
|
pluginWhitelist[contractHash] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addValidPlugins(bytes32[] contractHashes) external onlyOwner {
|
function addValidPlugins(bytes32[] contractHashes) external auth(PLUGIN_MANAGER_ROLE) {
|
||||||
for (uint8 i = 0; i < contractHashes.length; i++) {
|
for (uint8 i = 0; i < contractHashes.length; i++) {
|
||||||
addValidPlugin(contractHashes[i]);
|
addValidPlugin(contractHashes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeValidPlugin(bytes32 contractHash) external onlyOwner {
|
function removeValidPlugin(bytes32 contractHash) external auth(PLUGIN_MANAGER_ROLE) {
|
||||||
pluginWhitelist[contractHash] = false;
|
pluginWhitelist[contractHash] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useWhitelist(bool useWhitelist) external onlyOwner {
|
function useWhitelist(bool useWhitelist) external auth(PLUGIN_MANAGER_ROLE) {
|
||||||
whitelistDisabled = !useWhitelist;
|
whitelistDisabled = !useWhitelist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,42 +20,53 @@ pragma solidity ^0.4.18;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "./ILiquidPledgingPlugin.sol";
|
import "./ILiquidPledgingPlugin.sol";
|
||||||
import "./EternallyPersistentLib.sol";
|
|
||||||
import "./LiquidPledgingStorage.sol";
|
|
||||||
import "./LiquidPledgingPlugins.sol";
|
import "./LiquidPledgingPlugins.sol";
|
||||||
|
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||||
|
import "@aragon/os/contracts/acl/ACL.sol";
|
||||||
|
|
||||||
contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
contract PledgeAdmins is AragonApp, LiquidPledgingPlugins {
|
||||||
using EternallyPersistentLib for EternalStorage;
|
|
||||||
|
bytes32 constant public PLEDGE_ADMIN_ROLE = keccak256("PLEDGE_ADMIN_ROLE");
|
||||||
|
|
||||||
// Limits inserted to prevent large loops that could prevent canceling
|
// Limits inserted to prevent large loops that could prevent canceling
|
||||||
uint constant MAX_SUBPROJECT_LEVEL = 20;
|
uint constant MAX_SUBPROJECT_LEVEL = 20;
|
||||||
uint constant MAX_INTERPROJECT_LEVEL = 20;
|
uint constant MAX_INTERPROJECT_LEVEL = 20;
|
||||||
|
|
||||||
// Constants used when dealing with storage/retrieval of PledgeAdmins
|
|
||||||
string constant PLEDGE_ADMIN = "PledgeAdmin";
|
|
||||||
bytes32 constant PLEDGE_ADMINS_ARRAY = keccak256("pledgeAdmins");
|
|
||||||
|
|
||||||
//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?
|
|
||||||
|
|
||||||
enum PledgeAdminType { Giver, Delegate, Project }
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
event GiverAdded(uint indexed idGiver);
|
event GiverAdded(uint64 indexed idGiver);
|
||||||
event GiverUpdated(uint indexed idGiver);
|
event GiverUpdated(uint64 indexed idGiver);
|
||||||
event DelegateAdded(uint indexed idDelegate);
|
event DelegateAdded(uint64 indexed idDelegate);
|
||||||
event DelegateUpdated(uint indexed idDelegate);
|
event DelegateUpdated(uint64 indexed idDelegate);
|
||||||
event ProjectAdded(uint indexed idProject);
|
event ProjectAdded(uint64 indexed idProject);
|
||||||
event ProjectUpdated(uint indexed idProject);
|
event ProjectUpdated(uint64 indexed idProject);
|
||||||
|
|
||||||
|
PledgeAdmin[] admins; //The list of pledgeAdmins 0 means there is no admin
|
||||||
|
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
///////////////
|
///////////////
|
||||||
|
|
||||||
function PledgeAdmins(address _storage)
|
function PledgeAdmins()
|
||||||
LiquidPledgingStorage(_storage)
|
|
||||||
LiquidPledgingPlugins() public
|
LiquidPledgingPlugins() public
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -75,21 +86,31 @@ contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
||||||
function addGiver(
|
function addGiver(
|
||||||
string name,
|
string name,
|
||||||
string url,
|
string url,
|
||||||
uint commitTime,
|
uint64 commitTime,
|
||||||
ILiquidPledgingPlugin plugin
|
ILiquidPledgingPlugin plugin
|
||||||
) public returns (uint idGiver)
|
) public returns (uint64 idGiver)
|
||||||
{
|
{
|
||||||
require(isValidPlugin(plugin)); // Plugin check
|
require(isValidPlugin(plugin)); // Plugin check
|
||||||
|
|
||||||
idGiver = _storage.stgCollectionAddItem(PLEDGE_ADMINS_ARRAY);
|
idGiver = uint64(admins.length);
|
||||||
|
|
||||||
// Save the fields
|
// Save the fields
|
||||||
// don't set adminType to save gas, b/c 0 is Giver
|
admins.push(
|
||||||
_storage.stgObjectSetAddress(PLEDGE_ADMIN, idGiver, "addr", msg.sender);
|
PledgeAdmin(
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idGiver, "name", name);
|
PledgeAdminType.Giver,
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idGiver, "url", url);
|
msg.sender, // TODO: is this needed?
|
||||||
_storage.stgObjectSetUInt(PLEDGE_ADMIN, idGiver, "commitTime", commitTime);
|
name,
|
||||||
_storage.stgObjectSetAddress(PLEDGE_ADMIN, idGiver, "plugin", address(plugin));
|
url,
|
||||||
|
commitTime,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
plugin)
|
||||||
|
);
|
||||||
|
|
||||||
|
_grantPledgeAdminPermission(msg.sender, idGiver);
|
||||||
|
if (address(plugin) != 0) {
|
||||||
|
_grantPledgeAdminPermission(address(plugin), idGiver);
|
||||||
|
}
|
||||||
|
|
||||||
GiverAdded(idGiver);
|
GiverAdded(idGiver);
|
||||||
}
|
}
|
||||||
|
@ -104,21 +125,20 @@ contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
||||||
/// @param newCommitTime Sets the length of time in seconds the Giver has to
|
/// @param newCommitTime Sets the length of time in seconds the Giver has to
|
||||||
/// veto when the Giver's delegates Pledge funds to a project
|
/// veto when the Giver's delegates Pledge funds to a project
|
||||||
function updateGiver(
|
function updateGiver(
|
||||||
uint idGiver,
|
uint64 idGiver,
|
||||||
address newAddr,
|
address newAddr,
|
||||||
string newName,
|
string newName,
|
||||||
string newUrl,
|
string newUrl,
|
||||||
uint64 newCommitTime
|
uint64 newCommitTime
|
||||||
) public
|
) authP(PLEDGE_ADMIN_ROLE, arr(uint(idGiver))) public
|
||||||
{
|
{
|
||||||
require(getAdminType(idGiver) == PledgeAdminType.Giver); // Must be a Giver
|
PledgeAdmin storage giver = _findAdmin(idGiver);
|
||||||
require(getAdminAddr(idGiver) == msg.sender); // Current addr had to send this tx
|
require(giver.adminType == PledgeAdminType.Giver); // Must be a Giver
|
||||||
|
// require(giver.addr == msg.sender); // Current addr had to send this tx
|
||||||
// Save the fields
|
giver.addr = newAddr;
|
||||||
_storage.stgObjectSetAddress(PLEDGE_ADMIN, idGiver, "addr", newAddr);
|
giver.name = newName;
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idGiver, "name", newName);
|
giver.url = newUrl;
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idGiver, "url", newUrl);
|
giver.commitTime = newCommitTime;
|
||||||
_storage.stgObjectSetUInt(PLEDGE_ADMIN, idGiver, "commitTime", newCommitTime);
|
|
||||||
|
|
||||||
GiverUpdated(idGiver);
|
GiverUpdated(idGiver);
|
||||||
}
|
}
|
||||||
|
@ -138,19 +158,28 @@ contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
||||||
string url,
|
string url,
|
||||||
uint64 commitTime,
|
uint64 commitTime,
|
||||||
ILiquidPledgingPlugin plugin
|
ILiquidPledgingPlugin plugin
|
||||||
) public returns (uint idDelegate)
|
) public returns (uint64 idDelegate)
|
||||||
{
|
{
|
||||||
require(isValidPlugin(plugin)); // Plugin check
|
require(isValidPlugin(plugin)); // Plugin check
|
||||||
|
|
||||||
idDelegate = _storage.stgCollectionAddItem(PLEDGE_ADMINS_ARRAY);
|
idDelegate = uint64(admins.length);
|
||||||
|
|
||||||
// Save the fields
|
admins.push(
|
||||||
_storage.stgObjectSetUInt(PLEDGE_ADMIN, idDelegate, "adminType", uint(PledgeAdminType.Delegate));
|
PledgeAdmin(
|
||||||
_storage.stgObjectSetAddress(PLEDGE_ADMIN, idDelegate, "addr", msg.sender);
|
PledgeAdminType.Delegate,
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idDelegate, "name", name);
|
msg.sender,
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idDelegate, "url", url);
|
name,
|
||||||
_storage.stgObjectSetUInt(PLEDGE_ADMIN, idDelegate, "commitTime", commitTime);
|
url,
|
||||||
_storage.stgObjectSetAddress(PLEDGE_ADMIN, idDelegate, "plugin", address(plugin));
|
commitTime,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
plugin)
|
||||||
|
);
|
||||||
|
|
||||||
|
_grantPledgeAdminPermission(msg.sender, idDelegate);
|
||||||
|
if (address(plugin) != 0) {
|
||||||
|
_grantPledgeAdminPermission(address(plugin), idDelegate);
|
||||||
|
}
|
||||||
|
|
||||||
DelegateAdded(idDelegate);
|
DelegateAdded(idDelegate);
|
||||||
}
|
}
|
||||||
|
@ -167,21 +196,20 @@ contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
||||||
/// the time allowed to veto any event must be greater than or equal to
|
/// the time allowed to veto any event must be greater than or equal to
|
||||||
/// this time.
|
/// this time.
|
||||||
function updateDelegate(
|
function updateDelegate(
|
||||||
uint idDelegate,
|
uint64 idDelegate,
|
||||||
address newAddr,
|
address newAddr,
|
||||||
string newName,
|
string newName,
|
||||||
string newUrl,
|
string newUrl,
|
||||||
uint64 newCommitTime
|
uint64 newCommitTime
|
||||||
) public
|
) authP(PLEDGE_ADMIN_ROLE, arr(uint(idDelegate))) public
|
||||||
{
|
{
|
||||||
require(getAdminType(idDelegate) == PledgeAdminType.Delegate);
|
PledgeAdmin storage delegate = _findAdmin(idDelegate);
|
||||||
require(getAdminAddr(idDelegate) == msg.sender); // Current addr had to send this tx
|
require(delegate.adminType == PledgeAdminType.Delegate);
|
||||||
|
// require(delegate.addr == msg.sender);// Current addr had to send this tx
|
||||||
// Save the fields
|
delegate.addr = newAddr;
|
||||||
_storage.stgObjectSetAddress(PLEDGE_ADMIN, idDelegate, "addr", newAddr);
|
delegate.name = newName;
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idDelegate, "name", newName);
|
delegate.url = newUrl;
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idDelegate, "url", newUrl);
|
delegate.commitTime = newCommitTime;
|
||||||
_storage.stgObjectSetUInt(PLEDGE_ADMIN, idDelegate, "commitTime", newCommitTime);
|
|
||||||
|
|
||||||
DelegateUpdated(idDelegate);
|
DelegateUpdated(idDelegate);
|
||||||
}
|
}
|
||||||
|
@ -205,27 +233,35 @@ contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
||||||
uint64 parentProject,
|
uint64 parentProject,
|
||||||
uint64 commitTime,
|
uint64 commitTime,
|
||||||
ILiquidPledgingPlugin plugin
|
ILiquidPledgingPlugin plugin
|
||||||
) public returns (uint idProject)
|
) public returns (uint64 idProject)
|
||||||
{
|
{
|
||||||
require(isValidPlugin(plugin));
|
require(isValidPlugin(plugin));
|
||||||
|
|
||||||
if (parentProject != 0) {
|
if (parentProject != 0) {
|
||||||
|
PledgeAdmin storage a = _findAdmin(parentProject);
|
||||||
|
// require(a.adminType == PledgeAdminType.Project);
|
||||||
// getProjectLevel will check that parentProject has a `Project` adminType
|
// getProjectLevel will check that parentProject has a `Project` adminType
|
||||||
require(getProjectLevel(parentProject) < MAX_SUBPROJECT_LEVEL);
|
require(_getProjectLevel(a) < MAX_SUBPROJECT_LEVEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
idProject = _storage.stgCollectionAddItem(PLEDGE_ADMINS_ARRAY);//, idProject);
|
idProject = uint64(admins.length);
|
||||||
|
|
||||||
// Save the fields
|
admins.push(
|
||||||
_storage.stgObjectSetUInt(PLEDGE_ADMIN, idProject, "adminType", uint(PledgeAdminType.Project));
|
PledgeAdmin(
|
||||||
_storage.stgObjectSetAddress(PLEDGE_ADMIN, idProject, "addr", projectAdmin);
|
PledgeAdminType.Project,
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idProject, "name", name);
|
projectAdmin,
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idProject, "url", url);
|
name,
|
||||||
|
url,
|
||||||
|
commitTime,
|
||||||
|
parentProject,
|
||||||
|
false,
|
||||||
|
plugin)
|
||||||
|
);
|
||||||
|
|
||||||
_storage.stgObjectSetUInt(PLEDGE_ADMIN, idProject, "parentProject", parentProject);
|
_grantPledgeAdminPermission(msg.sender, idProject);
|
||||||
|
if (address(plugin) != 0) {
|
||||||
_storage.stgObjectSetUInt(PLEDGE_ADMIN, idProject, "commitTime", commitTime);
|
_grantPledgeAdminPermission(address(plugin), idProject);
|
||||||
_storage.stgObjectSetAddress(PLEDGE_ADMIN, idProject, "plugin", address(plugin));
|
}
|
||||||
|
|
||||||
ProjectAdded(idProject);
|
ProjectAdded(idProject);
|
||||||
}
|
}
|
||||||
|
@ -241,21 +277,22 @@ contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
||||||
/// to veto when the Project delegates to a Delegate and they pledge those
|
/// to veto when the Project delegates to a Delegate and they pledge those
|
||||||
/// funds to a project
|
/// funds to a project
|
||||||
function updateProject(
|
function updateProject(
|
||||||
uint idProject,
|
uint64 idProject,
|
||||||
address newAddr,
|
address newAddr,
|
||||||
string newName,
|
string newName,
|
||||||
string newUrl,
|
string newUrl,
|
||||||
uint64 newCommitTime
|
uint64 newCommitTime
|
||||||
) public
|
) authP(PLEDGE_ADMIN_ROLE, arr(uint(idProject))) public
|
||||||
{
|
{
|
||||||
require(getAdminType(idProject) == PledgeAdminType.Project);
|
PledgeAdmin storage project = _findAdmin(idProject);
|
||||||
require(getAdminAddr(idProject) == msg.sender); // Current addr had to send this tx
|
|
||||||
|
|
||||||
// Save the fields
|
require(project.adminType == PledgeAdminType.Project);
|
||||||
_storage.stgObjectSetAddress(PLEDGE_ADMIN, idProject, "addr", newAddr);
|
// require(project.addr == msg.sender);
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idProject, "name", newName);
|
|
||||||
_storage.stgObjectSetString(PLEDGE_ADMIN, idProject, "url", newUrl);
|
project.addr = newAddr;
|
||||||
_storage.stgObjectSetUInt(PLEDGE_ADMIN, idProject, "commitTime", newCommitTime);
|
project.name = newName;
|
||||||
|
project.url = newUrl;
|
||||||
|
project.commitTime = newCommitTime;
|
||||||
|
|
||||||
ProjectUpdated(idProject);
|
ProjectUpdated(idProject);
|
||||||
}
|
}
|
||||||
|
@ -268,7 +305,7 @@ contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
||||||
/// @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 _storage.stgCollectionLength(PLEDGE_ADMINS_ARRAY);
|
return admins.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice A constant getter to check the details of a specified Admin
|
/// @notice A constant getter to check the details of a specified Admin
|
||||||
|
@ -284,7 +321,7 @@ contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
||||||
/// canceled
|
/// canceled
|
||||||
/// @return plugin This is Project's liquidPledging plugin allowing for
|
/// @return plugin This is Project's liquidPledging plugin allowing for
|
||||||
/// extended functionality
|
/// extended functionality
|
||||||
function getPledgeAdmin(uint idAdmin) public view returns (
|
function getPledgeAdmin(uint64 idAdmin) public view returns (
|
||||||
PledgeAdminType adminType,
|
PledgeAdminType adminType,
|
||||||
address addr,
|
address addr,
|
||||||
string name,
|
string name,
|
||||||
|
@ -294,20 +331,15 @@ contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
||||||
bool canceled,
|
bool canceled,
|
||||||
address plugin
|
address plugin
|
||||||
) {
|
) {
|
||||||
adminType = getAdminType(idAdmin);
|
PledgeAdmin storage a = _findAdmin(idAdmin);
|
||||||
addr = getAdminAddr(idAdmin);
|
adminType = a.adminType;
|
||||||
name = getAdminName(idAdmin);
|
addr = a.addr;
|
||||||
url = _storage.stgObjectGetString(PLEDGE_ADMIN, idAdmin, "url");
|
name = a.name;
|
||||||
commitTime = uint64(getAdminCommitTime(idAdmin));
|
url = a.url;
|
||||||
|
commitTime = a.commitTime;
|
||||||
// parentProject & canceled only belong to Project admins,
|
parentProject = a.parentProject;
|
||||||
// so don't waste the gas to fetch the data
|
canceled = a.canceled;
|
||||||
if (adminType == PledgeAdminType.Project) {
|
plugin = address(a.plugin);
|
||||||
parentProject = uint64(getAdminParentProject(idAdmin));
|
|
||||||
canceled = getAdminCanceled(idAdmin);
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin = getAdminPlugin(idAdmin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -315,97 +347,60 @@ contract PledgeAdmins is LiquidPledgingStorage, LiquidPledgingPlugins {
|
||||||
// Internal methods
|
// Internal methods
|
||||||
///////////////////
|
///////////////////
|
||||||
|
|
||||||
|
/// @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 returns (PledgeAdmin storage) {
|
||||||
|
require(idAdmin < admins.length);
|
||||||
|
return admins[idAdmin];
|
||||||
|
}
|
||||||
|
|
||||||
/// @notice A getter to find if a specified Project has been canceled
|
/// @notice A getter to find if a specified Project has been canceled
|
||||||
/// @param projectId The Admin id number used to specify the Project
|
/// @param projectId The Admin id number used to specify the Project
|
||||||
/// @return True if the Project has been canceled
|
/// @return True if the Project has been canceled
|
||||||
function isProjectCanceled(uint projectId)
|
function _isProjectCanceled(uint64 projectId)
|
||||||
internal constant returns (bool)
|
internal constant returns (bool)
|
||||||
{
|
{
|
||||||
require(numberOfPledgeAdmins() >= projectId);
|
PledgeAdmin storage a = _findAdmin(projectId);
|
||||||
|
|
||||||
PledgeAdminType adminType = getAdminType(projectId);
|
if (a.adminType == PledgeAdminType.Giver) {
|
||||||
|
|
||||||
if (adminType == PledgeAdminType.Giver) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
assert(adminType == PledgeAdminType.Project);
|
|
||||||
|
|
||||||
if (getAdminCanceled(projectId)) {
|
assert(a.adminType == PledgeAdminType.Project);
|
||||||
|
|
||||||
|
if (a.canceled) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (a.parentProject == 0) {
|
||||||
uint parentProject = getAdminParentProject(projectId);
|
|
||||||
if (parentProject == 0) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isProjectCanceled(parentProject);
|
return _isProjectCanceled(a.parentProject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice Find the level of authority a specific Project has
|
/// @notice Find the level of authority a specific Project has
|
||||||
/// using a recursive loop
|
/// using a recursive loop
|
||||||
/// @param idProject The id of the Project being queried
|
/// @param a The project admin being queried
|
||||||
/// @return The level of authority a specific Project has
|
/// @return The level of authority a specific Project has
|
||||||
function getProjectLevel(uint idProject) internal returns(uint) {
|
function _getProjectLevel(PledgeAdmin a) internal returns(uint64) {
|
||||||
assert(getAdminType(idProject) == PledgeAdminType.Project);
|
assert(a.adminType == PledgeAdminType.Project);
|
||||||
uint parentProject = getAdminParentProject(idProject);
|
|
||||||
if (parentProject == 0) {
|
if (a.parentProject == 0) {
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
return getProjectLevel(parentProject) + 1;
|
|
||||||
|
PledgeAdmin storage parentA = _findAdmin(a.parentProject);
|
||||||
|
return _getProjectLevel(parentA) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function _grantPledgeAdminPermission(address _who, uint64 idPledge) internal {
|
||||||
|
bytes32 id;
|
||||||
|
assembly { id := idPledge }
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
uint[] memory params = new uint[](1);
|
||||||
// Getters for individual attributes of a PledgeAdmin
|
params[0] = uint(bytes32(1 << 8 * 30) | id);
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
function getAdminType(
|
ACL(kernel.acl()).grantPermissionP(_who, address(this), PLEDGE_ADMIN_ROLE, params);
|
||||||
uint idAdmin
|
|
||||||
) internal view returns (PledgeAdminType)
|
|
||||||
{
|
|
||||||
return PledgeAdminType(_storage.stgObjectGetUInt(PLEDGE_ADMIN, idAdmin, "adminType"));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function getAdminAddr(
|
|
||||||
uint idAdmin
|
|
||||||
) internal view returns (address)
|
|
||||||
{
|
|
||||||
return _storage.stgObjectGetAddress(PLEDGE_ADMIN, idAdmin, "addr");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAdminName(
|
|
||||||
uint idAdmin
|
|
||||||
) internal view returns (string)
|
|
||||||
{
|
|
||||||
return _storage.stgObjectGetString(PLEDGE_ADMIN, idAdmin, "name");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAdminParentProject(
|
|
||||||
uint idAdmin
|
|
||||||
) internal view returns (uint)
|
|
||||||
{
|
|
||||||
return _storage.stgObjectGetUInt(PLEDGE_ADMIN, idAdmin, "parentProject");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAdminCanceled(
|
|
||||||
uint idAdmin
|
|
||||||
) internal view returns (bool)
|
|
||||||
{
|
|
||||||
return _storage.stgObjectGetBoolean(PLEDGE_ADMIN, idAdmin, "canceled");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAdminPlugin(
|
|
||||||
uint idAdmin
|
|
||||||
) internal view returns (address)
|
|
||||||
{
|
|
||||||
return _storage.stgObjectGetAddress(PLEDGE_ADMIN, idAdmin, "plugin");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAdminCommitTime(
|
|
||||||
uint idAdmin
|
|
||||||
) internal view returns (uint)
|
|
||||||
{
|
|
||||||
return _storage.stgObjectGetUInt(PLEDGE_ADMIN, idAdmin, "commitTime");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,11 +19,9 @@ pragma solidity ^0.4.18;
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "./EternallyPersistentLib.sol";
|
import "@aragon/os/contracts/apps/AragonApp.sol";
|
||||||
import "./LiquidPledgingStorage.sol";
|
|
||||||
|
|
||||||
contract Pledges is LiquidPledgingStorage {
|
contract Pledges is AragonApp {
|
||||||
using EternallyPersistentLib 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;
|
||||||
|
@ -31,14 +29,10 @@ contract Pledges is LiquidPledgingStorage {
|
||||||
// a constant for when a delegate is requested that is not in the system
|
// a constant for when a delegate is requested that is not in the system
|
||||||
uint64 constant NOTFOUND = 0xFFFFFFFFFFFFFFFF;
|
uint64 constant NOTFOUND = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
|
||||||
// Constants used when dealing with storage/retrieval of Pledges
|
|
||||||
string constant PLEDGE = "Pledge";
|
|
||||||
bytes32 constant PLEDGES_ARRAY = keccak256("pledges");
|
|
||||||
|
|
||||||
enum PledgeState { Pledged, Paying, Paid }
|
enum PledgeState { Pledged, Paying, Paid }
|
||||||
|
|
||||||
struct Pledge {
|
struct Pledge {
|
||||||
uint id; // the id of this Pledge
|
// uint id; // the id of this Pledge
|
||||||
uint amount;
|
uint amount;
|
||||||
uint64 owner; // PledgeAdmin
|
uint64 owner; // PledgeAdmin
|
||||||
uint64[] delegationChain; // List of delegates in order of authority
|
uint64[] delegationChain; // List of delegates in order of authority
|
||||||
|
@ -48,13 +42,17 @@ contract Pledges is LiquidPledgingStorage {
|
||||||
PledgeState pledgeState; // Pledged, Paying, Paid
|
PledgeState pledgeState; // Pledged, Paying, Paid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pledge[] pledges;
|
||||||
|
/// @dev this mapping allows you to search for a specific pledge's
|
||||||
|
/// index number by the hash of that pledge
|
||||||
|
mapping (bytes32 => uint64) hPledge2idx;
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
// Constructor
|
// Constructor
|
||||||
///////////////
|
///////////////
|
||||||
|
|
||||||
function Pledges(address _storage)
|
function Pledges() public {
|
||||||
LiquidPledgingStorage(_storage) public
|
pledges.length = 1; // we reserve the 0 pledge
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +63,7 @@ contract Pledges is LiquidPledgingStorage {
|
||||||
/// @notice A constant getter that returns the total number of pledges
|
/// @notice A constant getter that returns the total number of pledges
|
||||||
/// @return The total number of Pledges in the system
|
/// @return The total number of Pledges in the system
|
||||||
function numberOfPledges() public view returns (uint) {
|
function numberOfPledges() public view returns (uint) {
|
||||||
return _storage.stgCollectionLength(PLEDGES_ARRAY);
|
return pledges.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice A getter that returns the details of the specified pledge
|
/// @notice A getter that returns the details of the specified pledge
|
||||||
|
@ -82,10 +80,10 @@ contract Pledges is LiquidPledgingStorage {
|
||||||
uint64 oldPledge,
|
uint64 oldPledge,
|
||||||
PledgeState pledgeState
|
PledgeState pledgeState
|
||||||
) {
|
) {
|
||||||
Pledge memory p = findPledge(idPledge);
|
Pledge memory p = _findPledge(idPledge);
|
||||||
amount = p.amount;
|
amount = p.amount;
|
||||||
owner = p.owner;
|
owner = p.owner;
|
||||||
nDelegates = uint64(getPledgeDelegateCount(idPledge));
|
nDelegates = uint64(p.delegationChain.length);
|
||||||
intendedProject = p.intendedProject;
|
intendedProject = p.intendedProject;
|
||||||
commitTime = p.commitTime;
|
commitTime = p.commitTime;
|
||||||
oldPledge = p.oldPledge;
|
oldPledge = p.oldPledge;
|
||||||
|
@ -113,89 +111,42 @@ contract Pledges is LiquidPledgingStorage {
|
||||||
/// will revert back to it's previous state
|
/// will revert back to it's previous state
|
||||||
/// @param state The pledge state: Pledged, Paying, or state
|
/// @param state The pledge state: Pledged, Paying, or state
|
||||||
/// @return The hPledge2idx index number
|
/// @return The hPledge2idx index number
|
||||||
function findOrCreatePledge(
|
function _findOrCreatePledge(
|
||||||
uint64 owner,
|
uint64 owner,
|
||||||
uint64[] delegationChain,
|
uint64[] delegationChain,
|
||||||
uint64 intendedProject,
|
uint64 intendedProject,
|
||||||
uint64 commitTime,
|
uint64 commitTime,
|
||||||
uint64 oldPledge,
|
uint64 oldPledge,
|
||||||
PledgeState state
|
PledgeState state
|
||||||
) internal returns (Pledge)
|
) internal returns (uint64)
|
||||||
{
|
{
|
||||||
bytes32 hPledge = keccak256(owner, delegationChain, intendedProject, commitTime, oldPledge, state);
|
bytes32 hPledge = keccak256(owner, delegationChain, intendedProject, commitTime, oldPledge, state);
|
||||||
uint id = _storage.getUIntValue(hPledge);
|
uint64 id = hPledge2idx[hPledge];
|
||||||
if (id > 0) {
|
if (id > 0) {
|
||||||
return Pledge(
|
return id;
|
||||||
id,
|
}
|
||||||
getPledgeAmount(id), //TODO don't fetch this here b/c it may not be needed?
|
|
||||||
|
id = uint64(pledges.length);
|
||||||
|
hPledge2idx[hPledge] = id;
|
||||||
|
pledges.push(
|
||||||
|
Pledge(
|
||||||
|
0,
|
||||||
owner,
|
owner,
|
||||||
delegationChain,
|
delegationChain,
|
||||||
intendedProject,
|
intendedProject,
|
||||||
commitTime,
|
commitTime,
|
||||||
oldPledge,
|
oldPledge,
|
||||||
state);
|
state
|
||||||
}
|
)
|
||||||
|
);
|
||||||
id = _storage.stgCollectionAddItem(PLEDGES_ARRAY);
|
return id;
|
||||||
_storage.setUIntValue(hPledge, id);
|
|
||||||
|
|
||||||
_storage.stgObjectSetUInt(PLEDGE, id, "owner", owner);
|
|
||||||
if (intendedProject > 0) {
|
|
||||||
_storage.stgObjectSetUInt(PLEDGE, id, "intendedProject", intendedProject);
|
|
||||||
}
|
|
||||||
if (commitTime > 0) {
|
|
||||||
_storage.stgObjectSetUInt(PLEDGE, id, "commitTime", commitTime);
|
|
||||||
}
|
|
||||||
if (oldPledge > 0) {
|
|
||||||
_storage.stgObjectSetUInt(PLEDGE, id, "oldPledge", oldPledge);
|
|
||||||
}
|
|
||||||
if (state != PledgeState.Pledged) {
|
|
||||||
_storage.stgObjectSetUInt(PLEDGE, id, "state", uint(state));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delegationChain.length > 0) {
|
|
||||||
_storage.setUIntValue(keccak256("delegationChain", id, "length"), delegationChain.length);
|
|
||||||
|
|
||||||
// TODO pack these? possibly add array method to EternalStorage in anticipation of the new solidity abi encoder
|
|
||||||
for (uint i = 0; i < delegationChain.length; i++) {
|
|
||||||
_storage.setUIntValue(keccak256("delegationChain", id, i), delegationChain[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Pledge(
|
|
||||||
id,
|
|
||||||
0,
|
|
||||||
owner,
|
|
||||||
delegationChain,
|
|
||||||
intendedProject,
|
|
||||||
commitTime,
|
|
||||||
oldPledge,
|
|
||||||
state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param idPledge the id of the pledge to load from storage
|
/// @param idPledge the id of the pledge to load from storage
|
||||||
/// @return The Pledge
|
/// @return The Pledge
|
||||||
function findPledge(uint idPledge) internal view returns(Pledge) {
|
function _findPledge(uint64 idPledge) internal view returns(Pledge storage) {
|
||||||
require(idPledge <= numberOfPledges());
|
require(idPledge < pledges.length);
|
||||||
|
return pledges[idPledge];
|
||||||
uint amount = getPledgeAmount(idPledge);
|
|
||||||
uint owner = getPledgeOwner(idPledge);
|
|
||||||
uint intendedProject = getPledgeIntendedProject(idPledge);
|
|
||||||
uint commitTime = getPledgeCommitTime(idPledge);
|
|
||||||
uint oldPledge = getPledgeOldPledge(idPledge);
|
|
||||||
PledgeState state = getPledgeState(idPledge);
|
|
||||||
uint64[] memory delegates = getPledgeDelegates(idPledge);
|
|
||||||
|
|
||||||
return Pledge(
|
|
||||||
idPledge,
|
|
||||||
amount,
|
|
||||||
uint64(owner),
|
|
||||||
delegates,
|
|
||||||
uint64(intendedProject),
|
|
||||||
uint64(commitTime),
|
|
||||||
uint64(oldPledge),
|
|
||||||
state
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @notice A getter that searches the delegationChain for the level of
|
/// @notice A getter that searches the delegationChain for the level of
|
||||||
|
@ -206,7 +157,7 @@ contract Pledges is LiquidPledgingStorage {
|
||||||
/// `admins` array index `idDelegate` this returns that delegates
|
/// `admins` array index `idDelegate` this returns that delegates
|
||||||
/// corresponding index in the delegationChain. Otherwise it returns
|
/// corresponding index in the delegationChain. Otherwise it returns
|
||||||
/// the NOTFOUND constant
|
/// the NOTFOUND constant
|
||||||
function getDelegateIdx(Pledge p, uint64 idDelegate) internal pure returns(uint64) {
|
function _getDelegateIdx(Pledge p, uint64 idDelegate) internal pure returns(uint64) {
|
||||||
for (uint i = 0; i < p.delegationChain.length; i++) {
|
for (uint i = 0; i < p.delegationChain.length; i++) {
|
||||||
if (p.delegationChain[i] == idDelegate) {
|
if (p.delegationChain[i] == idDelegate) {
|
||||||
return uint64(i);
|
return uint64(i);
|
||||||
|
@ -217,64 +168,13 @@ contract Pledges is LiquidPledgingStorage {
|
||||||
|
|
||||||
/// @notice A getter to find how many old "parent" pledges a specific Pledge
|
/// @notice A getter to find how many old "parent" pledges a specific Pledge
|
||||||
/// had using a self-referential loop
|
/// had using a self-referential loop
|
||||||
/// @param idOldPledge The Pledge being queried
|
/// @param p The Pledge being queried
|
||||||
/// @return The number of old "parent" pledges a specific Pledge had
|
/// @return The number of old "parent" pledges a specific Pledge had
|
||||||
function getPledgeLevel(uint idOldPledge) internal view returns(uint) {
|
function _getPledgeLevel(Pledge p) internal view returns(uint) {
|
||||||
if (idOldPledge == 0) {
|
if (p.oldPledge == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
idOldPledge = _storage.stgObjectGetUInt(PLEDGE, idOldPledge, "oldPledge");
|
Pledge storage oldP = _findPledge(p.oldPledge);
|
||||||
return getPledgeLevel(idOldPledge) + 1; // a loop lookup
|
return _getPledgeLevel(oldP) + 1; // a loop lookup
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
// Getters for individual attributes of a PledgeAdmin
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
function getPledgeOwner(uint idPledge) internal view returns(uint) {
|
|
||||||
return _storage.stgObjectGetUInt(PLEDGE, idPledge, "owner");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPledgeDelegate(uint idPledge, uint index) internal view returns(uint) {
|
|
||||||
return _storage.getUIntValue(keccak256("delegationChain", idPledge, index));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPledgeOldPledge(uint idPledge) internal view returns(uint) {
|
|
||||||
return _storage.stgObjectGetUInt(PLEDGE, idPledge, "oldPledge");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPledgeAmount(uint idPledge) internal view returns(uint) {
|
|
||||||
return _storage.stgObjectGetUInt(PLEDGE, idPledge, "amount");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPledgeIntendedProject(uint idPledge) internal view returns(uint) {
|
|
||||||
return _storage.stgObjectGetUInt(PLEDGE, idPledge, "intendedProject");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPledgeCommitTime(uint idPledge) internal view returns(uint) {
|
|
||||||
return _storage.stgObjectGetUInt(PLEDGE, idPledge, "commitTime");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPledgeState(uint idPledge) internal view returns(PledgeState) {
|
|
||||||
return PledgeState(_storage.stgObjectGetUInt(PLEDGE, idPledge, "state"));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPledgeDelegates(uint idPledge) internal view returns(uint64[]) {
|
|
||||||
//TODO pack/unpack chain
|
|
||||||
uint length = getPledgeDelegateCount(idPledge);
|
|
||||||
uint64[] memory delegates = new uint64[](length);
|
|
||||||
for (uint i = 0; i < length; i++) {
|
|
||||||
delegates[i] = uint64(getPledgeDelegate(idPledge, i));
|
|
||||||
}
|
|
||||||
return delegates;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPledgeDelegateCount(uint idPledge) internal view returns(uint) {
|
|
||||||
return _storage.getUIntValue(keccak256("delegationChain", idPledge, "length"));
|
|
||||||
}
|
|
||||||
|
|
||||||
function setPledgeAmount(uint idPledge, uint amount) internal {
|
|
||||||
_storage.stgObjectSetUInt(PLEDGE, idPledge, "amount", amount);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,13 +42,14 @@
|
||||||
"eslint-plugin-react": "^7.1.0",
|
"eslint-plugin-react": "^7.1.0",
|
||||||
"ganache-cli": "^7.0.0-beta.0",
|
"ganache-cli": "^7.0.0-beta.0",
|
||||||
"lerna": "^2.2.0",
|
"lerna": "^2.2.0",
|
||||||
"random-bytes": "^1.0.0",
|
|
||||||
"mocha": "^3.5.0",
|
"mocha": "^3.5.0",
|
||||||
"solcpiler": "0.0.10",
|
"random-bytes": "^1.0.0",
|
||||||
|
"solcpiler": "^0.0.15",
|
||||||
"web3": "1.0.0-beta.24"
|
"web3": "1.0.0-beta.24"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/Giveth/liquidpledging#readme",
|
"homepage": "https://github.com/Giveth/liquidpledging#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@aragon/os": "3.0.1",
|
||||||
"async": "^2.4.0",
|
"async": "^2.4.0",
|
||||||
"chai": "^4.1.0",
|
"chai": "^4.1.0",
|
||||||
"eth-contract-class": "0.0.6",
|
"eth-contract-class": "0.0.6",
|
||||||
|
|
|
@ -3,15 +3,12 @@
|
||||||
const TestRPC = require('ganache-cli');
|
const TestRPC = require('ganache-cli');
|
||||||
const Web3 = require('web3');
|
const Web3 = require('web3');
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
const liquidpledging = require('../index.js');
|
|
||||||
const EternalStorage = require('../js/eternalStorage');
|
|
||||||
const assertFail = require('./helpers/assertFail');
|
const assertFail = require('./helpers/assertFail');
|
||||||
|
const contracts = require("../build/contracts.js");
|
||||||
|
|
||||||
const { utils } = Web3;
|
const { utils } = Web3;
|
||||||
|
|
||||||
const LiquidPledging = liquidpledging.LiquidPledgingMock;
|
const LiquidPledgingState = require('../index').LiquidPledgingState;
|
||||||
const LPVault = liquidpledging.LPVault;
|
|
||||||
const LiquidPledgingState = liquidpledging.LiquidPledgingState;
|
|
||||||
const assert = chai.assert;
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,6 +33,7 @@ describe('LiquidPledging test', function () {
|
||||||
let adminProject2a;
|
let adminProject2a;
|
||||||
let adminProject3;
|
let adminProject3;
|
||||||
let delegate2;
|
let delegate2;
|
||||||
|
let escapeHatchDestination;
|
||||||
before(async () => {
|
before(async () => {
|
||||||
testrpc = TestRPC.server({
|
testrpc = TestRPC.server({
|
||||||
ws: true,
|
ws: true,
|
||||||
|
@ -55,6 +53,7 @@ describe('LiquidPledging test', function () {
|
||||||
delegate2 = accounts[6];
|
delegate2 = accounts[6];
|
||||||
giver2 = accounts[7];
|
giver2 = accounts[7];
|
||||||
adminProject3 = accounts[8];
|
adminProject3 = accounts[8];
|
||||||
|
escapeHatchDestination = accounts[9];
|
||||||
});
|
});
|
||||||
|
|
||||||
after((done) => {
|
after((done) => {
|
||||||
|
@ -63,13 +62,21 @@ describe('LiquidPledging test', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should deploy LiquidPledging contract', async () => {
|
it('Should deploy LiquidPledging contract', async () => {
|
||||||
vault = await LPVault.new(web3, accounts[0], accounts[1]);
|
const baseVault = await contracts.LPVault.new(web3);
|
||||||
const storage = await EternalStorage.new(web3, accounts[0], accounts[1]);
|
const baseLP = await contracts.LiquidPledgingMock.new(web3);
|
||||||
|
lpFactory = await contracts.LPFactory.new(web3, baseVault.$address, baseLP.$address);
|
||||||
|
|
||||||
liquidPledging = await LiquidPledging.new(web3, storage.$address, vault.$address, accounts[0], accounts[0], {gas: 6700000})
|
const r = await lpFactory.newLP(accounts[0], escapeHatchDestination);
|
||||||
|
|
||||||
await storage.changeOwnership(liquidPledging.$address);
|
const vaultAddress = r.events.DeployVault.returnValues.vault;
|
||||||
await vault.setLiquidPledging(liquidPledging.$address);
|
vault = new contracts.LPVault(web3, vaultAddress);
|
||||||
|
|
||||||
|
const lpAddress = r.events.DeployLiquidPledging.returnValues.liquidPledging;
|
||||||
|
lp = new contracts.LiquidPledgingMock(web3, lpAddress);
|
||||||
|
|
||||||
|
// setup permissions
|
||||||
|
// const kernel = new contracts.Kernel(web3, await vault.kernel());
|
||||||
|
// const acl = new contracts.ACL(web3, await kernel.acl());
|
||||||
|
|
||||||
liquidPledgingState = new LiquidPledgingState(liquidPledging);
|
liquidPledgingState = new LiquidPledgingState(liquidPledging);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue