diff --git a/.gitignore b/.gitignore index 829ea18..4909c3d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ +build + *.sw* *.DS_Store -admin-gui/node_modules -admin-gui/bower_components -build/__* diff --git a/README.md b/README.md index a4a72d1..5eecf68 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,13 @@ audit](https://github.com/nexusdev/dappsys/blob/master/doc/nexus-review-final-20 Installation --- - npm install dapple - dapple install https://github.com/nexusdev/dappsys + npm install -g dapple + # `dapple install` is not reliable yet + # dapple install dappsys 0.2.0 + git submodule add https://github.com/nexusdev/dappsys dapple_packages/dappsys -How to ---- -0.1.* Contracts +0.2.0 Contracts --- ### `auth`: diff --git a/contracts/actor/base.sol b/contracts/actor/base.sol index 40deef1..6b6b322 100644 --- a/contracts/actor/base.sol +++ b/contracts/actor/base.sol @@ -1,2 +1,20 @@ -// Filename alias. -import 'actor/base_actor.sol'; +// A base contract mostly used by governance contracts in `gov`. +// For now, this just means the multisig contract, but it could +// be used for stake-vote or futarchy. +contract DSBaseActor { + // return result of `call` keyword + function tryExec( address target, bytes calldata, uint value) + internal + returns (bool call_ret) + { + return target.call.value(value)(calldata); + } + function exec( address target, bytes calldata, uint value) + internal + { + if(!tryExec(target, calldata, value)) { + throw; + } + } +} + diff --git a/contracts/actor/base_actor.sol b/contracts/actor/base_actor.sol deleted file mode 100644 index 6b6b322..0000000 --- a/contracts/actor/base_actor.sol +++ /dev/null @@ -1,20 +0,0 @@ -// A base contract mostly used by governance contracts in `gov`. -// For now, this just means the multisig contract, but it could -// be used for stake-vote or futarchy. -contract DSBaseActor { - // return result of `call` keyword - function tryExec( address target, bytes calldata, uint value) - internal - returns (bool call_ret) - { - return target.call.value(value)(calldata); - } - function exec( address target, bytes calldata, uint value) - internal - { - if(!tryExec(target, calldata, value)) { - throw; - } - } -} - diff --git a/contracts/actor/base_actor_test.sol b/contracts/actor/base_test.sol similarity index 98% rename from contracts/actor/base_actor_test.sol rename to contracts/actor/base_test.sol index 4bdb620..1c9d139 100644 --- a/contracts/actor/base_actor_test.sol +++ b/contracts/actor/base_test.sol @@ -1,4 +1,4 @@ -import 'actor/base_actor.sol'; +import 'actor/base.sol'; import 'dapple/test.sol'; import 'dapple/debug.sol'; diff --git a/contracts/auth/enum_test.sol b/contracts/auth/enum_test.sol new file mode 100644 index 0000000..9409d18 --- /dev/null +++ b/contracts/auth/enum_test.sol @@ -0,0 +1,11 @@ +import 'dapple/test.sol'; +import 'auth/enum.sol'; + +contract AuthEnumValuesTest is Test, DSAuthModesEnum { + function setUp() {} + // TODO how to test they are still the same ABI type? + function testValues() { + assertEq( 0, uint(DSAuthModes.Owner) ); + assertEq( 1, uint(DSAuthModes.Authority) ); + } +} diff --git a/contracts/data.sol b/contracts/data.sol new file mode 100644 index 0000000..8797793 --- /dev/null +++ b/contracts/data.sol @@ -0,0 +1,5 @@ +import 'data/approval_db.sol'; +import 'data/balance_db.sol'; + +import 'data/map.sol'; +import 'data/nullmap.sol'; diff --git a/contracts/data/balance_db.sol b/contracts/data/balance_db.sol index b6560b9..f223a20 100644 --- a/contracts/data/balance_db.sol +++ b/contracts/data/balance_db.sol @@ -3,6 +3,8 @@ import 'auth.sol'; import 'util/safety.sol'; +import 'dapple/debug.sol'; + contract DSBalanceDBEvents { event BalanceUpdate( address indexed who, uint new_amount ); } diff --git a/contracts/dev.md b/contracts/dev.md deleted file mode 100644 index 1821b63..0000000 --- a/contracts/dev.md +++ /dev/null @@ -1,2 +0,0 @@ -auth/static_auth -util/ephemeral diff --git a/contracts/factory/data_factory.sol b/contracts/factory/data_factory.sol index 32333fc..c74f63e 100644 --- a/contracts/factory/data_factory.sol +++ b/contracts/factory/data_factory.sol @@ -1,8 +1,5 @@ import 'auth.sol'; -import 'data/balance_db.sol'; -import 'data/approval_db.sol'; -import 'data/nullmap.sol'; -import 'data/map.sol'; +import 'data.sol'; contract DSDataFactory is DSAuthUser { function buildDSBalanceDB() returns (DSBalanceDB ret) { diff --git a/contracts/factory/factory.sol b/contracts/factory/factory.sol index 76d4902..27bd786 100644 --- a/contracts/factory/factory.sol +++ b/contracts/factory/factory.sol @@ -1,14 +1,13 @@ import 'auth.sol'; import 'auth/basic_authority.sol'; -import 'data/balance_db.sol'; -import 'data/approval_db.sol'; + import 'gov/easy_multisig.sol'; import 'token/base.sol'; import 'token/controller.sol'; import 'token/frontend.sol'; -import 'factory/auth_factory.sol'; import 'factory/data_factory.sol'; +import 'factory/auth_factory.sol'; import 'factory/token_factory.sol'; import 'factory/multisig_factory.sol'; diff --git a/contracts/factory/token_factory.sol b/contracts/factory/token_factory.sol index dafa1de..26a4c0c 100644 --- a/contracts/factory/token_factory.sol +++ b/contracts/factory/token_factory.sol @@ -1,6 +1,6 @@ import 'auth.sol'; import 'auth/basic_authority.sol'; -import 'data/balance_db.sol'; +import 'data.sol'; import 'factory/data_factory.sol'; import 'factory/auth_factory.sol'; import 'token/controller.sol'; diff --git a/contracts/gov/easy_multisig.sol b/contracts/gov/easy_multisig.sol index a8ea2d0..6ff036b 100644 --- a/contracts/gov/easy_multisig.sol +++ b/contracts/gov/easy_multisig.sol @@ -102,10 +102,10 @@ contract DSEasyMultisig is DSBaseActor // Public getter for the action mapping doesn't work in web3.js yet function getActionStatus(uint action_id) constant - returns (uint confirmations, uint expiration, bool triggered) + returns (uint confirmations, uint expiration, bool triggered, address target, uint eth_value) { var a = actions[action_id]; - return (a.confirmations, a.expiration, a.triggered); + return (a.confirmations, a.expiration, a.triggered, a.target, a.value); } // `propose` an action using the calldata from this sender's last call. diff --git a/contracts/gov/easy_multisig_test.sol b/contracts/gov/easy_multisig_test.sol index 3272128..107b88e 100644 --- a/contracts/gov/easy_multisig_test.sol +++ b/contracts/gov/easy_multisig_test.sol @@ -96,11 +96,14 @@ contract DSEasyMultisigTest is Test, DSEasyMultisigEvents var (r, m, e, id) = ms.getInfo(); assertEq( id, 1, "wrong last action id"); uint c; bool t; - (c, e, t) = ms.getActionStatus(1); + address target; uint value; + (c, e, t, target, value) = ms.getActionStatus(1); assertTrue( c == 0, "wrong number of confirmations" ); + assertEq( target, address(h) ); + assertEq( value, 0 ); ms.confirm(1); DSEasyMultisig(t1).confirm(1); - (c, e, t) = ms.getActionStatus(1); + (c, e, t, target, value) = ms.getActionStatus(1); assertTrue( c == 2, "wrong number of confirmations" ); DSEasyMultisig(t1).trigger(1); assertEq( h._arg(), 1, "wrong last arg" ); diff --git a/contracts/lang/fallback_tests.sol b/contracts/lang/fallback_tests.sol new file mode 100644 index 0000000..4d76095 --- /dev/null +++ b/contracts/lang/fallback_tests.sol @@ -0,0 +1,73 @@ +// Some tests to verify behavior of fallbacks and rsult of calling addresses with unexpected types +// TODO demonstrate that garbage is not always calldata (except when calling no-code addresses) +import 'dapple/test.sol'; + +contract ThrowingFallback { + function() { + throw; + } +} + +contract UndefinedFunction { + function undefinedFunction() returns (bytes32); + function undefinedFunction2() returns (bytes32); +} + +contract TypedFallback { + function() returns (bytes32) { + return 0x42; + // same as "return bytes32(0x0);" + } +} + +contract UntypedFallback { + function() { + // same as "return bytes32(0x0);" + } +} + + +contract UndefinedFallback { + function iHaveCode() returns (bytes32) { + return "aaaaa"; + } +} + + +contract FallbackTest is Test { + ThrowingFallback throwing; + TypedFallback typed; + UntypedFallback untyped; + UndefinedFallback undefined; + address noCode; + function setUp() { + throwing = new ThrowingFallback(); + typed = new TypedFallback(); + untyped = new UntypedFallback(); + undefined = new UndefinedFallback(); + noCode = address(0x42); + } + function testFailThrowingFallback() { + UndefinedFunction(throwing).undefinedFunction(); + } + function testTypedFallbackReturnsFalse() { + var ret = UndefinedFunction(typed).undefinedFunction(); + assertEq32(ret, 0x42); + } + function testUntypedFallbackReturnsGarbage() { + var ret = UndefinedFunction(undefined).undefinedFunction(); + assertTrue( ret != bytes32(0), "ret is 0 by coincidence" ); + log_named_bytes32("garbage", ret); + } + function testUndefinedFallbackReturnsGarbage() { + var ret = UndefinedFunction(undefined).undefinedFunction(); + assertTrue( ret != bytes32(0), "ret is 0 by coincidence" ); + log_named_bytes32("garbage", ret); + } + function testNoCodeReturnsGarbage() { + var ret = UndefinedFunction(noCode).undefinedFunction(); + assertTrue( ret != bytes32(0), "ret is 0 by coincidence" ); + log_named_bytes32("garbage", ret); + } + +} diff --git a/contracts/token/base_test.sol b/contracts/token/base_test.sol deleted file mode 100644 index f9d96d8..0000000 --- a/contracts/token/base_test.sol +++ /dev/null @@ -1 +0,0 @@ -// See 'token/token_test.sol' diff --git a/contracts/token/provider.sol b/contracts/token/provider.sol index 8848cd4..16ba64b 100644 --- a/contracts/token/provider.sol +++ b/contracts/token/provider.sol @@ -2,5 +2,6 @@ import 'token/token.sol'; contract DSTokenProvider { function getToken(bytes32 symbol) returns (DSToken); + function tryGetToken(bytes32 symbol) returns (DSToken, bool ok); } diff --git a/contracts/token/registry.sol b/contracts/token/registry.sol index d868284..55d71ce 100644 --- a/contracts/token/registry.sol +++ b/contracts/token/registry.sol @@ -3,8 +3,13 @@ import 'token/provider.sol'; // Simple registry implementing DSTokenProvider contract DSTokenRegistry is DSTokenProvider, DSNullMap { + // throws. function getToken(bytes32 symbol) returns (DSToken) { return DSToken(address(get(symbol))); } + function tryGetToken(bytes32 symbol) returns (DSToken token, bool ok) { + var (_token, _ok) = tryGet(symbol); + return (DSToken(address(_token)), _ok); + } } diff --git a/contracts/token/registry_test.sol b/contracts/token/registry_test.sol index c7bd7c0..041ea0b 100644 --- a/contracts/token/registry_test.sol +++ b/contracts/token/registry_test.sol @@ -18,9 +18,17 @@ contract TokenRegistryTest is Test { registry.set(tokenName, bytes32(address(token))); assertEq(registry.getToken(tokenName), token); } - function testFailGetUnsetToken() { bytes32 tokenName = "Kanye Coin"; assertEq(registry.getToken(tokenName), token); } + function testTryGetToken() { + bytes32 tokenName = "Kanye Coin"; + registry.set(tokenName, bytes32(address(token))); + var (_token, ok) = registry.tryGetToken(tokenName); + assertTrue(ok); + assertEq(token, _token); + (_token, ok) = registry.tryGetToken("NIL"); + assertFalse(ok); + } } diff --git a/contracts/token/token_test.sol b/contracts/token/token_test.sol index 1000054..c44f612 100644 --- a/contracts/token/token_test.sol +++ b/contracts/token/token_test.sol @@ -11,6 +11,7 @@ contract DSTokenTester is Tester, Debug { function doTransferFrom(address from, address to, uint amount) returns (bool) { + logs("in doTransferFrom"); return DSToken(_t).transferFrom(from, to, amount); } @@ -71,6 +72,7 @@ contract DSTokenTest is Test, DSAuthUser { function testValidTransfers() logs_gas { uint sentAmount = 250; + log_named_address("token11111", token); token.transfer(user2, sentAmount); assertEq(token.balanceOf(user2), sentAmount); assertEq(token.balanceOf(me), initialBalance - sentAmount); diff --git a/dappfile b/dappfile index e777630..40ca6e9 100644 --- a/dappfile +++ b/dappfile @@ -1,9 +1,13 @@ name: dappsys -version: 0.1.3-dev +version: 0.2.0 layout: sol_sources: contracts build_dir: build -ignore: [] +ignore: + - actor/interpreter.sol + - auth/group_authority.sol + - data/vote_db.sol + - token/hooks/vote_sync.sol environments: morden: objects: