diff --git a/txs/events.go b/txs/events.go
deleted file mode 100644
index 6c634d18386d41b7596b310483fdf9c7acdb6896..0000000000000000000000000000000000000000
--- a/txs/events.go
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2017 Monax Industries Limited
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package txs
-
-import (
-	"fmt"
-	"time"
-
-	. "github.com/hyperledger/burrow/word256"
-
-	"github.com/tendermint/go-wire"
-	tm_types "github.com/tendermint/tendermint/types" // Block
-)
-
-// Functions to generate eventId strings
-
-func EventStringAccInput(addr []byte) string    { return fmt.Sprintf("Acc/%X/Input", addr) }
-func EventStringAccOutput(addr []byte) string   { return fmt.Sprintf("Acc/%X/Output", addr) }
-func EventStringAccCall(addr []byte) string     { return fmt.Sprintf("Acc/%X/Call", addr) }
-func EventStringLogEvent(addr []byte) string    { return fmt.Sprintf("Log/%X", addr) }
-func EventStringPermissions(name string) string { return fmt.Sprintf("Permissions/%s", name) }
-func EventStringNameReg(name string) string     { return fmt.Sprintf("NameReg/%s", name) }
-func EventStringBond() string                   { return "Bond" }
-func EventStringUnbond() string                 { return "Unbond" }
-func EventStringRebond() string                 { return "Rebond" }
-func EventStringDupeout() string                { return "Dupeout" }
-func EventStringNewBlock() string               { return "NewBlock" }
-func EventStringFork() string                   { return "Fork" }
-
-func EventStringNewRound() string         { return fmt.Sprintf("NewRound") }
-func EventStringTimeoutPropose() string   { return fmt.Sprintf("TimeoutPropose") }
-func EventStringCompleteProposal() string { return fmt.Sprintf("CompleteProposal") }
-func EventStringPolka() string            { return fmt.Sprintf("Polka") }
-func EventStringUnlock() string           { return fmt.Sprintf("Unlock") }
-func EventStringLock() string             { return fmt.Sprintf("Lock") }
-func EventStringRelock() string           { return fmt.Sprintf("Relock") }
-func EventStringTimeoutWait() string      { return fmt.Sprintf("TimeoutWait") }
-func EventStringVote() string             { return fmt.Sprintf("Vote") }
-
-//----------------------------------------
-
-const (
-	EventDataTypeNewBlock       = byte(0x01)
-	EventDataTypeFork           = byte(0x02)
-	EventDataTypeTx             = byte(0x03)
-	EventDataTypeCall           = byte(0x04)
-	EventDataTypeLog            = byte(0x05)
-	EventDataTypeNewBlockHeader = byte(0x06)
-
-	EventDataTypeRoundState = byte(0x11)
-	EventDataTypeVote       = byte(0x12)
-)
-
-type EventData interface {
-	AssertIsEventData()
-}
-
-var _ = wire.RegisterInterface(
-	struct{ EventData }{},
-	wire.ConcreteType{EventDataNewBlockHeader{}, EventDataTypeNewBlockHeader},
-	wire.ConcreteType{EventDataNewBlock{}, EventDataTypeNewBlock},
-	// wire.ConcreteType{EventDataFork{}, EventDataTypeFork },
-	wire.ConcreteType{EventDataTx{}, EventDataTypeTx},
-	wire.ConcreteType{EventDataCall{}, EventDataTypeCall},
-	wire.ConcreteType{EventDataLog{}, EventDataTypeLog},
-	wire.ConcreteType{EventDataRoundState{}, EventDataTypeRoundState},
-	wire.ConcreteType{EventDataVote{}, EventDataTypeVote},
-)
-
-// Most event messages are basic types (a block, a transaction)
-// but some (an input to a call tx or a receive) are more exotic
-
-type EventDataNewBlock struct {
-	Block *tm_types.Block `json:"block"`
-}
-
-type EventDataNewBlockHeader struct {
-	Header *tm_types.Header `json:"header"`
-}
-
-// All txs fire EventDataTx, but only CallTx might have Return or Exception
-type EventDataTx struct {
-	Tx        Tx     `json:"tx"`
-	Return    []byte `json:"return"`
-	Exception string `json:"exception"`
-}
-
-// EventDataCall fires when we call a contract, and when a contract calls another contract
-type EventDataCall struct {
-	CallData  *CallData `json:"call_data"`
-	Origin    []byte    `json:"origin"`
-	TxID      []byte    `json:"tx_id"`
-	Return    []byte    `json:"return"`
-	Exception string    `json:"exception"`
-}
-
-type CallData struct {
-	Caller []byte `json:"caller"`
-	Callee []byte `json:"callee"`
-	Data   []byte `json:"data"`
-	Value  int64  `json:"value"`
-	Gas    int64  `json:"gas"`
-}
-
-// EventDataLog fires when a contract executes the LOG opcode
-type EventDataLog struct {
-	Address Word256   `json:"address"`
-	Topics  []Word256 `json:"topics"`
-	Data    []byte    `json:"data"`
-	Height  int64     `json:"height"`
-}
-
-// We fire the most recent round state that led to the event
-// (ie. NewRound will have the previous rounds state)
-type EventDataRoundState struct {
-	CurrentTime time.Time `json:"current_time"`
-
-	Height        int                `json:"height"`
-	Round         int                `json:"round"`
-	Step          string             `json:"step"`
-	StartTime     time.Time          `json:"start_time"`
-	CommitTime    time.Time          `json:"commit_time"`
-	Proposal      *tm_types.Proposal `json:"proposal"`
-	ProposalBlock *tm_types.Block    `json:"proposal_block"`
-	LockedRound   int                `json:"locked_round"`
-	LockedBlock   *tm_types.Block    `json:"locked_block"`
-	POLRound      int                `json:"pol_round"`
-}
-
-type EventDataVote struct {
-	Index   int
-	Address []byte
-	Vote    *tm_types.Vote
-}
-
-func (_ EventDataNewBlock) AssertIsEventData()       {}
-func (_ EventDataNewBlockHeader) AssertIsEventData() {}
-func (_ EventDataTx) AssertIsEventData()             {}
-func (_ EventDataCall) AssertIsEventData()           {}
-func (_ EventDataLog) AssertIsEventData()            {}
-func (_ EventDataRoundState) AssertIsEventData()     {}
-func (_ EventDataVote) AssertIsEventData()           {}
diff --git a/txs/go_wire_codec.go b/txs/go_wire_codec.go
new file mode 100644
index 0000000000000000000000000000000000000000..ebedfcf7bc1d699d4d72a8238f493ccc4eb47de6
--- /dev/null
+++ b/txs/go_wire_codec.go
@@ -0,0 +1,53 @@
+package txs
+
+import (
+	"bytes"
+	"sync"
+
+	"github.com/tendermint/go-wire"
+)
+
+type goWireCodec struct {
+	// Worth it? Possibly not, but we need to instantiate a codec though so...
+	bufferPool sync.Pool
+}
+
+func NewGoWireCodec() *goWireCodec {
+	return &goWireCodec{
+		bufferPool: sync.Pool{
+			New: func() interface{} {
+				return new(bytes.Buffer)
+			},
+		},
+	}
+}
+
+func (gwc *goWireCodec) EncodeTx(tx Tx) ([]byte, error) {
+	var n int
+	var err error
+	buf := gwc.bufferPool.Get().(*bytes.Buffer)
+	defer gwc.recycle(buf)
+	wire.WriteBinary(struct{ Tx }{tx}, buf, &n, &err)
+	if err != nil {
+		return nil, err
+	}
+	return buf.Bytes(), nil
+}
+
+// panic on err
+func (gwc *goWireCodec) DecodeTx(txBytes []byte) (Tx, error) {
+	var n int
+	var err error
+	tx := new(Tx)
+	buf := bytes.NewBuffer(txBytes)
+	wire.ReadBinaryPtr(tx, buf, len(txBytes), &n, &err)
+	if err != nil {
+		return nil, err
+	}
+	return *tx, nil
+}
+
+func (gwc *goWireCodec) recycle(buf *bytes.Buffer) {
+	buf.Reset()
+	gwc.bufferPool.Put(buf)
+}
diff --git a/txs/go_wire_codec_test.go b/txs/go_wire_codec_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..7e191c19e6d5818b296064b27cda244780ddea9f
--- /dev/null
+++ b/txs/go_wire_codec_test.go
@@ -0,0 +1,59 @@
+package txs
+
+import (
+	"testing"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestEncodeTxDecodeTx(t *testing.T) {
+	gwc := NewGoWireCodec()
+	inputAddress := acm.Address{1, 2, 3, 4, 5}
+	outputAddress := acm.Address{5, 4, 3, 2, 1}
+	amount := uint64(2)
+	sequence := uint64(3)
+	tx := &SendTx{
+		Inputs: []*TxInput{{
+			Address:  inputAddress,
+			Amount:   amount,
+			Sequence: sequence,
+		}},
+		Outputs: []*TxOutput{{
+			Address: outputAddress,
+			Amount:  amount,
+		}},
+	}
+	txBytes, err := gwc.EncodeTx(tx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	txOut, err := gwc.DecodeTx(txBytes)
+	assert.NoError(t, err, "DecodeTx error")
+	assert.Equal(t, tx, txOut)
+}
+
+func TestEncodeTxDecodeTx_CallTx(t *testing.T) {
+	gwc := NewGoWireCodec()
+	inputAddress := acm.Address{1, 2, 3, 4, 5}
+	amount := uint64(2)
+	sequence := uint64(3)
+	tx := &CallTx{
+		Input: &TxInput{
+			Address:  inputAddress,
+			Amount:   amount,
+			Sequence: sequence,
+		},
+		GasLimit: 233,
+		Fee:      2,
+		Address:  nil,
+		Data:     []byte("code"),
+	}
+	txBytes, err := gwc.EncodeTx(tx)
+	if err != nil {
+		t.Fatal(err)
+	}
+	txOut, err := gwc.DecodeTx(txBytes)
+	assert.NoError(t, err, "DecodeTx error")
+	assert.Equal(t, tx, txOut)
+}
diff --git a/txs/names.go b/txs/names.go
index 6535bf7656870219e56dafa106cd254a80756e0d..23c693f0a1a8db9a6c6c559f30f601092482db99 100644
--- a/txs/names.go
+++ b/txs/names.go
@@ -16,20 +16,18 @@ package txs
 
 import (
 	"regexp"
-
-	core_types "github.com/hyperledger/burrow/core/types"
 )
 
 var (
-	MinNameRegistrationPeriod int = 5
+	MinNameRegistrationPeriod uint64 = 5
 
 	// NOTE: base costs and validity checks are here so clients
 	// can use them without importing state
 
 	// cost for storing a name for a block is
 	// CostPerBlock*CostPerByte*(len(data) + 32)
-	NameByteCostMultiplier  int64 = 1
-	NameBlockCostMultiplier int64 = 1
+	NameByteCostMultiplier  uint64 = 1
+	NameBlockCostMultiplier uint64 = 1
 
 	MaxNameLength = 64
 	MaxDataLength = 1 << 16
@@ -50,16 +48,10 @@ func validateNameRegEntryData(data string) bool {
 }
 
 // base cost is "effective" number of bytes
-func NameBaseCost(name, data string) int64 {
-	return int64(len(data) + 32)
+func NameBaseCost(name, data string) uint64 {
+	return uint64(len(data) + 32)
 }
 
-func NameCostPerBlock(baseCost int64) int64 {
+func NameCostPerBlock(baseCost uint64) uint64 {
 	return NameBlockCostMultiplier * NameByteCostMultiplier * baseCost
 }
-
-// XXX: vestige of an older time
-type ResultListNames struct {
-	BlockHeight int                        `json:"block_height"`
-	Names       []*core_types.NameRegEntry `json:"names"`
-}
diff --git a/txs/tx.go b/txs/tx.go
index 44cd1b1056dadd93225cad00f904d110039d684e..1cb2ea1b40e654562bc09457bfd78ff182edc064 100644
--- a/txs/tx.go
+++ b/txs/tx.go
@@ -15,32 +15,27 @@
 package txs
 
 import (
-	"bytes"
 	"encoding/json"
 	"errors"
+	"fmt"
 	"io"
 
-	"golang.org/x/crypto/ripemd160"
-
 	acm "github.com/hyperledger/burrow/account"
-	ptypes "github.com/hyperledger/burrow/permission/types"
-	. "github.com/tendermint/go-common"
-	"github.com/tendermint/go-wire"
-
+	ptypes "github.com/hyperledger/burrow/permission"
 	"github.com/tendermint/go-crypto"
-	tendermint_types "github.com/tendermint/tendermint/types" // votes for dupeout ..
+	"github.com/tendermint/go-wire"
+	"github.com/tendermint/go-wire/data"
+	"golang.org/x/crypto/ripemd160"
 )
 
 var (
-	ErrTxInvalidAddress       = errors.New("Error invalid address")
-	ErrTxDuplicateAddress     = errors.New("Error duplicate address")
-	ErrTxInvalidAmount        = errors.New("Error invalid amount")
-	ErrTxInsufficientFunds    = errors.New("Error insufficient funds")
-	ErrTxInsufficientGasPrice = errors.New("Error insufficient gas price")
-	ErrTxUnknownPubKey        = errors.New("Error unknown pubkey")
-	ErrTxInvalidPubKey        = errors.New("Error invalid pubkey")
-	ErrTxInvalidSignature     = errors.New("Error invalid signature")
-	ErrTxPermissionDenied     = errors.New("Error permission denied")
+	ErrTxInvalidAddress    = errors.New("error invalid address")
+	ErrTxDuplicateAddress  = errors.New("error duplicate address")
+	ErrTxInvalidAmount     = errors.New("error invalid amount")
+	ErrTxInsufficientFunds = errors.New("error insufficient funds")
+	ErrTxUnknownPubKey     = errors.New("error unknown pubkey")
+	ErrTxInvalidPubKey     = errors.New("error invalid pubkey")
+	ErrTxInvalidSignature  = errors.New("error invalid signature")
 )
 
 type ErrTxInvalidString struct {
@@ -52,12 +47,12 @@ func (e ErrTxInvalidString) Error() string {
 }
 
 type ErrTxInvalidSequence struct {
-	Got      int
-	Expected int
+	Got      uint64
+	Expected uint64
 }
 
 func (e ErrTxInvalidSequence) Error() string {
-	return Fmt("Error invalid sequence. Got %d, expected %d", e.Got, e.Expected)
+	return fmt.Sprintf("Error invalid sequence. Got %d, expected %d", e.Got, e.Expected)
 }
 
 /*
@@ -71,7 +66,6 @@ Account Txs:
 Validation Txs:
  - BondTx         New validator posts a bond
  - UnbondTx       Validator leaves
- - DupeoutTx      Validator dupes out (equivocates)
 
 Admin Txs:
  - PermissionsTx
@@ -85,27 +79,22 @@ const (
 	TxTypeName = byte(0x03)
 
 	// Validation transactions
-	TxTypeBond    = byte(0x11)
-	TxTypeUnbond  = byte(0x12)
-	TxTypeRebond  = byte(0x13)
-	TxTypeDupeout = byte(0x14)
+	TxTypeBond   = byte(0x11)
+	TxTypeUnbond = byte(0x12)
+	TxTypeRebond = byte(0x13)
 
 	// Admin transactions
-	TxTypePermissions = byte(0x20)
+	TxTypePermissions = byte(0x1f)
 )
 
-// for wire.readReflect
-var _ = wire.RegisterInterface(
-	struct{ Tx }{},
-	wire.ConcreteType{&SendTx{}, TxTypeSend},
-	wire.ConcreteType{&CallTx{}, TxTypeCall},
-	wire.ConcreteType{&NameTx{}, TxTypeName},
-	wire.ConcreteType{&BondTx{}, TxTypeBond},
-	wire.ConcreteType{&UnbondTx{}, TxTypeUnbond},
-	wire.ConcreteType{&RebondTx{}, TxTypeRebond},
-	wire.ConcreteType{&DupeoutTx{}, TxTypeDupeout},
-	wire.ConcreteType{&PermissionsTx{}, TxTypePermissions},
-)
+var mapper = data.NewMapper(Wrapper{}).
+	RegisterImplementation(&SendTx{}, "send_tx", TxTypeSend).
+	RegisterImplementation(&CallTx{}, "call_tx", TxTypeCall).
+	RegisterImplementation(&NameTx{}, "name_tx", TxTypeName).
+	RegisterImplementation(&BondTx{}, "bond_tx", TxTypeBond).
+	RegisterImplementation(&UnbondTx{}, "unbond_tx", TxTypeUnbond).
+	RegisterImplementation(&RebondTx{}, "rebond_tx", TxTypeRebond).
+	RegisterImplementation(&PermissionsTx{}, "permissions_tx", TxTypePermissions)
 
 //-----------------------------------------------------------------------------
 
@@ -114,6 +103,18 @@ type (
 		WriteSignBytes(chainID string, w io.Writer, n *int, err *error)
 	}
 
+	Wrapper struct {
+		Tx `json:"unwrap"`
+	}
+
+	Encoder interface {
+		EncodeTx(tx Tx) ([]byte, error)
+	}
+
+	Decoder interface {
+		DecodeTx(txBytes []byte) (Tx, error)
+	}
+
 	// UnconfirmedTxs
 	UnconfirmedTxs struct {
 		Txs []Tx `json:"txs"`
@@ -126,40 +127,73 @@ type (
 
 	// BroadcastTx or Transact
 	Receipt struct {
-		TxHash          []byte `json:"tx_hash"`
-		CreatesContract uint8  `json:"creates_contract"`
-		ContractAddr    []byte `json:"contract_addr"`
+		TxHash          []byte      `json:"tx_hash"`
+		CreatesContract bool        `json:"creates_contract"`
+		ContractAddr    acm.Address `json:"contract_addr"`
 	}
 
 	NameTx struct {
 		Input *TxInput `json:"input"`
 		Name  string   `json:"name"`
 		Data  string   `json:"data"`
-		Fee   int64    `json:"fee"`
+		Fee   uint64   `json:"fee"`
 	}
 
 	CallTx struct {
-		Input    *TxInput `json:"input"`
-		Address  []byte   `json:"address"`
-		GasLimit int64    `json:"gas_limit"`
-		Fee      int64    `json:"fee"`
-		Data     []byte   `json:"data"`
+		Input *TxInput `json:"input"`
+		// Pointer since CallTx defines unset 'to' address as inducing account creation
+		Address  *acm.Address `json:"address"`
+		GasLimit uint64       `json:"gas_limit"`
+		Fee      uint64       `json:"fee"`
+		Data     []byte       `json:"data"`
 	}
 
 	TxInput struct {
-		Address   []byte           `json:"address"`   // Hash of the PubKey
-		Amount    int64            `json:"amount"`    // Must not exceed account balance
-		Sequence  int              `json:"sequence"`  // Must be 1 greater than the last committed TxInput
-		Signature crypto.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx
-		PubKey    crypto.PubKey    `json:"pub_key"`   // Must not be nil, may be nil
+		Address   acm.Address      `json:"address"`   // Hash of the PublicKey
+		Amount    uint64           `json:"amount"`    // Must not exceed account balance
+		Sequence  uint64           `json:"sequence"`  // Must be 1 greater than the last committed TxInput
+		Signature crypto.Signature `json:"signature"` // Depends on the PublicKey type and the whole Tx
+		PubKey    acm.PublicKey    `json:"pub_key"`   // Must not be nil, may be nil
 	}
 
 	TxOutput struct {
-		Address []byte `json:"address"` // Hash of the PubKey
-		Amount  int64  `json:"amount"`  // The sum of all outputs must not exceed the inputs.
+		Address acm.Address `json:"address"` // Hash of the PublicKey
+		Amount  uint64      `json:"amount"`  // The sum of all outputs must not exceed the inputs.
 	}
 )
 
+// Wrap the Tx in a struct that allows for go-wire JSON serialisation
+func Wrap(tx Tx) Wrapper {
+	if txWrapped, ok := tx.(Wrapper); ok {
+		return txWrapped
+	}
+	return Wrapper{
+		Tx: tx,
+	}
+}
+
+// A serialisation wrapper that is itself a Tx
+func (txw Wrapper) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
+	txw.Tx.WriteSignBytes(chainID, w, n, err)
+}
+
+func (txw Wrapper) MarshalJSON() ([]byte, error) {
+	return mapper.ToJSON(txw.Tx)
+}
+
+func (txw *Wrapper) UnmarshalJSON(data []byte) (err error) {
+	parsed, err := mapper.FromJSON(data)
+	if err == nil && parsed != nil {
+		txw.Tx = parsed.(Tx)
+	}
+	return err
+}
+
+// Get the inner Tx that this Wrapper wraps
+func (txw *Wrapper) Unwrap() Tx {
+	return txw.Tx
+}
+
 func (txIn *TxInput) ValidateBasic() error {
 	if len(txIn.Address) != 20 {
 		return ErrTxInvalidAddress
@@ -171,11 +205,11 @@ func (txIn *TxInput) ValidateBasic() error {
 }
 
 func (txIn *TxInput) WriteSignBytes(w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v,"sequence":%v}`, txIn.Address, txIn.Amount, txIn.Sequence)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`{"address":"%s","amount":%v,"sequence":%v}`, txIn.Address, txIn.Amount, txIn.Sequence)), w, n, err)
 }
 
 func (txIn *TxInput) String() string {
-	return Fmt("TxInput{%X,%v,%v,%v,%v}", txIn.Address, txIn.Amount, txIn.Sequence, txIn.Signature, txIn.PubKey)
+	return fmt.Sprintf("TxInput{%s,%v,%v,%v,%v}", txIn.Address, txIn.Amount, txIn.Sequence, txIn.Signature, txIn.PubKey)
 }
 
 //-----------------------------------------------------------------------------
@@ -191,18 +225,18 @@ func (txOut *TxOutput) ValidateBasic() error {
 }
 
 func (txOut *TxOutput) WriteSignBytes(w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v}`, txOut.Address, txOut.Amount)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`{"address":"%s","amount":%v}`, txOut.Address, txOut.Amount)), w, n, err)
 }
 
 func (txOut *TxOutput) String() string {
-	return Fmt("TxOutput{%X,%v}", txOut.Address, txOut.Amount)
+	return fmt.Sprintf("TxOutput{%s,%v}", txOut.Address, txOut.Amount)
 }
 
 //-----------------------------------------------------------------------------
 
 func (tx *SendTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err)
 	for i, in := range tx.Inputs {
 		in.WriteSignBytes(w, n, err)
 		if i != len(tx.Inputs)-1 {
@@ -220,40 +254,31 @@ func (tx *SendTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error
 }
 
 func (tx *SendTx) String() string {
-	return Fmt("SendTx{%v -> %v}", tx.Inputs, tx.Outputs)
+	return fmt.Sprintf("SendTx{%v -> %v}", tx.Inputs, tx.Outputs)
 }
 
 //-----------------------------------------------------------------------------
 
 func (tx *CallTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err)
-	wire.WriteTo([]byte(Fmt(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err)
 	tx.Input.WriteSignBytes(w, n, err)
 	wire.WriteTo([]byte(`}]}`), w, n, err)
 }
 
 func (tx *CallTx) String() string {
-	return Fmt("CallTx{%v -> %x: %x}", tx.Input, tx.Address, tx.Data)
-}
-
-func NewContractAddress(caller []byte, nonce int) []byte {
-	temp := make([]byte, 32+8)
-	copy(temp, caller)
-	PutInt64BE(temp[32:], int64(nonce))
-	hasher := ripemd160.New()
-	hasher.Write(temp) // does not error
-	return hasher.Sum(nil)
+	return fmt.Sprintf("CallTx{%v -> %s: %X}", tx.Input, tx.Address, tx.Data)
 }
 
 //-----------------------------------------------------------------------------
 
 func (tx *NameTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"data":%s,"fee":%v`, TxTypeName, jsonEscape(tx.Data), tx.Fee)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"data":%s,"fee":%v`, TxTypeName, jsonEscape(tx.Data), tx.Fee)), w, n, err)
 	wire.WriteTo([]byte(`,"input":`), w, n, err)
 	tx.Input.WriteSignBytes(w, n, err)
-	wire.WriteTo([]byte(Fmt(`,"name":%s`, jsonEscape(tx.Name))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"name":%s`, jsonEscape(tx.Name))), w, n, err)
 	wire.WriteTo([]byte(`}]}`), w, n, err)
 }
 
@@ -262,46 +287,46 @@ func (tx *NameTx) ValidateStrings() error {
 		return ErrTxInvalidString{"Name must not be empty"}
 	}
 	if len(tx.Name) > MaxNameLength {
-		return ErrTxInvalidString{Fmt("Name is too long. Max %d bytes", MaxNameLength)}
+		return ErrTxInvalidString{fmt.Sprintf("Name is too long. Max %d bytes", MaxNameLength)}
 	}
 	if len(tx.Data) > MaxDataLength {
-		return ErrTxInvalidString{Fmt("Data is too long. Max %d bytes", MaxDataLength)}
+		return ErrTxInvalidString{fmt.Sprintf("Data is too long. Max %d bytes", MaxDataLength)}
 	}
 
 	if !validateNameRegEntryName(tx.Name) {
-		return ErrTxInvalidString{Fmt("Invalid characters found in NameTx.Name (%s). Only alphanumeric, underscores, dashes, forward slashes, and @ are allowed", tx.Name)}
+		return ErrTxInvalidString{fmt.Sprintf("Invalid characters found in NameTx.Name (%s). Only alphanumeric, underscores, dashes, forward slashes, and @ are allowed", tx.Name)}
 	}
 
 	if !validateNameRegEntryData(tx.Data) {
-		return ErrTxInvalidString{Fmt("Invalid characters found in NameTx.Data (%s). Only the kind of things found in a JSON file are allowed", tx.Data)}
+		return ErrTxInvalidString{fmt.Sprintf("Invalid characters found in NameTx.Data (%s). Only the kind of things found in a JSON file are allowed", tx.Data)}
 	}
 
 	return nil
 }
 
 func (tx *NameTx) String() string {
-	return Fmt("NameTx{%v -> %s: %s}", tx.Input, tx.Name, tx.Data)
+	return fmt.Sprintf("NameTx{%v -> %s: %s}", tx.Input, tx.Name, tx.Data)
 }
 
 //-----------------------------------------------------------------------------
 
 type BondTx struct {
-	PubKey    crypto.PubKeyEd25519    `json:"pub_key"` // NOTE: these don't have type byte
-	Signature crypto.SignatureEd25519 `json:"signature"`
-	Inputs    []*TxInput              `json:"inputs"`
-	UnbondTo  []*TxOutput             `json:"unbond_to"`
+	PubKey    acm.PublicKey    `json:"pub_key"` // NOTE: these don't have type byte
+	Signature crypto.Signature `json:"signature"`
+	Inputs    []*TxInput       `json:"inputs"`
+	UnbondTo  []*TxOutput      `json:"unbond_to"`
 }
 
 func (tx *BondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err)
 	for i, in := range tx.Inputs {
 		in.WriteSignBytes(w, n, err)
 		if i != len(tx.Inputs)-1 {
 			wire.WriteTo([]byte(","), w, n, err)
 		}
 	}
-	wire.WriteTo([]byte(Fmt(`],"pub_key":`)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`],"pub_key":`)), w, n, err)
 	wire.WriteTo(wire.JSONBytes(tx.PubKey), w, n, err)
 	wire.WriteTo([]byte(`,"unbond_to":[`), w, n, err)
 	for i, out := range tx.UnbondTo {
@@ -314,71 +339,53 @@ func (tx *BondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error
 }
 
 func (tx *BondTx) String() string {
-	return Fmt("BondTx{%v: %v -> %v}", tx.PubKey, tx.Inputs, tx.UnbondTo)
+	return fmt.Sprintf("BondTx{%v: %v -> %v}", tx.PubKey, tx.Inputs, tx.UnbondTo)
 }
 
 //-----------------------------------------------------------------------------
 
 type UnbondTx struct {
-	Address   []byte                  `json:"address"`
-	Height    int                     `json:"height"`
-	Signature crypto.SignatureEd25519 `json:"signature"`
+	Address   acm.Address      `json:"address"`
+	Height    int              `json:"height"`
+	Signature crypto.Signature `json:"signature"`
 }
 
 func (tx *UnbondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err)
 }
 
 func (tx *UnbondTx) String() string {
-	return Fmt("UnbondTx{%X,%v,%v}", tx.Address, tx.Height, tx.Signature)
+	return fmt.Sprintf("UnbondTx{%s,%v,%v}", tx.Address, tx.Height, tx.Signature)
 }
 
 //-----------------------------------------------------------------------------
 
 type RebondTx struct {
-	Address   []byte                  `json:"address"`
-	Height    int                     `json:"height"`
-	Signature crypto.SignatureEd25519 `json:"signature"`
+	Address   acm.Address      `json:"address"`
+	Height    int              `json:"height"`
+	Signature crypto.Signature `json:"signature"`
 }
 
 func (tx *RebondTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"address":"%s","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err)
 }
 
 func (tx *RebondTx) String() string {
-	return Fmt("RebondTx{%X,%v,%v}", tx.Address, tx.Height, tx.Signature)
-}
-
-//-----------------------------------------------------------------------------
-
-type DupeoutTx struct {
-	Address []byte                `json:"address"`
-	VoteA   tendermint_types.Vote `json:"vote_a"`
-	VoteB   tendermint_types.Vote `json:"vote_b"`
-}
-
-func (tx *DupeoutTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	// PanicSanity("DupeoutTx has no sign bytes")
-	// TODO
-	// return
-}
-
-func (tx *DupeoutTx) String() string {
-	return Fmt("DupeoutTx{%X,%v,%v}", tx.Address, tx.VoteA, tx.VoteB)
+	return fmt.Sprintf("RebondTx{%s,%v,%v}", tx.Address, tx.Height, tx.Signature)
 }
 
 //-----------------------------------------------------------------------------
 
 type PermissionsTx struct {
 	Input    *TxInput        `json:"input"`
-	PermArgs ptypes.PermArgs `json:"args"`
+	PermArgs *ptypes.PermArgs `json:"args"`
 }
 
 func (tx *PermissionsTx) WriteSignBytes(chainID string, w io.Writer, n *int, err *error) {
-	wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
-	wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"args":"`, TxTypePermissions)), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err)
+	wire.WriteTo([]byte(fmt.Sprintf(`,"tx":[%v,{"args":"`, TxTypePermissions)), w, n, err)
 	wire.WriteJSON(&tx.PermArgs, w, n, err)
 	wire.WriteTo([]byte(`","input":`), w, n, err)
 	tx.Input.WriteSignBytes(w, n, err)
@@ -386,7 +393,7 @@ func (tx *PermissionsTx) WriteSignBytes(chainID string, w io.Writer, n *int, err
 }
 
 func (tx *PermissionsTx) String() string {
-	return Fmt("PermissionsTx{%v -> %v}", tx.Input, tx.PermArgs)
+	return fmt.Sprintf("PermissionsTx{%v -> %v}", tx.Input, tx.PermArgs)
 }
 
 //-----------------------------------------------------------------------------
@@ -401,41 +408,16 @@ func TxHash(chainID string, tx Tx) []byte {
 
 //-----------------------------------------------------------------------------
 
-func EncodeTx(tx Tx) ([]byte, error) {
-	var n int
-	var err error
-	buf := new(bytes.Buffer)
-	wire.WriteBinary(struct{ Tx }{tx}, buf, &n, &err)
-	if err != nil {
-		return nil, err
-	}
-	return buf.Bytes(), nil
-}
-
-// panic on err
-func DecodeTx(txBytes []byte) (Tx, error) {
-	var n int
-	var err error
-	tx := new(Tx)
-	buf := bytes.NewBuffer(txBytes)
-	wire.ReadBinaryPtr(tx, buf, len(txBytes), &n, &err)
-	if err != nil {
-		return nil, err
-	}
-	return *tx, nil
-}
-
 func GenerateReceipt(chainId string, tx Tx) Receipt {
 	receipt := Receipt{
-		TxHash:          TxHash(chainId, tx),
-		CreatesContract: 0,
-		ContractAddr:    nil,
+		TxHash: TxHash(chainId, tx),
 	}
 	if callTx, ok := tx.(*CallTx); ok {
-		if len(callTx.Address) == 0 {
-			receipt.CreatesContract = 1
-			receipt.ContractAddr = NewContractAddress(callTx.Input.Address,
-				callTx.Input.Sequence)
+		receipt.CreatesContract = callTx.Address == nil
+		if receipt.CreatesContract {
+			receipt.ContractAddr = acm.NewContractAddress(callTx.Input.Address, callTx.Input.Sequence)
+		} else {
+			receipt.ContractAddr = *callTx.Address
 		}
 	}
 	return receipt
@@ -447,7 +429,7 @@ func GenerateReceipt(chainId string, tx Tx) Receipt {
 func jsonEscape(str string) string {
 	escapedBytes, err := json.Marshal(str)
 	if err != nil {
-		PanicSanity(Fmt("Error json-escaping a string", str))
+		panic(fmt.Sprintf("error json-escaping a string", str))
 	}
 	return string(escapedBytes)
 }
diff --git a/txs/tx_test.go b/txs/tx_test.go
index ca4b2ff0048278efdb71b55170bbd385d6e3af2e..6bc2f110a832ee7073ca335d5fae594dd1b46322 100644
--- a/txs/tx_test.go
+++ b/txs/tx_test.go
@@ -15,47 +15,53 @@
 package txs
 
 import (
+	"fmt"
 	"testing"
 
-	acm "github.com/hyperledger/burrow/account"
-	ptypes "github.com/hyperledger/burrow/permission/types"
+	"encoding/json"
 
+	acm "github.com/hyperledger/burrow/account"
+	ptypes "github.com/hyperledger/burrow/permission"
 	"github.com/stretchr/testify/assert"
-	. "github.com/tendermint/go-common"
-	"github.com/tendermint/go-crypto"
+	"github.com/stretchr/testify/require"
 )
 
 var chainID = "myChainID"
 
+func makeAddress(str string) (address acm.Address) {
+	copy(address[:], ([]byte)(str))
+	return
+}
+
 func TestSendTxSignable(t *testing.T) {
 	sendTx := &SendTx{
 		Inputs: []*TxInput{
-			&TxInput{
-				Address:  []byte("input1"),
+			{
+				Address:  makeAddress("input1"),
 				Amount:   12345,
 				Sequence: 67890,
 			},
-			&TxInput{
-				Address:  []byte("input2"),
+			{
+				Address:  makeAddress("input2"),
 				Amount:   111,
 				Sequence: 222,
 			},
 		},
 		Outputs: []*TxOutput{
-			&TxOutput{
-				Address: []byte("output1"),
+			{
+				Address: makeAddress("output1"),
 				Amount:  333,
 			},
-			&TxOutput{
-				Address: []byte("output2"),
+			{
+				Address: makeAddress("output2"),
 				Amount:  444,
 			},
 		},
 	}
 	signBytes := acm.SignBytes(chainID, sendTx)
 	signStr := string(signBytes)
-	expected := Fmt(`{"chain_id":"%s","tx":[1,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"outputs":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`,
-		chainID)
+	expected := fmt.Sprintf(`{"chain_id":"%s","tx":[1,{"inputs":[{"address":"%s","amount":12345,"sequence":67890},{"address":"%s","amount":111,"sequence":222}],"outputs":[{"address":"%s","amount":333},{"address":"%s","amount":444}]}]}`,
+		chainID, sendTx.Inputs[0].Address.String(), sendTx.Inputs[1].Address.String(), sendTx.Outputs[0].Address.String(), sendTx.Outputs[1].Address.String())
 
 	if signStr != expected {
 		t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr)
@@ -63,21 +69,22 @@ func TestSendTxSignable(t *testing.T) {
 }
 
 func TestCallTxSignable(t *testing.T) {
+	toAddress := makeAddress("contract1")
 	callTx := &CallTx{
 		Input: &TxInput{
-			Address:  []byte("input1"),
+			Address:  makeAddress("input1"),
 			Amount:   12345,
 			Sequence: 67890,
 		},
-		Address:  []byte("contract1"),
+		Address:  &toAddress,
 		GasLimit: 111,
 		Fee:      222,
 		Data:     []byte("data1"),
 	}
 	signBytes := acm.SignBytes(chainID, callTx)
 	signStr := string(signBytes)
-	expected := Fmt(`{"chain_id":"%s","tx":[2,{"address":"636F6E747261637431","data":"6461746131","fee":222,"gas_limit":111,"input":{"address":"696E70757431","amount":12345,"sequence":67890}}]}`,
-		chainID)
+	expected := fmt.Sprintf(`{"chain_id":"%s","tx":[2,{"address":"%s","data":"6461746131","fee":222,"gas_limit":111,"input":{"address":"%s","amount":12345,"sequence":67890}}]}`,
+		chainID, callTx.Address.String(), callTx.Input.Address.String())
 	if signStr != expected {
 		t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr)
 	}
@@ -86,7 +93,7 @@ func TestCallTxSignable(t *testing.T) {
 func TestNameTxSignable(t *testing.T) {
 	nameTx := &NameTx{
 		Input: &TxInput{
-			Address:  []byte("input1"),
+			Address:  makeAddress("input1"),
 			Amount:   12345,
 			Sequence: 250,
 		},
@@ -96,8 +103,8 @@ func TestNameTxSignable(t *testing.T) {
 	}
 	signBytes := acm.SignBytes(chainID, nameTx)
 	signStr := string(signBytes)
-	expected := Fmt(`{"chain_id":"%s","tx":[3,{"data":"secretly.not.google.com","fee":1000,"input":{"address":"696E70757431","amount":12345,"sequence":250},"name":"google.com"}]}`,
-		chainID)
+	expected := fmt.Sprintf(`{"chain_id":"%s","tx":[3,{"data":"secretly.not.google.com","fee":1000,"input":{"address":"%s","amount":12345,"sequence":250},"name":"google.com"}]}`,
+		chainID, nameTx.Input.Address.String())
 	if signStr != expected {
 		t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr)
 	}
@@ -105,50 +112,46 @@ func TestNameTxSignable(t *testing.T) {
 
 func TestBondTxSignable(t *testing.T) {
 	privKeyBytes := make([]byte, 64)
-	privAccount := acm.GenPrivAccountFromPrivKeyBytes(privKeyBytes)
+	privAccount := acm.GeneratePrivateAccountFromPrivateKeyBytes(privKeyBytes)
 	bondTx := &BondTx{
-		PubKey: privAccount.PubKey.(crypto.PubKeyEd25519),
+		PubKey: privAccount.PublicKey(),
 		Inputs: []*TxInput{
-			&TxInput{
-				Address:  []byte("input1"),
+			{
+				Address:  makeAddress("input1"),
 				Amount:   12345,
 				Sequence: 67890,
 			},
-			&TxInput{
-				Address:  []byte("input2"),
+			{
+				Address:  makeAddress("input2"),
 				Amount:   111,
 				Sequence: 222,
 			},
 		},
 		UnbondTo: []*TxOutput{
-			&TxOutput{
-				Address: []byte("output1"),
+			{
+				Address: makeAddress("output1"),
 				Amount:  333,
 			},
-			&TxOutput{
-				Address: []byte("output2"),
+			{
+				Address: makeAddress("output2"),
 				Amount:  444,
 			},
 		},
 	}
-	signBytes := acm.SignBytes(chainID, bondTx)
-	signStr := string(signBytes)
-	expected := Fmt(`{"chain_id":"%s","tx":[17,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"pub_key":"3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29","unbond_to":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`,
-		chainID)
-	if signStr != expected {
-		t.Errorf("Unexpected sign string for BondTx. \nGot %s\nExpected %s", signStr, expected)
-	}
+	expected := fmt.Sprintf(`{"chain_id":"%s","tx":[17,{"inputs":[{"address":"%s","amount":12345,"sequence":67890},{"address":"%s","amount":111,"sequence":222}],"pub_key":[1,"3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29"],"unbond_to":[{"address":"%s","amount":333},{"address":"%s","amount":444}]}]}`,
+		chainID, bondTx.Inputs[0].Address.String(), bondTx.Inputs[1].Address.String(), bondTx.UnbondTo[0].Address.String(), bondTx.UnbondTo[1].Address.String())
+	assert.Equal(t, expected, string(acm.SignBytes(chainID, bondTx)), "Unexpected sign string for BondTx")
 }
 
 func TestUnbondTxSignable(t *testing.T) {
 	unbondTx := &UnbondTx{
-		Address: []byte("address1"),
+		Address: makeAddress("address1"),
 		Height:  111,
 	}
 	signBytes := acm.SignBytes(chainID, unbondTx)
 	signStr := string(signBytes)
-	expected := Fmt(`{"chain_id":"%s","tx":[18,{"address":"6164647265737331","height":111}]}`,
-		chainID)
+	expected := fmt.Sprintf(`{"chain_id":"%s","tx":[18,{"address":"%s","height":111}]}`,
+		chainID, unbondTx.Address.String())
 	if signStr != expected {
 		t.Errorf("Got unexpected sign string for UnbondTx")
 	}
@@ -156,13 +159,13 @@ func TestUnbondTxSignable(t *testing.T) {
 
 func TestRebondTxSignable(t *testing.T) {
 	rebondTx := &RebondTx{
-		Address: []byte("address1"),
+		Address: makeAddress("address1"),
 		Height:  111,
 	}
 	signBytes := acm.SignBytes(chainID, rebondTx)
 	signStr := string(signBytes)
-	expected := Fmt(`{"chain_id":"%s","tx":[19,{"address":"6164647265737331","height":111}]}`,
-		chainID)
+	expected := fmt.Sprintf(`{"chain_id":"%s","tx":[19,{"address":"%s","height":111}]}`,
+		chainID, rebondTx.Address.String())
 	if signStr != expected {
 		t.Errorf("Got unexpected sign string for RebondTx")
 	}
@@ -171,77 +174,84 @@ func TestRebondTxSignable(t *testing.T) {
 func TestPermissionsTxSignable(t *testing.T) {
 	permsTx := &PermissionsTx{
 		Input: &TxInput{
-			Address:  []byte("input1"),
+			Address:  makeAddress("input1"),
 			Amount:   12345,
 			Sequence: 250,
 		},
-		PermArgs: &ptypes.SetBaseArgs{
-			Address:    []byte("address1"),
-			Permission: 1,
-			Value:      true,
-		},
+		PermArgs: ptypes.SetBaseArgs(makeAddress("address1"), 1, true),
 	}
 
 	signBytes := acm.SignBytes(chainID, permsTx)
 	signStr := string(signBytes)
-	expected := Fmt(`{"chain_id":"%s","tx":[32,{"args":"[2,{"address":"6164647265737331","permission":1,"value":true}]","input":{"address":"696E70757431","amount":12345,"sequence":250}}]}`,
-		chainID)
+	expected := fmt.Sprintf(`{"chain_id":"%s","tx":[31,{"args":"{"PermFlag":%v,"Address":"%s","Permission":1,"Value":true}","input":{"address":"%s","amount":12345,"sequence":250}}]}`,
+		chainID, ptypes.SetBase, permsTx.PermArgs.Address.String(), permsTx.Input.Address.String())
 	if signStr != expected {
 		t.Errorf("Got unexpected sign string for PermsTx. Expected:\n%v\nGot:\n%v", expected, signStr)
 	}
 }
 
-func TestEncodeTxDecodeTx(t *testing.T) {
-	inputAddress := []byte{1, 2, 3, 4, 5}
-	outputAddress := []byte{5, 4, 3, 2, 1}
-	amount := int64(2)
-	sequence := 3
-	tx := &SendTx{
-		Inputs: []*TxInput{{
-			Address:  inputAddress,
-			Amount:   amount,
-			Sequence: sequence,
-		}},
-		Outputs: []*TxOutput{{
-			Address: outputAddress,
-			Amount:  amount,
-		}},
-	}
-	txBytes, err := EncodeTx(tx)
-	if err != nil {
-		t.Fatal(err)
-	}
-	txOut, err := DecodeTx(txBytes)
-	assert.NoError(t, err, "DecodeTx error")
-	assert.Equal(t, tx, txOut)
+func TestTxWrapper_MarshalJSON(t *testing.T) {
+	toAddress := makeAddress("contract1")
+	callTx := &CallTx{
+		Input: &TxInput{
+			Address:  makeAddress("input1"),
+			Amount:   12345,
+			Sequence: 67890,
+		},
+		Address:  &toAddress,
+		GasLimit: 111,
+		Fee:      222,
+		Data:     []byte("data1"),
+	}
+	testTxMarshalJSON(t, callTx)
+}
+
+func TestNewPermissionsTxWithNonce(t *testing.T) {
+	privateKey := acm.PrivateKeyFromSecret("Shhh...")
+
+	args := ptypes.SetBaseArgs(privateKey.PublicKey().Address(), ptypes.HasRole, true)
+	permTx := NewPermissionsTxWithNonce(privateKey.PublicKey(), args, 1)
+	testTxMarshalJSON(t, permTx)
+}
+
+func testTxMarshalJSON(t *testing.T, tx Tx) {
+	txw := &Wrapper{Tx: tx}
+	bs, err := json.Marshal(txw)
+	require.NoError(t, err)
+	txwOut := new(Wrapper)
+	err = json.Unmarshal(bs, txwOut)
+	require.NoError(t, err)
+	bsOut, err := json.Marshal(txwOut)
+	require.NoError(t, err)
+	assert.Equal(t, string(bs), string(bsOut))
 }
 
 /*
 func TestDupeoutTxSignable(t *testing.T) {
-	privAcc := acm.GenPrivAccount()
-	partSetHeader := types.PartSetHeader{Total: 10, Hash: []byte("partsethash")}
+	privAcc := acm.GeneratePrivateAccount()
+	partSetHeader := types.PartSetHeader{Total: 10, Hash: makeAddress("partsethash")}
 	voteA := &types.Vote{
 		Height:           10,
 		Round:            2,
 		Type:             types.VoteTypePrevote,
-		BlockHash:        []byte("myblockhash"),
+		BlockHash:        makeAddress("myblockhash"),
 		BlockPartsHeader: partSetHeader,
 	}
-	sig := privAcc.Sign(chainID, voteA)
+	sig := privAcc acm.ChainSign(chainID, voteA)
 	voteA.Signature = sig.(crypto.SignatureEd25519)
 	voteB := voteA.Copy()
-	voteB.BlockHash = []byte("myotherblockhash")
-	sig = privAcc.Sign(chainID, voteB)
+	voteB.BlockHash = makeAddress("myotherblockhash")
+	sig = privAcc acm.ChainSign(chainID, voteB)
 	voteB.Signature = sig.(crypto.SignatureEd25519)
 
 	dupeoutTx := &DupeoutTx{
-		Address: []byte("address1"),
+		Address: makeAddress("address1"),
 		VoteA:   *voteA,
 		VoteB:   *voteB,
 	}
 	signBytes := acm.SignBytes(chainID, dupeoutTx)
 	signStr := string(signBytes)
-	expected := Fmt(`{"chain_id":"%s","tx":[20,{"address":"6164647265737331","vote_a":%v,"vote_b":%v}]}`,
+	expected := fmt.Sprintf(`{"chain_id":"%s","tx":[20,{"address":"%s","vote_a":%v,"vote_b":%v}]}`,
 		chainID, *voteA, *voteB)
 	if signStr != expected {
 		t.Errorf("Got unexpected sign string for DupeoutTx")
diff --git a/txs/tx_utils.go b/txs/tx_utils.go
index 6e1519b6850d1594bd7c25497059bd6dcbf80b61..c680a7f478807e2d704242dd7c665d3794524382 100644
--- a/txs/tx_utils.go
+++ b/txs/tx_utils.go
@@ -18,15 +18,11 @@ import (
 	"fmt"
 
 	acm "github.com/hyperledger/burrow/account"
-	ptypes "github.com/hyperledger/burrow/permission/types"
+	ptypes "github.com/hyperledger/burrow/permission"
 
 	"github.com/tendermint/go-crypto"
 )
 
-type AccountGetter interface {
-	GetAccount(addr []byte) *acm.Account
-}
-
 //----------------------------------------------------------------------------
 // SendTx interface for adding inputs/outputs and adding signatures
 
@@ -37,28 +33,31 @@ func NewSendTx() *SendTx {
 	}
 }
 
-func (tx *SendTx) AddInput(st AccountGetter, pubkey crypto.PubKey, amt int64) error {
+func (tx *SendTx) AddInput(st acm.Getter, pubkey acm.PublicKey, amt uint64) error {
 	addr := pubkey.Address()
-	acc := st.GetAccount(addr)
+	acc, err := st.GetAccount(addr)
+	if err != nil {
+		return err
+	}
 	if acc == nil {
-		return fmt.Errorf("Invalid address %X from pubkey %X", addr, pubkey)
+		return fmt.Errorf("invalid address %s from pubkey %s", addr, pubkey)
 	}
-	return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1)
+	return tx.AddInputWithNonce(pubkey, amt, acc.Sequence()+1)
 }
 
-func (tx *SendTx) AddInputWithNonce(pubkey crypto.PubKey, amt int64, nonce int) error {
+func (tx *SendTx) AddInputWithNonce(pubkey acm.PublicKey, amt uint64, sequence uint64) error {
 	addr := pubkey.Address()
 	tx.Inputs = append(tx.Inputs, &TxInput{
 		Address:   addr,
 		Amount:    amt,
-		Sequence:  nonce,
-		Signature: crypto.SignatureEd25519{},
+		Sequence:  sequence,
+		Signature: crypto.SignatureEd25519{}.Wrap(),
 		PubKey:    pubkey,
 	})
 	return nil
 }
 
-func (tx *SendTx) AddOutput(addr []byte, amt int64) error {
+func (tx *SendTx) AddOutput(addr acm.Address, amt uint64) error {
 	tx.Outputs = append(tx.Outputs, &TxOutput{
 		Address: addr,
 		Amount:  amt,
@@ -66,36 +65,41 @@ func (tx *SendTx) AddOutput(addr []byte, amt int64) error {
 	return nil
 }
 
-func (tx *SendTx) SignInput(chainID string, i int, privAccount *acm.PrivAccount) error {
+func (tx *SendTx) SignInput(chainID string, i int, privAccount acm.PrivateAccount) error {
 	if i >= len(tx.Inputs) {
 		return fmt.Errorf("Index %v is greater than number of inputs (%v)", i, len(tx.Inputs))
 	}
-	tx.Inputs[i].PubKey = privAccount.PubKey
-	tx.Inputs[i].Signature = privAccount.Sign(chainID, tx)
+	tx.Inputs[i].PubKey = privAccount.PublicKey()
+	tx.Inputs[i].Signature = acm.ChainSign(privAccount, chainID, tx)
 	return nil
 }
 
 //----------------------------------------------------------------------------
 // CallTx interface for creating tx
 
-func NewCallTx(st AccountGetter, from crypto.PubKey, to, data []byte, amt, gasLimit, fee int64) (*CallTx, error) {
+func NewCallTx(st acm.Getter, from acm.PublicKey, to *acm.Address, data []byte,
+	amt, gasLimit, fee uint64) (*CallTx, error) {
+
 	addr := from.Address()
-	acc := st.GetAccount(addr)
+	acc, err := st.GetAccount(addr)
+	if err != nil {
+		return nil, err
+	}
 	if acc == nil {
-		return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from)
+		return nil, fmt.Errorf("invalid address %s from pubkey %s", addr, from)
 	}
 
-	nonce := acc.Sequence + 1
+	nonce := acc.Sequence() + 1
 	return NewCallTxWithNonce(from, to, data, amt, gasLimit, fee, nonce), nil
 }
 
-func NewCallTxWithNonce(from crypto.PubKey, to, data []byte, amt, gasLimit, fee int64, nonce int) *CallTx {
-	addr := from.Address()
+func NewCallTxWithNonce(from acm.PublicKey, to *acm.Address, data []byte,
+	amt, gasLimit, fee, sequence uint64) *CallTx {
 	input := &TxInput{
-		Address:   addr,
+		Address:   from.Address(),
 		Amount:    amt,
-		Sequence:  nonce,
-		Signature: crypto.SignatureEd25519{},
+		Sequence:  sequence,
+		Signature: crypto.SignatureEd25519{}.Wrap(),
 		PubKey:    from,
 	}
 
@@ -108,32 +112,34 @@ func NewCallTxWithNonce(from crypto.PubKey, to, data []byte, amt, gasLimit, fee
 	}
 }
 
-func (tx *CallTx) Sign(chainID string, privAccount *acm.PrivAccount) {
-	tx.Input.PubKey = privAccount.PubKey
-	tx.Input.Signature = privAccount.Sign(chainID, tx)
+func (tx *CallTx) Sign(chainID string, privAccount acm.PrivateAccount) {
+	tx.Input.PubKey = privAccount.PublicKey()
+	tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx)
 }
 
 //----------------------------------------------------------------------------
 // NameTx interface for creating tx
 
-func NewNameTx(st AccountGetter, from crypto.PubKey, name, data string, amt, fee int64) (*NameTx, error) {
+func NewNameTx(st acm.Getter, from acm.PublicKey, name, data string, amt, fee uint64) (*NameTx, error) {
 	addr := from.Address()
-	acc := st.GetAccount(addr)
+	acc, err := st.GetAccount(addr)
+	if err != nil {
+		return nil, err
+	}
 	if acc == nil {
-		return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from)
+		return nil, fmt.Errorf("Invalid address %s from pubkey %s", addr, from)
 	}
 
-	nonce := acc.Sequence + 1
+	nonce := acc.Sequence() + 1
 	return NewNameTxWithNonce(from, name, data, amt, fee, nonce), nil
 }
 
-func NewNameTxWithNonce(from crypto.PubKey, name, data string, amt, fee int64, nonce int) *NameTx {
-	addr := from.Address()
+func NewNameTxWithNonce(from acm.PublicKey, name, data string, amt, fee, sequence uint64) *NameTx {
 	input := &TxInput{
-		Address:   addr,
+		Address:   from.Address(),
 		Amount:    amt,
-		Sequence:  nonce,
-		Signature: crypto.SignatureEd25519{},
+		Sequence:  sequence,
+		Signature: crypto.SignatureEd25519{}.Wrap(),
 		PubKey:    from,
 	}
 
@@ -145,48 +151,46 @@ func NewNameTxWithNonce(from crypto.PubKey, name, data string, amt, fee int64, n
 	}
 }
 
-func (tx *NameTx) Sign(chainID string, privAccount *acm.PrivAccount) {
-	tx.Input.PubKey = privAccount.PubKey
-	tx.Input.Signature = privAccount.Sign(chainID, tx)
+func (tx *NameTx) Sign(chainID string, privAccount acm.PrivateAccount) {
+	tx.Input.PubKey = privAccount.PublicKey()
+	tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx)
 }
 
 //----------------------------------------------------------------------------
 // BondTx interface for adding inputs/outputs and adding signatures
 
-func NewBondTx(pubkey crypto.PubKey) (*BondTx, error) {
-	pubkeyEd, ok := pubkey.(crypto.PubKeyEd25519)
-	if !ok {
-		return nil, fmt.Errorf("Pubkey must be ed25519")
-	}
+func NewBondTx(pubkey acm.PublicKey) (*BondTx, error) {
 	return &BondTx{
-		PubKey:   pubkeyEd,
+		PubKey:   pubkey,
 		Inputs:   []*TxInput{},
 		UnbondTo: []*TxOutput{},
 	}, nil
 }
 
-func (tx *BondTx) AddInput(st AccountGetter, pubkey crypto.PubKey, amt int64) error {
+func (tx *BondTx) AddInput(st acm.Getter, pubkey acm.PublicKey, amt uint64) error {
 	addr := pubkey.Address()
-	acc := st.GetAccount(addr)
+	acc, err := st.GetAccount(addr)
+	if err != nil {
+		return err
+	}
 	if acc == nil {
-		return fmt.Errorf("Invalid address %X from pubkey %X", addr, pubkey)
+		return fmt.Errorf("Invalid address %s from pubkey %s", addr, pubkey)
 	}
-	return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1)
+	return tx.AddInputWithNonce(pubkey, amt, acc.Sequence()+uint64(1))
 }
 
-func (tx *BondTx) AddInputWithNonce(pubkey crypto.PubKey, amt int64, nonce int) error {
-	addr := pubkey.Address()
+func (tx *BondTx) AddInputWithNonce(pubkey acm.PublicKey, amt uint64, sequence uint64) error {
 	tx.Inputs = append(tx.Inputs, &TxInput{
-		Address:   addr,
+		Address:   pubkey.Address(),
 		Amount:    amt,
-		Sequence:  nonce,
-		Signature: crypto.SignatureEd25519{},
+		Sequence:  sequence,
+		Signature: crypto.SignatureEd25519{}.Wrap(),
 		PubKey:    pubkey,
 	})
 	return nil
 }
 
-func (tx *BondTx) AddOutput(addr []byte, amt int64) error {
+func (tx *BondTx) AddOutput(addr acm.Address, amt uint64) error {
 	tx.UnbondTo = append(tx.UnbondTo, &TxOutput{
 		Address: addr,
 		Amount:  amt,
@@ -194,74 +198,71 @@ func (tx *BondTx) AddOutput(addr []byte, amt int64) error {
 	return nil
 }
 
-func (tx *BondTx) SignBond(chainID string, privAccount *acm.PrivAccount) error {
-	sig := privAccount.Sign(chainID, tx)
-	sigEd, ok := sig.(crypto.SignatureEd25519)
-	if !ok {
-		return fmt.Errorf("Bond signer must be ED25519")
-	}
-	tx.Signature = sigEd
+func (tx *BondTx) SignBond(chainID string, privAccount acm.PrivateAccount) error {
+	tx.Signature = acm.ChainSign(privAccount, chainID, tx)
 	return nil
 }
 
-func (tx *BondTx) SignInput(chainID string, i int, privAccount *acm.PrivAccount) error {
+func (tx *BondTx) SignInput(chainID string, i int, privAccount acm.PrivateAccount) error {
 	if i >= len(tx.Inputs) {
 		return fmt.Errorf("Index %v is greater than number of inputs (%v)", i, len(tx.Inputs))
 	}
-	tx.Inputs[i].PubKey = privAccount.PubKey
-	tx.Inputs[i].Signature = privAccount.Sign(chainID, tx)
+	tx.Inputs[i].PubKey = privAccount.PublicKey()
+	tx.Inputs[i].Signature = acm.ChainSign(privAccount, chainID, tx)
 	return nil
 }
 
 //----------------------------------------------------------------------
 // UnbondTx interface for creating tx
 
-func NewUnbondTx(addr []byte, height int) *UnbondTx {
+func NewUnbondTx(addr acm.Address, height int) *UnbondTx {
 	return &UnbondTx{
 		Address: addr,
 		Height:  height,
 	}
 }
 
-func (tx *UnbondTx) Sign(chainID string, privAccount *acm.PrivAccount) {
-	tx.Signature = privAccount.Sign(chainID, tx).(crypto.SignatureEd25519)
+func (tx *UnbondTx) Sign(chainID string, privAccount acm.PrivateAccount) {
+	tx.Signature = acm.ChainSign(privAccount, chainID, tx)
 }
 
 //----------------------------------------------------------------------
 // RebondTx interface for creating tx
 
-func NewRebondTx(addr []byte, height int) *RebondTx {
+func NewRebondTx(addr acm.Address, height int) *RebondTx {
 	return &RebondTx{
 		Address: addr,
 		Height:  height,
 	}
 }
 
-func (tx *RebondTx) Sign(chainID string, privAccount *acm.PrivAccount) {
-	tx.Signature = privAccount.Sign(chainID, tx).(crypto.SignatureEd25519)
+func (tx *RebondTx) Sign(chainID string, privAccount acm.PrivateAccount) {
+	tx.Signature = acm.ChainSign(privAccount, chainID, tx)
 }
 
 //----------------------------------------------------------------------------
 // PermissionsTx interface for creating tx
 
-func NewPermissionsTx(st AccountGetter, from crypto.PubKey, args ptypes.PermArgs) (*PermissionsTx, error) {
+func NewPermissionsTx(st acm.Getter, from acm.PublicKey, args *ptypes.PermArgs) (*PermissionsTx, error) {
 	addr := from.Address()
-	acc := st.GetAccount(addr)
+	acc, err := st.GetAccount(addr)
+	if err != nil {
+		return nil, err
+	}
 	if acc == nil {
-		return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from)
+		return nil, fmt.Errorf("Invalid address %s from pubkey %s", addr, from)
 	}
 
-	nonce := acc.Sequence + 1
+	nonce := acc.Sequence() + 1
 	return NewPermissionsTxWithNonce(from, args, nonce), nil
 }
 
-func NewPermissionsTxWithNonce(from crypto.PubKey, args ptypes.PermArgs, nonce int) *PermissionsTx {
-	addr := from.Address()
+func NewPermissionsTxWithNonce(from acm.PublicKey, args *ptypes.PermArgs, sequence uint64) *PermissionsTx {
 	input := &TxInput{
-		Address:   addr,
+		Address:   from.Address(),
 		Amount:    1, // NOTE: amounts can't be 0 ...
-		Sequence:  nonce,
-		Signature: crypto.SignatureEd25519{},
+		Sequence:  sequence,
+		Signature: crypto.SignatureEd25519{}.Wrap(),
 		PubKey:    from,
 	}
 
@@ -271,7 +272,7 @@ func NewPermissionsTxWithNonce(from crypto.PubKey, args ptypes.PermArgs, nonce i
 	}
 }
 
-func (tx *PermissionsTx) Sign(chainID string, privAccount *acm.PrivAccount) {
-	tx.Input.PubKey = privAccount.PubKey
-	tx.Input.Signature = privAccount.Sign(chainID, tx)
+func (tx *PermissionsTx) Sign(chainID string, privAccount acm.PrivateAccount) {
+	tx.Input.PubKey = privAccount.PublicKey()
+	tx.Input.Signature = acm.ChainSign(privAccount, chainID, tx)
 }