diff --git a/openrpc/cmd/cli.go b/openrpc/cmd/cli.go
index ba7c40dfd8a6990700541757fc327794a8a93c48..f9962a887be718cdcb9fb52cf6eba9bc412bdd34 100644
--- a/openrpc/cmd/cli.go
+++ b/openrpc/cmd/cli.go
@@ -4,9 +4,10 @@ import "C"
 import (
 	"encoding/json"
 	"fmt"
-	"gfx.cafe/open/jrpc/openrpc/generate"
 	"os"
 
+	"gfx.cafe/open/jrpc/openrpc/generate"
+
 	"gfx.cafe/open/jrpc/openrpc/types"
 	"github.com/alecthomas/kong"
 )
@@ -28,9 +29,10 @@ func (c *CompileCommand) Run() error {
 }
 
 type GenerateCommand struct {
-	Spec      string   `name:"spec" short:"s" help:"path to jopenrpc spec"`
-	Output    string   `name:"output" short:"o" help:"output directory and package"`
-	Templates []string `name:"templates" short:"t" help:"list of template types to generate for"`
+	Spec     string `name:"spec" short:"s" help:"path to jopenrpc spec"`
+	Output   string `name:"output" short:"o" help:"output directory and package"`
+	Template string `name:"template" short:"t" help:"template to generate with"`
+	Package  string `name:"package" short:"p" default:"api" help:"package name"`
 }
 
 func (c *GenerateCommand) Run() error {
@@ -41,8 +43,9 @@ func (c *GenerateCommand) Run() error {
 	if err != nil {
 		return err
 	}
+	openrpc.Package = c.Package
 
-	if err = generate.Generate(openrpc, c.Templates, c.Output); err != nil {
+	if err = generate.Generate(openrpc, c.Template, c.Output); err != nil {
 		return err
 	}
 
diff --git a/openrpc/generate/generate.go b/openrpc/generate/generate.go
index c7268ed76d239019f4eef485dd780d58376700a5..6bb5a81a97602e368570da1e69c5325bc8cd8d80 100644
--- a/openrpc/generate/generate.go
+++ b/openrpc/generate/generate.go
@@ -3,12 +3,14 @@ package generate
 import (
 	"bytes"
 	"fmt"
-	"gfx.cafe/open/jrpc/openrpc/types"
-	"github.com/iancoleman/strcase"
 	"go/format"
 	"os"
+	"path"
 	"path/filepath"
 	"text/template"
+
+	"gfx.cafe/open/jrpc/openrpc/types"
+	"github.com/iancoleman/strcase"
 )
 
 var defaultTemplates = []string{
@@ -41,37 +43,29 @@ var funcs = template.FuncMap{
 	},
 }
 
-func Generate(rpc *types.OpenRPC, templates []string, output string) error {
-	if len(templates) == 0 {
-		templates = defaultTemplates
-	}
+func Generate(rpc *types.OpenRPC, ts string, output string) error {
 
 	var wr bytes.Buffer
-	for _, tmpl := range templates {
-		name := filepath.Base(tmpl)
-
-		t, err := template.New(name).Funcs(funcs).ParseFiles(tmpl)
-		if err != nil {
-			return err
-		}
+	t, err := template.New(path.Base(ts)).Funcs(funcs).ParseFiles(ts)
+	if err != nil {
+		return err
+	}
 
-		err = t.Execute(&wr, rpc)
-		if err != nil {
-			return err
-		}
+	err = t.Execute(&wr, rpc)
+	if err != nil {
+		return err
+	}
 
-		var fmtd []byte
-		fmtd, err = format.Source(wr.Bytes())
-		if err != nil {
-			return err
-		}
-		wr.Reset()
+	var fmtd []byte
+	fmtd, err = format.Source(wr.Bytes())
+	if err != nil {
+		return err
+	}
+	wr.Reset()
 
-		name = name[:len(name)-len(filepath.Ext(name))]
-		err = os.WriteFile(filepath.Join(output, name+".go"), fmtd, 0777)
-		if err != nil {
-			return err
-		}
+	err = os.WriteFile(output, fmtd, 0777)
+	if err != nil {
+		return err
 	}
 
 	return nil
diff --git a/openrpc/out/generate.go b/openrpc/out/generate.go
new file mode 100644
index 0000000000000000000000000000000000000000..56b417cec0e46d257997e74360f18f131e0e48f9
--- /dev/null
+++ b/openrpc/out/generate.go
@@ -0,0 +1,3 @@
+package out
+
+//go:generate go run gfx.cafe/open/jrpc/openrpc/cmd generate -p out -s generated_spec.json -o generated_api.go -t ../templates/types.gotmpl
diff --git a/openrpc/eth-api.json b/openrpc/out/generated_spec.json
similarity index 100%
rename from openrpc/eth-api.json
rename to openrpc/out/generated_spec.json
diff --git a/openrpc/out/server.go b/openrpc/out/server.go
deleted file mode 100644
index abb0ac1483bd83efbe7ecf7bec4192d4bfb7139d..0000000000000000000000000000000000000000
--- a/openrpc/out/server.go
+++ /dev/null
@@ -1,498 +0,0 @@
-// Code generated by go-openrpc. DO NOT EDIT.
-
-package main
-
-import (
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"net/http"
-	"reflect"
-)
-
-const JSONRPC = "2.0"
-
-type Code uint32
-
-const (
-	ErrUnknown Code = iota
-	ErrCouldNotParse
-	ErrInvalidRequest
-	ErrNotFound
-	ErrInvalidParams
-	ErrInternal
-	ErrServer
-)
-
-func (c Code) Error() string {
-	return fmt.Sprintf("Error %d: %s", c, c.String())
-}
-
-func (c Code) String() string {
-	switch c {
-	case ErrCouldNotParse:
-		return "could not parse input"
-	case ErrInvalidRequest:
-		return "invalid request"
-	case ErrNotFound:
-		return "not found"
-	case ErrInvalidParams:
-		return "invalid parameters"
-	case ErrInternal:
-		return "internal error"
-	case ErrServer:
-		return "server error"
-	default:
-		return "unknown error"
-	}
-}
-
-func (c Code) RPCError() *RPCError {
-	switch c {
-	case ErrCouldNotParse:
-		return NewRPCError(-32700, c.String())
-	case ErrInvalidRequest:
-		return NewRPCError(-32600, c.String())
-	case ErrNotFound:
-		return NewRPCError(-32601, c.String())
-	case ErrInvalidParams:
-		return NewRPCError(-32602, c.String())
-	case ErrInternal:
-		return NewRPCError(-32603, c.String())
-	case ErrServer:
-		return NewRPCError(-32000, c.String())
-	default:
-		return NewRPCError(-32099, c.String())
-	}
-}
-
-func (c Code) RPCErrorWithMessage(msg string) *RPCError {
-	resp := c.RPCError()
-	resp.Message = msg
-	return resp
-}
-
-// https://www.jsonrpc.org/specification#request_object
-type RPCRequest struct {
-	JSONRPC string          `json:"jsonrpc"`
-	Method  string          `json:"method"`
-	Params  json.RawMessage `json:"params"`
-	ID      interface{}     `json:"id"`
-}
-
-// https://www.jsonrpc.org/specification#response_object
-type RPCResultResponse struct {
-	JSONRPC string      `json:"jsonrpc"`
-	Result  interface{} `json:"result"`
-	ID      interface{} `json:"id"`
-}
-
-// https://www.jsonrpc.org/specification#response_object
-type RPCErrorResponse struct {
-	JSONRPC string      `json:"jsonrpc"`
-	Error   *RPCError   `json:"error"`
-	ID      interface{} `json:"id"`
-}
-
-// https://www.jsonrpc.org/specification#error_object
-type RPCError struct {
-	Code    int         `json:"code"`
-	Message string      `json:"message"`
-	Data    interface{} `json:"data,omitempty"`
-}
-
-func NewRPCError(code int, msg string) *RPCError {
-	return &RPCError{Code: code, Message: msg}
-}
-
-type Server struct {
-	service GoOpenRPCService
-}
-
-func NewServer(rpc GoOpenRPCService) *Server {
-	return &Server{rpc}
-}
-
-func (srv *Server) HandleHTTP(rpcPath string) {
-	http.Handle(rpcPath, srv)
-}
-
-// https://github.com/a8m/reflect-examples#wrap-a-reflectvalue-with-pointer-t--t
-func ptr(v reflect.Value) reflect.Value {
-	pt := reflect.PtrTo(v.Type())
-	pv := reflect.New(pt.Elem())
-	pv.Elem().Set(v)
-	return pv
-}
-
-func ParamsToStruct(msg json.RawMessage, req interface{}) error {
-	// by-name
-	err := json.Unmarshal(msg, req)
-	if err == nil {
-		return nil
-	}
-
-	// by-position
-	params := make([]json.RawMessage, 0)
-	err = json.Unmarshal(msg, &params)
-	if err != nil {
-		return err
-	}
-	val := reflect.ValueOf(req)
-	if val.Kind() == reflect.Ptr {
-		val = val.Elem()
-	}
-
-	for i, p := range params {
-		if i >= val.NumField() {
-			break
-		}
-		field := val.Field(i)
-		if field.CanSet() {
-			pf := ptr(field)
-			err = json.Unmarshal(p, pf.Interface())
-			if err != nil {
-				return err
-			}
-			field.Set(pf.Elem())
-		}
-	}
-	return nil
-}
-
-func StructToResult(in interface{}) interface{} {
-	val := reflect.ValueOf(in)
-	if val.Kind() == reflect.Ptr {
-		val = val.Elem()
-	}
-	if val.Kind() != reflect.Struct {
-		return in
-	}
-	if val.NumField() == 1 {
-		return val.Field(0).Interface()
-	} else if val.NumField() > 1 {
-		result := make([]interface{}, 0)
-		for i := 0; i < val.NumField(); i++ {
-			field := val.Field(i)
-			if val.Kind() == reflect.Ptr {
-				field = field.Elem()
-			}
-
-			if field.Kind() == reflect.Slice {
-				for i := 0; i < field.Len(); i++ {
-					result = append(result, field.Index(i).Interface())
-				}
-			} else if field.CanInterface() {
-				result = append(result, field.Interface())
-			}
-		}
-		return result
-	} else {
-		return nil
-	}
-}
-
-func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	if r.Method == http.MethodOptions {
-		w.Header().Set("Access-Control-Allow-Origin", "*")
-		w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET")
-		w.Header().Set("Access-Control-Allow-Headers", "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range")
-		w.Header().Set("Accept-Range", "bytes")
-		w.WriteHeader(http.StatusOK)
-		w.Write([]byte{})
-		return
-	} else if r.Method != http.MethodPost {
-		WriteError(w, "", ErrInternal.RPCError())
-		return
-	}
-
-	data, err := ioutil.ReadAll(r.Body)
-	if err != nil {
-		WriteError(w, nil, ErrInvalidRequest.RPCError())
-		return
-	}
-	r.Body.Close()
-
-	in := new(RPCRequest)
-	err = json.Unmarshal(data, in)
-	if err != nil {
-		WriteError(w, nil, ErrCouldNotParse.RPCError())
-		return
-	}
-
-	if in.JSONRPC != JSONRPC || in.Method == "" || in.ID == nil {
-		WriteError(w, nil, ErrInvalidParams.RPCError())
-		return
-	}
-
-	var out interface{}
-
-	switch in.Method {
-	case "debug_getRawHeader":
-		req := new(DebugGetRawHeaderParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.DebugGetRawHeader(req)
-		}
-	case "debug_getRawBlock":
-		req := new(DebugGetRawBlockParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.DebugGetRawBlock(req)
-		}
-	case "debug_getRawTransaction":
-		req := new(DebugGetRawTransactionParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.DebugGetRawTransaction(req)
-		}
-	case "debug_getRawReceipts":
-		req := new(DebugGetRawReceiptsParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.DebugGetRawReceipts(req)
-		}
-	case "debug_getBadBlocks":
-		out, err = srv.service.DebugGetBadBlocks()
-	case "eth_getBlockByHash":
-		req := new(EthGetBlockByHashParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetBlockByHash(req)
-		}
-	case "eth_getBlockByNumber":
-		req := new(EthGetBlockByNumberParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetBlockByNumber(req)
-		}
-	case "eth_getBlockTransactionCountByHash":
-		req := new(EthGetBlockTransactionCountByHashParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetBlockTransactionCountByHash(req)
-		}
-	case "eth_getBlockTransactionCountByNumber":
-		req := new(EthGetBlockTransactionCountByNumberParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetBlockTransactionCountByNumber(req)
-		}
-	case "eth_getUncleCountByBlockHash":
-		req := new(EthGetUncleCountByBlockHashParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetUncleCountByBlockHash(req)
-		}
-	case "eth_getUncleCountByBlockNumber":
-		req := new(EthGetUncleCountByBlockNumberParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetUncleCountByBlockNumber(req)
-		}
-	case "eth_chainId":
-		out, err = srv.service.EthChainId()
-	case "eth_syncing":
-		out, err = srv.service.EthSyncing()
-	case "eth_coinbase":
-		out, err = srv.service.EthCoinbase()
-	case "eth_accounts":
-		out, err = srv.service.EthAccounts()
-	case "eth_blockNumber":
-		out, err = srv.service.EthBlockNumber()
-	case "eth_call":
-		req := new(EthCallParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthCall(req)
-		}
-	case "eth_estimateGas":
-		req := new(EthEstimateGasParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthEstimateGas(req)
-		}
-	case "eth_createAccessList":
-		req := new(EthCreateAccessListParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthCreateAccessList(req)
-		}
-	case "eth_gasPrice":
-		out, err = srv.service.EthGasPrice()
-	case "eth_maxPriorityFeePerGas":
-		out, err = srv.service.EthMaxPriorityFeePerGas()
-	case "eth_feeHistory":
-		req := new(EthFeeHistoryParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthFeeHistory(req)
-		}
-	case "eth_newFilter":
-		req := new(EthNewFilterParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthNewFilter(req)
-		}
-	case "eth_newBlockFilter":
-		out, err = srv.service.EthNewBlockFilter()
-	case "eth_newPendingTransactionFilter":
-		out, err = srv.service.EthNewPendingTransactionFilter()
-	case "eth_uninstallFilter":
-		req := new(EthUninstallFilterParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthUninstallFilter(req)
-		}
-	case "eth_getFilterChanges":
-		req := new(EthGetFilterChangesParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetFilterChanges(req)
-		}
-	case "eth_getFilterLogs":
-		req := new(EthGetFilterLogsParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetFilterLogs(req)
-		}
-	case "eth_getLogs":
-		req := new(EthGetLogsParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetLogs(req)
-		}
-	case "eth_mining":
-		out, err = srv.service.EthMining()
-	case "eth_hashrate":
-		out, err = srv.service.EthHashrate()
-	case "eth_getWork":
-		out, err = srv.service.EthGetWork()
-	case "eth_submitWork":
-		req := new(EthSubmitWorkParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthSubmitWork(req)
-		}
-	case "eth_submitHashrate":
-		req := new(EthSubmitHashrateParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthSubmitHashrate(req)
-		}
-	case "eth_sign":
-		req := new(EthSignParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthSign(req)
-		}
-	case "eth_signTransaction":
-		req := new(EthSignTransactionParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthSignTransaction(req)
-		}
-	case "eth_getBalance":
-		req := new(EthGetBalanceParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetBalance(req)
-		}
-	case "eth_getStorageAt":
-		req := new(EthGetStorageAtParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetStorageAt(req)
-		}
-	case "eth_getTransactionCount":
-		req := new(EthGetTransactionCountParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetTransactionCount(req)
-		}
-	case "eth_getCode":
-		req := new(EthGetCodeParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetCode(req)
-		}
-	case "eth_getProof":
-		req := new(EthGetProofParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetProof(req)
-		}
-	case "eth_sendTransaction":
-		req := new(EthSendTransactionParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthSendTransaction(req)
-		}
-	case "eth_sendRawTransaction":
-		req := new(EthSendRawTransactionParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthSendRawTransaction(req)
-		}
-	case "eth_getTransactionByHash":
-		req := new(EthGetTransactionByHashParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetTransactionByHash(req)
-		}
-	case "eth_getTransactionByBlockHashAndIndex":
-		req := new(EthGetTransactionByBlockHashAndIndexParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetTransactionByBlockHashAndIndex(req)
-		}
-	case "eth_getTransactionByBlockNumberAndIndex":
-		req := new(EthGetTransactionByBlockNumberAndIndexParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetTransactionByBlockNumberAndIndex(req)
-		}
-	case "eth_getTransactionReceipt":
-		req := new(EthGetTransactionReceiptParams)
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			out, err = srv.service.EthGetTransactionReceipt(req)
-		}
-	}
-
-	if err != nil {
-		WriteError(w, in.ID, ErrInternal.RPCErrorWithMessage(err.Error()))
-		return
-	}
-
-	WriteData(w, in.ID, out)
-}
-
-func WriteError(w http.ResponseWriter, id interface{}, resp *RPCError) {
-	data, err := json.Marshal(&RPCErrorResponse{
-		JSONRPC: JSONRPC,
-		Error:   resp,
-		ID:      id,
-	})
-	if err != nil {
-		panic(err)
-	}
-	w.Header().Set("Content-Type", "application/json")
-	w.Write(data)
-}
-
-func WriteData(w http.ResponseWriter, id interface{}, result interface{}) {
-	resp := &RPCResultResponse{
-		JSONRPC: JSONRPC,
-		ID:      id,
-		Result:  StructToResult(result),
-	}
-	data, err := json.Marshal(resp)
-	if err != nil {
-		WriteError(w, id, ErrInternal.RPCError())
-		return
-	}
-	w.Header().Set("Content-Type", "application/json")
-	w.WriteHeader(http.StatusOK)
-	w.Write(data)
-}
diff --git a/openrpc/out/types.go b/openrpc/out/types.go
deleted file mode 100644
index 5beaa29865bbaa3fc0aaa3e9d4bc4be69980006b..0000000000000000000000000000000000000000
--- a/openrpc/out/types.go
+++ /dev/null
@@ -1,411 +0,0 @@
-// Code generated by go-openrpc. DO NOT EDIT.
-
-package main
-
-type GoOpenRPCService interface {
-	// Returns an RLP-encoded header.
-	DebugGetRawHeader(
-		Block BlockNumberOrTag,
-	) (HeaderRLP Bytes)
-	// Returns an RLP-encoded block.
-	DebugGetRawBlock(
-		Block BlockNumberOrTag,
-	) (BlockRLP Bytes)
-	// Returns an array of EIP-2718 binary-encoded transactions.
-	DebugGetRawTransaction(
-		TransactionHash Hash32,
-	) (EIP2718BinaryEncodedTransaction Bytes)
-	// Returns an array of EIP-2718 binary-encoded receipts.
-	DebugGetRawReceipts(
-		Block BlockNumberOrTag,
-	) (Receipts []Bytes)
-	// Returns an array of recent bad blocks that the client has seen on the network.
-	DebugGetBadBlocks() (Blocks []BadBlock)
-	// Returns information about a block by hash.
-	EthGetBlockByHash(
-		BlockHash Hash32,
-		HydratedTransactions bool,
-	) (BlockInformation Block)
-	// Returns information about a block by number.
-	EthGetBlockByNumber(
-		Block BlockNumberOrTag,
-		HydratedTransactions bool,
-	) (BlockInformation Block)
-	// Returns the number of transactions in a block from a block matching the given block hash.
-	EthGetBlockTransactionCountByHash(
-		BlockHash Hash32,
-	) (TransactionCount Uint)
-	// Returns the number of transactions in a block matching the given block number.
-	EthGetBlockTransactionCountByNumber(
-		Block BlockNumberOrTag,
-	) (TransactionCount Uint)
-	// Returns the number of uncles in a block from a block matching the given block hash.
-	EthGetUncleCountByBlockHash(
-		BlockHash Hash32,
-	) (UncleCount Uint)
-	// Returns the number of transactions in a block matching the given block number.
-	EthGetUncleCountByBlockNumber(
-		Block BlockNumberOrTag,
-	) (UncleCount Uint)
-	// Returns the chain ID of the current network.
-	EthChainId() (ChainID Uint)
-	// Returns an object with data about the sync status or false.
-	EthSyncing() (SyncingStatus SyncingStatus)
-	// Returns the client coinbase address.
-	EthCoinbase() (CoinbaseAddress Address)
-	// Returns a list of addresses owned by client.
-	EthAccounts() (Accounts []Address)
-	// Returns the number of most recent block.
-	EthBlockNumber() (BlockNumber Uint)
-	// Executes a new message call immediately without creating a transaction on the block chain.
-	EthCall(
-		Transaction GenericTransaction,
-		Block BlockNumberOrTag,
-	) (ReturnData Bytes)
-	// Generates and returns an estimate of how much gas is necessary to allow the transaction to complete.
-	EthEstimateGas(
-		Transaction GenericTransaction,
-		Block BlockNumberOrTag,
-	) (GasUsed Uint)
-	// Generates an access list for a transaction.
-	EthCreateAccessList(
-		Transaction GenericTransaction,
-		Block BlockNumberOrTag,
-	) (GasUsed struct {
-		AccessList AccessList `json:"accessList"`
-		Error      string     `json:"error"`
-		GasUsed    Uint       `json:"gasUsed"`
-	})
-	// Returns the current price per gas in wei.
-	EthGasPrice() (GasPrice Uint)
-	// Returns the current maxPriorityFeePerGas per gas in wei.
-	EthMaxPriorityFeePerGas() (MaxPriorityFeePerGas Uint)
-	// Transaction fee history
-	EthFeeHistory(
-		BlockCount Uint,
-		NewestBlock BlockNumberOrTag,
-		RewardPercentiles []float64,
-	) (FeeHistoryResult struct {
-		BaseFeePerGas []Uint   `json:"baseFeePerGas"`
-		OldestBlock   Uint     `json:"oldestBlock"`
-		Reward        [][]Uint `json:"reward"`
-	})
-	// Creates a filter object, based on filter options, to notify when the state changes (logs).
-	EthNewFilter(
-		Filter Filter,
-	) (FilterIdentifier Uint)
-	// Creates a filter in the node, to notify when a new block arrives.
-	EthNewBlockFilter() (FilterIdentifier Uint)
-	// Creates a filter in the node, to notify when new pending transactions arrive.
-	EthNewPendingTransactionFilter() (FilterIdentifier Uint)
-	// Uninstalls a filter with given id.
-	EthUninstallFilter(
-		FilterIdentifier Uint,
-	) (Success bool)
-	// Polling method for a filter, which returns an array of logs which occurred since last poll.
-	EthGetFilterChanges(
-		FilterIdentifier Uint,
-	) (LogObjects FilterResults)
-	// Returns an array of all logs matching filter with given id.
-	EthGetFilterLogs(
-		FilterIdentifier Uint,
-	) (LogObjects FilterResults)
-	// Returns an array of all logs matching filter with given id.
-	EthGetLogs(
-		Filter Filter,
-	) (LogObjects FilterResults)
-	// Returns whether the client is actively mining new blocks.
-	EthMining() (MiningStatus bool)
-	// Returns the number of hashes per second that the node is mining with.
-	EthHashrate() (MiningStatus Uint)
-	// Returns the hash of the current block, the seedHash, and the boundary condition to be met (“target”).
-	EthGetWork() (CurrentWork []Bytes32)
-	// Used for submitting a proof-of-work solution.
-	EthSubmitWork(
-		Nonce Bytes8,
-		Hash Bytes32,
-		Digest Bytes32,
-	) (Success bool)
-	// Used for submitting mining hashrate.
-	EthSubmitHashrate(
-		Hashrate Bytes32,
-		Id Bytes32,
-	) (Success bool)
-	// Returns an EIP-191 signature over the provided data.
-	EthSign(
-		Address Address,
-		Message Bytes,
-	) (Signature Bytes65)
-	// Returns an RLP encoded transaction signed by the specified account.
-	EthSignTransaction(
-		Transaction GenericTransaction,
-	) (EncodedTransaction Bytes)
-	// Returns the balance of the account of given address.
-	EthGetBalance(
-		Address Address,
-		Block BlockNumberOrTag,
-	) (Balance Uint)
-	// Returns the value from a storage position at a given address.
-	EthGetStorageAt(
-		Address Address,
-		StorageSlot Uint256,
-		Block BlockNumberOrTag,
-	) (Value Bytes)
-	// Returns the number of transactions sent from an address.
-	EthGetTransactionCount(
-		Address Address,
-		Block BlockNumberOrTag,
-	) (TransactionCount Uint)
-	// Returns code at a given address.
-	EthGetCode(
-		Address Address,
-		Block BlockNumberOrTag,
-	) (Bytecode Bytes)
-	// Returns the merkle proof for a given account and optionally some storage keys.
-	EthGetProof(
-		Address Address,
-		StorageKeys []Hash32,
-		Block BlockNumberOrTag,
-	) (Account AccountProof)
-	// Signs and submits a transaction.
-	EthSendTransaction(
-		Transaction GenericTransaction,
-	) (TransactionHash Hash32)
-	// Submits a raw transaction.
-	EthSendRawTransaction(
-		Transaction Bytes,
-	) (TransactionHash Hash32)
-	// Returns the information about a transaction requested by transaction hash.
-	EthGetTransactionByHash(
-		TransactionHash Hash32,
-	) (TransactionInformation TransactionInfo)
-	// Returns information about a transaction by block hash and transaction index position.
-	EthGetTransactionByBlockHashAndIndex(
-		BlockHash Hash32,
-		TransactionIndex Uint,
-	) (TransactionInformation TransactionInfo)
-	// Returns information about a transaction by block number and transaction index position.
-	EthGetTransactionByBlockNumberAndIndex(
-		Block BlockNumberOrTag,
-		TransactionIndex Uint,
-	) (TransactionInformation TransactionInfo)
-	// Returns the receipt of a transaction by transaction hash.
-	EthGetTransactionReceipt(
-		TransactionHash Hash32,
-	) (ReceiptInformation ReceiptInfo)
-}
-type AccessList []AccessListEntry
-type AccessListEntry struct {
-	Address     Address  `json:"address"`
-	StorageKeys []Hash32 `json:"storageKeys"`
-}
-type AccountProof struct {
-	AccountProof []Bytes        `json:"accountProof"`
-	Address      Address        `json:"address"`
-	Balance      Uint256        `json:"balance"`
-	CodeHash     Hash32         `json:"codeHash"`
-	Nonce        Uint64         `json:"nonce"`
-	StorageHash  Hash32         `json:"storageHash"`
-	StorageProof []StorageProof `json:"storageProof"`
-}
-type BadBlock struct {
-	Block Bytes  `json:"block"`
-	Hash  Hash32 `json:"hash"`
-	Rlp   Bytes  `json:"rlp"`
-}
-type Block struct {
-	BaseFeePerGas   Uint     `json:"baseFeePerGas"`
-	Difficulty      Bytes    `json:"difficulty"`
-	ExtraData       Bytes    `json:"extraData"`
-	GasLimit        Uint     `json:"gasLimit"`
-	GasUsed         Uint     `json:"gasUsed"`
-	LogsBloom       Bytes256 `json:"logsBloom"`
-	Miner           Address  `json:"miner"`
-	MixHash         Hash32   `json:"mixHash"`
-	Nonce           Bytes8   `json:"nonce"`
-	Number          Uint     `json:"number"`
-	ParentHash      Hash32   `json:"parentHash"`
-	ReceiptsRoot    Hash32   `json:"receiptsRoot"`
-	Sha3Uncles      Hash32   `json:"sha3Uncles"`
-	Size            Uint     `json:"size"`
-	StateRoot       Hash32   `json:"stateRoot"`
-	Timestamp       Uint     `json:"timestamp"`
-	TotalDifficulty Uint     `json:"totalDifficulty"`
-	Transactions    struct {
-		Option0 []Hash32
-		Option1 []TransactionSigned
-	} `json:"transactions"`
-	TransactionsRoot Hash32   `json:"transactionsRoot"`
-	Uncles           []Hash32 `json:"uncles"`
-}
-type BlockNumberOrTag struct {
-	Option0 Uint
-	Option1 BlockTag
-}
-type BlockTag string
-type Filter struct {
-	Address struct {
-		Option0 Address
-		Option1 Addresses
-	} `json:"address"`
-	FromBlock Uint         `json:"fromBlock"`
-	ToBlock   Uint         `json:"toBlock"`
-	Topics    FilterTopics `json:"topics"`
-}
-type FilterResults struct {
-	Option0 []Hash32
-	Option1 []Hash32
-	Option2 []Log
-}
-type FilterTopic struct {
-	Option0 struct{}
-	Option1 Bytes32
-	Option2 []Bytes32
-}
-type FilterTopics []FilterTopic
-type GenericTransaction struct {
-	AccessList           AccessList `json:"accessList"`
-	ChainId              Uint       `json:"chainId"`
-	From                 Address    `json:"from"`
-	Gas                  Uint       `json:"gas"`
-	GasPrice             Uint       `json:"gasPrice"`
-	Input                Bytes      `json:"input"`
-	MaxFeePerGas         Uint       `json:"maxFeePerGas"`
-	MaxPriorityFeePerGas Uint       `json:"maxPriorityFeePerGas"`
-	Nonce                Uint       `json:"nonce"`
-	To                   Address    `json:"to"`
-	Type                 Byte       `json:"type"`
-	Value                Uint       `json:"value"`
-}
-type Log struct {
-	Address          Address   `json:"address"`
-	BlockHash        Hash32    `json:"blockHash"`
-	BlockNumber      Uint      `json:"blockNumber"`
-	Data             Bytes     `json:"data"`
-	LogIndex         Uint      `json:"logIndex"`
-	Removed          bool      `json:"removed"`
-	Topics           []Bytes32 `json:"topics"`
-	TransactionHash  Hash32    `json:"transactionHash"`
-	TransactionIndex Uint      `json:"transactionIndex"`
-}
-type ReceiptInfo struct {
-	BlockHash       Hash32 `json:"blockHash"`
-	BlockNumber     Uint   `json:"blockNumber"`
-	ContractAddress struct {
-		Option0 Address
-		Option1 struct{}
-	} `json:"contractAddress"`
-	CumulativeGasUsed Uint     `json:"cumulativeGasUsed"`
-	EffectiveGasPrice Uint     `json:"effectiveGasPrice"`
-	From              Address  `json:"from"`
-	GasUsed           Uint     `json:"gasUsed"`
-	Logs              []Log    `json:"logs"`
-	LogsBloom         Bytes256 `json:"logsBloom"`
-	Root              Bytes32  `json:"root"`
-	Status            Uint     `json:"status"`
-	To                Address  `json:"to"`
-	TransactionHash   Hash32   `json:"transactionHash"`
-	TransactionIndex  Uint     `json:"transactionIndex"`
-}
-type StorageProof struct {
-	Key   Hash32  `json:"key"`
-	Proof []Bytes `json:"proof"`
-	Value Uint256 `json:"value"`
-}
-type SyncingStatus struct {
-	Option0 struct {
-		CurrentBlock  Uint `json:"currentBlock"`
-		HighestBlock  Uint `json:"highestBlock"`
-		StartingBlock Uint `json:"startingBlock"`
-	}
-	Option1 bool
-}
-type Transaction1559Signed struct {
-	Field0 Transaction1559Unsigned
-	Field1 struct {
-		R       Uint `json:"r"`
-		S       Uint `json:"s"`
-		YParity Uint `json:"yParity"`
-	}
-}
-type Transaction1559Unsigned struct {
-	AccessList           AccessList `json:"accessList"`
-	ChainId              Uint       `json:"chainId"`
-	Gas                  Uint       `json:"gas"`
-	Input                Bytes      `json:"input"`
-	MaxFeePerGas         Uint       `json:"maxFeePerGas"`
-	MaxPriorityFeePerGas Uint       `json:"maxPriorityFeePerGas"`
-	Nonce                Uint       `json:"nonce"`
-	To                   Address    `json:"to"`
-	Type                 Byte       `json:"type"`
-	Value                Uint       `json:"value"`
-}
-type Transaction2930Signed struct {
-	Field0 Transaction2930Unsigned
-	Field1 struct {
-		R       Uint `json:"r"`
-		S       Uint `json:"s"`
-		YParity Uint `json:"yParity"`
-	}
-}
-type Transaction2930Unsigned struct {
-	AccessList AccessList `json:"accessList"`
-	ChainId    Uint       `json:"chainId"`
-	Gas        Uint       `json:"gas"`
-	GasPrice   Uint       `json:"gasPrice"`
-	Input      Bytes      `json:"input"`
-	Nonce      Uint       `json:"nonce"`
-	To         Address    `json:"to"`
-	Type       Byte       `json:"type"`
-	Value      Uint       `json:"value"`
-}
-type TransactionInfo struct {
-	Field0 struct {
-		BlockHash        Hash32  `json:"blockHash"`
-		BlockNumber      Uint    `json:"blockNumber"`
-		From             Address `json:"from"`
-		Hash             Hash32  `json:"hash"`
-		TransactionIndex Uint    `json:"transactionIndex"`
-	}
-	Field1 TransactionSigned
-}
-type TransactionLegacySigned struct {
-	Field0 TransactionLegacyUnsigned
-	Field1 struct {
-		R Uint `json:"r"`
-		S Uint `json:"s"`
-		V Uint `json:"v"`
-	}
-}
-type TransactionLegacyUnsigned struct {
-	ChainId  Uint    `json:"chainId"`
-	Gas      Uint    `json:"gas"`
-	GasPrice Uint    `json:"gasPrice"`
-	Input    Bytes   `json:"input"`
-	Nonce    Uint    `json:"nonce"`
-	To       Address `json:"to"`
-	Type     Byte    `json:"type"`
-	Value    Uint    `json:"value"`
-}
-type TransactionSigned struct {
-	Option0 Transaction1559Signed
-	Option1 Transaction2930Signed
-	Option2 TransactionLegacySigned
-}
-type TransactionUnsigned struct {
-	Option0 Transaction1559Unsigned
-	Option1 Transaction2930Unsigned
-	Option2 TransactionLegacyUnsigned
-}
-type Address string
-type Addresses []Address
-type Byte string
-type Bytes string
-type Bytes256 string
-type Bytes32 string
-type Bytes65 string
-type Bytes8 string
-type Hash32 string
-type Uint string
-type Uint256 string
-type Uint64 string
diff --git a/openrpc/templates/example-proxy-server.gotmpl b/openrpc/templates/example-proxy-server.gotmpl
deleted file mode 100644
index c7bb4755e1a9e2bff4394278e8777a67b92d3fdc..0000000000000000000000000000000000000000
--- a/openrpc/templates/example-proxy-server.gotmpl
+++ /dev/null
@@ -1,163 +0,0 @@
-// Code generated by go-openrpc. DO NOT EDIT.
-
-// This example program starts a basic HTTP server that would act as a proxy
-// to the upstream server described by an Open-RPC configuration.
-
-package main
-
-import (
-	"log"
-	"net/http"
-	rpct "github.com/gregdhill/go-openrpc/rpc"
-	"encoding/json"
-	"reflect"
-	"bytes"
-	"io/ioutil"
-)
-
-
-// https://github.com/a8m/reflect-examples#wrap-a-reflectvalue-with-pointer-t--t
-func ptr(v reflect.Value) reflect.Value {
-	pt := reflect.PtrTo(v.Type())
-	pv := reflect.New(pt.Elem())
-	pv.Elem().Set(v)
-	return pv
-}
-
-func ResultToStruct(msg json.RawMessage, res interface{}) error {
-	var err error
-	val := reflect.ValueOf(res)
-	if val.Kind() == reflect.Ptr {
-		val = val.Elem()
-	}
-	// Get first (and only field)
-	field := val.Field(0)
-	if field.CanSet() {
-		pf := ptr(field)
-		err = json.Unmarshal(msg, pf.Interface())
-		if err != nil {
-			return err
-		}
-		field.Set(pf.Elem())
-	}
-	return nil
-}
-
-var gethClientRPC string
-
-type exampleRPCService struct{}
-
-{{- range .Methods }}
-{{- $name := .Name | camelCase }}
-{{- $params := (maybeMethodParams .) }}
-{{- $result := (maybeMethodResult .) }}
-{{- $method := printf "%s" $name }}
-{{- $original_method := printf "%s" $name }}
-{{- if $params }}
-{{- $method = printf "%s(params *rpct.%s)" $method $params }}
-{{- else }}
-{{- $method = printf "%s()" $method }}
-{{- end }}
-{{- if $result }}
-{{- $method = printf "%s (result *rpct.%s, err error)" $method $result }}
-{{- else }}
-{{- $method = printf "%s error" $method $result }}
-{{- end }}
-{{ printf "func (s *exampleRPCService) %s {" $method }}
-{{- if $params }}
-{{ printf "defer log.Println(\"%s\", \"params=\", params)" .Name }}
-{{- end }}
-{{ printf "defer log.Println(`%s`)" .Name }}
-
-req := rpct.RPCRequest{
-		JSONRPC: "2.0",
-		Method:  "{{ .Name }}",
-		Params:  []byte("[]"),
-		ID:      1,
-	}
-
-{{- if $params }}
-	if params != nil {
-		set := []interface{}{}
-		val := reflect.ValueOf(params).Elem()
-
-		for i := 0; i < val.NumField(); i++ {
-			valField := val.Field(i)
-			set = append(set, valField.Interface())
-		}
-
-		b, err := json.Marshal(set)
-		if err != nil {
-			return nil, err
-		}
-
-		req.Params = b
-	}
-{{- end }}
-
-	reqB, err := json.Marshal(&req)
-	if err != nil {
-		return nil, err
-	}
-  log.Println("posting", string(reqB))
-	buf := bytes.NewBuffer(reqB)
-	res, err := http.Post(gethClientRPC, "application/json", buf)
-	if err != nil {
-    log.Println("POST error:", err)
-		return nil, err
-	}
-
-{{- if $result }}
-
-	gotB, err := ioutil.ReadAll(res.Body)
-	if err != nil {
-    log.Println("read body error:", err)
-		return nil, err
-	}
-
-  // TODO: handle server error response
-
-  gotRes := &struct{
-    JSONRPC string      `json:"jsonrpc"`
-    Result  json.RawMessage `json:"result"`
-    ID      interface{} `json:"id"`
-  }{}
-
-	err = json.Unmarshal(gotB, gotRes)
-	if err != nil {
-    log.Println("json unmarshal error:", err, "data", string(gotB))
-		return nil, err
-	}
-  log.Println("received OK response:", string(gotB))
-
-  wantRes := new(rpct.{{ $result }})
-  err = ResultToStruct(gotRes.Result, wantRes)
-  if err != nil {
-    log.Println("result to struct error:", err, "result", gotRes.Result)
-    return nil, err
-  }
-
-	return wantRes, nil
-
-{{- else }}
-
-  return
-
-{{- end }}
-
-{{ printf "%s" "}" }}
-{{- end }}
-
-func main() {
-     gethClientRPC = "http://localhost:8545"
-     service := new(exampleRPCService)
-     server := rpct.NewServer(service)
-
-     s := http.Server{
-       Addr: ":3000",
-       Handler: server,
-     }
-     log.Println("Expecting upstream eth RPC endpoint at", gethClientRPC)
-     log.Println("Serving on http://localhost:3000 ...")
-     log.Fatal(s.ListenAndServe())
-}
\ No newline at end of file
diff --git a/openrpc/templates/server.gotmpl b/openrpc/templates/server.gotmpl
deleted file mode 100644
index e5f07ddf73f9c64eb5428772b17ab4d01d677016..0000000000000000000000000000000000000000
--- a/openrpc/templates/server.gotmpl
+++ /dev/null
@@ -1,293 +0,0 @@
-// Code generated by go-openrpc. DO NOT EDIT.
-
-package main
-
-import (
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"net/http"
-	"reflect"
-)
-
-const JSONRPC = "2.0"
-
-type Code uint32
-
-const (
-	ErrUnknown Code = iota
-	ErrCouldNotParse
-	ErrInvalidRequest
-	ErrNotFound
-	ErrInvalidParams
-	ErrInternal
-	ErrServer
-)
-
-func (c Code) Error() string {
-	return fmt.Sprintf("Error %d: %s", c, c.String())
-}
-
-func (c Code) String() string {
-	switch c {
-	case ErrCouldNotParse:
-		return "could not parse input"
-	case ErrInvalidRequest:
-		return "invalid request"
-	case ErrNotFound:
-		return "not found"
-	case ErrInvalidParams:
-		return "invalid parameters"
-	case ErrInternal:
-		return "internal error"
-	case ErrServer:
-		return "server error"
-	default:
-		return "unknown error"
-	}
-}
-
-func (c Code) RPCError() *RPCError {
-	switch c {
-	case ErrCouldNotParse:
-		return NewRPCError(-32700, c.String())
-	case ErrInvalidRequest:
-		return NewRPCError(-32600, c.String())
-	case ErrNotFound:
-		return NewRPCError(-32601, c.String())
-	case ErrInvalidParams:
-		return NewRPCError(-32602, c.String())
-	case ErrInternal:
-		return NewRPCError(-32603, c.String())
-	case ErrServer:
-		return NewRPCError(-32000, c.String())
-	default:
-		return NewRPCError(-32099, c.String())
-	}
-}
-
-func (c Code) RPCErrorWithMessage(msg string) *RPCError {
-	resp := c.RPCError()
-	resp.Message = msg
-	return resp
-}
-
-// https://www.jsonrpc.org/specification#request_object
-type RPCRequest struct {
-	JSONRPC string          `json:"jsonrpc"`
-	Method  string          `json:"method"`
-	Params  json.RawMessage `json:"params"`
-	ID      interface{}    	`json:"id"`
-}
-
-// https://www.jsonrpc.org/specification#response_object
-type RPCResultResponse struct {
-	JSONRPC string      `json:"jsonrpc"`
-	Result  interface{} `json:"result"`
-	ID      interface{} `json:"id"`
-}
-
-// https://www.jsonrpc.org/specification#response_object
-type RPCErrorResponse struct {
-	JSONRPC string    	`json:"jsonrpc"`
-	Error   *RPCError 	`json:"error"`
-	ID      interface{} `json:"id"`
-}
-
-// https://www.jsonrpc.org/specification#error_object
-type RPCError struct {
-	Code    int         `json:"code"`
-	Message string      `json:"message"`
-	Data    interface{} `json:"data,omitempty"`
-}
-
-func NewRPCError(code int, msg string) *RPCError {
-	return &RPCError{Code: code, Message: msg}
-}
-
-type Server struct {
-	service GoOpenRPCService
-}
-
-func NewServer(rpc GoOpenRPCService) *Server {
-	return &Server{rpc}
-}
-
-func (srv *Server) HandleHTTP(rpcPath string) {
-	http.Handle(rpcPath, srv)
-}
-
-// https://github.com/a8m/reflect-examples#wrap-a-reflectvalue-with-pointer-t--t
-func ptr(v reflect.Value) reflect.Value {
-	pt := reflect.PtrTo(v.Type())
-	pv := reflect.New(pt.Elem())
-	pv.Elem().Set(v)
-	return pv
-}
-
-func ParamsToStruct(msg json.RawMessage, req interface{}) error {
-	// by-name
-	err := json.Unmarshal(msg, req)
-	if err == nil {
-		return nil
-	}
-
-	// by-position
-	params := make([]json.RawMessage, 0)
-	err = json.Unmarshal(msg, &params)
-	if err != nil {
-		return err
-	}
-	val := reflect.ValueOf(req)
-	if val.Kind() == reflect.Ptr {
-		val = val.Elem()
-	}
-
-	for i, p := range params {
-		if i >= val.NumField() {
-			break
-		}
-		field := val.Field(i)
-		if field.CanSet() {
-			pf := ptr(field)
-			err = json.Unmarshal(p, pf.Interface())
-			if err != nil {
-				return err
-			}
-			field.Set(pf.Elem())
-		}
-	}
-	return nil
-}
-
-func StructToResult(in interface{}) interface{} {
-	val := reflect.ValueOf(in)
-	if val.Kind() == reflect.Ptr {
-		val = val.Elem()
-	}
-	if val.Kind() != reflect.Struct {
-		return in
-	}
-	if val.NumField() == 1 {
-		return val.Field(0).Interface()
-	} else if val.NumField() > 1 {
-		result := make([]interface{}, 0)
-		for i := 0; i < val.NumField(); i++ {
-			field := val.Field(i)
-			if val.Kind() == reflect.Ptr {
-				field = field.Elem()
-			}
-
-			if field.Kind() == reflect.Slice {
-				for i := 0; i < field.Len(); i++ {
-					result = append(result, field.Index(i).Interface())
-				}
-			} else if field.CanInterface() {
-				result = append(result, field.Interface())
-			}
-		}
-		return result
-	} else {
-		return nil
-	}
-}
-
-func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	if r.Method == http.MethodOptions {
-		w.Header().Set("Access-Control-Allow-Origin", "*")
-		w.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET")
-		w.Header().Set("Access-Control-Allow-Headers", "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range")
-		w.Header().Set("Accept-Range", "bytes")
-		w.WriteHeader(http.StatusOK)
-		w.Write([]byte{})
-		return
-	} else if r.Method != http.MethodPost {
-		WriteError(w, "", ErrInternal.RPCError())
-		return
-	}
-
-	data, err := ioutil.ReadAll(r.Body)
-	if err != nil {
-		WriteError(w, nil, ErrInvalidRequest.RPCError())
-		return
-	}
-	r.Body.Close()
-
-	in := new(RPCRequest)
-	err = json.Unmarshal(data, in)
-	if err != nil {
-		WriteError(w, nil, ErrCouldNotParse.RPCError())
-		return
-	}
-
-	if in.JSONRPC != JSONRPC || in.Method == "" || in.ID == nil {
-		WriteError(w, nil, ErrInvalidParams.RPCError())
-		return
-	}
-
-	var out interface{}
-
-	switch in.Method {
-	{{- range .Methods }}
-	case "{{ .Name }}":
-	{{- $name := .Name | camelCase }}
-	{{- $params := maybeMethodParams . }}
-	{{- $result := maybeMethodResult . }}
-
-	{{- if $params }}
-		req := new({{ $params }})
-		err = ParamsToStruct(in.Params, req)
-		if err == nil {
-			{{- if $result }}
-			out, err = srv.service.{{ $name }}(req)
-			{{- else }}
-			err = srv.service.{{ $name }}(req)
-			{{- end }}
-		}
-	{{- else }}
-		{{- if $result }}
-		out, err = srv.service.{{ $name }}()
-		{{- else }}
-		err = srv.service.{{ $name }}()
-		{{- end }}
-	{{- end }}
-
-	{{- end }}
-	}
-
-	if err != nil {
-		WriteError(w, in.ID, ErrInternal.RPCErrorWithMessage(err.Error()))
-		return
-	}
-
-	WriteData(w, in.ID, out)
-}
-
-func WriteError(w http.ResponseWriter, id interface{}, resp *RPCError) {
-	data, err := json.Marshal(&RPCErrorResponse{
-		JSONRPC: JSONRPC,
-		Error:   resp,
-		ID:      id,
-	})
-	if err != nil {
-		panic(err)
-	}
-	w.Header().Set("Content-Type", "application/json")
-	w.Write(data)
-}
-
-func WriteData(w http.ResponseWriter, id interface{}, result interface{}) {
-	resp := &RPCResultResponse{
-		JSONRPC: JSONRPC,
-		ID:      id,
-		Result:  StructToResult(result),
-	}
-	data, err := json.Marshal(resp)
-	if err != nil {
-		WriteError(w, id, ErrInternal.RPCError())
-		return
-	}
-	w.Header().Set("Content-Type", "application/json")
-	w.WriteHeader(http.StatusOK)
-	w.Write(data)
-}
\ No newline at end of file
diff --git a/openrpc/templates/types.gotmpl b/openrpc/templates/types.gotmpl
index 949bfaa1893f71e594094b6c195f16c828b28763..03f539a7a2b4a64f91758e31bb1546d06a81880d 100644
--- a/openrpc/templates/types.gotmpl
+++ b/openrpc/templates/types.gotmpl
@@ -1,6 +1,6 @@
 // Code generated by go-openrpc. DO NOT EDIT.
 
-package main
+package {{ .Package }}
 
 {{define "schemaType" -}}
     {{if not (eq .Ref "") -}}
diff --git a/openrpc/types/types.go b/openrpc/types/types.go
index f8461de6c2e1ce98728fa0b96b15569ee1b0c75e..31afcc706009658b7fa11e7f81d1be224b9e0b41 100644
--- a/openrpc/types/types.go
+++ b/openrpc/types/types.go
@@ -62,6 +62,7 @@ type Method struct {
 }
 
 type OpenRPC struct {
+	Package    string   `json:"package"`
 	Version    string   `json:"openrpc"`
 	Info       Info     `json:"info"`
 	Methods    []Method `json:"methods"`