diff --git a/bfa_client/src/client/bfa_client.go b/bfa_client/src/client/bfa_client.go
index 2b11e791afb3f13dbe54bb6c871a4cedf18c85f1..76ba39e9b991a9b9124b067c06cebece7ecd73ae 100644
--- a/bfa_client/src/client/bfa_client.go
+++ b/bfa_client/src/client/bfa_client.go
@@ -11,10 +11,12 @@ import (
 	"sort"
 	"strconv"
 	"strings"
+	"time"
 )
 
 const (
-	latest = -1
+	latest     = -1
+	minSigners = 5
 )
 
 type Node = bfa.Node
@@ -42,7 +44,7 @@ func updateURL(url string) (updated string) {
 		defaultHTTP = "http://localhost:8545"
 	)
 	if url != "" { // We accept the user selected URL
-		return
+		return url
 	}
 	// First, we try IPC
 	updated = defaultIPC
@@ -102,11 +104,43 @@ func proposals() {
 	}
 }
 
+func parseFormatString(s string) (format string) {
+	replacements := []struct {
+		old string
+		new string
+	}{
+		{"YYYY", "2006"},
+		{"YYY", "006"},
+		{"YY", "06"},
+		{"MM", "01"},
+		{"DD", "02"},
+		{"hh", "15"},
+		{"mm", "04"},
+		{"ss", "05"},
+	}
+	switch s {
+	case "long":
+		return "2006-01-02 15:04:05"
+	case "short":
+		return "15:04:05"
+	case "unix":
+		return time.UnixDate
+	case "rfc3339":
+		return time.RFC3339
+	}
+	format = s
+	for _, repl := range replacements {
+		format = strings.Replace(format, repl.old, repl.new, 1)
+	}
+	return
+}
+
 func sealers() {
 	var (
 		blockNumber int64
 		status      bool
 		timestamp   bool
+		format      string
 		length      int64 = 10 // timestamp length
 	)
 	description = "Presenta la lista de selladores. Opcionalmente indica el último bloque sellado por cada uno."
@@ -114,11 +148,13 @@ func sealers() {
 	flags.Int64Var(&blockNumber, "block-number", latest, "Número del bloque en el cual se quiere conocer la lista de selladores (-1 para el último)")
 	flags.BoolVar(&status, "status", false, "Indica el último bloque sellado por cada sellador, o 0 si un nodo no ha sellado en las últimas 5 rondas.")
 	flags.BoolVar(&timestamp, "timestamp", false, "Muestra el timestamp del sellado en lugar del número de bloque.")
+	flags.StringVar(&format, "format", "", "Formato del timestamp. Ignorado en formato json. Opciones: 'unix', 'rfc3339', 'long' ('YYYY-MM-DD hh:mm:ss'), 'short' ('hh:mm:ss') o un formato específico. Ejemplo 'DD/MM/YY hh.mm.ss'. También se admite el formato del paquete 'time' de go.")
 	parseFlags()
 	if blockNumber == 0 {
 		panic("El bloque génesis no tiene firmantes")
 	}
 	url = updateURL(url)
+	fmt.Println(url)
 	node, err := bfa.Dial(url)
 	util.Check(err)
 	defer node.Close()
@@ -134,16 +170,27 @@ func sealers() {
 		}
 		sort.Slice(list, func(i, j int) bool { return sealers[list[i]].LastBlock > sealers[list[j]].LastBlock })
 		if !timestamp {
+
 			length = util.Max(2, int64(len(strconv.FormatInt(sealers[list[0]].LastBlock, 10))))
+		} else {
+			if len(format) > 0 {
+				format = parseFormatString(format)
+				length = int64(len(format))
+			}
 		}
 		for _, sealer := range list {
 			var output interface{}
 			if timestamp {
-				output = sealers[sealer].Time
+				t := int64(sealers[sealer].Time)
+				if len(format) > 0 && t > 0 {
+					output = time.Unix(t, 0).Format(format)
+				} else {
+					output = t
+				}
 			} else {
 				output = sealers[sealer].LastBlock
 			}
-			fmt.Printf("%v: %*d\n", sealer, length, output)
+			fmt.Printf("%v: %*v\n", sealer, length, output)
 		}
 	} else {
 		sealers := node.GetSignersAtBlock(blockNumber)
@@ -160,28 +207,30 @@ func sealers() {
 
 func propose() {
 	var (
-		all       bool
+		auto      bool
 		authorize bool
 		proposals []string
 	)
 	description = "Vota por una propuesta."
 	otherArgs = "[propuesta...]"
 	setFlags()
-	flags.BoolVar(&all, "all", false, "Vota en todas las propuestas activas")
-	flags.BoolVar(&authorize, "authorize", true, "Sentido del voto (true: a favor, false: en contra)")
+	flags.BoolVar(&auto, "auto", false, "Vota en todas las propuestas activas, en el sentido que corresponda.")
+	flags.BoolVar(&authorize, "authorize", true, "Sentido del voto (true: a favor, false: en contra).")
 	parseFlags()
 	url = updateURL(url)
 	node, err := bfa.Dial(url)
 	util.Check(err)
 	defer node.Close()
+	genesisSigners := node.GetSignersAtBlock(0)
 	util.PanicIf(!node.IsSealer(bfa.Self), "Solo los selladores pueden votar")
-	if all {
-		votes := node.GetVotes(latest)
+	votes := node.GetVotes(latest)
+	if auto {
 		for _, proposal := range votes.Proposals {
+			util.PanicIf(util.Contains(genesisSigners, proposal) && node.IsSealer(proposal), "No se puede quitar en forma automática a un sellador del bloque génesis.")
 			proposals = append(proposals, proposal)
 		}
 		if flags.NArg() != 0 {
-			fmt.Fprintf(os.Stderr, "Se especificó -all. Ignorando argumentos adicionales.")
+			fmt.Fprintf(os.Stderr, "Se especificó -auto. Ignorando argumentos adicionales.")
 		}
 	} else {
 		if flags.NArg() == 0 {
@@ -192,8 +241,11 @@ func propose() {
 			if !util.IsAddress(address) {
 				panic(fmt.Sprintf("'%v' no es una dirección válida", address))
 			}
+			if _, ok := votes.Tally[address]; ok {
+				continue // address is in a proposal, so we allow voting either way
+			}
 			isSealer := node.IsSealer(address)
-			switch {
+			switch { // address is not in a proposal, we allow removing signers or adding non signers
 			case isSealer && authorize:
 				panic(fmt.Sprintf("'%v' ya es un sellador", address))
 			case !isSealer && !authorize:
@@ -202,7 +254,12 @@ func propose() {
 			proposals = append(proposals, flags.Arg(i))
 		}
 	}
+	self, err := node.Coinbase()
+	util.Check(err)
 	for _, proposal := range proposals {
+		util.PanicIf(proposal == self, "No es válido votarse a sí mismo")
+		authorize = !node.IsSealer(proposal)
+		util.PanicIf(len(node.GetSigners()) <= minSigners && !authorize, "Hay sólo %v selladores. No se permite eliminar más selladores.", minSigners)
 		node.Propose(proposal, authorize)
 		fmt.Printf("Voto por %v: %v\n", proposal, authorize)
 	}