diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 22a0fd66f56e3359fd1f45ff55e57d752fa269ce..402d830390bd6d7293b864e5563ec8c19ebb082d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -38,16 +38,14 @@ push_to_github:
     - pyenv shell $PYENV_PYTHON_VERSION
 
 .changes: &changes
-  except:
+  only:
     changes:
-      - CHANGELOG.md
-      - ci/*
-      - config
-      - docs
-      - LICENSE*
-      - Makefile
-      - README*
-      - release.sh
+      - duniterpy/**/*.py
+      - .gitlab-ci.yml
+      - requirements_dev.txt
+      - requirements.txt
+      - setup.py
+      - tests/**/*.py
 
 build: &build
   <<: *pyenv
diff --git a/duniterpy/documents/transaction.py b/duniterpy/documents/transaction.py
index 8f8ea6dada456208457896fb5aca3e3bc4a15c57..5545d16b7994dd597ced99a4c6dbaaeefd9bb01c 100644
--- a/duniterpy/documents/transaction.py
+++ b/duniterpy/documents/transaction.py
@@ -486,8 +486,7 @@ class Transaction(Document):
         tx_data["currency"] = currency
         for data_list in ('issuers', 'outputs', 'inputs', 'unlocks', 'signatures'):
             tx_data['multiline_{0}'.format(data_list)] = '\n'.join(tx_data[data_list])
-        if tx_data["version"] >= 3:
-            signed_raw = """Version: {version}
+        return cls.from_signed_raw("""Version: {version}
 Type: Transaction
 Currency: {currency}
 Blockstamp: {blockstamp}
@@ -502,24 +501,7 @@ Outputs:
 {multiline_outputs}
 Comment: {comment}
 {multiline_signatures}
-""".format(**tx_data)
-        else:
-            signed_raw = """Version: {version}
-Type: Transaction
-Currency: {currency}
-Locktime: {locktime}
-Issuers:
-{multiline_issuers}
-Inputs:
-{multiline_inputs}
-Unlocks:
-{multiline_unlocks}
-Outputs:
-{multiline_outputs}
-Comment: {comment}
-{multiline_signatures}
-""".format(**tx_data)
-        return cls.from_signed_raw(signed_raw)
+""".format(**tx_data))
 
     @classmethod
     def from_compact(cls: Type[TransactionType], currency: str, compact: str) -> TransactionType:
@@ -613,10 +595,8 @@ Comment: {comment}
         currency = Transaction.parse_field("Currency", lines[n])
         n += 1
 
-        blockstamp = None  # type: Optional[BlockUID]
-        if version >= 3:
-            blockstamp = BlockUID.from_str(Transaction.parse_field("Blockstamp", lines[n]))
-            n += 1
+        blockstamp = BlockUID.from_str(Transaction.parse_field("Blockstamp", lines[n]))
+        n += 1
 
         locktime = Transaction.parse_field("Locktime", lines[n])
         n += 1
@@ -679,8 +659,7 @@ Currency: {1}
 """.format(self.version,
            self.currency)
 
-        if self.version >= 3:
-            doc += "Blockstamp: {0}\n".format(self.blockstamp)
+        doc += "Blockstamp: {0}\n".format(self.blockstamp)
 
         doc += "Locktime: {0}\n".format(self.locktime)
 
@@ -727,8 +706,7 @@ COMMENT
                                                         len(self.outputs),
                                                         '1' if self.comment != "" else '0',
                                                         self.locktime)
-        if self.version >= 3:
-            doc += "{0}\n".format(self.blockstamp)
+        doc += "{0}\n".format(self.blockstamp)
 
         for pubkey in self.issuers:
             doc += "{0}\n".format(pubkey)
diff --git a/duniterpy/grammars/output.py b/duniterpy/grammars/output.py
index f3e4225b6b1e3d46c5a26e6093f6eea6cd2f29b9..c180f5307e809cd96d8833cc0078245c64180715 100644
--- a/duniterpy/grammars/output.py
+++ b/duniterpy/grammars/output.py
@@ -32,7 +32,7 @@ SIGType = TypeVar('SIGType', bound='SIG')
 
 class SIG:
     """
