diff --git a/.solcover.js b/.solcover.js new file mode 100644 index 00000000..97dfff4d --- /dev/null +++ b/.solcover.js @@ -0,0 +1,4 @@ +module.exports = { + skipFiles: ['test/'], + istanbulReporter: ['html'] +}; diff --git a/coverage/base.css b/coverage/base.css new file mode 100644 index 00000000..29737bcb --- /dev/null +++ b/coverage/base.css @@ -0,0 +1,213 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.medium .chart { border:1px solid #f9cd0b; } +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } +/* light gray */ +span.cline-neutral { background: #eaeaea; } + +.cbranch-no { background: yellow !important; color: #111; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/controller/Avatar.sol.html b/coverage/controller/Avatar.sol.html new file mode 100644 index 00000000..86a54974 --- /dev/null +++ b/coverage/controller/Avatar.sol.html @@ -0,0 +1,476 @@ + + +
+| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +383× +383× +383× + + + + + + +45× + + + + + + + + + + + + + + + +23× +23× + + + + + + + + + +24× +22× +22× + + + + + + + + + + + + +12× +12× +12× + + + + + + + + + + + + + + + + + + +2× +2× +2× + + + + + + + + + + + + + +3× +3× +3× + + + + + + + + +291× +291× + + + + + | pragma solidity 0.5.17;
+
+import "@daostack/infra/contracts/Reputation.sol";
+import "./DAOToken.sol";
+import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
+import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
+import "../libs/SafeERC20.sol";
+
+
+/**
+ * @title An Avatar holds tokens, reputation and ether for a controller
+ */
+contract Avatar is Ownable {
+ using SafeERC20 for address;
+
+ string public orgName;
+ DAOToken public nativeToken;
+ Reputation public nativeReputation;
+
+ event GenericCall(address indexed _contract, bytes _data, uint _value, bool _success);
+ event SendEther(uint256 _amountInWei, address indexed _to);
+ event ExternalTokenTransfer(address indexed _externalToken, address indexed _to, uint256 _value);
+ event ExternalTokenTransferFrom(address indexed _externalToken, address _from, address _to, uint256 _value);
+ event ExternalTokenApproval(address indexed _externalToken, address _spender, uint256 _value);
+ event ReceiveEther(address indexed _sender, uint256 _value);
+ event MetaData(string _metaData);
+
+ /**
+ * @dev the constructor takes organization name, native token and reputation system
+ and creates an avatar for a controller
+ */
+ constructor(string memory _orgName, DAOToken _nativeToken, Reputation _nativeReputation) public {
+ orgName = _orgName;
+ nativeToken = _nativeToken;
+ nativeReputation = _nativeReputation;
+ }
+
+ /**
+ * @dev enables an avatar to receive ethers
+ */
+ function() external payable {
+ emit ReceiveEther(msg.sender, msg.value);
+ }
+
+ /**
+ * @dev perform a generic call to an arbitrary contract
+ * @param _contract the contract's address to call
+ * @param _data ABI-encoded contract call to call `_contract` address.
+ * @param _value value (ETH) to transfer with the transaction
+ * @return bool success or fail
+ * bytes - the return bytes of the called contract's function.
+ */
+ function genericCall(address _contract, bytes memory _data, uint256 _value)
+ public
+ onlyOwner
+ returns(bool success, bytes memory returnValue) {
+ // solhint-disable-next-line avoid-call-value
+ (success, returnValue) = _contract.call.value(_value)(_data);
+ emit GenericCall(_contract, _data, _value, success);
+ }
+
+ /**
+ * @dev send ethers from the avatar's wallet
+ * @param _amountInWei amount to send in Wei units
+ * @param _to send the ethers to this address
+ * @return bool which represents success
+ */
+ function sendEther(uint256 _amountInWei, address payable _to) public onlyOwner returns(bool) {
+ _to.transfer(_amountInWei);
+ emit SendEther(_amountInWei, _to);
+ return true;
+ }
+
+ /**
+ * @dev external token transfer
+ * @param _externalToken the token contract
+ * @param _to the destination address
+ * @param _value the amount of tokens to transfer
+ * @return bool which represents success
+ */
+ function externalTokenTransfer(IERC20 _externalToken, address _to, uint256 _value)
+ public onlyOwner returns(bool)
+ {
+ address(_externalToken).safeTransfer(_to, _value);
+ emit ExternalTokenTransfer(address(_externalToken), _to, _value);
+ return true;
+ }
+
+ /**
+ * @dev external token transfer from a specific account
+ * @param _externalToken the token contract
+ * @param _from the account to spend token from
+ * @param _to the destination address
+ * @param _value the amount of tokens to transfer
+ * @return bool which represents success
+ */
+ function externalTokenTransferFrom(
+ IERC20 _externalToken,
+ address _from,
+ address _to,
+ uint256 _value
+ )
+ public onlyOwner returns(bool)
+ {
+ address(_externalToken).safeTransferFrom(_from, _to, _value);
+ emit ExternalTokenTransferFrom(address(_externalToken), _from, _to, _value);
+ return true;
+ }
+
+ /**
+ * @dev externalTokenApproval approve the spender address to spend a specified amount of tokens
+ * on behalf of msg.sender.
+ * @param _externalToken the address of the Token Contract
+ * @param _spender address
+ * @param _value the amount of ether (in Wei) which the approval is referring to.
+ * @return bool which represents a success
+ */
+ function externalTokenApproval(IERC20 _externalToken, address _spender, uint256 _value)
+ public onlyOwner returns(bool)
+ {
+ address(_externalToken).safeApprove(_spender, _value);
+ emit ExternalTokenApproval(address(_externalToken), _spender, _value);
+ return true;
+ }
+
+ /**
+ * @dev metaData emits an event with a string, should contain the hash of some meta data.
+ * @param _metaData a string representing a hash of the meta data
+ * @return bool which represents a success
+ */
+ function metaData(string memory _metaData) public onlyOwner returns(bool) {
+ emit MetaData(_metaData);
+ return true;
+ }
+
+
+}
+ |
| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +354× +354× +354× +354× +354× + + + + + + + + + + +316× +316× + + + +1887× +1885× + + + +37× +37× + + + +4× +2× + + + +21× +21× + + + +290× +290× + + + +2222× +2222× +16× + + + +2207× +1979× +3× + + + + + + +2778× +2776× + + + + + + + + + + + + + + + +168× +168× + + + + + + + + + + + + + + + +22× +22× + + + + + + + + + + + + + + + +79× +79× + + + + + + + + + + + + + + + + + +923× + + + + + +923× + + +923× + + +923× +923× +923× +923× + + + + + + + + + + + + + + + +956× +1× + + +955× + + +731× +731× +731× + + + + + + + +33× +1× + +32× +32× +32× + + + + + + + + + + + + + + +25× +25× + +22× +20× +20× + + +2× + + +25× + +21× +19× +19× + + +2× + + +25× +25× + + + + + + + + + + + + + + +12× +12× +12× +12× + +12× + +12× +12× +12× +2× +2× +2× + +12× +12× +12× + + +12× + +11× +11× +11× +2× +2× +2× + +11× +11× +11× + + +12× +12× + + + + + +12× + + + + + + + + + + + + + + +2× +2× +2× +2× +2× +2× +2× +2× + +2× +2× +2× + +2× +2× + + + + + + + + + + + + + + + + + + +20× + + + + + + + + + + + + + + + +23× + + + + + + + + + + + + + + + + +11× + + + + + + + + + + + + + + + + + + + + + + + + +1× + + + + + + + + + + + + + + + + + +2× + + + + + + + + + + + + + + +290× + + + + + + + + +1× + + + +90× + + + + + + + + +57× + + + + + + + + +9× + + + + +2× + +2× +1× + + +1× + +1× +1× + + + + + + + + + + + + + + +38× + + + + + + + + +14× + + + + +1079× + + + | pragma solidity 0.5.17;
+
+import "./Avatar.sol";
+import "../globalConstraints/GlobalConstraintInterface.sol";
+
+/**
+ * @title Controller contract
+ * @dev A controller controls the organizations tokens, reputation and avatar.
+ * It is subject to a set of schemes and constraints that determine its behavior.
+ * Each scheme has it own parameters and operation permissions.
+ */
+contract Controller {
+
+ struct Scheme {
+ bytes32 paramsHash; // a hash "configuration" of the scheme
+ bytes4 permissions; // A bitwise flags of permissions,
+ // All 0: Not registered,
+ // 1st bit: Flag if the scheme is registered,
+ // 2nd bit: Scheme can register other schemes
+ // 3rd bit: Scheme can add/remove global constraints
+ // 4th bit: Scheme can upgrade the controller
+ // 5th bit: Scheme can call genericCall on behalf of
+ // the organization avatar
+ }
+
+ struct GlobalConstraint {
+ address gcAddress;
+ bytes32 params;
+ }
+
+ struct GlobalConstraintRegister {
+ bool isRegistered; //is registered
+ uint256 index; //index at globalConstraints
+ }
+
+ mapping(address=>Scheme) public schemes;
+
+ Avatar public avatar;
+ DAOToken public nativeToken;
+ Reputation public nativeReputation;
+ // newController will point to the new controller after the present controller is upgraded
+ address public newController;
+ // globalConstraintsPre that determine pre conditions for all actions on the controller
+
+ GlobalConstraint[] public globalConstraintsPre;
+ // globalConstraintsPost that determine post conditions for all actions on the controller
+ GlobalConstraint[] public globalConstraintsPost;
+ // globalConstraintsRegisterPre indicate if a globalConstraints is registered as a pre global constraint
+ mapping(address=>GlobalConstraintRegister) public globalConstraintsRegisterPre;
+ // globalConstraintsRegisterPost indicate if a globalConstraints is registered as a post global constraint
+ mapping(address=>GlobalConstraintRegister) public globalConstraintsRegisterPost;
+
+ event MintReputation (address indexed _sender, address indexed _to, uint256 _amount);
+ event BurnReputation (address indexed _sender, address indexed _from, uint256 _amount);
+ event MintTokens (address indexed _sender, address indexed _beneficiary, uint256 _amount);
+ event RegisterScheme (address indexed _sender, address indexed _scheme);
+ event UnregisterScheme (address indexed _sender, address indexed _scheme);
+ event UpgradeController(address indexed _oldController, address _newController);
+
+ event AddGlobalConstraint(
+ address indexed _globalConstraint,
+ bytes32 _params,
+ GlobalConstraintInterface.CallPhase _when);
+
+ event RemoveGlobalConstraint(address indexed _globalConstraint, uint256 _index, bool _isPre);
+
+ constructor( Avatar _avatar) public {
+ avatar = _avatar;
+ nativeToken = avatar.nativeToken();
+ nativeReputation = avatar.nativeReputation();
+ schemes[msg.sender] = Scheme({paramsHash: bytes32(0), permissions: bytes4(0x0000001F)});
+ emit RegisterScheme (msg.sender, msg.sender);
+ }
+
+ // Do not allow mistaken calls:
+ // solhint-disable-next-line payable-fallback
+ function() external {
+ revert();
+ }
+
+ // Modifiers:
+ modifier onlyRegisteredScheme() {
+ Erequire(schemes[msg.sender].permissions&bytes4(0x00000001) == bytes4(0x00000001));
+ _;
+ }
+
+ modifier onlyRegisteringSchemes() {
+ require(schemes[msg.sender].permissions&bytes4(0x00000002) == bytes4(0x00000002));
+ _;
+ }
+
+ modifier onlyGlobalConstraintsScheme() {
+ Erequire(schemes[msg.sender].permissions&bytes4(0x00000004) == bytes4(0x00000004));
+ _;
+ }
+
+ modifier onlyUpgradingScheme() {
+ require(schemes[msg.sender].permissions&bytes4(0x00000008) == bytes4(0x00000008));
+ _;
+ }
+
+ modifier onlyGenericCallScheme() {
+ Erequire(schemes[msg.sender].permissions&bytes4(0x00000010) == bytes4(0x00000010));
+ _;
+ }
+
+ modifier onlyMetaDataScheme() {
+ Erequire(schemes[msg.sender].permissions&bytes4(0x00000010) == bytes4(0x00000010));
+ _;
+ }
+
+ modifier onlySubjectToConstraint(bytes32 func) {
+ uint256 idx;
+ for (idx = 0; idx < globalConstraintsPre.length; idx++) {
+ require(
+ (GlobalConstraintInterface(globalConstraintsPre[idx].gcAddress))
+ .pre(msg.sender, globalConstraintsPre[idx].params, func));
+ }
+ _;
+ for (idx = 0; idx < globalConstraintsPost.length; idx++) {
+ require(
+ (GlobalConstraintInterface(globalConstraintsPost[idx].gcAddress))
+ .post(msg.sender, globalConstraintsPost[idx].params, func));
+ }
+ }
+
+ modifier isAvatarValid(address _avatar) {
+ require(_avatar == address(avatar));
+ _;
+ }
+
+ /**
+ * @dev Mint `_amount` of reputation that are assigned to `_to` .
+ * @param _amount amount of reputation to mint
+ * @param _to beneficiary address
+ * @return bool which represents a success
+ */
+ function mintReputation(uint256 _amount, address _to, address _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("mintReputation")
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ emit MintReputation(msg.sender, _to, _amount);
+ return nativeReputation.mint(_to, _amount);
+ }
+
+ /**
+ * @dev Burns `_amount` of reputation from `_from`
+ * @param _amount amount of reputation to burn
+ * @param _from The address that will lose the reputation
+ * @return bool which represents a success
+ */
+ function burnReputation(uint256 _amount, address _from, address _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("burnReputation")
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ emit BurnReputation(msg.sender, _from, _amount);
+ return nativeReputation.burn(_from, _amount);
+ }
+
+ /**
+ * @dev mint tokens .
+ * @param _amount amount of token to mint
+ * @param _beneficiary beneficiary address
+ * @return bool which represents a success
+ */
+ function mintTokens(uint256 _amount, address _beneficiary, address _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("mintTokens")
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ emit MintTokens(msg.sender, _beneficiary, _amount);
+ return nativeToken.mint(_beneficiary, _amount);
+ }
+
+ /**
+ * @dev register a scheme
+ * @param _scheme the address of the scheme
+ * @param _paramsHash a hashed configuration of the usage of the scheme
+ * @param _permissions the permissions the new scheme will have
+ * @return bool which represents a success
+ */
+ function registerScheme(address _scheme, bytes32 _paramsHash, bytes4 _permissions, address _avatar)
+ external
+ onlyRegisteringSchemes
+ onlySubjectToConstraint("registerScheme")
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+
+ Scheme memory scheme = schemes[_scheme];
+
+ // Check scheme has at least the permissions it is changing, and at least the current permissions:
+ // Implementation is a bit messy. One must recall logic-circuits ^^
+
+ // produces non-zero if sender does not have all of the perms that are changing between old and new
+ Erequire(bytes4(0x0000001f)&(_permissions^scheme.permissions)&(~schemes[msg.sender].permissions) == bytes4(0));
+
+ // produces non-zero if sender does not have all of the perms in the old scheme
+ Erequire(bytes4(0x0000001f)&(scheme.permissions&(~schemes[msg.sender].permissions)) == bytes4(0));
+
+ // Add or change the scheme:
+ schemes[_scheme].paramsHash = _paramsHash;
+ schemes[_scheme].permissions = _permissions|bytes4(0x00000001);
+ emit RegisterScheme(msg.sender, _scheme);
+ return true;
+ }
+
+ /**
+ * @dev unregister a scheme
+ * @param _scheme the address of the scheme
+ * @return bool which represents a success
+ */
+ function unregisterScheme( address _scheme, address _avatar)
+ external
+ onlyRegisteringSchemes
+ onlySubjectToConstraint("unregisterScheme")
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ //check if the scheme is registered
+ if (_isSchemeRegistered(_scheme) == false) {
+ return false;
+ }
+ // Check the unregistering scheme has enough permissions:
+ require(bytes4(0x0000001f)&(schemes[_scheme].permissions&(~schemes[msg.sender].permissions)) == bytes4(0));
+
+ // Unregister:
+ emit UnregisterScheme(msg.sender, _scheme);
+ delete schemes[_scheme];
+ return true;
+ }
+
+ /**
+ * @dev unregister the caller's scheme
+ * @return bool which represents a success
+ */
+ function unregisterSelf(address _avatar) external isAvatarValid(_avatar) returns(bool) {
+ if (_isSchemeRegistered(msg.sender) == false) {
+ return false;
+ }
+ delete schemes[msg.sender];
+ emit UnregisterScheme(msg.sender, msg.sender);
+ return true;
+ }
+
+ /**
+ * @dev add or update Global Constraint
+ * @param _globalConstraint the address of the global constraint to be added.
+ * @param _params the constraint parameters hash.
+ * @return bool which represents a success
+ */
+ function addGlobalConstraint(address _globalConstraint, bytes32 _params, address _avatar)
+ external
+ onlyGlobalConstraintsScheme
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ GlobalConstraintInterface.CallPhase when = GlobalConstraintInterface(_globalConstraint).when();
+ if ((when == GlobalConstraintInterface.CallPhase.Pre)||
+ (when == GlobalConstraintInterface.CallPhase.PreAndPost)) {
+ if (!globalConstraintsRegisterPre[_globalConstraint].isRegistered) {
+ globalConstraintsPre.push(GlobalConstraint(_globalConstraint, _params));
+ globalConstraintsRegisterPre[_globalConstraint] =
+ GlobalConstraintRegister(true, globalConstraintsPre.length-1);
+ }else {
+ globalConstraintsPre[globalConstraintsRegisterPre[_globalConstraint].index].params = _params;
+ }
+ }
+ if ((when == GlobalConstraintInterface.CallPhase.Post)||
+ (when == GlobalConstraintInterface.CallPhase.PreAndPost)) {
+ if (!globalConstraintsRegisterPost[_globalConstraint].isRegistered) {
+ globalConstraintsPost.push(GlobalConstraint(_globalConstraint, _params));
+ globalConstraintsRegisterPost[_globalConstraint] =
+ GlobalConstraintRegister(true, globalConstraintsPost.length-1);
+ }else {
+ globalConstraintsPost[globalConstraintsRegisterPost[_globalConstraint].index].params = _params;
+ }
+ }
+ emit AddGlobalConstraint(_globalConstraint, _params, when);
+ return true;
+ }
+
+ /**
+ * @dev remove Global Constraint
+ * @param _globalConstraint the address of the global constraint to be remove.
+ * @return bool which represents a success
+ */
+ // solhint-disable-next-line code-complexity
+ function removeGlobalConstraint (address _globalConstraint, address _avatar)
+ external
+ onlyGlobalConstraintsScheme
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ GlobalConstraintRegister memory globalConstraintRegister;
+ GlobalConstraint memory globalConstraint;
+ GlobalConstraintInterface.CallPhase when = GlobalConstraintInterface(_globalConstraint).when();
+ bool retVal = false;
+
+ Eif ((when == GlobalConstraintInterface.CallPhase.Pre)||
+ (when == GlobalConstraintInterface.CallPhase.PreAndPost)) {
+ globalConstraintRegister = globalConstraintsRegisterPre[_globalConstraint];
+ Eif (globalConstraintRegister.isRegistered) {
+ if (globalConstraintRegister.index < globalConstraintsPre.length-1) {
+ globalConstraint = globalConstraintsPre[globalConstraintsPre.length-1];
+ globalConstraintsPre[globalConstraintRegister.index] = globalConstraint;
+ globalConstraintsRegisterPre[globalConstraint.gcAddress].index = globalConstraintRegister.index;
+ }
+ globalConstraintsPre.length--;
+ delete globalConstraintsRegisterPre[_globalConstraint];
+ retVal = true;
+ }
+ }
+ if ((when == GlobalConstraintInterface.CallPhase.Post)||
+ (when == GlobalConstraintInterface.CallPhase.PreAndPost)) {
+ globalConstraintRegister = globalConstraintsRegisterPost[_globalConstraint];
+ Eif (globalConstraintRegister.isRegistered) {
+ if (globalConstraintRegister.index < globalConstraintsPost.length-1) {
+ globalConstraint = globalConstraintsPost[globalConstraintsPost.length-1];
+ globalConstraintsPost[globalConstraintRegister.index] = globalConstraint;
+ globalConstraintsRegisterPost[globalConstraint.gcAddress].index = globalConstraintRegister.index;
+ }
+ globalConstraintsPost.length--;
+ delete globalConstraintsRegisterPost[_globalConstraint];
+ retVal = true;
+ }
+ }
+ Eif (retVal) {
+ emit RemoveGlobalConstraint(
+ _globalConstraint,
+ globalConstraintRegister.index,
+ when == GlobalConstraintInterface.CallPhase.Pre
+ );
+ }
+ return retVal;
+ }
+
+ /**
+ * @dev upgrade the Controller
+ * The function will trigger an event 'UpgradeController'.
+ * @param _newController the address of the new controller.
+ * @return bool which represents a success
+ */
+ function upgradeController(address _newController, Avatar _avatar)
+ external
+ onlyUpgradingScheme
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ Erequire(newController == address(0)); // so the upgrade could be done once for a contract.
+ Erequire(_newController != address(0));
+ newController = _newController;
+ avatar.transferOwnership(_newController);
+ Erequire(avatar.owner() == _newController);
+ Eif (nativeToken.owner() == address(this)) {
+ nativeToken.transferOwnership(_newController);
+ Erequire(nativeToken.owner() == _newController);
+ }
+ Eif (nativeReputation.owner() == address(this)) {
+ nativeReputation.transferOwnership(_newController);
+ Erequire(nativeReputation.owner() == _newController);
+ }
+ emit UpgradeController(address(this), newController);
+ return true;
+ }
+
+ /**
+ * @dev perform a generic call to an arbitrary contract
+ * @param _contract the contract's address to call
+ * @param _data ABI-encoded contract call to call `_contract` address.
+ * @param _avatar the controller's avatar address
+ * @param _value value (ETH) to transfer with the transaction
+ * @return bool -success
+ * bytes - the return value of the called _contract's function.
+ */
+ function genericCall(address _contract, bytes calldata _data, Avatar _avatar, uint256 _value)
+ external
+ onlyGenericCallScheme
+ onlySubjectToConstraint("genericCall")
+ isAvatarValid(address(_avatar))
+ returns (bool, bytes memory)
+ {
+ return avatar.genericCall(_contract, _data, _value);
+ }
+
+ /**
+ * @dev send some ether
+ * @param _amountInWei the amount of ether (in Wei) to send
+ * @param _to address of the beneficiary
+ * @return bool which represents a success
+ */
+ function sendEther(uint256 _amountInWei, address payable _to, Avatar _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("sendEther")
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ return avatar.sendEther(_amountInWei, _to);
+ }
+
+ /**
+ * @dev send some amount of arbitrary ERC20 Tokens
+ * @param _externalToken the address of the Token Contract
+ * @param _to address of the beneficiary
+ * @param _value the amount of ether (in Wei) to send
+ * @return bool which represents a success
+ */
+ function externalTokenTransfer(IERC20 _externalToken, address _to, uint256 _value, Avatar _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("externalTokenTransfer")
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ return avatar.externalTokenTransfer(_externalToken, _to, _value);
+ }
+
+ /**
+ * @dev transfer token "from" address "to" address
+ * One must to approve the amount of tokens which can be spend from the
+ * "from" account.This can be done using externalTokenApprove.
+ * @param _externalToken the address of the Token Contract
+ * @param _from address of the account to send from
+ * @param _to address of the beneficiary
+ * @param _value the amount of ether (in Wei) to send
+ * @return bool which represents a success
+ */
+ function externalTokenTransferFrom(
+ IERC20 _externalToken,
+ address _from,
+ address _to,
+ uint256 _value,
+ Avatar _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("externalTokenTransferFrom")
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ return avatar.externalTokenTransferFrom(_externalToken, _from, _to, _value);
+ }
+
+ /**
+ * @dev externalTokenApproval approve the spender address to spend a specified amount of tokens
+ * on behalf of msg.sender.
+ * @param _externalToken the address of the Token Contract
+ * @param _spender address
+ * @param _value the amount of ether (in Wei) which the approval is referring to.
+ * @return bool which represents a success
+ */
+ function externalTokenApproval(IERC20 _externalToken, address _spender, uint256 _value, Avatar _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("externalTokenIncreaseApproval")
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ return avatar.externalTokenApproval(_externalToken, _spender, _value);
+ }
+
+ /**
+ * @dev metaData emits an event with a string, should contain the hash of some meta data.
+ * @param _metaData a string representing a hash of the meta data
+ * @param _avatar Avatar
+ * @return bool which represents a success
+ */
+ function metaData(string calldata _metaData, Avatar _avatar)
+ external
+ onlyMetaDataScheme
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ return avatar.metaData(_metaData);
+ }
+
+ /**
+ * @dev getNativeReputation
+ * @param _avatar the organization avatar.
+ * @return organization native reputation
+ */
+ function getNativeReputation(address _avatar) external isAvatarValid(_avatar) view returns(address) {
+ return address(nativeReputation);
+ }
+
+ function isSchemeRegistered(address _scheme, address _avatar) external isAvatarValid(_avatar) view returns(bool) {
+ return _isSchemeRegistered(_scheme);
+ }
+
+ function getSchemeParameters(address _scheme, address _avatar)
+ external
+ isAvatarValid(_avatar)
+ view
+ returns(bytes32)
+ {
+ return schemes[_scheme].paramsHash;
+ }
+
+ function getSchemePermissions(address _scheme, address _avatar)
+ external
+ isAvatarValid(_avatar)
+ view
+ returns(bytes4)
+ {
+ return schemes[_scheme].permissions;
+ }
+
+ function getGlobalConstraintParameters(address _globalConstraint, address) external view returns(bytes32) {
+
+ GlobalConstraintRegister memory register = globalConstraintsRegisterPre[_globalConstraint];
+
+ if (register.isRegistered) {
+ return globalConstraintsPre[register.index].params;
+ }
+
+ register = globalConstraintsRegisterPost[_globalConstraint];
+
+ Eif (register.isRegistered) {
+ return globalConstraintsPost[register.index].params;
+ }
+ }
+
+ /**
+ * @dev globalConstraintsCount return the global constraint pre and post count
+ * @return uint256 globalConstraintsPre count.
+ * @return uint256 globalConstraintsPost count.
+ */
+ function globalConstraintsCount(address _avatar)
+ external
+ isAvatarValid(_avatar)
+ view
+ returns(uint, uint)
+ {
+ return (globalConstraintsPre.length, globalConstraintsPost.length);
+ }
+
+ function isGlobalConstraintRegistered(address _globalConstraint, address _avatar)
+ external
+ isAvatarValid(_avatar)
+ view
+ returns(bool)
+ {
+ return (globalConstraintsRegisterPre[_globalConstraint].isRegistered ||
+ globalConstraintsRegisterPost[_globalConstraint].isRegistered);
+ }
+
+ function _isSchemeRegistered(address _scheme) private view returns(bool) {
+ return (schemes[_scheme].permissions&bytes4(0x00000001) != bytes4(0));
+ }
+}
+ |
| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 | + + + + + + + + + + + + + + + + + + + + + + + + + + + +371× +371× +371× + + + + + + + + +462× +4× +460× +460× + + + | pragma solidity 0.5.17;
+
+import "openzeppelin-solidity/contracts/token/ERC20/ERC20Burnable.sol";
+import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
+import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
+
+
+/**
+ * @title DAOToken, base on zeppelin contract.
+ * @dev ERC20 compatible token. It is a mintable, burnable token.
+ */
+
+contract DAOToken is ERC20, ERC20Burnable, Ownable {
+
+ string public name;
+ string public symbol;
+ // solhint-disable-next-line const-name-snakecase
+ uint8 public constant decimals = 18;
+ uint256 public cap;
+
+ /**
+ * @dev Constructor
+ * @param _name - token name
+ * @param _symbol - token symbol
+ * @param _cap - token cap - 0 value means no cap
+ */
+ constructor(string memory _name, string memory _symbol, uint256 _cap)
+ public {
+ name = _name;
+ symbol = _symbol;
+ cap = _cap;
+ }
+
+ /**
+ * @dev Function to mint tokens
+ * @param _to The address that will receive the minted tokens.
+ * @param _amount The amount of tokens to mint.
+ */
+ function mint(address _to, uint256 _amount) public onlyOwner returns (bool) {
+ if (cap > 0)
+ require(totalSupply().add(_amount) <= cap);
+ _mint(_to, _amount);
+ return true;
+ }
+}
+ |
| File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
|---|---|---|---|---|---|---|---|---|---|
| Avatar.sol | +100% | +20/20 | +100% | +0/0 | +100% | +8/8 | +100% | +20/20 | +|
| Controller.sol | +99.07% | +107/108 | +73.53% | +50/68 | +96.97% | +32/33 | +99.18% | +121/122 | +|
| DAOToken.sol | +100% | +7/7 | +100% | +4/4 | +100% | +2/2 | +100% | +7/7 | +
| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 | + + + + + + + + + + + + + + + | pragma solidity 0.5.17;
+
+
+contract GlobalConstraintInterface {
+
+ enum CallPhase { Pre, Post, PreAndPost }
+
+ function pre( address _scheme, bytes32 _params, bytes32 _method ) public returns(bool);
+ function post( address _scheme, bytes32 _params, bytes32 _method ) public returns(bool);
+ /**
+ * @dev when return if this globalConstraints is pre, post or both.
+ * @return CallPhase enum indication Pre, Post or PreAndPost.
+ */
+ function when() public returns(CallPhase);
+}
+ |
| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 | + + + + + + + + + + + + + + + + + + + + + + + + + + + +4× +4× +4× +4× + + + + + + + + + +8× + + + + + + + + +1× + + + + + + + + +7× + +3× + +4× + + + + + + + +1× + + + | pragma solidity 0.5.17;
+
+import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
+import "./GlobalConstraintInterface.sol";
+
+
+/**
+ * @title Token Cap Global Constraint
+ * @dev A simple global constraint to cap the number of tokens.
+ */
+
+contract TokenCapGC {
+ // A set of parameters, on which the cap will be checked:
+ struct Parameters {
+ IERC20 token;
+ uint256 cap;
+ }
+
+ // Mapping from the hash of the parameters to the parameters themselves:
+ mapping (bytes32=>Parameters) public parameters;
+
+ /**
+ * @dev adding a new set of parameters
+ * @param _token the token to add to the params.
+ * @param _cap the cap to check the total supply against.
+ * @return the calculated parameters hash
+ */
+ function setParameters(IERC20 _token, uint256 _cap) public returns(bytes32) {
+ bytes32 paramsHash = getParametersHash(_token, _cap);
+ parameters[paramsHash].token = _token;
+ parameters[paramsHash].cap = _cap;
+ return paramsHash;
+ }
+
+ /**
+ * @dev calculate and returns the hash of the given parameters
+ * @param _token the token to add to the params.
+ * @param _cap the cap to check the total supply against.
+ * @return the calculated parameters hash
+ */
+ function getParametersHash(IERC20 _token, uint256 _cap) public pure returns(bytes32) {
+ return (keccak256(abi.encodePacked(_token, _cap)));
+ }
+
+ /**
+ * @dev check the constraint after the action.
+ * This global constraint only checks the state after the action, so here we just return true:
+ * @return true
+ */
+ function pre(address, bytes32, bytes32) public pure returns(bool) {
+ return true;
+ }
+
+ /**
+ * @dev check the total supply cap.
+ * @param _paramsHash the parameters hash to check the total supply cap against.
+ * @return bool which represents a success
+ */
+ function post(address, bytes32 _paramsHash, bytes32) public view returns(bool) {
+ if ((parameters[_paramsHash].token != IERC20(0)) &&
+ (parameters[_paramsHash].token.totalSupply() > parameters[_paramsHash].cap)) {
+ return false;
+ }
+ 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.Post;
+ }
+}
+ |
| File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
|---|---|---|---|---|---|---|---|---|---|
| GlobalConstraintInterface.sol | +100% | +0/0 | +100% | +0/0 | +100% | +0/0 | +100% | +0/0 | +|
| TokenCapGC.sol | +100% | +10/10 | +100% | +2/2 | +100% | +5/5 | +100% | +10/10 | +
| File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
|---|---|---|---|---|---|---|---|---|---|
| controller/ | +99.26% | +134/135 | +75% | +54/72 | +97.67% | +42/43 | +99.33% | +148/149 | +|
| globalConstraints/ | +100% | +10/10 | +100% | +2/2 | +100% | +5/5 | +100% | +10/10 | +|
| libs/ | +100% | +13/13 | +50% | +10/20 | +100% | +3/3 | +100% | +13/13 | +|
| schemes/ | +99.07% | +638/644 | +76.55% | +346/452 | +97.85% | +91/93 | +99.08% | +645/651 | +|
| universalSchemes/ | +100% | +301/301 | +75% | +123/164 | +100% | +45/45 | +100% | +305/305 | +|
| utils/ | +94.29% | +66/70 | +72.5% | +29/40 | +100% | +14/14 | +94.44% | +68/72 | +|
| votingMachines/ | +76% | +19/25 | +57.14% | +8/14 | +100% | +7/7 | +76.92% | +20/26 | +
| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +383× +383× +383× + + + + + + +45× + + + + + + + + + + + + + + + +23× +23× + + + + + + + + + +24× +22× +22× + + + + + + + + + + + + +12× +12× +12× + + + + + + + + + + + + + + + + + + +2× +2× +2× + + + + + + + + + + + + + +3× +3× +3× + + + + + + + + +291× +291× + + + + + | pragma solidity 0.5.17;
+
+import "@daostack/infra/contracts/Reputation.sol";
+import "./DAOToken.sol";
+import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
+import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
+import "../libs/SafeERC20.sol";
+
+
+/**
+ * @title An Avatar holds tokens, reputation and ether for a controller
+ */
+contract Avatar is Ownable {
+ using SafeERC20 for address;
+
+ string public orgName;
+ DAOToken public nativeToken;
+ Reputation public nativeReputation;
+
+ event GenericCall(address indexed _contract, bytes _data, uint _value, bool _success);
+ event SendEther(uint256 _amountInWei, address indexed _to);
+ event ExternalTokenTransfer(address indexed _externalToken, address indexed _to, uint256 _value);
+ event ExternalTokenTransferFrom(address indexed _externalToken, address _from, address _to, uint256 _value);
+ event ExternalTokenApproval(address indexed _externalToken, address _spender, uint256 _value);
+ event ReceiveEther(address indexed _sender, uint256 _value);
+ event MetaData(string _metaData);
+
+ /**
+ * @dev the constructor takes organization name, native token and reputation system
+ and creates an avatar for a controller
+ */
+ constructor(string memory _orgName, DAOToken _nativeToken, Reputation _nativeReputation) public {
+ orgName = _orgName;
+ nativeToken = _nativeToken;
+ nativeReputation = _nativeReputation;
+ }
+
+ /**
+ * @dev enables an avatar to receive ethers
+ */
+ function() external payable {
+ emit ReceiveEther(msg.sender, msg.value);
+ }
+
+ /**
+ * @dev perform a generic call to an arbitrary contract
+ * @param _contract the contract's address to call
+ * @param _data ABI-encoded contract call to call `_contract` address.
+ * @param _value value (ETH) to transfer with the transaction
+ * @return bool success or fail
+ * bytes - the return bytes of the called contract's function.
+ */
+ function genericCall(address _contract, bytes memory _data, uint256 _value)
+ public
+ onlyOwner
+ returns(bool success, bytes memory returnValue) {
+ // solhint-disable-next-line avoid-call-value
+ (success, returnValue) = _contract.call.value(_value)(_data);
+ emit GenericCall(_contract, _data, _value, success);
+ }
+
+ /**
+ * @dev send ethers from the avatar's wallet
+ * @param _amountInWei amount to send in Wei units
+ * @param _to send the ethers to this address
+ * @return bool which represents success
+ */
+ function sendEther(uint256 _amountInWei, address payable _to) public onlyOwner returns(bool) {
+ _to.transfer(_amountInWei);
+ emit SendEther(_amountInWei, _to);
+ return true;
+ }
+
+ /**
+ * @dev external token transfer
+ * @param _externalToken the token contract
+ * @param _to the destination address
+ * @param _value the amount of tokens to transfer
+ * @return bool which represents success
+ */
+ function externalTokenTransfer(IERC20 _externalToken, address _to, uint256 _value)
+ public onlyOwner returns(bool)
+ {
+ address(_externalToken).safeTransfer(_to, _value);
+ emit ExternalTokenTransfer(address(_externalToken), _to, _value);
+ return true;
+ }
+
+ /**
+ * @dev external token transfer from a specific account
+ * @param _externalToken the token contract
+ * @param _from the account to spend token from
+ * @param _to the destination address
+ * @param _value the amount of tokens to transfer
+ * @return bool which represents success
+ */
+ function externalTokenTransferFrom(
+ IERC20 _externalToken,
+ address _from,
+ address _to,
+ uint256 _value
+ )
+ public onlyOwner returns(bool)
+ {
+ address(_externalToken).safeTransferFrom(_from, _to, _value);
+ emit ExternalTokenTransferFrom(address(_externalToken), _from, _to, _value);
+ return true;
+ }
+
+ /**
+ * @dev externalTokenApproval approve the spender address to spend a specified amount of tokens
+ * on behalf of msg.sender.
+ * @param _externalToken the address of the Token Contract
+ * @param _spender address
+ * @param _value the amount of ether (in Wei) which the approval is referring to.
+ * @return bool which represents a success
+ */
+ function externalTokenApproval(IERC20 _externalToken, address _spender, uint256 _value)
+ public onlyOwner returns(bool)
+ {
+ address(_externalToken).safeApprove(_spender, _value);
+ emit ExternalTokenApproval(address(_externalToken), _spender, _value);
+ return true;
+ }
+
+ /**
+ * @dev metaData emits an event with a string, should contain the hash of some meta data.
+ * @param _metaData a string representing a hash of the meta data
+ * @return bool which represents a success
+ */
+ function metaData(string memory _metaData) public onlyOwner returns(bool) {
+ emit MetaData(_metaData);
+ return true;
+ }
+
+
+}
+ |
| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +354× +354× +354× +354× +354× + + + + + + + + + + +316× +316× + + + +1887× +1885× + + + +37× +37× + + + +4× +2× + + + +21× +21× + + + +290× +290× + + + +2222× +2222× +16× + + + +2207× +1979× +3× + + + + + + +2778× +2776× + + + + + + + + + + + + + + + +168× +168× + + + + + + + + + + + + + + + +22× +22× + + + + + + + + + + + + + + + +79× +79× + + + + + + + + + + + + + + + + + +923× + + + + + +923× + + +923× + + +923× +923× +923× +923× + + + + + + + + + + + + + + + +956× +1× + + +955× + + +731× +731× +731× + + + + + + + +33× +1× + +32× +32× +32× + + + + + + + + + + + + + + +25× +25× + +22× +20× +20× + + +2× + + +25× + +21× +19× +19× + + +2× + + +25× +25× + + + + + + + + + + + + + + +12× +12× +12× +12× + +12× + +12× +12× +12× +2× +2× +2× + +12× +12× +12× + + +12× + +11× +11× +11× +2× +2× +2× + +11× +11× +11× + + +12× +12× + + + + + +12× + + + + + + + + + + + + + + +2× +2× +2× +2× +2× +2× +2× +2× + +2× +2× +2× + +2× +2× + + + + + + + + + + + + + + + + + + +20× + + + + + + + + + + + + + + + +23× + + + + + + + + + + + + + + + + +11× + + + + + + + + + + + + + + + + + + + + + + + + +1× + + + + + + + + + + + + + + + + + +2× + + + + + + + + + + + + + + +290× + + + + + + + + +1× + + + +90× + + + + + + + + +57× + + + + + + + + +9× + + + + +2× + +2× +1× + + +1× + +1× +1× + + + + + + + + + + + + + + +38× + + + + + + + + +14× + + + + +1079× + + + | pragma solidity 0.5.17;
+
+import "./Avatar.sol";
+import "../globalConstraints/GlobalConstraintInterface.sol";
+
+/**
+ * @title Controller contract
+ * @dev A controller controls the organizations tokens, reputation and avatar.
+ * It is subject to a set of schemes and constraints that determine its behavior.
+ * Each scheme has it own parameters and operation permissions.
+ */
+contract Controller {
+
+ struct Scheme {
+ bytes32 paramsHash; // a hash "configuration" of the scheme
+ bytes4 permissions; // A bitwise flags of permissions,
+ // All 0: Not registered,
+ // 1st bit: Flag if the scheme is registered,
+ // 2nd bit: Scheme can register other schemes
+ // 3rd bit: Scheme can add/remove global constraints
+ // 4th bit: Scheme can upgrade the controller
+ // 5th bit: Scheme can call genericCall on behalf of
+ // the organization avatar
+ }
+
+ struct GlobalConstraint {
+ address gcAddress;
+ bytes32 params;
+ }
+
+ struct GlobalConstraintRegister {
+ bool isRegistered; //is registered
+ uint256 index; //index at globalConstraints
+ }
+
+ mapping(address=>Scheme) public schemes;
+
+ Avatar public avatar;
+ DAOToken public nativeToken;
+ Reputation public nativeReputation;
+ // newController will point to the new controller after the present controller is upgraded
+ address public newController;
+ // globalConstraintsPre that determine pre conditions for all actions on the controller
+
+ GlobalConstraint[] public globalConstraintsPre;
+ // globalConstraintsPost that determine post conditions for all actions on the controller
+ GlobalConstraint[] public globalConstraintsPost;
+ // globalConstraintsRegisterPre indicate if a globalConstraints is registered as a pre global constraint
+ mapping(address=>GlobalConstraintRegister) public globalConstraintsRegisterPre;
+ // globalConstraintsRegisterPost indicate if a globalConstraints is registered as a post global constraint
+ mapping(address=>GlobalConstraintRegister) public globalConstraintsRegisterPost;
+
+ event MintReputation (address indexed _sender, address indexed _to, uint256 _amount);
+ event BurnReputation (address indexed _sender, address indexed _from, uint256 _amount);
+ event MintTokens (address indexed _sender, address indexed _beneficiary, uint256 _amount);
+ event RegisterScheme (address indexed _sender, address indexed _scheme);
+ event UnregisterScheme (address indexed _sender, address indexed _scheme);
+ event UpgradeController(address indexed _oldController, address _newController);
+
+ event AddGlobalConstraint(
+ address indexed _globalConstraint,
+ bytes32 _params,
+ GlobalConstraintInterface.CallPhase _when);
+
+ event RemoveGlobalConstraint(address indexed _globalConstraint, uint256 _index, bool _isPre);
+
+ constructor( Avatar _avatar) public {
+ avatar = _avatar;
+ nativeToken = avatar.nativeToken();
+ nativeReputation = avatar.nativeReputation();
+ schemes[msg.sender] = Scheme({paramsHash: bytes32(0), permissions: bytes4(0x0000001F)});
+ emit RegisterScheme (msg.sender, msg.sender);
+ }
+
+ // Do not allow mistaken calls:
+ // solhint-disable-next-line payable-fallback
+ function() external {
+ revert();
+ }
+
+ // Modifiers:
+ modifier onlyRegisteredScheme() {
+ Erequire(schemes[msg.sender].permissions&bytes4(0x00000001) == bytes4(0x00000001));
+ _;
+ }
+
+ modifier onlyRegisteringSchemes() {
+ require(schemes[msg.sender].permissions&bytes4(0x00000002) == bytes4(0x00000002));
+ _;
+ }
+
+ modifier onlyGlobalConstraintsScheme() {
+ Erequire(schemes[msg.sender].permissions&bytes4(0x00000004) == bytes4(0x00000004));
+ _;
+ }
+
+ modifier onlyUpgradingScheme() {
+ require(schemes[msg.sender].permissions&bytes4(0x00000008) == bytes4(0x00000008));
+ _;
+ }
+
+ modifier onlyGenericCallScheme() {
+ Erequire(schemes[msg.sender].permissions&bytes4(0x00000010) == bytes4(0x00000010));
+ _;
+ }
+
+ modifier onlyMetaDataScheme() {
+ Erequire(schemes[msg.sender].permissions&bytes4(0x00000010) == bytes4(0x00000010));
+ _;
+ }
+
+ modifier onlySubjectToConstraint(bytes32 func) {
+ uint256 idx;
+ for (idx = 0; idx < globalConstraintsPre.length; idx++) {
+ require(
+ (GlobalConstraintInterface(globalConstraintsPre[idx].gcAddress))
+ .pre(msg.sender, globalConstraintsPre[idx].params, func));
+ }
+ _;
+ for (idx = 0; idx < globalConstraintsPost.length; idx++) {
+ require(
+ (GlobalConstraintInterface(globalConstraintsPost[idx].gcAddress))
+ .post(msg.sender, globalConstraintsPost[idx].params, func));
+ }
+ }
+
+ modifier isAvatarValid(address _avatar) {
+ require(_avatar == address(avatar));
+ _;
+ }
+
+ /**
+ * @dev Mint `_amount` of reputation that are assigned to `_to` .
+ * @param _amount amount of reputation to mint
+ * @param _to beneficiary address
+ * @return bool which represents a success
+ */
+ function mintReputation(uint256 _amount, address _to, address _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("mintReputation")
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ emit MintReputation(msg.sender, _to, _amount);
+ return nativeReputation.mint(_to, _amount);
+ }
+
+ /**
+ * @dev Burns `_amount` of reputation from `_from`
+ * @param _amount amount of reputation to burn
+ * @param _from The address that will lose the reputation
+ * @return bool which represents a success
+ */
+ function burnReputation(uint256 _amount, address _from, address _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("burnReputation")
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ emit BurnReputation(msg.sender, _from, _amount);
+ return nativeReputation.burn(_from, _amount);
+ }
+
+ /**
+ * @dev mint tokens .
+ * @param _amount amount of token to mint
+ * @param _beneficiary beneficiary address
+ * @return bool which represents a success
+ */
+ function mintTokens(uint256 _amount, address _beneficiary, address _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("mintTokens")
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ emit MintTokens(msg.sender, _beneficiary, _amount);
+ return nativeToken.mint(_beneficiary, _amount);
+ }
+
+ /**
+ * @dev register a scheme
+ * @param _scheme the address of the scheme
+ * @param _paramsHash a hashed configuration of the usage of the scheme
+ * @param _permissions the permissions the new scheme will have
+ * @return bool which represents a success
+ */
+ function registerScheme(address _scheme, bytes32 _paramsHash, bytes4 _permissions, address _avatar)
+ external
+ onlyRegisteringSchemes
+ onlySubjectToConstraint("registerScheme")
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+
+ Scheme memory scheme = schemes[_scheme];
+
+ // Check scheme has at least the permissions it is changing, and at least the current permissions:
+ // Implementation is a bit messy. One must recall logic-circuits ^^
+
+ // produces non-zero if sender does not have all of the perms that are changing between old and new
+ Erequire(bytes4(0x0000001f)&(_permissions^scheme.permissions)&(~schemes[msg.sender].permissions) == bytes4(0));
+
+ // produces non-zero if sender does not have all of the perms in the old scheme
+ Erequire(bytes4(0x0000001f)&(scheme.permissions&(~schemes[msg.sender].permissions)) == bytes4(0));
+
+ // Add or change the scheme:
+ schemes[_scheme].paramsHash = _paramsHash;
+ schemes[_scheme].permissions = _permissions|bytes4(0x00000001);
+ emit RegisterScheme(msg.sender, _scheme);
+ return true;
+ }
+
+ /**
+ * @dev unregister a scheme
+ * @param _scheme the address of the scheme
+ * @return bool which represents a success
+ */
+ function unregisterScheme( address _scheme, address _avatar)
+ external
+ onlyRegisteringSchemes
+ onlySubjectToConstraint("unregisterScheme")
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ //check if the scheme is registered
+ if (_isSchemeRegistered(_scheme) == false) {
+ return false;
+ }
+ // Check the unregistering scheme has enough permissions:
+ require(bytes4(0x0000001f)&(schemes[_scheme].permissions&(~schemes[msg.sender].permissions)) == bytes4(0));
+
+ // Unregister:
+ emit UnregisterScheme(msg.sender, _scheme);
+ delete schemes[_scheme];
+ return true;
+ }
+
+ /**
+ * @dev unregister the caller's scheme
+ * @return bool which represents a success
+ */
+ function unregisterSelf(address _avatar) external isAvatarValid(_avatar) returns(bool) {
+ if (_isSchemeRegistered(msg.sender) == false) {
+ return false;
+ }
+ delete schemes[msg.sender];
+ emit UnregisterScheme(msg.sender, msg.sender);
+ return true;
+ }
+
+ /**
+ * @dev add or update Global Constraint
+ * @param _globalConstraint the address of the global constraint to be added.
+ * @param _params the constraint parameters hash.
+ * @return bool which represents a success
+ */
+ function addGlobalConstraint(address _globalConstraint, bytes32 _params, address _avatar)
+ external
+ onlyGlobalConstraintsScheme
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ GlobalConstraintInterface.CallPhase when = GlobalConstraintInterface(_globalConstraint).when();
+ if ((when == GlobalConstraintInterface.CallPhase.Pre)||
+ (when == GlobalConstraintInterface.CallPhase.PreAndPost)) {
+ if (!globalConstraintsRegisterPre[_globalConstraint].isRegistered) {
+ globalConstraintsPre.push(GlobalConstraint(_globalConstraint, _params));
+ globalConstraintsRegisterPre[_globalConstraint] =
+ GlobalConstraintRegister(true, globalConstraintsPre.length-1);
+ }else {
+ globalConstraintsPre[globalConstraintsRegisterPre[_globalConstraint].index].params = _params;
+ }
+ }
+ if ((when == GlobalConstraintInterface.CallPhase.Post)||
+ (when == GlobalConstraintInterface.CallPhase.PreAndPost)) {
+ if (!globalConstraintsRegisterPost[_globalConstraint].isRegistered) {
+ globalConstraintsPost.push(GlobalConstraint(_globalConstraint, _params));
+ globalConstraintsRegisterPost[_globalConstraint] =
+ GlobalConstraintRegister(true, globalConstraintsPost.length-1);
+ }else {
+ globalConstraintsPost[globalConstraintsRegisterPost[_globalConstraint].index].params = _params;
+ }
+ }
+ emit AddGlobalConstraint(_globalConstraint, _params, when);
+ return true;
+ }
+
+ /**
+ * @dev remove Global Constraint
+ * @param _globalConstraint the address of the global constraint to be remove.
+ * @return bool which represents a success
+ */
+ // solhint-disable-next-line code-complexity
+ function removeGlobalConstraint (address _globalConstraint, address _avatar)
+ external
+ onlyGlobalConstraintsScheme
+ isAvatarValid(_avatar)
+ returns(bool)
+ {
+ GlobalConstraintRegister memory globalConstraintRegister;
+ GlobalConstraint memory globalConstraint;
+ GlobalConstraintInterface.CallPhase when = GlobalConstraintInterface(_globalConstraint).when();
+ bool retVal = false;
+
+ Eif ((when == GlobalConstraintInterface.CallPhase.Pre)||
+ (when == GlobalConstraintInterface.CallPhase.PreAndPost)) {
+ globalConstraintRegister = globalConstraintsRegisterPre[_globalConstraint];
+ Eif (globalConstraintRegister.isRegistered) {
+ if (globalConstraintRegister.index < globalConstraintsPre.length-1) {
+ globalConstraint = globalConstraintsPre[globalConstraintsPre.length-1];
+ globalConstraintsPre[globalConstraintRegister.index] = globalConstraint;
+ globalConstraintsRegisterPre[globalConstraint.gcAddress].index = globalConstraintRegister.index;
+ }
+ globalConstraintsPre.length--;
+ delete globalConstraintsRegisterPre[_globalConstraint];
+ retVal = true;
+ }
+ }
+ if ((when == GlobalConstraintInterface.CallPhase.Post)||
+ (when == GlobalConstraintInterface.CallPhase.PreAndPost)) {
+ globalConstraintRegister = globalConstraintsRegisterPost[_globalConstraint];
+ Eif (globalConstraintRegister.isRegistered) {
+ if (globalConstraintRegister.index < globalConstraintsPost.length-1) {
+ globalConstraint = globalConstraintsPost[globalConstraintsPost.length-1];
+ globalConstraintsPost[globalConstraintRegister.index] = globalConstraint;
+ globalConstraintsRegisterPost[globalConstraint.gcAddress].index = globalConstraintRegister.index;
+ }
+ globalConstraintsPost.length--;
+ delete globalConstraintsRegisterPost[_globalConstraint];
+ retVal = true;
+ }
+ }
+ Eif (retVal) {
+ emit RemoveGlobalConstraint(
+ _globalConstraint,
+ globalConstraintRegister.index,
+ when == GlobalConstraintInterface.CallPhase.Pre
+ );
+ }
+ return retVal;
+ }
+
+ /**
+ * @dev upgrade the Controller
+ * The function will trigger an event 'UpgradeController'.
+ * @param _newController the address of the new controller.
+ * @return bool which represents a success
+ */
+ function upgradeController(address _newController, Avatar _avatar)
+ external
+ onlyUpgradingScheme
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ Erequire(newController == address(0)); // so the upgrade could be done once for a contract.
+ Erequire(_newController != address(0));
+ newController = _newController;
+ avatar.transferOwnership(_newController);
+ Erequire(avatar.owner() == _newController);
+ Eif (nativeToken.owner() == address(this)) {
+ nativeToken.transferOwnership(_newController);
+ Erequire(nativeToken.owner() == _newController);
+ }
+ Eif (nativeReputation.owner() == address(this)) {
+ nativeReputation.transferOwnership(_newController);
+ Erequire(nativeReputation.owner() == _newController);
+ }
+ emit UpgradeController(address(this), newController);
+ return true;
+ }
+
+ /**
+ * @dev perform a generic call to an arbitrary contract
+ * @param _contract the contract's address to call
+ * @param _data ABI-encoded contract call to call `_contract` address.
+ * @param _avatar the controller's avatar address
+ * @param _value value (ETH) to transfer with the transaction
+ * @return bool -success
+ * bytes - the return value of the called _contract's function.
+ */
+ function genericCall(address _contract, bytes calldata _data, Avatar _avatar, uint256 _value)
+ external
+ onlyGenericCallScheme
+ onlySubjectToConstraint("genericCall")
+ isAvatarValid(address(_avatar))
+ returns (bool, bytes memory)
+ {
+ return avatar.genericCall(_contract, _data, _value);
+ }
+
+ /**
+ * @dev send some ether
+ * @param _amountInWei the amount of ether (in Wei) to send
+ * @param _to address of the beneficiary
+ * @return bool which represents a success
+ */
+ function sendEther(uint256 _amountInWei, address payable _to, Avatar _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("sendEther")
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ return avatar.sendEther(_amountInWei, _to);
+ }
+
+ /**
+ * @dev send some amount of arbitrary ERC20 Tokens
+ * @param _externalToken the address of the Token Contract
+ * @param _to address of the beneficiary
+ * @param _value the amount of ether (in Wei) to send
+ * @return bool which represents a success
+ */
+ function externalTokenTransfer(IERC20 _externalToken, address _to, uint256 _value, Avatar _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("externalTokenTransfer")
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ return avatar.externalTokenTransfer(_externalToken, _to, _value);
+ }
+
+ /**
+ * @dev transfer token "from" address "to" address
+ * One must to approve the amount of tokens which can be spend from the
+ * "from" account.This can be done using externalTokenApprove.
+ * @param _externalToken the address of the Token Contract
+ * @param _from address of the account to send from
+ * @param _to address of the beneficiary
+ * @param _value the amount of ether (in Wei) to send
+ * @return bool which represents a success
+ */
+ function externalTokenTransferFrom(
+ IERC20 _externalToken,
+ address _from,
+ address _to,
+ uint256 _value,
+ Avatar _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("externalTokenTransferFrom")
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ return avatar.externalTokenTransferFrom(_externalToken, _from, _to, _value);
+ }
+
+ /**
+ * @dev externalTokenApproval approve the spender address to spend a specified amount of tokens
+ * on behalf of msg.sender.
+ * @param _externalToken the address of the Token Contract
+ * @param _spender address
+ * @param _value the amount of ether (in Wei) which the approval is referring to.
+ * @return bool which represents a success
+ */
+ function externalTokenApproval(IERC20 _externalToken, address _spender, uint256 _value, Avatar _avatar)
+ external
+ onlyRegisteredScheme
+ onlySubjectToConstraint("externalTokenIncreaseApproval")
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ return avatar.externalTokenApproval(_externalToken, _spender, _value);
+ }
+
+ /**
+ * @dev metaData emits an event with a string, should contain the hash of some meta data.
+ * @param _metaData a string representing a hash of the meta data
+ * @param _avatar Avatar
+ * @return bool which represents a success
+ */
+ function metaData(string calldata _metaData, Avatar _avatar)
+ external
+ onlyMetaDataScheme
+ isAvatarValid(address(_avatar))
+ returns(bool)
+ {
+ return avatar.metaData(_metaData);
+ }
+
+ /**
+ * @dev getNativeReputation
+ * @param _avatar the organization avatar.
+ * @return organization native reputation
+ */
+ function getNativeReputation(address _avatar) external isAvatarValid(_avatar) view returns(address) {
+ return address(nativeReputation);
+ }
+
+ function isSchemeRegistered(address _scheme, address _avatar) external isAvatarValid(_avatar) view returns(bool) {
+ return _isSchemeRegistered(_scheme);
+ }
+
+ function getSchemeParameters(address _scheme, address _avatar)
+ external
+ isAvatarValid(_avatar)
+ view
+ returns(bytes32)
+ {
+ return schemes[_scheme].paramsHash;
+ }
+
+ function getSchemePermissions(address _scheme, address _avatar)
+ external
+ isAvatarValid(_avatar)
+ view
+ returns(bytes4)
+ {
+ return schemes[_scheme].permissions;
+ }
+
+ function getGlobalConstraintParameters(address _globalConstraint, address) external view returns(bytes32) {
+
+ GlobalConstraintRegister memory register = globalConstraintsRegisterPre[_globalConstraint];
+
+ if (register.isRegistered) {
+ return globalConstraintsPre[register.index].params;
+ }
+
+ register = globalConstraintsRegisterPost[_globalConstraint];
+
+ Eif (register.isRegistered) {
+ return globalConstraintsPost[register.index].params;
+ }
+ }
+
+ /**
+ * @dev globalConstraintsCount return the global constraint pre and post count
+ * @return uint256 globalConstraintsPre count.
+ * @return uint256 globalConstraintsPost count.
+ */
+ function globalConstraintsCount(address _avatar)
+ external
+ isAvatarValid(_avatar)
+ view
+ returns(uint, uint)
+ {
+ return (globalConstraintsPre.length, globalConstraintsPost.length);
+ }
+
+ function isGlobalConstraintRegistered(address _globalConstraint, address _avatar)
+ external
+ isAvatarValid(_avatar)
+ view
+ returns(bool)
+ {
+ return (globalConstraintsRegisterPre[_globalConstraint].isRegistered ||
+ globalConstraintsRegisterPost[_globalConstraint].isRegistered);
+ }
+
+ function _isSchemeRegistered(address _scheme) private view returns(bool) {
+ return (schemes[_scheme].permissions&bytes4(0x00000001) != bytes4(0));
+ }
+}
+ |
| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 | + + + + + + + + + + + + + + + + + + + + + + + + + + + +371× +371× +371× + + + + + + + + +462× +4× +460× +460× + + + | pragma solidity 0.5.17;
+
+import "openzeppelin-solidity/contracts/token/ERC20/ERC20Burnable.sol";
+import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
+import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
+
+
+/**
+ * @title DAOToken, base on zeppelin contract.
+ * @dev ERC20 compatible token. It is a mintable, burnable token.
+ */
+
+contract DAOToken is ERC20, ERC20Burnable, Ownable {
+
+ string public name;
+ string public symbol;
+ // solhint-disable-next-line const-name-snakecase
+ uint8 public constant decimals = 18;
+ uint256 public cap;
+
+ /**
+ * @dev Constructor
+ * @param _name - token name
+ * @param _symbol - token symbol
+ * @param _cap - token cap - 0 value means no cap
+ */
+ constructor(string memory _name, string memory _symbol, uint256 _cap)
+ public {
+ name = _name;
+ symbol = _symbol;
+ cap = _cap;
+ }
+
+ /**
+ * @dev Function to mint tokens
+ * @param _to The address that will receive the minted tokens.
+ * @param _amount The amount of tokens to mint.
+ */
+ function mint(address _to, uint256 _amount) public onlyOwner returns (bool) {
+ if (cap > 0)
+ require(totalSupply().add(_amount) <= cap);
+ _mint(_to, _amount);
+ return true;
+ }
+}
+ |
| File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
|---|---|---|---|---|---|---|---|---|---|
| Avatar.sol | +100% | +20/20 | +100% | +0/0 | +100% | +8/8 | +100% | +20/20 | +|
| Controller.sol | +99.07% | +107/108 | +73.53% | +50/68 | +96.97% | +32/33 | +99.18% | +121/122 | +|
| DAOToken.sol | +100% | +7/7 | +100% | +4/4 | +100% | +2/2 | +100% | +7/7 | +
| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 | + + + + + + + + + + + + + + + | pragma solidity 0.5.17;
+
+
+contract GlobalConstraintInterface {
+
+ enum CallPhase { Pre, Post, PreAndPost }
+
+ function pre( address _scheme, bytes32 _params, bytes32 _method ) public returns(bool);
+ function post( address _scheme, bytes32 _params, bytes32 _method ) public returns(bool);
+ /**
+ * @dev when return if this globalConstraints is pre, post or both.
+ * @return CallPhase enum indication Pre, Post or PreAndPost.
+ */
+ function when() public returns(CallPhase);
+}
+ |
| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 | + + + + + + + + + + + + + + + + + + + + + + + + + + + +4× +4× +4× +4× + + + + + + + + + +8× + + + + + + + + +1× + + + + + + + + +7× + +3× + +4× + + + + + + + +1× + + + | pragma solidity 0.5.17;
+
+import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
+import "./GlobalConstraintInterface.sol";
+
+
+/**
+ * @title Token Cap Global Constraint
+ * @dev A simple global constraint to cap the number of tokens.
+ */
+
+contract TokenCapGC {
+ // A set of parameters, on which the cap will be checked:
+ struct Parameters {
+ IERC20 token;
+ uint256 cap;
+ }
+
+ // Mapping from the hash of the parameters to the parameters themselves:
+ mapping (bytes32=>Parameters) public parameters;
+
+ /**
+ * @dev adding a new set of parameters
+ * @param _token the token to add to the params.
+ * @param _cap the cap to check the total supply against.
+ * @return the calculated parameters hash
+ */
+ function setParameters(IERC20 _token, uint256 _cap) public returns(bytes32) {
+ bytes32 paramsHash = getParametersHash(_token, _cap);
+ parameters[paramsHash].token = _token;
+ parameters[paramsHash].cap = _cap;
+ return paramsHash;
+ }
+
+ /**
+ * @dev calculate and returns the hash of the given parameters
+ * @param _token the token to add to the params.
+ * @param _cap the cap to check the total supply against.
+ * @return the calculated parameters hash
+ */
+ function getParametersHash(IERC20 _token, uint256 _cap) public pure returns(bytes32) {
+ return (keccak256(abi.encodePacked(_token, _cap)));
+ }
+
+ /**
+ * @dev check the constraint after the action.
+ * This global constraint only checks the state after the action, so here we just return true:
+ * @return true
+ */
+ function pre(address, bytes32, bytes32) public pure returns(bool) {
+ return true;
+ }
+
+ /**
+ * @dev check the total supply cap.
+ * @param _paramsHash the parameters hash to check the total supply cap against.
+ * @return bool which represents a success
+ */
+ function post(address, bytes32 _paramsHash, bytes32) public view returns(bool) {
+ if ((parameters[_paramsHash].token != IERC20(0)) &&
+ (parameters[_paramsHash].token.totalSupply() > parameters[_paramsHash].cap)) {
+ return false;
+ }
+ 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.Post;
+ }
+}
+ |
| File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
|---|---|---|---|---|---|---|---|---|---|
| GlobalConstraintInterface.sol | +100% | +0/0 | +100% | +0/0 | +100% | +0/0 | +100% | +0/0 | +|
| TokenCapGC.sol | +100% | +10/10 | +100% | +2/2 | +100% | +5/5 | +100% | +10/10 | +
| File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
|---|---|---|---|---|---|---|---|---|---|
| controller/ | +99.26% | +134/135 | +75% | +54/72 | +97.67% | +42/43 | +99.33% | +148/149 | +|
| globalConstraints/ | +100% | +10/10 | +100% | +2/2 | +100% | +5/5 | +100% | +10/10 | +|
| libs/ | +100% | +13/13 | +50% | +10/20 | +100% | +3/3 | +100% | +13/13 | +|
| schemes/ | +99.07% | +638/644 | +76.55% | +346/452 | +97.85% | +91/93 | +99.08% | +645/651 | +|
| universalSchemes/ | +100% | +301/301 | +75% | +123/164 | +100% | +45/45 | +100% | +305/305 | +|
| utils/ | +94.29% | +66/70 | +72.5% | +29/40 | +100% | +14/14 | +94.44% | +68/72 | +|
| votingMachines/ | +76% | +19/25 | +57.14% | +8/14 | +100% | +7/7 | +76.92% | +20/26 | +
| 1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + +45× + +45× + + + +45× + +45× + + + + + +70× + +70× + + + +70× + +70× + + + + + +7× + + + +7× + +7× + + + +7× + +7× + + + | /*
+
+SafeERC20 by daostack.
+The code is based on a fix by SECBIT Team.
+
+USE WITH CAUTION & NO WARRANTY
+
+REFERENCE & RELATED READING
+- https://github.com/ethereum/solidity/issues/4116
+- https://medium.com/@chris_77367/explaining-unexpected-reverts-starting-with-solidity-0-4-22-3ada6e82308c
+- https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca
+- https://gist.github.com/BrendanChou/88a2eeb80947ff00bcf58ffdafeaeb61
+
+*/
+pragma solidity 0.5.17;
+
+import "openzeppelin-solidity/contracts/utils/Address.sol";
+import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
+
+library SafeERC20 {
+ using Address for address;
+
+ bytes4 constant private TRANSFER_SELECTOR = bytes4(keccak256(bytes("transfer(address,uint256)")));
+ bytes4 constant private TRANSFERFROM_SELECTOR = bytes4(keccak256(bytes("transferFrom(address,address,uint256)")));
+ bytes4 constant private APPROVE_SELECTOR = bytes4(keccak256(bytes("approve(address,uint256)")));
+
+ function safeTransfer(address _erc20Addr, address _to, uint256 _value) internal {
+
+ // Must be a contract addr first!
+ Erequire(_erc20Addr.isContract());
+
+ (bool success, bytes memory returnValue) =
+ // solhint-disable-next-line avoid-low-level-calls
+ _erc20Addr.call(abi.encodeWithSelector(TRANSFER_SELECTOR, _to, _value));
+ // call return false when something wrong
+ Erequire(success);
+ //check return value
+ Erequire(returnValue.length == 0 || (returnValue.length == 32 && (returnValue[31] != 0)));
+ }
+
+ function safeTransferFrom(address _erc20Addr, address _from, address _to, uint256 _value) internal {
+
+ // Must be a contract addr first!
+ Erequire(_erc20Addr.isContract());
+
+ (bool success, bytes memory returnValue) =
+ // solhint-disable-next-line avoid-low-level-calls
+ _erc20Addr.call(abi.encodeWithSelector(TRANSFERFROM_SELECTOR, _from, _to, _value));
+ // call return false when something wrong
+ Erequire(success);
+ //check return value
+ Erequire(returnValue.length == 0 || (returnValue.length == 32 && (returnValue[31] != 0)));
+ }
+
+ function safeApprove(address _erc20Addr, address _spender, uint256 _value) internal {
+
+ // Must be a contract addr first!
+ Erequire(_erc20Addr.isContract());
+
+ // safeApprove should only be called when setting an initial allowance,
+ // or when resetting it to zero.
+ Erequire((_value == 0) || (IERC20(_erc20Addr).allowance(address(this), _spender) == 0));
+
+ (bool success, bytes memory returnValue) =
+ // solhint-disable-next-line avoid-low-level-calls
+ _erc20Addr.call(abi.encodeWithSelector(APPROVE_SELECTOR, _spender, _value));
+ // call return false when something wrong
+ Erequire(success);
+ //check return value
+ Erequire(returnValue.length == 0 || (returnValue.length == 32 && (returnValue[31] != 0)));
+ }
+}
+ |
| File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
|---|---|---|---|---|---|---|---|---|---|
| SafeERC20.sol | +100% | +13/13 | +50% | +10/20 | +100% | +3/3 | +100% | +13/13 | +