diff --git a/doc/uml/tx_lifecycle.png b/doc/uml/tx_lifecycle.png
index d73d828a1511f68a30f4d03bfdd317e0189c0636..e27439cdf29b9dc51156869612b86feef74afc49 100644
Binary files a/doc/uml/tx_lifecycle.png and b/doc/uml/tx_lifecycle.png differ
diff --git a/doc/uml/tx_lifecycle.pu b/doc/uml/tx_lifecycle.pu
index 28405b6461c5fdf3dce93e6da1f807144f739411..bce551415a952a9de828c5c9264c0e320c707112 100644
--- a/doc/uml/tx_lifecycle.pu
+++ b/doc/uml/tx_lifecycle.pu
@@ -1 +1 @@
-@startuml

note "With B a Block\nWith W the Median fork window\nWith Cur the current block of the main branch" as N1
state Local_Tx {
 [*] --> To_send : Signed locally
 To_send : B = none
 To_send --> Awaiting : Node answered\n200 OK to POST
 Awaiting : B = Cur
 Awaiting --> Refused : Not registered in [B; B+W]
 Refused --> To_send : Send back
 Refused --> [*] : Drop
}
state Registered {
 [*] --> Validating : Posted\nsin the blockchain
 Validating : B = Block containing the Tx
 Awaiting --> Validating : Found in the blockchain
 Validating --> Validated : Cur-B > W
 Validated --> Validating : Blockchain\nrollback
 Validated --> Awaiting : Blockchain\nrollback\ntx local removed
 Validated --> [*] : Blockchain\nrollback\ntx removed
 Validating --> [*] : Blockchain\nrollback\ntx removed
}

@enduml
\ No newline at end of file
+@startuml

note "With B a Block\nWith W the Median fork window\nWith Cur the current block of the main branch\nWith T a time" as N1
state Local_Tx {
 [*] --> To_send : Signed locally
 To_send : B = none
 To_send --> Awaiting : Node answered\n200 OK to POST
 Awaiting : Time = Cur.MedianTime
 Awaiting --> Refused : Not registered in [T; T+W*MedianTime]
 Refused --> To_send : Send back
 Refused --> [*] : Drop
}
state Registered {
 [*] --> Validating : Posted\nsin the blockchain
 Validating : B = Block containing the Tx
 Awaiting --> Validating : Found in the blockchain
 Validating --> Validated : Cur-B > W
 Validated --> Validating : Blockchain\nrollback
 Validated --> Awaiting : Blockchain\nrollback\ntx local removed
 Validated --> [*] : Blockchain\nrollback\ntx removed
 Validating --> [*] : Blockchain\nrollback\ntx removed
}

@enduml
\ No newline at end of file
diff --git a/lib/ucoinpy/documents/__init__.py b/lib/ucoinpy/documents/__init__.py
index 9763c366155f445dd55be9022f8d2cacf381036a..2291e35a028452620bc12c2101ee2fd5a4bb8220 100644
--- a/lib/ucoinpy/documents/__init__.py
+++ b/lib/ucoinpy/documents/__init__.py
@@ -1,44 +1,7 @@
-"""
-Created on 3 déc. 2014
-
-@author: inso
-"""
-import base58
-import base64
-import re
-import logging
-from ..key import Base58Encoder
-
-class Document:
-    re_version = re.compile("Version: ([0-9]+)\n")
-    re_currency = re.compile("Currency: ([^\n]+)\n")
-    re_signature = re.compile("([A-Za-z0-9+/]+(?:=|==)?)\n")
-
-    def __init__(self, version, currency, signatures):
-        self.version = version
-        self.currency = currency
-        if signatures:
-            self.signatures = [s for s in signatures if s is not None]
-        else:
-            self.signatures = []
-
-    def sign(self, keys):
-        """
-        Sign the current document.
-        Warning : current signatures will be replaced with the new ones.
-        """
-        self.signatures = []
-        for key in keys:
-            signing = base64.b64encode(key.signature(bytes(self.raw(), 'ascii')))
-            logging.debug("Signature : \n{0}".format(signing.decode("ascii")))
-            self.signatures.append(signing.decode("ascii"))
-
-    def signed_raw(self):
-        """
-        If keys are None, returns the raw + current signatures
-        If keys are present, returns the raw signed by these keys
-        """
-        raw = self.raw()
-        signed = "\n".join(self.signatures)
-        signed_raw = raw + signed + "\n"
-        return signed_raw
+from .block import Block, BlockId
+from .certification import SelfCertification, Certification
+from .membership import Membership
+from .peer import Endpoint, BMAEndpoint, UnknownEndpoint, Peer
+from .status import Status
+from .transaction import SimpleTransaction, Transaction
+from .document import Document
\ No newline at end of file
diff --git a/lib/ucoinpy/documents/block.py b/lib/ucoinpy/documents/block.py
index 00ce0f779ce1fc9cef56a5f5b41ecabedf6bd2bd..81fafccca05300252fe4c2edeb54d7a5fca262e7 100644
--- a/lib/ucoinpy/documents/block.py
+++ b/lib/ucoinpy/documents/block.py
@@ -5,7 +5,7 @@ Created on 2 déc. 2014
 """
 
 from .. import PROTOCOL_VERSION
-from . import Document
+from .document import Document
 from .certification import SelfCertification, Certification
 from .membership import Membership
 from .transaction import Transaction
@@ -14,6 +14,36 @@ import re
 import logging
 
 
+class BlockId:
+    """
+    A simple block id
+    """
+    re_hash = re.compile("([0-9a-fA-F]{5,40})")
+
+    @classmethod
+    def empty(cls):
+        return cls(0, Block.Empty_Hash)
+
+    def __init__(self, number, sha_hash):
+        assert(type(number) is int)
+        assert(BlockId.re_hash.match(sha_hash) is not None)
+        self.number = number
+        self.sha_hash = sha_hash
+
+    @classmethod
+    def from_str(cls, blockid):
+        """
+        :param str blockid: The block id
+        """
+        data = blockid.split("-")
+        number = int(data[0])
+        sha_hash = data[1]
+        return cls(number, sha_hash)
+
+    def __str__(self):
+        return "{0}-{1}".format(self.number, self.sha_hash)
+
+
 class Block(Document):
     """
 Version: VERSION