-    Signature function in transaction output condition
+    SIGnature function in transaction output condition
     """
     grammar = "SIG(", attr('pubkey', Pubkey), ")"
 
@@ -60,7 +60,7 @@ class SIG:
         sig.pubkey = pubkey
         return sig
 
-    def compose(self, parser: Any, grammar: Any = None, attr_of: Any = None) -> str:
+    def compose(self, parser: Any = None, grammar: Any = None, attr_of: Any = None) -> str:
         """
         Return the SIG(pubkey) expression as string format
 
@@ -106,7 +106,7 @@ class CSV:
         csv.time = str(time)
         return csv
 
-    def compose(self, parser: Any, grammar: Any = None, attr_of: str = None):
+    def compose(self, parser: Any = None, grammar: Any = None, attr_of: str = None):
         """
         Return the CSV(time) expression as string format
 
@@ -151,7 +151,7 @@ class CLTV:
         cltv.timestamp = str(timestamp)
         return cltv
 
-    def compose(self, parser: Any, grammar: Any = None, attr_of: str = None):
+    def compose(self, parser: Any = None, grammar: Any = None, attr_of: str = None):
         """
         Return the CLTV(timestamp) expression as string format
 
@@ -196,7 +196,7 @@ class XHX:
         xhx.sha_hash = sha_hash
         return xhx
 
-    def compose(self, parser: Any, grammar: Any = None, attr_of: str = None) -> str:
+    def compose(self, parser: Any = None, grammar: Any = None, attr_of: str = None) -> str:
         """
         Return the XHX(sha_hash) expression as string format
 
@@ -229,7 +229,7 @@ class Operator(Keyword):
         op = cls(keyword)
         return op
 
-    def compose(self, parser: Any, grammar: Any = None, attr_of: str = None) -> str:
+    def compose(self, parser: Any = None, grammar: Any = None, attr_of: str = None) -> str:
         """
         Return the Operator keyword as string format
 
diff --git a/tests/grammars/test_output.py b/tests/grammars/test_output.py
index 2e6a6cee72058b5a8be8271e457249799ea35334..3ef0557707b61b109a0b2994466996cf96cf054f 100644
--- a/tests/grammars/test_output.py
+++ b/tests/grammars/test_output.py
@@ -2,92 +2,109 @@ import unittest
 
 import pypeg2
 
-from duniterpy.grammars import output
+from duniterpy.grammars.output import SIG, CLTV, CSV, XHX, Operator, Condition
 
+pubkey = "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"
 
 class TestOutputgrammar(unittest.TestCase):
     def test_sig(self):
         condition = "SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd)"
-        result = pypeg2.parse(condition, output.SIG)
+        result = pypeg2.parse(condition, SIG)
         self.assertEqual(result.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
-        self.assertEqual(pypeg2.compose(result, output.Condition), condition)
+        self.assertEqual(pypeg2.compose(result, Condition), condition)
 
     def test_xhx(self):
         condition = "XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)"
-        result = pypeg2.parse(condition, output.XHX)
+        result = pypeg2.parse(condition, XHX)
         self.assertEqual(result.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6")
 
     def test_sig_condition(self):
         condition = "SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd)"
-        result = pypeg2.parse(condition, output.Condition)
+        result = pypeg2.parse(condition, Condition)
         self.assertEqual(result.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
-        self.assertEqual(pypeg2.compose(result, output.Condition), condition)
+        self.assertEqual(pypeg2.compose(result, Condition), condition)
 
     def test_xhr_condition(self):
         condition = "SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd)"
-        result = pypeg2.parse(condition, output.Condition)
+        result = pypeg2.parse(condition, Condition)
         self.assertEqual(result.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
-        self.assertEqual(pypeg2.compose(result, output.Condition), condition)
+        self.assertEqual(pypeg2.compose(result, Condition), condition)
 
     def test_simple_condition(self):
         condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd))"
-        result = pypeg2.parse(condition, output.Condition)
+        result = pypeg2.parse(condition, Condition)
         self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
-        self.assertEqual(pypeg2.compose(result, output.Condition), condition)
+        self.assertEqual(pypeg2.compose(result, Condition), condition)
 
     def test_simple_and_condition(self):
         condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) && XHX(" \
                     "309BC5E644F797F53E5A2065EAF38A173437F2E6))"
