diff --git a/app/lib/blockchain/Switcher.ts b/app/lib/blockchain/Switcher.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ea4514ebd74df39490851625d755c39747f09d1f
--- /dev/null
+++ b/app/lib/blockchain/Switcher.ts
@@ -0,0 +1,159 @@
+export interface SwitchBlock {
+
+  number:number
+  hash:string
+  previousHash:string
+  medianTime:number
+}
+
+export interface SwitcherDao {
+
+  getCurrent(): SwitchBlock
+  getPotentials(numberStart:number, timeStart:number): SwitchBlock[]
+  getBlockchainBlock(number:number, hash:string): SwitchBlock|null
+  getSandboxBlock(number:number, hash:string): SwitchBlock|null
+  revertTo(number:number): SwitchBlock[]
+  addBlock(block:SwitchBlock): SwitchBlock
+}
+
+export class Switcher {
+
+  constructor(private dao:SwitcherDao, private avgGenTime:number, private forkWindowSize:number) {}
+
+  /**
+   * Looks at known blocks in the sandbox and try to follow the longest resulting chain that has at least both 3 blocks of
+   * advance and 3 * avgGenTime of medianTime advancce.
+   * @returns {SwitchBlock}
+   */
+  tryToFork() {
+    const current = this.dao.getCurrent()
+    const numberStart = current.number + 3
+    const timeStart = current.medianTime + 3 * this.avgGenTime
+    // Phase 1: find potential chains
+    const suites = this.findPotentialSuites(current, numberStart, timeStart)
+    // Phase 2: select the best chain
+    let longestChain:null|SwitchBlock[] = this.findLongestChain(suites)
+    // Phase 3: a best exist?
+    if (longestChain) {
+      const chainHEAD = longestChain[longestChain.length - 1]
+      // apply it if it respects the 3-3 rule
+      if (chainHEAD.number >= numberStart && chainHEAD.medianTime >= timeStart) {
+        this.switchOnChain(longestChain)
+      }
+    }
+    return this.dao.getCurrent()
+  }
+
+  /**
+   * Looks at the potential blocks that could form fork chains in the sandbox, and sort them to have a maximum of unique
+   * chains.
+   * @param {SwitchBlock} current HEAD of local blockchain.
+   * @param {number} numberStart The minimum number of a fork block.
+   * @param {number} timeStart The minimum medianTime of a fork block.
+   * @returns {SwitchBlock[][]} The suites found.
+   */
+  private findPotentialSuites(current:SwitchBlock, numberStart:number, timeStart:number) {
+    const suites:SwitchBlock[][] = []
+    const potentials:SwitchBlock[] = this.dao.getPotentials(numberStart, timeStart)
+    const invalids: { [hash:string]: SwitchBlock } = {}
+    for (const candidate of potentials) {
+      const suite:SwitchBlock[] = []
+      // Do not process the block if it is already known as invalid (has no fork point with current blockchain or misses
+      // some blocks) or is already contained in a valid chain.
+      if (!invalids[candidate.hash] && !Switcher.suitesContains(suites, candidate)) {
+        // Tries to build up a full chain that is linked to current chain by a fork point.
+        let previous:SwitchBlock|null = candidate, commonRootFound = false
+        while (previous && previous.number > current.number - this.forkWindowSize) {
+          suite.push(previous)
+          const previousNumber = previous.number - 1
+          const previousHash = previous.previousHash
+          previous = this.dao.getBlockchainBlock(previousNumber, previousHash)
+          if (previous) {
+            // Stop the loop: common block has been found
+            previous = null
+            suites.push(suite)
+            commonRootFound = true
+          } else {
+            // Have a look in sandboxes
+            previous = this.dao.getSandboxBlock(previousNumber, previousHash)
+          }
+        }
+        // Forget about invalid blocks
+        if (!commonRootFound) {
+          for (const b of suite) {
+            invalids[b.hash] = b
+          }
+        }
+      }
+    }
+    return suites
+  }
+
+  /**
+   * Find the longest chain among a suite of chains. Tests the validity of each block against the current blockchain.
+   * The length of a chain is the number of blocks successfuly added to current blockchain.
+   * @param {SwitchBlock[][]} suites
+   * @returns {SwitchBlock[]}
+   */
+  private findLongestChain(suites:SwitchBlock[][]) {
+    let longestChain:null|SwitchBlock[] = null
+    for (const s of suites) {
+      s.reverse()
+      // Revert current blockchain to fork point
+      const reverted = this.dao.revertTo(s[0].number - 1)
+      // Try to add a maximum of blocks
+      let added = true, i = 0, successfulBlocks:SwitchBlock[] = []
+      while (added) {
+        try {
+          this.dao.addBlock(s[i])
+          successfulBlocks.push(s[i])
+        } catch (e) {
+          added = false
+        }
+        i++
+      }
+      // Pop the successfuly added blocks
+      if (successfulBlocks.length) {
+        this.dao.revertTo(this.dao.getCurrent().number - successfulBlocks.length)
+      }
+      // Push back the initial blocks that were temporarily reverted
+      reverted.reverse()
+      for (const b of reverted) {
+        this.dao.addBlock(b)
+      }
+      // Remember the chain if it is the longest among tested chains
+      if ((!longestChain && successfulBlocks.length > 0) || (longestChain && longestChain.length < successfulBlocks.length)) {
+        longestChain = successfulBlocks
+      }
+    }
+    return longestChain
+  }
+
+  /**
+   * Switch current blockchain on another chain, by poping top blocks and replacing them by new ones.
+   * @param {SwitchBlock[]} chain
+   */
+  private switchOnChain(chain:SwitchBlock[]) {
+    this.dao.revertTo(chain[0].number - 1)
+    for (const b of chain) {
+      this.dao.addBlock(b)
+    }
+  }
+
+  /**
+   * Checks if a suite of chains contains a particular block in one of its chains.
+   * @param {SwitchBlock[][]} suites
+   * @param {SwitchBlock} block
+   * @returns {boolean}
+   */
+  static suitesContains(suites:SwitchBlock[][], block:SwitchBlock) {
+    for (const suite of suites) {
+      for (const b of suite) {
+        if (b.number === block.number && b.hash === block.hash) {
+          return true
+        }
+      }
+    }
+    return false
+  }
+}
\ No newline at end of file
diff --git a/test/fast/fork-resolution-3-3.ts b/test/fast/fork-resolution-3-3.ts
index b3d4fa084b77d5c4cd4ff3497e979f09aaf5ca40..2d951c3d724d5c53764af37946fd56f115be691a 100644
--- a/test/fast/fork-resolution-3-3.ts
+++ b/test/fast/fork-resolution-3-3.ts
@@ -1,4 +1,5 @@
 import * as assert from 'assert'
