Skip to content

Commit

Permalink
Added upgradable contraintLimits (#798)
Browse files Browse the repository at this point in the history
* simplify contract

* tests

* test approval

* check spender is white listed

* clean

* poc

* Add SchemeConstraints interface

* add eth constraint as an example for DxDaoSchemeConstraint

* +

* more ..

* fix dxdao constraints

* check schemeConstraint exist

* + comments

* coverage

* Added upgradable contraintLimits

* updated genericschmemulticall tests

* Updated DXdaoSchemeConstraints

* Added contraint events and smaller updates

* Added additional tests for DxDaoSchemeConstraints

* rebase from arc/master

* Updated DxDaoSchemeContraints events & general cleanup

* solhint cleanup

* cleanup

* Fixed test issues

* updated DxDaoSchemeConstraints.sol

* only genericSchemeMultiCall can call isAllowToCall

test coverage

* comments

* Added additional test for GenericSchemeMultiCall

Co-authored-by: Oren Sokolowsky <[email protected]>
Co-authored-by: orenyodfat <[email protected]>
  • Loading branch information
3 people authored Oct 16, 2020
1 parent 19682c2 commit 7d6ce3a
Show file tree
Hide file tree
Showing 2 changed files with 484 additions and 46 deletions.
99 changes: 84 additions & 15 deletions contracts/schemes/DxDaoSchemeConstraints.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,25 @@ pragma experimental ABIEncoderV2;

import "./SchemeConstraints.sol";


contract DxDaoSchemeConstraints is SchemeConstraints {
using SafeMath for uint256;

event UpdatedContractsWhitelist(
address[] _contractsAddresses,
bool[] _contractsWhitelisted
);

event UpdatedPeriodLimitsTokens(
address[] _tokensAddresses,
uint256[] _tokensPeriodLimits
);

event UpdatedPeriodLimitWei(
uint256 _periodLimitWei
);

address public avatar;
address public genericSchemeMultiCall;
uint256 public initialTimestamp;
uint256 public periodSize;
uint256 public periodLimitWei;
Expand All @@ -18,26 +33,32 @@ contract DxDaoSchemeConstraints is SchemeConstraints {
bytes4 private constant APPROVE_SIGNATURE = 0x095ea7b3;//approve(address,uint256)

/* @dev initialize
* @param avatar the DAOs avatar address
* @param _periodSize the time period to limit the tokens and eth spending
* @param _periodLimitWei the limit of eth which can be sent per period
* @param _periodLimitTokensAddresses tokens to limit
* @param _periodLimitTokensAmounts the limit of token which can be sent per period
* @param _contractsWhiteList the contracts the scheme is allowed to interact with
* @param _genericSchemeMultiCall genericSchemeMultiCall which allowed to call isAllowedToCall
*/
function initialize(
address _avatar,
uint256 _periodSize,
uint256 _periodLimitWei,
address[] calldata _periodLimitTokensAddresses,
uint256[] calldata _periodLimitTokensAmounts,
address[] calldata _contractsWhiteList
address[] calldata _contractsWhiteList,
address _genericSchemeMultiCall
)
external {
require(initialTimestamp == 0, "cannot initialize twice");
require(_periodSize > 0, "preriod size should be greater than 0");
require(_periodLimitTokensAddresses.length == _periodLimitTokensAmounts.length,
"invalid length _periodLimitTokensAddresses");
require(_genericSchemeMultiCall != address(0), "genericSchemeMultiCall cannot be zero");
periodSize = _periodSize;
periodLimitWei = _periodLimitWei;
avatar = _avatar;
// solhint-disable-next-line not-rely-on-time
initialTimestamp = block.timestamp;
for (uint i = 0; i < _contractsWhiteList.length; i++) {
Expand All @@ -47,6 +68,55 @@ contract DxDaoSchemeConstraints is SchemeConstraints {
periodLimitToken[_periodLimitTokensAddresses[i]] = _periodLimitTokensAmounts[i];
}
contractsWhiteList = _contractsWhiteList;
genericSchemeMultiCall = _genericSchemeMultiCall;
}

/*
* @dev updateContractWhitelist used to let the DAO update whitelisted contracts.
* @param _contractsAddresses - The contract that should be update
* @param _contractsWhitelisted – true adds a contract to the whitelist, false removes it.
*/
function updateContractsWhitelist(
address[] calldata _contractsAddresses,
bool[] calldata _contractsWhitelisted
)
external {
require(msg.sender == avatar, "caller must be avatar");
require(_contractsAddresses.length == _contractsWhitelisted.length,
"invalid length _periodLimitTokensAddresses");
for (uint i = 0; i < _contractsAddresses.length; i++) {
contractsWhiteListMap[_contractsAddresses[i]] = _contractsWhitelisted[i];
}
emit UpdatedContractsWhitelist(_contractsAddresses, _contractsWhitelisted);
}

/*
* @dev updatePeriodLimitsTokens lets the dao update limits to token limits.
* @param _tokensAddresses - The token addresses to be updated
* @param _tokensPeriodLimits – The token amounts to be set as period limit.
*/
function updatePeriodLimitsTokens(
address[] calldata _tokensAddresses,
uint256[] calldata _tokensPeriodLimits
)
external {
require(msg.sender == avatar, "caller must be avatar");
require(_tokensAddresses.length == _tokensPeriodLimits.length,
"invalid length _tokensPeriodLimits");
for (uint i = 0; i < _tokensAddresses.length; i++) {
periodLimitToken[_tokensAddresses[i]] = _tokensPeriodLimits[i];
}
emit UpdatedPeriodLimitsTokens(_tokensAddresses, _tokensPeriodLimits);
}

/*
* @dev updatePeriodLimitWei lets the dao update limits to ETH spending limit.
* @param _periodLimitWei - The new spending limit in WEI that should be set.
*/
function updatePeriodLimitWei(uint256 _periodLimitWei) external {
require(msg.sender == avatar, "caller must be avatar");
periodLimitWei = _periodLimitWei;
emit UpdatedPeriodLimitWei(_periodLimitWei);
}

/*
Expand All @@ -68,10 +138,11 @@ contract DxDaoSchemeConstraints is SchemeConstraints {
external
returns(bool)
{

require(msg.sender == genericSchemeMultiCall, "only genericSchemeMultiCall");
uint256 observervationIndex = observationIndex();
uint256 totalPeriodSpendingInWei;
for (uint i = 0; i < _contractsToCall.length; i++) {
require(contractsWhiteListMap[_contractsToCall[i]], "contract not whitelisted");
// constraint eth transfer
totalPeriodSpendingInWei = totalPeriodSpendingInWei.add(_values[i]);
bytes memory callData = _callsData[i];
Expand All @@ -81,11 +152,14 @@ contract DxDaoSchemeConstraints is SchemeConstraints {
callData[2] == APPROVE_SIGNATURE[2] &&
callData[3] == APPROVE_SIGNATURE[3]) {
uint256 amount;
address spender;
address contractToCall = _contractsToCall[i];
// solhint-disable-next-line no-inline-assembly
assembly {
amount := mload(add(callData, 68))
spender := mload(add(callData, 36))
amount := mload(add(callData, 68))
}
require(contractsWhiteListMap[spender], "spender contract not whitelisted");
periodSpendingToken[observervationIndex][contractToCall] =
periodSpendingToken[observervationIndex][contractToCall].add(amount);
require(
Expand Down Expand Up @@ -118,18 +192,13 @@ contract DxDaoSchemeConstraints is SchemeConstraints {
returns(bool)
{
for (uint i = 0; i < _contractsToCall.length; i++) {
if (!contractsWhiteListMap[_contractsToCall[i]]) {
require(contractsWhiteListMap[_contractsToCall[i]], "contract not whitelisted");
bytes memory callData = _callsData[i];
if (callData[0] == APPROVE_SIGNATURE[0] &&
callData[1] == APPROVE_SIGNATURE[1] &&
callData[2] == APPROVE_SIGNATURE[2] &&
callData[3] == APPROVE_SIGNATURE[3]) {
address spender;
bytes memory callData = _callsData[i];
require(
callData[0] == APPROVE_SIGNATURE[0] &&
callData[1] == APPROVE_SIGNATURE[1] &&
callData[2] == APPROVE_SIGNATURE[2] &&
callData[3] == APPROVE_SIGNATURE[3],
"allow only approve call for none whitelistedContracts");
//in solidity > 6 this can be replaced by:
//(spender,) = abi.descode(callData[4:], (address, uint));
// see https://github.com/ethereum/solidity/issues/9439
// solhint-disable-next-line no-inline-assembly
assembly {
spender := mload(add(callData, 36))
Expand Down
Loading

0 comments on commit 7d6ce3a

Please sign in to comment.