diff --git a/account/account_test.go b/account/account_test.go
index ca3e41fdba161931d24a8610ded01aee33301110..68a5b1eef23b67083ce9295953ca06700763ce50 100644
--- a/account/account_test.go
+++ b/account/account_test.go
@@ -22,8 +22,7 @@ import (
 	"fmt"
 
 	"github.com/hyperledger/burrow/crypto"
-	"github.com/hyperledger/burrow/permission"
-	"github.com/hyperledger/burrow/permission/types"
+	ptypes "github.com/hyperledger/burrow/permission/types"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/tendermint/go-wire"
@@ -79,10 +78,10 @@ func TestAccountSerialise(t *testing.T) {
 
 func TestDecodeConcrete(t *testing.T) {
 	concreteAcc := NewConcreteAccountFromSecret("Super Semi Secret")
-	concreteAcc.Permissions = types.AccountPermissions{
-		Base: types.BasePermissions{
-			Perms:  permission.SetGlobal,
-			SetBit: permission.SetGlobal,
+	concreteAcc.Permissions = ptypes.AccountPermissions{
+		Base: ptypes.BasePermissions{
+			Perms:  ptypes.SetGlobal,
+			SetBit: ptypes.SetGlobal,
 		},
 		Roles: []string{"bums"},
 	}
diff --git a/account/state/state_cache_test.go b/account/state/state_cache_test.go
index 92171155cf68cf2d796a83159c6d1fcb0ee14bb9..6df18eb923680239f1feb1268f39a5d135eac463 100644
--- a/account/state/state_cache_test.go
+++ b/account/state/state_cache_test.go
@@ -1,15 +1,14 @@
 package state
 
 import (
-	"testing"
-
 	"fmt"
+	"testing"
 
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/execution/evm/asm"
-	"github.com/hyperledger/burrow/permission"
+	ptypes "github.com/hyperledger/burrow/permission/types"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
@@ -290,11 +289,11 @@ func TestStateCache_get(t *testing.T) {
 
 func testAccounts() *MemoryState {
 	acc1 := acm.NewConcreteAccountFromSecret("acc1")
-	acc1.Permissions.Base.Perms = permission.AddRole | permission.Send
+	acc1.Permissions.Base.Perms = ptypes.AddRole | ptypes.Send
 	acc1.Permissions.Base.SetBit = acc1.Permissions.Base.Perms
 
 	acc2 := acm.NewConcreteAccountFromSecret("acc2")
-	acc2.Permissions.Base.Perms = permission.AddRole | permission.Send
+	acc2.Permissions.Base.Perms = ptypes.AddRole | ptypes.Send
 	acc2.Permissions.Base.SetBit = acc1.Permissions.Base.Perms
 	acc2.Code, _ = acm.NewBytecode(asm.PUSH1, 0x20)
 
diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go
index ec125ea7b4192f524c2ce39261df74ab65822409..98e48b14a237d2c37a3a2035e42d369521ef237f 100644
--- a/blockchain/blockchain.go
+++ b/blockchain/blockchain.go
@@ -33,9 +33,7 @@ const DefaultValidatorsWindowSize = 10
 
 var stateKey = []byte("BlockchainState")
 
-type BlockchainInfo interface {
-	GenesisHash() []byte
-	GenesisDoc() genesis.GenesisDoc
+type TipInfo interface {
 	ChainID() string
 	LastBlockHeight() uint64
 	LastBlockTime() time.Time
@@ -43,6 +41,12 @@ type BlockchainInfo interface {
 	AppHashAfterLastBlock() []byte
 }
 
+type BlockchainInfo interface {
+	TipInfo
+	GenesisHash() []byte
+	GenesisDoc() genesis.GenesisDoc
+}
+
 type Root struct {
 	genesisHash []byte
 	genesisDoc  genesis.GenesisDoc
diff --git a/client/rpc/client.go b/client/rpc/client.go
index e940ee3e15e1a26d442309d04088618ca110c90b..9e5364246cc38ae2975b50f2252391db73ae46be 100644
--- a/client/rpc/client.go
+++ b/client/rpc/client.go
@@ -19,14 +19,13 @@ import (
 	"fmt"
 	"strconv"
 
-	"github.com/hyperledger/burrow/crypto"
-	ptypes "github.com/hyperledger/burrow/permission"
-	"github.com/hyperledger/burrow/txs/payload"
-
 	"github.com/hyperledger/burrow/client"
+	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/keys"
 	"github.com/hyperledger/burrow/permission/snatives"
+	ptypes "github.com/hyperledger/burrow/permission/types"
 	"github.com/hyperledger/burrow/txs"
+	"github.com/hyperledger/burrow/txs/payload"
 )
 
 //------------------------------------------------------------------------------------
diff --git a/client/websocket_client.go b/client/websocket_client.go
index 81be41982a8cc735f934bcbec2b702dfbbc7a4cb..5d4253441abee05ed3305e8bf81965b62a38fbe2 100644
--- a/client/websocket_client.go
+++ b/client/websocket_client.go
@@ -22,6 +22,7 @@ import (
 	"encoding/json"
 
 	"github.com/hyperledger/burrow/crypto"
+	"github.com/hyperledger/burrow/execution/errors"
 	exeEvents "github.com/hyperledger/burrow/execution/events"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
@@ -170,12 +171,12 @@ func (burrowNodeWebsocketClient *burrowNodeWebsocketClient) WaitForConfirmation(
 						continue
 					}
 
-					if eventDataTx.Exception != "" {
+					if eventDataTx.Exception != nil && eventDataTx.Exception.Code != errors.ErrorCodeExecutionReverted {
 						confirmationChannel <- Confirmation{
 							BlockHash:   latestBlockHash,
 							EventDataTx: eventDataTx,
-							Exception: fmt.Errorf("transaction confirmed but execution gave exception: %v",
-								eventDataTx.Exception),
+							Exception: errors.Wrap(eventDataTx.Exception,
+								"transaction confirmed but execution gave exception: %v"),
 							Error: nil,
 						}
 						return
diff --git a/core/kernel.go b/core/kernel.go
index eceaec854897465455f7fcc15b709ae21221085d..18f52126913db41dab63b1d77e9511846dbccd39 100644
--- a/core/kernel.go
+++ b/core/kernel.go
@@ -94,10 +94,10 @@ func NewKernel(ctx context.Context, keyClient keys.KeyClient, privValidator tm_t
 	}
 
 	tmGenesisDoc := tendermint.DeriveGenesisDoc(genesisDoc)
-	checker := execution.NewBatchChecker(state, tmGenesisDoc.ChainID, blockchain.Tip, logger)
+	checker := execution.NewBatchChecker(state, blockchain.Tip, logger)
 
 	emitter := event.NewEmitter(logger)
-	committer := execution.NewBatchCommitter(state, tmGenesisDoc.ChainID, blockchain.Tip, emitter, logger, exeOptions...)
+	committer := execution.NewBatchCommitter(state, blockchain.Tip, emitter, logger, exeOptions...)
 	tmNode, err := tendermint.NewNode(tmConf, privValidator, tmGenesisDoc, blockchain, checker, committer, tmLogger)
 
 	if err != nil {
diff --git a/core/kernel_test.go b/core/kernel_test.go
index 68cb5f9dd34264b09d0d65de7c577cf26d55eaa8..d242de8e9946a882c68cd54e894a156168248754 100644
--- a/core/kernel_test.go
+++ b/core/kernel_test.go
@@ -2,13 +2,11 @@ package core
 
 import (
 	"context"
+	"fmt"
 	"os"
 	"testing"
-
 	"time"
 
-	"fmt"
-
 	"github.com/hyperledger/burrow/consensus/tendermint"
 	"github.com/hyperledger/burrow/consensus/tendermint/validator"
 	"github.com/hyperledger/burrow/genesis"
@@ -16,8 +14,8 @@ import (
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/rpc"
 	"github.com/stretchr/testify/assert"
-	tm_config "github.com/tendermint/tendermint/config"
-	tm_types "github.com/tendermint/tendermint/types"
+	tmConfig "github.com/tendermint/tendermint/config"
+	tmTypes "github.com/tendermint/tendermint/types"
 )
 
 const testDir = "./test_scratch/kernel_test"
@@ -26,7 +24,7 @@ func TestBootThenShutdown(t *testing.T) {
 	os.RemoveAll(testDir)
 	os.MkdirAll(testDir, 0777)
 	os.Chdir(testDir)
-	tmConf := tm_config.DefaultConfig()
+	tmConf := tmConfig.DefaultConfig()
 	//logger, _, _ := lifecycle.NewStdErrLogger()
 	logger := logging.NewNoopLogger()
 	genesisDoc, _, privateValidators := genesis.NewDeterministicGenesis(123).GenesisDoc(1, true, 1000, 1, true, 1000)
@@ -38,7 +36,7 @@ func TestBootShutdownResume(t *testing.T) {
 	os.RemoveAll(testDir)
 	os.MkdirAll(testDir, 0777)
 	os.Chdir(testDir)
-	tmConf := tm_config.DefaultConfig()
+	tmConf := tmConfig.DefaultConfig()
 	//logger, _, _ := lifecycle.NewStdErrLogger()
 	logger := logging.NewNoopLogger()
 	genesisDoc, _, privateValidators := genesis.NewDeterministicGenesis(123).GenesisDoc(1, true, 1000, 1, true, 1000)
@@ -46,7 +44,7 @@ func TestBootShutdownResume(t *testing.T) {
 
 	i := int64(1)
 	// asserts we get a consecutive run of blocks
-	blockChecker := func(block *tm_types.EventDataNewBlock) bool {
+	blockChecker := func(block *tmTypes.EventDataNewBlock) bool {
 		assert.Equal(t, i, block.Block.Height)
 		i++
 		// stop every third block
@@ -61,9 +59,9 @@ func TestBootShutdownResume(t *testing.T) {
 	assert.Error(t, bootWaitBlocksShutdown(privValidator, genesisDoc, tmConf, logger, blockChecker))
 }
 
-func bootWaitBlocksShutdown(privValidator tm_types.PrivValidator, genesisDoc *genesis.GenesisDoc,
-	tmConf *tm_config.Config, logger *logging.Logger,
-	blockChecker func(block *tm_types.EventDataNewBlock) (cont bool)) error {
+func bootWaitBlocksShutdown(privValidator tmTypes.PrivValidator, genesisDoc *genesis.GenesisDoc,
+	tmConf *tmConfig.Config, logger *logging.Logger,
+	blockChecker func(block *tmTypes.EventDataNewBlock) (cont bool)) error {
 
 	keyStore := keys.NewKeyStore(keys.DefaultKeysDir, false, logger)
 	keyClient := keys.NewLocalKeyClient(keyStore, logging.NewNoopLogger())
@@ -78,7 +76,7 @@ func bootWaitBlocksShutdown(privValidator tm_types.PrivValidator, genesisDoc *ge
 		return err
 	}
 
-	ch := make(chan *tm_types.EventDataNewBlock)
+	ch := make(chan *tmTypes.EventDataNewBlock)
 	tendermint.SubscribeNewBlock(context.Background(), kern.Emitter, "TestBootShutdownResume", ch)
 	cont := true
 	for cont {
diff --git a/event/emitter.go b/event/emitter.go
index ec9f1e31187c6e436d12ec1396ad57bd55dc3ce1..738104fdea49cdd1b1f15e8709257fa887862e60 100644
--- a/event/emitter.go
+++ b/event/emitter.go
@@ -42,6 +42,12 @@ type Publisher interface {
 	Publish(ctx context.Context, message interface{}, tags map[string]interface{}) error
 }
 
+type PublisherFunc func(ctx context.Context, message interface{}, tags map[string]interface{}) error
+
+func (pf PublisherFunc) Publish(ctx context.Context, message interface{}, tags map[string]interface{}) error {
+	return pf(ctx, message, tags)
+}
+
 type Emitter interface {
 	Subscribable
 	Publisher
diff --git a/execution/errors/errors.go b/execution/errors/errors.go
new file mode 100644
index 0000000000000000000000000000000000000000..20248d408272f12abf709fcdc61546b68c27dbff
--- /dev/null
+++ b/execution/errors/errors.go
@@ -0,0 +1,142 @@
+package errors
+
+import (
+	"fmt"
+)
+
+type CodedError interface {
+	error
+	ErrorCode() ErrorCode
+}
+
+type ErrorCode int8
+
+const (
+	ErrorCodeGeneric ErrorCode = iota
+	ErrorCodeUnknownAddress
+	ErrorCodeInsufficientBalance
+	ErrorCodeInvalidJumpDest
+	ErrorCodeInsufficientGas
+	ErrorCodeMemoryOutOfBounds
+	ErrorCodeCodeOutOfBounds
+	ErrorCodeInputOutOfBounds
+	ErrorCodeReturnDataOutOfBounds
+	ErrorCodeCallStackOverflow
+	ErrorCodeCallStackUnderflow
+	ErrorCodeDataStackOverflow
+	ErrorCodeDataStackUnderflow
+	ErrorCodeInvalidContract
+	ErrorCodeNativeContractCodeCopy
+	ErrorCodeExecutionAborted
+	ErrorCodeExecutionReverted
+	ErrorCodePermissionDenied
+	ErrorCodeNativeFunction
+)
+
+func (ec ErrorCode) ErrorCode() ErrorCode {
+	return ec
+}
+
+func (ec ErrorCode) Error() string {
+	switch ec {
+	case ErrorCodeUnknownAddress:
+		return "Unknown address"
+	case ErrorCodeInsufficientBalance:
+		return "Insufficient balance"
+	case ErrorCodeInvalidJumpDest:
+		return "Invalid jump dest"
+	case ErrorCodeInsufficientGas:
+		return "Insufficient gas"
+	case ErrorCodeMemoryOutOfBounds:
+		return "Memory out of bounds"
+	case ErrorCodeCodeOutOfBounds:
+		return "Code out of bounds"
+	case ErrorCodeInputOutOfBounds:
+		return "Input out of bounds"
+	case ErrorCodeReturnDataOutOfBounds:
+		return "Return data out of bounds"
+	case ErrorCodeCallStackOverflow:
+		return "Call stack overflow"
+	case ErrorCodeCallStackUnderflow:
+		return "Call stack underflow"
+	case ErrorCodeDataStackOverflow:
+		return "Data stack overflow"
+	case ErrorCodeDataStackUnderflow:
+		return "Data stack underflow"
+	case ErrorCodeInvalidContract:
+		return "Invalid contract"
+	case ErrorCodeNativeContractCodeCopy:
+		return "Tried to copy native contract code"
+	case ErrorCodeExecutionAborted:
+		return "Execution aborted"
+	case ErrorCodeExecutionReverted:
+		return "Execution reverted"
+	case ErrorCodeNativeFunction:
+		return "Native function error"
+	default:
+		return "Generic error"
+	}
+}
+
+// Exception provides a serialisable coded error for the VM
+type Exception struct {
+	Code      ErrorCode
+	Exception string
+}
+
+func NewCodedError(errorCode ErrorCode, exception string) *Exception {
+	if exception == "" {
+		return nil
+	}
+	return &Exception{
+		Code:      errorCode,
+		Exception: exception,
+	}
+}
+
+// Wraps any error as a Exception
+func AsCodedError(err error) *Exception {
+	if err == nil {
+		return nil
+	}
+	switch e := err.(type) {
+	case *Exception:
+		return e
+	case CodedError:
+		return NewCodedError(e.ErrorCode(), e.Error())
+	default:
+		return NewCodedError(ErrorCodeGeneric, err.Error())
+	}
+}
+
+func Wrap(err CodedError, message string) *Exception {
+	return NewCodedError(err.ErrorCode(), message+": "+err.Error())
+}
+
+func Errorf(format string, a ...interface{}) CodedError {
+	return ErrorCodef(ErrorCodeGeneric, format, a...)
+}
+
+func ErrorCodef(errorCode ErrorCode, format string, a ...interface{}) CodedError {
+	return NewCodedError(errorCode, fmt.Sprintf(format, a...))
+}
+
+func (e *Exception) AsError() error {
+	// thanks go, you dick
+	if e == nil {
+		return nil
+	}
+	return e
+}
+
+func (e *Exception) ErrorCode() ErrorCode {
+	return e.Code
+}
+
+func (e *Exception) String() string {
+	return e.Error()
+}
+
+func (e *Exception) Error() string {
+	return fmt.Sprintf("VM Error %v: %s", e.Code, e.Exception)
+}
diff --git a/execution/errors/native.go b/execution/errors/native.go
new file mode 100644
index 0000000000000000000000000000000000000000..df35e9a4f1379b37c6368764156e214ed0a70087
--- /dev/null
+++ b/execution/errors/native.go
@@ -0,0 +1,20 @@
+package errors
+
+import (
+	"fmt"
+
+	"github.com/hyperledger/burrow/crypto"
+)
+
+type LacksSNativePermission struct {
+	Address crypto.Address
+	SNative string
+}
+
+func (e LacksSNativePermission) Error() string {
+	return fmt.Sprintf("account %s does not have SNative function call permission: %s", e.Address, e.SNative)
+}
+
+func (e LacksSNativePermission) ErrorCode() ErrorCode {
+	return ErrorCodeNativeFunction
+}
diff --git a/execution/errors/vm.go b/execution/errors/vm.go
new file mode 100644
index 0000000000000000000000000000000000000000..d8b164c230fd94e490dd4bd91154fad93a68f9fb
--- /dev/null
+++ b/execution/errors/vm.go
@@ -0,0 +1,60 @@
+package errors
+
+import (
+	"bytes"
+	"fmt"
+
+	"github.com/hyperledger/burrow/crypto"
+	"github.com/hyperledger/burrow/permission/types"
+)
+
+type PermissionDenied struct {
+	Perm types.PermFlag
+}
+
+func (err PermissionDenied) ErrorCode() ErrorCode {
+	return ErrorCodePermissionDenied
+}
+
+func (err PermissionDenied) Error() string {
+	return fmt.Sprintf("Contract does not have permission to %v", err.Perm)
+}
+
+type NestedCall struct {
+	NestedError CodedError
+	Caller      crypto.Address
+	Callee      crypto.Address
+	StackDepth  int
+}
+
+func (err NestedCall) ErrorCode() ErrorCode {
+	return err.NestedError.ErrorCode()
+}
+
+func (err NestedCall) Error() string {
+	return fmt.Sprintf("error in nested call at depth %v: %s (callee) -> %s (caller): %v",
+		err.StackDepth, err.Callee, err.Caller, err.NestedError)
+}
+
+type Call struct {
+	CallError    CodedError
+	NestedErrors []NestedCall
+}
+
+func (err Call) ErrorCode() ErrorCode {
+	return err.CallError.ErrorCode()
+}
+
+func (err Call) Error() string {
+	buf := new(bytes.Buffer)
+	buf.WriteString("call error: ")
+	buf.WriteString(err.CallError.Error())
+	if len(err.NestedErrors) > 0 {
+		buf.WriteString(", nested call errors:\n")
+		for _, nestedErr := range err.NestedErrors {
+			buf.WriteString(nestedErr.Error())
+			buf.WriteByte('\n')
+		}
+	}
+	return buf.String()
+}
diff --git a/execution/events/events.go b/execution/events/events.go
index fd28bfe896d42f7e8910f5cf208028c7c0f658a3..6a7e64faa7e725a2838eb08865c5f2ab266a6440 100644
--- a/execution/events/events.go
+++ b/execution/events/events.go
@@ -7,6 +7,8 @@ import (
 
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/event"
+	"github.com/hyperledger/burrow/execution/errors"
+	ptypes "github.com/hyperledger/burrow/permission/types"
 	"github.com/hyperledger/burrow/txs"
 	"github.com/hyperledger/burrow/txs/payload"
 	"github.com/tmthrgd/go-hex"
@@ -15,7 +17,7 @@ import (
 func EventStringAccountInput(addr crypto.Address) string  { return fmt.Sprintf("Acc/%s/Input", addr) }
 func EventStringAccountOutput(addr crypto.Address) string { return fmt.Sprintf("Acc/%s/Output", addr) }
 func EventStringNameReg(name string) string               { return fmt.Sprintf("NameReg/%s", name) }
-func EventStringPermissions(name string) string           { return fmt.Sprintf("Permissions/%s", name) }
+func EventStringPermissions(perm ptypes.PermFlag) string  { return fmt.Sprintf("Permissions/%v", perm) }
 func EventStringBond() string                             { return "Bond" }
 func EventStringUnbond() string                           { return "Unbond" }
 func EventStringRebond() string                           { return "Rebond" }
@@ -24,7 +26,7 @@ func EventStringRebond() string                           { return "Rebond" }
 type EventDataTx struct {
 	Tx        *txs.Tx
 	Return    []byte
-	Exception string
+	Exception *errors.Exception
 }
 
 // For re-use
@@ -54,7 +56,7 @@ func SubscribeAccountOutputSendTx(ctx context.Context, subscribable event.Subscr
 }
 
 func PublishAccountOutput(publisher event.Publisher, address crypto.Address, tx *txs.Tx, ret []byte,
-	exception string) error {
+	exception *errors.Exception) error {
 
 	return event.PublishWithEventID(publisher, EventStringAccountOutput(address),
 		&EventDataTx{
@@ -70,7 +72,7 @@ func PublishAccountOutput(publisher event.Publisher, address crypto.Address, tx
 }
 
 func PublishAccountInput(publisher event.Publisher, address crypto.Address, tx *txs.Tx, ret []byte,
-	exception string) error {
+	exception *errors.Exception) error {
 
 	return event.PublishWithEventID(publisher, EventStringAccountInput(address),
 		&EventDataTx{
@@ -98,14 +100,14 @@ func PublishNameReg(publisher event.Publisher, tx *txs.Tx) error {
 		})
 }
 
-func PublishPermissions(publisher event.Publisher, name string, tx *txs.Tx) error {
+func PublishPermissions(publisher event.Publisher, perm ptypes.PermFlag, tx *txs.Tx) error {
 	_, ok := tx.Payload.(*payload.PermissionsTx)
 	if !ok {
 		return fmt.Errorf("Tx payload must be PermissionsTx to PublishPermissions")
 	}
-	return event.PublishWithEventID(publisher, EventStringPermissions(name), &EventDataTx{Tx: tx},
+	return event.PublishWithEventID(publisher, EventStringPermissions(perm), &EventDataTx{Tx: tx},
 		map[string]interface{}{
-			"name":          name,
+			"name":          perm.String(),
 			event.TxTypeKey: tx.Type().String(),
 			event.TxHashKey: hex.EncodeUpperToString(tx.Hash()),
 		})
diff --git a/execution/evm/events/events.go b/execution/evm/events/events.go
index 9ae628a7a829ac0c858811cd5643910abbffc7da..9095d7687fa84b88a99585bdecf5e7a2d420fa04 100644
--- a/execution/evm/events/events.go
+++ b/execution/evm/events/events.go
@@ -21,6 +21,7 @@ import (
 	. "github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/event"
+	"github.com/hyperledger/burrow/execution/errors"
 	"github.com/tmthrgd/go-hex"
 )
 
@@ -38,7 +39,7 @@ type EventDataCall struct {
 	TxHash     []byte
 	StackDepth int
 	Return     []byte
-	Exception  string
+	Exception  *errors.Exception
 }
 
 type CallData struct {
diff --git a/execution/evm/native.go b/execution/evm/native.go
index 70f00ed6d2a25c31a42de210f29161f0905cb68b..4a7c7e615141faf3dd92b50fe4ec095d6a8cbdb4 100644
--- a/execution/evm/native.go
+++ b/execution/evm/native.go
@@ -20,13 +20,15 @@ import (
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/account/state"
 	. "github.com/hyperledger/burrow/binary"
+	"github.com/hyperledger/burrow/crypto"
+	"github.com/hyperledger/burrow/execution/errors"
 	"github.com/hyperledger/burrow/logging"
 	"golang.org/x/crypto/ripemd160"
 )
 
 var registeredNativeContracts = make(map[Word256]NativeContract)
 
-func RegisteredNativeContract(address Word256) bool {
+func IsRegisteredNativeContract(address Word256) bool {
 	_, ok := registeredNativeContracts[address]
 	return ok
 }
@@ -54,6 +56,21 @@ func registerNativeContracts() {
 
 //-----------------------------------------------------------------------------
 
+func ExecuteNativeContract(address Word256, state state.Writer, caller acm.Account, input []byte, gas *uint64,
+	logger *logging.Logger) ([]byte, errors.CodedError) {
+
+	contract, ok := registeredNativeContracts[address]
+	if !ok {
+		return nil, errors.ErrorCodef(errors.ErrorCodeNativeFunction,
+			"no native contract registered at address: %v", crypto.AddressFromWord256(address))
+	}
+	output, err := contract(state, caller, input, gas, logger)
+	if err != nil {
+		return nil, errors.NewCodedError(errors.ErrorCodeNativeFunction, err.Error())
+	}
+	return output, nil
+}
+
 type NativeContract func(state state.Writer, caller acm.Account, input []byte, gas *uint64,
 	logger *logging.Logger) (output []byte, err error)
 
@@ -86,7 +103,7 @@ func sha256Func(state state.Writer, caller acm.Account, input []byte, gas *uint6
 	// Deduct gas
 	gasRequired := uint64((len(input)+31)/32)*GasSha256Word + GasSha256Base
 	if *gas < gasRequired {
-		return nil, ErrInsufficientGas
+		return nil, errors.ErrorCodeInsufficientGas
 	} else {
 		*gas -= gasRequired
 	}
@@ -102,7 +119,7 @@ func ripemd160Func(state state.Writer, caller acm.Account, input []byte, gas *ui
 	// Deduct gas
 	gasRequired := uint64((len(input)+31)/32)*GasRipemd160Word + GasRipemd160Base
 	if *gas < gasRequired {
-		return nil, ErrInsufficientGas
+		return nil, errors.ErrorCodeInsufficientGas
 	} else {
 		*gas -= gasRequired
 	}
@@ -118,7 +135,7 @@ func identityFunc(state state.Writer, caller acm.Account, input []byte, gas *uin
 	// Deduct gas
 	gasRequired := uint64((len(input)+31)/32)*GasIdentityWord + GasIdentityBase
 	if *gas < gasRequired {
-		return nil, ErrInsufficientGas
+		return nil, errors.ErrorCodeInsufficientGas
 	} else {
 		*gas -= gasRequired
 	}
diff --git a/execution/evm/snative.go b/execution/evm/snative.go
index 8afbd171c84ed8a05e72c948dcc231958bfd4ee8..7f9c25e57ff60891305b15c58edd02fcb827aed1 100644
--- a/execution/evm/snative.go
+++ b/execution/evm/snative.go
@@ -23,11 +23,11 @@ import (
 	"github.com/hyperledger/burrow/account/state"
 	. "github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/crypto"
+	"github.com/hyperledger/burrow/execution/errors"
 	"github.com/hyperledger/burrow/execution/evm/abi"
 	"github.com/hyperledger/burrow/execution/evm/sha3"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
-	"github.com/hyperledger/burrow/permission"
 	ptypes "github.com/hyperledger/burrow/permission/types"
 )
 
@@ -98,7 +98,7 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 					abiArg("_role", roleTypeName),
 				},
 				abiReturn("result", abi.BoolTypeName),
-				permission.AddRole,
+				ptypes.AddRole,
 				addRole},
 
 			&SNativeFunctionDescription{`
@@ -113,7 +113,7 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 					abiArg("_role", roleTypeName),
 				},
 				abiReturn("result", abi.BoolTypeName),
-				permission.RemoveRole,
+				ptypes.RemoveRole,
 				removeRole},
 
 			&SNativeFunctionDescription{`
@@ -128,7 +128,7 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 					abiArg("_role", roleTypeName),
 				},
 				abiReturn("result", abi.BoolTypeName),
-				permission.HasRole,
+				ptypes.HasRole,
 				hasRole},
 
 			&SNativeFunctionDescription{`
@@ -145,7 +145,7 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 					abiArg("_set", abi.BoolTypeName),
 				},
 				abiReturn("result", permFlagTypeName),
-				permission.SetBase,
+				ptypes.SetBase,
 				setBase},
 
 			&SNativeFunctionDescription{`
@@ -159,7 +159,7 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 					abiArg("_account", abi.AddressTypeName),
 					abiArg("_permission", permFlagTypeName)},
 				abiReturn("result", permFlagTypeName),
-				permission.UnsetBase,
+				ptypes.UnsetBase,
 				unsetBase},
 
 			&SNativeFunctionDescription{`
@@ -173,7 +173,7 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 					abiArg("_account", abi.AddressTypeName),
 					abiArg("_permission", permFlagTypeName)},
 				abiReturn("result", abi.BoolTypeName),
-				permission.HasBase,
+				ptypes.HasBase,
 				hasBase},
 
 			&SNativeFunctionDescription{`
@@ -187,7 +187,7 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 					abiArg("_permission", permFlagTypeName),
 					abiArg("_set", abi.BoolTypeName)},
 				abiReturn("result", permFlagTypeName),
-				permission.SetGlobal,
+				ptypes.SetGlobal,
 				setGlobal},
 		),
 	}
@@ -227,15 +227,6 @@ func NewSNativeContract(comment, name string,
 	}
 }
 
-type ErrLacksSNativePermission struct {
-	Address crypto.Address
-	SNative string
-}
-
-func (e ErrLacksSNativePermission) Error() string {
-	return fmt.Sprintf("account %s does not have SNative function call permission: %s", e.Address, e.SNative)
-}
-
 // This function is designed to be called from the EVM once a SNative contract
 // has been selected. It is also placed in a registry by registerSNativeContracts
 // So it can be looked up by SNative address
@@ -245,8 +236,9 @@ func (contract *SNativeContractDescription) Dispatch(state state.Writer, caller
 	logger = logger.With(structure.ScopeKey, "Dispatch", "contract_name", contract.Name)
 
 	if len(args) < abi.FunctionSelectorLength {
-		return nil, fmt.Errorf("SNatives dispatch requires a 4-byte function "+
-			"identifier but arguments are only %v bytes long", len(args))
+		return nil, errors.ErrorCodef(errors.ErrorCodeNativeFunction,
+			"SNatives dispatch requires a 4-byte function identifier but arguments are only %v bytes long",
+			len(args))
 	}
 
 	function, err := contract.FunctionByID(abi.FirstFourBytes(args))
@@ -262,12 +254,12 @@ func (contract *SNativeContractDescription) Dispatch(state state.Writer, caller
 
 	// check if we have permission to call this function
 	if !HasPermission(state, caller, function.PermFlag) {
-		return nil, ErrLacksSNativePermission{caller.Address(), function.Name}
+		return nil, errors.LacksSNativePermission{caller.Address(), function.Name}
 	}
 
 	// ensure there are enough arguments
 	if len(remainingArgs) != function.NArgs()*Word256Length {
-		return nil, fmt.Errorf("%s() takes %d arguments but got %d (with %d bytes unconsumed - should be 0)",
+		return nil, errors.ErrorCodef(errors.ErrorCodeNativeFunction, "%s() takes %d arguments but got %d (with %d bytes unconsumed - should be 0)",
 			function.Name, function.NArgs(), len(remainingArgs)/Word256Length, len(remainingArgs)%Word256Length)
 	}
 
@@ -284,11 +276,11 @@ func (contract *SNativeContractDescription) Address() (address crypto.Address) {
 }
 
 // Get function by calling identifier FunctionSelector
-func (contract *SNativeContractDescription) FunctionByID(id abi.FunctionSelector) (*SNativeFunctionDescription, error) {
+func (contract *SNativeContractDescription) FunctionByID(id abi.FunctionSelector) (*SNativeFunctionDescription, errors.CodedError) {
 	f, ok := contract.functionsByID[id]
 	if !ok {
 		return nil,
-			fmt.Errorf("unknown SNative function with ID %x", id)
+			errors.ErrorCodef(errors.ErrorCodeNativeFunction, "unknown SNative function with ID %x", id)
 	}
 	return f, nil
 }
@@ -527,7 +519,7 @@ func removeRole(stateWriter state.Writer, caller acm.Account, args []byte, gas *
 
 // Checks if a permission flag is valid (a known base chain or snative permission)
 func ValidPermN(n ptypes.PermFlag) bool {
-	return n <= permission.AllPermFlags
+	return n <= ptypes.AllPermFlags
 }
 
 // Get the global BasePermissions
diff --git a/execution/evm/snative_test.go b/execution/evm/snative_test.go
index 3f5e5eae9cc0dba28c35f849dd587312b35f65b3..e9b4150db7256f160dede1eaab8e73962fae5cb1 100644
--- a/execution/evm/snative_test.go
+++ b/execution/evm/snative_test.go
@@ -23,10 +23,11 @@ import (
 	acm "github.com/hyperledger/burrow/account"
 	. "github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/crypto"
+	"github.com/hyperledger/burrow/execution/errors"
 	"github.com/hyperledger/burrow/execution/evm/abi"
 	"github.com/hyperledger/burrow/execution/evm/asm/bc"
 	"github.com/hyperledger/burrow/execution/evm/sha3"
-	"github.com/hyperledger/burrow/permission"
+	permission "github.com/hyperledger/burrow/permission/types"
 	ptypes "github.com/hyperledger/burrow/permission/types"
 	"github.com/stretchr/testify/assert"
 )
@@ -87,7 +88,7 @@ func TestSNativeContractDescription_Dispatch(t *testing.T) {
 	if !assert.Error(t, err, "Should fail due to lack of permissions") {
 		return
 	}
-	assert.IsType(t, err, ErrLacksSNativePermission{})
+	assert.IsType(t, err, errors.LacksSNativePermission{})
 
 	// Grant all permissions and dispatch should success
 	caller.SetPermissions(allAccountPermissions())
diff --git a/execution/evm/stack.go b/execution/evm/stack.go
index 3e9dfd5b8987707f68334e6b56f7044bc8fd409c..9a244265c1cf895955982a4f80dc4307a2d88559 100644
--- a/execution/evm/stack.go
+++ b/execution/evm/stack.go
@@ -20,6 +20,7 @@ import (
 	"math/big"
 
 	. "github.com/hyperledger/burrow/binary"
+	"github.com/hyperledger/burrow/execution/errors"
 )
 
 // Not goroutine safe
@@ -28,10 +29,10 @@ type Stack struct {
 	ptr  int
 
 	gas *uint64
-	err *error
+	err *errors.CodedError
 }
 
-func NewStack(capacity int, gas *uint64, err *error) *Stack {
+func NewStack(capacity int, gas *uint64, err *errors.CodedError) *Stack {
 	return &Stack{
 		data: make([]Word256, capacity),
 		ptr:  0,
@@ -44,11 +45,11 @@ func (st *Stack) useGas(gasToUse uint64) {
 	if *st.gas > gasToUse {
 		*st.gas -= gasToUse
 	} else {
-		st.setErr(ErrInsufficientGas)
+		st.setErr(errors.ErrorCodeInsufficientGas)
 	}
 }
 
-func (st *Stack) setErr(err error) {
+func (st *Stack) setErr(err errors.CodedError) {
 	if *st.err == nil {
 		*st.err = err
 	}
@@ -57,7 +58,7 @@ func (st *Stack) setErr(err error) {
 func (st *Stack) Push(d Word256) {
 	st.useGas(GasStackOp)
 	if st.ptr == cap(st.data) {
-		st.setErr(ErrDataStackOverflow)
+		st.setErr(errors.ErrorCodeDataStackOverflow)
 		return
 	}
 	st.data[st.ptr] = d
@@ -92,7 +93,7 @@ func (st *Stack) PushBigInt(bigInt *big.Int) Word256 {
 func (st *Stack) Pop() Word256 {
 	st.useGas(GasStackOp)
 	if st.ptr == 0 {
-		st.setErr(ErrDataStackUnderflow)
+		st.setErr(errors.ErrorCodeDataStackUnderflow)
 		return Zero256
 	}
 	st.ptr--
@@ -103,18 +104,18 @@ func (st *Stack) PopBytes() []byte {
 	return st.Pop().Bytes()
 }
 
-func (st *Stack) Pop64() (int64, error) {
+func (st *Stack) Pop64() (int64, errors.CodedError) {
 	d := st.Pop()
 	if Is64BitOverflow(d) {
-		return 0, fmt.Errorf("int64 overflow from word: %v", d)
+		return 0, errors.ErrorCodef(errors.ErrorCodeCallStackOverflow, "int64 overflow from word: %v", d)
 	}
 	return Int64FromWord256(d), nil
 }
 
-func (st *Stack) PopU64() (uint64, error) {
+func (st *Stack) PopU64() (uint64, errors.CodedError) {
 	d := st.Pop()
 	if Is64BitOverflow(d) {
-		return 0, fmt.Errorf("uint64 overflow from word: %v", d)
+		return 0, errors.ErrorCodef(errors.ErrorCodeCallStackOverflow, "int64 overflow from word: %v", d)
 	}
 	return Uint64FromWord256(d), nil
 }
@@ -135,7 +136,7 @@ func (st *Stack) Len() int {
 func (st *Stack) Swap(n int) {
 	st.useGas(GasStackOp)
 	if st.ptr < n {
-		st.setErr(ErrDataStackUnderflow)
+		st.setErr(errors.ErrorCodeDataStackUnderflow)
 		return
 	}
 	st.data[st.ptr-n], st.data[st.ptr-1] = st.data[st.ptr-1], st.data[st.ptr-n]
@@ -144,7 +145,7 @@ func (st *Stack) Swap(n int) {
 func (st *Stack) Dup(n int) {
 	st.useGas(GasStackOp)
 	if st.ptr < n {
-		st.setErr(ErrDataStackUnderflow)
+		st.setErr(errors.ErrorCodeDataStackUnderflow)
 		return
 	}
 	st.Push(st.data[st.ptr-n])
@@ -153,7 +154,7 @@ func (st *Stack) Dup(n int) {
 // Not an opcode, costs no gas.
 func (st *Stack) Peek() Word256 {
 	if st.ptr == 0 {
-		st.setErr(ErrDataStackUnderflow)
+		st.setErr(errors.ErrorCodeDataStackUnderflow)
 		return Zero256
 	}
 	return st.data[st.ptr-1]
diff --git a/execution/evm/vm.go b/execution/evm/vm.go
index 37e9ec0658cc31da92b6979453833772acb7d606..ec4eb07e1e02f96ec6116da7ff978b8474a02efc 100644
--- a/execution/evm/vm.go
+++ b/execution/evm/vm.go
@@ -16,7 +16,6 @@ package evm
 
 import (
 	"bytes"
-	"errors"
 	"fmt"
 	"io/ioutil"
 	"math/big"
@@ -27,77 +26,19 @@ import (
 	. "github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/event"
+	"github.com/hyperledger/burrow/execution/errors"
 	. "github.com/hyperledger/burrow/execution/evm/asm"
 	"github.com/hyperledger/burrow/execution/evm/events"
 	"github.com/hyperledger/burrow/execution/evm/sha3"
 	"github.com/hyperledger/burrow/logging"
-	"github.com/hyperledger/burrow/permission"
 	ptypes "github.com/hyperledger/burrow/permission/types"
 )
 
-var (
-	ErrUnknownAddress         = errors.New("Unknown address")
-	ErrInsufficientBalance    = errors.New("Insufficient balance")
-	ErrInvalidJumpDest        = errors.New("Invalid jump dest")
-	ErrInsufficientGas        = errors.New("Insufficient gas")
-	ErrMemoryOutOfBounds      = errors.New("Memory out of bounds")
-	ErrCodeOutOfBounds        = errors.New("Code out of bounds")
-	ErrInputOutOfBounds       = errors.New("Input out of bounds")
-	ErrReturnDataOutOfBounds  = errors.New("Return data out of bounds")
-	ErrCallStackOverflow      = errors.New("Call stack overflow")
-	ErrCallStackUnderflow     = errors.New("Call stack underflow")
-	ErrDataStackOverflow      = errors.New("Data stack overflow")
-	ErrDataStackUnderflow     = errors.New("Data stack underflow")
-	ErrInvalidContract        = errors.New("Invalid contract")
-	ErrNativeContractCodeCopy = errors.New("Tried to copy native contract code")
-	ErrExecutionAborted       = errors.New("Execution aborted")
-	ErrExecutionReverted      = errors.New("Execution reverted")
-)
-
 const (
 	dataStackCapacity = 1024
 	callStackCapacity = 100 // TODO ensure usage.
 )
 
-type ErrPermission struct {
-	typ string
-}
-
-func (err ErrPermission) Error() string {
-	return fmt.Sprintf("Contract does not have permission to %s", err.typ)
-}
-
-type ErrNestedCall struct {
-	NestedError error
-	Caller      crypto.Address
-	Callee      crypto.Address
-	StackDepth  int
-}
-
-func (err ErrNestedCall) Error() string {
-	return fmt.Sprintf("error in nested call at depth %v: %s (callee) -> %s (caller): %v",
-		err.StackDepth, err.Callee, err.Caller, err.NestedError)
-}
-
-type ErrCall struct {
-	CallError    error
-	NestedErrors []ErrNestedCall
-}
-
-func (err ErrCall) Error() string {
-	buf := new(bytes.Buffer)
-	buf.WriteString("call error: ")
-	buf.WriteString(err.CallError.Error())
-	if len(err.NestedErrors) > 0 {
-		buf.WriteString(", nested call errors:\n")
-		for _, nestedErr := range err.NestedErrors {
-			buf.WriteString(nestedErr.Error())
-			buf.WriteByte('\n')
-		}
-	}
-	return buf.String()
-}
-
 type Params struct {
 	BlockHeight uint64
 	BlockHash   Word256
@@ -111,7 +52,7 @@ type VM struct {
 	origin           crypto.Address
 	txHash           []byte
 	stackDepth       int
-	nestedCallErrors []ErrNestedCall
+	nestedCallErrors []errors.NestedCall
 	publisher        event.Publisher
 	logger           *logging.Logger
 	returnData       []byte
@@ -157,40 +98,41 @@ func HasPermission(stateWriter state.Writer, acc acm.Account, perm ptypes.PermFl
 	return value
 }
 
-func (vm *VM) fireCallEvent(exception *string, output *[]byte, callerAddress, calleeAddress crypto.Address, input []byte, value uint64, gas *uint64) {
+func (vm *VM) fireCallEvent(exception *errors.CodedError, output *[]byte, callerAddress, calleeAddress crypto.Address, input []byte, value uint64, gas *uint64) {
 	// fire the post call event (including exception if applicable)
 	if vm.publisher != nil {
-		events.PublishAccountCall(vm.publisher, calleeAddress, &events.EventDataCall{
-			CallData: &events.CallData{
-				Caller: callerAddress,
-				Callee: calleeAddress,
-				Data:   input,
-				Value:  value,
-				Gas:    *gas,
-			},
-			Origin:     vm.origin,
-			TxHash:     vm.txHash,
-			StackDepth: vm.stackDepth,
-			Return:     *output,
-			Exception:  *exception,
-		})
+		events.PublishAccountCall(vm.publisher, calleeAddress,
+			&events.EventDataCall{
+				CallData: &events.CallData{
+					Caller: callerAddress,
+					Callee: calleeAddress,
+					Data:   input,
+					Value:  value,
+					Gas:    *gas,
+				},
+				Origin:     vm.origin,
+				TxHash:     vm.txHash,
+				StackDepth: vm.stackDepth,
+				Return:     *output,
+				Exception:  errors.AsCodedError(*exception),
+			})
 	}
 }
 
 // CONTRACT state is aware of caller and callee, so we can just mutate them.
 // CONTRACT code and input are not mutated.
 // CONTRACT returned 'ret' is a new compact slice.
-// value: To be transferred from caller to callee. Refunded upon error.
+// value: To be transferred from caller to callee. Refunded upon errors.CodedError.
 // gas:   Available gas. No refunds for gas.
 // code: May be nil, since the CALL opcode may be used to send value from contracts to accounts
-func (vm *VM) Call(callState state.Cache, caller, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
+func (vm *VM) Call(callState state.Cache, caller, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err errors.CodedError) {
 
-	exception := new(string)
+	exception := new(errors.CodedError)
 	// fire the post call event (including exception if applicable)
 	defer vm.fireCallEvent(exception, &output, caller.Address(), callee.Address(), input, value, gas)
 
 	if err = transfer(caller, callee, value); err != nil {
-		*exception = err.Error()
+		*exception = err
 		return
 	}
 	//childCallState
@@ -201,15 +143,14 @@ func (vm *VM) Call(callState state.Cache, caller, callee acm.MutableAccount, cod
 		output, err = vm.call(childCallState, caller, callee, code, input, value, gas)
 		vm.stackDepth -= 1
 		if err != nil {
-			err = ErrCall{
+			*exception = errors.Call{
 				CallError:    err,
 				NestedErrors: vm.nestedCallErrors,
 			}
-			*exception = err.Error()
 			transferErr := transfer(callee, caller, value)
 			if transferErr != nil {
-				return nil, fmt.Errorf("error transferring value %v %s (callee) -> %s (caller)",
-					value, callee, caller)
+				return nil, errors.Wrap(transferErr,
+					fmt.Sprintf("error transferring value %v %s (callee) -> %s (caller)", value, callee, caller))
 			}
 		} else {
 			// Copy any state updates from child call frame into current call frame
@@ -228,7 +169,7 @@ func (vm *VM) Call(callState state.Cache, caller, callee acm.MutableAccount, cod
 // The intent of delegate call is to run the code of the callee in the storage context of the caller;
 // while preserving the original caller to the previous callee.
 // Different to the normal CALL or CALLCODE, the value does not need to be transferred to the callee.
-func (vm *VM) DelegateCall(callState state.Cache, caller acm.Account, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
+func (vm *VM) DelegateCall(callState state.Cache, caller acm.Account, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err errors.CodedError) {
 
 	exception := new(string)
 	// fire the post call event (including exception if applicable)
@@ -257,18 +198,18 @@ func (vm *VM) DelegateCall(callState state.Cache, caller acm.Account, callee acm
 
 // Try to deduct gasToUse from gasLeft.  If ok return false, otherwise
 // set err and return true.
-func useGasNegative(gasLeft *uint64, gasToUse uint64, err *error) bool {
+func useGasNegative(gasLeft *uint64, gasToUse uint64, err *errors.CodedError) bool {
 	if *gasLeft >= gasToUse {
 		*gasLeft -= gasToUse
 		return false
 	} else if *err == nil {
-		*err = ErrInsufficientGas
+		*err = errors.ErrorCodeInsufficientGas
 	}
 	return true
 }
 
 // Just like Call() but does not transfer 'value' or modify the callDepth.
-func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
+func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.MutableAccount, code, input []byte, value uint64, gas *uint64) (output []byte, err errors.CodedError) {
 	vm.Debugf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.stackDepth, caller.Address().Bytes()[:4], callee.Address(),
 		len(callee.Code()), *gas, input)
 
@@ -555,7 +496,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			data, memErr := memory.Read(offset, size)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 			data = sha3.Sha3(data)
 			stack.PushBytes(data)
@@ -575,7 +516,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 				return nil, firstErr(err, errAcc)
 			}
 			if acc == nil {
-				return nil, firstErr(err, ErrUnknownAddress)
+				return nil, firstErr(err, errors.ErrorCodeUnknownAddress)
 			}
 			balance := acc.Balance()
 			stack.PushU64(balance)
@@ -600,7 +541,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			}
 			data, ok := subslice(input, offset, 32)
 			if !ok {
-				return nil, firstErr(err, ErrInputOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeInputOutOfBounds)
 			}
 			res := LeftPadWord256(data)
 			stack.Push(res)
@@ -622,12 +563,12 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			}
 			data, ok := subslice(input, inputOff, length)
 			if !ok {
-				return nil, firstErr(err, ErrInputOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeInputOutOfBounds)
 			}
 			memErr := memory.Write(memOff, data)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 			vm.Debugf(" => [%v, %v, %v] %X\n", memOff, inputOff, length, data)
 
@@ -648,12 +589,12 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			}
 			data, ok := subslice(code, codeOff, length)
 			if !ok {
-				return nil, firstErr(err, ErrCodeOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeCodeOutOfBounds)
 			}
 			memErr := memory.Write(memOff, data)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 			vm.Debugf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data)
 
@@ -672,7 +613,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			}
 			if acc == nil {
 				if _, ok := registeredNativeContracts[addr]; !ok {
-					return nil, firstErr(err, ErrUnknownAddress)
+					return nil, firstErr(err, errors.ErrorCodeUnknownAddress)
 				}
 				vm.Debugf(" => returning code size of 1 to indicated existence of native contract at %X\n", addr)
 				stack.Push(One256)
@@ -694,9 +635,9 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			if acc == nil {
 				if _, ok := registeredNativeContracts[addr]; ok {
 					vm.Debugf(" => attempted to copy native contract at %X but this is not supported\n", addr)
-					return nil, firstErr(err, ErrNativeContractCodeCopy)
+					return nil, firstErr(err, errors.ErrorCodeNativeContractCodeCopy)
 				}
-				return nil, firstErr(err, ErrUnknownAddress)
+				return nil, firstErr(err, errors.ErrorCodeUnknownAddress)
 			}
 			code := acc.Code()
 			memOff := stack.PopBigInt()
@@ -710,12 +651,12 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			}
 			data, ok := subslice(code, codeOff, length)
 			if !ok {
-				return nil, firstErr(err, ErrCodeOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeCodeOutOfBounds)
 			}
 			memErr := memory.Write(memOff, data)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 			vm.Debugf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data)
 
@@ -729,7 +670,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			end := new(big.Int).Add(outputOff, length)
 
 			if end.BitLen() > 64 || uint64(len(vm.returnData)) < end.Uint64() {
-				return nil, ErrReturnDataOutOfBounds
+				return nil, errors.ErrorCodeReturnDataOutOfBounds
 			}
 
 			data := vm.returnData
@@ -737,7 +678,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			memErr := memory.Write(memOff, data)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 			vm.Debugf(" => [%v, %v, %v] %X\n", memOff, outputOff, length, data)
 
@@ -772,7 +713,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			data, memErr := memory.Read(offset, BigWord256Length)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 			stack.Push(LeftPadWord256(data))
 			vm.Debugf(" => 0x%X @ 0x%X\n", data, offset)
@@ -782,7 +723,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			memErr := memory.Write(offset, data.Bytes())
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 			vm.Debugf(" => 0x%X @ 0x%X\n", data, offset)
 
@@ -796,7 +737,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			memErr := memory.Write(offset, []byte{val})
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 			vm.Debugf(" => [%v] 0x%X\n", offset, val)
 
@@ -867,7 +808,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			a := int64(op - PUSH1 + 1)
 			codeSegment, ok := subslice(code, pc+1, a)
 			if !ok {
-				return nil, firstErr(err, ErrCodeOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeCodeOutOfBounds)
 			}
 			res := LeftPadWord256(codeSegment)
 			stack.Push(res)
@@ -896,7 +837,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			data, memErr := memory.Read(offset, size)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 			if vm.publisher != nil {
 				events.PublishLogEvent(vm.publisher, callee.Address(), &events.EventDataLog{
@@ -911,8 +852,8 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 		case CREATE: // 0xF0
 			vm.returnData = nil
 
-			if !HasPermission(callState, callee, permission.CreateContract) {
-				return nil, ErrPermission{"create_contract"}
+			if !HasPermission(callState, callee, ptypes.CreateContract) {
+				return nil, errors.PermissionDenied{Perm: ptypes.CreateContract}
 			}
 			contractValue, popErr := stack.PopU64()
 			if popErr != nil {
@@ -922,16 +863,16 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			input, memErr := memory.Read(offset, size)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 
 			// Check balance
 			if callee.Balance() < uint64(contractValue) {
-				return nil, firstErr(err, ErrInsufficientBalance)
+				return nil, firstErr(err, errors.ErrorCodeInsufficientBalance)
 			}
 
 			// TODO charge for gas to create account _ the code length * GasCreateByte
-			var gasErr error
+			var gasErr errors.CodedError
 			if useGasNegative(gas, GasCreateAccount, &gasErr) {
 				return nil, firstErr(err, gasErr)
 			}
@@ -942,24 +883,24 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 
 			// Run the input to get the contract code.
 			// NOTE: no need to copy 'input' as per Call contract.
-			ret, err_ := vm.Call(callState, callee, newAccount, input, input, contractValue, gas)
-			if err_ != nil {
+			ret, callErr := vm.Call(callState, callee, newAccount, input, input, contractValue, gas)
+			if callErr != nil {
 				stack.Push(Zero256)
+				// Note we both set the return buffer and return the result normally
 				vm.returnData = ret
+				if callErr.ErrorCode() == errors.ErrorCodeExecutionReverted {
+					return ret, callErr
+				}
 			} else {
 				newAccount.SetCode(ret) // Set the code (ret need not be copied as per Call contract)
 				stack.Push(newAccount.Address().Word256())
 			}
 
-			if err_ == ErrExecutionReverted {
-				return nil, ErrExecutionReverted
-			}
-
 		case CALL, CALLCODE, DELEGATECALL: // 0xF1, 0xF2, 0xF4
 			vm.returnData = nil
 
-			if !HasPermission(callState, callee, permission.Call) {
-				return nil, ErrPermission{"call"}
+			if !HasPermission(callState, callee, ptypes.Call) {
+				return nil, errors.PermissionDenied{Perm: ptypes.Call}
 			}
 			gasLimit, popErr := stack.PopU64()
 			if popErr != nil {
@@ -991,12 +932,12 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			args, memErr := memory.Read(inOffset, inSize)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 
 			// Ensure that gasLimit is reasonable
 			if *gas < gasLimit {
-				// EIP150 - the 63/64 rule - rather than error we pass this specified fraction of the total available gas
+				// EIP150 - the 63/64 rule - rather than errors.CodedError we pass this specified fraction of the total available gas
 				gasLimit = *gas - *gas/64
 			}
 			// NOTE: we will return any used gas later.
@@ -1004,19 +945,14 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 
 			// Begin execution
 			var ret []byte
-			var callErr error
+			var callErr errors.CodedError
 
-			if nativeContract := registeredNativeContracts[addr]; nativeContract != nil {
+			if IsRegisteredNativeContract(addr) {
 				// Native contract
-				ret, callErr = nativeContract(callState, callee, args, &gasLimit, logger)
-
+				ret, callErr = ExecuteNativeContract(addr, callState, callee, args, &gasLimit, logger)
 				// for now we fire the Call event. maybe later we'll fire more particulars
-				var exception string
-				if callErr != nil {
-					exception = callErr.Error()
-				}
 				// NOTE: these fire call go_events and not particular go_events for eg name reg or permissions
-				vm.fireCallEvent(&exception, &ret, callee.Address(), crypto.AddressFromWord256(addr), args, value, &gasLimit)
+				vm.fireCallEvent(&callErr, &ret, callee.Address(), crypto.AddressFromWord256(addr), args, value, &gasLimit)
 			} else {
 				// EVM contract
 				if useGasNegative(gas, GasGetAccount, &callErr) {
@@ -1027,24 +963,24 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 					return nil, firstErr(callErr, errAcc)
 				}
 				// since CALL is used also for sending funds,
-				// acc may not exist yet. This is an error for
+				// acc may not exist yet. This is an errors.CodedError for
 				// CALLCODE, but not for CALL, though I don't think
 				// ethereum actually cares
 				if op == CALLCODE {
 					if acc == nil {
-						return nil, firstErr(callErr, ErrUnknownAddress)
+						return nil, firstErr(callErr, errors.ErrorCodeUnknownAddress)
 					}
 					ret, callErr = vm.Call(callState, callee, callee, acc.Code(), args, value, &gasLimit)
 				} else if op == DELEGATECALL {
 					if acc == nil {
-						return nil, firstErr(callErr, ErrUnknownAddress)
+						return nil, firstErr(callErr, errors.ErrorCodeUnknownAddress)
 					}
 					ret, callErr = vm.DelegateCall(callState, caller, callee, acc.Code(), args, value, &gasLimit)
 				} else {
 					// nil account means we're sending funds to a new account
 					if acc == nil {
-						if !HasPermission(callState, caller, permission.CreateAccount) {
-							return nil, ErrPermission{"create_account"}
+						if !HasPermission(callState, caller, ptypes.CreateAccount) {
+							return nil, errors.PermissionDenied{Perm: ptypes.CreateAccount}
 						}
 						acc = acm.ConcreteAccount{Address: crypto.AddressFromWord256(addr)}.MutableAccount()
 					}
@@ -1070,8 +1006,8 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			// Push result
 			if callErr != nil {
 				vm.Debugf("error from nested sub-call (depth: %v): %s\n", vm.stackDepth, callErr.Error())
-				// So we can return nested error if the top level return is an error
-				vm.nestedCallErrors = append(vm.nestedCallErrors, ErrNestedCall{
+				// So we can return nested errors.CodedError if the top level return is an errors.CodedError
+				vm.nestedCallErrors = append(vm.nestedCallErrors, errors.NestedCall{
 					NestedError: callErr,
 					StackDepth:  vm.stackDepth,
 					Caller:      caller.Address(),
@@ -1079,7 +1015,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 				})
 				stack.Push(Zero256)
 
-				if callErr == ErrExecutionReverted {
+				if callErr.ErrorCode() == errors.ErrorCodeExecutionReverted {
 					memory.Write(retOffset, RightPadBytes(ret, int(retSize)))
 				}
 			} else {
@@ -1091,7 +1027,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 				memErr := memory.Write(retOffset, RightPadBytes(ret, int(retSize)))
 				if memErr != nil {
 					vm.Debugf(" => Memory err: %s", memErr)
-					return nil, firstErr(callErr, ErrMemoryOutOfBounds)
+					return nil, firstErr(callErr, errors.ErrorCodeMemoryOutOfBounds)
 				}
 			}
 
@@ -1105,7 +1041,7 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			output, memErr := memory.Read(offset, size)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 			vm.Debugf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(output), output)
 			return output, nil
@@ -1115,14 +1051,14 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			output, memErr := memory.Read(offset, size)
 			if memErr != nil {
 				vm.Debugf(" => Memory err: %s", memErr)
-				return nil, firstErr(err, ErrMemoryOutOfBounds)
+				return nil, firstErr(err, errors.ErrorCodeMemoryOutOfBounds)
 			}
 
 			vm.Debugf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(output), output)
-			return output, ErrExecutionReverted
+			return output, errors.ErrorCodeExecutionReverted
 
 		case INVALID: //0xFE
-			return nil, ErrExecutionAborted
+			return nil, errors.ErrorCodeExecutionAborted
 
 		case SELFDESTRUCT: // 0xFF
 			addr := stack.Pop()
@@ -1134,14 +1070,14 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 				return nil, firstErr(err, errAcc)
 			}
 			if receiver == nil {
-				var gasErr error
+				var gasErr errors.CodedError
 				if useGasNegative(gas, GasCreateAccount, &gasErr) {
 					return nil, firstErr(err, gasErr)
 				}
-				if !HasPermission(callState, callee, permission.CreateContract) {
-					return nil, firstErr(err, ErrPermission{"create_contract"})
+				if !HasPermission(callState, callee, ptypes.CreateContract) {
+					return nil, firstErr(err, errors.PermissionDenied{Perm: ptypes.CreateContract})
 				}
-				var createErr error
+				var createErr errors.CodedError
 				receiver, createErr = vm.createAccount(callState, callee, logger)
 				if createErr != nil {
 					return nil, firstErr(err, createErr)
@@ -1162,25 +1098,25 @@ func (vm *VM) call(callState state.Cache, caller acm.Account, callee acm.Mutable
 			return nil, nil
 
 		case STATICCALL, CREATE2:
-			return nil, fmt.Errorf("%s not yet implemented", op.Name())
+			return nil, errors.Errorf("%s not yet implemented", op.Name())
 
 		default:
 			vm.Debugf("(pc) %-3v Unknown opcode %X\n", pc, op)
-			return nil, fmt.Errorf("unknown opcode %X", op)
+			return nil, errors.Errorf("unknown opcode %X", op)
 		}
 		pc++
 	}
 }
 
-func (vm *VM) createAccount(callState state.Cache, callee acm.MutableAccount, logger *logging.Logger) (acm.MutableAccount, error) {
+func (vm *VM) createAccount(callState state.Cache, callee acm.MutableAccount, logger *logging.Logger) (acm.MutableAccount, errors.CodedError) {
 	newAccount := DeriveNewAccount(callee, state.GlobalAccountPermissions(callState), logger)
 	err := callState.UpdateAccount(newAccount)
 	if err != nil {
-		return nil, err
+		return nil, errors.AsCodedError(err)
 	}
 	err = callState.UpdateAccount(callee)
 	if err != nil {
-		return nil, err
+		return nil, errors.AsCodedError(err)
 	}
 	return newAccount, nil
 }
@@ -1216,33 +1152,33 @@ func codeGetOp(code []byte, n int64) OpCode {
 	}
 }
 
-func (vm *VM) jump(code []byte, to int64, pc *int64) (err error) {
+func (vm *VM) jump(code []byte, to int64, pc *int64) (err errors.CodedError) {
 	dest := codeGetOp(code, to)
 	if dest != JUMPDEST {
 		vm.Debugf(" ~> %v invalid jump dest %v\n", to, dest)
-		return ErrInvalidJumpDest
+		return errors.ErrorCodeInvalidJumpDest
 	}
 	vm.Debugf(" ~> %v\n", to)
 	*pc = to
 	return nil
 }
 
-func firstErr(errA, errB error) error {
+func firstErr(errA, errB error) errors.CodedError {
 	if errA != nil {
-		return errA
+		return errors.AsCodedError(errA)
 	} else {
-		return errB
+		return errors.AsCodedError(errB)
 	}
 }
 
-func transfer(from, to acm.MutableAccount, amount uint64) error {
+func transfer(from, to acm.MutableAccount, amount uint64) errors.CodedError {
 	if from.Balance() < amount {
-		return ErrInsufficientBalance
+		return errors.ErrorCodeInsufficientBalance
 	} else {
 		from.SubtractFromBalance(amount)
 		_, err := to.AddToBalance(amount)
 		if err != nil {
-			return err
+			return errors.AsCodedError(err)
 		}
 	}
 	return nil
diff --git a/execution/evm/vm_test.go b/execution/evm/vm_test.go
index fcd008459d25238492445e8acf065ef7dce91b8a..b7752b66c324ece4cc1d0f97d4f497934084e3cb 100644
--- a/execution/evm/vm_test.go
+++ b/execution/evm/vm_test.go
@@ -17,7 +17,6 @@ package evm
 import (
 	"context"
 	"encoding/hex"
-	"errors"
 	"fmt"
 	"strconv"
 	"testing"
@@ -28,6 +27,7 @@ import (
 	. "github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/event"
+	"github.com/hyperledger/burrow/execution/errors"
 	. "github.com/hyperledger/burrow/execution/evm/asm"
 	. "github.com/hyperledger/burrow/execution/evm/asm/bc"
 	evm_events "github.com/hyperledger/burrow/execution/evm/events"
@@ -663,8 +663,8 @@ func TestRevert(t *testing.T) {
 	0x67, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, PUSH1, 0x00, MSTORE, PUSH1, 0x0E, PUSH1, 0x00, REVERT)*/
 
-	output, err := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas)
-	assert.Error(t, err, "Expected execution reverted error")
+	output, cErr := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas)
+	assert.Error(t, cErr, "Expected execution reverted error")
 
 	storageVal, err := cache.GetStorage(account1.Address(), LeftPadWord256(key))
 	assert.Equal(t, LeftPadWord256(value), storageVal)
@@ -884,7 +884,7 @@ func TestInvalid(t *testing.T) {
 		0x00, 0x00, 0x00, PUSH1, 0x00, MSTORE, PUSH1, 0x0E, PUSH1, 0x00, INVALID)
 
 	output, err := ourVm.Call(cache, account1, account2, bytecode, []byte{}, 0, &gas)
-	expected := "call error: " + ErrExecutionAborted.Error()
+	expected := errors.ErrorCodeExecutionAborted.Error()
 	assert.EqualError(t, err, expected)
 	t.Logf("Output: %v Error: %v\n", output, err)
 
@@ -1021,8 +1021,8 @@ func runVMWaitError(vmCache state.Cache, ourVm *VM, caller, callee acm.MutableAc
 	}
 	select {
 	case eventDataCall := <-eventCh:
-		if eventDataCall.Exception != "" {
-			return output, errors.New(eventDataCall.Exception)
+		if eventDataCall.Exception != nil {
+			return output, eventDataCall.Exception
 		}
 		return output, nil
 	}
diff --git a/execution/execution.go b/execution/execution.go
index 74eab81fe51fae147219e0fbcd3bc4935a478cc7..74e6ce5fc1a97eb9ae198bbf665dab18d96357ce 100644
--- a/execution/execution.go
+++ b/execution/execution.go
@@ -25,26 +25,25 @@ import (
 	bcm "github.com/hyperledger/burrow/blockchain"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/event"
-	"github.com/hyperledger/burrow/execution/events"
 	"github.com/hyperledger/burrow/execution/evm"
+	"github.com/hyperledger/burrow/execution/executors"
 	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
-	"github.com/hyperledger/burrow/permission"
-	ptypes "github.com/hyperledger/burrow/permission/types"
 	"github.com/hyperledger/burrow/txs"
 	"github.com/hyperledger/burrow/txs/payload"
 )
 
-// TODO: make configurable
-const GasLimit = uint64(1000000)
+type Executor interface {
+	Execute(txEnv *txs.Envelope) error
+}
 
 type BatchExecutor interface {
 	// Provides access to write lock for a BatchExecutor so reads can be prevented for the duration of a commit
 	sync.Locker
 	state.Reader
 	// Execute transaction against block cache (i.e. block buffer)
-	Execute(txEnv *txs.Envelope) error
+	Executor
 	// Reset executor to underlying State
 	Reset() error
 }
@@ -59,55 +58,105 @@ type BatchCommitter interface {
 
 type executor struct {
 	sync.RWMutex
-	chainID      string
-	tip          *bcm.Tip
 	runCall      bool
 	state        *State
 	stateCache   state.Cache
-	nameRegCache *NameRegCache
-	publisher    event.Publisher
+	nameRegCache *names.Cache
 	eventCache   *event.Cache
 	logger       *logging.Logger
 	vmOptions    []func(*evm.VM)
+	txExecutors  map[payload.Type]Executor
 }
 
 var _ BatchExecutor = (*executor)(nil)
 
 // Wraps a cache of what is variously known as the 'check cache' and 'mempool'
-func NewBatchChecker(backend *State, chainID string, tip *bcm.Tip, logger *logging.Logger,
+func NewBatchChecker(backend *State, tip *bcm.Tip, logger *logging.Logger,
 	options ...ExecutionOption) BatchExecutor {
 
-	return newExecutor("CheckCache", false, backend, chainID, tip, event.NewNoOpPublisher(),
+	return newExecutor("CheckCache", false, backend, tip, event.NewNoOpPublisher(),
 		logger.WithScope("NewBatchExecutor"), options...)
 }
 
-func NewBatchCommitter(backend *State, chainID string, tip *bcm.Tip, publisher event.Publisher, logger *logging.Logger,
+func NewBatchCommitter(backend *State, tip *bcm.Tip, publisher event.Publisher, logger *logging.Logger,
 	options ...ExecutionOption) BatchCommitter {
 
-	return newExecutor("CommitCache", true, backend, chainID, tip, publisher,
+	return newExecutor("CommitCache", true, backend, tip, publisher,
 		logger.WithScope("NewBatchCommitter"), options...)
 }
 
-func newExecutor(name string, runCall bool, backend *State, chainID string, tip *bcm.Tip, publisher event.Publisher,
+func newExecutor(name string, runCall bool, backend *State, tip *bcm.Tip, publisher event.Publisher,
 	logger *logging.Logger, options ...ExecutionOption) *executor {
 
 	exe := &executor{
-		chainID:      chainID,
-		tip:          tip,
 		runCall:      runCall,
 		state:        backend,
 		stateCache:   state.NewCache(backend, state.Name(name)),
-		nameRegCache: NewNameRegCache(backend),
-		publisher:    publisher,
 		eventCache:   event.NewEventCache(publisher),
+		nameRegCache: names.NewCache(backend),
 		logger:       logger.With(structure.ComponentKey, "Executor"),
 	}
 	for _, option := range options {
 		option(exe)
 	}
+	exe.txExecutors = map[payload.Type]Executor{
+		payload.TypeSend: &executors.SendContext{
+			StateWriter:    exe.stateCache,
+			EventPublisher: exe.eventCache,
+			Logger:         exe.logger,
+		},
+		payload.TypeCall: &executors.CallContext{
+			StateWriter:    exe.stateCache,
+			EventPublisher: exe.eventCache,
+			Tip:            tip,
+			RunCall:        runCall,
+			VMOptions:      exe.vmOptions,
+			Logger:         exe.logger,
+		},
+		payload.TypeName: &executors.NameContext{
+			StateWriter:    exe.stateCache,
+			EventPublisher: exe.eventCache,
+			NameReg:        exe.nameRegCache,
+			Tip:            tip,
+			Logger:         exe.logger,
+		},
+		payload.TypePermissions: &executors.PermissionsContext{
+			StateWriter:    exe.stateCache,
+			EventPublisher: exe.eventCache,
+			Logger:         exe.logger,
+		},
+	}
 	return exe
 }
 
+// If the tx is invalid, an error will be returned.
+// Unlike ExecBlock(), state will not be altered.
+func (exe *executor) Execute(txEnv *txs.Envelope) (err error) {
+	defer func() {
+		if r := recover(); r != nil {
+			err = fmt.Errorf("recovered from panic in executor.Execute(%s): %v\n%s", txEnv.String(), r,
+				debug.Stack())
+		}
+	}()
+
+	logger := exe.logger.WithScope("executor.Execute(tx txs.Tx)").With(
+		"run_call", exe.runCall,
+		"tx_hash", txEnv.Tx.Hash())
+
+	logger.TraceMsg("Executing transaction", "tx", txEnv.String())
+
+	// Verify transaction signature against inputs
+	err = txEnv.Verify(exe.stateCache)
+	if err != nil {
+		return err
+	}
+
+	if txExecutor, ok := exe.txExecutors[txEnv.Tx.Type()]; ok {
+		return txExecutor.Execute(txEnv)
+	}
+	return fmt.Errorf("unknown transaction type: %v", txEnv.Tx.Type())
+}
+
 // executor exposes access to the underlying state cache protected by a RWMutex that prevents access while locked
 // (during an ABCI commit). while access can occur (and needs to continue for CheckTx/DeliverTx to make progress)
 // through calls to Execute() external readers will be blocked until the executor is unlocked that allows the Transactor
@@ -160,1094 +209,3 @@ func (exe *executor) Reset() error {
 	exe.nameRegCache.Reset(exe.state)
 	return nil
 }
-
-// If the tx is invalid, an error will be returned.
-// Unlike ExecBlock(), state will not be altered.
-func (exe *executor) Execute(txEnv *txs.Envelope) (err error) {
-	defer func() {
-		if r := recover(); r != nil {
-			err = fmt.Errorf("recovered from panic in executor.Execute(%s): %v\n%s", txEnv.String(), r,
-				debug.Stack())
-		}
-	}()
-
-	logger := exe.logger.WithScope("executor.Execute(tx txs.Tx)").With(
-		"run_call", exe.runCall,
-		"tx_hash", txEnv.Tx.Hash())
-	logger.TraceMsg("Executing transaction", "tx", txEnv.String())
-	// TODO: do something with fees
-	fees := uint64(0)
-
-	// Verify transaction signature against inputs
-	err = txEnv.Verify(exe.stateCache)
-	if err != nil {
-		return err
-	}
-
-	// Exec tx
-	switch tx := txEnv.Tx.Payload.(type) {
-	case *payload.SendTx:
-		accounts, err := getInputs(exe.stateCache, tx.Inputs)
-		if err != nil {
-			return err
-		}
-
-		// ensure all inputs have send permissions
-		if !hasSendPermission(exe.stateCache, accounts, logger) {
-			return fmt.Errorf("at least one input lacks permission for SendTx")
-		}
-
-		// add outputs to accounts map
-		// if any outputs don't exist, all inputs must have CreateAccount perm
-		accounts, err = getOrMakeOutputs(exe.stateCache, accounts, tx.Outputs, logger)
-		if err != nil {
-			return err
-		}
-
-		inTotal, err := validateInputs(accounts, tx.Inputs)
-		if err != nil {
-			return err
-		}
-		outTotal, err := validateOutputs(tx.Outputs)
-		if err != nil {
-			return err
-		}
-		if outTotal > inTotal {
-			return payload.ErrTxInsufficientFunds
-		}
-		fee := inTotal - outTotal
-		fees += fee
-
-		// Good! Adjust accounts
-		err = adjustByInputs(accounts, tx.Inputs, logger)
-		if err != nil {
-			return err
-		}
-
-		err = adjustByOutputs(accounts, tx.Outputs)
-		if err != nil {
-			return err
-		}
-
-		for _, acc := range accounts {
-			exe.stateCache.UpdateAccount(acc)
-		}
-
-		if exe.eventCache != nil {
-			for _, i := range tx.Inputs {
-				events.PublishAccountInput(exe.eventCache, i.Address, txEnv.Tx, nil, "")
-			}
-
-			for _, o := range tx.Outputs {
-				events.PublishAccountOutput(exe.eventCache, o.Address, txEnv.Tx, nil, "")
-			}
-		}
-		return nil
-
-	case *payload.CallTx:
-		var inAcc acm.MutableAccount
-		var outAcc acm.Account
-
-		// Validate input
-		inAcc, err := state.GetMutableAccount(exe.stateCache, tx.Input.Address)
-		if err != nil {
-			return err
-		}
-		if inAcc == nil {
-			logger.InfoMsg("Cannot find input account",
-				"tx_input", tx.Input)
-			return payload.ErrTxInvalidAddress
-		}
-
-		// Calling a nil destination is defined as requesting contract creation
-		createContract := tx.Address == nil
-		if createContract {
-			if !hasCreateContractPermission(exe.stateCache, inAcc, logger) {
-				return fmt.Errorf("account %s does not have CreateContract permission", tx.Input.Address)
-			}
-		} else {
-			if !hasCallPermission(exe.stateCache, inAcc, logger) {
-				return fmt.Errorf("account %s does not have Call permission", tx.Input.Address)
-			}
-		}
-
-		err = validateInput(inAcc, tx.Input)
-		if err != nil {
-			logger.InfoMsg("validateInput failed",
-				"tx_input", tx.Input, structure.ErrorKey, err)
-			return err
-		}
-		if tx.Input.Amount < tx.Fee {
-			logger.InfoMsg("Sender did not send enough to cover the fee",
-				"tx_input", tx.Input)
-			return payload.ErrTxInsufficientFunds
-		}
-
-		if !createContract {
-			// check if its a native contract
-			if evm.RegisteredNativeContract(tx.Address.Word256()) {
-				return fmt.Errorf("attempt to call a native contract at %s, "+
-					"but native contracts cannot be called using CallTx. Use a "+
-					"contract that calls the native contract or the appropriate tx "+
-					"type (eg. PermissionsTx, NameTx)", tx.Address)
-			}
-
-			// Output account may be nil if we are still in mempool and contract was created in same block as this tx
-			// but that's fine, because the account will be created properly when the create tx runs in the block
-			// and then this won't return nil. otherwise, we take their fee
-			// Note: tx.Address == nil iff createContract so dereference is okay
-			outAcc, err = exe.stateCache.GetAccount(*tx.Address)
-			if err != nil {
-				return err
-			}
-		}
-
-		logger.Trace.Log("output_account", outAcc)
-
-		// Good!
-		value := tx.Input.Amount - tx.Fee
-
-		logger.TraceMsg("Incrementing sequence number for CallTx",
-			"tag", "sequence",
-			"account", inAcc.Address(),
-			"old_sequence", inAcc.Sequence(),
-			"new_sequence", inAcc.Sequence()+1)
-
-		inAcc, err = inAcc.IncSequence().SubtractFromBalance(tx.Fee)
-		if err != nil {
-			return err
-		}
-
-		exe.stateCache.UpdateAccount(inAcc)
-
-		// The logic in runCall MUST NOT return.
-		if exe.runCall {
-			// VM call variables
-			var (
-				gas     uint64             = tx.GasLimit
-				err     error              = nil
-				caller  acm.MutableAccount = acm.AsMutableAccount(inAcc)
-				callee  acm.MutableAccount = nil // initialized below
-				code    []byte             = nil
-				ret     []byte             = nil
-				txCache                    = state.NewCache(exe.stateCache, state.Name("TxCache"))
-				params                     = evm.Params{
-					BlockHeight: exe.tip.LastBlockHeight(),
-					BlockHash:   binary.LeftPadWord256(exe.tip.LastBlockHash()),
-					BlockTime:   exe.tip.LastBlockTime().Unix(),
-					GasLimit:    GasLimit,
-				}
-			)
-
-			if !createContract && (outAcc == nil || len(outAcc.Code()) == 0) {
-				// if you call an account that doesn't exist
-				// or an account with no code then we take fees (sorry pal)
-				// NOTE: it's fine to create a contract and call it within one
-				// block (sequence number will prevent re-ordering of those txs)
-				// but to create with one contract and call with another
-				// you have to wait a block to avoid a re-ordering attack
-				// that will take your fees
-				if outAcc == nil {
-					logger.InfoMsg("Call to address that does not exist",
-						"caller_address", inAcc.Address(),
-						"callee_address", tx.Address)
-				} else {
-					logger.InfoMsg("Call to address that holds no code",
-						"caller_address", inAcc.Address(),
-						"callee_address", tx.Address)
-				}
-				err = payload.ErrTxInvalidAddress
-				goto CALL_COMPLETE
-			}
-
-			// get or create callee
-			if createContract {
-				// We already checked for permission
-				callee = evm.DeriveNewAccount(caller, state.GlobalAccountPermissions(exe.state),
-					logger.With(
-						"tx", tx.String(),
-						"tx_hash", txEnv.Tx.Hash(),
-						"run_call", exe.runCall,
-					))
-				code = tx.Data
-				logger.TraceMsg("Creating new contract",
-					"contract_address", callee.Address(),
-					"init_code", code)
-			} else {
-				callee = acm.AsMutableAccount(outAcc)
-				code = callee.Code()
-				logger.TraceMsg("Calling existing contract",
-					"contract_address", callee.Address(),
-					"input", tx.Data,
-					"contract_code", code)
-			}
-			logger.Trace.Log("callee", callee.Address().String())
-
-			// Run VM call and sync txCache to exe.blockCache.
-			{ // Capture scope for goto.
-				// Write caller/callee to txCache.
-				txCache.UpdateAccount(caller)
-				txCache.UpdateAccount(callee)
-				vmach := evm.NewVM(params, caller.Address(), txEnv.Tx.Hash(), logger, exe.vmOptions...)
-				vmach.SetPublisher(exe.eventCache)
-				// NOTE: Call() transfers the value from caller to callee iff call succeeds.
-				ret, err = vmach.Call(txCache, caller, callee, code, tx.Data, value, &gas)
-				if err != nil {
-					// Failure. Charge the gas fee. The 'value' was otherwise not transferred.
-					logger.InfoMsg("Error on execution",
-						structure.ErrorKey, err)
-					goto CALL_COMPLETE
-				}
-
-				logger.TraceMsg("Successful execution")
-				if createContract {
-					callee.SetCode(ret)
-				}
-				txCache.Sync(exe.stateCache)
-			}
-
-		CALL_COMPLETE: // err may or may not be nil.
-
-			// Create a receipt from the ret and whether it erred.
-			logger.TraceMsg("VM call complete",
-				"caller", caller,
-				"callee", callee,
-				"return", ret,
-				structure.ErrorKey, err)
-
-			// Fire Events for sender and receiver
-			// a separate event will be fired from vm for each additional call
-			if exe.eventCache != nil {
-				exception := ""
-				if err != nil {
-					exception = err.Error()
-				}
-				events.PublishAccountInput(exe.eventCache, tx.Input.Address, txEnv.Tx, ret, exception)
-				if tx.Address != nil {
-					events.PublishAccountOutput(exe.eventCache, *tx.Address, txEnv.Tx, ret, exception)
-				}
-			}
-		} else {
-			// The mempool does not call txs until
-			// the proposer determines the order of txs.
-			// So mempool will skip the actual .Call(),
-			// and only deduct from the caller's balance.
-			inAcc, err = inAcc.SubtractFromBalance(value)
-			if err != nil {
-				return err
-			}
-			if createContract {
-				// This is done by DeriveNewAccount when runCall == true
-				logger.TraceMsg("Incrementing sequence number since creates contract",
-					"tag", "sequence",
-					"account", inAcc.Address(),
-					"old_sequence", inAcc.Sequence(),
-					"new_sequence", inAcc.Sequence()+1)
-				inAcc.IncSequence()
-			}
-			exe.stateCache.UpdateAccount(inAcc)
-		}
-
-		return nil
-
-	case *payload.NameTx:
-		// Validate input
-		inAcc, err := state.GetMutableAccount(exe.stateCache, tx.Input.Address)
-		if err != nil {
-			return err
-		}
-		if inAcc == nil {
-			logger.InfoMsg("Cannot find input account",
-				"tx_input", tx.Input)
-			return payload.ErrTxInvalidAddress
-		}
-		// check permission
-		if !hasNamePermission(exe.stateCache, inAcc, logger) {
-			return fmt.Errorf("account %s does not have Name permission", tx.Input.Address)
-		}
-		err = validateInput(inAcc, tx.Input)
-		if err != nil {
-			logger.InfoMsg("validateInput failed",
-				"tx_input", tx.Input, structure.ErrorKey, err)
-			return err
-		}
-		if tx.Input.Amount < tx.Fee {
-			logger.InfoMsg("Sender did not send enough to cover the fee",
-				"tx_input", tx.Input)
-			return payload.ErrTxInsufficientFunds
-		}
-
-		// validate the input strings
-		if err := tx.ValidateStrings(); err != nil {
-			return err
-		}
-
-		value := tx.Input.Amount - tx.Fee
-
-		// let's say cost of a name for one block is len(data) + 32
-		costPerBlock := names.NameCostPerBlock(names.NameBaseCost(tx.Name, tx.Data))
-		expiresIn := value / uint64(costPerBlock)
-		lastBlockHeight := exe.tip.LastBlockHeight()
-
-		logger.TraceMsg("New NameTx",
-			"value", value,
-			"cost_per_block", costPerBlock,
-			"expires_in", expiresIn,
-			"last_block_height", lastBlockHeight)
-
-		// check if the name exists
-		entry, err := exe.nameRegCache.GetNameRegEntry(tx.Name)
-		if err != nil {
-			return err
-		}
-
-		if entry != nil {
-			var expired bool
-
-			// if the entry already exists, and hasn't expired, we must be owner
-			if entry.Expires > lastBlockHeight {
-				// ensure we are owner
-				if entry.Owner != tx.Input.Address {
-					return fmt.Errorf("permission denied: sender %s is trying to update a name (%s) for "+
-						"which they are not an owner", tx.Input.Address, tx.Name)
-				}
-			} else {
-				expired = true
-			}
-
-			// no value and empty data means delete the entry
-			if value == 0 && len(tx.Data) == 0 {
-				// maybe we reward you for telling us we can delete this crap
-				// (owners if not expired, anyone if expired)
-				logger.TraceMsg("Removing NameReg entry (no value and empty data in tx requests this)",
-					"name", entry.Name)
-				err := exe.nameRegCache.RemoveNameRegEntry(entry.Name)
-				if err != nil {
-					return err
-				}
-			} else {
-				// update the entry by bumping the expiry
-				// and changing the data
-				if expired {
-					if expiresIn < names.MinNameRegistrationPeriod {
-						return fmt.Errorf("Names must be registered for at least %d blocks", names.MinNameRegistrationPeriod)
-					}
-					entry.Expires = lastBlockHeight + expiresIn
-					entry.Owner = tx.Input.Address
-					logger.TraceMsg("An old NameReg entry has expired and been reclaimed",
-						"name", entry.Name,
-						"expires_in", expiresIn,
-						"owner", entry.Owner)
-				} else {
-					// since the size of the data may have changed
-					// we use the total amount of "credit"
-					oldCredit := (entry.Expires - lastBlockHeight) * names.NameBaseCost(entry.Name, entry.Data)
-					credit := oldCredit + value
-					expiresIn = uint64(credit / costPerBlock)
-					if expiresIn < names.MinNameRegistrationPeriod {
-						return fmt.Errorf("names must be registered for at least %d blocks", names.MinNameRegistrationPeriod)
-					}
-					entry.Expires = lastBlockHeight + expiresIn
-					logger.TraceMsg("Updated NameReg entry",
-						"name", entry.Name,
-						"expires_in", expiresIn,
-						"old_credit", oldCredit,
-						"value", value,
-						"credit", credit)
-				}
-				entry.Data = tx.Data
-				err := exe.nameRegCache.UpdateNameRegEntry(entry)
-				if err != nil {
-					return err
-				}
-			}
-		} else {
-			if expiresIn < names.MinNameRegistrationPeriod {
-				return fmt.Errorf("Names must be registered for at least %d blocks", names.MinNameRegistrationPeriod)
-			}
-			// entry does not exist, so create it
-			entry = &NameRegEntry{
-				Name:    tx.Name,
-				Owner:   tx.Input.Address,
-				Data:    tx.Data,
-				Expires: lastBlockHeight + expiresIn,
-			}
-			logger.TraceMsg("Creating NameReg entry",
-				"name", entry.Name,
-				"expires_in", expiresIn)
-			err := exe.nameRegCache.UpdateNameRegEntry(entry)
-			if err != nil {
-				return err
-			}
-		}
-
-		// TODO: something with the value sent?
-
-		// Good!
-		logger.TraceMsg("Incrementing sequence number for NameTx",
-			"tag", "sequence",
-			"account", inAcc.Address(),
-			"old_sequence", inAcc.Sequence(),
-			"new_sequence", inAcc.Sequence()+1)
-		inAcc.IncSequence()
-		inAcc, err = inAcc.SubtractFromBalance(value)
-		if err != nil {
-			return err
-		}
-		exe.stateCache.UpdateAccount(inAcc)
-
-		// TODO: maybe we want to take funds on error and allow txs in that don't do anythingi?
-
-		if exe.eventCache != nil {
-			events.PublishAccountInput(exe.eventCache, tx.Input.Address, txEnv.Tx, nil, "")
-			events.PublishNameReg(exe.eventCache, txEnv.Tx)
-		}
-
-		return nil
-
-		// Consensus related Txs inactivated for now
-		// TODO!
-		/*
-			case *payload.BondTx:
-						valInfo := exe.blockCache.State().GetValidatorInfo(tx.PublicKey().Address())
-						if valInfo != nil {
-							// TODO: In the future, check that the validator wasn't destroyed,
-							// add funds, merge UnbondTo outputs, and unbond validator.
-							return errors.New("Adding coins to existing validators not yet supported")
-						}
-
-						accounts, err := getInputs(exe.blockCache, tx.Inputs)
-						if err != nil {
-							return err
-						}
-
-						// add outputs to accounts map
-						// if any outputs don't exist, all inputs must have CreateAccount perm
-						// though outputs aren't created until unbonding/release time
-						canCreate := hasCreateAccountPermission(exe.blockCache, accounts)
-						for _, out := range tx.UnbondTo {
-							acc := exe.blockCache.GetAccount(out.Address)
-							if acc == nil && !canCreate {
-								return fmt.Errorf("At least one input does not have permission to create accounts")
-							}
-						}
-
-						bondAcc := exe.blockCache.GetAccount(tx.PublicKey().Address())
-						if !hasBondPermission(exe.blockCache, bondAcc) {
-							return fmt.Errorf("The bonder does not have permission to bond")
-						}
-
-						if !hasBondOrSendPermission(exe.blockCache, accounts) {
-							return fmt.Errorf("At least one input lacks permission to bond")
-						}
-
-						signBytes := acm.SignBytes(exe.chainID, tx)
-						inTotal, err := validateInputs(accounts, signBytes, tx.Inputs)
-						if err != nil {
-							return err
-						}
-						if !tx.PublicKey().VerifyBytes(signBytes, tx.Signature) {
-							return payload.ErrTxInvalidSignature
-						}
-						outTotal, err := validateOutputs(tx.UnbondTo)
-						if err != nil {
-							return err
-						}
-						if outTotal > inTotal {
-							return payload.ErrTxInsufficientFunds
-						}
-						fee := inTotal - outTotal
-						fees += fee
-
-						// Good! Adjust accounts
-						adjustByInputs(accounts, tx.Inputs)
-						for _, acc := range accounts {
-							exe.blockCache.UpdateAccount(acc)
-						}
-						// Add ValidatorInfo
-						_s.SetValidatorInfo(&txs.ValidatorInfo{
-							Address:         tx.PublicKey().Address(),
-							PublicKey:          tx.PublicKey(),
-							UnbondTo:        tx.UnbondTo,
-							FirstBondHeight: _s.lastBlockHeight + 1,
-							FirstBondAmount: outTotal,
-						})
-						// Add Validator
-						added := _s.BondedValidators.Add(&txs.Validator{
-							Address:     tx.PublicKey().Address(),
-							PublicKey:      tx.PublicKey(),
-							BondHeight:  _s.lastBlockHeight + 1,
-							VotingPower: outTotal,
-							Accum:       0,
-						})
-						if !added {
-							PanicCrisis("Failed to add validator")
-						}
-						if exe.eventCache != nil {
-							// TODO: fire for all inputs
-							exe.eventCache.Fire(txs.EventStringBond(), txs.EventDataTx{tx, nil, ""})
-						}
-						return nil
-
-					case *payload.UnbondTx:
-						// The validator must be active
-						_, val := _s.BondedValidators.GetByAddress(tx.Address)
-						if val == nil {
-							return payload.ErrTxInvalidAddress
-						}
-
-						// Verify the signature
-						signBytes := acm.SignBytes(exe.chainID, tx)
-						if !val.PublicKey().VerifyBytes(signBytes, tx.Signature) {
-							return payload.ErrTxInvalidSignature
-						}
-
-						// tx.Height must be greater than val.LastCommitHeight
-						if tx.Height <= val.LastCommitHeight {
-							return errors.New("Invalid unbond height")
-						}
-
-						// Good!
-						_s.unbondValidator(val)
-						if exe.eventCache != nil {
-							exe.eventCache.Fire(txs.EventStringUnbond(), txs.EventDataTx{tx, nil, ""})
-						}
-						return nil
-
-					case *txs.RebondTx:
-						// The validator must be inactive
-						_, val := _s.UnbondingValidators.GetByAddress(tx.Address)
-						if val == nil {
-							return payload.ErrTxInvalidAddress
-						}
-
-						// Verify the signature
-						signBytes := acm.SignBytes(exe.chainID, tx)
-						if !val.PublicKey().VerifyBytes(signBytes, tx.Signature) {
-							return payload.ErrTxInvalidSignature
-						}
-
-						// tx.Height must be in a suitable range
-						minRebondHeight := _s.lastBlockHeight - (validatorTimeoutBlocks / 2)
-						maxRebondHeight := _s.lastBlockHeight + 2
-						if !((minRebondHeight <= tx.Height) && (tx.Height <= maxRebondHeight)) {
-							return errors.New(Fmt("Rebond height not in range.  Expected %v <= %v <= %v",
-								minRebondHeight, tx.Height, maxRebondHeight))
-						}
-
-						// Good!
-						_s.rebondValidator(val)
-						if exe.eventCache != nil {
-							exe.eventCache.Fire(txs.EventStringRebond(), txs.EventDataTx{tx, nil, ""})
-						}
-						return nil
-
-		*/
-
-	case *payload.PermissionsTx:
-		// Validate input
-		inAcc, err := state.GetMutableAccount(exe.stateCache, tx.Input.Address)
-		if err != nil {
-			return err
-		}
-		if inAcc == nil {
-			logger.InfoMsg("Cannot find input account",
-				"tx_input", tx.Input)
-			return payload.ErrTxInvalidAddress
-		}
-
-		err = tx.PermArgs.EnsureValid()
-		if err != nil {
-			return fmt.Errorf("PermissionsTx received containing invalid PermArgs: %v", err)
-		}
-
-		permFlag := tx.PermArgs.PermFlag
-		// check permission
-		if !HasPermission(exe.stateCache, inAcc, permFlag, logger) {
-			return fmt.Errorf("account %s does not have moderator permission %s (%b)", tx.Input.Address,
-				permission.PermFlagToString(permFlag), permFlag)
-		}
-
-		err = validateInput(inAcc, tx.Input)
-		if err != nil {
-			logger.InfoMsg("validateInput failed",
-				"tx_input", tx.Input,
-				structure.ErrorKey, err)
-			return err
-		}
-
-		value := tx.Input.Amount
-
-		logger.TraceMsg("New PermissionsTx",
-			"perm_args", tx.PermArgs.String())
-
-		var permAcc acm.Account
-		switch tx.PermArgs.PermFlag {
-		case permission.HasBase:
-			// this one doesn't make sense from txs
-			return fmt.Errorf("HasBase is for contracts, not humans. Just look at the blockchain")
-		case permission.SetBase:
-			permAcc, err = mutatePermissions(exe.stateCache, *tx.PermArgs.Address,
-				func(perms *ptypes.AccountPermissions) error {
-					return perms.Base.Set(*tx.PermArgs.Permission, *tx.PermArgs.Value)
-				})
-		case permission.UnsetBase:
-			permAcc, err = mutatePermissions(exe.stateCache, *tx.PermArgs.Address,
-				func(perms *ptypes.AccountPermissions) error {
-					return perms.Base.Unset(*tx.PermArgs.Permission)
-				})
-		case permission.SetGlobal:
-			permAcc, err = mutatePermissions(exe.stateCache, acm.GlobalPermissionsAddress,
-				func(perms *ptypes.AccountPermissions) error {
-					return perms.Base.Set(*tx.PermArgs.Permission, *tx.PermArgs.Value)
-				})
-		case permission.HasRole:
-			return fmt.Errorf("HasRole is for contracts, not humans. Just look at the blockchain")
-		case permission.AddRole:
-			permAcc, err = mutatePermissions(exe.stateCache, *tx.PermArgs.Address,
-				func(perms *ptypes.AccountPermissions) error {
-					if !perms.AddRole(*tx.PermArgs.Role) {
-						return fmt.Errorf("role (%s) already exists for account %s",
-							*tx.PermArgs.Role, *tx.PermArgs.Address)
-					}
-					return nil
-				})
-		case permission.RemoveRole:
-			permAcc, err = mutatePermissions(exe.stateCache, *tx.PermArgs.Address,
-				func(perms *ptypes.AccountPermissions) error {
-					if !perms.RmRole(*tx.PermArgs.Role) {
-						return fmt.Errorf("role (%s) does not exist for account %s",
-							*tx.PermArgs.Role, *tx.PermArgs.Address)
-					}
-					return nil
-				})
-		default:
-			return fmt.Errorf("invalid permission function: %s", permission.PermFlagToString(permFlag))
-		}
-
-		// TODO: maybe we want to take funds on error and allow txs in that don't do anythingi?
-		if err != nil {
-			return err
-		}
-
-		// Good!
-		logger.TraceMsg("Incrementing sequence number for PermissionsTx",
-			"tag", "sequence",
-			"account", inAcc.Address(),
-			"old_sequence", inAcc.Sequence(),
-			"new_sequence", inAcc.Sequence()+1)
-		inAcc.IncSequence()
-		inAcc, err = inAcc.SubtractFromBalance(value)
-		if err != nil {
-			return err
-		}
-		exe.stateCache.UpdateAccount(inAcc)
-		if permAcc != nil {
-			exe.stateCache.UpdateAccount(permAcc)
-		}
-
-		if exe.eventCache != nil {
-			events.PublishAccountInput(exe.eventCache, tx.Input.Address, txEnv.Tx, nil, "")
-			events.PublishPermissions(exe.eventCache, permission.PermFlagToString(permFlag), txEnv.Tx)
-		}
-
-		return nil
-
-	default:
-		// binary decoding should not let this happen
-		return fmt.Errorf("unknown Tx type: %#v", tx)
-	}
-}
-
-func mutatePermissions(stateReader state.Reader, address crypto.Address,
-	mutator func(*ptypes.AccountPermissions) error) (acm.Account, error) {
-
-	account, err := stateReader.GetAccount(address)
-	if err != nil {
-		return nil, err
-	}
-	if account == nil {
-		return nil, fmt.Errorf("could not get account at address %s in order to alter permissions", address)
-	}
-	mutableAccount := acm.AsMutableAccount(account)
-
-	return mutableAccount, mutator(mutableAccount.MutablePermissions())
-}
-
-// ExecBlock stuff is now taken care of by the consensus engine.
-// But we leave here for now for reference when we have to do validator updates
-
-/*
-
-// NOTE: If an error occurs during block execution, state will be left
-// at an invalid state.  Copy the state before calling ExecBlock!
-func ExecBlock(s *State, block *txs.Block, blockPartsHeader txs.PartSetHeader) error {
-	err := execBlock(s, block, blockPartsHeader)
-	if err != nil {
-		return err
-	}
-	// State.Hash should match block.StateHash
-	stateHash := s.Hash()
-	if !bytes.Equal(stateHash, block.StateHash) {
-		return errors.New(Fmt("Invalid state hash. Expected %X, got %X",
-			stateHash, block.StateHash))
-	}
-	return nil
-}
-
-// executes transactions of a block, does not check block.StateHash
-// NOTE: If an error occurs during block execution, state will be left
-// at an invalid state.  Copy the state before calling execBlock!
-func execBlock(s *State, block *txs.Block, blockPartsHeader txs.PartSetHeader) error {
-	// Basic block validation.
-	err := block.ValidateBasic(s.chainID, s.lastBlockHeight, s.lastBlockAppHash, s.LastBlockParts, s.lastBlockTime)
-	if err != nil {
-		return err
-	}
-
-	// Validate block LastValidation.
-	if block.Height == 1 {
-		if len(block.LastValidation.Precommits) != 0 {
-			return errors.New("Block at height 1 (first block) should have no LastValidation precommits")
-		}
-	} else {
-		if len(block.LastValidation.Precommits) != s.LastBondedValidators.Size() {
-			return errors.New(Fmt("Invalid block validation size. Expected %v, got %v",
-				s.LastBondedValidators.Size(), len(block.LastValidation.Precommits)))
-		}
-		err := s.LastBondedValidators.VerifyValidation(
-			s.chainID, s.lastBlockAppHash, s.LastBlockParts, block.Height-1, block.LastValidation)
-		if err != nil {
-			return err
-		}
-	}
-
-	// Update Validator.LastCommitHeight as necessary.
-	for i, precommit := range block.LastValidation.Precommits {
-		if precommit == nil {
-			continue
-		}
-		_, val := s.LastBondedValidators.GetByIndex(i)
-		if val == nil {
-			PanicCrisis(Fmt("Failed to fetch validator at index %v", i))
-		}
-		if _, val_ := s.BondedValidators.GetByAddress(val.Address); val_ != nil {
-			val_.LastCommitHeight = block.Height - 1
-			updated := s.BondedValidators.Update(val_)
-			if !updated {
-				PanicCrisis("Failed to update bonded validator LastCommitHeight")
-			}
-		} else if _, val_ := s.UnbondingValidators.GetByAddress(val.Address); val_ != nil {
-			val_.LastCommitHeight = block.Height - 1
-			updated := s.UnbondingValidators.Update(val_)
-			if !updated {
-				PanicCrisis("Failed to update unbonding validator LastCommitHeight")
-			}
-		} else {
-			PanicCrisis("Could not find validator")
-		}
-	}
-
-	// Remember LastBondedValidators
-	s.LastBondedValidators = s.BondedValidators.Copy()
-
-	// Create BlockCache to cache changes to state.
-	blockCache := NewBlockCache(s)
-
-	// Execute each tx
-	for _, tx := range block.Data.Txs {
-		err := ExecTx(blockCache, tx, true, s.eventCache)
-		if err != nil {
-			return InvalidTxError{tx, err}
-		}
-	}
-
-	// Now sync the BlockCache to the backend.
-	blockCache.Sync()
-
-	// If any unbonding periods are over,
-	// reward account with bonded coins.
-	toRelease := []*txs.Validator{}
-	s.UnbondingValidators.Iterate(func(index int, val *txs.Validator) bool {
-		if val.UnbondHeight+unbondingPeriodBlocks < block.Height {
-			toRelease = append(toRelease, val)
-		}
-		return false
-	})
-	for _, val := range toRelease {
-		s.releaseValidator(val)
-	}
-
-	// If any validators haven't signed in a while,
-	// unbond them, they have timed out.
-	toTimeout := []*txs.Validator{}
-	s.BondedValidators.Iterate(func(index int, val *txs.Validator) bool {
-		lastActivityHeight := MaxInt(val.BondHeight, val.LastCommitHeight)
-		if lastActivityHeight+validatorTimeoutBlocks < block.Height {
-			log.Notice("Validator timeout", "validator", val, "height", block.Height)
-			toTimeout = append(toTimeout, val)
-		}
-		return false
-	})
-	for _, val := range toTimeout {
-		s.unbondValidator(val)
-	}
-
-	// Increment validator AccumPowers
-	s.BondedValidators.IncrementAccum(1)
-	s.lastBlockHeight = block.Height
-	s.lastBlockAppHash = block.Hash()
-	s.LastBlockParts = blockPartsHeader
-	s.lastBlockTime = block.Time
-	return nil
-}
-*/
-
-// The accounts from the TxInputs must either already have
-// acm.PublicKey().(type) != nil, (it must be known),
-// or it must be specified in the TxInput.  If redeclared,
-// the TxInput is modified and input.PublicKey() set to nil.
-func getInputs(accountGetter state.AccountGetter,
-	ins []*payload.TxInput) (map[crypto.Address]acm.MutableAccount, error) {
-
-	accounts := map[crypto.Address]acm.MutableAccount{}
-	for _, in := range ins {
-		// Account shouldn't be duplicated
-		if _, ok := accounts[in.Address]; ok {
-			return nil, payload.ErrTxDuplicateAddress
-		}
-		acc, err := state.GetMutableAccount(accountGetter, in.Address)
-		if err != nil {
-			return nil, err
-		}
-		if acc == nil {
-			return nil, payload.ErrTxInvalidAddress
-		}
-		accounts[in.Address] = acc
-	}
-	return accounts, nil
-}
-
-func getOrMakeOutputs(accountGetter state.AccountGetter, accs map[crypto.Address]acm.MutableAccount,
-	outs []*payload.TxOutput, logger *logging.Logger) (map[crypto.Address]acm.MutableAccount, error) {
-	if accs == nil {
-		accs = make(map[crypto.Address]acm.MutableAccount)
-	}
-
-	// we should err if an account is being created but the inputs don't have permission
-	var checkedCreatePerms bool
-	for _, out := range outs {
-		// Account shouldn't be duplicated
-		if _, ok := accs[out.Address]; ok {
-			return nil, payload.ErrTxDuplicateAddress
-		}
-		acc, err := state.GetMutableAccount(accountGetter, out.Address)
-		if err != nil {
-			return nil, err
-		}
-		// output account may be nil (new)
-		if acc == nil {
-			if !checkedCreatePerms {
-				if !hasCreateAccountPermission(accountGetter, accs, logger) {
-					return nil, fmt.Errorf("at least one input does not have permission to create accounts")
-				}
-				checkedCreatePerms = true
-			}
-			acc = acm.ConcreteAccount{
-				Address:     out.Address,
-				Sequence:    0,
-				Balance:     0,
-				Permissions: permission.ZeroAccountPermissions,
-			}.MutableAccount()
-		}
-		accs[out.Address] = acc
-	}
-	return accs, nil
-}
-
-func validateInputs(accs map[crypto.Address]acm.MutableAccount, ins []*payload.TxInput) (uint64, error) {
-	total := uint64(0)
-	for _, in := range ins {
-		acc := accs[in.Address]
-		if acc == nil {
-			return 0, fmt.Errorf("validateInputs() expects account in accounts, but account %s not found", in.Address)
-		}
-		err := validateInput(acc, in)
-		if err != nil {
-			return 0, err
-		}
-		// Good. Add amount to total
-		total += in.Amount
-	}
-	return total, nil
-}
-
-func validateInput(acc acm.MutableAccount, in *payload.TxInput) error {
-	// Check TxInput basic
-	if err := in.ValidateBasic(); err != nil {
-		return err
-	}
-	// Check sequences
-	if acc.Sequence()+1 != uint64(in.Sequence) {
-		return payload.ErrTxInvalidSequence{
-			Got:      in.Sequence,
-			Expected: acc.Sequence() + uint64(1),
-		}
-	}
-	// Check amount
-	if acc.Balance() < uint64(in.Amount) {
-		return payload.ErrTxInsufficientFunds
-	}
-	return nil
-}
-
-func validateOutputs(outs []*payload.TxOutput) (uint64, error) {
-	total := uint64(0)
-	for _, out := range outs {
-		// Check TxOutput basic
-		if err := out.ValidateBasic(); err != nil {
-			return 0, err
-		}
-		// Good. Add amount to total
-		total += out.Amount
-	}
-	return total, nil
-}
-
-func adjustByInputs(accs map[crypto.Address]acm.MutableAccount, ins []*payload.TxInput, logger *logging.Logger) error {
-	for _, in := range ins {
-		acc := accs[in.Address]
-		if acc == nil {
-			return fmt.Errorf("adjustByInputs() expects account in accounts, but account %s not found", in.Address)
-		}
-		if acc.Balance() < in.Amount {
-			panic("adjustByInputs() expects sufficient funds")
-			return fmt.Errorf("adjustByInputs() expects sufficient funds but account %s only has balance %v and "+
-				"we are deducting %v", in.Address, acc.Balance(), in.Amount)
-		}
-		acc, err := acc.SubtractFromBalance(in.Amount)
-		if err != nil {
-			return err
-		}
-		logger.TraceMsg("Incrementing sequence number for SendTx (adjustByInputs)",
-			"tag", "sequence",
-			"account", acc.Address(),
-			"old_sequence", acc.Sequence(),
-			"new_sequence", acc.Sequence()+1)
-		acc.IncSequence()
-	}
-	return nil
-}
-
-func adjustByOutputs(accs map[crypto.Address]acm.MutableAccount, outs []*payload.TxOutput) error {
-	for _, out := range outs {
-		acc := accs[out.Address]
-		if acc == nil {
-			return fmt.Errorf("adjustByOutputs() expects account in accounts, but account %s not found",
-				out.Address)
-		}
-		_, err := acc.AddToBalance(out.Amount)
-		if err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-//---------------------------------------------------------------
-
-// Get permission on an account or fall back to global value
-func HasPermission(accountGetter state.AccountGetter, acc acm.Account, perm ptypes.PermFlag, logger *logging.Logger) bool {
-	if perm > permission.AllPermFlags {
-		logger.InfoMsg(
-			fmt.Sprintf("HasPermission called on invalid permission 0b%b (invalid) > 0b%b (maximum) ",
-				perm, permission.AllPermFlags),
-			"invalid_permission", perm,
-			"maximum_permission", permission.AllPermFlags)
-		return false
-	}
-
-	permString := permission.String(perm)
-
-	v, err := acc.Permissions().Base.Compose(state.GlobalAccountPermissions(accountGetter).Base).Get(perm)
-	if err != nil {
-		logger.TraceMsg("Error obtaining permission value (will default to false/deny)",
-			"perm_flag", permString,
-			structure.ErrorKey, err)
-	}
-
-	if v {
-		logger.TraceMsg("Account has permission",
-			"account_address", acc.Address,
-			"perm_flag", permString)
-	} else {
-		logger.TraceMsg("Account does not have permission",
-			"account_address", acc.Address,
-			"perm_flag", permString)
-	}
-	return v
-}
-
-// TODO: for debug log the failed accounts
-func hasSendPermission(accountGetter state.AccountGetter, accs map[crypto.Address]acm.MutableAccount,
-	logger *logging.Logger) bool {
-	for _, acc := range accs {
-		if !HasPermission(accountGetter, acc, permission.Send, logger) {
-			return false
-		}
-	}
-	return true
-}
-
-func hasNamePermission(accountGetter state.AccountGetter, acc acm.Account,
-	logger *logging.Logger) bool {
-	return HasPermission(accountGetter, acc, permission.Name, logger)
-}
-
-func hasCallPermission(accountGetter state.AccountGetter, acc acm.Account,
-	logger *logging.Logger) bool {
-	return HasPermission(accountGetter, acc, permission.Call, logger)
-}
-
-func hasCreateContractPermission(accountGetter state.AccountGetter, acc acm.Account,
-	logger *logging.Logger) bool {
-	return HasPermission(accountGetter, acc, permission.CreateContract, logger)
-}
-
-func hasCreateAccountPermission(accountGetter state.AccountGetter, accs map[crypto.Address]acm.MutableAccount,
-	logger *logging.Logger) bool {
-	for _, acc := range accs {
-		if !HasPermission(accountGetter, acc, permission.CreateAccount, logger) {
-			return false
-		}
-	}
-	return true
-}
-
-func hasBondPermission(accountGetter state.AccountGetter, acc acm.Account,
-	logger *logging.Logger) bool {
-	return HasPermission(accountGetter, acc, permission.Bond, logger)
-}
-
-func hasBondOrSendPermission(accountGetter state.AccountGetter, accs map[crypto.Address]acm.Account,
-	logger *logging.Logger) bool {
-	for _, acc := range accs {
-		if !HasPermission(accountGetter, acc, permission.Bond, logger) {
-			if !HasPermission(accountGetter, acc, permission.Send, logger) {
-				return false
-			}
-		}
-	}
-	return true
-}
-
-//-----------------------------------------------------------------------------
-
-type InvalidTxError struct {
-	Tx     txs.Tx
-	Reason error
-}
-
-func (txErr InvalidTxError) Error() string {
-	return fmt.Sprintf("Invalid tx: [%v] reason: [%v]", txErr.Tx, txErr.Reason)
-}
diff --git a/execution/execution_test.go b/execution/execution_test.go
index e846840971b8f741ffa2bf54a8f425161728fbd7..93fb03b443a9602ba5118f9312e080ad2f8a5bde 100644
--- a/execution/execution_test.go
+++ b/execution/execution_test.go
@@ -30,7 +30,7 @@ import (
 	bcm "github.com/hyperledger/burrow/blockchain"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/event"
-	exe_events "github.com/hyperledger/burrow/execution/events"
+	"github.com/hyperledger/burrow/execution/errors"
 	"github.com/hyperledger/burrow/execution/evm"
 	. "github.com/hyperledger/burrow/execution/evm/asm"
 	"github.com/hyperledger/burrow/execution/evm/asm/bc"
@@ -139,9 +139,10 @@ func newBlockchain(genesisDoc *genesis.GenesisDoc) *bcm.Blockchain {
 	return bc
 }
 
-func makeExecutor(state *State) *executor {
-	return newExecutor("makeExecutorCache", true, state, testChainID,
-		newBlockchain(testGenesisDoc).Tip, event.NewEmitter(logger), logger)
+func makeExecutor(state *State) (*executor, event.Emitter) {
+	emitter := event.NewEmitter(logger)
+	return newExecutor("makeExecutorCache", true, state,
+		newBlockchain(testGenesisDoc).Tip, emitter, logger), emitter
 }
 
 func newBaseGenDoc(globalPerm, accountPerm ptypes.AccountPermissions) genesis.GenesisDoc {
@@ -187,12 +188,12 @@ func TestSendFails(t *testing.T) {
 	stateDB := dbm.NewDB("state", dbBackend, dbDir)
 	defer stateDB.Close()
 	genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions)
-	genDoc.Accounts[1].Permissions.Base.Set(permission.Send, true)
-	genDoc.Accounts[2].Permissions.Base.Set(permission.Call, true)
-	genDoc.Accounts[3].Permissions.Base.Set(permission.CreateContract, true)
+	genDoc.Accounts[1].Permissions.Base.Set(ptypes.Send, true)
+	genDoc.Accounts[2].Permissions.Base.Set(ptypes.Call, true)
+	genDoc.Accounts[3].Permissions.Base.Set(ptypes.CreateContract, true)
 	st, err := MakeGenesisState(stateDB, &genDoc)
 	require.NoError(t, err)
-	batchCommitter := makeExecutor(st)
+	batchCommitter, _ := makeExecutor(st)
 
 	//-------------------
 	// send txs
@@ -224,7 +225,7 @@ func TestSendFails(t *testing.T) {
 
 	// simple send tx to unknown account without create_account perm should fail
 	acc := getAccount(batchCommitter.stateCache, users[3].Address())
-	acc.MutablePermissions().Base.Set(permission.Send, true)
+	acc.MutablePermissions().Base.Set(ptypes.Send, true)
 	batchCommitter.stateCache.UpdateAccount(acc)
 	tx = payload.NewSendTx()
 	if err := tx.AddInput(batchCommitter.stateCache, users[3].PublicKey(), 5); err != nil {
@@ -238,11 +239,11 @@ func TestName(t *testing.T) {
 	stateDB := dbm.NewDB("state", dbBackend, dbDir)
 	defer stateDB.Close()
 	genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions)
-	genDoc.Accounts[0].Permissions.Base.Set(permission.Send, true)
-	genDoc.Accounts[1].Permissions.Base.Set(permission.Name, true)
+	genDoc.Accounts[0].Permissions.Base.Set(ptypes.Send, true)
+	genDoc.Accounts[1].Permissions.Base.Set(ptypes.Name, true)
 	st, err := MakeGenesisState(stateDB, &genDoc)
 	require.NoError(t, err)
-	batchCommitter := makeExecutor(st)
+	batchCommitter, _ := makeExecutor(st)
 
 	//-------------------
 	// name txs
@@ -266,12 +267,12 @@ func TestCallFails(t *testing.T) {
 	stateDB := dbm.NewDB("state", dbBackend, dbDir)
 	defer stateDB.Close()
 	genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions)
-	genDoc.Accounts[1].Permissions.Base.Set(permission.Send, true)
-	genDoc.Accounts[2].Permissions.Base.Set(permission.Call, true)
-	genDoc.Accounts[3].Permissions.Base.Set(permission.CreateContract, true)
+	genDoc.Accounts[1].Permissions.Base.Set(ptypes.Send, true)
+	genDoc.Accounts[2].Permissions.Base.Set(ptypes.Call, true)
+	genDoc.Accounts[3].Permissions.Base.Set(ptypes.CreateContract, true)
 	st, err := MakeGenesisState(stateDB, &genDoc)
 	require.NoError(t, err)
-	batchCommitter := makeExecutor(st)
+	batchCommitter, _ := makeExecutor(st)
 
 	//-------------------
 	// call txs
@@ -309,10 +310,10 @@ func TestSendPermission(t *testing.T) {
 	stateDB := dbm.NewDB("state", dbBackend, dbDir)
 	defer stateDB.Close()
 	genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions)
-	genDoc.Accounts[0].Permissions.Base.Set(permission.Send, true) // give the 0 account permission
+	genDoc.Accounts[0].Permissions.Base.Set(ptypes.Send, true) // give the 0 account permission
 	st, err := MakeGenesisState(stateDB, &genDoc)
 	require.NoError(t, err)
-	batchCommitter := makeExecutor(st)
+	batchCommitter, _ := makeExecutor(st)
 
 	// A single input, having the permission, should succeed
 	tx := payload.NewSendTx()
@@ -334,10 +335,10 @@ func TestCallPermission(t *testing.T) {
 	stateDB := dbm.NewDB("state", dbBackend, dbDir)
 	defer stateDB.Close()
 	genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions)
-	genDoc.Accounts[0].Permissions.Base.Set(permission.Call, true) // give the 0 account permission
+	genDoc.Accounts[0].Permissions.Base.Set(ptypes.Call, true) // give the 0 account permission
 	st, err := MakeGenesisState(stateDB, &genDoc)
 	require.NoError(t, err)
-	batchCommitter := makeExecutor(st)
+	batchCommitter, emitter := makeExecutor(st)
 
 	//------------------------------
 	// call to simple contract
@@ -382,27 +383,23 @@ func TestCallPermission(t *testing.T) {
 	require.NoError(t, txEnv.Sign(users[0]))
 
 	// we need to subscribe to the Call event to detect the exception
-	_, exception := execTxWaitEvent(t, batchCommitter, txEnv, evm_events.EventStringAccountCall(caller1ContractAddr)) //
-	if exception == "" {
-		t.Fatal("Expected exception")
-	}
+	_, err = execTxWaitAccountCall(t, batchCommitter, emitter, txEnv, caller1ContractAddr) //
+	require.Error(t, err)
 
 	//----------------------------------------------------------
 	// call to contract that calls simple contract - with perm
 	fmt.Println("\n##### CALL TO SIMPLE CONTRACT (PASS)")
 
 	// A single input, having the permission, and the contract has permission
-	caller1Acc.MutablePermissions().Base.Set(permission.Call, true)
+	caller1Acc.MutablePermissions().Base.Set(ptypes.Call, true)
 	batchCommitter.stateCache.UpdateAccount(caller1Acc)
 	tx, _ = payload.NewCallTx(batchCommitter.stateCache, users[0].PublicKey(), &caller1ContractAddr, nil, 100, 10000, 100)
 	txEnv = txs.Enclose(testChainID, tx)
 	require.NoError(t, txEnv.Sign(users[0]))
 
 	// we need to subscribe to the Call event to detect the exception
-	_, exception = execTxWaitEvent(t, batchCommitter, txEnv, evm_events.EventStringAccountCall(caller1ContractAddr)) //
-	if exception != "" {
-		t.Fatal("Unexpected exception:", exception)
-	}
+	_, err = execTxWaitAccountCall(t, batchCommitter, emitter, txEnv, caller1ContractAddr) //
+	require.NoError(t, err)
 
 	//----------------------------------------------------------
 	// call to contract that calls contract that calls simple contract - without perm
@@ -420,8 +417,8 @@ func TestCallPermission(t *testing.T) {
 		StorageRoot: Zero256.Bytes(),
 		Permissions: permission.ZeroAccountPermissions,
 	}.MutableAccount()
-	caller1Acc.MutablePermissions().Base.Set(permission.Call, false)
-	caller2Acc.MutablePermissions().Base.Set(permission.Call, true)
+	caller1Acc.MutablePermissions().Base.Set(ptypes.Call, false)
+	caller2Acc.MutablePermissions().Base.Set(ptypes.Call, true)
 	batchCommitter.stateCache.UpdateAccount(caller1Acc)
 	batchCommitter.stateCache.UpdateAccount(caller2Acc)
 
@@ -429,10 +426,8 @@ func TestCallPermission(t *testing.T) {
 	txEnv = txs.Enclose(testChainID, tx)
 	require.NoError(t, txEnv.Sign(users[0]))
 	// we need to subscribe to the Call event to detect the exception
-	_, exception = execTxWaitEvent(t, batchCommitter, txEnv, evm_events.EventStringAccountCall(caller1ContractAddr)) //
-	if exception == "" {
-		t.Fatal("Expected exception")
-	}
+	_, err = execTxWaitAccountCall(t, batchCommitter, emitter, txEnv, caller1ContractAddr) //
+	require.Error(t, err)
 
 	//----------------------------------------------------------
 	// call to contract that calls contract that calls simple contract - without perm
@@ -440,7 +435,7 @@ func TestCallPermission(t *testing.T) {
 	// both caller1 and caller2 have permission
 	fmt.Println("\n##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (PASS)")
 
-	caller1Acc.MutablePermissions().Base.Set(permission.Call, true)
+	caller1Acc.MutablePermissions().Base.Set(ptypes.Call, true)
 	batchCommitter.stateCache.UpdateAccount(caller1Acc)
 
 	tx, _ = payload.NewCallTx(batchCommitter.stateCache, users[0].PublicKey(), &caller2ContractAddr, nil, 100, 10000, 100)
@@ -448,21 +443,19 @@ func TestCallPermission(t *testing.T) {
 	require.NoError(t, txEnv.Sign(users[0]))
 
 	// we need to subscribe to the Call event to detect the exception
-	_, exception = execTxWaitEvent(t, batchCommitter, txEnv, evm_events.EventStringAccountCall(caller1ContractAddr)) //
-	if exception != "" {
-		t.Fatal("Unexpected exception", exception)
-	}
+	_, err = execTxWaitAccountCall(t, batchCommitter, emitter, txEnv, caller1ContractAddr) //
+	require.NoError(t, err)
 }
 
 func TestCreatePermission(t *testing.T) {
 	stateDB := dbm.NewDB("state", dbBackend, dbDir)
 	defer stateDB.Close()
 	genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions)
-	genDoc.Accounts[0].Permissions.Base.Set(permission.CreateContract, true) // give the 0 account permission
-	genDoc.Accounts[0].Permissions.Base.Set(permission.Call, true)           // give the 0 account permission
+	genDoc.Accounts[0].Permissions.Base.Set(ptypes.CreateContract, true) // give the 0 account permission
+	genDoc.Accounts[0].Permissions.Base.Set(ptypes.Call, true)           // give the 0 account permission
 	st, err := MakeGenesisState(stateDB, &genDoc)
 	require.NoError(t, err)
-	batchCommitter := makeExecutor(st)
+	batchCommitter, emitter := makeExecutor(st)
 
 	//------------------------------
 	// create a simple contract
@@ -517,16 +510,14 @@ func TestCreatePermission(t *testing.T) {
 	txEnv := txs.Enclose(testChainID, tx)
 	require.NoError(t, txEnv.Sign(users[0]))
 	// we need to subscribe to the Call event to detect the exception
-	_, exception := execTxWaitEvent(t, batchCommitter, txEnv, evm_events.EventStringAccountCall(contractAddr)) //
-	if exception == "" {
-		t.Fatal("expected exception")
-	}
+	_, err = execTxWaitAccountCall(t, batchCommitter, emitter, txEnv, contractAddr) //
+	require.Error(t, err)
 
 	//------------------------------
 	// call the contract (should PASS)
 	fmt.Println("\n###### CALL THE FACTORY (PASS)")
 
-	contractAcc.MutablePermissions().Base.Set(permission.CreateContract, true)
+	contractAcc.MutablePermissions().Base.Set(ptypes.CreateContract, true)
 	batchCommitter.stateCache.UpdateAccount(contractAcc)
 
 	// A single input, having the permission, should succeed
@@ -534,10 +525,8 @@ func TestCreatePermission(t *testing.T) {
 	txEnv = txs.Enclose(testChainID, tx)
 	require.NoError(t, txEnv.Sign(users[0]))
 	// we need to subscribe to the Call event to detect the exception
-	_, exception = execTxWaitEvent(t, batchCommitter, txEnv, evm_events.EventStringAccountCall(contractAddr)) //
-	if exception != "" {
-		t.Fatal("unexpected exception", exception)
-	}
+	_, err = execTxWaitAccountCall(t, batchCommitter, emitter, txEnv, contractAddr) //
+	require.NoError(t, err)
 
 	//--------------------------------
 	fmt.Println("\n##### CALL to empty address")
@@ -552,8 +541,8 @@ func TestCreatePermission(t *testing.T) {
 		StorageRoot: Zero256.Bytes(),
 		Permissions: permission.ZeroAccountPermissions,
 	}.MutableAccount()
-	contractAcc.MutablePermissions().Base.Set(permission.Call, true)
-	contractAcc.MutablePermissions().Base.Set(permission.CreateContract, true)
+	contractAcc.MutablePermissions().Base.Set(ptypes.Call, true)
+	contractAcc.MutablePermissions().Base.Set(ptypes.CreateContract, true)
 	batchCommitter.stateCache.UpdateAccount(contractAcc)
 
 	// this should call the 0 address but not create ...
@@ -561,10 +550,8 @@ func TestCreatePermission(t *testing.T) {
 	txEnv = txs.Enclose(testChainID, tx)
 	require.NoError(t, txEnv.Sign(users[0]))
 	// we need to subscribe to the Call event to detect the exception
-	_, exception = execTxWaitEvent(t, batchCommitter, txEnv, evm_events.EventStringAccountCall(crypto.Address{})) //
-	if exception != "" {
-		t.Fatal("unexpected exception", exception)
-	}
+	_, err = execTxWaitAccountCall(t, batchCommitter, emitter, txEnv, crypto.Address{}) //
+	require.NoError(t, err)
 	zeroAcc := getAccount(batchCommitter.stateCache, crypto.Address{})
 	if len(zeroAcc.Code()) != 0 {
 		t.Fatal("the zero account was given code from a CALL!")
@@ -575,12 +562,12 @@ func TestCreateAccountPermission(t *testing.T) {
 	stateDB := dbm.NewDB("state", dbBackend, dbDir)
 	defer stateDB.Close()
 	genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions)
-	genDoc.Accounts[0].Permissions.Base.Set(permission.Send, true)          // give the 0 account permission
-	genDoc.Accounts[1].Permissions.Base.Set(permission.Send, true)          // give the 0 account permission
-	genDoc.Accounts[0].Permissions.Base.Set(permission.CreateAccount, true) // give the 0 account permission
+	genDoc.Accounts[0].Permissions.Base.Set(ptypes.Send, true)          // give the 0 account permission
+	genDoc.Accounts[1].Permissions.Base.Set(ptypes.Send, true)          // give the 0 account permission
+	genDoc.Accounts[0].Permissions.Base.Set(ptypes.CreateAccount, true) // give the 0 account permission
 	st, err := MakeGenesisState(stateDB, &genDoc)
 	require.NoError(t, err)
-	batchCommitter := makeExecutor(st)
+	batchCommitter, emitter := makeExecutor(st)
 
 	//----------------------------------------------------------
 	// SendTx to unknown account
@@ -618,7 +605,7 @@ func TestCreateAccountPermission(t *testing.T) {
 
 	// Two inputs, both with send, both with create, should pass
 	acc := getAccount(batchCommitter.stateCache, users[1].Address())
-	acc.MutablePermissions().Base.Set(permission.CreateAccount, true)
+	acc.MutablePermissions().Base.Set(ptypes.CreateAccount, true)
 	batchCommitter.stateCache.UpdateAccount(acc)
 	tx = payload.NewSendTx()
 	if err := tx.AddInput(batchCommitter.stateCache, users[0].PublicKey(), 5); err != nil {
@@ -646,7 +633,7 @@ func TestCreateAccountPermission(t *testing.T) {
 	// CALL to unknown account
 
 	acc = getAccount(batchCommitter.stateCache, users[0].Address())
-	acc.MutablePermissions().Base.Set(permission.Call, true)
+	acc.MutablePermissions().Base.Set(ptypes.Call, true)
 	batchCommitter.stateCache.UpdateAccount(acc)
 
 	// call to contract that calls unknown account - without create_account perm
@@ -669,15 +656,13 @@ func TestCreateAccountPermission(t *testing.T) {
 	txCallEnv.Sign(users[0])
 
 	// we need to subscribe to the Call event to detect the exception
-	_, exception := execTxWaitEvent(t, batchCommitter, txCallEnv, evm_events.EventStringAccountCall(caller1ContractAddr)) //
-	if exception == "" {
-		t.Fatal("Expected exception")
-	}
+	_, err = execTxWaitAccountCall(t, batchCommitter, emitter, txCallEnv, caller1ContractAddr) //
+	require.Error(t, err)
 
 	// NOTE: for a contract to be able to CreateAccount, it must be able to call
 	// NOTE: for a users to be able to CreateAccount, it must be able to send!
-	caller1Acc.MutablePermissions().Base.Set(permission.CreateAccount, true)
-	caller1Acc.MutablePermissions().Base.Set(permission.Call, true)
+	caller1Acc.MutablePermissions().Base.Set(ptypes.CreateAccount, true)
+	caller1Acc.MutablePermissions().Base.Set(ptypes.Call, true)
 	batchCommitter.stateCache.UpdateAccount(caller1Acc)
 	// A single input, having the permission, but the contract doesn't have permission
 	txCall, _ = payload.NewCallTx(batchCommitter.stateCache, users[0].PublicKey(), &caller1ContractAddr, nil, 100, 10000, 100)
@@ -685,10 +670,8 @@ func TestCreateAccountPermission(t *testing.T) {
 	txCallEnv.Sign(users[0])
 
 	// we need to subscribe to the Call event to detect the exception
-	_, exception = execTxWaitEvent(t, batchCommitter, txCallEnv, evm_events.EventStringAccountCall(caller1ContractAddr)) //
-	if exception != "" {
-		t.Fatal("Unexpected exception", exception)
-	}
+	_, err = execTxWaitAccountCall(t, batchCommitter, emitter, txCallEnv, caller1ContractAddr) //
+	require.NoError(t, err)
 
 }
 
@@ -703,13 +686,13 @@ func TestSNativeCALL(t *testing.T) {
 	stateDB := dbm.NewDB("state", dbBackend, dbDir)
 	defer stateDB.Close()
 	genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions)
-	genDoc.Accounts[0].Permissions.Base.Set(permission.Call, true) // give the 0 account permission
-	genDoc.Accounts[3].Permissions.Base.Set(permission.Bond, true) // some arbitrary permission to play with
+	genDoc.Accounts[0].Permissions.Base.Set(ptypes.Call, true) // give the 0 account permission
+	genDoc.Accounts[3].Permissions.Base.Set(ptypes.Bond, true) // some arbitrary permission to play with
 	genDoc.Accounts[3].Permissions.AddRole("bumble")
 	genDoc.Accounts[3].Permissions.AddRole("bee")
 	st, err := MakeGenesisState(stateDB, &genDoc)
 	require.NoError(t, err)
-	batchCommitter := makeExecutor(st)
+	batchCommitter, emitter := makeExecutor(st)
 
 	//----------------------------------------------------------
 	// Test CALL to SNative contracts
@@ -724,15 +707,15 @@ func TestSNativeCALL(t *testing.T) {
 		Permissions: permission.ZeroAccountPermissions,
 	}.MutableAccount()
 
-	doug.MutablePermissions().Base.Set(permission.Call, true)
+	doug.MutablePermissions().Base.Set(ptypes.Call, true)
 	//doug.Permissions.Base.Set(permission.HasBase, true)
 	batchCommitter.stateCache.UpdateAccount(doug)
 
 	fmt.Println("\n#### HasBase")
 	// HasBase
-	snativeAddress, pF, data := snativePermTestInputCALL("hasBase", users[3], permission.Bond, false)
-	testSNativeCALLExpectFail(t, batchCommitter, doug, snativeAddress, data)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error {
+	snativeAddress, pF, data := snativePermTestInputCALL("hasBase", users[3], ptypes.Bond, false)
+	testSNativeCALLExpectFail(t, batchCommitter, emitter, doug, snativeAddress, data)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error {
 		// return value should be true or false as a 32 byte array...
 		if !IsZeros(ret[:31]) || ret[31] != byte(1) {
 			return fmt.Errorf("Expected 1. Got %X", ret)
@@ -742,21 +725,21 @@ func TestSNativeCALL(t *testing.T) {
 
 	fmt.Println("\n#### SetBase")
 	// SetBase
-	snativeAddress, pF, data = snativePermTestInputCALL("setBase", users[3], permission.Bond, false)
-	testSNativeCALLExpectFail(t, batchCommitter, doug, snativeAddress, data)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
-	snativeAddress, pF, data = snativePermTestInputCALL("hasBase", users[3], permission.Bond, false)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error {
+	snativeAddress, pF, data = snativePermTestInputCALL("setBase", users[3], ptypes.Bond, false)
+	testSNativeCALLExpectFail(t, batchCommitter, emitter, doug, snativeAddress, data)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
+	snativeAddress, pF, data = snativePermTestInputCALL("hasBase", users[3], ptypes.Bond, false)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error {
 		// return value should be true or false as a 32 byte array...
 		if !IsZeros(ret) {
 			return fmt.Errorf("Expected 0. Got %X", ret)
 		}
 		return nil
 	})
-	snativeAddress, pF, data = snativePermTestInputCALL("setBase", users[3], permission.CreateContract, true)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
-	snativeAddress, pF, data = snativePermTestInputCALL("hasBase", users[3], permission.CreateContract, false)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error {
+	snativeAddress, pF, data = snativePermTestInputCALL("setBase", users[3], ptypes.CreateContract, true)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
+	snativeAddress, pF, data = snativePermTestInputCALL("hasBase", users[3], ptypes.CreateContract, false)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error {
 		// return value should be true or false as a 32 byte array...
 		if !IsZeros(ret[:31]) || ret[31] != byte(1) {
 			return fmt.Errorf("Expected 1. Got %X", ret)
@@ -766,11 +749,11 @@ func TestSNativeCALL(t *testing.T) {
 
 	fmt.Println("\n#### UnsetBase")
 	// UnsetBase
-	snativeAddress, pF, data = snativePermTestInputCALL("unsetBase", users[3], permission.CreateContract, false)
-	testSNativeCALLExpectFail(t, batchCommitter, doug, snativeAddress, data)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
-	snativeAddress, pF, data = snativePermTestInputCALL("hasBase", users[3], permission.CreateContract, false)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error {
+	snativeAddress, pF, data = snativePermTestInputCALL("unsetBase", users[3], ptypes.CreateContract, false)
+	testSNativeCALLExpectFail(t, batchCommitter, emitter, doug, snativeAddress, data)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
+	snativeAddress, pF, data = snativePermTestInputCALL("hasBase", users[3], ptypes.CreateContract, false)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error {
 		if !IsZeros(ret) {
 			return fmt.Errorf("Expected 0. Got %X", ret)
 		}
@@ -779,11 +762,11 @@ func TestSNativeCALL(t *testing.T) {
 
 	fmt.Println("\n#### SetGlobal")
 	// SetGlobalPerm
-	snativeAddress, pF, data = snativePermTestInputCALL("setGlobal", users[3], permission.CreateContract, true)
-	testSNativeCALLExpectFail(t, batchCommitter, doug, snativeAddress, data)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
-	snativeAddress, pF, data = snativePermTestInputCALL("hasBase", users[3], permission.CreateContract, false)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error {
+	snativeAddress, pF, data = snativePermTestInputCALL("setGlobal", users[3], ptypes.CreateContract, true)
+	testSNativeCALLExpectFail(t, batchCommitter, emitter, doug, snativeAddress, data)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
+	snativeAddress, pF, data = snativePermTestInputCALL("hasBase", users[3], ptypes.CreateContract, false)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error {
 		// return value should be true or false as a 32 byte array...
 		if !IsZeros(ret[:31]) || ret[31] != byte(1) {
 			return fmt.Errorf("Expected 1. Got %X", ret)
@@ -794,8 +777,8 @@ func TestSNativeCALL(t *testing.T) {
 	fmt.Println("\n#### HasRole")
 	// HasRole
 	snativeAddress, pF, data = snativeRoleTestInputCALL("hasRole", users[3], "bumble")
-	testSNativeCALLExpectFail(t, batchCommitter, doug, snativeAddress, data)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error {
+	testSNativeCALLExpectFail(t, batchCommitter, emitter, doug, snativeAddress, data)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error {
 		if !IsZeros(ret[:31]) || ret[31] != byte(1) {
 			return fmt.Errorf("Expected 1. Got %X", ret)
 		}
@@ -805,17 +788,17 @@ func TestSNativeCALL(t *testing.T) {
 	fmt.Println("\n#### AddRole")
 	// AddRole
 	snativeAddress, pF, data = snativeRoleTestInputCALL("hasRole", users[3], "chuck")
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error {
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error {
 		if !IsZeros(ret) {
 			return fmt.Errorf("Expected 0. Got %X", ret)
 		}
 		return nil
 	})
 	snativeAddress, pF, data = snativeRoleTestInputCALL("addRole", users[3], "chuck")
-	testSNativeCALLExpectFail(t, batchCommitter, doug, snativeAddress, data)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
+	testSNativeCALLExpectFail(t, batchCommitter, emitter, doug, snativeAddress, data)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
 	snativeAddress, pF, data = snativeRoleTestInputCALL("hasRole", users[3], "chuck")
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error {
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error {
 		if !IsZeros(ret[:31]) || ret[31] != byte(1) {
 			return fmt.Errorf("Expected 1. Got %X", ret)
 		}
@@ -825,10 +808,10 @@ func TestSNativeCALL(t *testing.T) {
 	fmt.Println("\n#### RemoveRole")
 	// RemoveRole
 	snativeAddress, pF, data = snativeRoleTestInputCALL("removeRole", users[3], "chuck")
-	testSNativeCALLExpectFail(t, batchCommitter, doug, snativeAddress, data)
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
+	testSNativeCALLExpectFail(t, batchCommitter, emitter, doug, snativeAddress, data)
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error { return nil })
 	snativeAddress, pF, data = snativeRoleTestInputCALL("hasRole", users[3], "chuck")
-	testSNativeCALLExpectPass(t, batchCommitter, doug, pF, snativeAddress, data, func(ret []byte) error {
+	testSNativeCALLExpectPass(t, batchCommitter, emitter, doug, pF, snativeAddress, data, func(ret []byte) error {
 		if !IsZeros(ret) {
 			return fmt.Errorf("Expected 0. Got %X", ret)
 		}
@@ -840,50 +823,50 @@ func TestSNativeTx(t *testing.T) {
 	stateDB := dbm.NewDB("state", dbBackend, dbDir)
 	defer stateDB.Close()
 	genDoc := newBaseGenDoc(permission.ZeroAccountPermissions, permission.ZeroAccountPermissions)
-	genDoc.Accounts[0].Permissions.Base.Set(permission.Call, true) // give the 0 account permission
-	genDoc.Accounts[3].Permissions.Base.Set(permission.Bond, true) // some arbitrary permission to play with
+	genDoc.Accounts[0].Permissions.Base.Set(ptypes.Call, true) // give the 0 account permission
+	genDoc.Accounts[3].Permissions.Base.Set(ptypes.Bond, true) // some arbitrary permission to play with
 	genDoc.Accounts[3].Permissions.AddRole("bumble")
 	genDoc.Accounts[3].Permissions.AddRole("bee")
 	st, err := MakeGenesisState(stateDB, &genDoc)
 	require.NoError(t, err)
-	batchCommitter := makeExecutor(st)
+	batchCommitter, _ := makeExecutor(st)
 
 	//----------------------------------------------------------
 	// Test SNativeTx
 
 	fmt.Println("\n#### SetBase")
 	// SetBase
-	snativeArgs := snativePermTestInputTx("setBase", users[3], permission.Bond, false)
+	snativeArgs := snativePermTestInputTx("setBase", users[3], ptypes.Bond, false)
 	testSNativeTxExpectFail(t, batchCommitter, snativeArgs)
-	testSNativeTxExpectPass(t, batchCommitter, permission.SetBase, snativeArgs)
+	testSNativeTxExpectPass(t, batchCommitter, ptypes.SetBase, snativeArgs)
 	acc := getAccount(batchCommitter.stateCache, users[3].Address())
-	if v, _ := acc.MutablePermissions().Base.Get(permission.Bond); v {
+	if v, _ := acc.MutablePermissions().Base.Get(ptypes.Bond); v {
 		t.Fatal("expected permission to be set false")
 	}
-	snativeArgs = snativePermTestInputTx("setBase", users[3], permission.CreateContract, true)
-	testSNativeTxExpectPass(t, batchCommitter, permission.SetBase, snativeArgs)
+	snativeArgs = snativePermTestInputTx("setBase", users[3], ptypes.CreateContract, true)
+	testSNativeTxExpectPass(t, batchCommitter, ptypes.SetBase, snativeArgs)
 	acc = getAccount(batchCommitter.stateCache, users[3].Address())
-	if v, _ := acc.MutablePermissions().Base.Get(permission.CreateContract); !v {
+	if v, _ := acc.MutablePermissions().Base.Get(ptypes.CreateContract); !v {
 		t.Fatal("expected permission to be set true")
 	}
 
 	fmt.Println("\n#### UnsetBase")
 	// UnsetBase
-	snativeArgs = snativePermTestInputTx("unsetBase", users[3], permission.CreateContract, false)
+	snativeArgs = snativePermTestInputTx("unsetBase", users[3], ptypes.CreateContract, false)
 	testSNativeTxExpectFail(t, batchCommitter, snativeArgs)
-	testSNativeTxExpectPass(t, batchCommitter, permission.UnsetBase, snativeArgs)
+	testSNativeTxExpectPass(t, batchCommitter, ptypes.UnsetBase, snativeArgs)
 	acc = getAccount(batchCommitter.stateCache, users[3].Address())
-	if v, _ := acc.MutablePermissions().Base.Get(permission.CreateContract); v {
+	if v, _ := acc.MutablePermissions().Base.Get(ptypes.CreateContract); v {
 		t.Fatal("expected permission to be set false")
 	}
 
 	fmt.Println("\n#### SetGlobal")
 	// SetGlobalPerm
-	snativeArgs = snativePermTestInputTx("setGlobal", users[3], permission.CreateContract, true)
+	snativeArgs = snativePermTestInputTx("setGlobal", users[3], ptypes.CreateContract, true)
 	testSNativeTxExpectFail(t, batchCommitter, snativeArgs)
-	testSNativeTxExpectPass(t, batchCommitter, permission.SetGlobal, snativeArgs)
+	testSNativeTxExpectPass(t, batchCommitter, ptypes.SetGlobal, snativeArgs)
 	acc = getAccount(batchCommitter.stateCache, acm.GlobalPermissionsAddress)
-	if v, _ := acc.MutablePermissions().Base.Get(permission.CreateContract); !v {
+	if v, _ := acc.MutablePermissions().Base.Get(ptypes.CreateContract); !v {
 		t.Fatal("expected permission to be set true")
 	}
 
@@ -891,7 +874,7 @@ func TestSNativeTx(t *testing.T) {
 	// AddRole
 	snativeArgs = snativeRoleTestInputTx("addRole", users[3], "chuck")
 	testSNativeTxExpectFail(t, batchCommitter, snativeArgs)
-	testSNativeTxExpectPass(t, batchCommitter, permission.AddRole, snativeArgs)
+	testSNativeTxExpectPass(t, batchCommitter, ptypes.AddRole, snativeArgs)
 	acc = getAccount(batchCommitter.stateCache, users[3].Address())
 	if v := acc.Permissions().HasRole("chuck"); !v {
 		t.Fatal("expected role to be added")
@@ -901,7 +884,7 @@ func TestSNativeTx(t *testing.T) {
 	// RemoveRole
 	snativeArgs = snativeRoleTestInputTx("removeRole", users[3], "chuck")
 	testSNativeTxExpectFail(t, batchCommitter, snativeArgs)
-	testSNativeTxExpectPass(t, batchCommitter, permission.RemoveRole, snativeArgs)
+	testSNativeTxExpectPass(t, batchCommitter, ptypes.RemoveRole, snativeArgs)
 	acc = getAccount(batchCommitter.stateCache, users[3].Address())
 	if v := acc.Permissions().HasRole("chuck"); v {
 		t.Fatal("expected role to be removed")
@@ -993,7 +976,7 @@ func TestNameTxs(t *testing.T) {
 		}
 	}
 
-	validateEntry := func(t *testing.T, entry *NameRegEntry, name, data string, addr crypto.Address, expires uint64) {
+	validateEntry := func(t *testing.T, entry *names.Entry, name, data string, addr crypto.Address, expires uint64) {
 
 		if entry == nil {
 			t.Fatalf("Could not find name %s", name)
@@ -1022,7 +1005,7 @@ func TestNameTxs(t *testing.T) {
 	if err := execTxWithState(state, txEnv); err != nil {
 		t.Fatal(err)
 	}
-	entry, err := state.GetNameRegEntry(name)
+	entry, err := state.GetNameEntry(name)
 	require.NoError(t, err)
 	validateEntry(t, entry, name, data, testPrivAccounts[0].Address(), startingBlock+numDesiredBlocks)
 
@@ -1042,7 +1025,7 @@ func TestNameTxs(t *testing.T) {
 	if err := execTxWithStateNewBlock(state, blockchain, txEnv); err != nil {
 		t.Fatal(err)
 	}
-	entry, err = state.GetNameRegEntry(name)
+	entry, err = state.GetNameEntry(name)
 	require.NoError(t, err)
 	validateEntry(t, entry, name, data, testPrivAccounts[0].Address(), startingBlock+numDesiredBlocks*2)
 
@@ -1053,7 +1036,7 @@ func TestNameTxs(t *testing.T) {
 	if err := execTxWithStateNewBlock(state, blockchain, txEnv); err != nil {
 		t.Fatal(err)
 	}
-	entry, err = state.GetNameRegEntry(name)
+	entry, err = state.GetNameEntry(name)
 	require.NoError(t, err)
 	validateEntry(t, entry, name, data, testPrivAccounts[0].Address(), startingBlock+numDesiredBlocks*3)
 
@@ -1077,7 +1060,7 @@ func TestNameTxs(t *testing.T) {
 	if err := execTxWithStateAndBlockchain(state, blockchain.Tip, txEnv); err != nil {
 		t.Fatal(err)
 	}
-	entry, err = state.GetNameRegEntry(name)
+	entry, err = state.GetNameEntry(name)
 	require.NoError(t, err)
 	validateEntry(t, entry, name, data, testPrivAccounts[1].Address(), blockchain.LastBlockHeight()+numDesiredBlocks)
 
@@ -1092,7 +1075,7 @@ func TestNameTxs(t *testing.T) {
 	if err := execTxWithStateAndBlockchain(state, blockchain.Tip, txEnv); err != nil {
 		t.Fatal(err)
 	}
-	entry, err = state.GetNameRegEntry(name)
+	entry, err = state.GetNameEntry(name)
 	require.NoError(t, err)
 	validateEntry(t, entry, name, data, testPrivAccounts[1].Address(), blockchain.LastBlockHeight()+numDesiredBlocks)
 
@@ -1105,7 +1088,7 @@ func TestNameTxs(t *testing.T) {
 	if err := execTxWithStateNewBlock(state, blockchain, txEnv); err != nil {
 		t.Fatal(err)
 	}
-	entry, err = state.GetNameRegEntry(name)
+	entry, err = state.GetNameEntry(name)
 	require.NoError(t, err)
 	if entry != nil {
 		t.Fatal("Expected removed entry to be nil")
@@ -1122,7 +1105,7 @@ func TestNameTxs(t *testing.T) {
 	if err := execTxWithStateAndBlockchain(state, blockchain.Tip, txEnv); err != nil {
 		t.Fatal(err)
 	}
-	entry, err = state.GetNameRegEntry(name)
+	entry, err = state.GetNameEntry(name)
 	require.NoError(t, err)
 	validateEntry(t, entry, name, data, testPrivAccounts[0].Address(), blockchain.LastBlockHeight()+numDesiredBlocks)
 	// Fast forward
@@ -1138,7 +1121,7 @@ func TestNameTxs(t *testing.T) {
 	if err := execTxWithStateNewBlock(state, blockchain, txEnv); err != nil {
 		t.Fatal(err)
 	}
-	entry, err = state.GetNameRegEntry(name)
+	entry, err = state.GetNameEntry(name)
 	require.NoError(t, err)
 	if entry != nil {
 		t.Fatal("Expected removed entry to be nil")
@@ -1482,7 +1465,7 @@ proof-of-work chain as proof of what happened while they were gone `
 			t.Errorf("Unexpected newAcc0 balance. Expected %v, got %v",
 				acc0.Balance()-entryAmount, newAcc0.Balance())
 		}
-		entry, err := stateNameTx.GetNameRegEntry(entryName)
+		entry, err := stateNameTx.GetNameEntry(entryName)
 		require.NoError(t, err)
 		if entry == nil {
 			t.Errorf("Expected an entry but got nil")
@@ -1578,7 +1561,7 @@ func TestSelfDestruct(t *testing.T) {
 	tx := payload.NewCallTxWithSequence(acc0PubKey, addressPtr(acc1), nil, sendingAmount, 1000, 0, acc0.Sequence()+1)
 
 	// we use cache instead of execTxWithState so we can run the tx twice
-	exe := NewBatchCommitter(state, testChainID, newBlockchain(testGenesisDoc).Tip, event.NewNoOpPublisher(), logger)
+	exe := NewBatchCommitter(state, newBlockchain(testGenesisDoc).Tip, event.NewNoOpPublisher(), logger)
 	signAndExecute(t, false, exe, testChainID, tx, privAccounts[0])
 
 	// if we do it again, we won't get an error, but the self-destruct
@@ -1616,7 +1599,7 @@ func signAndExecute(t *testing.T, shoudlFail bool, exe BatchExecutor, chainID st
 }
 
 func execTxWithStateAndBlockchain(state *State, tip *bcm.Tip, txEnv *txs.Envelope) error {
-	exe := newExecutor("execTxWithStateAndBlockchainCache", true, state, testChainID, tip,
+	exe := newExecutor("execTxWithStateAndBlockchainCache", true, state, tip,
 		event.NewNoOpPublisher(), logger)
 	if err := exe.Execute(txEnv); err != nil {
 		return err
@@ -1671,36 +1654,31 @@ func addressPtr(account acm.Account) *crypto.Address {
 //-------------------------------------------------------------------------------------
 // helpers
 
-var ExceptionTimeOut = "timed out waiting for event"
+var ExceptionTimeOut = errors.NewCodedError(errors.ErrorCodeGeneric, "timed out waiting for event")
 
 // run ExecTx and wait for the Call event on given addr
 // returns the msg data and an error/exception
-func execTxWaitEvent(t *testing.T, batchCommitter *executor, txEnv *txs.Envelope, eventid string) (interface{}, string) {
-	emitter := event.NewEmitter(logger)
-	ch := make(chan interface{})
-	emitter.Subscribe(context.Background(), "test", event.QueryForEventID(eventid), ch)
-	evc := event.NewEventCache(emitter)
-	batchCommitter.eventCache = evc
-	go func() {
-		if err := batchCommitter.Execute(txEnv); err != nil {
-			ch <- err.Error()
-		}
-		evc.Flush()
-	}()
+func execTxWaitAccountCall(t *testing.T, batchCommitter *executor, emitter event.Emitter, txEnv *txs.Envelope,
+	address crypto.Address) (*evm_events.EventDataCall, error) {
+
+	ch := make(chan *evm_events.EventDataCall)
+	ctx := context.Background()
+	const subscriber = "exexTxWaitEvent"
+	//emitter.Subscribe(ctx, subscriber, event.QueryForEventID(eventid), ch)
+	evm_events.SubscribeAccountCall(ctx, emitter, subscriber, address, txEnv.Tx.Hash(), -1, ch)
+	defer emitter.UnsubscribeAll(ctx, subscriber)
+	err := batchCommitter.Execute(txEnv)
+	if err != nil {
+		return nil, err
+	}
+	batchCommitter.Commit()
 	ticker := time.NewTicker(5 * time.Second)
 
 	select {
-	case msg := <-ch:
-		switch ev := msg.(type) {
-		case *exe_events.EventDataTx:
-			return ev, ev.Exception
-		case *evm_events.EventDataCall:
-			return ev, ev.Exception
-		case string:
-			return nil, ev
-		default:
-			return ev, ""
-		}
+	case eventDataCall := <-ch:
+		fmt.Println("MSG: ", eventDataCall)
+		return eventDataCall, eventDataCall.Exception.AsError()
+
 	case <-ticker.C:
 		return nil, ExceptionTimeOut
 	}
@@ -1708,18 +1686,18 @@ func execTxWaitEvent(t *testing.T, batchCommitter *executor, txEnv *txs.Envelope
 }
 
 // give a contract perms for an snative, call it, it calls the snative, but shouldn't have permission
-func testSNativeCALLExpectFail(t *testing.T, batchCommitter *executor, doug acm.MutableAccount,
+func testSNativeCALLExpectFail(t *testing.T, batchCommitter *executor, emitter event.Emitter, doug acm.MutableAccount,
 	snativeAddress crypto.Address, data []byte) {
-	testSNativeCALL(t, false, batchCommitter, doug, 0, snativeAddress, data, nil)
+	testSNativeCALL(t, false, batchCommitter, emitter, doug, 0, snativeAddress, data, nil)
 }
 
 // give a contract perms for an snative, call it, it calls the snative, ensure the check funciton (f) succeeds
-func testSNativeCALLExpectPass(t *testing.T, batchCommitter *executor, doug acm.MutableAccount, snativePerm ptypes.PermFlag,
+func testSNativeCALLExpectPass(t *testing.T, batchCommitter *executor, emitter event.Emitter, doug acm.MutableAccount, snativePerm ptypes.PermFlag,
 	snativeAddress crypto.Address, data []byte, f func([]byte) error) {
-	testSNativeCALL(t, true, batchCommitter, doug, snativePerm, snativeAddress, data, f)
+	testSNativeCALL(t, true, batchCommitter, emitter, doug, snativePerm, snativeAddress, data, f)
 }
 
-func testSNativeCALL(t *testing.T, expectPass bool, batchCommitter *executor, doug acm.MutableAccount,
+func testSNativeCALL(t *testing.T, expectPass bool, batchCommitter *executor, emitter event.Emitter, doug acm.MutableAccount,
 	snativePerm ptypes.PermFlag, snativeAddress crypto.Address, data []byte, f func([]byte) error) {
 	if expectPass {
 		doug.MutablePermissions().Base.Set(snativePerm, true)
@@ -1733,23 +1711,18 @@ func testSNativeCALL(t *testing.T, expectPass bool, batchCommitter *executor, do
 	txEnv := txs.Enclose(testChainID, tx)
 	require.NoError(t, txEnv.Sign(users[0]))
 	t.Logf("subscribing to %v", evm_events.EventStringAccountCall(snativeAddress))
-	ev, exception := execTxWaitEvent(t, batchCommitter, txEnv, evm_events.EventStringAccountCall(snativeAddress))
-	if exception == ExceptionTimeOut {
+	ev, err := execTxWaitAccountCall(t, batchCommitter, emitter, txEnv, snativeAddress)
+	if err == ExceptionTimeOut {
 		t.Fatal("Timed out waiting for event")
 	}
 	if expectPass {
-		if exception != "" {
-			t.Fatal("Unexpected exception", exception)
-		}
-		evv := ev.(*evm_events.EventDataCall)
-		ret := evv.Return
+		require.NoError(t, err)
+		ret := ev.Return
 		if err := f(ret); err != nil {
 			t.Fatal(err)
 		}
 	} else {
-		if exception == "" {
-			t.Fatal("Expected exception")
-		}
+		require.Error(t, err)
 	}
 }
 
@@ -1820,7 +1793,7 @@ func snativePermTestInputCALL(name string, user acm.AddressableSigner, perm ptyp
 	}
 	data = append(permNameToFuncID(name), data...)
 	var err error
-	if pF, err = permission.PermStringToFlag(name); err != nil {
+	if pF, err = ptypes.PermStringToFlag(name); err != nil {
 		panic(fmt.Sprintf("failed to convert perm string (%s) to flag", name))
 	}
 	return
@@ -1850,7 +1823,7 @@ func snativeRoleTestInputCALL(name string, user acm.AddressableSigner,
 	data = append(permNameToFuncID(name), data...)
 
 	var err error
-	if pF, err = permission.PermStringToFlag(name); err != nil {
+	if pF, err = ptypes.PermStringToFlag(name); err != nil {
 		panic(fmt.Sprintf("failed to convert perm string (%s) to flag", name))
 	}
 	return
diff --git a/execution/executors/call.go b/execution/executors/call.go
new file mode 100644
index 0000000000000000000000000000000000000000..f377e9147eb14d022400aa3380b26ced004bc292
--- /dev/null
+++ b/execution/executors/call.go
@@ -0,0 +1,246 @@
+package executors
+
+import (
+	"fmt"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/binary"
+	"github.com/hyperledger/burrow/blockchain"
+	"github.com/hyperledger/burrow/event"
+	"github.com/hyperledger/burrow/execution/errors"
+	"github.com/hyperledger/burrow/execution/events"
+	"github.com/hyperledger/burrow/execution/evm"
+	"github.com/hyperledger/burrow/logging"
+	"github.com/hyperledger/burrow/logging/structure"
+	"github.com/hyperledger/burrow/txs"
+	"github.com/hyperledger/burrow/txs/payload"
+)
+
+// TODO: make configurable
+const GasLimit = uint64(1000000)
+
+type CallContext struct {
+	Tip            blockchain.TipInfo
+	StateWriter    state.Writer
+	EventPublisher event.Publisher
+	RunCall        bool
+	VMOptions      []func(*evm.VM)
+	Logger         *logging.Logger
+	tx             *payload.CallTx
+	txEnv          *txs.Envelope
+}
+
+func (ctx *CallContext) Execute(txEnv *txs.Envelope) error {
+	var ok bool
+	ctx.tx, ok = txEnv.Tx.Payload.(*payload.CallTx)
+	if !ok {
+		return fmt.Errorf("payload must be CallTx, but is: %v", txEnv.Tx.Payload)
+	}
+	ctx.txEnv = txEnv
+	inAcc, outAcc, err := ctx.Precheck()
+	if err != nil {
+		return err
+	}
+	// That the fee less than the input amount is checked by Precheck
+	value := ctx.tx.Input.Amount - ctx.tx.Fee
+
+	if ctx.RunCall {
+		ctx.Deliver(inAcc, outAcc, value)
+	} else {
+		ctx.Check(inAcc, value)
+	}
+
+	return nil
+}
+
+func (ctx *CallContext) Precheck() (acm.MutableAccount, acm.Account, error) {
+	var outAcc acm.Account
+	// Validate input
+	inAcc, err := state.GetMutableAccount(ctx.StateWriter, ctx.tx.Input.Address)
+	if err != nil {
+		return nil, nil, err
+	}
+	if inAcc == nil {
+		ctx.Logger.InfoMsg("Cannot find input account",
+			"tx_input", ctx.tx.Input)
+		return nil, nil, payload.ErrTxInvalidAddress
+	}
+
+	err = validateInput(inAcc, ctx.tx.Input)
+	if err != nil {
+		ctx.Logger.InfoMsg("validateInput failed",
+			"tx_input", ctx.tx.Input, structure.ErrorKey, err)
+		return nil, nil, err
+	}
+	if ctx.tx.Input.Amount < ctx.tx.Fee {
+		ctx.Logger.InfoMsg("Sender did not send enough to cover the fee",
+			"tx_input", ctx.tx.Input)
+		return nil, nil, payload.ErrTxInsufficientFunds
+	}
+
+	ctx.Logger.TraceMsg("Incrementing sequence number for CallTx",
+		"tag", "sequence",
+		"account", inAcc.Address(),
+		"old_sequence", inAcc.Sequence(),
+		"new_sequence", inAcc.Sequence()+1)
+
+	inAcc, err = inAcc.IncSequence().SubtractFromBalance(ctx.tx.Fee)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// Calling a nil destination is defined as requesting contract creation
+	createContract := ctx.tx.Address == nil
+
+	if createContract {
+		if !hasCreateContractPermission(ctx.StateWriter, inAcc, ctx.Logger) {
+			return nil, nil, fmt.Errorf("account %s does not have CreateContract permission", ctx.tx.Input.Address)
+		}
+	} else {
+		if !hasCallPermission(ctx.StateWriter, inAcc, ctx.Logger) {
+			return nil, nil, fmt.Errorf("account %s does not have Call permission", ctx.tx.Input.Address)
+		}
+		// check if its a native contract
+		if evm.IsRegisteredNativeContract(ctx.tx.Address.Word256()) {
+			return nil, nil, fmt.Errorf("attempt to call a native contract at %s, "+
+				"but native contracts cannot be called using CallTx. Use a "+
+				"contract that calls the native contract or the appropriate tx "+
+				"type (eg. PermissionsTx, NameTx)", ctx.tx.Address)
+		}
+
+		// Output account may be nil if we are still in mempool and contract was created in same block as this tx
+		// but that's fine, because the account will be created properly when the create tx runs in the block
+		// and then this won't return nil. otherwise, we take their fee
+		// Note: ctx.tx.Address == nil iff createContract so dereference is okay
+		outAcc, err = ctx.StateWriter.GetAccount(*ctx.tx.Address)
+		if err != nil {
+			return nil, nil, err
+		}
+	}
+
+	err = ctx.StateWriter.UpdateAccount(inAcc)
+	if err != nil {
+		return nil, nil, err
+	}
+	return inAcc, outAcc, nil
+}
+
+func (ctx *CallContext) Check(inAcc acm.MutableAccount, value uint64) error {
+	createContract := ctx.tx.Address == nil
+	// The mempool does not call txs until
+	// the proposer determines the order of txs.
+	// So mempool will skip the actual .Call(),
+	// and only deduct from the caller's balance.
+	inAcc, err := inAcc.SubtractFromBalance(value)
+	if err != nil {
+		return err
+	}
+	if createContract {
+		// This is done by DeriveNewAccount when runCall == true
+		ctx.Logger.TraceMsg("Incrementing sequence number since creates contract",
+			"tag", "sequence",
+			"account", inAcc.Address(),
+			"old_sequence", inAcc.Sequence(),
+			"new_sequence", inAcc.Sequence()+1)
+		inAcc.IncSequence()
+	}
+	return ctx.StateWriter.UpdateAccount(inAcc)
+}
+
+func (ctx *CallContext) Deliver(inAcc, outAcc acm.Account, value uint64) error {
+	createContract := ctx.tx.Address == nil
+	// VM call variables
+	var (
+		gas     uint64             = ctx.tx.GasLimit
+		caller  acm.MutableAccount = acm.AsMutableAccount(inAcc)
+		callee  acm.MutableAccount = nil // initialized below
+		code    []byte             = nil
+		ret     []byte             = nil
+		txCache                    = state.NewCache(ctx.StateWriter, state.Name("TxCache"))
+		params                     = evm.Params{
+			BlockHeight: ctx.Tip.LastBlockHeight(),
+			BlockHash:   binary.LeftPadWord256(ctx.Tip.LastBlockHash()),
+			BlockTime:   ctx.Tip.LastBlockTime().Unix(),
+			GasLimit:    GasLimit,
+		}
+	)
+
+	// get or create callee
+	if createContract {
+		// We already checked for permission
+		callee = evm.DeriveNewAccount(caller, state.GlobalAccountPermissions(ctx.StateWriter), ctx.Logger)
+		code = ctx.tx.Data
+		ctx.Logger.TraceMsg("Creating new contract",
+			"contract_address", callee.Address(),
+			"init_code", code)
+	} else {
+		if outAcc == nil || len(outAcc.Code()) == 0 {
+			// if you call an account that doesn't exist
+			// or an account with no code then we take fees (sorry pal)
+			// NOTE: it's fine to create a contract and call it within one
+			// block (sequence number will prevent re-ordering of those txs)
+			// but to create with one contract and call with another
+			// you have to wait a block to avoid a re-ordering attack
+			// that will take your fees
+			if outAcc == nil {
+				ctx.Logger.InfoMsg("Call to address that does not exist",
+					"caller_address", inAcc.Address(),
+					"callee_address", ctx.tx.Address)
+			} else {
+				ctx.Logger.InfoMsg("Call to address that holds no code",
+					"caller_address", inAcc.Address(),
+					"callee_address", ctx.tx.Address)
+			}
+			ctx.FireCallEvents(nil, payload.ErrTxInvalidAddress)
+			return nil
+		}
+		callee = acm.AsMutableAccount(outAcc)
+		code = callee.Code()
+		ctx.Logger.TraceMsg("Calling existing contract",
+			"contract_address", callee.Address(),
+			"input", ctx.tx.Data,
+			"contract_code", code)
+	}
+	ctx.Logger.Trace.Log("callee", callee.Address().String())
+
+	txCache.UpdateAccount(caller)
+	txCache.UpdateAccount(callee)
+	vmach := evm.NewVM(params, caller.Address(), ctx.txEnv.Tx.Hash(), ctx.Logger, ctx.VMOptions...)
+	vmach.SetPublisher(ctx.EventPublisher)
+	// NOTE: Call() transfers the value from caller to callee iff call succeeds.
+	ret, exception := vmach.Call(txCache, caller, callee, code, ctx.tx.Data, value, &gas)
+	if exception != nil {
+		// Failure. Charge the gas fee. The 'value' was otherwise not transferred.
+		ctx.Logger.InfoMsg("Error on execution",
+			structure.ErrorKey, exception)
+	} else {
+		ctx.Logger.TraceMsg("Successful execution")
+		if createContract {
+			callee.SetCode(ret)
+		}
+		err := txCache.Sync(ctx.StateWriter)
+		if err != nil {
+			return err
+		}
+	}
+	// Create a receipt from the ret and whether it erred.
+	ctx.Logger.TraceMsg("VM call complete",
+		"caller", caller,
+		"callee", callee,
+		"return", ret,
+		structure.ErrorKey, exception)
+	ctx.FireCallEvents(ret, exception)
+	return nil
+}
+
+func (ctx *CallContext) FireCallEvents(ret []byte, err error) {
+	// Fire Events for sender and receiver
+	// a separate event will be fired from vm for each additional call
+	if ctx.EventPublisher != nil {
+		events.PublishAccountInput(ctx.EventPublisher, ctx.tx.Input.Address, ctx.txEnv.Tx, ret, errors.AsCodedError(err))
+		if ctx.tx.Address != nil {
+			events.PublishAccountOutput(ctx.EventPublisher, *ctx.tx.Address, ctx.txEnv.Tx, ret, errors.AsCodedError(err))
+		}
+	}
+}
diff --git a/execution/executors/name.go b/execution/executors/name.go
new file mode 100644
index 0000000000000000000000000000000000000000..dbd2978a82395e5ca5a19adb6c951405f6c800d5
--- /dev/null
+++ b/execution/executors/name.go
@@ -0,0 +1,185 @@
+package executors
+
+import (
+	"fmt"
+
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/blockchain"
+	"github.com/hyperledger/burrow/event"
+	"github.com/hyperledger/burrow/execution/events"
+	"github.com/hyperledger/burrow/execution/names"
+	"github.com/hyperledger/burrow/logging"
+	"github.com/hyperledger/burrow/logging/structure"
+	"github.com/hyperledger/burrow/txs"
+	"github.com/hyperledger/burrow/txs/payload"
+)
+
+type NameContext struct {
+	Tip            blockchain.TipInfo
+	StateWriter    state.Writer
+	EventPublisher event.Publisher
+	NameReg        names.Writer
+	Logger         *logging.Logger
+	tx             *payload.NameTx
+}
+
+func (ctx *NameContext) Execute(txEnv *txs.Envelope) error {
+	var ok bool
+	ctx.tx, ok = txEnv.Tx.Payload.(*payload.NameTx)
+	if !ok {
+		return fmt.Errorf("payload must be NameTx, but is: %v", txEnv.Tx.Payload)
+	}
+	// Validate input
+	inAcc, err := state.GetMutableAccount(ctx.StateWriter, ctx.tx.Input.Address)
+	if err != nil {
+		return err
+	}
+	if inAcc == nil {
+		ctx.Logger.InfoMsg("Cannot find input account",
+			"tx_input", ctx.tx.Input)
+		return payload.ErrTxInvalidAddress
+	}
+	// check permission
+	if !hasNamePermission(ctx.StateWriter, inAcc, ctx.Logger) {
+		return fmt.Errorf("account %s does not have Name permission", ctx.tx.Input.Address)
+	}
+	err = validateInput(inAcc, ctx.tx.Input)
+	if err != nil {
+		ctx.Logger.InfoMsg("validateInput failed",
+			"tx_input", ctx.tx.Input, structure.ErrorKey, err)
+		return err
+	}
+	if ctx.tx.Input.Amount < ctx.tx.Fee {
+		ctx.Logger.InfoMsg("Sender did not send enough to cover the fee",
+			"tx_input", ctx.tx.Input)
+		return payload.ErrTxInsufficientFunds
+	}
+
+	// validate the input strings
+	if err := ctx.tx.ValidateStrings(); err != nil {
+		return err
+	}
+
+	value := ctx.tx.Input.Amount - ctx.tx.Fee
+
+	// let's say cost of a name for one block is len(data) + 32
+	costPerBlock := names.NameCostPerBlock(names.NameBaseCost(ctx.tx.Name, ctx.tx.Data))
+	expiresIn := value / uint64(costPerBlock)
+	lastBlockHeight := ctx.Tip.LastBlockHeight()
+
+	ctx.Logger.TraceMsg("New NameTx",
+		"value", value,
+		"cost_per_block", costPerBlock,
+		"expires_in", expiresIn,
+		"last_block_height", lastBlockHeight)
+
+	// check if the name exists
+	entry, err := ctx.NameReg.GetNameEntry(ctx.tx.Name)
+	if err != nil {
+		return err
+	}
+
+	if entry != nil {
+		var expired bool
+
+		// if the entry already exists, and hasn't expired, we must be owner
+		if entry.Expires > lastBlockHeight {
+			// ensure we are owner
+			if entry.Owner != ctx.tx.Input.Address {
+				return fmt.Errorf("permission denied: sender %s is trying to update a name (%s) for "+
+					"which they are not an owner", ctx.tx.Input.Address, ctx.tx.Name)
+			}
+		} else {
+			expired = true
+		}
+
+		// no value and empty data means delete the entry
+		if value == 0 && len(ctx.tx.Data) == 0 {
+			// maybe we reward you for telling us we can delete this crap
+			// (owners if not expired, anyone if expired)
+			ctx.Logger.TraceMsg("Removing NameReg entry (no value and empty data in tx requests this)",
+				"name", entry.Name)
+			err := ctx.NameReg.RemoveNameEntry(entry.Name)
+			if err != nil {
+				return err
+			}
+		} else {
+			// update the entry by bumping the expiry
+			// and changing the data
+			if expired {
+				if expiresIn < names.MinNameRegistrationPeriod {
+					return fmt.Errorf("Names must be registered for at least %d blocks", names.MinNameRegistrationPeriod)
+				}
+				entry.Expires = lastBlockHeight + expiresIn
+				entry.Owner = ctx.tx.Input.Address
+				ctx.Logger.TraceMsg("An old NameReg entry has expired and been reclaimed",
+					"name", entry.Name,
+					"expires_in", expiresIn,
+					"owner", entry.Owner)
+			} else {
+				// since the size of the data may have changed
+				// we use the total amount of "credit"
+				oldCredit := (entry.Expires - lastBlockHeight) * names.NameBaseCost(entry.Name, entry.Data)
+				credit := oldCredit + value
+				expiresIn = uint64(credit / costPerBlock)
+				if expiresIn < names.MinNameRegistrationPeriod {
+					return fmt.Errorf("names must be registered for at least %d blocks", names.MinNameRegistrationPeriod)
+				}
+				entry.Expires = lastBlockHeight + expiresIn
+				ctx.Logger.TraceMsg("Updated NameReg entry",
+					"name", entry.Name,
+					"expires_in", expiresIn,
+					"old_credit", oldCredit,
+					"value", value,
+					"credit", credit)
+			}
+			entry.Data = ctx.tx.Data
+			err := ctx.NameReg.UpdateNameEntry(entry)
+			if err != nil {
+				return err
+			}
+		}
+	} else {
+		if expiresIn < names.MinNameRegistrationPeriod {
+			return fmt.Errorf("Names must be registered for at least %d blocks", names.MinNameRegistrationPeriod)
+		}
+		// entry does not exist, so create it
+		entry = &names.Entry{
+			Name:    ctx.tx.Name,
+			Owner:   ctx.tx.Input.Address,
+			Data:    ctx.tx.Data,
+			Expires: lastBlockHeight + expiresIn,
+		}
+		ctx.Logger.TraceMsg("Creating NameReg entry",
+			"name", entry.Name,
+			"expires_in", expiresIn)
+		err := ctx.NameReg.UpdateNameEntry(entry)
+		if err != nil {
+			return err
+		}
+	}
+
+	// TODO: something with the value sent?
+
+	// Good!
+	ctx.Logger.TraceMsg("Incrementing sequence number for NameTx",
+		"tag", "sequence",
+		"account", inAcc.Address(),
+		"old_sequence", inAcc.Sequence(),
+		"new_sequence", inAcc.Sequence()+1)
+	inAcc.IncSequence()
+	inAcc, err = inAcc.SubtractFromBalance(value)
+	if err != nil {
+		return err
+	}
+	ctx.StateWriter.UpdateAccount(inAcc)
+
+	// TODO: maybe we want to take funds on error and allow txs in that don't do anythingi?
+
+	if ctx.EventPublisher != nil {
+		events.PublishAccountInput(ctx.EventPublisher, ctx.tx.Input.Address, txEnv.Tx, nil, nil)
+		events.PublishNameReg(ctx.EventPublisher, txEnv.Tx)
+	}
+
+	return nil
+}
diff --git a/execution/executors/permissions.go b/execution/executors/permissions.go
new file mode 100644
index 0000000000000000000000000000000000000000..06dbd8c0acb3ddc1d96ead562557b7cb58dfb7d0
--- /dev/null
+++ b/execution/executors/permissions.go
@@ -0,0 +1,153 @@
+package executors
+
+import (
+	"fmt"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/crypto"
+	"github.com/hyperledger/burrow/event"
+	"github.com/hyperledger/burrow/execution/events"
+	"github.com/hyperledger/burrow/logging"
+	"github.com/hyperledger/burrow/logging/structure"
+	ptypes "github.com/hyperledger/burrow/permission/types"
+	"github.com/hyperledger/burrow/txs"
+	"github.com/hyperledger/burrow/txs/payload"
+)
+
+type PermissionsContext struct {
+	StateWriter    state.Writer
+	EventPublisher event.Publisher
+	Logger         *logging.Logger
+	tx             *payload.PermissionsTx
+}
+
+func (ctx *PermissionsContext) Execute(txEnv *txs.Envelope) error {
+	var ok bool
+	ctx.tx, ok = txEnv.Tx.Payload.(*payload.PermissionsTx)
+	if !ok {
+		return fmt.Errorf("payload must be PermissionsTx, but is: %v", txEnv.Tx.Payload)
+	}
+	// Validate input
+	inAcc, err := state.GetMutableAccount(ctx.StateWriter, ctx.tx.Input.Address)
+	if err != nil {
+		return err
+	}
+	if inAcc == nil {
+		ctx.Logger.InfoMsg("Cannot find input account",
+			"tx_input", ctx.tx.Input)
+		return payload.ErrTxInvalidAddress
+	}
+
+	err = ctx.tx.PermArgs.EnsureValid()
+	if err != nil {
+		return fmt.Errorf("PermissionsTx received containing invalid PermArgs: %v", err)
+	}
+
+	permFlag := ctx.tx.PermArgs.PermFlag
+	// check permission
+	if !HasPermission(ctx.StateWriter, inAcc, permFlag, ctx.Logger) {
+		return fmt.Errorf("account %s does not have moderator permission %s (%b)", ctx.tx.Input.Address,
+			permFlag.String(), permFlag)
+	}
+
+	err = validateInput(inAcc, ctx.tx.Input)
+	if err != nil {
+		ctx.Logger.InfoMsg("validateInput failed",
+			"tx_input", ctx.tx.Input,
+			structure.ErrorKey, err)
+		return err
+	}
+
+	value := ctx.tx.Input.Amount
+
+	ctx.Logger.TraceMsg("New PermissionsTx",
+		"perm_args", ctx.tx.PermArgs.String())
+
+	var permAcc acm.Account
+	switch ctx.tx.PermArgs.PermFlag {
+	case ptypes.HasBase:
+		// this one doesn't make sense from txs
+		return fmt.Errorf("HasBase is for contracts, not humans. Just look at the blockchain")
+	case ptypes.SetBase:
+		permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Address,
+			func(perms *ptypes.AccountPermissions) error {
+				return perms.Base.Set(*ctx.tx.PermArgs.Permission, *ctx.tx.PermArgs.Value)
+			})
+	case ptypes.UnsetBase:
+		permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Address,
+			func(perms *ptypes.AccountPermissions) error {
+				return perms.Base.Unset(*ctx.tx.PermArgs.Permission)
+			})
+	case ptypes.SetGlobal:
+		permAcc, err = mutatePermissions(ctx.StateWriter, acm.GlobalPermissionsAddress,
+			func(perms *ptypes.AccountPermissions) error {
+				return perms.Base.Set(*ctx.tx.PermArgs.Permission, *ctx.tx.PermArgs.Value)
+			})
+	case ptypes.HasRole:
+		return fmt.Errorf("HasRole is for contracts, not humans. Just look at the blockchain")
+	case ptypes.AddRole:
+		permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Address,
+			func(perms *ptypes.AccountPermissions) error {
+				if !perms.AddRole(*ctx.tx.PermArgs.Role) {
+					return fmt.Errorf("role (%s) already exists for account %s",
+						*ctx.tx.PermArgs.Role, *ctx.tx.PermArgs.Address)
+				}
+				return nil
+			})
+	case ptypes.RemoveRole:
+		permAcc, err = mutatePermissions(ctx.StateWriter, *ctx.tx.PermArgs.Address,
+			func(perms *ptypes.AccountPermissions) error {
+				if !perms.RmRole(*ctx.tx.PermArgs.Role) {
+					return fmt.Errorf("role (%s) does not exist for account %s",
+						*ctx.tx.PermArgs.Role, *ctx.tx.PermArgs.Address)
+				}
+				return nil
+			})
+	default:
+		return fmt.Errorf("invalid permission function: %v", permFlag)
+	}
+
+	// TODO: maybe we want to take funds on error and allow txs in that don't do anythingi?
+	if err != nil {
+		return err
+	}
+
+	// Good!
+	ctx.Logger.TraceMsg("Incrementing sequence number for PermissionsTx",
+		"tag", "sequence",
+		"account", inAcc.Address(),
+		"old_sequence", inAcc.Sequence(),
+		"new_sequence", inAcc.Sequence()+1)
+	inAcc.IncSequence()
+	inAcc, err = inAcc.SubtractFromBalance(value)
+	if err != nil {
+		return err
+	}
+	ctx.StateWriter.UpdateAccount(inAcc)
+	if permAcc != nil {
+		ctx.StateWriter.UpdateAccount(permAcc)
+	}
+
+	if ctx.EventPublisher != nil {
+		events.PublishAccountInput(ctx.EventPublisher, ctx.tx.Input.Address, txEnv.Tx, nil, nil)
+		events.PublishPermissions(ctx.EventPublisher, permFlag, txEnv.Tx)
+	}
+
+	return nil
+}
+
+func mutatePermissions(stateReader state.Reader, address crypto.Address,
+	mutator func(*ptypes.AccountPermissions) error) (acm.Account, error) {
+
+	account, err := stateReader.GetAccount(address)
+	if err != nil {
+		return nil, err
+	}
+	if account == nil {
+		return nil, fmt.Errorf("could not get account at address %s in order to alter permissions", address)
+	}
+	mutableAccount := acm.AsMutableAccount(account)
+
+	return mutableAccount, mutator(mutableAccount.MutablePermissions())
+}
diff --git a/execution/executors/send.go b/execution/executors/send.go
new file mode 100644
index 0000000000000000000000000000000000000000..6c79eba84f00fd214cc45e92d405c60e29ecbbc8
--- /dev/null
+++ b/execution/executors/send.go
@@ -0,0 +1,81 @@
+package executors
+
+import (
+	"fmt"
+
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/event"
+	"github.com/hyperledger/burrow/execution/events"
+	"github.com/hyperledger/burrow/logging"
+	"github.com/hyperledger/burrow/txs"
+	"github.com/hyperledger/burrow/txs/payload"
+)
+
+type SendContext struct {
+	StateWriter    state.Writer
+	EventPublisher event.Publisher
+	Logger         *logging.Logger
+	tx             *payload.SendTx
+}
+
+func (ctx *SendContext) Execute(txEnv *txs.Envelope) error {
+	var ok bool
+	ctx.tx, ok = txEnv.Tx.Payload.(*payload.SendTx)
+	if !ok {
+		return fmt.Errorf("payload must be NameTx, but is: %v", txEnv.Tx.Payload)
+	}
+	accounts, err := getInputs(ctx.StateWriter, ctx.tx.Inputs)
+	if err != nil {
+		return err
+	}
+
+	// ensure all inputs have send permissions
+	if !hasSendPermission(ctx.StateWriter, accounts, ctx.Logger) {
+		return fmt.Errorf("at least one input lacks permission for SendTx")
+	}
+
+	// add outputs to accounts map
+	// if any outputs don't exist, all inputs must have CreateAccount perm
+	accounts, err = getOrMakeOutputs(ctx.StateWriter, accounts, ctx.tx.Outputs, ctx.Logger)
+	if err != nil {
+		return err
+	}
+
+	inTotal, err := validateInputs(accounts, ctx.tx.Inputs)
+	if err != nil {
+		return err
+	}
+	outTotal, err := validateOutputs(ctx.tx.Outputs)
+	if err != nil {
+		return err
+	}
+	if outTotal > inTotal {
+		return payload.ErrTxInsufficientFunds
+	}
+
+	// Good! Adjust accounts
+	err = adjustByInputs(accounts, ctx.tx.Inputs, ctx.Logger)
+	if err != nil {
+		return err
+	}
+
+	err = adjustByOutputs(accounts, ctx.tx.Outputs)
+	if err != nil {
+		return err
+	}
+
+	for _, acc := range accounts {
+		ctx.StateWriter.UpdateAccount(acc)
+	}
+
+	if ctx.EventPublisher != nil {
+		for _, i := range ctx.tx.Inputs {
+			events.PublishAccountInput(ctx.EventPublisher, i.Address, txEnv.Tx, nil, nil)
+		}
+
+		for _, o := range ctx.tx.Outputs {
+			events.PublishAccountOutput(ctx.EventPublisher, o.Address, txEnv.Tx, nil, nil)
+		}
+	}
+	return nil
+}
diff --git a/execution/executors/shared.go b/execution/executors/shared.go
new file mode 100644
index 0000000000000000000000000000000000000000..8843249b1eaa488400db617ea18676deed2ea647
--- /dev/null
+++ b/execution/executors/shared.go
@@ -0,0 +1,250 @@
+package executors
+
+import (
+	"fmt"
+
+	acm "github.com/hyperledger/burrow/account"
+	"github.com/hyperledger/burrow/account/state"
+	"github.com/hyperledger/burrow/crypto"
+	"github.com/hyperledger/burrow/logging"
+	"github.com/hyperledger/burrow/logging/structure"
+	"github.com/hyperledger/burrow/permission"
+	ptypes "github.com/hyperledger/burrow/permission/types"
+	"github.com/hyperledger/burrow/txs/payload"
+)
+
+// The accounts from the TxInputs must either already have
+// acm.PublicKey().(type) != nil, (it must be known),
+// or it must be specified in the TxInput.  If redeclared,
+// the TxInput is modified and input.PublicKey() set to nil.
+func getInputs(accountGetter state.AccountGetter,
+	ins []*payload.TxInput) (map[crypto.Address]acm.MutableAccount, error) {
+
+	accounts := map[crypto.Address]acm.MutableAccount{}
+	for _, in := range ins {
+		// Account shouldn't be duplicated
+		if _, ok := accounts[in.Address]; ok {
+			return nil, payload.ErrTxDuplicateAddress
+		}
+		acc, err := state.GetMutableAccount(accountGetter, in.Address)
+		if err != nil {
+			return nil, err
+		}
+		if acc == nil {
+			return nil, payload.ErrTxInvalidAddress
+		}
+		accounts[in.Address] = acc
+	}
+	return accounts, nil
+}
+
+func getOrMakeOutputs(accountGetter state.AccountGetter, accs map[crypto.Address]acm.MutableAccount,
+	outs []*payload.TxOutput, logger *logging.Logger) (map[crypto.Address]acm.MutableAccount, error) {
+	if accs == nil {
+		accs = make(map[crypto.Address]acm.MutableAccount)
+	}
+
+	// we should err if an account is being created but the inputs don't have permission
+	var checkedCreatePerms bool
+	for _, out := range outs {
+		// Account shouldn't be duplicated
+		if _, ok := accs[out.Address]; ok {
+			return nil, payload.ErrTxDuplicateAddress
+		}
+		acc, err := state.GetMutableAccount(accountGetter, out.Address)
+		if err != nil {
+			return nil, err
+		}
+		// output account may be nil (new)
+		if acc == nil {
+			if !checkedCreatePerms {
+				if !hasCreateAccountPermission(accountGetter, accs, logger) {
+					return nil, fmt.Errorf("at least one input does not have permission to create accounts")
+				}
+				checkedCreatePerms = true
+			}
+			acc = acm.ConcreteAccount{
+				Address:     out.Address,
+				Sequence:    0,
+				Balance:     0,
+				Permissions: permission.ZeroAccountPermissions,
+			}.MutableAccount()
+		}
+		accs[out.Address] = acc
+	}
+	return accs, nil
+}
+
+func validateInputs(accs map[crypto.Address]acm.MutableAccount, ins []*payload.TxInput) (uint64, error) {
+	total := uint64(0)
+	for _, in := range ins {
+		acc := accs[in.Address]
+		if acc == nil {
+			return 0, fmt.Errorf("validateInputs() expects account in accounts, but account %s not found", in.Address)
+		}
+		err := validateInput(acc, in)
+		if err != nil {
+			return 0, err
+		}
+		// Good. Add amount to total
+		total += in.Amount
+	}
+	return total, nil
+}
+
+func validateInput(acc acm.MutableAccount, in *payload.TxInput) error {
+	// Check TxInput basic
+	if err := in.ValidateBasic(); err != nil {
+		return err
+	}
+	// Check sequences
+	if acc.Sequence()+1 != uint64(in.Sequence) {
+		return payload.ErrTxInvalidSequence{
+			Got:      in.Sequence,
+			Expected: acc.Sequence() + uint64(1),
+		}
+	}
+	// Check amount
+	if acc.Balance() < uint64(in.Amount) {
+		return payload.ErrTxInsufficientFunds
+	}
+	return nil
+}
+
+func validateOutputs(outs []*payload.TxOutput) (uint64, error) {
+	total := uint64(0)
+	for _, out := range outs {
+		// Check TxOutput basic
+		if err := out.ValidateBasic(); err != nil {
+			return 0, err
+		}
+		// Good. Add amount to total
+		total += out.Amount
+	}
+	return total, nil
+}
+
+func adjustByInputs(accs map[crypto.Address]acm.MutableAccount, ins []*payload.TxInput, logger *logging.Logger) error {
+	for _, in := range ins {
+		acc := accs[in.Address]
+		if acc == nil {
+			return fmt.Errorf("adjustByInputs() expects account in accounts, but account %s not found", in.Address)
+		}
+		if acc.Balance() < in.Amount {
+			panic("adjustByInputs() expects sufficient funds")
+			return fmt.Errorf("adjustByInputs() expects sufficient funds but account %s only has balance %v and "+
+				"we are deducting %v", in.Address, acc.Balance(), in.Amount)
+		}
+		acc, err := acc.SubtractFromBalance(in.Amount)
+		if err != nil {
+			return err
+		}
+		logger.TraceMsg("Incrementing sequence number for SendTx (adjustByInputs)",
+			"tag", "sequence",
+			"account", acc.Address(),
+			"old_sequence", acc.Sequence(),
+			"new_sequence", acc.Sequence()+1)
+		acc.IncSequence()
+	}
+	return nil
+}
+
+func adjustByOutputs(accs map[crypto.Address]acm.MutableAccount, outs []*payload.TxOutput) error {
+	for _, out := range outs {
+		acc := accs[out.Address]
+		if acc == nil {
+			return fmt.Errorf("adjustByOutputs() expects account in accounts, but account %s not found",
+				out.Address)
+		}
+		_, err := acc.AddToBalance(out.Amount)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+//---------------------------------------------------------------
+
+// Get permission on an account or fall back to global value
+func HasPermission(accountGetter state.AccountGetter, acc acm.Account, perm ptypes.PermFlag, logger *logging.Logger) bool {
+	if perm > ptypes.AllPermFlags {
+		logger.InfoMsg(
+			fmt.Sprintf("HasPermission called on invalid permission 0b%b (invalid) > 0b%b (maximum) ",
+				perm, ptypes.AllPermFlags),
+			"invalid_permission", perm,
+			"maximum_permission", ptypes.AllPermFlags)
+		return false
+	}
+
+	v, err := acc.Permissions().Base.Compose(state.GlobalAccountPermissions(accountGetter).Base).Get(perm)
+	if err != nil {
+		logger.TraceMsg("Error obtaining permission value (will default to false/deny)",
+			"perm_flag", perm.String(),
+			structure.ErrorKey, err)
+	}
+
+	if v {
+		logger.TraceMsg("Account has permission",
+			"account_address", acc.Address,
+			"perm_flag", perm.String())
+	} else {
+		logger.TraceMsg("Account does not have permission",
+			"account_address", acc.Address,
+			"perm_flag", perm.String())
+	}
+	return v
+}
+
+// TODO: for debug log the failed accounts
+func hasSendPermission(accountGetter state.AccountGetter, accs map[crypto.Address]acm.MutableAccount,
+	logger *logging.Logger) bool {
+	for _, acc := range accs {
+		if !HasPermission(accountGetter, acc, ptypes.Send, logger) {
+			return false
+		}
+	}
+	return true
+}
+
+func hasNamePermission(accountGetter state.AccountGetter, acc acm.Account,
+	logger *logging.Logger) bool {
+	return HasPermission(accountGetter, acc, ptypes.Name, logger)
+}
+
+func hasCallPermission(accountGetter state.AccountGetter, acc acm.Account,
+	logger *logging.Logger) bool {
+	return HasPermission(accountGetter, acc, ptypes.Call, logger)
+}
+
+func hasCreateContractPermission(accountGetter state.AccountGetter, acc acm.Account,
+	logger *logging.Logger) bool {
+	return HasPermission(accountGetter, acc, ptypes.CreateContract, logger)
+}
+
+func hasCreateAccountPermission(accountGetter state.AccountGetter, accs map[crypto.Address]acm.MutableAccount,
+	logger *logging.Logger) bool {
+	for _, acc := range accs {
+		if !HasPermission(accountGetter, acc, ptypes.CreateAccount, logger) {
+			return false
+		}
+	}
+	return true
+}
+
+func hasBondPermission(accountGetter state.AccountGetter, acc acm.Account,
+	logger *logging.Logger) bool {
+	return HasPermission(accountGetter, acc, ptypes.Bond, logger)
+}
+
+func hasBondOrSendPermission(accountGetter state.AccountGetter, accs map[crypto.Address]acm.Account,
+	logger *logging.Logger) bool {
+	for _, acc := range accs {
+		if !HasPermission(accountGetter, acc, ptypes.Bond, logger) {
+			if !HasPermission(accountGetter, acc, ptypes.Send, logger) {
+				return false
+			}
+		}
+	}
+	return true
+}
diff --git a/execution/namereg.go b/execution/namereg.go
deleted file mode 100644
index 0c57b351c540e019ae6ab2f68d7e61bb8c5f650c..0000000000000000000000000000000000000000
--- a/execution/namereg.go
+++ /dev/null
@@ -1,51 +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 execution
-
-import "github.com/hyperledger/burrow/crypto"
-
-// NameReg provides a global key value store based on Name, Data pairs that are subject to expiry and ownership by an
-// account.
-type NameRegEntry struct {
-	// registered name for the entry
-	Name string
-	// address that created the entry
-	Owner crypto.Address
-	// data to store under this name
-	Data string
-	// block at which this entry expires
-	Expires uint64
-}
-
-type NameRegGetter interface {
-	GetNameRegEntry(name string) (*NameRegEntry, error)
-}
-
-type NameRegUpdater interface {
-	// Updates the name entry creating it if it does not exist
-	UpdateNameRegEntry(entry *NameRegEntry) error
-	// Remove the name entry
-	RemoveNameRegEntry(name string) error
-}
-
-type NameRegWriter interface {
-	NameRegGetter
-	NameRegUpdater
-}
-
-type NameRegIterable interface {
-	NameRegGetter
-	IterateNameRegEntries(consumer func(*NameRegEntry) (stop bool)) (stopped bool, err error)
-}
diff --git a/execution/namereg_cache.go b/execution/names/cache.go
similarity index 65%
rename from execution/namereg_cache.go
rename to execution/names/cache.go
index 5cb0c63aacd2b8d1851f3901fb93dae044cd7ae2..074ff290eeba3cc401baf3a4d47a51dcd4fa02f0 100644
--- a/execution/namereg_cache.go
+++ b/execution/names/cache.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package execution
+package names
 
 import (
 	"fmt"
@@ -20,33 +20,33 @@ import (
 	"sync"
 )
 
-// The NameRegCache helps prevent unnecessary IAVLTree updates and garbage generation.
-type NameRegCache struct {
+// The Cache helps prevent unnecessary IAVLTree updates and garbage generation.
+type Cache struct {
 	sync.RWMutex
-	backend NameRegGetter
+	backend Getter
 	names   map[string]*nameInfo
 }
 
 type nameInfo struct {
 	sync.RWMutex
-	entry   *NameRegEntry
+	entry   *Entry
 	removed bool
 	updated bool
 }
 
-var _ NameRegWriter = &NameRegCache{}
+var _ Writer = &Cache{}
 
-// Returns a NameRegCache that wraps an underlying NameRegCacheGetter to use on a cache miss, can write to an
-// output NameRegWriter via Sync.
+// Returns a Cache that wraps an underlying NameRegCacheGetter to use on a cache miss, can write to an
+// output Writer via Sync.
 // Not goroutine safe, use syncStateCache if you need concurrent access
-func NewNameRegCache(backend NameRegGetter) *NameRegCache {
-	return &NameRegCache{
+func NewCache(backend Getter) *Cache {
+	return &Cache{
 		backend: backend,
 		names:   make(map[string]*nameInfo),
 	}
 }
 
-func (cache *NameRegCache) GetNameRegEntry(name string) (*NameRegEntry, error) {
+func (cache *Cache) GetNameEntry(name string) (*Entry, error) {
 	nameInfo, err := cache.get(name)
 	if err != nil {
 		return nil, err
@@ -59,7 +59,7 @@ func (cache *NameRegCache) GetNameRegEntry(name string) (*NameRegEntry, error) {
 	return nameInfo.entry, nil
 }
 
-func (cache *NameRegCache) UpdateNameRegEntry(entry *NameRegEntry) error {
+func (cache *Cache) UpdateNameEntry(entry *Entry) error {
 	nameInfo, err := cache.get(entry.Name)
 	if err != nil {
 		return err
@@ -67,7 +67,7 @@ func (cache *NameRegCache) UpdateNameRegEntry(entry *NameRegEntry) error {
 	nameInfo.Lock()
 	defer nameInfo.Unlock()
 	if nameInfo.removed {
-		return fmt.Errorf("UpdateNameRegEntry on a removed name: %s", nameInfo.entry.Name)
+		return fmt.Errorf("UpdateNameEntry on a removed name: %s", nameInfo.entry.Name)
 	}
 
 	nameInfo.entry = entry
@@ -75,7 +75,7 @@ func (cache *NameRegCache) UpdateNameRegEntry(entry *NameRegEntry) error {
 	return nil
 }
 
-func (cache *NameRegCache) RemoveNameRegEntry(name string) error {
+func (cache *Cache) RemoveNameEntry(name string) error {
 	nameInfo, err := cache.get(name)
 	if err != nil {
 		return err
@@ -83,15 +83,15 @@ func (cache *NameRegCache) RemoveNameRegEntry(name string) error {
 	nameInfo.Lock()
 	defer nameInfo.Unlock()
 	if nameInfo.removed {
-		return fmt.Errorf("RemoveNameRegEntry on removed name: %s", name)
+		return fmt.Errorf("RemoveNameEntry on removed name: %s", name)
 	}
 	nameInfo.removed = true
 	return nil
 }
 
-// Writes whatever is in the cache to the output NameRegWriter state. Does not flush the cache, to do that call Reset()
+// Writes whatever is in the cache to the output Writer state. Does not flush the cache, to do that call Reset()
 // after Sync or use Flusth if your wish to use the output state as your next backend
-func (cache *NameRegCache) Sync(state NameRegWriter) error {
+func (cache *Cache) Sync(state Writer) error {
 	cache.Lock()
 	defer cache.Unlock()
 	// Determine order for names
@@ -107,13 +107,13 @@ func (cache *NameRegCache) Sync(state NameRegWriter) error {
 		nameInfo := cache.names[name]
 		nameInfo.RLock()
 		if nameInfo.removed {
-			err := state.RemoveNameRegEntry(name)
+			err := state.RemoveNameEntry(name)
 			if err != nil {
 				nameInfo.RUnlock()
 				return err
 			}
 		} else if nameInfo.updated {
-			err := state.UpdateNameRegEntry(nameInfo.entry)
+			err := state.UpdateNameEntry(nameInfo.entry)
 			if err != nil {
 				nameInfo.RUnlock()
 				return err
@@ -125,15 +125,15 @@ func (cache *NameRegCache) Sync(state NameRegWriter) error {
 }
 
 // Resets the cache to empty initialising the backing map to the same size as the previous iteration.
-func (cache *NameRegCache) Reset(backend NameRegGetter) {
+func (cache *Cache) Reset(backend Getter) {
 	cache.Lock()
 	defer cache.Unlock()
 	cache.backend = backend
 	cache.names = make(map[string]*nameInfo)
 }
 
-// Syncs the NameRegCache and Resets it to use NameRegWriter as the backend NameRegGetter
-func (cache *NameRegCache) Flush(state NameRegWriter) error {
+// Syncs the Cache and Resets it to use Writer as the backend Getter
+func (cache *Cache) Flush(state Writer) error {
 	err := cache.Sync(state)
 	if err != nil {
 		return err
@@ -142,12 +142,12 @@ func (cache *NameRegCache) Flush(state NameRegWriter) error {
 	return nil
 }
 
-func (cache *NameRegCache) Backend() NameRegGetter {
+func (cache *Cache) Backend() Getter {
 	return cache.backend
 }
 
 // Get the cache accountInfo item creating it if necessary
-func (cache *NameRegCache) get(name string) (*nameInfo, error) {
+func (cache *Cache) get(name string) (*nameInfo, error) {
 	cache.RLock()
 	nmeInfo := cache.names[name]
 	cache.RUnlock()
@@ -156,7 +156,7 @@ func (cache *NameRegCache) get(name string) (*nameInfo, error) {
 		defer cache.Unlock()
 		nmeInfo = cache.names[name]
 		if nmeInfo == nil {
-			entry, err := cache.backend.GetNameRegEntry(name)
+			entry, err := cache.backend.GetNameEntry(name)
 			if err != nil {
 				return nil, err
 			}
diff --git a/execution/namereg_cache_test.go b/execution/names/cache_test.go
similarity index 98%
rename from execution/namereg_cache_test.go
rename to execution/names/cache_test.go
index 7671133b8d934c25bb9a8c531faeadd8a84d729a..7b52912c9556a514564a4d588ba94c802f74c9f6 100644
--- a/execution/namereg_cache_test.go
+++ b/execution/names/cache_test.go
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package execution
+package names
 
 import (
 	"testing"
diff --git a/execution/names/names.go b/execution/names/names.go
index cfa656d696c3f920b8759a71746a17a6b2211ce6..586fb7b3ee77f23131a5aeb165bed566ff033762 100644
--- a/execution/names/names.go
+++ b/execution/names/names.go
@@ -14,6 +14,8 @@
 
 package names
 
+import "github.com/hyperledger/burrow/crypto"
+
 var (
 	MinNameRegistrationPeriod uint64 = 5
 
@@ -29,6 +31,40 @@ var (
 	MaxDataLength = 1 << 16
 )
 
+// NameReg provides a global key value store based on Name, Data pairs that are subject to expiry and ownership by an
+// account.
+type Entry struct {
+	// registered name for the entry
+	Name string
+	// address that created the entry
+	Owner crypto.Address
+	// data to store under this name
+	Data string
+	// block at which this entry expires
+	Expires uint64
+}
+
+type Getter interface {
+	GetNameEntry(name string) (*Entry, error)
+}
+
+type Updater interface {
+	// Updates the name entry creating it if it does not exist
+	UpdateNameEntry(entry *Entry) error
+	// Remove the name entry
+	RemoveNameEntry(name string) error
+}
+
+type Writer interface {
+	Getter
+	Updater
+}
+
+type Iterable interface {
+	Getter
+	IterateNameEntries(consumer func(*Entry) (stop bool)) (stopped bool, err error)
+}
+
 // base cost is "effective" number of bytes
 func NameBaseCost(name, data string) uint64 {
 	return uint64(len(data) + 32)
diff --git a/execution/state.go b/execution/state.go
index 7ccc79196f5d61145ff22a9286e351ec05a9963b..469b10828a267aa2bfd173da7a665c7aff233f55 100644
--- a/execution/state.go
+++ b/execution/state.go
@@ -28,7 +28,8 @@ import (
 	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/logging"
-	ptypes "github.com/hyperledger/burrow/permission"
+	"github.com/hyperledger/burrow/permission"
+	ptypes "github.com/hyperledger/burrow/permission/types"
 	"github.com/tendermint/go-wire"
 	"github.com/tendermint/iavl"
 	dbm "github.com/tendermint/tmlibs/db"
@@ -106,7 +107,7 @@ func MakeGenesisState(db dbm.DB, genesisDoc *genesis.GenesisDoc) (*State, error)
 
 	// global permissions are saved as the 0 address
 	// so they are included in the accounts tree
-	globalPerms := ptypes.DefaultAccountPermissions
+	globalPerms := permission.DefaultAccountPermissions
 	globalPerms = genesisDoc.GlobalPermissions
 	// XXX: make sure the set bits are all true
 	// Without it the HasPermission() functions will fail
@@ -270,9 +271,9 @@ func (s *State) IterateStorage(address crypto.Address,
 //-------------------------------------
 // State.nameReg
 
-var _ NameRegIterable = &State{}
+var _ names.Iterable = &State{}
 
-func (s *State) GetNameRegEntry(name string) (*NameRegEntry, error) {
+func (s *State) GetNameEntry(name string) (*names.Entry, error) {
 	_, valueBytes := s.tree.Get(prefixedKey(nameRegPrefix, []byte(name)))
 	if valueBytes == nil {
 		return nil, nil
@@ -281,13 +282,13 @@ func (s *State) GetNameRegEntry(name string) (*NameRegEntry, error) {
 	return DecodeNameRegEntry(valueBytes), nil
 }
 
-func (s *State) IterateNameRegEntries(consumer func(*NameRegEntry) (stop bool)) (stopped bool, err error) {
+func (s *State) IterateNameEntries(consumer func(*names.Entry) (stop bool)) (stopped bool, err error) {
 	return s.tree.IterateRange(nameRegStart, nameRegEnd, true, func(key []byte, value []byte) (stop bool) {
 		return consumer(DecodeNameRegEntry(value))
 	}), nil
 }
 
-func (s *State) UpdateNameRegEntry(entry *NameRegEntry) error {
+func (s *State) UpdateNameEntry(entry *names.Entry) error {
 	w := new(bytes.Buffer)
 	var n int
 	var err error
@@ -299,7 +300,7 @@ func (s *State) UpdateNameRegEntry(entry *NameRegEntry) error {
 	return nil
 }
 
-func (s *State) RemoveNameRegEntry(name string) error {
+func (s *State) RemoveNameEntry(name string) error {
 	s.tree.Remove(prefixedKey(nameRegPrefix, []byte(name)))
 	return nil
 }
@@ -314,19 +315,19 @@ func (s *State) Copy(db dbm.DB) *State {
 	return state
 }
 
-func DecodeNameRegEntry(entryBytes []byte) *NameRegEntry {
+func DecodeNameRegEntry(entryBytes []byte) *names.Entry {
 	var n int
 	var err error
 	value := NameRegDecode(bytes.NewBuffer(entryBytes), &n, &err)
-	return value.(*NameRegEntry)
+	return value.(*names.Entry)
 }
 
 func NameRegEncode(o interface{}, w io.Writer, n *int, err *error) {
-	wire.WriteBinary(o.(*NameRegEntry), w, n, err)
+	wire.WriteBinary(o.(*names.Entry), w, n, err)
 }
 
 func NameRegDecode(r io.Reader, n *int, err *error) interface{} {
-	return wire.ReadBinary(&NameRegEntry{}, r, names.MaxDataLength, n, err)
+	return wire.ReadBinary(&names.Entry{}, r, names.MaxDataLength, n, err)
 }
 
 func prefixedKey(prefix string, suffices ...[]byte) []byte {
diff --git a/execution/state_test.go b/execution/state_test.go
index 6ad9c32192ec5efc1cec705138a5ef83f2cb400d..e72076b1359f6d07294c123a2a36b6637fd32278 100644
--- a/execution/state_test.go
+++ b/execution/state_test.go
@@ -18,7 +18,7 @@ import (
 	"testing"
 
 	acm "github.com/hyperledger/burrow/account"
-	"github.com/hyperledger/burrow/permission"
+	permission "github.com/hyperledger/burrow/permission/types"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/tendermint/tmlibs/db"
diff --git a/execution/transactor.go b/execution/transactor.go
index bc0c9b9c69bc05bef889d5066da099d8002128f7..042eb11b20f89b2f34595e867a5b316d346e69d0 100644
--- a/execution/transactor.go
+++ b/execution/transactor.go
@@ -29,9 +29,11 @@ import (
 	"github.com/hyperledger/burrow/consensus/tendermint/codes"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/event"
+	"github.com/hyperledger/burrow/execution/errors"
 	exe_events "github.com/hyperledger/burrow/execution/events"
 	"github.com/hyperledger/burrow/execution/evm"
 	evm_events "github.com/hyperledger/burrow/execution/evm/events"
+	"github.com/hyperledger/burrow/execution/executors"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
 	"github.com/hyperledger/burrow/txs"
@@ -71,7 +73,7 @@ func NewTransactor(tip *blockchain.Tip, eventEmitter event.Emitter,
 func (trans *Transactor) Call(reader state.Reader, fromAddress, toAddress crypto.Address,
 	data []byte) (call *Call, err error) {
 
-	if evm.RegisteredNativeContract(toAddress.Word256()) {
+	if evm.IsRegisteredNativeContract(toAddress.Word256()) {
 		return nil, fmt.Errorf("attempt to call native contract at address "+
 			"%X, but native contracts can not be called directly. Use a deployed "+
 			"contract that calls the native function instead", toAddress)
@@ -235,8 +237,8 @@ func (trans *Transactor) TransactAndHold(sequentialSigningAccount *SequentialSig
 	case <-timer.C:
 		return nil, fmt.Errorf("transaction timed out TxHash: %X", expectedReceipt.TxHash)
 	case eventDataCall := <-ch:
-		if eventDataCall.Exception != "" {
-			return nil, fmt.Errorf("error when transacting: " + eventDataCall.Exception)
+		if eventDataCall.Exception != nil && eventDataCall.Exception.Code != errors.ErrorCodeExecutionReverted {
+			return nil, fmt.Errorf("error when transacting: %v", eventDataCall.Exception)
 		} else {
 			return eventDataCall, nil
 		}
@@ -392,6 +394,6 @@ func vmParams(tip *blockchain.Tip) evm.Params {
 		BlockHeight: tip.LastBlockHeight(),
 		BlockHash:   binary.LeftPadWord256(tip.LastBlockHash()),
 		BlockTime:   tip.LastBlockTime().Unix(),
-		GasLimit:    GasLimit,
+		GasLimit:    executors.GasLimit,
 	}
 }
diff --git a/genesis/spec/genesis_spec_test.go b/genesis/spec/genesis_spec_test.go
index ca91146fb71be6356ffd55abd31cec4590fc0b0b..6ce214dc434fda5299990847385feb9cb110a513 100644
--- a/genesis/spec/genesis_spec_test.go
+++ b/genesis/spec/genesis_spec_test.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/keys/mock"
-	"github.com/hyperledger/burrow/permission"
+	permission "github.com/hyperledger/burrow/permission/types"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
diff --git a/genesis/spec/presets.go b/genesis/spec/presets.go
index 312ec7a79a78888f687210a56e218c32ad16a4e4..9454520c9f284666349d8b2334c59879e1c169d0 100644
--- a/genesis/spec/presets.go
+++ b/genesis/spec/presets.go
@@ -3,7 +3,7 @@ package spec
 import (
 	"sort"
 
-	"github.com/hyperledger/burrow/permission"
+	permission "github.com/hyperledger/burrow/permission/types"
 )
 
 // Files here can be used as starting points for building various 'chain types' but are otherwise
diff --git a/genesis/spec/presets_test.go b/genesis/spec/presets_test.go
index 8e578640e8790aab8923006e7ec8d864a3cec5b5..dde6f296c7103fa5ca33dcaf0416aa797c440265 100644
--- a/genesis/spec/presets_test.go
+++ b/genesis/spec/presets_test.go
@@ -4,7 +4,7 @@ import (
 	"testing"
 
 	"github.com/hyperledger/burrow/keys/mock"
-	"github.com/hyperledger/burrow/permission"
+	permission "github.com/hyperledger/burrow/permission/types"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
diff --git a/permission/permissions.go b/permission/permissions.go
index 5bfcf61c9205c1a6ae222e8110298759c8cd8a9a..48b5bd9dd3bd2e11353993c8ce96964017a8a75a 100644
--- a/permission/permissions.go
+++ b/permission/permissions.go
@@ -15,82 +15,9 @@
 package permission
 
 import (
-	"fmt"
-	"strings"
-
 	"github.com/hyperledger/burrow/permission/types"
 )
 
-//------------------------------------------------------------------------------------------------
-
-// Base permission references are like unix (the index is already bit shifted)
-const (
-	// Chain permissions.
-	// These permissions grant the ability for accounts to perform certain transition within the execution package
-	// Root is a reserved permission currently unused that may be used in the future to grant super-user privileges
-	// for instance to a governance contract
-	Root types.PermFlag = 1 << iota // 1
-	// Send permits an account to issue a SendTx to transfer value from one account to another. Note that value can
-	// still be transferred with a CallTx by specifying an Amount in the InputTx. Funding an account is the basic
-	// prerequisite for an account to act in the system so is often used as a surrogate for 'account creation' when
-	// sending to a unknown account - in order for this to be permitted the input account needs the CreateAccount
-	// permission in addition.
-	Send // 2
-	// Call permits and account to issue a CallTx, which can be used to call (run) the code of an existing
-	// account/contract (these are synonymous in Burrow/EVM). A CallTx can be used to create an account if it points to
-	// a nil address - in order for an account to be permitted to do this the input (calling) account needs the
-	// CreateContract permission in addition.
-	Call // 4
-	// CreateContract permits the input account of a CallTx to create a new contract/account when CallTx.Address is nil
-	// and permits an executing contract in the EVM to create a new contract programmatically.
-	CreateContract // 8
-	// CreateAccount permits an input account of a SendTx to add value to non-existing (unfunded) accounts
-	CreateAccount // 16
-	// Bond is a reserved permission for making changes to the validator set - currently unused
-	Bond // 32
-	// Name permits manipulation of the name registry by allowing an account to issue a NameTx
-	Name // 64
-
-	// Moderator permissions.
-	// These permissions concern the alteration of the chain permissions listed above. Each permission relates to a
-	// particular canonical permission mutation or query function. When an account is granted a moderation permission
-	// it is permitted to call that function. See snative.go for a marked-up description of what each function does.
-	HasBase
-	SetBase
-	UnsetBase
-	SetGlobal
-	HasRole
-	AddRole
-	RemoveRole
-
-	NumPermissions uint = 14 // NOTE Adjust this too. We can support upto 64
-
-	TopPermFlag      types.PermFlag = 1 << (NumPermissions - 1)
-	AllPermFlags     types.PermFlag = TopPermFlag | (TopPermFlag - 1)
-	DefaultPermFlags types.PermFlag = Send | Call | CreateContract | CreateAccount | Bond | Name | HasBase | HasRole
-
-	// Chain permissions strings
-	RootString           string = "root"
-	SendString                  = "send"
-	CallString                  = "call"
-	CreateContractString        = "createContract"
-	CreateAccountString         = "createAccount"
-	BondString                  = "bond"
-	NameString                  = "name"
-
-	// Moderator permissions strings
-	HasBaseString    = "hasBase"
-	SetBaseString    = "setBase"
-	UnsetBaseString  = "unsetBase"
-	SetGlobalString  = "setGlobal"
-	HasRoleString    = "hasRole"
-	AddRoleString    = "addRole"
-	RemoveRoleString = "removeRole"
-	UnknownString    = "#-UNKNOWN-#"
-
-	AllString = "all"
-)
-
 var (
 	ZeroBasePermissions    = types.BasePermissions{0, 0}
 	ZeroAccountPermissions = types.AccountPermissions{
@@ -98,99 +25,16 @@ var (
 	}
 	DefaultAccountPermissions = types.AccountPermissions{
 		Base: types.BasePermissions{
-			Perms:  DefaultPermFlags,
-			SetBit: AllPermFlags,
+			Perms:  types.DefaultPermFlags,
+			SetBit: types.AllPermFlags,
 		},
 		Roles: []string{},
 	}
 	AllAccountPermissions = types.AccountPermissions{
 		Base: types.BasePermissions{
-			Perms:  AllPermFlags,
-			SetBit: AllPermFlags,
+			Perms:  types.AllPermFlags,
+			SetBit: types.AllPermFlags,
 		},
 		Roles: []string{},
 	}
 )
-
-//---------------------------------------------------------------------------------------------
-
-//--------------------------------------------------------------------------------
-// string utilities
-
-// Returns the string name of a single bit non-composite PermFlag, or otherwise UnknownString
-// See BasePermissionsToStringList to generate a string representation of a composite PermFlag
-func PermFlagToString(pf types.PermFlag) string {
-	switch pf {
-	case AllPermFlags:
-		return AllString
-	case Root:
-		return RootString
-	case Send:
-		return SendString
-	case Call:
-		return CallString
-	case CreateContract:
-		return CreateContractString
-	case CreateAccount:
-		return CreateAccountString
-	case Bond:
-		return BondString
-	case Name:
-		return NameString
-	case HasBase:
-		return HasBaseString
-	case SetBase:
-		return SetBaseString
-	case UnsetBase:
-		return UnsetBaseString
-	case SetGlobal:
-		return SetGlobalString
-	case HasRole:
-		return HasRoleString
-	case AddRole:
-		return AddRoleString
-	case RemoveRole:
-		return RemoveRoleString
-	default:
-		return UnknownString
-	}
-}
-
-// PermStringToFlag maps camel- and snake case strings to the
-// the corresponding permission flag.
-func PermStringToFlag(perm string) (types.PermFlag, error) {
-	switch strings.ToLower(perm) {
-	case AllString:
-		return AllPermFlags, nil
-	case RootString:
-		return Root, nil
-	case SendString:
-		return Send, nil
-	case CallString:
-		return Call, nil
-	case CreateContractString, "createcontract", "create_contract":
-		return CreateContract, nil
-	case CreateAccountString, "createaccount", "create_account":
-		return CreateAccount, nil
-	case BondString:
-		return Bond, nil
-	case NameString:
-		return Name, nil
-	case HasBaseString, "hasbase", "has_base":
-		return HasBase, nil
-	case SetBaseString, "setbase", "set_base":
-		return SetBase, nil
-	case UnsetBaseString, "unsetbase", "unset_base":
-		return UnsetBase, nil
-	case SetGlobalString, "setglobal", "set_global":
-		return SetGlobal, nil
-	case HasRoleString, "hasrole", "has_role":
-		return HasRole, nil
-	case AddRoleString, "addrole", "add_role":
-		return AddRole, nil
-	case RemoveRoleString, "removerole", "rmrole", "rm_role":
-		return RemoveRole, nil
-	default:
-		return 0, fmt.Errorf("unknown permission %s", perm)
-	}
-}
diff --git a/permission/snatives/snatives.go b/permission/snatives/snatives.go
index 40e560ea9087903b220e5eaec49a82a3721ce352..5b47b8af5e894c0b9f5cdf6e26947db2ad398c35 100644
--- a/permission/snatives/snatives.go
+++ b/permission/snatives/snatives.go
@@ -21,6 +21,7 @@ import (
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/permission"
 	"github.com/hyperledger/burrow/permission/types"
+	ptypes "github.com/hyperledger/burrow/permission/types"
 )
 
 //---------------------------------------------------------------------------------------------------
@@ -36,12 +37,12 @@ type PermArgs struct {
 
 func (pa PermArgs) String() string {
 	body := make([]string, 0, 5)
-	body = append(body, fmt.Sprintf("PermFlag: %s", permission.String(pa.PermFlag)))
+	body = append(body, fmt.Sprintf("PermFlag: %v", permission.String(pa.PermFlag)))
 	if pa.Address != nil {
 		body = append(body, fmt.Sprintf("Address: %s", *pa.Address))
 	}
 	if pa.Permission != nil {
-		body = append(body, fmt.Sprintf("Permission: %s", permission.String(*pa.Permission)))
+		body = append(body, fmt.Sprintf("Permission: %v", permission.String(*pa.Permission)))
 	}
 	if pa.Role != nil {
 		body = append(body, fmt.Sprintf("Role: %s", *pa.Role))
@@ -55,10 +56,10 @@ func (pa PermArgs) String() string {
 func (pa PermArgs) EnsureValid() error {
 	pf := pa.PermFlag
 	// Address
-	if pa.Address == nil && pf != permission.SetGlobal {
+	if pa.Address == nil && pf != ptypes.SetGlobal {
 		return fmt.Errorf("PermArgs for PermFlag %v requires Address to be provided but was nil", pf)
 	}
-	if pf == permission.HasRole || pf == permission.AddRole || pf == permission.RemoveRole {
+	if pf == ptypes.HasRole || pf == ptypes.AddRole || pf == ptypes.RemoveRole {
 		// Role
 		if pa.Role == nil {
 			return fmt.Errorf("PermArgs for PermFlag %v requires Role to be provided but was nil", pf)
@@ -67,7 +68,7 @@ func (pa PermArgs) EnsureValid() error {
 	} else if pa.Permission == nil {
 		return fmt.Errorf("PermArgs for PermFlag %v requires Permission to be provided but was nil", pf)
 		// Value
-	} else if (pf == permission.SetBase || pf == permission.SetGlobal) && pa.Value == nil {
+	} else if (pf == ptypes.SetBase || pf == ptypes.SetGlobal) && pa.Value == nil {
 		return fmt.Errorf("PermArgs for PermFlag %v requires Value to be provided but was nil", pf)
 	}
 	return nil
@@ -75,7 +76,7 @@ func (pa PermArgs) EnsureValid() error {
 
 func HasBaseArgs(address crypto.Address, permFlag types.PermFlag) PermArgs {
 	return PermArgs{
-		PermFlag:   permission.HasBase,
+		PermFlag:   ptypes.HasBase,
 		Address:    &address,
 		Permission: &permFlag,
 	}
@@ -83,7 +84,7 @@ func HasBaseArgs(address crypto.Address, permFlag types.PermFlag) PermArgs {
 
 func SetBaseArgs(address crypto.Address, permFlag types.PermFlag, value bool) PermArgs {
 	return PermArgs{
-		PermFlag:   permission.SetBase,
+		PermFlag:   ptypes.SetBase,
 		Address:    &address,
 		Permission: &permFlag,
 		Value:      &value,
@@ -92,7 +93,7 @@ func SetBaseArgs(address crypto.Address, permFlag types.PermFlag, value bool) Pe
 
 func UnsetBaseArgs(address crypto.Address, permFlag types.PermFlag) PermArgs {
 	return PermArgs{
-		PermFlag:   permission.UnsetBase,
+		PermFlag:   ptypes.UnsetBase,
 		Address:    &address,
 		Permission: &permFlag,
 	}
@@ -100,7 +101,7 @@ func UnsetBaseArgs(address crypto.Address, permFlag types.PermFlag) PermArgs {
 
 func SetGlobalArgs(permFlag types.PermFlag, value bool) PermArgs {
 	return PermArgs{
-		PermFlag:   permission.SetGlobal,
+		PermFlag:   ptypes.SetGlobal,
 		Permission: &permFlag,
 		Value:      &value,
 	}
@@ -108,7 +109,7 @@ func SetGlobalArgs(permFlag types.PermFlag, value bool) PermArgs {
 
 func HasRoleArgs(address crypto.Address, role string) PermArgs {
 	return PermArgs{
-		PermFlag: permission.HasRole,
+		PermFlag: ptypes.HasRole,
 		Address:  &address,
 		Role:     &role,
 	}
@@ -116,7 +117,7 @@ func HasRoleArgs(address crypto.Address, role string) PermArgs {
 
 func AddRoleArgs(address crypto.Address, role string) PermArgs {
 	return PermArgs{
-		PermFlag: permission.AddRole,
+		PermFlag: ptypes.AddRole,
 		Address:  &address,
 		Role:     &role,
 	}
@@ -124,7 +125,7 @@ func AddRoleArgs(address crypto.Address, role string) PermArgs {
 
 func RemoveRoleArgs(address crypto.Address, role string) PermArgs {
 	return PermArgs{
-		PermFlag: permission.RemoveRole,
+		PermFlag: ptypes.RemoveRole,
 		Address:  &address,
 		Role:     &role,
 	}
diff --git a/permission/snatives/snatives_test.go b/permission/snatives/snatives_test.go
index 76545151df366826e1f24deb5a6f100af8e48b2d..9441ed15eaccc20c7391e3ce4452ec01933ecb4a 100644
--- a/permission/snatives/snatives_test.go
+++ b/permission/snatives/snatives_test.go
@@ -3,7 +3,7 @@ package snatives
 import (
 	"testing"
 
-	"github.com/hyperledger/burrow/permission"
+	permission "github.com/hyperledger/burrow/permission/types"
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/permission/types/base_permissions.go b/permission/types/base_permissions.go
index fe0dd5e32abe7f1db5dd33cb1906a784e3f8129a..401f46d1225a4589311cfa8472ce52310bbd576c 100644
--- a/permission/types/base_permissions.go
+++ b/permission/types/base_permissions.go
@@ -2,24 +2,6 @@ package types
 
 import "fmt"
 
-// A particular permission
-type PermFlag uint64
-
-// permission number out of bounds
-type ErrInvalidPermission PermFlag
-
-func (e ErrInvalidPermission) Error() string {
-	return fmt.Sprintf("invalid permission %d", e)
-}
-
-// set=false. This error should be caught and the global
-// value fetched for the permission by the caller
-type ErrValueNotSet PermFlag
-
-func (e ErrValueNotSet) Error() string {
-	return fmt.Sprintf("the value for permission %d is not set", e)
-}
-
 // Base chain permissions struct
 type BasePermissions struct {
 	// bit array with "has"/"doesn't have" for each permission
diff --git a/permission/errors.go b/permission/types/errors.go
similarity index 59%
rename from permission/errors.go
rename to permission/types/errors.go
index 795b621cac31d5a52159c6a16bafa24ce4106e68..0b022277e9352561b2fe83a655f750c6a146d21f 100644
--- a/permission/errors.go
+++ b/permission/types/errors.go
@@ -12,7 +12,22 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package permission
+package types
 
-//------------------------------------------------------------------------------------------------
-// Some errors
+import (
+	"fmt"
+)
+
+type ErrInvalidPermission PermFlag
+
+func (e ErrInvalidPermission) Error() string {
+	return fmt.Sprintf("invalid permission %d", e)
+}
+
+// set=false. This error should be caught and the global
+// value fetched for the permission by the caller
+type ErrValueNotSet PermFlag
+
+func (e ErrValueNotSet) Error() string {
+	return fmt.Sprintf("the value for permission %d is not set", e)
+}
diff --git a/permission/types/perm_flag.go b/permission/types/perm_flag.go
new file mode 100644
index 0000000000000000000000000000000000000000..c749aa308b6f3e1b292b0e30cefc4a4030958b24
--- /dev/null
+++ b/permission/types/perm_flag.go
@@ -0,0 +1,155 @@
+package types
+
+import (
+	"fmt"
+	"strings"
+)
+
+// Base permission references are like unix (the index is already bit shifted)
+const (
+	// Chain permissions.
+	// These permissions grant the ability for accounts to perform certain transition within the execution package
+	// Root is a reserved permission currently unused that may be used in the future to grant super-user privileges
+	// for instance to a governance contract
+	Root PermFlag = 1 << iota // 1
+	// Send permits an account to issue a SendTx to transfer value from one account to another. Note that value can
+	// still be transferred with a CallTx by specifying an Amount in the InputTx. Funding an account is the basic
+	// prerequisite for an account to act in the system so is often used as a surrogate for 'account creation' when
+	// sending to a unknown account - in order for this to be permitted the input account needs the CreateAccount
+	// permission in addition.
+	Send // 2
+	// Call permits and account to issue a CallTx, which can be used to call (run) the code of an existing
+	// account/contract (these are synonymous in Burrow/EVM). A CallTx can be used to create an account if it points to
+	// a nil address - in order for an account to be permitted to do this the input (calling) account needs the
+	// CreateContract permission in addition.
+	Call // 4
+	// CreateContract permits the input account of a CallTx to create a new contract/account when CallTx.Address is nil
+	// and permits an executing contract in the EVM to create a new contract programmatically.
+	CreateContract // 8
+	// CreateAccount permits an input account of a SendTx to add value to non-existing (unfunded) accounts
+	CreateAccount // 16
+	// Bond is a reserved permission for making changes to the validator set - currently unused
+	Bond // 32
+	// Name permits manipulation of the name registry by allowing an account to issue a NameTx
+	Name // 64
+
+	// Moderator permissions.
+	// These permissions concern the alteration of the chain permissions listed above. Each permission relates to a
+	// particular canonical permission mutation or query function. When an account is granted a moderation permission
+	// it is permitted to call that function. See snative.go for a marked-up description of what each function does.
+	HasBase
+	SetBase
+	UnsetBase
+	SetGlobal
+	HasRole
+	AddRole
+	RemoveRole
+
+	NumPermissions uint = 14 // NOTE Adjust this too. We can support upto 64
+
+	TopPermFlag      PermFlag = 1 << (NumPermissions - 1)
+	AllPermFlags     PermFlag = TopPermFlag | (TopPermFlag - 1)
+	DefaultPermFlags PermFlag = Send | Call | CreateContract | CreateAccount | Bond | Name | HasBase | HasRole
+
+	// Chain permissions strings
+	RootString           string = "root"
+	SendString                  = "send"
+	CallString                  = "call"
+	CreateContractString        = "createContract"
+	CreateAccountString         = "createAccount"
+	BondString                  = "bond"
+	NameString                  = "name"
+
+	// Moderator permissions strings
+	HasBaseString    = "hasBase"
+	SetBaseString    = "setBase"
+	UnsetBaseString  = "unsetBase"
+	SetGlobalString  = "setGlobal"
+	HasRoleString    = "hasRole"
+	AddRoleString    = "addRole"
+	RemoveRoleString = "removeRole"
+	UnknownString    = "#-UNKNOWN-#"
+
+	AllString = "all"
+)
+
+// A particular permission
+type PermFlag uint64
+
+// Returns the string name of a single bit non-composite PermFlag, or otherwise UnknownString
+// See BasePermissionsToStringList to generate a string representation of a composite PermFlag
+func (pf PermFlag) String() string {
+	switch pf {
+	case AllPermFlags:
+		return AllString
+	case Root:
+		return RootString
+	case Send:
+		return SendString
+	case Call:
+		return CallString
+	case CreateContract:
+		return CreateContractString
+	case CreateAccount:
+		return CreateAccountString
+	case Bond:
+		return BondString
+	case Name:
+		return NameString
+	case HasBase:
+		return HasBaseString
+	case SetBase:
+		return SetBaseString
+	case UnsetBase:
+		return UnsetBaseString
+	case SetGlobal:
+		return SetGlobalString
+	case HasRole:
+		return HasRoleString
+	case AddRole:
+		return AddRoleString
+	case RemoveRole:
+		return RemoveRoleString
+	default:
+		return UnknownString
+	}
+}
+
+// PermStringToFlag maps camel- and snake case strings to the
+// the corresponding permission flag.
+func PermStringToFlag(perm string) (PermFlag, error) {
+	switch strings.ToLower(perm) {
+	case AllString:
+		return AllPermFlags, nil
+	case RootString:
+		return Root, nil
+	case SendString:
+		return Send, nil
+	case CallString:
+		return Call, nil
+	case CreateContractString, "createcontract", "create_contract":
+		return CreateContract, nil
+	case CreateAccountString, "createaccount", "create_account":
+		return CreateAccount, nil
+	case BondString:
+		return Bond, nil
+	case NameString:
+		return Name, nil
+	case HasBaseString, "hasbase", "has_base":
+		return HasBase, nil
+	case SetBaseString, "setbase", "set_base":
+		return SetBase, nil
+	case UnsetBaseString, "unsetbase", "unset_base":
+		return UnsetBase, nil
+	case SetGlobalString, "setglobal", "set_global":
+		return SetGlobal, nil
+	case HasRoleString, "hasrole", "has_role":
+		return HasRole, nil
+	case AddRoleString, "addrole", "add_role":
+		return AddRole, nil
+	case RemoveRoleString, "removerole", "rmrole", "rm_role":
+		return RemoveRole, nil
+	default:
+		return 0, fmt.Errorf("unknown permission %s", perm)
+	}
+}
diff --git a/permission/permissions_test.go b/permission/types/perm_flag_test.go
similarity index 91%
rename from permission/permissions_test.go
rename to permission/types/perm_flag_test.go
index 5d930a7c703809a04adbf4cfe2512249b1490481..2ec7a6edb257f51ff897cc7d29151df051706e3a 100644
--- a/permission/permissions_test.go
+++ b/permission/types/perm_flag_test.go
@@ -1,4 +1,4 @@
-package permission
+package types
 
 import (
 	"testing"
diff --git a/permission/util.go b/permission/util.go
index 656761cd83030127313ede68c528ffe8973b00cd..7470b94d90b27ee48b04cf40b67b215c8370f4c2 100644
--- a/permission/util.go
+++ b/permission/util.go
@@ -45,7 +45,7 @@ func convertPermissionsMapStringIntToBasePermissions(permissions map[string]bool
 	basePermissions := ZeroBasePermissions
 
 	for permissionName, value := range permissions {
-		permissionsFlag, err := PermStringToFlag(permissionName)
+		permissionsFlag, err := types.PermStringToFlag(permissionName)
 		if err != nil {
 			return basePermissions, err
 		}
@@ -74,7 +74,7 @@ func BasePermissionsFromStringList(permissions []string) (types.BasePermissions,
 func PermFlagFromStringList(permissions []string) (types.PermFlag, error) {
 	var permFlag types.PermFlag
 	for _, perm := range permissions {
-		flag, err := PermStringToFlag(perm)
+		flag, err := types.PermStringToFlag(perm)
 		if err != nil {
 			return permFlag, err
 		}
@@ -92,15 +92,15 @@ func BasePermissionsToStringList(basePermissions types.BasePermissions) ([]strin
 // Creates a list of individual permission flag strings from a possibly composite PermFlag
 // by projecting out each bit and adding its permission string if it is set
 func PermFlagToStringList(permFlag types.PermFlag) ([]string, error) {
-	permStrings := make([]string, 0, NumPermissions)
-	if permFlag > AllPermFlags {
+	permStrings := make([]string, 0, types.NumPermissions)
+	if permFlag > types.AllPermFlags {
 		return nil, fmt.Errorf("resultant permission 0b%b is invalid: has permission flag set above top flag 0b%b",
-			permFlag, TopPermFlag)
+			permFlag, types.TopPermFlag)
 	}
-	for i := uint(0); i < NumPermissions; i++ {
+	for i := uint(0); i < types.NumPermissions; i++ {
 		permFlag := permFlag & (1 << i)
 		if permFlag > 0 {
-			permStrings = append(permStrings, PermFlagToString(permFlag))
+			permStrings = append(permStrings, permFlag.String())
 		}
 	}
 	return permStrings, nil
@@ -110,7 +110,7 @@ func PermFlagToStringList(permFlag types.PermFlag) ([]string, error) {
 func BasePermissionsString(basePermissions types.BasePermissions) string {
 	permStrings, err := BasePermissionsToStringList(basePermissions)
 	if err != nil {
-		return UnknownString
+		return types.UnknownString
 	}
 	return strings.Join(permStrings, " | ")
 }
@@ -118,7 +118,7 @@ func BasePermissionsString(basePermissions types.BasePermissions) string {
 func String(permFlag types.PermFlag) string {
 	permStrings, err := PermFlagToStringList(permFlag)
 	if err != nil {
-		return UnknownString
+		return types.UnknownString
 	}
 	return strings.Join(permStrings, " | ")
 }
diff --git a/permission/util_test.go b/permission/util_test.go
index 4d1c806b1073c39c83bc7a6d1a18f85a1117dfb6..780c1651cb91900798536133288d0a8cdfeed134 100644
--- a/permission/util_test.go
+++ b/permission/util_test.go
@@ -9,15 +9,15 @@ import (
 )
 
 func TestBasePermissionsFromStringList(t *testing.T) {
-	basePerms, err := BasePermissionsFromStringList([]string{HasRoleString, CreateContractString, SendString})
+	basePerms, err := BasePermissionsFromStringList([]string{types.HasRoleString, types.CreateContractString, types.SendString})
 	require.NoError(t, err)
-	permFlag := HasRole | CreateContract | Send
+	permFlag := types.HasRole | types.CreateContract | types.Send
 	assert.Equal(t, permFlag, basePerms.Perms)
 	assert.Equal(t, permFlag, basePerms.SetBit)
 
-	basePerms, err = BasePermissionsFromStringList([]string{AllString})
+	basePerms, err = BasePermissionsFromStringList([]string{types.AllString})
 	require.NoError(t, err)
-	permFlag = AllPermFlags
+	permFlag = types.AllPermFlags
 	assert.Equal(t, permFlag, basePerms.Perms)
 	assert.Equal(t, permFlag, basePerms.SetBit)
 
@@ -26,21 +26,21 @@ func TestBasePermissionsFromStringList(t *testing.T) {
 }
 
 func TestBasePermissionsToStringList(t *testing.T) {
-	permStrings, err := BasePermissionsToStringList(allSetBasePermission(Root | HasRole | SetBase | Call))
+	permStrings, err := BasePermissionsToStringList(allSetBasePermission(types.Root | types.HasRole | types.SetBase | types.Call))
 	require.NoError(t, err)
 	assert.Equal(t, []string{"root", "call", "setBase", "hasRole"}, permStrings)
 
-	permStrings, err = BasePermissionsToStringList(allSetBasePermission(AllPermFlags))
+	permStrings, err = BasePermissionsToStringList(allSetBasePermission(types.AllPermFlags))
 	require.NoError(t, err)
 	assert.Equal(t, []string{"root", "send", "call", "createContract", "createAccount", "bond", "name", "hasBase",
 		"setBase", "unsetBase", "setGlobal", "hasRole", "addRole", "removeRole"}, permStrings)
 
-	permStrings, err = BasePermissionsToStringList(allSetBasePermission(AllPermFlags + 1))
+	permStrings, err = BasePermissionsToStringList(allSetBasePermission(types.AllPermFlags + 1))
 	assert.Error(t, err)
 }
 
 func TestBasePermissionsString(t *testing.T) {
-	permissionString := BasePermissionsString(allSetBasePermission(AllPermFlags &^ Root))
+	permissionString := BasePermissionsString(allSetBasePermission(types.AllPermFlags &^ types.Root))
 	assert.Equal(t, "send | call | createContract | createAccount | bond | name | hasBase | "+
 		"setBase | unsetBase | setGlobal | hasRole | addRole | removeRole", permissionString)
 }
diff --git a/rpc/filters/namereg.go b/rpc/filters/namereg.go
index 10634e7104a931abf563cd096bc25d2056f3e0a1..6d822fb177c21221a627d8cb4f8c90211de744a9 100644
--- a/rpc/filters/namereg.go
+++ b/rpc/filters/namereg.go
@@ -20,7 +20,7 @@ import (
 	"fmt"
 	"sync"
 
-	"github.com/hyperledger/burrow/execution"
+	"github.com/hyperledger/burrow/execution/names"
 )
 
 func NewNameRegFilterFactory() *FilterFactory {
@@ -82,7 +82,7 @@ func (nrnf *NameRegNameFilter) Configure(fd *FilterData) error {
 }
 
 func (nrnf *NameRegNameFilter) Match(v interface{}) bool {
-	nre, ok := v.(*execution.NameRegEntry)
+	nre, ok := v.(*names.Entry)
 	if !ok {
 		return false
 	}
@@ -121,7 +121,7 @@ func (nrof *NameRegOwnerFilter) Configure(fd *FilterData) error {
 }
 
 func (nrof *NameRegOwnerFilter) Match(v interface{}) bool {
-	nre, ok := v.(*execution.NameRegEntry)
+	nre, ok := v.(*names.Entry)
 	if !ok {
 		return false
 	}
@@ -157,7 +157,7 @@ func (nrdf *NameRegDataFilter) Configure(fd *FilterData) error {
 }
 
 func (nrdf *NameRegDataFilter) Match(v interface{}) bool {
-	nre, ok := v.(*execution.NameRegEntry)
+	nre, ok := v.(*names.Entry)
 	if !ok {
 		return false
 	}
@@ -188,7 +188,7 @@ func (nref *NameRegExpiresFilter) Configure(fd *FilterData) error {
 }
 
 func (nref *NameRegExpiresFilter) Match(v interface{}) bool {
-	nre, ok := v.(*execution.NameRegEntry)
+	nre, ok := v.(*names.Entry)
 	if !ok {
 		return false
 	}
diff --git a/rpc/result.go b/rpc/result.go
index 8fd7a96fa883cb46028d34236b2519b7ecacd3d7..4dc921fc20bbf8a63c6d7970e743599285cc912f 100644
--- a/rpc/result.go
+++ b/rpc/result.go
@@ -23,6 +23,7 @@ import (
 	"github.com/hyperledger/burrow/execution"
 	exeEvents "github.com/hyperledger/burrow/execution/events"
 	evmEvents "github.com/hyperledger/burrow/execution/evm/events"
+	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/genesis"
 	"github.com/hyperledger/burrow/txs"
 	"github.com/tendermint/go-amino"
@@ -161,7 +162,7 @@ type ResultPeers struct {
 
 type ResultListNames struct {
 	BlockHeight uint64
-	Names       []*execution.NameRegEntry
+	Names       []*names.Entry
 }
 
 type ResultGeneratePrivateAccount struct {
@@ -205,7 +206,7 @@ type ResultListUnconfirmedTxs struct {
 }
 
 type ResultGetName struct {
-	Entry *execution.NameRegEntry
+	Entry *names.Entry
 }
 
 type ResultGenesis struct {
diff --git a/rpc/service.go b/rpc/service.go
index 7348118ecb244fd990b0653fc01644945f4b1653..dab10524d4d88570b4e7eaa365f5bea2232b4a1f 100644
--- a/rpc/service.go
+++ b/rpc/service.go
@@ -26,6 +26,7 @@ import (
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/event"
 	"github.com/hyperledger/burrow/execution"
+	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/keys"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/logging/structure"
@@ -45,7 +46,7 @@ const AccountsRingMutexCount = 100
 type Service struct {
 	ctx             context.Context
 	state           state.Iterable
-	nameReg         execution.NameRegIterable
+	nameReg         names.Iterable
 	mempoolAccounts *execution.Accounts
 	subscribable    event.Subscribable
 	blockchain      *bcm.Blockchain
@@ -54,7 +55,7 @@ type Service struct {
 	logger          *logging.Logger
 }
 
-func NewService(ctx context.Context, state state.Iterable, nameReg execution.NameRegIterable,
+func NewService(ctx context.Context, state state.Iterable, nameReg names.Iterable,
 	checker state.Reader, subscribable event.Subscribable, blockchain *bcm.Blockchain, keyClient keys.KeyClient,
 	transactor *execution.Transactor, nodeView *query.NodeView, logger *logging.Logger) *Service {
 
@@ -320,7 +321,7 @@ func (s *Service) GetAccountHumanReadable(address crypto.Address) (*ResultGetAcc
 
 // Name registry
 func (s *Service) GetName(name string) (*ResultGetName, error) {
-	entry, err := s.nameReg.GetNameRegEntry(name)
+	entry, err := s.nameReg.GetNameEntry(name)
 	if err != nil {
 		return nil, err
 	}
@@ -330,17 +331,17 @@ func (s *Service) GetName(name string) (*ResultGetName, error) {
 	return &ResultGetName{Entry: entry}, nil
 }
 
-func (s *Service) ListNames(predicate func(*execution.NameRegEntry) bool) (*ResultListNames, error) {
-	var names []*execution.NameRegEntry
-	s.nameReg.IterateNameRegEntries(func(entry *execution.NameRegEntry) (stop bool) {
+func (s *Service) ListNames(predicate func(*names.Entry) bool) (*ResultListNames, error) {
+	var nms []*names.Entry
+	s.nameReg.IterateNameEntries(func(entry *names.Entry) (stop bool) {
 		if predicate(entry) {
-			names = append(names, entry)
+			nms = append(nms, entry)
 		}
 		return
 	})
 	return &ResultListNames{
 		BlockHeight: s.blockchain.Tip.LastBlockHeight(),
-		Names:       names,
+		Names:       nms,
 	}, nil
 }
 
diff --git a/rpc/tm/client/client.go b/rpc/tm/client/client.go
index 8dbdc716799e55e8ffc35dcf537f86e91abc257c..1b03a76e348cd6ae9042376aab316b7dfc41d488 100644
--- a/rpc/tm/client/client.go
+++ b/rpc/tm/client/client.go
@@ -20,7 +20,7 @@ import (
 
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/crypto"
-	"github.com/hyperledger/burrow/execution"
+	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/rpc"
 	"github.com/hyperledger/burrow/rpc/tm"
 	"github.com/hyperledger/burrow/txs"
@@ -125,7 +125,7 @@ func Call(client RPCClient, fromAddress, toAddress crypto.Address, data []byte)
 	return res, nil
 }
 
-func GetName(client RPCClient, name string) (*execution.NameRegEntry, error) {
+func GetName(client RPCClient, name string) (*names.Entry, error) {
 	res := new(rpc.ResultGetName)
 	_, err := client.Call(tm.GetName, pmap("name", name), res)
 	if err != nil {
diff --git a/rpc/tm/integration/shared.go b/rpc/tm/integration/shared.go
index 9939c1e378ae8b652a46b92c0c352904c79c454f..d01322d005a5fbcf400ae64cc7326b997eb98d62 100644
--- a/rpc/tm/integration/shared.go
+++ b/rpc/tm/integration/shared.go
@@ -26,7 +26,7 @@ import (
 	"github.com/hyperledger/burrow/binary"
 	"github.com/hyperledger/burrow/core/integration"
 	"github.com/hyperledger/burrow/crypto"
-	"github.com/hyperledger/burrow/execution"
+	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/rpc"
 	tmClient "github.com/hyperledger/burrow/rpc/tm/client"
 	rpcClient "github.com/hyperledger/burrow/rpc/tm/lib/client"
@@ -173,7 +173,7 @@ func callContract(t *testing.T, client tmClient.RPCClient, fromAddress, toAddres
 }
 
 // get the namereg entry
-func getNameRegEntry(t *testing.T, client tmClient.RPCClient, name string) *execution.NameRegEntry {
+func getNameRegEntry(t *testing.T, client tmClient.RPCClient, name string) *names.Entry {
 	entry, err := tmClient.GetName(client, name)
 	if err != nil {
 		t.Fatal(err)
diff --git a/rpc/tm/integration/websocket_helpers.go b/rpc/tm/integration/websocket_helpers.go
index 0844f0e78211e96674917c12eefda230f98cf165..9355829e4f2be8bf816040aaec8126d7cc7b7782 100644
--- a/rpc/tm/integration/websocket_helpers.go
+++ b/rpc/tm/integration/websocket_helpers.go
@@ -254,8 +254,8 @@ func unmarshalValidateSend(amt uint64, toAddr crypto.Address, resultEvent *rpc.R
 	if data == nil {
 		return fmt.Errorf("event data %v is not EventDataTx", resultEvent)
 	}
-	if data.Exception != "" {
-		return fmt.Errorf(data.Exception)
+	if data.Exception == nil {
+		return data.Exception.AsError()
 	}
 	tx := data.Tx.Payload.(*payload.SendTx)
 	if tx.Inputs[0].Address != privateAccounts[0].Address() {
@@ -278,8 +278,8 @@ func unmarshalValidateTx(amt uint64, returnCode []byte) resultEventChecker {
 		if data == nil {
 			return true, fmt.Errorf("event data %v is not EventDataTx", *resultEvent)
 		}
-		if data.Exception != "" {
-			return true, fmt.Errorf(data.Exception)
+		if data.Exception != nil {
+			return true, data.Exception.AsError()
 		}
 		tx := data.Tx.Payload.(*payload.CallTx)
 		if tx.Input.Address != privateAccounts[0].Address() {
@@ -304,8 +304,8 @@ func unmarshalValidateCall(origin crypto.Address, returnCode []byte, txid *[]byt
 		if data == nil {
 			return true, fmt.Errorf("event data %v is not EventDataTx", *resultEvent)
 		}
-		if data.Exception != "" {
-			return true, fmt.Errorf(data.Exception)
+		if data.Exception != nil {
+			return true, data.Exception.AsError()
 		}
 		if data.Origin != origin {
 			return true, fmt.Errorf("origin does not match up! Got %s, expected %s", data.Origin, origin)
diff --git a/rpc/tm/methods.go b/rpc/tm/methods.go
index 12807a640cde692828be707ce505fad760e14c18..47883f6d70e7e595e9cbf385598daead4de0a417 100644
--- a/rpc/tm/methods.go
+++ b/rpc/tm/methods.go
@@ -8,7 +8,7 @@ import (
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/event"
-	"github.com/hyperledger/burrow/execution"
+	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/rpc"
 	"github.com/hyperledger/burrow/rpc/tm/lib/server"
@@ -168,7 +168,7 @@ func GetRoutes(service *rpc.Service, logger *logging.Logger) map[string]*server.
 		// Names
 		GetName: server.NewRPCFunc(service.GetName, "name"),
 		ListNames: server.NewRPCFunc(func() (*rpc.ResultListNames, error) {
-			return service.ListNames(func(*execution.NameRegEntry) bool {
+			return service.ListNames(func(*names.Entry) bool {
 				return true
 			})
 		}, ""),
diff --git a/rpc/v0/methods.go b/rpc/v0/methods.go
index 26e788dd51ca51fdb117c015d19db8ace1d77f26..e391f5333aa608097d5eda79d9ab8fe6355b2532 100644
--- a/rpc/v0/methods.go
+++ b/rpc/v0/methods.go
@@ -20,6 +20,7 @@ import (
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/crypto"
 	"github.com/hyperledger/burrow/execution"
+	"github.com/hyperledger/burrow/execution/names"
 	"github.com/hyperledger/burrow/logging"
 	"github.com/hyperledger/burrow/rpc"
 	"github.com/hyperledger/burrow/rpc/filters"
@@ -257,11 +258,11 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 			if err != nil {
 				return nil, rpc.INVALID_PARAMS, err
 			}
-			ce, err := service.Transactor().TransactAndHold(inputAccount, address, param.Data, param.GasLimit, param.Fee)
+			eventDataCall, err := service.Transactor().TransactAndHold(inputAccount, address, param.Data, param.GasLimit, param.Fee)
 			if err != nil {
 				return nil, rpc.INTERNAL_ERROR, err
 			}
-			return ce, 0, nil
+			return eventDataCall, 0, nil
 		},
 		SEND: func(request *rpc.RPCRequest, requester interface{}) (interface{}, int, error) {
 			param := &SendParam{}
@@ -347,7 +348,7 @@ func GetMethods(codec rpc.Codec, service *rpc.Service, logger *logging.Logger) m
 			if err != nil {
 				return nil, rpc.INVALID_PARAMS, err
 			}
-			list, err := service.ListNames(func(entry *execution.NameRegEntry) bool {
+			list, err := service.ListNames(func(entry *names.Entry) bool {
 				return filter.Match(entry)
 			})
 			if err != nil {
diff --git a/txs/tx_test.go b/txs/tx_test.go
index ada6bcd607b1964a943ae5fccb90f306afe69644..bb916e86ab3a144dfaf9d170d1a195a8b7ac01ed 100644
--- a/txs/tx_test.go
+++ b/txs/tx_test.go
@@ -21,8 +21,8 @@ import (
 
 	acm "github.com/hyperledger/burrow/account"
 	"github.com/hyperledger/burrow/crypto"
-	ptypes "github.com/hyperledger/burrow/permission"
 	"github.com/hyperledger/burrow/permission/snatives"
+	ptypes "github.com/hyperledger/burrow/permission/types"
 	"github.com/hyperledger/burrow/txs/payload"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"