diff --git a/logging/loggers/burrow_format_logger.go b/logging/loggers/burrow_format_logger.go
index ec522b3d896495e052616007d7eaa578d4c60961..2af1b4032eb3d0576fbffc9296ad238dd500bf92 100644
--- a/logging/loggers/burrow_format_logger.go
+++ b/logging/loggers/burrow_format_logger.go
@@ -20,6 +20,7 @@ import (
 	"github.com/hyperledger/burrow/logging/structure"
 
 	kitlog "github.com/go-kit/kit/log"
+	"github.com/hyperledger/burrow/word256"
 )
 
 // Logger that implements some formatting conventions for burrow and burrow-client
@@ -50,7 +51,10 @@ func burrowFormatKeyValueMapper(key, value interface{}) (interface{}, interface{
 		switch v := value.(type) {
 		case []byte:
 			return key, fmt.Sprintf("%X", v)
+		case word256.Word256:
+			return burrowFormatKeyValueMapper(key, v.Bytes())
 		}
+
 	}
 	return key, value
 }
diff --git a/manager/burrow-mint/evm/log_event_test.go b/manager/burrow-mint/evm/log_event_test.go
index 91431adc7477fe1a29e77f4dfdf42aaa8e997f60..7dd569a63008a5cf0bbf43a0ef31f7f94e3cd451 100644
--- a/manager/burrow-mint/evm/log_event_test.go
+++ b/manager/burrow-mint/evm/log_event_test.go
@@ -47,7 +47,7 @@ func TestLog4(t *testing.T) {
 	st.accounts[account1.Address.String()] = account1
 	st.accounts[account2.Address.String()] = account2
 
-	ourVm := NewVM(st, newParams(), Zero256, nil)
+	ourVm := NewVM(st, DefaultDynamicMemoryProvider, newParams(), Zero256, nil)
 
 	eventSwitch := events.NewEventSwitch()
 	_, err := eventSwitch.Start()
diff --git a/manager/burrow-mint/evm/memory.go b/manager/burrow-mint/evm/memory.go
new file mode 100644
index 0000000000000000000000000000000000000000..fc24dbd7d85adcfbbb1ca26f0508675b1047e5fb
--- /dev/null
+++ b/manager/burrow-mint/evm/memory.go
@@ -0,0 +1,115 @@
+package vm
+
+import (
+	"fmt"
+	"math"
+)
+
+const (
+	defaultInitialMemoryCapacity = 0x100000  // 1 MiB
+	defaultMaximumMemoryCapacity = 0x1000000 // 16 MiB
+)
+
+// Change the length of this zero array to tweak the size of the block of zeros
+// written to the backing slice at a time when it is grown. A larger number may
+// lead to less calls to append to achieve the desired capacity although it is
+// unlikely to make a lot of difference.
+var zeroBlock []byte = make([]byte, 32)
+
+// Interface for a bounded linear memory indexed by a single int64 parameter
+// for each byte in the memory.
+type Memory interface {
+	// Read a value from the memory store starting at offset
+	// (index of first byte will equal offset). The value will be returned as a
+	// length-bytes byte slice. Returns an error if the memory cannot be read or
+	// is not allocated.
+	//
+	// The value returned should be copy of any underlying memory, not a reference
+	// to the underlying store.
+	Read(offset, length int64) ([]byte, error)
+	// Write a value to the memory starting at offset (the index of the first byte
+	// written will equal offset). The value is provided as bytes to be written
+	// consecutively to the memory store. Return an error if the memory cannot be
+	// written or allocated.
+	Write(offset int64, value []byte) error
+	// Returns the current capacity of the memory. For dynamically allocating
+	// memory this capacity can be used as a write offset that is guaranteed to be
+	// unused. Solidity in particular makes this assumption when using MSIZE to
+	// get the current allocated memory.
+	Capacity() int64
+}
+
+func NewDynamicMemory(initialCapacity, maximumCapacity int64) Memory {
+	return &dynamicMemory{
+		slice:           make([]byte, initialCapacity),
+		maximumCapacity: maximumCapacity,
+	}
+}
+
+func DefaultDynamicMemoryProvider() Memory {
+	return NewDynamicMemory(defaultInitialMemoryCapacity, defaultMaximumMemoryCapacity)
+}
+
+// Implements a bounded dynamic memory that relies on Go's (pretty good) dynamic
+// array allocation via a backing slice
+type dynamicMemory struct {
+	slice           []byte
+	maximumCapacity int64
+}
+
+func (mem *dynamicMemory) Read(offset, length int64) ([]byte, error) {
+	capacity := offset + length
+	err := mem.ensureCapacity(capacity)
+	if err != nil {
+		return nil, err
+	}
+	value := make([]byte, length)
+	copy(value, mem.slice[offset:capacity])
+	return value, nil
+}
+
+func (mem *dynamicMemory) Write(offset int64, value []byte) error {
+	capacity := offset + int64(len(value))
+	err := mem.ensureCapacity(capacity)
+	if err != nil {
+		return err
+	}
+	copy(mem.slice[offset:capacity], value)
+	return nil
+}
+
+func (mem *dynamicMemory) Capacity() int64 {
+	return int64(len(mem.slice))
+}
+
+// Ensures the current memory store can hold newCapacity. Will only grow the
+// memory (will not shrink).
+func (mem *dynamicMemory) ensureCapacity(newCapacity int64) error {
+	if newCapacity > math.MaxInt32 {
+		// If we ever did want to then we would need to maintain multiple pages
+		// of memory
+		return fmt.Errorf("Cannot address memory beyond a maximum index "+
+			"of Int32 type (%v bytes)", math.MaxInt32)
+	}
+	newCapacityInt := int(newCapacity)
+	// We're already big enough so return
+	if newCapacityInt <= len(mem.slice) {
+		return nil
+	}
+	if newCapacity > mem.maximumCapacity {
+		return fmt.Errorf("Cannot grow memory because it would exceed the "+
+			"current maximum limit of %v bytes", mem.maximumCapacity)
+	}
+	// Ensure the backing array of slice is big enough
+	// Grow the memory one word at time using the pre-allocated zeroBlock to avoid
+	// unnecessary allocations. Use append to make use of any spare capacity in
+	// the slice's backing array.
+	for newCapacityInt > cap(mem.slice) {
+		// We'll trust Go exponentially grow our arrays (at first).
+		mem.slice = append(mem.slice, zeroBlock...)
+	}
+	// Now we've ensured the backing array of the slice is big enough we can
+	// just re-slice (even if len(mem.slice) < newCapacity)
+	mem.slice = mem.slice[:newCapacity]
+	return nil
+}
diff --git a/manager/burrow-mint/evm/memory_test.go b/manager/burrow-mint/evm/memory_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..2477b32d8292aa2c0aab36d4af575458322fb26b
--- /dev/null
+++ b/manager/burrow-mint/evm/memory_test.go
@@ -0,0 +1,120 @@
+package vm
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+// Test static memory allocation with maximum == initial capacity - memory should not grow
+func TestDynamicMemory_StaticAllocation(t *testing.T) {
+	mem := NewDynamicMemory(4, 4).(*dynamicMemory)
+	mem.Write(0, []byte{1})
+	mem.Write(1, []byte{0, 0, 1})
+	assert.Equal(t, []byte{1, 0, 0, 1}, mem.slice)
+	assert.Equal(t, 4, cap(mem.slice), "Slice capacity should not grow")
+}
+
+// Test reading beyond the current capacity - memory should grow
+func TestDynamicMemory_ReadAhead(t *testing.T) {
+	mem := NewDynamicMemory(4, 8).(*dynamicMemory)
+	value, err := mem.Read(2, 4)
+	assert.NoError(t, err)
+	// Value should be size requested
+	assert.Equal(t, []byte{0, 0, 0, 0}, value)
+	// Slice should have grown to that plus offset
+	assert.Equal(t, []byte{0, 0, 0, 0, 0, 0}, mem.slice)
+
+	value, err = mem.Read(2, 6)
+	assert.NoError(t, err)
+	assert.Equal(t, []byte{0, 0, 0, 0, 0, 0}, value)
+	assert.Equal(t, []byte{0, 0, 0, 0, 0, 0, 0, 0}, mem.slice)
+
+	// Check cannot read out of bounds
+	_, err = mem.Read(2, 7)
+	assert.Error(t, err)
+}
+
+// Test writing beyond the current capacity - memory should grow
+func TestDynamicMemory_WriteAhead(t *testing.T) {
+	mem := NewDynamicMemory(4, 8).(*dynamicMemory)
+	err := mem.Write(4, []byte{1, 2, 3, 4})
+	assert.NoError(t, err)
+	assert.Equal(t, []byte{0, 0, 0, 0, 1, 2, 3, 4}, mem.slice)
+
+	err = mem.Write(4, []byte{1, 2, 3, 4, 5})
+	assert.Error(t, err)
+}
+
+func TestDynamicMemory_WriteRead(t *testing.T) {
+	mem := NewDynamicMemory(1, 0x10000000).(*dynamicMemory)
+	// Text is out of copyright
+	bytesToWrite := []byte(`He paused. He felt the rhythm of the verse about him in the room.
+How melancholy it was! Could he, too, write like that, express the
+melancholy of his soul in verse? There were so many things he wanted
+to describe: his sensation of a few hours before on Grattan Bridge, for
+example. If he could get back again into that mood....`)
+
+	// Write the bytes
+	offset := 0x1000000
+	err := mem.Write(int64(offset), bytesToWrite)
+	assert.NoError(t, err)
+	assert.Equal(t, append(make([]byte, offset), bytesToWrite...), mem.slice)
+	assert.Equal(t, offset+len(bytesToWrite), len(mem.slice))
+
+	// Read them back
+	value, err := mem.Read(int64(offset), int64(len(bytesToWrite)))
+	assert.NoError(t, err)
+	assert.Equal(t, bytesToWrite, value)
+}
+
+func TestDynamicMemory_ZeroInitialMemory(t *testing.T) {
+	mem := NewDynamicMemory(0, 16).(*dynamicMemory)
+	err := mem.Write(4, []byte{1, 2, 3, 4})
+	assert.NoError(t, err)
+	assert.Equal(t, []byte{0, 0, 0, 0, 1, 2, 3, 4}, mem.slice)
+}
+
+func TestDynamicMemory_Capacity(t *testing.T) {
+	mem := NewDynamicMemory(1, 0x10000000).(*dynamicMemory)
+
+	assert.Equal(t, int64(1), mem.Capacity())
+
+	capacity := int64(1234)
+	err := mem.ensureCapacity(capacity)
+	assert.NoError(t, err)
+	assert.Equal(t, capacity, mem.Capacity())
+
+	capacity = int64(123456789)
+	err = mem.ensureCapacity(capacity)
+	assert.NoError(t, err)
+	assert.Equal(t, capacity, mem.Capacity())
+
+	// Check doesn't shrink or err
+	err = mem.ensureCapacity(12)
+	assert.NoError(t, err)
+	assert.Equal(t, capacity, mem.Capacity())
+}
+
+func TestDynamicMemory_ensureCapacity(t *testing.T) {
+	mem := NewDynamicMemory(4, 16).(*dynamicMemory)
+	// Check we can grow within bounds
+	err := mem.ensureCapacity(8)
+	assert.NoError(t, err)
+	expected := make([]byte, 8)
+	assert.Equal(t, expected, mem.slice)
+
+	// Check we can grow to bounds
+	err = mem.ensureCapacity(16)
+	assert.NoError(t, err)
+	expected = make([]byte, 16)
+	assert.Equal(t, expected, mem.slice)
+
+	err = mem.ensureCapacity(1)
+	assert.NoError(t, err)
+	assert.Equal(t, 16, len(mem.slice))
+
+	err = mem.ensureCapacity(17)
+	assert.Error(t, err, "Should not be possible to grow over capacity")
+
+}
diff --git a/manager/burrow-mint/evm/opcodes/opcodes.go b/manager/burrow-mint/evm/opcodes/opcodes.go
index 0debc94ec780e70dc6db6448317b684bcb44e34d..a8139d82f25bde769328ea169b176facd913a75c 100644
--- a/manager/burrow-mint/evm/opcodes/opcodes.go
+++ b/manager/burrow-mint/evm/opcodes/opcodes.go
@@ -244,9 +244,7 @@ var opCodeToString = map[OpCode]string{
 	EXTCODECOPY:           "EXTCODECOPY",
 
 	// 0x50 range - 'storage' and execution
-	POP: "POP",
-	//DUP:     "DUP",
-	//SWAP:    "SWAP",
+	POP:      "POP",
 	MLOAD:    "MLOAD",
 	MSTORE:   "MSTORE",
 	MSTORE8:  "MSTORE8",
diff --git a/manager/burrow-mint/evm/snative.go b/manager/burrow-mint/evm/snative.go
index ab7e68a432374030f512d88d8c91129ba940358d..d256ddf23b151277885db854cef18cbce9c61f21 100644
--- a/manager/burrow-mint/evm/snative.go
+++ b/manager/burrow-mint/evm/snative.go
@@ -87,10 +87,10 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 			`,
 				"addRole",
 				[]abi.Arg{
-					arg("_account", abi.AddressTypeName),
-					arg("_role", roleTypeName),
+					abiArg("_account", abi.AddressTypeName),
+					abiArg("_role", roleTypeName),
 				},
-				ret("result", abi.BoolTypeName),
+				abiReturn("result", abi.BoolTypeName),
 				ptypes.AddRole,
 				addRole},
 
@@ -102,10 +102,10 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 			`,
 				"removeRole",
 				[]abi.Arg{
-					arg("_account", abi.AddressTypeName),
-					arg("_role", roleTypeName),
+					abiArg("_account", abi.AddressTypeName),
+					abiArg("_role", roleTypeName),
 				},
-				ret("result", abi.BoolTypeName),
+				abiReturn("result", abi.BoolTypeName),
 				ptypes.RmRole,
 				removeRole},
 
@@ -117,10 +117,10 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 			`,
 				"hasRole",
 				[]abi.Arg{
-					arg("_account", abi.AddressTypeName),
-					arg("_role", roleTypeName),
+					abiArg("_account", abi.AddressTypeName),
+					abiArg("_role", roleTypeName),
 				},
-				ret("result", abi.BoolTypeName),
+				abiReturn("result", abi.BoolTypeName),
 				ptypes.HasRole,
 				hasRole},
 
@@ -133,11 +133,11 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 			`,
 				"setBase",
 				[]abi.Arg{
-					arg("_account", abi.AddressTypeName),
-					arg("_permission", permFlagTypeName),
-					arg("_set", abi.BoolTypeName),
+					abiArg("_account", abi.AddressTypeName),
+					abiArg("_permission", permFlagTypeName),
+					abiArg("_set", abi.BoolTypeName),
 				},
-				ret("result", permFlagTypeName),
+				abiReturn("result", permFlagTypeName),
 				ptypes.SetBase,
 				setBase},
 