@@ -107,6 +137,10 @@ BOTTOM_SIGNATURE
         self.certifications = certifications
         self.transactions = transactions
 
+    @property
+    def blockid(self):
+        return BlockId(self.number, self.sha_hash)
+
     @classmethod
     def from_signed_raw(cls, raw):
         lines = raw.splitlines(True)
diff --git a/lib/ucoinpy/documents/certification.py b/lib/ucoinpy/documents/certification.py
index d7e79adb550dcc1ce15c10dc20fa7e0629c40758..61999ccf4ca13f7baabe204e886ace19a917afa7 100644
--- a/lib/ucoinpy/documents/certification.py
+++ b/lib/ucoinpy/documents/certification.py
@@ -7,7 +7,7 @@ import re
 import base64
 import logging
 
-from . import Document
+from .document import Document
 
 
 class SelfCertification(Document):
diff --git a/lib/ucoinpy/documents/membership.py b/lib/ucoinpy/documents/membership.py
index 570110e29772f1ed473f02a5c788cc4505cbe2ca..097d36762c51b94d289b8123258991570baa248a 100644
--- a/lib/ucoinpy/documents/membership.py
+++ b/lib/ucoinpy/documents/membership.py
@@ -4,7 +4,7 @@ Created on 2 déc. 2014
 @author: inso
 """
 from .. import PROTOCOL_VERSION
-from . import Document
+from .document import Document
 
 import re
 
diff --git a/lib/ucoinpy/documents/peer.py b/lib/ucoinpy/documents/peer.py
index 6ca7606c6429b7521318720b0336649676a70dd6..80dddef7c73e65c6cc4893f357fd92697aa3f469 100644
--- a/lib/ucoinpy/documents/peer.py
+++ b/lib/ucoinpy/documents/peer.py
@@ -7,7 +7,7 @@ Created on 2 déc. 2014
 import re
 
 from ..api.bma import ConnectionHandler
-from . import Document
+from .document import Document
 from .. import PROTOCOL_VERSION, MANAGED_API
 
 
diff --git a/lib/ucoinpy/documents/status.py b/lib/ucoinpy/documents/status.py
index f11e7542c338f57831f6972f11a260a10d0d0254..acfd5eb47654b41813a847eb36662fd6f75dae25 100644
--- a/lib/ucoinpy/documents/status.py
+++ b/lib/ucoinpy/documents/status.py
@@ -5,7 +5,7 @@ Created on 2 déc. 2014
 """
 
 import re
-from . import Document
+from .document import Document
 
 
 class Status(Document):
diff --git a/lib/ucoinpy/documents/transaction.py b/lib/ucoinpy/documents/transaction.py
index 0a9d40d21b797cd1dfd7f35bcaac230c73170c6a..5f2f4e1333f64eb4ee3844d5012a0fcc092fe97a 100644
--- a/lib/ucoinpy/documents/transaction.py
+++ b/lib/ucoinpy/documents/transaction.py
@@ -4,10 +4,11 @@ Created on 2 déc. 2014
 @author: inso
 """
 
-from . import Document
+from .document import Document
 import re
 import logging
 
+
 class Transaction(Document):
     """
 Document format :
diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py
index d2658542a6e854c294c4d18e673b08fdbf3c2fab..8098594c2005db64d6df90a06983eae9c2d4e589 100644
--- a/src/cutecoin/core/community.py
+++ b/src/cutecoin/core/community.py
@@ -16,7 +16,7 @@ from PyQt5.QtCore import QObject, pyqtSignal
 from ..tools.exceptions import NoPeerAvailable
 from .net.network import Network
 from ucoinpy.api import bma
-from ucoinpy.documents.block import Block
+from ucoinpy.documents import Block, BlockId
 from .net.api.bma.access import BmaAccess
 
 
@@ -287,14 +287,11 @@ class Community(QObject):
         try:
             block = yield from self.bma_access.future_request(bma.blockchain.Current)
             signed_raw = "{0}{1}\n".format(block['raw'], block['signature'])
