-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
etherGC.sol +reputationGC.sol #756
Draft
orenyodfat
wants to merge
7
commits into
master
Choose a base branch
from
dxdao_gc
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+523
−1
Draft
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
pragma solidity 0.5.17; | ||
|
||
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; | ||
import "./GlobalConstraintInterface.sol"; | ||
import "openzeppelin-solidity/contracts/math/SafeMath.sol"; | ||
import "../controller/Avatar.sol"; | ||
|
||
|
||
/** | ||
* @title EtherGC ether constraint per period | ||
*/ | ||
contract EtherGC is GlobalConstraintInterface { | ||
using SafeMath for uint256; | ||
|
||
uint256 public periodLength; //the period length in seconds | ||
uint256 public amountAllowedPerPeriod; | ||
Avatar public avatar; | ||
uint256 public startTime; | ||
uint256 public avatarBalanceBefore; | ||
// a mapping from period indexes to amounts | ||
mapping(uint256=>uint256) public totalAmountSentPerPeriod; | ||
|
||
/** | ||
* @dev initialize | ||
* @param _avatar the avatar to enforce the constraint on | ||
* @param _periodLength the periodLength in seconds | ||
* @param _amountAllowedPerPeriod the amount of eth to constraint for each period | ||
*/ | ||
function initialize( | ||
Avatar _avatar, | ||
uint256 _periodLength, | ||
uint256 _amountAllowedPerPeriod | ||
) | ||
external | ||
{ | ||
require(avatar == Avatar(0), "can be called only one time"); | ||
require(_avatar != Avatar(0), "avatar cannot be zero"); | ||
avatar = _avatar; | ||
periodLength = _periodLength; | ||
amountAllowedPerPeriod = _amountAllowedPerPeriod; | ||
// solhint-disable-next-line not-rely-on-time | ||
startTime = now; | ||
} | ||
|
||
/** | ||
* @dev check the constraint before the action. | ||
* @return true | ||
*/ | ||
function pre(address, bytes32, bytes32) public returns(bool) { | ||
require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); | ||
avatarBalanceBefore = address(avatar).balance; | ||
return true; | ||
} | ||
|
||
/** | ||
* @dev check the allowance of ether sent per period | ||
* and throws an error if the constraint is violated | ||
* @return bool which represents a success | ||
*/ | ||
function post(address, bytes32, bytes32) public returns(bool) { | ||
require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); | ||
if (avatarBalanceBefore > address(avatar).balance) { | ||
// solhint-disable-next-line not-rely-on-time | ||
uint256 currentPeriodIndex = (now - startTime)/periodLength; | ||
totalAmountSentPerPeriod[currentPeriodIndex] = | ||
totalAmountSentPerPeriod[currentPeriodIndex].add(avatarBalanceBefore.sub(address(avatar).balance)); | ||
require(totalAmountSentPerPeriod[currentPeriodIndex] <= amountAllowedPerPeriod, | ||
"Violation of Global constraint EtherGC:amount sent exceed in current period"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should set back avatarBalanceBefore to zero, as it will save gas. |
||
} | ||
avatarBalanceBefore = 0; //save gas | ||
return true; | ||
} | ||
|
||
/** | ||
* @dev when return if this globalConstraints is pre, post or both. | ||
* @return CallPhase enum indication Pre, Post or PreAndPost. | ||
*/ | ||
function when() public pure returns(GlobalConstraintInterface.CallPhase) { | ||
return GlobalConstraintInterface.CallPhase.PreAndPost; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
pragma solidity 0.5.17; | ||
|
||
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; | ||
import "./GlobalConstraintInterface.sol"; | ||
import "openzeppelin-solidity/contracts/math/SafeMath.sol"; | ||
import "../controller/Avatar.sol"; | ||
|
||
|
||
/** | ||
* @title ReputationGC reputation mint/butn constraint per period | ||
*/ | ||
contract ReputationGC is GlobalConstraintInterface { | ||
using SafeMath for uint256; | ||
|
||
uint256 public periodLength; //the period length in seconds | ||
uint256 public percentageAllowedPerPeriod; | ||
Avatar public avatar; | ||
uint256 public startTime; | ||
uint256 public totalRepSupplyBefore; | ||
|
||
// a mapping from period indexes to amounts | ||
mapping(uint256=>uint256) public totalRepMintedPerPeriod; | ||
mapping(uint256=>uint256) public totalRepBurnedPerPeriod; | ||
// a mapping from period to totalSupply | ||
mapping(uint256=>uint256) public totalRepSupplyPerPeriod; | ||
|
||
/** | ||
* @dev initialize | ||
* @param _avatar the avatar to enforce the constraint on | ||
* @param _periodLength the periodLength in seconds | ||
* @param _percentageAllowedPerPeriod the amount of reputation to constraint for each period (brun and mint) | ||
*/ | ||
function initialize( | ||
Avatar _avatar, | ||
uint256 _periodLength, | ||
uint256 _percentageAllowedPerPeriod | ||
) | ||
external | ||
{ | ||
require(avatar == Avatar(0), "can be called only one time"); | ||
require(_avatar != Avatar(0), "avatar cannot be zero"); | ||
require(_percentageAllowedPerPeriod <= 100, "precentage allowed cannot be greated than 100"); | ||
avatar = _avatar; | ||
periodLength = _periodLength; | ||
percentageAllowedPerPeriod = _percentageAllowedPerPeriod; | ||
// solhint-disable-next-line not-rely-on-time | ||
startTime = now; | ||
} | ||
|
||
/** | ||
* @dev check the constraint before the action. | ||
* @return true | ||
*/ | ||
function pre(address, bytes32, bytes32) public returns(bool) { | ||
require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); | ||
totalRepSupplyBefore = (avatar.nativeReputation()).totalSupply(); | ||
// solhint-disable-next-line not-rely-on-time | ||
uint256 currentPeriodIndex = (now - startTime)/periodLength; | ||
if (totalRepSupplyPerPeriod[currentPeriodIndex] == 0) { | ||
totalRepSupplyPerPeriod[currentPeriodIndex] = totalRepSupplyBefore; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* @dev check the allowance of reputation minted or burned per period | ||
* and throws an error if the constraint is violated | ||
* @return bool which represents a success | ||
*/ | ||
function post(address, bytes32, bytes32) public returns(bool) { | ||
require(msg.sender == avatar.owner(), "only avatar owner is authorize to call"); | ||
uint256 currentRepTotalSupply = (avatar.nativeReputation()).totalSupply(); | ||
if (totalRepSupplyBefore != currentRepTotalSupply) { | ||
// solhint-disable-next-line not-rely-on-time | ||
uint256 currentPeriodIndex = (now - startTime)/periodLength; | ||
uint256 repAllowedForCurrentPeriod = totalRepSupplyPerPeriod[currentPeriodIndex] | ||
.mul(percentageAllowedPerPeriod) | ||
.div(100); | ||
|
||
if (totalRepSupplyBefore > currentRepTotalSupply) { | ||
//reputation was burned | ||
uint256 burnedReputation = totalRepSupplyBefore.sub(currentRepTotalSupply); | ||
totalRepBurnedPerPeriod[currentPeriodIndex] = | ||
totalRepBurnedPerPeriod[currentPeriodIndex].add(burnedReputation); | ||
|
||
require(totalRepBurnedPerPeriod[currentPeriodIndex] <= repAllowedForCurrentPeriod, | ||
"Violation of Global constraint ReputationGC:amount of reputation burned exceed in current period"); | ||
} else { | ||
// reputation was minted | ||
uint256 mintedReputation = currentRepTotalSupply.sub(totalRepSupplyBefore); | ||
totalRepMintedPerPeriod[currentPeriodIndex] = | ||
totalRepMintedPerPeriod[currentPeriodIndex].add(mintedReputation); | ||
require(totalRepMintedPerPeriod[currentPeriodIndex] <= repAllowedForCurrentPeriod, | ||
"Violation of Global constraint ReputationGC:amount of reputation minted exceed in current period"); | ||
} | ||
} | ||
totalRepSupplyBefore = 0; //save gas | ||
return true; | ||
} | ||
|
||
/** | ||
* @dev when return if this globalConstraints is pre, post or both. | ||
* @return CallPhase enum indication Pre, Post or PreAndPost. | ||
*/ | ||
function when() public pure returns(GlobalConstraintInterface.CallPhase) { | ||
return GlobalConstraintInterface.CallPhase.PreAndPost; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
pragma solidity 0.5.17; | ||
|
||
import "../controller/Controller.sol"; | ||
|
||
/** | ||
* @title A scheme for adding or removing a global constraint | ||
* The scheme will unregister itself after register the globalConstraint | ||
* This scheme should be register to the dao with permission 0x00000004 | ||
*/ | ||
|
||
contract GlobalConstraintAddOrRemove { | ||
ben-kaufman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Avatar public avatar; | ||
address public globalConstraint; | ||
bytes32 public paramsHash; | ||
|
||
/** | ||
* @dev initialize | ||
* @param _avatar the avatar to mint reputation from | ||
* @param _globalConstraint the globalConstraint address | ||
* @param _paramsHash globalConstraint paramsHash | ||
*/ | ||
function initialize( | ||
Avatar _avatar, | ||
address _globalConstraint, | ||
bytes32 _paramsHash | ||
) external { | ||
require(avatar == Avatar(0), "can be called only one time"); | ||
require(_avatar != Avatar(0), "avatar cannot be zero"); | ||
avatar = _avatar; | ||
globalConstraint = _globalConstraint; | ||
paramsHash = _paramsHash; | ||
} | ||
|
||
/** | ||
* @dev add globalConstraint | ||
* and remove itsef. | ||
*/ | ||
function add() external { | ||
Controller(avatar.owner()).addGlobalConstraint(globalConstraint, paramsHash, address(avatar)); | ||
Controller(avatar.owner()).unregisterSelf(address(avatar)); | ||
} | ||
|
||
/** | ||
* @dev remove globalConstraint | ||
* and remove itsef. | ||
*/ | ||
function remove() external { | ||
Controller(avatar.owner()).removeGlobalConstraint(globalConstraint, address(avatar)); | ||
Controller(avatar.owner()).unregisterSelf(address(avatar)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import * as helpers from './helpers'; | ||
const DAOToken = artifacts.require("./DAOToken.sol"); | ||
const EtherGC = artifacts.require('./globalConstraints/EtherGC.sol'); | ||
const Controller = artifacts.require("./Controller.sol"); | ||
const Reputation = artifacts.require("./Reputation.sol"); | ||
const Avatar = artifacts.require("./Avatar.sol"); | ||
const ActionMock = artifacts.require("./ActionMock.sol"); | ||
var constants = require('../test/constants'); | ||
|
||
|
||
let reputation, avatar,token,controller,etherGC; | ||
var periodLengthConst = 1000; | ||
const setup = async function () { | ||
token = await DAOToken.new("TEST","TST",0); | ||
// set up a reputation system | ||
reputation = await Reputation.new(); | ||
avatar = await Avatar.new('name', token.address, reputation.address); | ||
controller = await Controller.new(avatar.address,{gas: constants.ARC_GAS_LIMIT}); | ||
await avatar.transferOwnership(controller.address); | ||
etherGC = await EtherGC.new(); | ||
await etherGC.initialize(avatar.address,periodLengthConst,web3.utils.toWei('5', "ether")); //periodLengthConst seconds ,5 eth | ||
}; | ||
|
||
contract('EtherGC', accounts => { | ||
it("initialize", async () => { | ||
await setup(); | ||
assert.equal(await etherGC.avatar(),avatar.address); | ||
assert.equal(await etherGC.amountAllowedPerPeriod(),web3.utils.toWei('5', "ether")); | ||
assert.equal(await etherGC.periodLength(),1000); | ||
}); | ||
|
||
it("send ether check", async () => { | ||
|
||
await setup(); | ||
try { | ||
await etherGC.initialize(avatar.address,periodLengthConst,web3.utils.toWei('5', "ether")); //periodLengthConst seconds ,5 eth | ||
assert(false,"cannpt init twice "); | ||
} catch(ex){ | ||
helpers.assertVMException(ex); | ||
} | ||
var startTime = await etherGC.startTime(); | ||
|
||
await controller.addGlobalConstraint(etherGC.address,helpers.NULL_HASH,avatar.address); | ||
//move 10 ether to avatar | ||
await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); | ||
await controller.sendEther(web3.utils.toWei('1', "ether"), accounts[2],avatar.address); | ||
await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); | ||
|
||
try { | ||
await controller.sendEther(web3.utils.toWei('1', "ether"), accounts[2],avatar.address); | ||
assert(false,"sendEther should fail due to the etherGC global constraint "); | ||
} | ||
catch(ex){ | ||
helpers.assertVMException(ex); | ||
} | ||
helpers.increaseTime(periodLengthConst+1); | ||
await controller.sendEther(web3.utils.toWei('1', "ether"), accounts[2],avatar.address); | ||
await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); | ||
await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); | ||
var diff = ((await web3.eth.getBlock("latest")).timestamp - startTime.toNumber())% periodLengthConst; | ||
//increment time for next period | ||
helpers.increaseTime(periodLengthConst-diff); | ||
await controller.sendEther(web3.utils.toWei('4', "ether"), accounts[2],avatar.address); | ||
}); | ||
|
||
it("genericCall check", async () => { | ||
|
||
await setup(); | ||
try { | ||
await etherGC.initialize(avatar.address,periodLengthConst,web3.utils.toWei('5', "ether")); //periodLengthConst seconds ,5 eth | ||
assert(false,"cannpt init twice "); | ||
} catch(ex){ | ||
helpers.assertVMException(ex); | ||
} | ||
var startTime = await etherGC.startTime(); | ||
|
||
await controller.addGlobalConstraint(etherGC.address,helpers.NULL_HASH,avatar.address); | ||
//move 10 ether to avatar | ||
await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); | ||
|
||
let actionMock = await ActionMock.new(); | ||
let a = 7; | ||
let b = actionMock.address; | ||
let c = "0x1234"; | ||
const encodeABI = await new web3.eth.Contract(actionMock.abi).methods.test(a,b,c).encodeABI(); | ||
await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); | ||
await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('4', "ether")); | ||
|
||
try { | ||
await controller.sendEther(web3.utils.toWei('1', "ether"), accounts[2],avatar.address); | ||
assert(false,"sendEther should fail due to the etherGC global constraint "); | ||
} | ||
catch(ex){ | ||
helpers.assertVMException(ex); | ||
} | ||
|
||
try { | ||
await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); | ||
assert(false,"sendEther should fail due to the etherGC global constraint "); | ||
} | ||
catch(ex){ | ||
helpers.assertVMException(ex); | ||
} | ||
helpers.increaseTime(periodLengthConst+1); | ||
await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('1', "ether")); | ||
await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('4', "ether")); | ||
await web3.eth.sendTransaction({from:accounts[0],to:avatar.address, value: web3.utils.toWei('10', "ether")}); | ||
var diff = ((await web3.eth.getBlock("latest")).timestamp - startTime.toNumber())% periodLengthConst; | ||
//increment time for next period | ||
helpers.increaseTime(periodLengthConst-diff); | ||
await controller.genericCall(actionMock.address,encodeABI,avatar.address,web3.utils.toWei('4', "ether")); | ||
}); | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this should be percentage-wise, or absolute values. Probably better to keep it absolute.