From 4cfebbc5fb1062159faf439b91a1ba747c489dca Mon Sep 17 00:00:00 2001 From: perissology Date: Tue, 13 Feb 2018 00:24:26 +0100 Subject: [PATCH] moving things around / cleanup --- contracts/EternalStorage.sol | 96 ------- contracts/EternallyPersistentLib.sol | 108 -------- contracts/LiquidPledging.sol | 369 +-------------------------- contracts/LiquidPledgingBase.sol | 353 ++++++++++++++++++++++++- contracts/LiquidPledgingStorage.sol | 12 - index.js | 6 +- js/eternalStorage.js | 6 - js/liquidPledging.js | 6 - js/liquidPledgingMock.js | 5 - js/vault.js | 5 - test/AdminPlugins.js | 5 +- test/CancelPledge.js | 5 +- test/DelegationChain.js | 3 +- test/NormalOperation.js | 3 +- test/NormalizePledge.js | 5 +- test/Vault.js | 5 +- 16 files changed, 361 insertions(+), 631 deletions(-) delete mode 100644 contracts/EternalStorage.sol delete mode 100644 contracts/EternallyPersistentLib.sol delete mode 100644 contracts/LiquidPledgingStorage.sol delete mode 100644 js/eternalStorage.js delete mode 100644 js/liquidPledging.js delete mode 100644 js/liquidPledgingMock.js delete mode 100644 js/vault.js diff --git a/contracts/EternalStorage.sol b/contracts/EternalStorage.sol deleted file mode 100644 index 3531808..0000000 --- a/contracts/EternalStorage.sol +++ /dev/null @@ -1,96 +0,0 @@ -pragma solidity ^0.4.0; - -import "node_modules/giveth-common-contracts/contracts/Escapable.sol"; - -contract EternalStorage is Escapable { - - mapping(bytes32 => uint) UIntStorage; - mapping(bytes32 => int) IntStorage; - mapping(bytes32 => bool) BooleanStorage; - mapping(bytes32 => address) AddressStorage; - mapping(bytes32 => string) StringStorage; - mapping(bytes32 => bytes) BytesStorage; - mapping(bytes32 => bytes32) Bytes32Storage; - - function EternalStorage(address _escapeHatchCaller, address _escapeHatchDestination) - Escapable(_escapeHatchCaller, _escapeHatchDestination) public { - } - - /// UInt Storage - - function getUIntValue(bytes32 record) public view returns (uint) { - return UIntStorage[record]; - } - - function setUIntValue(bytes32 record, uint value) public onlyOwner { - UIntStorage[record] = value; - } - - function incrementUIntValue(bytes32 record) public returns (uint) { - return UIntStorage[record] += 1; - } - - /// Int Storage - - function getIntValue(bytes32 record) public view returns (int) { - return IntStorage[record]; - } - - function setIntValue(bytes32 record, int value) public onlyOwner { - IntStorage[record] = value; - } - - function incrementIntValue(bytes32 record) public returns (int) { - return IntStorage[record] += int(1); - } - - /// Address Storage - - function getAddressValue(bytes32 record) public view returns (address) { - return AddressStorage[record]; - } - - function setAddressValue(bytes32 record, address value) public onlyOwner { - AddressStorage[record] = value; - } - - /// String Storage - - function getStringValue(bytes32 record) public view returns (string) { - return StringStorage[record]; - } - - function setStringValue(bytes32 record, string value) public onlyOwner { - StringStorage[record] = value; - } - - /// Bytes Storage - - function getBytesValue(bytes32 record) public view returns (bytes) { - return BytesStorage[record]; - } - - function setBytesValue(bytes32 record, bytes value) public onlyOwner { - BytesStorage[record] = value; - } - - /// Bytes Storage - - function getBytes32Value(bytes32 record) public view returns (bytes32) { - return Bytes32Storage[record]; - } - - function setBytes32Value(bytes32 record, bytes32 value) public onlyOwner { - Bytes32Storage[record] = value; - } - - /// Boolean Storage - - function getBooleanValue(bytes32 record) public view returns (bool) { - return BooleanStorage[record]; - } - - function setBooleanValue(bytes32 record, bool value) public onlyOwner { - BooleanStorage[record] = value; - } -} diff --git a/contracts/EternallyPersistentLib.sol b/contracts/EternallyPersistentLib.sol deleted file mode 100644 index 067074a..0000000 --- a/contracts/EternallyPersistentLib.sol +++ /dev/null @@ -1,108 +0,0 @@ -pragma solidity ^0.4.0; - -import "./EternalStorage.sol"; - -library EternallyPersistentLib { - - // UInt - //TODO if we use assembly here, we can save ~ 600 gas / call, due to skipping the extcodesize check that solidity adds. - - function stgObjectGetUInt(EternalStorage _storage, string class, uint id, string fieldName) internal view returns (uint) { - bytes32 record = keccak256(class, id, fieldName); - return _storage.getUIntValue(record); - } - - function stgObjectSetUInt(EternalStorage _storage, string class, uint id, string fieldName, uint value) internal { - bytes32 record = keccak256(class, id, fieldName); - return _storage.setUIntValue(record, value); - } - - // Boolean - - function stgObjectGetBoolean(EternalStorage _storage, string class, uint id, string fieldName) internal view returns (bool) { - bytes32 record = keccak256(class, id, fieldName); - return _storage.getBooleanValue(record); - } - - function stgObjectSetBoolean(EternalStorage _storage, string class, uint id, string fieldName, bool value) internal { - bytes32 record = keccak256(class, id, fieldName); - return _storage.setBooleanValue(record, value); - } - - // string - - function stgObjectGetString(EternalStorage _storage, string class, uint id, string fieldName) internal view returns (string) { - bytes32 record = keccak256(class, id, fieldName); - bytes4 sig = 0xa209a29c; // bytes4(keccak256("getStringValue(bytes32)")); - string memory s; - - assembly { - let ptr := mload(0x40) //Find empty storage location using "free memory pointer" - mstore(ptr, sig) //Place signature at beginning of empty storage - mstore(add(ptr, 0x04), record) //Place first argument directly next to signature - - let result := staticcall(sub(gas, 10000), _storage, ptr, 0x24, 0, 0) - - let size := returndatasize - returndatacopy(ptr, 0, size) // overwrite ptr to save a bit of gas - - // revert instead of invalid() bc if the underlying call failed with invalid() it already wasted gas. - // if the call returned error data, forward it - switch result case 0 { revert(ptr, size) } - default { - mstore(0x40, add(ptr, size)) // update free mem location - // We need to skip the first 32 bytes which contains the start offset of the returned byte array - s := add(ptr, 0x20) // set the string - } - } - - return s; - } - - function stgObjectSetString(EternalStorage _storage, string class, uint id, string fieldName, string value) internal { - bytes32 record = keccak256(class, id, fieldName); - return _storage.setStringValue(record, value); - } - - // address - - function stgObjectGetAddress(EternalStorage _storage, string class, uint id, string fieldName) internal view returns (address) { - bytes32 record = keccak256(class, id, fieldName); - return _storage.getAddressValue(record); - } - - function stgObjectSetAddress(EternalStorage _storage, string class, uint id, string fieldName, address value) internal { - bytes32 record = keccak256(class, id, fieldName); - return _storage.setAddressValue(record, value); - } - - // bytes32 - - function stgObjectGetBytes32(EternalStorage _storage, string class, uint id, string fieldName) internal view returns (bytes32) { - bytes32 record = keccak256(class, id, fieldName); - return _storage.getBytes32Value(record); - } - - function stgObjectSetBytes32(EternalStorage _storage, string class, uint id, string fieldName, bytes32 value) internal { - bytes32 record = keccak256(class, id, fieldName); - return _storage.setBytes32Value(record, value); - } - - // Array - - function stgCollectionAddItem(EternalStorage _storage, bytes32 idArray) internal returns (uint) { - return _storage.incrementUIntValue(keccak256(idArray, "length")); - } - - function stgCollectionLength(EternalStorage _storage, bytes32 idArray) internal view returns (uint) { - return _storage.getUIntValue(keccak256(idArray, "length")); - } - - function stgCollectionIdFromIdx(EternalStorage _storage, bytes32 idArray, uint idx) internal view returns (bytes32) { - return _storage.getBytes32Value(keccak256(idArray, idx)); - } - - function stgUpgrade(EternalStorage _storage, address newContract) internal { - _storage.changeOwnership(newContract); - } -} \ No newline at end of file diff --git a/contracts/LiquidPledging.sol b/contracts/LiquidPledging.sol index c332fd8..8377259 100644 --- a/contracts/LiquidPledging.sol +++ b/contracts/LiquidPledging.sol @@ -27,7 +27,6 @@ import "./LiquidPledgingBase.sol"; /// to allow for expanded functionality. contract LiquidPledging is LiquidPledgingBase { - /// @notice This is how value enters the system and how pledges are created; /// the ether is sent to the vault, an pledge for the Giver is created (or /// found), the amount of ETH donated in wei is added to the `amount` in @@ -39,7 +38,6 @@ contract LiquidPledging is LiquidPledgingBase { function donate(uint64 idGiver, uint64 idReceiver) public payable { - // TODO: maybe need a separate role here to allow giver creation if (idGiver == 0) { // default to a 3 day (259200 seconds) commitTime idGiver = uint64(addGiver("", "", 259200, ILiquidPledgingPlugin(0x0))); @@ -93,9 +91,7 @@ contract LiquidPledging is LiquidPledgingBase { Pledges.Pledge storage p = _findPledge(idPledge); PledgeAdmins.PledgeAdmin storage receiver = _findAdmin(idReceiver); - // PledgeAdmins.PledgeAdmin storage sender = _findAdmin(idSender); - // _checkAdminOwner(sender); require(p.pledgeState == PledgeState.Pledged); // If the sender is the owner of the Pledge @@ -128,7 +124,7 @@ contract LiquidPledging is LiquidPledgingBase { } else { // owner is not vetoing an intendedProject and is transferring the pledge to a delegate, // so we want to reset the delegationChain - idPledge = _undelegate( + idPledge = _undelegate( idPledge, amount, p.delegationChain.length @@ -241,7 +237,6 @@ contract LiquidPledging is LiquidPledgingBase { /// @param idPledge Id of the pledge that is to be withdrawn /// @param amount Quantity of ether (in wei) to be withdrawn function confirmPayment(uint64 idPledge, uint amount) public onlyVault { - //TODO don't fetch entire pledge Pledges.Pledge storage p = _findPledge(idPledge); require(p.pledgeState == Pledges.PledgeState.Paying); @@ -297,15 +292,13 @@ contract LiquidPledging is LiquidPledgingBase { /// @param idPledge Id of the pledge that is to be canceled /// @param amount Quantity of ether (in wei) to be transfered to the /// `oldPledge` - function cancelPledge(uint64 idPledge, uint amount) public {//authP(PLEDGE_ADMIN_ROLE, arr(uint(idPledge))) public { + function cancelPledge(uint64 idPledge, uint amount) public { idPledge = normalizePledge(idPledge); Pledges.Pledge storage p = _findPledge(idPledge); require(p.oldPledge != 0); require(canPerform(msg.sender, PLEDGE_ADMIN_ROLE, arr(uint(p.owner)))); - // PledgeAdmins.PledgeAdmin storage a = _findAdmin(p.owner); - // _checkAdminOwner(a); uint64 oldPledge = _getOldestPledgeNotCanceled(p.oldPledge); _doTransfer(idPledge, oldPledge, amount); @@ -396,192 +389,6 @@ contract LiquidPledging is LiquidPledgingBase { } } -//////// -// Private methods -/////// - - /// @notice `transferOwnershipToProject` allows for the transfer of - /// 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 - /// @param idPledge the id of the pledge to be transfered. - /// @param amount Quantity of value that's being transfered - /// @param idReceiver The new owner of the project (or self to un-delegate) - function _transferOwnershipToProject( - uint64 idPledge, - uint amount, - uint64 idReceiver - ) internal - { - Pledges.Pledge storage p = _findPledge(idPledge); - - // Ensure that the pledge is not already at max pledge depth - // and the project has not been canceled - require(_getPledgeLevel(p) < MAX_INTERPROJECT_LEVEL); - require(!_isProjectCanceled(idReceiver)); - - uint64 oldPledge = _findOrCreatePledge( - p.owner, - p.delegationChain, - 0, - 0, - p.oldPledge, - Pledges.PledgeState.Pledged - ); - uint64 toPledge = _findOrCreatePledge( - idReceiver, // Set the new owner - new uint64[](0), // clear the delegation chain - 0, - 0, - uint64(oldPledge), - Pledges.PledgeState.Pledged - ); - _doTransfer(idPledge, toPledge, amount); - } - - - /// @notice `transferOwnershipToGiver` allows for the transfer of - /// value back to the Giver, value is placed in a pledged state - /// without being attached to a project, delegation chain, or time line. - /// @param idPledge the id of the pledge to be transfered. - /// @param amount Quantity of value that's being transfered - /// @param idReceiver The new owner of the pledge - function _transferOwnershipToGiver( - uint64 idPledge, - uint amount, - uint64 idReceiver - ) internal - { - uint64 toPledge = _findOrCreatePledge( - idReceiver, - new uint64[](0), - 0, - 0, - 0, - Pledges.PledgeState.Pledged - ); - _doTransfer(idPledge, toPledge, amount); - } - - /// @notice `appendDelegate` allows for a delegate to be added onto the - /// end of the delegate chain for a given Pledge. - /// @param idPledge the id of the pledge thats delegate chain will be modified. - /// @param amount Quantity of value that's being chained. - /// @param idReceiver The delegate to be added at the end of the chain - function _appendDelegate( - uint64 idPledge, - uint amount, - uint64 idReceiver - ) internal - { - Pledges.Pledge storage p = _findPledge(idPledge); - - require(p.delegationChain.length < MAX_DELEGATES); - uint64[] memory newDelegationChain = new uint64[]( - p.delegationChain.length + 1 - ); - for (uint i = 0; i < p.delegationChain.length; i++) { - newDelegationChain[i] = p.delegationChain[i]; - } - - // Make the last item in the array the idReceiver - newDelegationChain[p.delegationChain.length] = idReceiver; - - uint64 toPledge = _findOrCreatePledge( - p.owner, - newDelegationChain, - 0, - 0, - p.oldPledge, - Pledges.PledgeState.Pledged - ); - _doTransfer(idPledge, toPledge, amount); - } - - /// @notice `appendDelegate` allows for a delegate to be added onto the - /// end of the delegate chain for a given Pledge. - /// @param idPledge the id of the pledge thats delegate chain will be modified. - /// @param amount Quantity of value that's shifted from delegates. - /// @param q Number (or depth) of delegates to remove - /// @return toPledge The id for the pledge being adjusted or created - function _undelegate( - uint64 idPledge, - uint amount, - uint q - ) internal returns (uint64 toPledge) - { - Pledges.Pledge storage p = _findPledge(idPledge); - uint64[] memory newDelegationChain = new uint64[]( - p.delegationChain.length - q - ); - - for (uint i = 0; i < p.delegationChain.length - q; i++) { - newDelegationChain[i] = p.delegationChain[i]; - } - toPledge = _findOrCreatePledge( - p.owner, - newDelegationChain, - 0, - 0, - p.oldPledge, - Pledges.PledgeState.Pledged - ); - _doTransfer(idPledge, toPledge, amount); - } - - /// @notice `proposeAssignProject` proposes the assignment of a pledge - /// to a specific project. - /// @dev This function should potentially be named more specifically. - /// @param idPledge the id of the pledge that will be assigned. - /// @param amount Quantity of value this pledge leader would be assigned. - /// @param idReceiver The project this pledge will potentially - /// be assigned to. - function _proposeAssignProject( - uint64 idPledge, - uint amount, - uint64 idReceiver - ) internal - { - Pledges.Pledge storage p = _findPledge(idPledge); - - require(_getPledgeLevel(p) < MAX_INTERPROJECT_LEVEL); - require(!_isProjectCanceled(idReceiver)); - - uint64 toPledge = _findOrCreatePledge( - p.owner, - p.delegationChain, - idReceiver, - uint64(_getTime() + _maxCommitTime(p)), - p.oldPledge, - Pledges.PledgeState.Pledged - ); - _doTransfer(idPledge, toPledge, amount); - } - - /// @notice `doTransfer` is designed to allow for pledge amounts to be - /// shifted around internally. - /// @param from This is the id of the pledge from which value will be transfered. - /// @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. - function _doTransfer(uint64 from, uint64 to, uint _amount) internal { - uint amount = _callPlugins(true, from, to, _amount); - if (from == to) { - return; - } - if (amount == 0) { - return; - } - - Pledges.Pledge storage pFrom = _findPledge(from); - Pledges.Pledge storage pTo = _findPledge(to); - - require(pFrom.amount >= amount); - pFrom.amount -= amount; - pTo.amount += amount; - - Transfer(from, to, amount); - _callPlugins(false, from, to, amount); - } - /// @notice Only affects pledges with the Pledged Pledges.PledgeState for 2 things: /// #1: Checks if the pledge should be committed. This means that /// if the pledge has an intendedProject and it is past the @@ -638,176 +445,4 @@ contract LiquidPledging is LiquidPledgingBase { return toPledge; } - -///////////// -// Plugins -///////////// - - /// @notice `callPlugin` is used to trigger the general functions in the - /// plugin for any actions needed before and after a transfer happens. - /// Specifically what this does in relation to the plugin is something - /// that largely depends on the functions of that plugin. This function - /// is generally called in pairs, once before, and once after a transfer. - /// @param before This toggle determines whether the plugin call is occurring - /// before or after a transfer. - /// @param adminId This should be the Id of the *trusted* individual - /// who has control over this plugin. - /// @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 context The situation that is triggering the plugin. See plugin - /// for a full description of contexts. - /// @param amount The amount of value that is being transfered. - function _callPlugin( - bool before, - uint64 adminId, - uint64 fromPledge, - uint64 toPledge, - uint64 context, - uint amount - ) internal returns (uint allowedAmount) { - - uint newAmount; - allowedAmount = amount; - PledgeAdmins.PledgeAdmin storage admin = _findAdmin(adminId); - - // Checks admin has a plugin assigned and a non-zero amount is requested - if (address(admin.plugin) != 0 && allowedAmount > 0) { - // There are two seperate functions called in the plugin. - // One is called before the transfer and one after - if (before) { - newAmount = admin.plugin.beforeTransfer( - adminId, - fromPledge, - toPledge, - context, - amount - ); - require(newAmount <= allowedAmount); - allowedAmount = newAmount; - } else { - admin.plugin.afterTransfer( - adminId, - fromPledge, - toPledge, - context, - amount - ); - } - } - } - - /// @notice `callPluginsPledge` is used to apply plugin calls to - /// the delegate chain and the intended project if there is one. - /// It does so in either a transferring or receiving context based - /// on the `p` and `fromPledge` parameters. - /// @param before This toggle determines whether the plugin call is occuring - /// before or after a transfer. - /// @param idPledge This is the id of the pledge on which this plugin - /// is being called. - /// @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 amount The amount of value that is being transfered. - function _callPluginsPledge( - bool before, - uint64 idPledge, - uint64 fromPledge, - uint64 toPledge, - uint amount - ) internal returns (uint allowedAmount) { - // Determine if callPlugin is being applied in a receiving - // or transferring context - uint64 offset = idPledge == fromPledge ? 0 : 256; - allowedAmount = amount; - Pledges.Pledge storage p = _findPledge(idPledge); - - // Always call the plugin on the owner - allowedAmount = _callPlugin( - before, - p.owner, - fromPledge, - toPledge, - offset, - allowedAmount - ); - - // Apply call plugin to all delegates - for (uint64 i = 0; i < p.delegationChain.length; i++) { - allowedAmount = _callPlugin( - before, - p.delegationChain[i], - fromPledge, - toPledge, - offset + i + 1, - allowedAmount - ); - } - - // If there is an intended project also call the plugin in - // either a transferring or receiving context based on offset - // on the intended project - if (p.intendedProject > 0) { - allowedAmount = _callPlugin( - before, - p.intendedProject, - fromPledge, - toPledge, - offset + 255, - allowedAmount - ); - } - } - - - /// @notice `callPlugins` calls `callPluginsPledge` once for the transfer - /// context and once for the receiving context. The aggregated - /// allowed amount is then returned. - /// @param before This toggle determines whether the plugin call is occurring - /// before or after a transfer. - /// @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 amount The amount of value that is being transferred. - function _callPlugins( - bool before, - uint64 fromPledge, - uint64 toPledge, - uint amount - ) internal returns (uint allowedAmount) { - allowedAmount = amount; - - // Call the pledges plugins in the transfer context - allowedAmount = _callPluginsPledge( - before, - fromPledge, - fromPledge, - toPledge, - allowedAmount - ); - - // Call the pledges plugins in the receive context - allowedAmount = _callPluginsPledge( - before, - toPledge, - fromPledge, - toPledge, - allowedAmount - ); - } - -///////////// -// Test functions -///////////// - - /// @notice Basic helper function to return the current time - function _getTime() internal view returns (uint) { - return now; - } - - function getTime() public view returns(uint) { - return _getTime(); - } - - // Event Declarations - event Transfer(uint indexed from, uint indexed to, uint amount); - event CancelProject(uint indexed idProject); - } diff --git a/contracts/LiquidPledgingBase.sol b/contracts/LiquidPledgingBase.sol index c1cea00..b28e6d1 100644 --- a/contracts/LiquidPledgingBase.sol +++ b/contracts/LiquidPledgingBase.sol @@ -38,6 +38,10 @@ interface ILPVault { /// data structures contract LiquidPledgingBase is PledgeAdmins, Pledges, EscapableApp { + // Event Declarations + event Transfer(uint indexed from, uint indexed to, uint amount); + event CancelProject(uint indexed idProject); + ILPVault public vault; ///////////// @@ -51,7 +55,6 @@ contract LiquidPledgingBase is PledgeAdmins, Pledges, EscapableApp { _; } - /////////////// // Constructor /////////////// @@ -99,12 +102,187 @@ contract LiquidPledgingBase is PledgeAdmins, Pledges, EscapableApp { // Internal methods //////////////////// - /// @notice A check to see if the msg.sender is the owner or the - /// plugin contract for a specific Admin - /// @param a The admin being checked - // function _checkAdminOwner(PledgeAdmin a) internal constant { - // require(msg.sender == a.addr || msg.sender == address(a.plugin)); - // } + /// @notice `transferOwnershipToProject` allows for the transfer of + /// 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 + /// @param idPledge the id of the pledge to be transfered. + /// @param amount Quantity of value that's being transfered + /// @param idReceiver The new owner of the project (or self to un-delegate) + function _transferOwnershipToProject( + uint64 idPledge, + uint amount, + uint64 idReceiver + ) internal + { + Pledges.Pledge storage p = _findPledge(idPledge); + + // Ensure that the pledge is not already at max pledge depth + // and the project has not been canceled + require(_getPledgeLevel(p) < MAX_INTERPROJECT_LEVEL); + require(!_isProjectCanceled(idReceiver)); + + uint64 oldPledge = _findOrCreatePledge( + p.owner, + p.delegationChain, + 0, + 0, + p.oldPledge, + Pledges.PledgeState.Pledged + ); + uint64 toPledge = _findOrCreatePledge( + idReceiver, // Set the new owner + new uint64[](0), // clear the delegation chain + 0, + 0, + uint64(oldPledge), + Pledges.PledgeState.Pledged + ); + _doTransfer(idPledge, toPledge, amount); + } + + + /// @notice `transferOwnershipToGiver` allows for the transfer of + /// value back to the Giver, value is placed in a pledged state + /// without being attached to a project, delegation chain, or time line. + /// @param idPledge the id of the pledge to be transfered. + /// @param amount Quantity of value that's being transfered + /// @param idReceiver The new owner of the pledge + function _transferOwnershipToGiver( + uint64 idPledge, + uint amount, + uint64 idReceiver + ) internal + { + uint64 toPledge = _findOrCreatePledge( + idReceiver, + new uint64[](0), + 0, + 0, + 0, + Pledges.PledgeState.Pledged + ); + _doTransfer(idPledge, toPledge, amount); + } + + /// @notice `appendDelegate` allows for a delegate to be added onto the + /// end of the delegate chain for a given Pledge. + /// @param idPledge the id of the pledge thats delegate chain will be modified. + /// @param amount Quantity of value that's being chained. + /// @param idReceiver The delegate to be added at the end of the chain + function _appendDelegate( + uint64 idPledge, + uint amount, + uint64 idReceiver + ) internal + { + Pledges.Pledge storage p = _findPledge(idPledge); + + require(p.delegationChain.length < MAX_DELEGATES); + uint64[] memory newDelegationChain = new uint64[]( + p.delegationChain.length + 1 + ); + for (uint i = 0; i < p.delegationChain.length; i++) { + newDelegationChain[i] = p.delegationChain[i]; + } + + // Make the last item in the array the idReceiver + newDelegationChain[p.delegationChain.length] = idReceiver; + + uint64 toPledge = _findOrCreatePledge( + p.owner, + newDelegationChain, + 0, + 0, + p.oldPledge, + Pledges.PledgeState.Pledged + ); + _doTransfer(idPledge, toPledge, amount); + } + + /// @notice `appendDelegate` allows for a delegate to be added onto the + /// end of the delegate chain for a given Pledge. + /// @param idPledge the id of the pledge thats delegate chain will be modified. + /// @param amount Quantity of value that's shifted from delegates. + /// @param q Number (or depth) of delegates to remove + /// @return toPledge The id for the pledge being adjusted or created + function _undelegate( + uint64 idPledge, + uint amount, + uint q + ) internal returns (uint64 toPledge) + { + Pledges.Pledge storage p = _findPledge(idPledge); + uint64[] memory newDelegationChain = new uint64[]( + p.delegationChain.length - q + ); + + for (uint i = 0; i < p.delegationChain.length - q; i++) { + newDelegationChain[i] = p.delegationChain[i]; + } + toPledge = _findOrCreatePledge( + p.owner, + newDelegationChain, + 0, + 0, + p.oldPledge, + Pledges.PledgeState.Pledged + ); + _doTransfer(idPledge, toPledge, amount); + } + + /// @notice `proposeAssignProject` proposes the assignment of a pledge + /// to a specific project. + /// @dev This function should potentially be named more specifically. + /// @param idPledge the id of the pledge that will be assigned. + /// @param amount Quantity of value this pledge leader would be assigned. + /// @param idReceiver The project this pledge will potentially + /// be assigned to. + function _proposeAssignProject( + uint64 idPledge, + uint amount, + uint64 idReceiver + ) internal + { + Pledges.Pledge storage p = _findPledge(idPledge); + + require(_getPledgeLevel(p) < MAX_INTERPROJECT_LEVEL); + require(!_isProjectCanceled(idReceiver)); + + uint64 toPledge = _findOrCreatePledge( + p.owner, + p.delegationChain, + idReceiver, + uint64(_getTime() + _maxCommitTime(p)), + p.oldPledge, + Pledges.PledgeState.Pledged + ); + _doTransfer(idPledge, toPledge, amount); + } + + /// @notice `doTransfer` is designed to allow for pledge amounts to be + /// shifted around internally. + /// @param from This is the id of the pledge from which value will be transfered. + /// @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. + function _doTransfer(uint64 from, uint64 to, uint _amount) internal { + uint amount = _callPlugins(true, from, to, _amount); + if (from == to) { + return; + } + if (amount == 0) { + return; + } + + Pledges.Pledge storage pFrom = _findPledge(from); + Pledges.Pledge storage pTo = _findPledge(to); + + require(pFrom.amount >= amount); + pFrom.amount -= amount; + pTo.amount += amount; + + Transfer(from, to, amount); + _callPlugins(false, from, to, amount); + } /// @notice A getter to find the longest commitTime out of the owner and all /// the delegates for a specified pledge @@ -149,4 +327,165 @@ contract LiquidPledgingBase is PledgeAdmins, Pledges, EscapableApp { return _getOldestPledgeNotCanceled(p.oldPledge); } + + /// @notice `callPlugin` is used to trigger the general functions in the + /// plugin for any actions needed before and after a transfer happens. + /// Specifically what this does in relation to the plugin is something + /// that largely depends on the functions of that plugin. This function + /// is generally called in pairs, once before, and once after a transfer. + /// @param before This toggle determines whether the plugin call is occurring + /// before or after a transfer. + /// @param adminId This should be the Id of the *trusted* individual + /// who has control over this plugin. + /// @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 context The situation that is triggering the plugin. See plugin + /// for a full description of contexts. + /// @param amount The amount of value that is being transfered. + function _callPlugin( + bool before, + uint64 adminId, + uint64 fromPledge, + uint64 toPledge, + uint64 context, + uint amount + ) internal returns (uint allowedAmount) + { + + uint newAmount; + allowedAmount = amount; + PledgeAdmins.PledgeAdmin storage admin = _findAdmin(adminId); + + // Checks admin has a plugin assigned and a non-zero amount is requested + if (address(admin.plugin) != 0 && allowedAmount > 0) { + // There are two seperate functions called in the plugin. + // One is called before the transfer and one after + if (before) { + newAmount = admin.plugin.beforeTransfer( + adminId, + fromPledge, + toPledge, + context, + amount + ); + require(newAmount <= allowedAmount); + allowedAmount = newAmount; + } else { + admin.plugin.afterTransfer( + adminId, + fromPledge, + toPledge, + context, + amount + ); + } + } + } + + /// @notice `callPluginsPledge` is used to apply plugin calls to + /// the delegate chain and the intended project if there is one. + /// It does so in either a transferring or receiving context based + /// on the `p` and `fromPledge` parameters. + /// @param before This toggle determines whether the plugin call is occuring + /// before or after a transfer. + /// @param idPledge This is the id of the pledge on which this plugin + /// is being called. + /// @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 amount The amount of value that is being transfered. + function _callPluginsPledge( + bool before, + uint64 idPledge, + uint64 fromPledge, + uint64 toPledge, + uint amount + ) internal returns (uint allowedAmount) + { + // Determine if callPlugin is being applied in a receiving + // or transferring context + uint64 offset = idPledge == fromPledge ? 0 : 256; + allowedAmount = amount; + Pledges.Pledge storage p = _findPledge(idPledge); + + // Always call the plugin on the owner + allowedAmount = _callPlugin( + before, + p.owner, + fromPledge, + toPledge, + offset, + allowedAmount + ); + + // Apply call plugin to all delegates + for (uint64 i = 0; i < p.delegationChain.length; i++) { + allowedAmount = _callPlugin( + before, + p.delegationChain[i], + fromPledge, + toPledge, + offset + i + 1, + allowedAmount + ); + } + + // If there is an intended project also call the plugin in + // either a transferring or receiving context based on offset + // on the intended project + if (p.intendedProject > 0) { + allowedAmount = _callPlugin( + before, + p.intendedProject, + fromPledge, + toPledge, + offset + 255, + allowedAmount + ); + } + } + + /// @notice `callPlugins` calls `callPluginsPledge` once for the transfer + /// context and once for the receiving context. The aggregated + /// allowed amount is then returned. + /// @param before This toggle determines whether the plugin call is occurring + /// before or after a transfer. + /// @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 amount The amount of value that is being transferred. + function _callPlugins( + bool before, + uint64 fromPledge, + uint64 toPledge, + uint amount + ) internal returns (uint allowedAmount) + { + allowedAmount = amount; + + // Call the pledges plugins in the transfer context + allowedAmount = _callPluginsPledge( + before, + fromPledge, + fromPledge, + toPledge, + allowedAmount + ); + + // Call the pledges plugins in the receive context + allowedAmount = _callPluginsPledge( + before, + toPledge, + fromPledge, + toPledge, + allowedAmount + ); + } + +///////////// +// Test functions +///////////// + + /// @notice Basic helper function to return the current time + function _getTime() internal view returns (uint) { + return now; + } } diff --git a/contracts/LiquidPledgingStorage.sol b/contracts/LiquidPledgingStorage.sol deleted file mode 100644 index f7573bc..0000000 --- a/contracts/LiquidPledgingStorage.sol +++ /dev/null @@ -1,12 +0,0 @@ -pragma solidity ^0.4.18; - -import "./EternalStorage.sol"; - -contract LiquidPledgingStorage { - - EternalStorage public _storage; - - function LiquidPledgingStorage(address _s) public { - _storage = EternalStorage(_s); - } -} \ No newline at end of file diff --git a/index.js b/index.js index f2fe61c..790e712 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -exports.LiquidPledging = require('./lib/liquidPledging.js'); -exports.LiquidPledgingMock = require('./lib/liquidPledgingMock.js'); +const contracts = require('./build/contracts'); +exports.LiquidPledging = contracts.LiquidPledging; exports.LiquidPledgingState = require('./lib/liquidPledgingState.js'); -exports.LPVault = require('./lib/vault.js'); +exports.LPVault = contracts.LPVault; diff --git a/js/eternalStorage.js b/js/eternalStorage.js deleted file mode 100644 index 4351a62..0000000 --- a/js/eternalStorage.js +++ /dev/null @@ -1,6 +0,0 @@ -const EternalStorageAbi = require('../build/EternalStorage.sol').EternalStorageAbi; -const EternalStorageCode = require('../build/EternalStorage.sol').EternalStorageByteCode; -const generateClass = require('eth-contract-class').default; - -module.exports = generateClass(EternalStorageAbi, EternalStorageCode); - diff --git a/js/liquidPledging.js b/js/liquidPledging.js deleted file mode 100644 index 55b709c..0000000 --- a/js/liquidPledging.js +++ /dev/null @@ -1,6 +0,0 @@ -const LiquidPledgingAbi = require('../build/LiquidPledging.sol').LiquidPledgingAbi; -const LiquidPledgingCode = require('../build/LiquidPledging.sol').LiquidPledgingByteCode; -const generateClass = require('eth-contract-class').default; - -module.exports = generateClass(LiquidPledgingAbi, LiquidPledgingCode); - diff --git a/js/liquidPledgingMock.js b/js/liquidPledgingMock.js deleted file mode 100644 index bd69d80..0000000 --- a/js/liquidPledgingMock.js +++ /dev/null @@ -1,5 +0,0 @@ -const LiquidPledgingMockAbi = require('../build/LiquidPledgingMock.sol').LiquidPledgingMockAbi; -const LiquidPledgingMockCode = require('../build/LiquidPledgingMock.sol').LiquidPledgingMockByteCode; -const generateClass = require('eth-contract-class').default; - -module.exports = generateClass(LiquidPledgingMockAbi, LiquidPledgingMockCode); diff --git a/js/vault.js b/js/vault.js deleted file mode 100644 index ef19239..0000000 --- a/js/vault.js +++ /dev/null @@ -1,5 +0,0 @@ -const LPVaultAbi = require('../build/LPVault.sol').LPVaultAbi; -const LPVaultByteCode = require('../build/LPVault.sol').LPVaultByteCode; -const generateClass = require('eth-contract-class').default; - -module.exports = generateClass(LPVaultAbi, LPVaultByteCode); \ No newline at end of file diff --git a/test/AdminPlugins.js b/test/AdminPlugins.js index 14f6712..fc5a095 100644 --- a/test/AdminPlugins.js +++ b/test/AdminPlugins.js @@ -32,14 +32,13 @@ describe('LiquidPledging plugins test', function () { before(async () => { testrpc = TestRPC.server({ - ws: true, gasLimit: 6700000, total_accounts: 10, }); - testrpc.listen(8546, '127.0.0.1'); + testrpc.listen(8545, '127.0.0.1'); - web3 = new Web3('ws://localhost:8546'); + web3 = new Web3('http://localhost:8545'); accounts = await web3.eth.getAccounts(); giver1 = accounts[1]; adminProject1 = accounts[2]; diff --git a/test/CancelPledge.js b/test/CancelPledge.js index b38f680..5e6d103 100644 --- a/test/CancelPledge.js +++ b/test/CancelPledge.js @@ -29,14 +29,13 @@ describe('LiquidPledging cancelPledge normal scenario', function () { before(async () => { testrpc = TestRPC.server({ - ws: true, gasLimit: 6700000, total_accounts: 10, }); - testrpc.listen(8546, '127.0.0.1'); + testrpc.listen(8545, '127.0.0.1'); - web3 = new Web3('ws://localhost:8546'); + web3 = new Web3('http://localhost:8545'); accounts = await web3.eth.getAccounts(); giver1 = accounts[ 1 ]; adminProject1 = accounts[ 2 ]; diff --git a/test/DelegationChain.js b/test/DelegationChain.js index 4610668..6d961f6 100644 --- a/test/DelegationChain.js +++ b/test/DelegationChain.js @@ -33,14 +33,13 @@ describe('DelegationChain test', function () { const gasUsage = {}; before(async () => { testrpc = TestRPC.server({ - ws: true, gasLimit: 6700000, total_accounts: 10, }); testrpc.listen(8545, '127.0.0.1'); - web3 = new Web3('ws://localhost:8545'); + web3 = new Web3('http://localhost:8545'); accounts = await web3.eth.getAccounts(); giver1 = accounts[1]; delegate1 = accounts[2]; diff --git a/test/NormalOperation.js b/test/NormalOperation.js index c7e12b8..8f14b3b 100644 --- a/test/NormalOperation.js +++ b/test/NormalOperation.js @@ -39,14 +39,13 @@ describe('LiquidPledging test', function () { before(async () => { testrpc = TestRPC.server({ - ws: true, gasLimit: 6700000, total_accounts: 11, }); testrpc.listen(8545, '127.0.0.1'); - web3 = new Web3('ws://localhost:8545'); + web3 = new Web3('http://localhost:8545'); accounts = await web3.eth.getAccounts(); giver1 = accounts[1]; delegate1 = accounts[2]; diff --git a/test/NormalizePledge.js b/test/NormalizePledge.js index 6147cfb..beef5b9 100644 --- a/test/NormalizePledge.js +++ b/test/NormalizePledge.js @@ -31,14 +31,13 @@ describe('NormalizePledge test', function () { before(async () => { testrpc = TestRPC.server({ - ws: true, gasLimit: 6700000, total_accounts: 10, }); - testrpc.listen(8546, '127.0.0.1'); + testrpc.listen(8545, '127.0.0.1'); - web3 = new Web3('ws://localhost:8546'); + web3 = new Web3('http://localhost:8545'); accounts = await web3.eth.getAccounts(); giver1 = accounts[1]; delegate1 = accounts[2]; diff --git a/test/Vault.js b/test/Vault.js index ddaad54..12212f4 100644 --- a/test/Vault.js +++ b/test/Vault.js @@ -27,14 +27,13 @@ describe('Vault test', function () { before(async () => { testrpc = TestRPC.server({ - ws: true, gasLimit: 6700000, total_accounts: 10, }); - testrpc.listen(8546, '127.0.0.1'); + testrpc.listen(8545, '127.0.0.1'); - web3 = new Web3('ws://localhost:8546'); + web3 = new Web3('http://localhost:8545'); accounts = await web3.eth.getAccounts(); giver1 = accounts[ 1 ]; adminProject1 = accounts[ 2 ];