-            block_hash = hashlib.sha1(signed_raw.encode("ascii")).hexdigest().upper()
-            block_number = block['number']
         except ValueError as e:
             if '404' in str(e):
-                block_hash = Block.Empty_Hash
-                block_number = 0
+                return BlockId.empty()
 
-        return {'number': block_number, 'hash': block_hash}
+        return Block.from_signed_raw(signed_raw).blockid
 
     @asyncio.coroutine
     def members_pubkeys(self):
diff --git a/src/cutecoin/core/net/network.py b/src/cutecoin/core/net/network.py
index 4146da8d9b5390f16f3c7b0f3aa818b7647dd45b..1d6030ff3f6b31a7180a40ab2cc3bb519de58270 100644
--- a/src/cutecoin/core/net/network.py
+++ b/src/cutecoin/core/net/network.py
@@ -12,8 +12,6 @@ import asyncio
 from ucoinpy.documents.peer import Peer
 from ucoinpy.documents.block import Block
 
-from ...tools.decorators import asyncify
-
 from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QTimer
 from collections import Counter
 
diff --git a/src/cutecoin/core/net/node.py b/src/cutecoin/core/net/node.py
index a64b6fa879f24689a2971b4a1b28e322a8da4a7a..19c71e9672fef6e69dfc69f6dc2dcc2de5d00bf5 100644
--- a/src/cutecoin/core/net/node.py
+++ b/src/cutecoin/core/net/node.py
@@ -296,8 +296,8 @@ class Node(QObject):
 
             if not self.block or block_hash != self.block['hash']:
                 try:
