diff --git a/manager/eris-mint/evm/opcodes.go b/manager/eris-mint/evm/opcodes/opcodes.go
similarity index 81%
rename from manager/eris-mint/evm/opcodes.go
rename to manager/eris-mint/evm/opcodes/opcodes.go
index ee125eaa7202f584e49a050ced61cac0910960b1..b4205f2fe9633a80643740da942fbc51b1ff5382 100644
--- a/manager/eris-mint/evm/opcodes.go
+++ b/manager/eris-mint/evm/opcodes/opcodes.go
@@ -1,4 +1,4 @@
-package vm
+package opcodes
 
 import (
 	"fmt"
@@ -355,3 +355,51 @@ func AnalyzeJumpDests(code []byte) (dests *set.Set) {
 	}
 	return
 }
+
+// Convenience function to allow us to mix bytes, ints, and OpCodes that
+// represent bytes in an EVM assembly code to make assembly more readable.
+// Also allows us to splice together assembly
+// fragments because any []byte arguments are flattened in the result.
+func Bytecode(bytelikes ...interface{}) []byte {
+	bytes := make([]byte, len(bytelikes))
+	for i, bytelike := range bytelikes {
+		switch b := bytelike.(type) {
+		case byte:
+			bytes[i] = b
+		case OpCode:
+			bytes[i] = byte(b)
+		case int:
+			bytes[i] = byte(b)
+			if int(bytes[i]) != b {
+				panic(fmt.Sprintf("The int %v does not fit inside a byte", b))
+			}
+		case int64:
+			bytes[i] = byte(b)
+			if int64(bytes[i]) != b {
+				panic(fmt.Sprintf("The int64 %v does not fit inside a byte", b))
+			}
+		case []byte:
+			// splice
+			return Concat(bytes[:i], b, Bytecode(bytelikes[i+1:]...))
+		default:
+			panic("Only byte-like codes (and []byte sequences) can be used to form bytecode")
+		}
+	}
+	return bytes
+}
+
+func Concat(bss ...[]byte) []byte {
+	offset := 0
+	for _, bs := range bss {
+		offset += len(bs)
+	}
+	bytes := make([]byte, offset)
+	offset = 0
+	for _, bs := range bss {
+		for i, b := range bs {
+			bytes[offset+i] = b
+		}
+		offset += len(bs)
+	}
+	return bytes
+}
diff --git a/manager/eris-mint/evm/test/log_event_test.go b/manager/eris-mint/evm/test/log_event_test.go
index 302f2912571e87d7f605f0370b81e7f66f32ec07..5f1eb2f463acfc0842878724c557d4f73d99ea6e 100644
--- a/manager/eris-mint/evm/test/log_event_test.go
+++ b/manager/eris-mint/evm/test/log_event_test.go
@@ -6,6 +6,7 @@ import (
 	"testing"
 
 	. "github.com/eris-ltd/eris-db/manager/eris-mint/evm"
+	. "github.com/eris-ltd/eris-db/manager/eris-mint/evm/opcodes"
 	"github.com/eris-ltd/eris-db/txs"
 	. "github.com/tendermint/go-common"
 	"github.com/tendermint/go-events"
diff --git a/manager/eris-mint/evm/test/vm_test.go b/manager/eris-mint/evm/test/vm_test.go
index 11686e63a9676e837511dccd87ef2476cbe721e8..53895c0da1b590c7754c290ed5922b086a437010 100644
--- a/manager/eris-mint/evm/test/vm_test.go
+++ b/manager/eris-mint/evm/test/vm_test.go
@@ -8,13 +8,21 @@ import (
 	"testing"
 	"time"
 
+	"errors"
+
 	. "github.com/eris-ltd/eris-db/manager/eris-mint/evm"
+	. "github.com/eris-ltd/eris-db/manager/eris-mint/evm/opcodes"
 	ptypes "github.com/eris-ltd/eris-db/permission/types"
 	"github.com/eris-ltd/eris-db/txs"
+	"github.com/stretchr/testify/assert"
 	. "github.com/tendermint/go-common"
 	"github.com/tendermint/go-events"
 )
 
+func init() {
+	SetDebug(true)
+}
+
 func newAppState() *FakeAppState {
 	fas := &FakeAppState{
 		accounts: make(map[string]*Account),
@@ -154,65 +162,164 @@ func TestSendCall(t *testing.T) {
 
 	//----------------------------------------------
 	// account2 has insufficient balance, should fail
-	fmt.Println("Should fail with insufficient balance")
-
-	exception := runVMWaitEvents(t, ourVm, account1, account2, addr, contractCode, 1000)
-	if exception == "" {
-		t.Fatal("Expected exception")
-	}
+	_, err := runVMWaitError(ourVm, account1, account2, addr, contractCode, 1000)
+	assert.Error(t, err, "Expected insufficient balance error")
 
 	//----------------------------------------------
 	// give account2 sufficient balance, should pass
-
 	account2.Balance = 100000
-	exception = runVMWaitEvents(t, ourVm, account1, account2, addr, contractCode, 1000)
-	if exception != "" {
-		t.Fatal("Unexpected exception", exception)
-	}
+	_, err = runVMWaitError(ourVm, account1, account2, addr, contractCode, 1000)
+	assert.NoError(t, err, "Should have sufficient balance")
 
 	//----------------------------------------------
 	// insufficient gas, should fail
-	fmt.Println("Should fail with insufficient gas")
 
 	account2.Balance = 100000
-	exception = runVMWaitEvents(t, ourVm, account1, account2, addr, contractCode, 100)
-	if exception == "" {
-		t.Fatal("Expected exception")
+	_, err = runVMWaitError(ourVm, account1, account2, addr, contractCode, 100)
+	assert.Error(t, err, "Expected insufficient gas error")
+}
+
+// This test was introduced to cover an issues exposed in our handling of the
+// gas limit passed from caller to callee on various forms of CALL
+// this ticket gives some background: https://github.com/eris-ltd/eris-pm/issues/212
+// The idea of this test is to implement a simple DelegateCall in EVM code
+// We first run the DELEGATECALL with _just_ enough gas expecting a simple return,
+// and then run it with 1 gas unit less, expecting a failure
+func TestDelegateCallGas(t *testing.T) {
+	appState := newAppState()
+	ourVm := NewVM(appState, newParams(), Zero256, nil)
+
+	inOff := 0
+	inSize := 0 // no call data
+	retOff := 0
+	retSize := 32
+	calleeReturnValue := int64(20)
+
+	// DELEGATECALL(retSize, refOffset, inSize, inOffset, addr, gasLimit)
+	// 6 pops
+	delegateCallCost := GasStackOp * 6
+	// 1 push
+	gasCost := GasStackOp
+	// 2 pops, 1 push
+	subCost := GasStackOp * 3
+	pushCost := GasStackOp
+
+	costBetweenGasAndDelegateCall := gasCost + subCost + delegateCallCost + pushCost
+
+	// Do a simple operation using 1 gas unit
+	calleeAccount, calleeAddress := makeAccountWithCode(appState, "callee",
+		Bytecode(PUSH1, calleeReturnValue, return1()))
+
+	// Here we split up the caller code so we can make a DELEGATE call with
+	// different amounts of gas. The value we sandwich in the middle is the amount
+	// we subtract from the available gas (that the caller has available), so:
+	// code := Bytecode(callerCodePrefix, <amount to subtract from GAS> , callerCodeSuffix)
+	// gives us the code to make the call
+	callerCodePrefix := Bytecode(PUSH1, retSize, PUSH1, retOff, PUSH1, inSize,
+		PUSH1, inOff, PUSH20, calleeAddress, PUSH1)
+	callerCodeSuffix := Bytecode(GAS, SUB, DELEGATECALL, returnWord())
+
+	// Perform a delegate call
+	callerAccount, _ := makeAccountWithCode(appState, "caller",
+		Bytecode(callerCodePrefix,
+			// Give just enough gas to make the DELEGATECALL
+			costBetweenGasAndDelegateCall,
+			callerCodeSuffix))
+
+	// Should pass
+	output, err := runVMWaitError(ourVm, callerAccount, calleeAccount, calleeAddress,
+		callerAccount.Code, 100)
+	assert.NoError(t, err, "Should have sufficient funds for call")
+	assert.Equal(t, Int64ToWord256(calleeReturnValue).Bytes(), output)
+
+	callerAccount.Code = Bytecode(callerCodePrefix,
+		// Shouldn't be enough gas to make call
+		costBetweenGasAndDelegateCall-1,
+		callerCodeSuffix)
+
+	// Should fail
+	_, err = runVMWaitError(ourVm, callerAccount, calleeAccount, calleeAddress,
+		callerAccount.Code, 100)
+	assert.Error(t, err, "Should have insufficient funds for call")
+}
+
+// Store the top element of the stack (which is a 32-byte word) in memory
+// and return it. Useful for a simple return value.
+func return1() []byte {
+	return Bytecode(PUSH1, 0, MSTORE, returnWord())
+}
+
+func returnWord() []byte {
+	// PUSH1 => return size, PUSH1 => return offset, RETURN
+	return Bytecode(PUSH1, 32, PUSH1, 0, RETURN)
+}
+
+func makeAccountWithCode(appState AppState, name string,
+	code []byte) (*Account, []byte) {
+	account := &Account{
+		Address: LeftPadWord256([]byte(name)),
+		Balance: 9999999,
+		Code:    code,
+		Nonce:   0,
+	}
+	account.Code = code
+	appState.UpdateAccount(account)
+	// Sanity check
+	address := new([20]byte)
+	for i, b := range account.Address.Postfix(20) {
+		address[i] = b
+	}
+	return account, address[:]
+}
+
+// Subscribes to an AccCall, runs the vm, returns the output any direct exception
+// and then waits for any exceptions transmitted by EventData in the AccCall
+// event (in the case of no direct error from call we will block waiting for
+// at least 1 AccCall event)
+func runVMWaitError(ourVm *VM, caller, callee *Account, subscribeAddr,
+	contractCode []byte, gas int64) (output []byte, err error) {
+	eventCh := make(chan txs.EventData)
+	output, err = runVM(eventCh, ourVm, caller, callee, subscribeAddr,
+		contractCode, gas)
+	if err != nil {
+		return
+	}
+	msg := <-eventCh
+	var errString string
+	switch ev := msg.(type) {
+	case txs.EventDataTx:
+		errString = ev.Exception
+	case txs.EventDataCall:
+		errString = ev.Exception
+	}
+
+	if errString != "" {
+		err = errors.New(errString)
 	}
+	return
 }
 
-// subscribes to an AccCall, runs the vm, returns the exception
-func runVMWaitEvents(t *testing.T, ourVm *VM, caller, callee *Account, subscribeAddr, contractCode []byte, gas int64) string {
+// Subscribes to an AccCall, runs the vm, returns the output and any direct
+// exception
+func runVM(eventCh chan txs.EventData, ourVm *VM, caller, callee *Account,
+	subscribeAddr, contractCode []byte, gas int64) ([]byte, error) {
+
 	// we need to catch the event from the CALL to check for exceptions
 	evsw := events.NewEventSwitch()
 	evsw.Start()
-	ch := make(chan interface{})
 	fmt.Printf("subscribe to %x\n", subscribeAddr)
-	evsw.AddListenerForEvent("test", txs.EventStringAccCall(subscribeAddr), func(msg events.EventData) {
-		ch <- msg
-	})
+	evsw.AddListenerForEvent("test", txs.EventStringAccCall(subscribeAddr),
+		func(msg events.EventData) {
+			eventCh <- msg.(txs.EventData)
+		})
 	evc := events.NewEventCache(evsw)
 	ourVm.SetFireable(evc)
-	go func() {
-		start := time.Now()
-		output, err := ourVm.Call(caller, callee, contractCode, []byte{}, 0, &gas)
-		fmt.Printf("Output: %v Error: %v\n", output, err)
-		fmt.Println("Call took:", time.Since(start))
-		if err != nil {
-			ch <- err.Error()
-		}
-		evc.Flush()
-	}()
-	msg := <-ch
-	switch ev := msg.(type) {
-	case txs.EventDataTx:
-		return ev.Exception
-	case txs.EventDataCall:
-		return ev.Exception
-	case string:
-		return ev
-	}
-	return ""
+	start := time.Now()
+	output, err := ourVm.Call(caller, callee, contractCode, []byte{}, 0, &gas)
+	fmt.Printf("Output: %v Error: %v\n", output, err)
+	fmt.Println("Call took:", time.Since(start))
+	go func() { evc.Flush() }()
+	return output, err
 }
 
 // this is code to call another contract (hardcoded as addr)
@@ -222,17 +329,42 @@ func callContractCode(addr []byte) []byte {
 	inOff, inSize := byte(0x0), byte(0x0) // no call data
 	retOff, retSize := byte(0x0), byte(0x20)
 	// this is the code we want to run (send funds to an account and return)
+	return Bytecode(PUSH1, retSize, PUSH1, retOff, PUSH1, inSize, PUSH1,
+		inOff, PUSH1, value, PUSH20, addr, PUSH2, gas1, gas2, CALL, PUSH1, retSize,
+		PUSH1, retOff, RETURN)
+}
+
+func TestBytecode(t *testing.T) {
+	assert.Equal(t,
+		Bytecode(1, 2, 3, 4, 5, 6),
+		Bytecode(1, 2, 3, Bytecode(4, 5, 6)))
+	assert.Equal(t,
+		Bytecode(1, 2, 3, 4, 5, 6, 7, 8),
+		Bytecode(1, 2, 3, Bytecode(4, Bytecode(5), 6), 7, 8))
+	assert.Equal(t,
+		Bytecode(PUSH1, 2),
+		Bytecode(byte(PUSH1), 0x02))
+	assert.Equal(t,
+		[]byte{},
+		Bytecode(Bytecode(Bytecode())))
+
+	contractAccount := &Account{Address: Int64ToWord256(102)}
+	addr := contractAccount.Address.Postfix(20)
+	gas1, gas2 := byte(0x1), byte(0x1)
+	value := byte(0x69)
+	inOff, inSize := byte(0x0), byte(0x0) // no call data
+	retOff, retSize := byte(0x0), byte(0x20)
+	contractCodeBytecode := Bytecode(PUSH1, retSize, PUSH1, retOff, PUSH1, inSize, PUSH1,
+		inOff, PUSH1, value, PUSH20, addr, PUSH2, gas1, gas2, CALL, PUSH1, retSize,
+		PUSH1, retOff, RETURN)
 	contractCode := []byte{0x60, retSize, 0x60, retOff, 0x60, inSize, 0x60, inOff, 0x60, value, 0x73}
 	contractCode = append(contractCode, addr...)
 	contractCode = append(contractCode, []byte{0x61, gas1, gas2, 0xf1, 0x60, 0x20, 0x60, 0x0, 0xf3}...)
-	return contractCode
+	assert.Equal(t, contractCode, contractCodeBytecode)
 }
 
-/*
-	// infinite loop
-	code := []byte{0x5B, 0x60, 0x00, 0x56}
-	// mstore
-	code := []byte{0x60, 0x00, 0x60, 0x20}
-	// mstore, mload
-	code := []byte{0x60, 0x01, 0x60, 0x20, 0x52, 0x60, 0x20, 0x51}
-*/
+func TestConcat(t *testing.T) {
+	assert.Equal(t,
+		[]byte{0x01, 0x02, 0x03, 0x04},
+		Concat([]byte{0x01, 0x02}, []byte{0x03, 0x04}))
+}
diff --git a/manager/eris-mint/evm/vm.go b/manager/eris-mint/evm/vm.go
index cb451f34a89256a61cb91447b9ed511e1779e887..a3f4d51eacf5809c96f966e2a67df25146bd63e3 100644
--- a/manager/eris-mint/evm/vm.go
+++ b/manager/eris-mint/evm/vm.go
@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"math/big"
 
+	. "github.com/eris-ltd/eris-db/manager/eris-mint/evm/opcodes"
 	"github.com/eris-ltd/eris-db/manager/eris-mint/evm/sha3"
 	ptypes "github.com/eris-ltd/eris-db/permission/types"
 	"github.com/eris-ltd/eris-db/txs"
@@ -17,7 +18,7 @@ var (
 	ErrUnknownAddress      = errors.New("Unknown address")
 	ErrInsufficientBalance = errors.New("Insufficient balance")
 	ErrInvalidJumpDest     = errors.New("Invalid jump dest")
-	ErrInsufficientGas     = errors.New("Insuffient gas")
+	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")
@@ -194,7 +195,6 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 	)
 
 	for {
-
 		// Use BaseOp gas.
 		if useGasNegative(gas, GasBaseOp, &err) {
 			return nil, err
@@ -816,7 +816,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 					exception = err.Error()
 				}
 				// NOTE: these fire call events and not particular events for eg name reg or permissions
-				vm.fireCallEvent(&exception, &ret, callee, &Account{Address: addr}, args, value, gas)
+				vm.fireCallEvent(&exception, &ret, callee, &Account{Address: addr}, args, value, &gasLimit)
 			} else {
 				// EVM contract
 				if useGasNegative(gas, GasGetAccount, &err) {
@@ -831,12 +831,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 					if acc == nil {
 						return nil, firstErr(err, ErrUnknownAddress)
 					}
-					ret, err = vm.Call(callee, callee, acc.Code, args, value, gas)
+					ret, err = vm.Call(callee, callee, acc.Code, args, value, &gasLimit)
 				} else if op == DELEGATECALL {
 					if acc == nil {
 						return nil, firstErr(err, ErrUnknownAddress)
 					}
-					ret, err = vm.DelegateCall(caller, callee, acc.Code, args, value, gas)
+					ret, err = vm.DelegateCall(caller, callee, acc.Code, args, value, &gasLimit)
 				} else {
 					// nil account means we're sending funds to a new account
 					if acc == nil {
@@ -847,7 +847,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 					}
 					// add account to the tx cache
 					vm.appState.UpdateAccount(acc)
-					ret, err = vm.Call(callee, acc, acc.Code, args, value, gas)
+					ret, err = vm.Call(callee, acc, acc.Code, args, value, &gasLimit)
 				}
 			}
 
@@ -906,7 +906,6 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 		}
 
 		pc++
-
 	}
 }
 
diff --git a/manager/eris-mint/state/permissions_test.go b/manager/eris-mint/state/permissions_test.go
index 5c311405a0dec3288770b8cbd2e2b347b89ec6a3..523a5ffc8b2a75a13749c8ba924d4c6ded2e824a 100644
--- a/manager/eris-mint/state/permissions_test.go
+++ b/manager/eris-mint/state/permissions_test.go
@@ -14,6 +14,7 @@ import (
 	ptypes "github.com/eris-ltd/eris-db/permission/types"
 	"github.com/eris-ltd/eris-db/txs"
 
+	. "github.com/eris-ltd/eris-db/manager/eris-mint/evm/opcodes"
 	. "github.com/tendermint/go-common"
 	"github.com/tendermint/go-crypto"
 	dbm "github.com/tendermint/go-db"
@@ -1257,17 +1258,17 @@ func snativeRoleTestInputTx(name string, user *acm.PrivAccount, role string) (sn
 func callContractCode(contractAddr []byte) []byte {
 	// calldatacopy into mem and use as input to call
 	memOff, inputOff := byte(0x0), byte(0x0)
-	contractCode := []byte{0x36, 0x60, inputOff, 0x60, memOff, 0x37}
-
-	gas1, gas2 := byte(0x1), byte(0x1)
 	value := byte(0x1)
 	inOff := byte(0x0)
 	retOff, retSize := byte(0x0), byte(0x20)
+
 	// this is the code we want to run (call a contract and return)
-	contractCode = append(contractCode, []byte{0x60, retSize, 0x60, retOff, 0x36, 0x60, inOff, 0x60, value, 0x73}...)
-	contractCode = append(contractCode, contractAddr...)
-	contractCode = append(contractCode, []byte{0x61, gas1, gas2, 0xf1, 0x60, 0x20, 0x60, 0x0, 0xf3}...)
-	return contractCode
+	return Bytecode(CALLDATASIZE, PUSH1, inputOff, PUSH1, memOff,
+		CALLDATACOPY, PUSH1, retSize, PUSH1, retOff, CALLDATASIZE, PUSH1, inOff,
+		PUSH1, value, PUSH20, contractAddr,
+		// Zeno loves us - call with half of the available gas each time we CALL
+		PUSH1, 2, GAS, DIV, CALL,
+		PUSH1, 32, PUSH1, 0, RETURN)
 }
 
 // convenience function for contract that is a factory for the code that comes as call data
diff --git a/manager/eris-mint/state/state_test.go b/manager/eris-mint/state/state_test.go
index 7f8cb8f11258e167fd2fe99fe8bc0dc7c5d794e2..be619f3354ec8853285e842e11576fbade65c824 100644
--- a/manager/eris-mint/state/state_test.go
+++ b/manager/eris-mint/state/state_test.go
@@ -11,12 +11,13 @@ import (
 	// tmtypes "github.com/tendermint/tendermint/types"
 
 	core_types "github.com/eris-ltd/eris-db/core/types"
-	//evm "github.com/eris-ltd/eris-db/manager/eris-mint/evm"
 	"github.com/eris-ltd/eris-db/txs"
+	evm "github.com/eris-ltd/eris-db/manager/eris-mint/evm"
 )
 
 func init() {
 	tendermint_test.ResetConfig("state_test")
+	evm.SetDebug(true)
 }
 
 func execTxWithState(state *State, tx txs.Tx, runCall bool) error {
@@ -463,7 +464,7 @@ func TestCreates(t *testing.T) {
 			PubKey:   acc0PubKey,
 		},
 		Address:  acc1.Address,
-		GasLimit: 10000,
+		GasLimit: 100000,
 		Data:     createData,
 	}