Repository: vyperlang/vyper

Issue:
Event parameter doesn't support unit type
### What's your issue about?

```
MyLog: __log__({arg1: indexed(num(wei))})
```
is a valid event declaration, but
```
 MyLog: __log__({arg1: num(wei)})
```
is not. It seems that the compiler confuses indexed topic with unit type.

### How can it be fixed?

In `event_signature.py`, add logic to differentiate topic declaration and unit type.

#### Cute Animal Picture

![image](https://user-images.githubusercontent.com/5641590/33356963-2e5cde12-d485-11e7-9ebf-503193a56523.png)




Discussion:
On it, thanks for the bug report :)

Resolving patch:
diff --git a/viper/signatures/event_signature.py b/viper/signatures/event_signature.py
--- a/viper/signatures/event_signature.py
+++ b/viper/signatures/event_signature.py
@@ -30,18 +30,15 @@ def from_declaration(cls, code):
             for i in range(len(keys)):
                 typ = values[i]
                 arg = keys[i].id
-                if isinstance(typ, ast.Call):
-                    # Check to see if argument is a topic
-                    if typ.func.id == 'indexed':
-                        typ = values[i].args[0]
-                        indexed_list.append(True)
-                        topics_count += 1
-                    else:
-                        raise VariableDeclarationException("Only indexed keyword is allowed", arg)
+                # Check to see if argument is a topic
+                if isinstance(typ, ast.Call) and typ.func.id == 'indexed':
+                    typ = values[i].args[0]
+                    indexed_list.append(True)
+                    topics_count += 1
                 else:
-                    if hasattr(typ, 'left') and typ.left.id == 'bytes' and typ.comparators[0].n > 32:
-                        raise VariableDeclarationException("Can only log a maximum of 32 bytes at a time.")
                     indexed_list.append(False)
+                if hasattr(typ, 'left') and typ.left.id == 'bytes' and typ.comparators[0].n > 32:
+                    raise VariableDeclarationException("Can only log a maximum of 32 bytes at a time.")
                 if topics_count > 4:
                     raise VariableDeclarationException("Maximum of 3 topics {} given".format(topics_count - 1), arg)
                 if not isinstance(arg, str):
diff --git a/viper/types.py b/viper/types.py
--- a/viper/types.py
+++ b/viper/types.py
@@ -262,7 +262,8 @@ def parse_type(item, location, sigs={}):
             raise InvalidTypeException("Malformed unit type:", item)
         base_type = item.func.id
         if base_type not in ('num', 'decimal'):
-            raise InvalidTypeException("Base type with units can only be num, decimal", item)
+            raise InvalidTypeException("You must use num, decimal, address, contract, \
+                for variable declarations and indexed for logging topics ", item)
         if len(item.args) == 0:
             raise InvalidTypeException("Malformed unit type", item)
         if isinstance(item.args[-1], ast.Name) and item.args[-1].id == "positional":
diff --git a/viper/utils.py b/viper/utils.py
--- a/viper/utils.py
+++ b/viper/utils.py
@@ -113,6 +113,9 @@ class SizeLimits:
 # Available base types
 base_types = ['num', 'decimal', 'bytes32', 'num256', 'signed256', 'bool', 'address']
 
+# Keywords available for ast.Call type
+valid_call_keywords = ['num', 'decimal', 'address', 'contract', 'indexed']
+
 # Valid base units
 valid_units = ['currency', 'wei', 'currency1', 'currency2', 'sec', 'm', 'kg']
 


Test patch:
diff --git a/tests/parser/features/test_logging.py b/tests/parser/features/test_logging.py
--- a/tests/parser/features/test_logging.py
+++ b/tests/parser/features/test_logging.py
@@ -131,6 +131,16 @@ def foo():
     assert c.translator.decode_event(logs.topics, logs.data) == {'arg1': 123, '_event_type': b'MyLog'}
 
 
+def test_event_logging_with_units(get_contract_with_gas_estimation, chain, utils):
+    code = """
+MyLog: __log__({arg1: indexed(num(wei)), arg2: num(wei)})
+
+@public
+def foo():
+    log.MyLog(1, 2)
+"""
+    get_contract_with_gas_estimation(code)
+
 def test_event_loggging_with_fixed_array_data(get_contract_with_gas_estimation, chain, utils):
     loggy_code = """
 MyLog: __log__({arg1: num[2], arg2: timestamp[3], arg3: num[2][2]})
@@ -640,3 +650,21 @@ def set_list():
     c.set_list()
     c.foo()
     assert get_last_log(t, c)["_value"] == [1.33, 2.33, 3.33, 4.33]
+
+
+def test_logging_fails_when_declartation_is_too_big(assert_tx_failed, get_contract_with_gas_estimation):
+    code = """
+Bar: __log__({_value: indexed(bytes <= 33)})
+"""
+    assert_tx_failed(lambda: get_contract_with_gas_estimation(code), VariableDeclarationException)
+
+
+def test_logging_fails_when_input_is_too_big(assert_tx_failed, get_contract_with_gas_estimation):
+    code = """
+Bar: __log__({_value: indexed(bytes <= 32)})
+
+@public
+def foo(inp: bytes <= 33):
+    log.Bar(inp)
+"""
+    assert_tx_failed(lambda: get_contract_with_gas_estimation(code), TypeMismatchException)