+import {SwitchBlock, Switcher, SwitcherDao} from "../../app/lib/blockchain/Switcher"
 
 describe("Fork resolution 3-3 algo", () => {
 
@@ -21,7 +22,7 @@ describe("Fork resolution 3-3 algo", () => {
       Block.from("C15"),
       Block.from("C16")
     ])
-    const switcher = new BlockchainSwitcher(bc, sbx)
+    const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize)
     switcher.tryToFork()
     assert.equal(bc.current.number, 16)
     assert.equal(bc.current.hash, "C16")
@@ -45,7 +46,7 @@ describe("Fork resolution 3-3 algo", () => {
       Block.from("C14"),
       Block.from("C15")
     ])
-    const switcher = new BlockchainSwitcher(bc, sbx)
+    const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize)
     switcher.tryToFork()
     assert.equal(bc.current.number, 13)
     assert.equal(bc.current.hash, "B13")
@@ -67,7 +68,7 @@ describe("Fork resolution 3-3 algo", () => {
       Block.from("C14"),
       Block.from("C15")
     ])
-    const switcher = new BlockchainSwitcher(bc, sbx)
+    const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize)
     switcher.tryToFork()
     assert.equal(bc.current.number, 13)
     assert.equal(bc.current.hash, "B13")
@@ -94,7 +95,7 @@ describe("Fork resolution 3-3 algo", () => {
       Block.from("C15"),
       Block.from("C16")
     ])