-                    #TODO: Check previous block
-                    self.main_chain_previous_block = yield from bma.blockchain.Block(conn_handler,
+                    if self.block:
+                        self.main_chain_previous_block = yield from bma.blockchain.Block(conn_handler,
                                                                                      self.block['number']).get()
                 except ValueError as e:
                     if '404' in str(e):
diff --git a/src/cutecoin/core/transfer.py b/src/cutecoin/core/transfer.py
index 29902ca573b85fda70195b39ee820347d87a902a..5a78b7c2a5d5be8f113ce730bafff5cdf410708d 100644
--- a/src/cutecoin/core/transfer.py
+++ b/src/cutecoin/core/transfer.py
@@ -6,14 +6,14 @@ Created on 31 janv. 2015
 import logging
 import asyncio
 from ucoinpy.api import bma
-from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject
-from PyQt5.QtNetwork import QNetworkReply
+from ucoinpy.documents import Block, BlockId
+from PyQt5.QtCore import pyqtSignal, QObject
 import hashlib
+from enum import Enum
 
 
-class Transfer(QObject):
+class TransferState(Enum):
     """
-    A transfer is the lifecycle of a transaction.
     TO_SEND means the transaction wasn't sent yet
     AWAITING means the transaction is waiting to reach K blockchain validation
     VALIDATED means the transaction was validated locally and is considered present in the blockchain
@@ -29,10 +29,15 @@ class Transfer(QObject):
     REFUSED = 3
     DROPPED = 5
 
+
+class Transfer(QObject):
+    """
+    A transfer is the lifecycle of a transaction.
+    """
     transfer_broadcasted = pyqtSignal(str)
     broadcast_error = pyqtSignal(int, str)
 
-    def __init__(self, hash, state, metadata):
+    def __init__(self, sha_hash, state, blockid, metadata, locally_created):
         """
         The constructor of a transfer.
         Check for metadata keys which must be present :
@@ -43,12 +48,12 @@ class Transfer(QObject):
         - amount
         - comment
 
-        :param txdoc: The Transaction ucoinpy object
-        :param state: The state of the Transfer (TO_SEND, AWAITING, VALIDATED, REFUSED or DROPPED)
-        :param metadata: The transfer metadata
+        :param str sha_hash: The hash of the transaction
+        :param TransferState state: The state of the Transfer
+        :param ucoinpy.documents.BlockId blockid: The blockid of the transaction in the blockchain
+        :param dict metadata: The transfer metadata
         """
         assert('receiver' in metadata)
-        assert('block' in metadata)
         assert('time' in metadata)
         assert('issuer' in metadata)
         assert('amount' in metadata)
@@ -58,32 +63,81 @@ class Transfer(QObject):
         assert('txid' in metadata)
         super().__init__()
 
-        self.hash = hash
+        self.sha_hash = sha_hash
         self.state = state
+        self.blockid = blockid
+        self._locally_created = locally_created
         self._metadata = metadata
 
+        self._table_states = {
+            (TransferState.TO_SEND, (list, Block)):
+                (self._broadcast_success, self._wait, TransferState.AWAITING),
+
+            (TransferState.AWAITING, (bool, Block)):
+                (self._found_in_block, self._be_validating, TransferState.VALIDATING),
+            (TransferState.AWAITING, (bool, Block, int)):
+                (self._not_found_in_blockchain, None, TransferState.REFUSED),
+
+            (TransferState.VALIDATING, (bool, Block, int)):
+                (self._reached_enough_validation, None, TransferState.VALIDATED),
+            (TransferState.VALIDATING, (bool, Block)):
+                (self._rollback_and_removed, self._drop, TransferState.DROPPED),
+
+            (TransferState.VALIDATED, (bool, Block)):
+                (self._rollback_still_present, self._be_validating, TransferState.VALIDATING),
+            (TransferState.VALIDATED, (bool, Block)):
+                (self._rollback_and_removed, self._drop, TransferState.DROPPED),
+            (TransferState.VALIDATED, (bool, Block)):
+                (self._rollback_and_local, self._wait, TransferState.AWAITING),
+
+            (TransferState.DROPPED, ()):
+                (self._is_locally_created, None, TransferState.TO_SEND),
+            (TransferState.REFUSED, ()):
+                (self._is_locally_created, self._drop, TransferState.DROPPED),
+        }
+
     @classmethod
     def initiate(cls, metadata):
         """
         Create a new transfer in a "TO_SEND" state.
+        :param dict metadata: The computed metadata of the transfer
+        :return: A new transfer
+        :rtype: Transfer
         """
-        return cls(None, Transfer.TO_SEND, metadata)
+        return cls(None, TransferState.TO_SEND, None, metadata, True)
 
     @classmethod
-    def create_from_blockchain(cls, hash, metadata, block_number, time, nb_validation):
+    def create_from_blockchain(cls, hash, blockid, metadata):
         """
         Create a new transfer sent from another cutecoin instance
+        :param str hash: The transaction hash
+        :param ucoinpy.documents.BlockId blockid: The block id were we found the tx
+        :param dict metadata: The computed metadata of the transaction
+        :return: A new transfer
+        :rtype: Transfer
         """
-        tx = cls(hash, Transfer.VALIDATING, metadata)
-        tx.check_registered(block_number, time, nb_validation)
-        return tx
+        return cls(hash, TransferState.VALIDATING, blockid, metadata, False)
 
     @classmethod
     def load(cls, data):
         """
         Create a new transfer from a dict in json format.
+        :param dict data: The loaded data
+        :return: A new transfer
+        :rtype: Transfer
         """
-        return cls(data['hash'], data['state'], data['metadata'])
+        return cls(data['hash'], TransferState[data['state']], BlockId.from_str(data['blockid']),
+                   data['metadata'], data['local'])
+
+    def jsonify(self):
+        """
+        :return: The transfer as a dict in json format
+        """
+        return {'hash': self.sha_hash,
+                'state': self.state.name,
+                'blockid': str(self.blockid),
+                'metadata': self._metadata,
+                'local': self._locally_created}
 
     @property
     def metadata(self):
@@ -92,13 +146,159 @@ class Transfer(QObject):
         """
         return self._metadata
 
-    def jsonify(self):
+    def _not_found_in_blockchain(self, rollback, block, mediantime_target):
         """
-        :return: The transfer as a dict in json format
+        Check if the transaction could not be found in the blockchain
+        :param bool rollback: True if we are in a rollback procedure
+        :param ucoinpy.documents.Block block: The block to look for the tx
+        :param int mediantime_target: The mediantime to mine a block in the community parameters
+        :return: True if the transaction could not be found in a given time
+        :rtype: bool
+        """
+        if not rollback:
+            for tx in block.transactions:
+                if tx.hash == self.sha_hash:
+                    return False
+            if block.time > self.metadata['time'] + mediantime_target*10:
+                return True
+        return False
+
+    def _found_in_block(self, rollback, block):
+        """
+        Check if the transaction can be found in the blockchain
+        :param bool rollback: True if we are in a rollback procedure
+        :param ucoinpy.documents.Block block: The block to check for the transaction
+        :return: True if the transaction was found
+        :rtype: bool
+        """
+        if not rollback:
+            for tx in block.transactions:
+                if tx.hash == self.sha_hash:
+                    return True
+        return False
+
+    def _broadcast_success(self, ret_codes, time):
+        """
+        Check if the retcode is 200 after a POST
+        :param list ret_codes: The POST return codes of the broadcast
+        :param int time: The mediantime of the blockchain. Used for transition.
+        :return: True if the post was successful
+        :rtype: bool
+        """
+        return 200 in ret_codes
+
+    def _reached_enough_validation(self, rollback, current_block, fork_window):
         """
-        return {'hash': self.hash,
-                'state': self.state,
-                'metadata': self._metadata}
+        Check if the transfer reached enough validation in the blockchain
+        :param bool rollback: True if we are in a rollback procedure
+        :param ucoinpy.documents.Block current_block: The current block of the main blockchain
+        :param int fork_window: The number of validations needed on the network
+        :return: True if the transfer reached enough validations
+        :rtype: bool
+        """
+        return not rollback and self.blockid.number + fork_window <= current_block.number
+
+    def _rollback_and_removed(self, rollback, block):
+        """
+        Check if the transfer is not in the block anymore
+        :param bool rollback: True if we are in a rollback procedure
+        :param ucoinpy.documents.Block block: The block to check for the transaction
+        :return: True if the transfer is not found in the block
+        """
+        if rollback and block.blockid == self.blockid:
+            return self.sha_hash not in [t.hash for t in block.transactions]
+        return False
+
+    def _rollback_still_present(self, rollback, block):
+        """
+        Check if the transfer is not in the block anymore
+        :param bool rollback: True if we are in a rollback procedure
+        :param ucoinpy.documents.Block block: The block to check for the transaction
+        :return: True if the transfer is found in the block
+        """
+        if rollback and block.blockid == self.blockid:
+            return self.sha_hash in [t.hash for t in block.transactions]
+        return False
+
+    def _rollback_and_local(self, rollback, block):
+        """
+        Check if the transfer is not in the block anymore
+        :param bool rollback: True if we are in a rollback procedure
+        :param ucoinpy.documents.Block block: The block to check for the transaction
+        :return: True if the transfer is found in the block
+        """
+        if rollback and self._locally_created and block.blockid == self.blockid:
+            return self.sha_hash not in [t.hash for t in block.transactions]
+        return False
+
+    def _is_locally_created(self):
+        """
+        Check if we can send back the transaction if it was locally created
+        :return: True if the transaction was locally created
+        """
+        return self._locally_created
+
+    def _wait(self, ret_codes, current_block):
+        """
+        Set the transfer as AWAITING validation.
+        :param list ret_codes: The responses return codes
+        :param ucoinpy.documents.Block current_block: Current block of the main blockchain
+        """
+        self.blockid = current_block
+        self._metadata['time'] = current_block.mediantime
+
+    def _be_validating(self, rollback, block):
+        """
+        Action when the transfer ins found in a block
+
+        :param bool rollback: True if we are in a rollback procedure
+        :param ucoinpy.documents.Block block: The block checked
+        """
+        self.blockid = block.blockid
+        self._metadata['time'] = block.mediantime
+
+    def _drop(self):
+        """
+        Cancel the transfer locally.
+        The transfer state becomes TransferState.DROPPED.
+        """
+        self.blockid = None
+
+    def _try_transition(self, transition_key, inputs):
+        """
+        Try the transition defined by the given transition_key
+        with inputs
+        :param tuple transition_key: The transition key in the table states
+        :param tuple inputs: The inputs
+        :return: True if the transition was applied
+        :rtype: bool
+        """
+        if len(inputs) == len(transition_key[1]):
+            for i, input in enumerate(inputs):
+                if type(input) is not transition_key[1][i]:
+                    return False
+            if self._table_states[transition_key][0](*inputs):
+                next_state = self._table_states[transition_key]
+                logging.debug("{0} : {1} --> {2}".format(self.sha_hash[:5], self.state.name, next_state[2].name))
+                # If the transition changes data, apply changes
+                if next_state[1]:
+                    next_state[1](*inputs)
+                self.state = next_state[2]
+                return True
+        return False
+
+    def run_state_transitions(self, inputs):
+        """
+        Try all current state transitions with inputs
+        :param tuple inputs: The inputs passed to the transitions
+        :return: True if the transaction changed state
+        :rtype: bool
+        """
+        transition_keys = [k for k in self._table_states.keys() if k[0] == self.state]
+        for key in transition_keys:
+            if self._try_transition(key, inputs):
+                return True
+        return False
 
     @asyncio.coroutine
     def send(self, txdoc, community):
@@ -112,13 +312,10 @@ class Transfer(QObject):
         """
         responses = yield from community.bma_access.broadcast(bma.tx.Process,
                 post_args={'transaction': txdoc.signed_raw()})
-        self.state = Transfer.AWAITING
-        self.hash = hashlib.sha1(txdoc.signed_raw().encode("ascii")).hexdigest().upper()
         blockid = yield from community.blockid()
         block = yield from community.bma_access.future_request(bma.blockchain.Block,
-                                  req_args={'number': blockid['number']})
-        self._metadata['block'] = blockid['number']
-        self._metadata['time'] = block['medianTime']
+                                  req_args={'number': blockid.number})
+        time = block['medianTime']
         result = (False, "")
         for r in responses:
             if r.status == 200:
@@ -127,43 +324,5 @@ class Transfer(QObject):
                 result = (False, (yield from r.text()))
             else:
                 yield from r.text()
-
+        self.run_state_transitions(([r.status for r in responses], time))
         return result
-
-    def check_registered(self, txhash, block_number, time, nb_validation):
-        """
-        Check if the transfer was registered in a block.
-        Update the transfer state to VALIDATED if it was registered.
-
-        :param txhash: A transaction ucoinpy object found in the block
-        :param int block_number: The block number checked
-        :param int time: The time of the block
-        :param int nb_validation: The number of validations needed to become VALIDATED
-        """
-        if txhash == self.hash:
-            if self.state == Transfer.AWAITING:
-                self.state = Transfer.VALIDATING
-                self._metadata['block'] = block_number
-                self._metadata['time'] = time
-            if self.state == Transfer.VALIDATING and \
-                    self._metadata['block'] - block_number >= nb_validation:
-                self.state = Transfer.VALIDATED
-
-    def check_refused(self, time, block_time, mediantime_blocks):
-        """
-        Check if the transfer was refused
-        If more than block_time*15 seconds passed since
-        transfer, it is considered as refused.
-
-        :param int block: The current block number
-        """
-        if time > self._metadata['time'] + block_time*mediantime_blocks*10:
-            self.state = Transfer.REFUSED
-
-    def drop(self):
-        """
-        Cancel the transfer locally.
-        The transfer state becomes "DROPPED".
-        """
-        self.state = Transfer.DROPPED
-
diff --git a/src/cutecoin/core/txhistory.py b/src/cutecoin/core/txhistory.py
index 98bb117ab9195b90671de12fa14f1d45a2a3da81..d3cd3c08027ce79b3aa706756187d1962be3d515 100644
--- a/src/cutecoin/core/txhistory.py
+++ b/src/cutecoin/core/txhistory.py
@@ -1,7 +1,7 @@
 import asyncio
 import logging
 import hashlib
-from .transfer import Transfer
+from .transfer import Transfer, TransferState
 from ucoinpy.documents.transaction import InputSource, OutputSource
 from ucoinpy.documents.block import Block
 from ..tools.exceptions import LookupFailureError, NoPeerAvailable
@@ -39,6 +39,7 @@ class TxHistory():
             self.available_sources.append(InputSource.from_inline(s['inline']))
 
         for d in data['dividends']:
+            d['state'] = TransferState[d['state']]
             self._dividends.append(d)
 
         self.latest_block = data['latest_block']
@@ -54,7 +55,8 @@ class TxHistory():
             data_sources.append({'inline': "{0}\n".format(s.inline())})
 
         data_dividends = []
-        for d in self._dividends:
+        for d in self._dividends.copy():
+            d['state'] = d['state'].name
             data_dividends.append(d)
 
         return {'latest_block': self.latest_block,
@@ -64,7 +66,7 @@ class TxHistory():
 
     @property
     def transfers(self):
-        return [t for t in self._transfers if t.state != Transfer.DROPPED]
+        return [t for t in self._transfers if t.state != TransferState.DROPPED]
 
     @property
     def dividends(self):
@@ -73,34 +75,22 @@ class TxHistory():
     def stop_coroutines(self):
         self._stop_coroutines = True
 
-    @staticmethod
     @asyncio.coroutine
-    def _validation_state(community, block_number, current_block):
-        members_pubkeys = yield from community.members_pubkeys()
-        if block_number + community.network.fork_window(members_pubkeys) <= current_block["number"]:
-            state = Transfer.VALIDATED
-        else:
-            state = Transfer.VALIDATING
-        return state
-
-    @asyncio.coroutine
-    def _parse_transaction(self, community, tx, block_number,
-                           mediantime, received_list,
-                           current_block, txid):
+    def _parse_transaction(self, community, tx, blockid,
+                           mediantime, received_list, txid):
         """
         Parse a transaction
         :param cutecoin.core.Community community: The community
         :param ucoinpy.documents.Transaction tx: The tx json data
-        :param int block_number: The block number were we found the tx
+        :param ucoinpy.documents.BlockId blockid: The block id where we found the tx
         :param int mediantime: Median time on the network
         :param list received_list: The list of received transactions
-        :param int current_block: The current block of the network
         :param int txid: The latest txid
         :return: the found transaction
         """
         receivers = [o.pubkey for o in tx.outputs
                      if o.pubkey != tx.issuers[0]]
-        nb_validations = community.network.fork_window((yield from community.members_pubkeys()))
+
         if len(receivers) == 0:
             receivers = [tx.issuers[0]]
 
@@ -116,58 +106,51 @@ class TxHistory():
         except LookupFailureError:
             receiver_uid = ""
 
-        metadata = {'block': block_number,
+        metadata = {
                     'time': mediantime,
                     'comment': tx.comment,
                     'issuer': tx.issuers[0],
                     'issuer_uid': issuer_uid,
                     'receiver': receivers[0],
                     'receiver_uid': receiver_uid,
-                    'txid': txid}
+                    'txid': txid
+                    }
 
         in_issuers = len([i for i in tx.issuers
                      if i == self.wallet.pubkey]) > 0
         in_outputs = len([o for o in tx.outputs
                        if o.pubkey == self.wallet.pubkey]) > 0
-        watched = [t for t in self._transfers
-                    if t.state in (Transfer.AWAITING, Transfer.VALIDATING)]
 
         # We check if the transaction correspond to one we sent
         # but not from this cutecoin Instance
         tx_hash = hashlib.sha1(tx.signed_raw().encode("ascii")).hexdigest().upper()
-        if tx_hash not in [t.hash for t in watched]:
-            # If the wallet pubkey is in the issuers we sent this transaction
-            if in_issuers:
-                outputs = [o for o in tx.outputs
-                           if o.pubkey != self.wallet.pubkey]
-                amount = 0
-                for o in outputs:
-                    amount += o.amount
-                metadata['amount'] = amount
-                transfer = Transfer.create_from_blockchain(tx_hash,
-                                                     metadata.copy(),
-                                                   current_block['number'],
-                                                   mediantime, nb_validations)
-                return transfer
-            # If we are not in the issuers,
-            # maybe it we are in the recipients of this transaction
-            elif in_outputs:
-                outputs = [o for o in tx.outputs
-                           if o.pubkey == self.wallet.pubkey]
-                amount = 0
-                for o in outputs:
-                    amount += o.amount
-                metadata['amount'] = amount
-                transfer = Transfer.create_from_blockchain(tx_hash,
-                                                     metadata.copy(),
-                                                       current_block['number'],
-                                                       mediantime, nb_validations)
-                received_list.append(transfer)
-                return transfer
-        else:
-            transfer = [t for t in watched if t.hash == tx_hash][0]
-
-            transfer.check_registered(tx_hash, current_block['number'], mediantime, nb_validations)
+        # If the wallet pubkey is in the issuers we sent this transaction
+        if in_issuers:
+            outputs = [o for o in tx.outputs
+                       if o.pubkey != self.wallet.pubkey]
+            amount = 0
+            for o in outputs:
+                amount += o.amount
+            metadata['amount'] = amount
+            transfer = Transfer.create_from_blockchain(tx_hash,
+                                                       blockid,
+                                                 metadata.copy())
+            return transfer
+        # If we are not in the issuers,
+        # maybe it we are in the recipients of this transaction
+        elif in_outputs:
+            outputs = [o for o in tx.outputs
+                       if o.pubkey == self.wallet.pubkey]
+            amount = 0
+            for o in outputs:
+                amount += o.amount
+            metadata['amount'] = amount
+
+            transfer = Transfer.create_from_blockchain(tx_hash,
+                                                       blockid,
+                                                 metadata.copy())
+            received_list.append(transfer)
+            return transfer
         return None
 
     @asyncio.coroutine
@@ -202,10 +185,16 @@ class TxHistory():
                     block = None
                     tries += 1
         if block_doc:
-            for (txid, tx) in enumerate(block_doc.transactions):
-                transfer = yield from self._parse_transaction(community, tx, block_number,
-                                        block_doc.mediantime, received_list,
-                                        current_block, txid+txmax)
+            for transfer in [t for t in self._transfers if t.state == TransferState.AWAITING]:
+                transfer.run_state_transitions((False, block_doc))
+
+            new_tx = [t for t in block_doc.transactions
+                      if t.sha_hash not in [trans.sha_hash for trans in self._transfers]
+                      ]
+
+            for (txid, tx) in enumerate(new_tx):
+                transfer = yield from self._parse_transaction(community, tx, block_doc.blockid,
+                                        block_doc.mediantime, received_list, txid+txmax)
                 if transfer != None:
                     #logging.debug("Transfer amount : {0}".format(transfer.metadata['amount']))
                     transfers.append(transfer)
@@ -223,7 +212,8 @@ class TxHistory():
                 dividends_data = yield from community.bma_access.future_request(bma.ud.History,
                                                 req_args={'pubkey': self.wallet.pubkey})
 
-                dividends = dividends_data['history']['history']
+                dividends = dividends_data['history']['history'].copy()
+
                 for d in dividends:
                     if d['block_number'] < parsed_block:
                         dividends.remove(d)
@@ -245,21 +235,25 @@ class TxHistory():
             logging.debug("Refresh from : {0} to {1}".format(block_number_from, self._block_to['number']))
             dividends = yield from self.request_dividends(community, block_number_from)
             with_tx_data = yield from community.bma_access.future_request(bma.blockchain.TX)
+            members_pubkeys = yield from community.members_pubkeys()
+            fork_window = community.network.fork_window(members_pubkeys)
             blocks_with_tx = with_tx_data['result']['blocks']
             new_transfers = []
             new_dividends = []
             # Lets look if transactions took too long to be validated
             awaiting = [t for t in self._transfers
-                        if t.state == Transfer.AWAITING]
+                        if t.state == TransferState.AWAITING]
             while block_number_from <= self._block_to['number']:
                 udid = 0
                 for d in [ud for ud in dividends if ud['block_number'] == block_number_from]:
-                    state = yield from TxHistory._validation_state(community, d['block_number'], self._block_to)
+                    state = TransferState.VALIDATED if block_number_from + fork_window <= self._block_to['number'] \
+                        else TransferState.VALIDATING
 
                     if d['block_number'] not in [ud['block_number'] for ud in self._dividends]:
                         d['id'] = udid
                         d['state'] = state
                         new_dividends.append(d)
+
                         udid += 1
                     else:
                         known_dividend = [ud for ud in self._dividends
@@ -268,11 +262,6 @@ class TxHistory():
 
                 # We parse only blocks with transactions
                 if block_number_from in blocks_with_tx:
-                    # We check if validated transfers should go back to validating...
-                    for t in [t for t in self._transfers if t.metadata['block'] == block_number_from]:
-                        t.state = yield from TxHistory._validation_state(community, t.metadata['block'],
-                                                                         self._block_to)
-
                     transfers = yield from self._parse_block(community, block_number_from,
                                                              received_list, self._block_to,
                                                              udid + len(new_transfers))
@@ -281,6 +270,12 @@ class TxHistory():
                 self.wallet.refresh_progressed.emit(block_number_from, self._block_to['number'], self.wallet.pubkey)
                 block_number_from += 1
 
+            signed_raw = "{0}{1}\n".format(self._block_to['raw'],
+                                       self._block_to['signature'])
+            block_to = Block.from_signed_raw(signed_raw)
+            for transfer in [t for t in self._transfers if t.state == TransferState.VALIDATING]:
+                transfer.run_state_transitions((False, block_to, fork_window))
+
             # We check if latest parsed block_number is a new high number
             if block_number_from > self.latest_block:
                 self.available_sources = yield from self.wallet.sources(community)
@@ -313,10 +308,12 @@ class TxHistory():
                                         req_args={'number': latest_block_number})
                 members_pubkeys = yield from community.members_pubkeys()
                 # We look for the first block to parse, depending on awaiting and validating transfers and ud...
-                blocks = [tx.metadata['block'] for tx in self._transfers
-                          if tx.state in (Transfer.AWAITING, Transfer.VALIDATING)] +\
-                         [ud['block_number'] for ud in self._dividends
-                          if ud['state'] in (Transfer.AWAITING, Transfer.VALIDATING)] +\
+                tx_blocks = [tx.blockid.number for tx in self._transfers
+                          if tx.state in (TransferState.AWAITING, TransferState.VALIDATING) \
+                         and tx.blockid is not None]
+                ud_blocks = [ud['block_number'] for ud in self._dividends
+                          if ud['state'] in (TransferState.AWAITING, TransferState.VALIDATING)]
+                blocks = tx_blocks + ud_blocks + \
                          [max(0, self.latest_block - community.network.fork_window(members_pubkeys))]
                 parsed_block = min(set(blocks))
                 self._block_to = current_block
diff --git a/src/cutecoin/models/txhistory.py b/src/cutecoin/models/txhistory.py
index 482fed11b3c063ae61790717a2342a33312ad9f7..4e434d6158ff492736bd50f1efb49a5802cc51f0 100644
--- a/src/cutecoin/models/txhistory.py
+++ b/src/cutecoin/models/txhistory.py
@@ -7,7 +7,7 @@ Created on 5 févr. 2014
 import datetime
 import logging
 import asyncio
-from ..core.transfer import Transfer
+from ..core.transfer import Transfer, TransferState
 from ..tools.exceptions import NoPeerAvailable
 from ..tools.decorators import asyncify, once_at_a_time, cancel_once_task
 from PyQt5.QtCore import QAbstractTableModel, Qt, QVariant, QSortFilterProxyModel, \
@@ -119,20 +119,20 @@ class TxFilterProxyModel(QSortFilterProxyModel):
 
         if role == Qt.FontRole:
             font = QFont()
-            if state_data == Transfer.AWAITING or state_data == Transfer.VALIDATING:
+            if state_data == TransferState.AWAITING or state_data == TransferState.VALIDATING:
                 font.setItalic(True)
-            elif state_data == Transfer.REFUSED:
+            elif state_data == TransferState.REFUSED:
                 font.setItalic(True)
-            elif state_data == Transfer.TO_SEND:
+            elif state_data == TransferState.TO_SEND:
                 font.setBold(True)
             else:
                 font.setItalic(False)
             return font
 
         if role == Qt.ForegroundRole:
-            if state_data == Transfer.REFUSED:
+            if state_data == TransferState.REFUSED:
                 return QColor(Qt.red)
-            elif state_data == Transfer.TO_SEND:
+            elif state_data == TransferState.TO_SEND:
                 return QColor(Qt.blue)
 
         if role == Qt.TextAlignmentRole:
@@ -146,13 +146,13 @@ class TxFilterProxyModel(QSortFilterProxyModel):
             if source_index.column() == self.sourceModel().columns_types.index('date'):
                 return QDateTime.fromTime_t(source_data).toString(Qt.SystemLocaleLongDate)
 
-            if state_data == Transfer.VALIDATING or state_data == Transfer.AWAITING:
+            if state_data == TransferState.VALIDATING or state_data == TransferState.AWAITING:
                 block_col = model.columns_types.index('block_number')
                 block_index = model.index(source_index.row(), block_col)
                 block_data = model.data(block_index, Qt.DisplayRole)
 
                 current_validations = 0
-                if state_data == Transfer.VALIDATING:
+                if state_data == TransferState.VALIDATING:
                     latest_block_number = self.community.network.latest_block_number
                     if latest_block_number:
                         current_validations = latest_block_number - block_data
@@ -241,7 +241,10 @@ class HistoryTableModel(QAbstractTableModel):
 
         date_ts = transfer.metadata['time']
         txid = transfer.metadata['txid']
-        block_number = transfer.metadata['block']
+        if transfer.blockid:
+            block_number = transfer.blockid.number
+        else:
+            block_number = None
 
         return (date_ts, sender, "", deposit,
                 comment, transfer.state, txid,
@@ -262,7 +265,10 @@ class HistoryTableModel(QAbstractTableModel):
 
         date_ts = transfer.metadata['time']
         txid = transfer.metadata['txid']
-        block_number = transfer.metadata['block']
+        if transfer.blockid:
+            block_number = transfer.blockid.number
+        else:
+            block_number = None
 
         return (date_ts, receiver, paiment,
                 "", comment, transfer.state, txid,