Merge branch 'aragonOs-update'

This commit is contained in:
perissology 2018-06-16 10:57:17 -07:00
commit 5dabfc4b62
25 changed files with 6635 additions and 9846 deletions

View File

@ -1,98 +0,0 @@
pragma solidity ^0.4.18;
/*
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 `EscapableApp` is a base level 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 = keccak256("ESCAPE_HATCH_CALLER_ROLE");
event EscapeHatchBlackistedToken(address token);
event EscapeHatchCalled(address token, uint amount);
address public escapeHatchDestination;
mapping (address=>bool) private escapeBlacklist; // Token contract addresses
uint[20] private storageOffset; // reserve 20 slots for future upgrades
function EscapableApp(address _escapeHatchDestination) public {
_init(_escapeHatchDestination);
}
/// @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 public {
_init(_escapeHatchDestination);
}
/// @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) external 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);
}
/// @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) view external returns (bool) {
return !escapeBlacklist[_token];
}
function _init(address _escapeHatchDestination) internal {
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);
}
}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11; pragma solidity ^0.4.0;
/* /*
Copyright 2017, Jordi Baylina Copyright 2017, Jordi Baylina

View File

@ -5,14 +5,15 @@ import "./LPVault.sol";
import "./LiquidPledging.sol"; import "./LiquidPledging.sol";
import "./LPConstants.sol"; import "./LPConstants.sol";
contract LPFactory is LPConstants, DAOFactory { contract LPFactory is LPConstants, DAOFactory(new Kernel(), new ACL(), 0) {
bytes32 public constant RECOVERY_VAULT_ID = keccak256("recoveryVault");
address public vaultBase; address public vaultBase;
address public lpBase; address public lpBase;
event DeployVault(address vault); event DeployVault(address vault);
event DeployLiquidPledging(address liquidPledging); event DeployLiquidPledging(address liquidPledging);
function LPFactory(address _vaultBase, address _lpBase) public DAOFactory(0) { function LPFactory(address _vaultBase, address _lpBase) public {
require(_vaultBase != 0); require(_vaultBase != 0);
require(_lpBase != 0); require(_lpBase != 0);
vaultBase = _vaultBase; vaultBase = _vaultBase;
@ -28,12 +29,14 @@ contract LPFactory is LPConstants, DAOFactory {
acl.createPermission(this, address(kernel), appManagerRole, this); acl.createPermission(this, address(kernel), appManagerRole, this);
LPVault v = LPVault(kernel.newAppInstance(VAULT_APP_ID, vaultBase)); LPVault v = LPVault(kernel.newAppInstance(VAULT_APP_ID, vaultBase));
LiquidPledging lp = LiquidPledging(kernel.newAppInstance(LP_APP_ID, lpBase)); // deploy & register the lp instance w/ the kernel
v.initialize(address(lp), _escapeHatchDestination); LiquidPledging lp = LiquidPledging(kernel.newAppInstance(LP_APP_ID, lpBase, true));
lp.initialize(address(v), _escapeHatchDestination); v.initialize(address(lp));
lp.initialize(address(v));
// register the lp instance w/ the kernel // set the recoveryVault to the escapeHatchDestination
kernel.setApp(kernel.APP_ADDR_NAMESPACE(), LP_APP_ID, address(lp)); kernel.setRecoveryVaultId(RECOVERY_VAULT_ID);
kernel.setApp(APP_ADDR_NAMESPACE, RECOVERY_VAULT_ID, _escapeHatchDestination);
_setPermissions(_root, acl, kernel, v, lp); _setPermissions(_root, acl, kernel, v, lp);
} }

View File

@ -24,9 +24,8 @@ pragma solidity ^0.4.18;
/// 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 "./EscapableApp.sol";
import "./LiquidPledgingACLHelpers.sol"; import "./LiquidPledgingACLHelpers.sol";
import "giveth-common-contracts/contracts/ERC20.sol"; import "@aragon/os/contracts/apps/AragonApp.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.
@ -37,11 +36,12 @@ contract ILiquidPledging {
/// @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 EscapableApp, LiquidPledgingACLHelpers { contract LPVault is AragonApp, LiquidPledgingACLHelpers {
bytes32 constant public CONFIRM_PAYMENT_ROLE = keccak256("CONFIRM_PAYMENT_ROLE"); bytes32 constant public CONFIRM_PAYMENT_ROLE = keccak256("CONFIRM_PAYMENT_ROLE");
bytes32 constant public CANCEL_PAYMENT_ROLE = keccak256("CANCEL_PAYMENT_ROLE"); bytes32 constant public CANCEL_PAYMENT_ROLE = keccak256("CANCEL_PAYMENT_ROLE");
bytes32 constant public SET_AUTOPAY_ROLE = keccak256("SET_AUTOPAY_ROLE"); bytes32 constant public SET_AUTOPAY_ROLE = keccak256("SET_AUTOPAY_ROLE");
bytes32 constant public ESCAPE_HATCH_CALLER_ROLE = keccak256("ESCAPE_HATCH_CALLER_ROLE");
event AutoPaySet(bool autoPay); event AutoPaySet(bool autoPay);
event EscapeFundsCalled(address token, uint amount); event EscapeFundsCalled(address token, uint amount);
@ -85,23 +85,12 @@ contract LPVault is EscapableApp, LiquidPledgingACLHelpers {
_; _;
} }
function LPVault(address _escapeHatchDestination) EscapableApp(_escapeHatchDestination) public { /// @param _liquidPledging Address of the liquidPledging instance associated
} /// with this LPVault
function initialize(address _liquidPledging) onlyInit external {
function initialize(address _escapeHatchDestination) onlyInit public {
require(false); // overload the EscapableApp
_escapeHatchDestination;
}
/// @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 {
super.initialize(_escapeHatchDestination);
require(_liquidPledging != 0x0); require(_liquidPledging != 0x0);
initialized();
liquidPledging = ILiquidPledging(_liquidPledging); liquidPledging = ILiquidPledging(_liquidPledging);
} }
@ -180,16 +169,16 @@ contract LPVault is EscapableApp, LiquidPledgingACLHelpers {
} }
} }
/// Transfer tokens to the escapeHatchDestination. /**
/// Used as a safety mechanism to prevent the vault from holding too much value * @dev By default, AragonApp will allow anyone to call transferToVault
/// before being thoroughly battle-tested. * Because this app is designed to hold funds, we only want to call
/// @param _token to transfer * transferToVault in the case of an emergency. Only senders with the
/// @param _amount to transfer * ESCAPE_HATCH_CALLER_ROLE are allowed to pull the "escapeHatch"
function escapeFunds(address _token, uint _amount) external authP(ESCAPE_HATCH_CALLER_ROLE, arr(_token)) { * @param token Token address that would be recovered
require(_token != 0x0); * @return bool whether the app allows the recovery
ERC20 token = ERC20(_token); */
require(token.transfer(escapeHatchDestination, _amount)); function allowRecoverability(address token) public view returns (bool) {
EscapeFundsCalled(_token, _amount); return canPerform(msg.sender, ESCAPE_HATCH_CALLER_ROLE, arr(token));
} }
/// @return The total number of payments that have ever been authorized /// @return The total number of payments that have ever been authorized