-    const switcher = new BlockchainSwitcher(bc, sbx)
+    const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize)
     switcher.tryToFork()
     assert.equal(bc.current.number, 13)
     assert.equal(bc.current.hash, "B13")
@@ -120,7 +121,7 @@ describe("Fork resolution 3-3 algo", () => {
       Block.from("C15"),
       Block.from("C16")
     ])
-    const switcher = new BlockchainSwitcher(bc, sbx)
+    const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize)
     switcher.tryToFork()
     assert.equal(bc.current.number, 16)
     assert.equal(bc.current.hash, "C16")
@@ -145,7 +146,7 @@ describe("Fork resolution 3-3 algo", () => {
       Block.from("C15"),
       Block.from("C16")
     ])
-    const switcher = new BlockchainSwitcher(bc, sbx)
+    const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize)
     switcher.tryToFork()
     assert.equal(bc.current.number, 13)
     assert.equal(bc.current.hash, "B13")
@@ -176,7 +177,7 @@ describe("Fork resolution 3-3 algo", () => {
       Block.from("D16"),
       Block.from("D17")
     ])
-    const switcher = new BlockchainSwitcher(bc, sbx)
+    const switcher = new Switcher(new TestingSwitcherDao(bc, sbx), avgGenTime, forkWindowSize)
     switcher.tryToFork()
     assert.equal(bc.current.number, 17)
     assert.equal(bc.current.hash, "D17")
