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 | +