-        result = pypeg2.parse(condition, output.Condition)
+        result = pypeg2.parse(condition, Condition)
         self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
         self.assertEqual(result.left.op.name, "&&")
         self.assertEqual(result.left.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6")
-        self.assertEqual(pypeg2.compose(result, output.Condition), condition)
+        self.assertEqual(pypeg2.compose(result, Condition), condition)
 
     def test_simple_or_condition(self):
         condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || XHX(" \
                     "309BC5E644F797F53E5A2065EAF38A173437F2E6))"
-        result = pypeg2.parse(condition, output.Condition)
+        result = pypeg2.parse(condition, Condition)
         self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
         self.assertEqual(result.left.op.name, "||")
         self.assertEqual(result.left.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6")
-        self.assertEqual(pypeg2.compose(result, output.Condition), condition)
+        self.assertEqual(pypeg2.compose(result, Condition), condition)
 
     def test_complex_condition(self):
         condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(" \
                     "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))"
-        result = pypeg2.parse(condition, output.Condition)
+        result = pypeg2.parse(condition, Condition)
         self.assertEqual(result.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
         self.assertEqual(result.left.op.name, "||")
         self.assertEqual(result.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
         self.assertEqual(result.left.right.op.name, "&&")
         self.assertEqual(result.left.right.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6")
-        self.assertEqual(pypeg2.compose(result, output.Condition), condition)
+        self.assertEqual(pypeg2.compose(result, Condition), condition)
 
     def test_csv_cltv_condition(self):
         condition = "(CSV(1654300) || (SIG(DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && CLTV(2594024)))"
-        result = pypeg2.parse(condition, output.Condition)
+        result = pypeg2.parse(condition, Condition)
         self.assertEqual(result.left.left.time, "1654300")
         self.assertEqual(result.left.op.name, "||")
         self.assertEqual(result.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
         self.assertEqual(result.left.right.op.name, "&&")
         self.assertEqual(result.left.right.right.timestamp, "2594024")
-        self.assertEqual(pypeg2.compose(result, output.Condition), condition)
+        self.assertEqual(pypeg2.compose(result, Condition), condition)
 
     def test_instanciate_condition(self):
-        output.Condition.token(output.SIG.token("HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd"),
-                               output.Operator.token("||"),
-                               output.Condition.token(
-                                   output.SIG.token("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"),
-                                   output.Operator.token("&&"),
-                                   output.XHX.token("309BC5E644F797F53E5A2065EAF38A173437F2E6")
+        Condition.token(SIG.token("HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd"),
+                               Operator.token("||"),
+                               Condition.token(
+                                   SIG.token("DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV"),
+                                   Operator.token("&&"),
+                                   XHX.token("309BC5E644F797F53E5A2065EAF38A173437F2E6")
                                ))
         condition = "(SIG(HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd) || (SIG(" \
                     "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV) && XHX(309BC5E644F797F53E5A2065EAF38A173437F2E6)))"
-        inst = pypeg2.parse(condition, output.Condition)
+        inst = pypeg2.parse(condition, Condition)
         self.assertEqual(inst.left.left.pubkey, "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd")
         self.assertEqual(inst.left.op.name, "||")
         self.assertEqual(inst.left.right.left.pubkey, "DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV")
         self.assertEqual(inst.left.right.op.name, "&&")
         self.assertEqual(inst.left.right.right.sha_hash, "309BC5E644F797F53E5A2065EAF38A173437F2E6")
-        self.assertEqual(pypeg2.compose(inst, output.Condition), condition)
+        self.assertEqual(pypeg2.compose(inst, Condition), condition)
+
+
+    def test_SIG_token_and_compose(self):
+        self.assertEqual(SIG.token(pubkey).compose(), "SIG(" + pubkey + ")")
+
+
+    def test_CSV_token_and_compose(self):
+        self.assertEqual(CSV.token(pubkey).compose(), "CSV(" + pubkey + ")")
+
+
+    def test_CLTV_token_and_compose(self):
+        self.assertEqual(CLTV.token(pubkey).compose(), "CLTV(" + pubkey + ")")
+
+
+    def test_HXH_token_and_compose(self):
+        self.assertEqual(XHX.token(pubkey).compose(), "XHX(" + pubkey + ")")