@@ -186,100 +187,50 @@ describe("Fork resolution 3-3 algo", () => {
 const avgGenTime = 5 * 60
 const forkWindowSize = 3
 
-class BlockchainSwitcher {
+class TestingSwitcherDao implements SwitcherDao {
 
-  constructor(private bc:Blockchain, private sbx:BlockSandbox) {}
-
-  tryToFork() {
-    const current = this.bc.current
-    const numberStart = current.number + 3
-    const timeStart = current.time + 3*avgGenTime
-    const suites:Block[][] = []
-    const potentials:Block[] = this.sbx.getPotentials(numberStart, timeStart)
-    const invalids: { [hash:string]: Block } = {}
-    // Phase 1: find chains
-    for (const candidate of potentials) {
-      const suite:Block[] = []
-      if (!invalids[candidate.hash] && !BlockchainSwitcher.suitesContains(suites, candidate)) {
-        let previous:Block|null = candidate, commonRootFound = false
-        while (previous && previous.number > current.number - forkWindowSize) {
-          suite.push(previous)
-          const previousNumber = previous.number - 1
-          const previousHash = previous.previousHash
-          previous = this.bc.getBlock(previousNumber, previousHash)
-          if (previous) {
-            // Stop the loop: common block has been found
-            previous = null
-            suites.push(suite)
-            commonRootFound = true
-          } else {
-            // Have a look in sandboxes
-            previous = this.sbx.getBlock(previousNumber, previousHash)
-          }
-        }
-        // Forget about invalid blocks
-        if (!commonRootFound) {
-          for (const b of suite) {
-            invalids[b.hash] = b
-          }
-        }
-      }
-    }
-    // Phase 2: select the best chain
-    let longestChain:null|Block[] = null
-    for (const s of suites) {
-      s.reverse()
-      const reverted = this.bc.revertTo(s[0].number - 1)
-      let added = true, i = 0, successfulBlocks:Block[] = []
-      while (added) {
-        try {
-          this.bc.add(s[i])
-          successfulBlocks.push(s[i])
-        } catch (e) {
-          added = false
-        }
-        i++
-      }
-      if (successfulBlocks.length) {
-        this.bc.revertTo(this.bc.current.number - successfulBlocks.length)
-      }
-      reverted.reverse()
-      for (const b of reverted) {
-        this.bc.add(b)
-      }
-      if ((!longestChain && successfulBlocks.length > 0) || (longestChain && longestChain.length < successfulBlocks.length)) {
-        longestChain = successfulBlocks
-      }
-    }
-    // Phase 3: a best exist? apply it if it respects the 3-3 rule
-    if (longestChain) {
-      const b = longestChain[longestChain.length - 1]
-      if (b.number >= numberStart && b.time >= timeStart) {
-        this.bc.revertTo(longestChain[0].number - 1)
-        for (const b of longestChain) {
-          this.bc.add(b)
-        }
-      }
-    }
+  getCurrent(): SwitchBlock {
     return this.bc.current
   }
 
-  static suitesContains(suites:Block[][], block:Block) {
-    for (const suite of suites) {
-      for (const b of suite) {
-        if (b.number === block.number && b.hash === block.hash) {
-          return true
-        }
-      }
-    }
-    return false
+  getPotentials(numberStart:number, timeStart:number) {
+    return this.sbx.getPotentials(numberStart, timeStart)
   }
+
+
+  getBlockchainBlock(number: number, hash: string): SwitchBlock|null {
+    return this.bc.getBlock(number, hash)
+  }
+
+
+  getSandboxBlock(number: number, hash: string): SwitchBlock | any {
+    return this.sbx.getBlock(number, hash)
+  }
+
+  revertTo(number: number): SwitchBlock[] {
+    return this.bc.revertTo(number)
+  }
+
+  addBlock(block: Block): SwitchBlock {
+    return this.bc.add(block)
+  }
+
+  constructor(private bc:Blockchain, private sbx:BlockSandbox) {}
 }
 
+/**
+ * A super simple sandbox for new blocks.
+ */
 class BlockSandbox {
 
   constructor(private blocks:Block[] = []) {}
 
+  /**
+   * Gets a particular block.
+   * @param number The block number.
+   * @param {hash} hash The block hash.
+   * @returns The block or null if it was not found.
+   */
   getBlock(number:number, hash:string) {
     for (const b of this.blocks) {
       if (b.number === number && b.hash === hash) {
@@ -289,10 +240,16 @@ class BlockSandbox {
     return null
   }
 
+  /**
+   * Retrieves all the candidate blocks for the switch.
+   * @param numberStart Will pick blocks whose number >= numberStart
+   * @param timeStart
+   * @returns The candidate blocks.
+   */
   getPotentials(numberStart:number, timeStart:number) {
     const potentials = []
     for (const b of this.blocks) {
-      if (b.number >= numberStart && b.time >= timeStart) {
+      if (b.number >= numberStart && b.medianTime >= timeStart) {
         potentials.push(b)
       }
     }
@@ -300,19 +257,34 @@ class BlockSandbox {
   }
 }
 
-
+/**
+ * A super simple blockchain
+ */
 class Blockchain {
 
   private blocks:Block[] = []
 
+  /**
+   * The root block of the blockchain (does not need to have number `0`).
+   * @param {Block} rootBlock
+   */
   constructor(rootBlock:Block) {
     this.blocks.push(rootBlock)
   }
 
+  /**
+   * Returns the current block (HEAD) of the blockchain.
+   * @returns {Block}
+   */
   get current() {
     return this.blocks[this.blocks.length - 1]
   }
 
+  /**
+   * Adds a block on top of HEAD.
+   * @param {Block} block
+   * @returns {Block}
+   */
   add(block:Block) {
     if (!block.chainsOn(this.current)) {
       throw "Unchainable"
@@ -321,6 +293,12 @@ class Blockchain {
     return block
   }
 
+  /**
+   * Gets a particular block.
+   * @param number The block number.
+   * @param hash The block hash.
+   * @returns The block or null if it was not found.
+   */
   getBlock(number:number, hash:string) {
     for (const b of this.blocks) {
       if (b.number === number && b.hash === hash) {
@@ -330,6 +308,11 @@ class Blockchain {
     return null
   }
 
+  /**
+   * Pops blocks from HEAD to HEAD - number.
+   * @param number The block number that will be our new HEAD.
+   * @returns {Block[]}
+   */
   revertTo(number:number) {
     const reverted:Block[] = []
     if (this.current.number < number) {
@@ -343,7 +326,7 @@ class Blockchain {
   }
 }
 
-class Block {
+class Block implements SwitchBlock {
 
   private constructor(public chain:string, public number:number, private thePreviousHash:string, private chainsOnHook: (previous:Block)=>boolean = () => true) {
   }
@@ -352,7 +335,7 @@ class Block {
     return [this.chain, this.number].join('')
   }
 
-  get time() {
+  get medianTime() {
     return this.number * avgGenTime
   }