@@ -149,9 +149,9 @@ func SNativeContracts() map[string]*SNativeContractDescription {
       `,
 				"unsetBase",
 				[]abi.Arg{
-					arg("_account", abi.AddressTypeName),
-					arg("_permission", permFlagTypeName)},
-				ret("result", permFlagTypeName),
+					abiArg("_account", abi.AddressTypeName),
+					abiArg("_permission", permFlagTypeName)},
+				abiReturn("result", permFlagTypeName),
 				ptypes.UnsetBase,
 				unsetBase},
 
@@ -163,9 +163,9 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 			`,
 				"hasBase",
 				[]abi.Arg{
-					arg("_account", abi.AddressTypeName),
-					arg("_permission", permFlagTypeName)},
-				ret("result", abi.BoolTypeName),
+					abiArg("_account", abi.AddressTypeName),
+					abiArg("_permission", permFlagTypeName)},
+				abiReturn("result", abi.BoolTypeName),
 				ptypes.HasBase,
 				hasBase},
 
@@ -177,9 +177,9 @@ func SNativeContracts() map[string]*SNativeContractDescription {
 			`,
 				"setGlobal",
 				[]abi.Arg{
-					arg("_permission", permFlagTypeName),
-					arg("_set", abi.BoolTypeName)},
-				ret("result", permFlagTypeName),
+					abiArg("_permission", permFlagTypeName),
+					abiArg("_set", abi.BoolTypeName)},
+				abiReturn("result", permFlagTypeName),
 				ptypes.SetGlobal,
 				setGlobal},
 		),
@@ -324,14 +324,14 @@ func (function *SNativeFunctionDescription) NArgs() int {
 	return len(function.Args)
 }
 
-func arg(name string, abiTypeName abi.TypeName) abi.Arg {
+func abiArg(name string, abiTypeName abi.TypeName) abi.Arg {
 	return abi.Arg{
 		Name:     name,
 		TypeName: abiTypeName,
 	}
 }
 
-func ret(name string, abiTypeName abi.TypeName) abi.Return {
+func abiReturn(name string, abiTypeName abi.TypeName) abi.Return {
 	return abi.Return{
 		Name:     name,
 		TypeName: abiTypeName,
diff --git a/manager/burrow-mint/evm/vm.go b/manager/burrow-mint/evm/vm.go
index 26d4d196c761b7828da4d602ffb8d0d2db71e2c9..60ae0f64e3bc0ffffa65e4f7849f75bb6221dab9 100644
--- a/manager/burrow-mint/evm/vm.go
+++ b/manager/burrow-mint/evm/vm.go
@@ -20,7 +20,6 @@ import (
 	"fmt"
 	"math/big"
 
-	"github.com/hyperledger/burrow/common/math/integral"
 	"github.com/hyperledger/burrow/common/sanity"
 	. "github.com/hyperledger/burrow/manager/burrow-mint/evm/opcodes"
 	"github.com/hyperledger/burrow/manager/burrow-mint/evm/sha3"
@@ -57,8 +56,7 @@ func (err ErrPermission) Error() string {
 
 const (
 	dataStackCapacity = 1024
-	callStackCapacity = 100         // TODO ensure usage.
-	memoryCapacity    = 1024 * 1024 // 1 MB
+	callStackCapacity = 100 // TODO ensure usage.
 )
 
 type Debug bool
@@ -76,23 +74,26 @@ func (d Debug) Printf(s string, a ...interface{}) {
 }
 
 type VM struct {
-	appState AppState
-	params   Params
-	origin   Word256
-	txid     []byte
+	appState       AppState
+	memoryProvider func() Memory
+	params         Params
+	origin         Word256
+	txid           []byte
 
 	callDepth int
 
 	evc events.Fireable
 }
 
-func NewVM(appState AppState, params Params, origin Word256, txid []byte) *VM {
+func NewVM(appState AppState, memoryProvider func() Memory, params Params,
+	origin Word256, txid []byte) *VM {
 	return &VM{
-		appState:  appState,
-		params:    params,
-		origin:    origin,
-		callDepth: 0,
-		txid:      txid,
+		appState:       appState,
+		memoryProvider: memoryProvider,
+		params:         params,
+		origin:         origin,
+		callDepth:      0,
+		txid:           txid,
 	}
 }
 
@@ -211,7 +212,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 	var (
 		pc     int64 = 0
 		stack        = NewStack(dataStackCapacity, gas, &err)
-		memory       = make([]byte, memoryCapacity)
+		memory       = vm.memoryProvider()
 	)
 
 	for {
@@ -488,8 +489,9 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 				return nil, err
 			}
 			offset, size := stack.Pop64(), stack.Pop64()
-			data, ok := subslice(memory, offset, size)
-			if !ok {
+			data, memErr := memory.Read(offset, size)
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
 			data = sha3.Sha3(data)
@@ -547,11 +549,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 			if !ok {
 				return nil, firstErr(err, ErrInputOutOfBounds)
 			}
-			dest, ok := subslice(memory, memOff, length)
-			if !ok {
+			memErr := memory.Write(memOff, data)
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
-			copy(dest, data)
 			dbg.Printf(" => [%v, %v, %v] %X\n", memOff, inputOff, length, data)
 
 		case CODESIZE: // 0x38
@@ -567,11 +569,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 			if !ok {
 				return nil, firstErr(err, ErrCodeOutOfBounds)
 			}
-			dest, ok := subslice(memory, memOff, length)
-			if !ok {
+			memErr := memory.Write(memOff, data)
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
-			copy(dest, data)
 			dbg.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data)
 
 		case GASPRICE_DEPRECATED: // 0x3A
@@ -617,11 +619,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 			if !ok {
 				return nil, firstErr(err, ErrCodeOutOfBounds)
 			}
-			dest, ok := subslice(memory, memOff, length)
-			if !ok {
+			memErr := memory.Write(memOff, data)
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
-			copy(dest, data)
 			dbg.Printf(" => [%v, %v, %v] %X\n", memOff, codeOff, length, data)
 
 		case BLOCKHASH: // 0x40
@@ -652,28 +654,30 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 
 		case MLOAD: // 0x51
 			offset := stack.Pop64()
-			data, ok := subslice(memory, offset, 32)
-			if !ok {
+			data, memErr := memory.Read(offset, 32)
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
 			stack.Push(LeftPadWord256(data))
-			dbg.Printf(" => 0x%X\n", data)
+			dbg.Printf(" => 0x%X @ 0x%X\n", data, offset)
 
 		case MSTORE: // 0x52
 			offset, data := stack.Pop64(), stack.Pop()
-			dest, ok := subslice(memory, offset, 32)
-			if !ok {
+			memErr := memory.Write(offset, data.Bytes())
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
-			copy(dest, data[:])
-			dbg.Printf(" => 0x%X\n", data)
+			dbg.Printf(" => 0x%X @ 0x%X\n", data, offset)
 
 		case MSTORE8: // 0x53
 			offset, val := stack.Pop64(), byte(stack.Pop64()&0xFF)
-			if len(memory) <= int(offset) {
+			memErr := memory.Write(offset, []byte{val})
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
-			memory[offset] = val
 			dbg.Printf(" => [%v] 0x%X\n", offset, val)
 
 		case SLOAD: // 0x54
@@ -710,7 +714,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 			stack.Push64(pc)
 
 		case MSIZE: // 0x59
-			stack.Push64(int64(len(memory)))
+			// Note: Solidity will write to this offset expecting to find guaranteed
+			// free memory to be allocated for it if a subsequent MSTORE is made to
+			// this offset.
+			capacity := memory.Capacity()
+			stack.Push64(capacity)
+			dbg.Printf(" => 0x%X\n", capacity)
 
 		case GAS: // 0x5A
 			stack.Push64(*gas)
@@ -750,11 +759,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 			for i := 0; i < n; i++ {
 				topics[i] = stack.Pop()
 			}
-			data, ok := subslice(memory, offset, size)
-			if !ok {
+			data, memErr := memory.Read(offset, size)
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
-			data = copyslice(data)
 			if vm.evc != nil {
 				eventID := txs.EventStringLogEvent(callee.Address.Postfix(20))
 				fmt.Printf("eventID: %s\n", eventID)
@@ -774,8 +783,9 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 			}
 			contractValue := stack.Pop64()
 			offset, size := stack.Pop64(), stack.Pop64()
-			input, ok := subslice(memory, offset, size)
-			if !ok {
+			input, memErr := memory.Read(offset, size)
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
 
@@ -785,7 +795,6 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 			}
 
 			// TODO charge for gas to create account _ the code length * GasCreateByte
-
 			newAccount := vm.appState.CreateAccount(callee)
 
 			// Run the input to get the contract code.
@@ -817,11 +826,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 			dbg.Printf(" => %X\n", addr)
 
 			// Get the arguments from the memory
-			args, ok := subslice(memory, inOffset, inSize)
-			if !ok {
+			args, memErr := memory.Read(inOffset, inSize)
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
-			args = copyslice(args)
 
 			// Ensure that gasLimit is reasonable
 			if *gas < gasLimit {
@@ -885,11 +894,15 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 				stack.Push(Zero256)
 			} else {
 				stack.Push(One256)
-				dest, ok := subslice(memory, retOffset, retSize)
-				if !ok {
+
+				// Should probably only be necessary when there is no return value and
+				// ret is empty, but since EVM expects retSize to be respected this will
+				// defensively pad or truncate the portion of ret to be returned.
+				memErr := memory.Write(retOffset, RightPadBytes(ret, int(retSize)))
+				if memErr != nil {
+					dbg.Printf(" => Memory err: %s", memErr)
 					return nil, firstErr(err, ErrMemoryOutOfBounds)
 				}
-				copy(dest, ret)
 			}
 
 			// Handle remaining gas.
@@ -899,12 +912,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 
 		case RETURN: // 0xF3
 			offset, size := stack.Pop64(), stack.Pop64()
-			ret, ok := subslice(memory, offset, size)
-			if !ok {
+			output, memErr := memory.Read(offset, size)
+			if memErr != nil {
+				dbg.Printf(" => Memory err: %s", memErr)
 				return nil, firstErr(err, ErrMemoryOutOfBounds)
 			}
-			dbg.Printf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(ret), ret)
-			output = copyslice(ret)
+			dbg.Printf(" => [%v, %v] (%d) 0x%X\n", offset, size, len(output), output)
 			return output, nil
 
 		case SELFDESTRUCT: // 0xFF
@@ -937,6 +950,16 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas
 	}
 }
 
+// TODO: [Silas] this function seems extremely dubious to me. It was being used
+// in circumstances where its behaviour did not match the intention. It's bounds
+// check is strange (treats a read at data length as a zero read of arbitrary length)
+// I have left it in for now to be conservative about where its behaviour is being used
+//
+// Returns a subslice from offset of length length and a bool
+// (true iff slice was possible). If the subslice
+// extends past the end of data it returns A COPY of the segment at the end of
+// data padded with zeroes on the right. If offset == len(data) it returns all
+// zeroes. if offset > len(data) it returns a false
 func subslice(data []byte, offset, length int64) (ret []byte, ok bool) {
 	size := int64(len(data))
 	if size < offset {
@@ -950,18 +973,6 @@ func subslice(data []byte, offset, length int64) (ret []byte, ok bool) {
 	return
 }
 
-func copyslice(src []byte) (dest []byte) {
-	dest = make([]byte, len(src))
-	copy(dest, src)
-	return dest
-}
-
-func rightMostBytes(data []byte, n int) []byte {
-	size := integral.MinInt(len(data), n)
-	offset := len(data) - size
-	return data[offset:]
-}
-
 func codeGetOp(code []byte, n int64) OpCode {
 	if int64(len(code)) <= n {
 		return OpCode(0) // stop
diff --git a/manager/burrow-mint/evm/vm_test.go b/manager/burrow-mint/evm/vm_test.go
index dc316ec68856934aed5d7ce37c52d9e6dbc1c6f0..a7e36a7088dc0c8b392b24d2dd4258bba2997770 100644
--- a/manager/burrow-mint/evm/vm_test.go
+++ b/manager/burrow-mint/evm/vm_test.go
@@ -65,7 +65,7 @@ func makeBytes(n int) []byte {
 
 // Runs a basic loop
 func TestVM(t *testing.T) {
-	ourVm := NewVM(newAppState(), newParams(), Zero256, nil)
+	ourVm := NewVM(newAppState(), DefaultDynamicMemoryProvider, newParams(), Zero256, nil)
 
 	// Create accounts
 	account1 := &Account{
@@ -91,7 +91,7 @@ func TestVM(t *testing.T) {
 }
 
 func TestJumpErr(t *testing.T) {
-	ourVm := NewVM(newAppState(), newParams(), Zero256, nil)
+	ourVm := NewVM(newAppState(), DefaultDynamicMemoryProvider, newParams(), Zero256, nil)
 
 	// Create accounts
 	account1 := &Account{
@@ -134,7 +134,7 @@ func TestSubcurrency(t *testing.T) {
 	st.accounts[account1.Address.String()] = account1
 	st.accounts[account2.Address.String()] = account2
 
-	ourVm := NewVM(st, newParams(), Zero256, nil)
+	ourVm := NewVM(st, DefaultDynamicMemoryProvider, newParams(), Zero256, nil)
 
 	var gas int64 = 1000
 	code_parts := []string{"620f42403355",
@@ -156,7 +156,7 @@ func TestSubcurrency(t *testing.T) {
 // Test sending tokens from a contract to another account
 func TestSendCall(t *testing.T) {
 	fakeAppState := newAppState()
-	ourVm := NewVM(fakeAppState, newParams(), Zero256, nil)
+	ourVm := NewVM(fakeAppState, DefaultDynamicMemoryProvider, newParams(), Zero256, nil)
 
 	// Create accounts
 	account1 := &Account{
@@ -199,7 +199,7 @@ func TestSendCall(t *testing.T) {
 // 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)
+	ourVm := NewVM(appState, DefaultDynamicMemoryProvider, newParams(), Zero256, nil)
 
 	inOff := 0
 	inSize := 0 // no call data
@@ -255,6 +255,66 @@ func TestDelegateCallGas(t *testing.T) {
 	assert.Error(t, err, "Should have insufficient funds for call")
 }
 
+func TestMemoryBounds(t *testing.T) {
+	appState := newAppState()
+	memoryProvider := func() Memory {
+		return NewDynamicMemory(1024, 2048)
+	}
+	ourVm := NewVM(appState, memoryProvider, newParams(), Zero256, nil)
+	caller, _ := makeAccountWithCode(appState, "caller", nil)
+	callee, _ := makeAccountWithCode(appState, "callee", nil)
+	gas := int64(100000)
+	// This attempts to store a value at the memory boundary and return it
+	word := One256
+	output, err := ourVm.call(caller, callee,
+		Bytecode(pushWord(word), storeAtEnd(), MLOAD, storeAtEnd(), returnAfterStore()),
+		nil, 0, &gas)
+	assert.NoError(t, err)
+	assert.Equal(t, word.Bytes(), output)
+
+	// Same with number
+	word = Int64ToWord256(232234234432)
+	output, err = ourVm.call(caller, callee,
+		Bytecode(pushWord(word), storeAtEnd(), MLOAD, storeAtEnd(), returnAfterStore()),
+		nil, 0, &gas)
+	assert.NoError(t, err)
+	assert.Equal(t, word.Bytes(), output)
+
+	// Now test a series of boundary stores
+	code := pushWord(word)
+	for i := 0; i < 10; i++ {
+		code = Bytecode(code, storeAtEnd(), MLOAD)
+	}
+	output, err = ourVm.call(caller, callee, Bytecode(code, storeAtEnd(), returnAfterStore()),
+		nil, 0, &gas)
+	assert.NoError(t, err)
+	assert.Equal(t, word.Bytes(), output)
+
+	// Same as above but we should breach the upper memory limit set in memoryProvider
+	code = pushWord(word)
+	for i := 0; i < 100; i++ {
+		code = Bytecode(code, storeAtEnd(), MLOAD)
+	}
+	output, err = ourVm.call(caller, callee, Bytecode(code, storeAtEnd(), returnAfterStore()),
+		nil, 0, &gas)
+	assert.Error(t, err, "Should hit memory out of bounds")
+}
+
+// These code segment helpers exercise the MSTORE MLOAD MSTORE cycle to test
+// both of the memory operations. Each MSTORE is done on the memory boundary
+// (at MSIZE) which Solidity uses to find guaranteed unallocated memory.
+
+// storeAtEnd expects the value to be stored to be on top of the stack, it then
+// stores that value at the current memory boundary
+func storeAtEnd() []byte {
+	// Pull in MSIZE (to carry forward to MLOAD), swap in value to store, store it at MSIZE
+	return Bytecode(MSIZE, SWAP1, DUP2, MSTORE)
+}
+
+func returnAfterStore() []byte {
+	return Bytecode(PUSH1, 32, DUP2, RETURN)
+}
+
 // 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 {
@@ -346,6 +406,37 @@ func callContractCode(addr []byte) []byte {
 		PUSH1, retOff, RETURN)
 }
 
+func pushInt64(i int64) []byte {
+	return pushWord(Int64ToWord256(i))
+}
+
+// Produce bytecode for a PUSH<N>, b_1, ..., b_N where the N is number of bytes
+// contained in the unpadded word
+func pushWord(word Word256) []byte {
+	leadingZeros := byte(0)
+	for leadingZeros < 32 {
+		if word[leadingZeros] == 0 {
+			leadingZeros++
+		} else {
+			return Bytecode(byte(PUSH32)-leadingZeros, word[leadingZeros:])
+		}
+	}
+	return Bytecode(PUSH1, 0)
+}
+
+func TestPushWord(t *testing.T) {
+	word := Int64ToWord256(int64(2133213213))
+	assert.Equal(t, Bytecode(PUSH4, 0x7F, 0x26, 0x40, 0x1D), pushWord(word))
+	word[0] = 1
+	assert.Equal(t, Bytecode(PUSH32,
+		1, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0, 0, 0, 0,
+		0, 0, 0, 0, 0x7F, 0x26, 0x40, 0x1D), pushWord(word))
+	assert.Equal(t, Bytecode(PUSH1, 0), pushWord(Word256{}))
+	assert.Equal(t, Bytecode(PUSH1, 1), pushWord(Int64ToWord256(1)))
+}
+
 func TestBytecode(t *testing.T) {
 	assert.Equal(t,
 		Bytecode(1, 2, 3, 4, 5, 6),
diff --git a/manager/burrow-mint/pipe.go b/manager/burrow-mint/pipe.go
index 7091058285a45cb2f1de36770d1910bffc0449f6..b8315dd5ec765b20df182bb0f7ae3ddbe2cd2984 100644
--- a/manager/burrow-mint/pipe.go
+++ b/manager/burrow-mint/pipe.go
@@ -434,7 +434,8 @@ func (pipe *burrowMintPipe) Call(fromAddress, toAddress, data []byte) (*rpc_tm_t
 		GasLimit:    gasLimit,
 	}
 
-	vmach := vm.NewVM(txCache, params, caller.Address, nil)
+	vmach := vm.NewVM(txCache, vm.DefaultDynamicMemoryProvider, params,
+		caller.Address, nil)
 	gas := gasLimit
 	ret, err := vmach.Call(caller, callee, callee.Code, data, 0, &gas)
 	if err != nil {
@@ -461,7 +462,8 @@ func (pipe *burrowMintPipe) CallCode(fromAddress, code, data []byte) (*rpc_tm_ty
 		GasLimit:    gasLimit,
 	}
 
-	vmach := vm.NewVM(txCache, params, caller.Address, nil)
+	vmach := vm.NewVM(txCache, vm.DefaultDynamicMemoryProvider, params,
+		caller.Address, nil)
 	gas := gasLimit
 	ret, err := vmach.Call(caller, callee, code, data, 0, &gas)
 	if err != nil {
diff --git a/manager/burrow-mint/state/execution.go b/manager/burrow-mint/state/execution.go
index edda1cb7f0cf5d227d751c56b0391708982ef5bf..50745e1a35aabc74b0c4a0403f9b6f163673047e 100644
--- a/manager/burrow-mint/state/execution.go
+++ b/manager/burrow-mint/state/execution.go
@@ -515,7 +515,8 @@ func ExecTx(blockCache *BlockCache, tx txs.Tx, runCall bool, evc events.Fireable
 				// Write caller/callee to txCache.
 				txCache.UpdateAccount(caller)
 				txCache.UpdateAccount(callee)
-				vmach := vm.NewVM(txCache, params, caller.Address, txs.TxHash(_s.ChainID, tx))
+				vmach := vm.NewVM(txCache, vm.DefaultDynamicMemoryProvider, params,
+					caller.Address, txs.TxHash(_s.ChainID, tx))
 				vmach.SetFireable(evc)
 				// NOTE: Call() transfers the value from caller to callee iff call succeeds.
 				ret, err = vmach.Call(caller, callee, code, tx.Data, value, &gas)
diff --git a/manager/burrow-mint/transactor.go b/manager/burrow-mint/transactor.go
index f368f79cf3927e4368557911a5602aa258324121..3f73737b1def8ccc376b9ec2d2f438bb4ff7284a 100644
--- a/manager/burrow-mint/transactor.go
+++ b/manager/burrow-mint/transactor.go
@@ -85,7 +85,8 @@ func (this *transactor) Call(fromAddress, toAddress, data []byte) (
 		GasLimit:    gasLimit,
 	}
 
-	vmach := vm.NewVM(txCache, params, caller.Address, nil)
+	vmach := vm.NewVM(txCache, vm.DefaultDynamicMemoryProvider, params,
+		caller.Address, nil)
 	vmach.SetFireable(this.eventSwitch)
 	gas := gasLimit
 	ret, err := vmach.Call(caller, callee, callee.Code, data, 0, &gas)
@@ -118,7 +119,8 @@ func (this *transactor) CallCode(fromAddress, code, data []byte) (
 		GasLimit:    gasLimit,
 	}
 
-	vmach := vm.NewVM(txCache, params, caller.Address, nil)
+	vmach := vm.NewVM(txCache, vm.DefaultDynamicMemoryProvider, params,
+		caller.Address, nil)
 	gas := gasLimit
 	ret, err := vmach.Call(caller, callee, code, data, 0, &gas)
 	if err != nil {