View File

@ -27,9 +27,6 @@ import "./LiquidPledgingBase.sol";
/// to allow for expanded functionality. /// to allow for expanded functionality.
contract LiquidPledging is LiquidPledgingBase { contract LiquidPledging is LiquidPledgingBase {
function LiquidPledging(address _escapeHatchDestination) EscapableApp(_escapeHatchDestination) public {
}
function addGiverAndDonate(uint64 idReceiver, address token, uint amount) function addGiverAndDonate(uint64 idReceiver, address token, uint amount)
public public
{ {
@ -63,9 +60,6 @@ contract LiquidPledging is LiquidPledgingBase {
PledgeAdmin storage sender = _findAdmin(idGiver); PledgeAdmin storage sender = _findAdmin(idGiver);
require(sender.adminType == PledgeAdminType.Giver); require(sender.adminType == PledgeAdminType.Giver);
// TODO should this be done at the end of this function?
// what re-entrancy issues are there if this is done here?
// if done at the end of the function, will that affect plugins?
require(ERC20(token).transferFrom(msg.sender, address(vault), amount)); // transfer the token to the `vault` require(ERC20(token).transferFrom(msg.sender, address(vault), amount)); // transfer the token to the `vault`
uint64 idPledge = _findOrCreatePledge( uint64 idPledge = _findOrCreatePledge(
@ -258,32 +252,6 @@ contract LiquidPledging is LiquidPledgingBase {
} }
} }
/// @notice `mConfirmPayment` allows for multiple pledges to be confirmed
/// efficiently
/// @param pledgesAmounts An array of pledge amounts and IDs which are extrapolated
/// using the D64 bitmask
function mConfirmPayment(uint[] pledgesAmounts) public {
for (uint i = 0; i < pledgesAmounts.length; i++ ) {
uint64 idPledge = uint64(pledgesAmounts[i] & (D64-1));
uint amount = pledgesAmounts[i] / D64;
confirmPayment(idPledge, amount);
}
}
/// @notice `mCancelPayment` allows for multiple pledges to be canceled
/// efficiently
/// @param pledgesAmounts An array of pledge amounts and IDs which are extrapolated
/// using the D64 bitmask
function mCancelPayment(uint[] pledgesAmounts) public {
for (uint i = 0; i < pledgesAmounts.length; i++ ) {
uint64 idPledge = uint64(pledgesAmounts[i] & (D64-1));
uint amount = pledgesAmounts[i] / D64;
cancelPayment(idPledge, amount);
}
}
/// @notice `mNormalizePledge` allows for multiple pledges to be /// @notice `mNormalizePledge` allows for multiple pledges to be
/// normalized efficiently /// normalized efficiently
/// @param pledges An array of pledge IDs /// @param pledges An array of pledge IDs

View File

@ -22,12 +22,12 @@ pragma solidity ^0.4.18;
import "./LiquidPledgingStorage.sol"; import "./LiquidPledgingStorage.sol";
import "./PledgeAdmins.sol"; import "./PledgeAdmins.sol";
import "./Pledges.sol"; import "./Pledges.sol";
import "./EscapableApp.sol"; import "@aragon/os/contracts/apps/AragonApp.sol";
/// @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 EscapableApp, LiquidPledgingStorage, PledgeAdmins, Pledges { contract LiquidPledgingBase is AragonApp, LiquidPledgingStorage, PledgeAdmins, Pledges {
event Transfer(uint indexed from, uint indexed to, uint amount); event Transfer(uint indexed from, uint indexed to, uint amount);
event CancelProject(uint indexed idProject); event CancelProject(uint indexed idProject);
@ -47,19 +47,10 @@ contract LiquidPledgingBase is EscapableApp, LiquidPledgingStorage, PledgeAdmins
// Constructor // Constructor
/////////////// ///////////////
function initialize(address _escapeHatchDestination) onlyInit public {
require(false); // overload the EscapableApp
_escapeHatchDestination;
}
/// @param _vault The vault where the ETH backing the pledges is stored /// @param _vault The vault where the ETH backing the pledges is stored
/// @param _escapeHatchDestination The address of a safe location (usu a function initialize(address _vault) onlyInit public {
/// 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 public {
super.initialize(_escapeHatchDestination);
require(_vault != 0x0); require(_vault != 0x0);
initialized();
vault = ILPVault(_vault); vault = ILPVault(_vault);

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11; pragma solidity ^0.4.18;
/* /*
Copyright 2017, Jordi Baylina Copyright 2017, Jordi Baylina
Contributor: Adrià Massanet <adria@codecontext.io> Contributor: Adrià Massanet <adria@codecontext.io>
@ -26,13 +26,10 @@ contract LiquidPledgingMock is LiquidPledging {
uint public mock_time; uint public mock_time;
function LiquidPledgingMock(address _escapeHatchDestination) LiquidPledging(_escapeHatchDestination) public {
}
/// @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.
function initialize(address _vault, address _escapeHatchDestination) onlyInit public { function initialize(address _vault) onlyInit public {
super.initialize(_vault, _escapeHatchDestination); super.initialize(_vault);
mock_time = now; mock_time = now;
} }

View File

@ -27,10 +27,18 @@ contract LiquidPledgingPlugins is AragonApp, LiquidPledgingStorage, LiquidPledgi
bytes32 constant public PLUGIN_MANAGER_ROLE = keccak256("PLUGIN_MANAGER_ROLE"); bytes32 constant public PLUGIN_MANAGER_ROLE = keccak256("PLUGIN_MANAGER_ROLE");
/**
* @dev adds an instance of a plugin to the whitelist
*/
function addValidPluginInstance(address addr) auth(PLUGIN_MANAGER_ROLE) external { function addValidPluginInstance(address addr) auth(PLUGIN_MANAGER_ROLE) external {
pluginInstanceWhitelist[addr] = true; pluginInstanceWhitelist[addr] = true;
} }
/**
* @dev add a contract to the plugin whitelist.
* @notice Proxy contracts should never be added using this method. Each individual
* proxy instance should be added by calling `addValidPluginInstance`
*/
function addValidPluginContract(bytes32 contractHash) auth(PLUGIN_MANAGER_ROLE) public { function addValidPluginContract(bytes32 contractHash) auth(PLUGIN_MANAGER_ROLE) public {
pluginContractWhitelist[contractHash] = true; pluginContractWhitelist[contractHash] = true;
} }
@ -41,18 +49,31 @@ contract LiquidPledgingPlugins is AragonApp, LiquidPledgingStorage, LiquidPledgi
} }
} }
/**
* @dev removes a contract from the plugin whitelist
*/
function removeValidPluginContract(bytes32 contractHash) external authP(PLUGIN_MANAGER_ROLE, arr(contractHash)) { function removeValidPluginContract(bytes32 contractHash) external authP(PLUGIN_MANAGER_ROLE, arr(contractHash)) {
pluginContractWhitelist[contractHash] = false; pluginContractWhitelist[contractHash] = false;
} }
/**
* @dev removes an instance of a plugin to the whitelist
*/
function removeValidPluginInstance(address addr) external authP(PLUGIN_MANAGER_ROLE, arr(addr)) { function removeValidPluginInstance(address addr) external authP(PLUGIN_MANAGER_ROLE, arr(addr)) {
pluginInstanceWhitelist[addr] = false; pluginInstanceWhitelist[addr] = false;
} }
/**
* @dev enable/disable the plugin whitelist.
* @notice you better know what you're doing if you are going to disable it
*/
function useWhitelist(bool useWhitelist) external auth(PLUGIN_MANAGER_ROLE) { function useWhitelist(bool useWhitelist) external auth(PLUGIN_MANAGER_ROLE) {
whitelistDisabled = !useWhitelist; whitelistDisabled = !useWhitelist;
} }
/**
* check if the contract at the provided address is in the plugin whitelist
*/
function isValidPlugin(address addr) public view returns(bool) { function isValidPlugin(address addr) public view returns(bool) {
if (whitelistDisabled || addr == 0x0) { if (whitelistDisabled || addr == 0x0) {
return true; return true;
@ -69,6 +90,9 @@ contract LiquidPledgingPlugins is AragonApp, LiquidPledgingStorage, LiquidPledgi
return pluginContractWhitelist[contractHash]; return pluginContractWhitelist[contractHash];
} }
/**
* @return the hash of the code for the given address
*/
function getCodeHash(address addr) public view returns(bytes32) { function getCodeHash(address addr) public view returns(bytes32) {
bytes memory o_code; bytes memory o_code;
assembly { assembly {

View File

@ -58,8 +58,6 @@ contract LiquidPledgingStorage {
ILPVault public vault; ILPVault public vault;
// reserve 50 slots for future upgrades. I'm not sure if this is necessary // reserve 50 slots for future upgrades.
// but b/c of multiple inheritance used in lp, better safe then sorry.
// especially since it is free
uint[50] private storageOffset; uint[50] private storageOffset;
} }

View File

@ -63,7 +63,6 @@ contract PledgeAdmins is AragonApp, LiquidPledgingPlugins {
); );
} }
// TODO: is there an issue w/ allowing anyone to create a giver on behalf of another addy?
function addGiver( function addGiver(
address addr, address addr,
string name, string name,

View File

@ -0,0 +1,6 @@
pragma solidity ^0.4.18;
/**
* WARNING: for testing only. DO NOT USE
**/
contract RecoveryVault {}

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11; pragma solidity ^0.4.18;
import "../LiquidPledging.sol"; import "../LiquidPledging.sol";
@ -36,6 +36,7 @@ contract TestSimpleDelegatePlugin {
uint amount uint amount
) external returns (uint maxAllowed) { ) external returns (uint maxAllowed) {
require(!initPending); require(!initPending);
maxAllowed;
BeforeTransfer(pledgeAdmin, pledgeFrom, pledgeTo, context, amount); BeforeTransfer(pledgeAdmin, pledgeFrom, pledgeTo, context, amount);
} }

View File

@ -1,4 +1,4 @@
pragma solidity ^0.4.11; pragma solidity ^0.4.18;
import "../LiquidPledging.sol"; import "../LiquidPledging.sol";
@ -11,7 +11,7 @@ contract TestSimpleProjectPlugin {
event BeforeTransfer(uint64 pledgeAdmin, uint64 pledgeFrom, uint64 pledgeTo, uint64 context, uint amount); event BeforeTransfer(uint64 pledgeAdmin, uint64 pledgeFrom, uint64 pledgeTo, uint64 context, uint amount);
event AfterTransfer(uint64 pledgeAdmin, uint64 pledgeFrom, uint64 pledgeTo, uint64 context, uint amount); event AfterTransfer(uint64 pledgeAdmin, uint64 pledgeFrom, uint64 pledgeTo, uint64 context, uint amount);
function TestSimpleProjectPlugin() { function TestSimpleProjectPlugin() public {
require(msg.sender != tx.origin); // Avoids being created directly by mistake. require(msg.sender != tx.origin); // Avoids being created directly by mistake.
initPending = true; initPending = true;
} }
@ -21,7 +21,7 @@ contract TestSimpleProjectPlugin {
string name, string name,
string url, string url,
uint64 parentProject uint64 parentProject
) { ) public {
require(initPending); require(initPending);
idProject = liquidPledging.addProject(name, url, address(this), parentProject, 0, ILiquidPledgingPlugin(this)); idProject = liquidPledging.addProject(name, url, address(this), parentProject, 0, ILiquidPledgingPlugin(this));
initPending = false; initPending = false;
@ -35,6 +35,7 @@ contract TestSimpleProjectPlugin {
uint amount uint amount
) external returns (uint maxAllowed) { ) external returns (uint maxAllowed) {
require(!initPending); require(!initPending);
maxAllowed;
BeforeTransfer(pledgeAdmin, pledgeFrom, pledgeTo, context, amount); BeforeTransfer(pledgeAdmin, pledgeFrom, pledgeTo, context, amount);
} }

View File

@ -11,7 +11,7 @@ contract TestSimpleProjectPluginFactory {
string name, string name,
string url, string url,
uint64 parentProject uint64 parentProject
) { ) public {
TestSimpleProjectPlugin p = new TestSimpleProjectPlugin(); TestSimpleProjectPlugin p = new TestSimpleProjectPlugin();
p.init(liquidPledging, name, url, parentProject); p.init(liquidPledging, name, url, parentProject);
} }

View File

@ -1,30 +1,43 @@
const contractInfo = require('./build/LPFactory.sol'); const LPFactoryArtifact = require('./build/LPFactory.json');
const LiquidPledgingMockInfo = require('./build/LiquidPledgingMock.sol'); const LiquidPledgingArtifact = require('./build/LiquidPledging.json');
const LPVaultInfo = require('./build/LPVault.sol'); const LPVaultArtifact = require('./build/LPVault.json');
const StandardTokenInfo = require('./build/StandardToken.sol'); const KernelArtifact = require('./build/Kernel.json');
const KernelInfo = require('./build/Kernel.sol'); const ACLArtifact = require('./build/ACL.json');
const ACLInfo = require('./build/ACL.sol'); const StandardTokenTestAtifact = require('./build/StandardToken.json');
const LiquidPledgingMockArtifact = require('./build/LiquidPledgingMock.json');
const generateClass = require('eth-contract-class').default; const generateClass = require('eth-contract-class').default;
module.exports = { module.exports = {
LiquidPledging: generateClass( LiquidPledging: generateClass(
contractInfo.LiquidPledgingAbi, LiquidPledgingArtifact.compilerOutput.abi,
contractInfo.LiquidPledgingByteCode, LiquidPledgingArtifact.compilerOutput.evm.bytecode.object,
),
LPFactory: generateClass(
LPFactoryArtifact.compilerOutput.abi,
LPFactoryArtifact.compilerOutput.evm.bytecode.object,
), ),
LPFactory: generateClass(contractInfo.LPFactoryAbi, contractInfo.LPFactoryByteCode),
LiquidPledgingState: require('./lib/liquidPledgingState.js'), LiquidPledgingState: require('./lib/liquidPledgingState.js'),
LPVault: generateClass(contractInfo.LPVaultAbi, contractInfo.LPVaultByteCode), LPVault: generateClass(
Kernel: generateClass(KernelInfo.KernelAbi, KernelInfo.KernelByteCode), LPVaultArtifact.compilerOutput.abi,
ACL: generateClass(ACLInfo.ACLAbi, ACLInfo.ACLByteCode), LPVaultArtifact.compilerOutput.evm.bytecode.object,
),
Kernel: generateClass(
KernelArtifact.compilerOutput.abi,
KernelArtifact.compilerOutput.evm.bytecode.object,
),
ACL: generateClass(
ACLArtifact.compilerOutput.abi,
ACLArtifact.compilerOutput.evm.bytecode.object,
),
test: { test: {
StandardTokenTest: generateClass( StandardTokenTest: generateClass(
StandardTokenInfo.StandardTokenAbi, StandardTokenTestAtifact.compilerOutput.abi,
StandardTokenInfo.StandardTokenByteCode, StandardTokenTestAtifact.compilerOutput.evm.bytecode.object,
), ),
assertFail: require('./test/helpers/assertFail'), assertFail: require('./test/helpers/assertFail'),
LiquidPledgingMock: generateClass( LiquidPledgingMock: generateClass(
LiquidPledgingMockInfo.LiquidPledgingMockAbi, LiquidPledgingMockArtifact.compilerOutput.abi,
LiquidPledgingMockInfo.LiquidPledgingMockByteCode, LiquidPledgingMockArtifact.compilerOutput.evm.bytecode.object,
), ),
}, },
}; };

9435
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "giveth-liquidpledging", "name": "giveth-liquidpledging",
"version": "0.1.1", "version": "1.0.0-beta.0",
"description": "Liquid Pledging Smart Contract", "description": "Liquid Pledging Smart Contract",
"main": "index.js", "main": "index.js",
"directories": { "directories": {
@ -8,18 +8,26 @@
"test": "test" "test": "test"
}, },
"scripts": { "scripts": {
"test": "npm run build; mocha --harmony", "test": "npm run build && mocha --harmony",
"sol-compile": "compile:sol": "solcpiler --solc-version v0.4.18+commit.9cf6e910 -i './contracts/**/*.sol' ./node_modules/@aragon/os/contracts/{kernel/Kernel.sol,acl/ACL.sol} --output-sol-dir build/contracts",
"solcpiler --solc-version v0.4.18+commit.9cf6e910 -i './contracts/**/*.sol' ./node_modules/@aragon/os/contracts/{kernel/Kernel.sol,acl/ACL.sol}", "compile:js": "babel -d lib/ js/",
"js-compile": "babel -d lib/ js/", "compile": "npm run compile:sol && npm run compile:js",
"build": "npm run sol-compile; npm run js-compile", "build": "npm run compile",
"prepublish": "npm run build" "prepublish": "npm run build"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/Giveth/liquidpledging.git" "url": "git+https://github.com/Giveth/liquidpledging.git"
}, },
"keywords": ["liquid", "pledging", "tracking", "smart", "contract", "solidity", "donation"], "keywords": [
"liquid",
"pledging",
"tracking",
"smart",
"contract",
"solidity",
"donation"
],
"author": "Jordi Baylina", "author": "Jordi Baylina",
"license": "GPL-3.0", "license": "GPL-3.0",
"bugs": { "bugs": {
@ -33,19 +41,18 @@
"eslint-plugin-import": "^2.6.0", "eslint-plugin-import": "^2.6.0",
"eslint-plugin-jsx-a11y": "^6.0.2", "eslint-plugin-jsx-a11y": "^6.0.2",
"eslint-plugin-react": "^7.1.0", "eslint-plugin-react": "^7.1.0",
"ganache-cli": "^7.0.0-beta.0", "ganache-cli": "^6.1.3",
"lerna": "^2.2.0", "lerna": "^2.2.0",
"mocha": "^3.5.0", "mocha": "^3.5.0",
"random-bytes": "^1.0.0", "random-bytes": "^1.0.0",
"solcpiler": "https://github.com/perissology/solcpiler.git#6393e66", "solcpiler": "1.0.0-beta.5",
"web3": "1.0.0-beta.31" "web3": "1.0.0-beta.34"
}, },
"homepage": "https://github.com/Giveth/liquidpledging#readme", "homepage": "https://github.com/Giveth/liquidpledging#readme",
"dependencies": { "dependencies": {
"@aragon/os": "3.0.1", "@aragon/os": "3.1.9",
"async": "^2.4.0", "async": "^2.4.0",
"chai": "^4.1.0", "chai": "^4.1.0",
"eth-contract-class": "^0.0.9", "eth-contract-class": "^0.0.10"
"giveth-common-contracts": "^0.4.0"
} }
} }

View File

@ -1,24 +1,18 @@
/* eslint-env mocha */ /* eslint-env mocha */
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
const TestRPC = require('ganache-cli'); const Ganache = require('ganache-cli');
const Web3 = require('web3'); const Web3 = require('web3');
const chai = require('chai'); const chai = require('chai');
const { const { test } = require('../index');
LPVault, const deployLP = require('./helpers/deployLP');
LPFactory,
LiquidPledgingState,
test,
} = require('../index');
const simpleProjectPluginFactoryAbi = require('../build/TestSimpleProjectPluginFactory.sol') const { compilerOutput } = require('../build/TestSimpleProjectPluginFactory.json');
.TestSimpleProjectPluginFactoryAbi; const simpleProjectPluginFactoryAbi = compilerOutput.abi;
const simpleProjectPluginFactoryByteCode = require('../build/TestSimpleProjectPluginFactory.sol') const simpleProjectPluginFactoryByteCode = compilerOutput.evm.bytecode.object;
.TestSimpleProjectPluginFactoryByteCode; const simpleProjectPluginRuntimeByteCode = '0x' + require('../build/TestSimpleProjectPlugin.json').compilerOutput.evm.deployedBytecode.object;
const simpleProjectPluginRuntimeByteCode = require('../build/TestSimpleProjectPluginFactory.sol')
.TestSimpleProjectPluginRuntimeByteCode;
const assert = chai.assert; const assert = chai.assert;
const { StandardTokenTest, assertFail, LiquidPledgingMock } = test; const { assertFail } = test;
const printState = async liquidPledgingState => { const printState = async liquidPledgingState => {
const st = await liquidPledgingState.getState(); const st = await liquidPledgingState.getState();
@ -28,7 +22,7 @@ const printState = async liquidPledgingState => {
describe('LiquidPledging plugins test', function() { describe('LiquidPledging plugins test', function() {
this.timeout(0); this.timeout(0);
let testrpc; let ganache;
let web3; let web3;
let accounts; let accounts;
let liquidPledging; let liquidPledging;
@ -37,48 +31,32 @@ describe('LiquidPledging plugins test', function() {
let giver1; let giver1;
let adminProject1; let adminProject1;
let adminDelegate1; let adminDelegate1;
let token;
before(async () => { before(async () => {
testrpc = TestRPC.server({ ganache = Ganache.server({
gasLimit: 6700000, gasLimit: 6700000,
total_accounts: 10, total_accounts: 10,
}); });
testrpc.listen(8545, '127.0.0.1'); ganache.listen(8545, '127.0.0.1');
web3 = new Web3('http://localhost:8545'); web3 = new Web3('http://localhost:8545');
accounts = await web3.eth.getAccounts(); accounts = await web3.eth.getAccounts();
giver1 = accounts[1];
adminProject1 = accounts[2]; adminProject1 = accounts[2];
adminDelegate1 = accounts[3]; adminDelegate1 = accounts[3];
const deployment = await deployLP(web3);
giver1 = deployment.giver1;
vault = deployment.vault;
liquidPledging = deployment.liquidPledging;
liquidPledgingState = deployment.liquidPledgingState;
}); });
after(done => { after(done => {
testrpc.close(); ganache.close();
done(); done();
}); });
it('Should deploy LiquidPledging contract', async function() {
const baseVault = await LPVault.new(web3, accounts[0]);
const baseLP = await LiquidPledgingMock.new(web3, accounts[0]);
lpFactory = await LPFactory.new(web3, baseVault.$address, baseLP.$address);
const r = await lpFactory.newLP(accounts[0], accounts[0]);
const vaultAddress = r.events.DeployVault.returnValues.vault;
vault = new LPVault(web3, vaultAddress);
const lpAddress = r.events.DeployLiquidPledging.returnValues.liquidPledging;
liquidPledging = new LiquidPledgingMock(web3, lpAddress);
liquidPledgingState = new LiquidPledgingState(liquidPledging);
token = await StandardTokenTest.new(web3);
await token.mint(giver1, web3.utils.toWei('1000'));
await token.approve(liquidPledging.$address, '0xFFFFFFFFFFFFFFFF', { from: giver1 });
});
it('Should create create giver with no plugin', async function() { it('Should create create giver with no plugin', async function() {
await liquidPledging.addGiver('Giver1', '', 0, '0x0', { from: adminProject1 }); await liquidPledging.addGiver('Giver1', '', 0, '0x0', { from: adminProject1 });

View File

@ -1,11 +1,12 @@
/* eslint-env mocha */ /* eslint-env mocha */
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
const TestRPC = require('ganache-cli'); const Ganache = require('ganache-cli');
const Web3 = require('web3'); const Web3 = require('web3');
const { assert } = require('chai'); const { assert } = require('chai');
const { LPVault, LPFactory, LiquidPledgingState, test } = require('../index'); const { test } = require('../index');
const deployLP = require('./helpers/deployLP');
const { StandardTokenTest, assertFail, LiquidPledgingMock } = test; const { assertFail } = test;
const printState = async liquidPledgingState => { const printState = async liquidPledgingState => {
const st = await liquidPledgingState.getState(); const st = await liquidPledgingState.getState();
@ -15,7 +16,7 @@ const printState = async liquidPledgingState => {
describe('LiquidPledging cancelPledge normal scenario', function() { describe('LiquidPledging cancelPledge normal scenario', function() {
this.timeout(0); this.timeout(0);
let testrpc; let ganache;
let web3; let web3;
let accounts; let accounts;
let liquidPledging; let liquidPledging;
@ -27,45 +28,31 @@ describe('LiquidPledging cancelPledge normal scenario', function() {
let token; let token;
before(async () => { before(async () => {
testrpc = TestRPC.server({ ganache = Ganache.server({
gasLimit: 6700000, gasLimit: 6700000,
total_accounts: 10, total_accounts: 10,
}); });
testrpc.listen(8545, '127.0.0.1'); ganache.listen(8545, '127.0.0.1');
web3 = new Web3('http://localhost:8545'); web3 = new Web3('http://localhost:8545');
accounts = await web3.eth.getAccounts(); accounts = await web3.eth.getAccounts();
giver1 = accounts[1];
adminProject1 = accounts[2]; adminProject1 = accounts[2];
adminProject2 = accounts[3]; adminProject2 = accounts[3];
const deployment = await deployLP(web3);
giver1 = deployment.giver1;
vault = deployment.vault;
liquidPledging = deployment.liquidPledging;
liquidPledgingState = deployment.liquidPledgingState;
token = deployment.token;
}); });
after(done => { after(done => {
testrpc.close(); ganache.close();
done(); done();
}); });
it('Should deploy LiquidPledging contract', async () => {
const baseVault = await LPVault.new(web3, accounts[0]);
const baseLP = await LiquidPledgingMock.new(web3, accounts[0]);
lpFactory = await LPFactory.new(web3, baseVault.$address, baseLP.$address);
const r = await lpFactory.newLP(accounts[0], accounts[0]);
const vaultAddress = r.events.DeployVault.returnValues.vault;
vault = new LPVault(web3, vaultAddress);
const lpAddress = r.events.DeployLiquidPledging.returnValues.liquidPledging;
liquidPledging = new LiquidPledgingMock(web3, lpAddress);
liquidPledgingState = new LiquidPledgingState(liquidPledging);
token = await StandardTokenTest.new(web3);
await token.mint(giver1, web3.utils.toWei('1000'));
await token.approve(liquidPledging.$address, '0xFFFFFFFFFFFFFFFF', { from: giver1 });
});
it('Should add project and donate ', async () => { it('Should add project and donate ', async () => {
await liquidPledging.addProject('Project1', 'URLProject1', adminProject1, 0, 0, '0x0', { await liquidPledging.addProject('Project1', 'URLProject1', adminProject1, 0, 0, '0x0', {
from: adminProject1, from: adminProject1,

View File

@ -1,11 +1,12 @@
/* eslint-env mocha */ /* eslint-env mocha */
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
const TestRPC = require('ganache-cli'); const Ganache = require('ganache-cli');
const Web3 = require('web3'); const Web3 = require('web3');
const { assert } = require('chai'); const { assert } = require('chai');
const { LPVault, LPFactory, LiquidPledgingState, test } = require('../index'); const { test } = require('../index');
const deployLP = require('./helpers/deployLP');
const { StandardTokenTest, assertFail, LiquidPledgingMock } = test; const { assertFail } = test;
const printState = async liquidPledgingState => { const printState = async liquidPledgingState => {
const st = await liquidPledgingState.getState(); const st = await liquidPledgingState.getState();
@ -15,7 +16,7 @@ const printState = async liquidPledgingState => {
describe('DelegationChain test', function() { describe('DelegationChain test', function() {
this.timeout(0); this.timeout(0);
let testrpc; let ganache;
let web3; let web3;
let accounts; let accounts;
let liquidPledging; let liquidPledging;
@ -31,48 +32,34 @@ describe('DelegationChain test', function() {
const gasUsage = {}; const gasUsage = {};
before(async () => { before(async () => {
testrpc = TestRPC.server({ ganache = Ganache.server({
gasLimit: 6700000, gasLimit: 6700000,
total_accounts: 10, total_accounts: 10,
}); });
testrpc.listen(8545, '127.0.0.1'); ganache.listen(8545, '127.0.0.1');
web3 = new Web3('http://localhost:8545'); web3 = new Web3('http://localhost:8545');
accounts = await web3.eth.getAccounts(); accounts = await web3.eth.getAccounts();
giver1 = accounts[1];
delegate1 = accounts[2]; delegate1 = accounts[2];
delegate2 = accounts[3]; delegate2 = accounts[3];
delegate3 = accounts[4]; delegate3 = accounts[4];
adminProject1 = accounts[5]; adminProject1 = accounts[5];
giver2 = accounts[6]; giver2 = accounts[6];
const deployment = await deployLP(web3);
giver1 = deployment.giver1;
vault = deployment.vault;
liquidPledging = deployment.liquidPledging;
liquidPledgingState = deployment.liquidPledgingState;
token = deployment.token;
}); });
after(done => { after(done => {
testrpc.close(); ganache.close();
done(); done();
}); });
it('Should deploy LiquidPledging contract', async () => {
const baseVault = await LPVault.new(web3, accounts[0]);
const baseLP = await LiquidPledgingMock.new(web3, accounts[0]);
lpFactory = await LPFactory.new(web3, baseVault.$address, baseLP.$address);
const r = await lpFactory.newLP(accounts[0], accounts[0]);
const vaultAddress = r.events.DeployVault.returnValues.vault;
vault = new LPVault(web3, vaultAddress);
const lpAddress = r.events.DeployLiquidPledging.returnValues.liquidPledging;
liquidPledging = new LiquidPledgingMock(web3, lpAddress);
liquidPledgingState = new LiquidPledgingState(liquidPledging);
token = await StandardTokenTest.new(web3);
await token.mint(giver1, web3.utils.toWei('1000'));
await token.approve(liquidPledging.$address, '0xFFFFFFFFFFFFFFFF', { from: giver1 });
});
it('Should add pledgeAdmins', async () => { it('Should add pledgeAdmins', async () => {
await liquidPledging.addGiver('Giver1', 'URLGiver1', 86400, 0, { from: giver1 }); // pledgeAdmin 1 await liquidPledging.addGiver('Giver1', 'URLGiver1', 86400, 0, { from: giver1 }); // pledgeAdmin 1
await liquidPledging.addDelegate('Delegate1', 'URLDelegate1', 259200, 0, { from: delegate1 }); // pledgeAdmin 2 await liquidPledging.addDelegate('Delegate1', 'URLDelegate1', 259200, 0, { from: delegate1 }); // pledgeAdmin 2

View File

@ -4,10 +4,11 @@ const TestRPC = require('ganache-cli');
const Web3 = require('web3'); const Web3 = require('web3');
const { assert } = require('chai'); const { assert } = require('chai');
const { LPVault, LPFactory, LiquidPledgingState, Kernel, ACL, test } = require('../index'); const { LPVault, LPFactory, LiquidPledgingState, Kernel, ACL, test } = require('../index');
const { RecoveryVault } = require('../build/contracts');
const { StandardTokenTest, assertFail, LiquidPledgingMock } = test; const { StandardTokenTest, assertFail, LiquidPledgingMock } = test;
describe('Vault test', function() { describe('LPVault test', function() {
this.timeout(0); this.timeout(0);
let testrpc; let testrpc;
@ -18,7 +19,7 @@ describe('Vault test', function() {
let vault; let vault;
let vaultOwner; let vaultOwner;
let escapeHatchCaller; let escapeHatchCaller;
let escapeHatchDestination; let recoveryVault;
let giver1; let giver1;
let adminProject1; let adminProject1;
let restrictedPaymentsConfirmer; let restrictedPaymentsConfirmer;
@ -37,9 +38,9 @@ describe('Vault test', function() {
giver1 = accounts[1]; giver1 = accounts[1];
adminProject1 = accounts[2]; adminProject1 = accounts[2];
vaultOwner = accounts[3]; vaultOwner = accounts[3];
escapeHatchDestination = accounts[4]; escapeHatchCaller = accounts[4];
escapeHatchCaller = accounts[5]; recoveryVault = (await RecoveryVault.new(web3)).$address;
restrictedPaymentsConfirmer = accounts[6]; restrictedPaymentsConfirmer = accounts[5];
}); });
after(done => { after(done => {
@ -47,12 +48,14 @@ describe('Vault test', function() {
done(); done();
}); });
it('Should deploy Vault contract', async function() { it('Should deploy LPVault contract', async function() {
const baseVault = await LPVault.new(web3, escapeHatchDestination); const baseVault = await LPVault.new(web3);
const baseLP = await LiquidPledgingMock.new(web3, escapeHatchDestination); const baseLP = await LiquidPledgingMock.new(web3, {
lpFactory = await LPFactory.new(web3, baseVault.$address, baseLP.$address); gas: 6700000,
});
lpFactory = await LPFactory.new(web3, baseVault.$address, baseLP.$address, { gas: 6700000 });
const r = await lpFactory.newLP(accounts[0], escapeHatchDestination); const r = await lpFactory.newLP(accounts[0], recoveryVault);
const vaultAddress = r.events.DeployVault.returnValues.vault; const vaultAddress = r.events.DeployVault.returnValues.vault;
vault = new LPVault(web3, vaultAddress); vault = new LPVault(web3, vaultAddress);
@ -85,12 +88,6 @@ describe('Vault test', function() {
await vault.ESCAPE_HATCH_CALLER_ROLE(), await vault.ESCAPE_HATCH_CALLER_ROLE(),
{ $extraGas: 200000 }, { $extraGas: 200000 },
); );
await acl.revokePermission(
accounts[0],
vault.$address,
await vault.ESCAPE_HATCH_CALLER_ROLE(),
{ $extraGas: 200000 },
);
await liquidPledging.addGiver('Giver1', '', 0, '0x0', { from: giver1, $extraGas: 100000 }); await liquidPledging.addGiver('Giver1', '', 0, '0x0', { from: giver1, $extraGas: 100000 });
await liquidPledging.addProject('Project1', '', adminProject1, 0, 0, '0x0', { await liquidPledging.addProject('Project1', '', adminProject1, 0, 0, '0x0', {
@ -116,35 +113,6 @@ describe('Vault test', function() {
assert.equal(10000, balance); assert.equal(10000, balance);
}); });
it('escapeFunds should fail', async function() {
// only vaultOwner can escapeFunds
await assertFail(vault.escapeFunds(0x0, 1000, { gas: 4000000 }));
// can't send more then the balance
await assertFail(vault.escapeFunds(0x0, 11000, { from: vaultOwner, gas: 4000000 }));
});
it('escapeFunds should send funds to escapeHatchDestination', async function() {
const preBalance = await token.balanceOf(escapeHatchDestination);
await assertFail(vault.escapeFunds(0x0, 1000, { from: escapeHatchCaller, gas: 1000000 }));
await vault.escapeFunds(token.$address, 1000, { from: escapeHatchCaller, $extraGas: 200000 });
const vaultBalance = await token.balanceOf(vault.$address);
assert.equal(9000, vaultBalance);
const expected = web3.utils
.toBN(preBalance)
.add(web3.utils.toBN('1000'))
.toString();
const postBalance = await token.balanceOf(escapeHatchDestination);
assert.equal(expected, postBalance);
await token.transfer(vault.$address, 1000, { from: escapeHatchDestination, $extraGas: 200000 });
});
it('should restrict confirm payment to payments under specified amount', async function() { it('should restrict confirm payment to payments under specified amount', async function() {
await liquidPledging.withdraw(2, 300, { from: adminProject1, $extraGas: 200000 }); await liquidPledging.withdraw(2, 300, { from: adminProject1, $extraGas: 200000 });
await liquidPledging.withdraw(2, 700, { from: adminProject1, $extraGas: 200000 }); await liquidPledging.withdraw(2, 700, { from: adminProject1, $extraGas: 200000 });
@ -161,4 +129,21 @@ describe('Vault test', function() {
await assertFail(vault.confirmPayment(1, { from: restrictedPaymentsConfirmer, gas: 4000000 })); await assertFail(vault.confirmPayment(1, { from: restrictedPaymentsConfirmer, gas: 4000000 }));
await vault.confirmPayment(0, { from: restrictedPaymentsConfirmer, $extraGas: 200000 }); await vault.confirmPayment(0, { from: restrictedPaymentsConfirmer, $extraGas: 200000 });
}); });
it('Only escapeHatchCaller role should be able to pull "escapeHatch"', async function() {
const preVaultBalance = await token.balanceOf(vault.$address);
// transferToVault is a bit confusing, but is the name of the function in aragonOs
// this is the escapeHatch and will transfer all funds to the recoveryVault
await assertFail(vault.transferToVault(token.$address, { from: vaultOwner, gas: 6700000 }));
assert.equal(await token.balanceOf(vault.$address), preVaultBalance);
await vault.transferToVault(token.$address, { from: escapeHatchCaller, $extraGas: 100000 });
const vaultBalance = await token.balanceOf(vault.$address);
assert.equal(0, vaultBalance);
const recoveryVaultBalance = await token.balanceOf(recoveryVault);
assert.equal(preVaultBalance, recoveryVaultBalance);
});
}); });

View File

@ -1,9 +1,10 @@
/* eslint-env mocha */ /* eslint-env mocha */
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
const TestRPC = require('ganache-cli'); const Ganache = require('ganache-cli');
const Web3 = require('web3'); const Web3 = require('web3');
const { assert } = require('chai'); const { assert } = require('chai');
const { LPVault, LPFactory, LiquidPledgingState, Kernel, ACL, test } = require('../index'); const { LPVault, LPFactory, LiquidPledgingState, Kernel, ACL, test } = require('../index');
const { RecoveryVault } = require('../build/contracts');
const { StandardTokenTest, assertFail, LiquidPledgingMock } = test; const { StandardTokenTest, assertFail, LiquidPledgingMock } = test;
const { utils } = Web3; const { utils } = Web3;
@ -15,7 +16,7 @@ const printState = async liquidPledgingState => {
describe('LiquidPledging test', function() { describe('LiquidPledging test', function() {
this.timeout(0); this.timeout(0);
let testrpc; let ganache;
let web3; let web3;
let accounts; let accounts;
let liquidPledging; let liquidPledging;
@ -29,19 +30,19 @@ describe('LiquidPledging test', function() {
let adminProject2a; let adminProject2a;
let adminProject3; let adminProject3;
let delegate2; let delegate2;
let escapeHatchDestination; let recoveryVault;
let escapeHatchCaller; let escapeHatchCaller;
let acl; let acl;
let giver1Token; let giver1Token;
let giver2Token; let giver2Token;
before(async () => { before(async () => {
testrpc = TestRPC.server({ ganache = Ganache.server({
gasLimit: 6700000, gasLimit: 6700000,
total_accounts: 11, total_accounts: 11,
}); });
testrpc.listen(8545, '127.0.0.1'); ganache.listen(8545, '127.0.0.1');
web3 = new Web3('http://localhost:8545'); web3 = new Web3('http://localhost:8545');
accounts = await web3.eth.getAccounts(); accounts = await web3.eth.getAccounts();
@ -53,26 +54,23 @@ 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]; recoveryVault = (await RecoveryVault.new(web3)).$address;
escapeHatchCaller = accounts[10]; escapeHatchCaller = accounts[10];
}); });
after(done => { after(done => {
testrpc.close(); ganache.close();
done(); done();
}); });
it('Should deploy LiquidPledging contract', async () => { it('Should deploy LiquidPledging contract', async () => {
const baseVault = await LPVault.new(web3, escapeHatchDestination); const baseVault = await LPVault.new(web3);
const baseLP = await LiquidPledgingMock.new(web3, escapeHatchDestination, { const baseLP = await LiquidPledgingMock.new(web3, {
gas: 6700000, gas: 6700000,
}); });
lpFactory = await LPFactory.new(web3, baseVault.$address, baseLP.$address); lpFactory = await LPFactory.new(web3, baseVault.$address, baseLP.$address, { gas: 6700000 });
assert.isAbove(Number(await baseVault.getInitializationBlock()), 0); const r = await lpFactory.newLP(accounts[0], recoveryVault);
assert.isAbove(Number(await baseLP.getInitializationBlock()), 0);
const r = await lpFactory.newLP(accounts[0], escapeHatchDestination);
const vaultAddress = r.events.DeployVault.returnValues.vault; const vaultAddress = r.events.DeployVault.returnValues.vault;
vault = new LPVault(web3, vaultAddress); vault = new LPVault(web3, vaultAddress);
@ -80,6 +78,9 @@ describe('LiquidPledging test', function() {
const lpAddress = r.events.DeployLiquidPledging.returnValues.liquidPledging; const lpAddress = r.events.DeployLiquidPledging.returnValues.liquidPledging;
liquidPledging = new LiquidPledgingMock(web3, lpAddress); liquidPledging = new LiquidPledgingMock(web3, lpAddress);
assert.isAbove(Number(await vault.getInitializationBlock()), 0);
assert.isAbove(Number(await liquidPledging.getInitializationBlock()), 0);
liquidPledgingState = new LiquidPledgingState(liquidPledging); liquidPledgingState = new LiquidPledgingState(liquidPledging);
// set permissions // set permissions
@ -494,4 +495,29 @@ describe('LiquidPledging test', function() {
const giver1Bal = await giver1Token.balanceOf(giver1); const giver1Bal = await giver1Token.balanceOf(giver1);
assert.equal(new utils.BN(preGiver1Bal).subn(11).toString(), giver1Bal); assert.equal(new utils.BN(preGiver1Bal).subn(11).toString(), giver1Bal);
}); });
it('Should recover funds from contract instances', async function() {
assert.equal(await giver1Token.balanceOf(recoveryVault), 0);
assert.equal(await giver1Token.balanceOf(liquidPledging.$address), 0);
// shouldn't be able to send eth to contract
await assertFail(
web3.eth.sendTransaction({
to: liquidPledging.$address,
value: 1000,
from: giver1,
gas: 6700000,
}),
);
// however, we can't stop tokens, so lets make sure we can recover them
await giver1Token.transfer(liquidPledging.$address, 1000, { from: giver1 });
assert.equal(await giver1Token.balanceOf(liquidPledging.$address), 1000);
const kernel = new Kernel(web3, await liquidPledging.kernel());
await liquidPledging.transferToVault(giver1Token.$address, { $extraGas: 100000 });
assert.equal(await giver1Token.balanceOf(recoveryVault), 1000);
assert.equal(await giver1Token.balanceOf(liquidPledging.$address), 0);
});
}); });

View File

@ -1,11 +1,9 @@
/* eslint-env mocha */ /* eslint-env mocha */
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
const TestRPC = require('ganache-cli'); const Ganache = require('ganache-cli');
const Web3 = require('web3'); const Web3 = require('web3');
const { assert } = require('chai'); const { assert } = require('chai');
const { LPVault, LPFactory, LiquidPledgingState, test } = require('../index'); const deployLP = require('./helpers/deployLP');
const { StandardTokenTest, assertFail, LiquidPledgingMock } = test;
const printState = async liquidPledgingState => { const printState = async liquidPledgingState => {
const st = await liquidPledgingState.getState(); const st = await liquidPledgingState.getState();
@ -15,12 +13,11 @@ const printState = async liquidPledgingState => {
describe('NormalizePledge test', function() { describe('NormalizePledge test', function() {
this.timeout(0); this.timeout(0);
let testrpc; let ganache;
let web3; let web3;
let accounts; let accounts;
let liquidPledging; let liquidPledging;
let liquidPledgingState; let liquidPledgingState;
let vault;
let giver1; let giver1;
let giver2; let giver2;
let delegate1; let delegate1;
@ -30,50 +27,36 @@ describe('NormalizePledge test', function() {
let token; let token;
before(async () => { before(async () => {
testrpc = TestRPC.server({ ganache = Ganache.server({
gasLimit: 6700000, gasLimit: 6700000,
total_accounts: 10, total_accounts: 10,
}); });
testrpc.listen(8545, '127.0.0.1'); ganache.listen(8545, '127.0.0.1');
web3 = new Web3('http://localhost:8545'); web3 = new Web3('http://localhost:8545');
accounts = await web3.eth.getAccounts(); accounts = await web3.eth.getAccounts();
giver1 = accounts[1];
delegate1 = accounts[2]; delegate1 = accounts[2];
delegate2 = accounts[3]; delegate2 = accounts[3];
adminProject1 = accounts[4]; adminProject1 = accounts[4];
adminProject2 = accounts[5]; adminProject2 = accounts[5];
giver2 = accounts[6]; giver2 = accounts[6];
const deployment = await deployLP(web3);
giver1 = deployment.giver1;
liquidPledging = deployment.liquidPledging;
liquidPledgingState = deployment.liquidPledgingState;
token = deployment.token;
await token.mint(giver2, web3.utils.toWei('1000'));
await token.approve(liquidPledging.$address, '0xFFFFFFFFFFFFFFFF', { from: giver2 });
}); });
after(done => { after(done => {
testrpc.close(); ganache.close();
done(); done();
}); });
it('Should deploy LiquidPledging contract', async () => {
const baseVault = await LPVault.new(web3, accounts[0]);
const baseLP = await LiquidPledgingMock.new(web3, accounts[0]);
lpFactory = await LPFactory.new(web3, baseVault.$address, baseLP.$address);
const r = await lpFactory.newLP(accounts[0], accounts[0]);
const vaultAddress = r.events.DeployVault.returnValues.vault;
vault = new LPVault(web3, vaultAddress);
const lpAddress = r.events.DeployLiquidPledging.returnValues.liquidPledging;
liquidPledging = new LiquidPledgingMock(web3, lpAddress);
liquidPledgingState = new LiquidPledgingState(liquidPledging);
token = await StandardTokenTest.new(web3);
await token.mint(giver1, web3.utils.toWei('1000'));
await token.mint(giver2, web3.utils.toWei('1000'));
await token.approve(liquidPledging.$address, '0xFFFFFFFFFFFFFFFF', { from: giver1 });
await token.approve(liquidPledging.$address, '0xFFFFFFFFFFFFFFFF', { from: giver2 });
});
it('Should add pledgeAdmins', async () => { it('Should add pledgeAdmins', async () => {
await liquidPledging.addGiver('Giver1', 'URLGiver1', 86400, 0, { from: giver1 }); // pledgeAdmin 1 await liquidPledging.addGiver('Giver1', 'URLGiver1', 86400, 0, { from: giver1 }); // pledgeAdmin 1
await liquidPledging.addDelegate('Delegate1', 'URLDelegate1', 259200, 0, { from: delegate1 }); // pledgeAdmin 2 await liquidPledging.addDelegate('Delegate1', 'URLDelegate1', 259200, 0, { from: delegate1 }); // pledgeAdmin 2

38
test/helpers/deployLP.js Normal file
View File

@ -0,0 +1,38 @@
const { LPVault, LPFactory, LiquidPledgingState, Kernel, ACL, test } = require('../../index');
const { RecoveryVault } = require('../../build/contracts');
module.exports = async web3 => {
const accounts = await web3.eth.getAccounts();
const giver1 = accounts[1];
const baseVault = await LPVault.new(web3);
const baseLP = await test.LiquidPledgingMock.new(web3, {
gas: 6700000,
});
const lpFactory = await LPFactory.new(web3, baseVault.$address, baseLP.$address, {
gas: 6700000,
});
const recoveryVault = (await RecoveryVault.new(web3)).$address;
const r = await lpFactory.newLP(accounts[0], recoveryVault);
const vaultAddress = r.events.DeployVault.returnValues.vault;
const vault = new LPVault(web3, vaultAddress);
const lpAddress = r.events.DeployLiquidPledging.returnValues.liquidPledging;
const liquidPledging = new test.LiquidPledgingMock(web3, lpAddress);
const liquidPledgingState = new LiquidPledgingState(liquidPledging);
const token = await test.StandardTokenTest.new(web3);
await token.mint(giver1, web3.utils.toWei('1000'));
await token.approve(liquidPledging.$address, '0xFFFFFFFFFFFFFFFF', { from: giver1 });
return {
liquidPledging,
liquidPledgingState,
vault,
token,
giver1,
};
};

6341
yarn.lock

File diff suppressed because it is too large Load Diff