github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/evm/handler/handler.go (about)

     1  package handler
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"github.com/onflow/cadence/runtime/common"
     7  	gethCommon "github.com/onflow/go-ethereum/common"
     8  	gethTypes "github.com/onflow/go-ethereum/core/types"
     9  
    10  	"github.com/onflow/flow-go/fvm/environment"
    11  	fvmErrors "github.com/onflow/flow-go/fvm/errors"
    12  	"github.com/onflow/flow-go/fvm/evm/handler/coa"
    13  	"github.com/onflow/flow-go/fvm/evm/types"
    14  	"github.com/onflow/flow-go/model/flow"
    15  )
    16  
    17  // ContractHandler is responsible for triggering calls to emulator, metering,
    18  // event emission and updating the block
    19  type ContractHandler struct {
    20  	flowChainID        flow.ChainID
    21  	evmContractAddress flow.Address
    22  	flowTokenAddress   common.Address
    23  	blockStore         types.BlockStore
    24  	addressAllocator   types.AddressAllocator
    25  	backend            types.Backend
    26  	emulator           types.Emulator
    27  	precompiles        []types.Precompile
    28  }
    29  
    30  func (h *ContractHandler) FlowTokenAddress() common.Address {
    31  	return h.flowTokenAddress
    32  }
    33  
    34  func (h *ContractHandler) EVMContractAddress() common.Address {
    35  	return common.Address(h.evmContractAddress)
    36  }
    37  
    38  var _ types.ContractHandler = &ContractHandler{}
    39  
    40  func NewContractHandler(
    41  	flowChainID flow.ChainID,
    42  	evmContractAddress flow.Address,
    43  	flowTokenAddress common.Address,
    44  	randomBeaconAddress flow.Address,
    45  	blockStore types.BlockStore,
    46  	addressAllocator types.AddressAllocator,
    47  	backend types.Backend,
    48  	emulator types.Emulator,
    49  ) *ContractHandler {
    50  	return &ContractHandler{
    51  		flowChainID:        flowChainID,
    52  		evmContractAddress: evmContractAddress,
    53  		flowTokenAddress:   flowTokenAddress,
    54  		blockStore:         blockStore,
    55  		addressAllocator:   addressAllocator,
    56  		backend:            backend,
    57  		emulator:           emulator,
    58  		precompiles:        preparePrecompiles(evmContractAddress, randomBeaconAddress, addressAllocator, backend),
    59  	}
    60  }
    61  
    62  // DeployCOA deploys a cadence-owned-account and returns the address
    63  func (h *ContractHandler) DeployCOA(uuid uint64) types.Address {
    64  	res, err := h.deployCOA(uuid)
    65  	panicOnErrorOrInvalidOrFailedState(res, err)
    66  	return *res.DeployedContractAddress
    67  }
    68  
    69  func (h *ContractHandler) deployCOA(uuid uint64) (*types.Result, error) {
    70  	target := h.addressAllocator.AllocateCOAAddress(uuid)
    71  	gaslimit := types.GasLimit(coa.ContractDeploymentRequiredGas)
    72  	err := h.checkGasLimit(gaslimit)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	factory := h.addressAllocator.COAFactoryAddress()
    78  	factoryAccount := h.AccountByAddress(factory, false)
    79  	call := types.NewDeployCallWithTargetAddress(
    80  		factory,
    81  		target,
    82  		coa.ContractBytes,
    83  		uint64(gaslimit),
    84  		new(big.Int),
    85  		factoryAccount.Nonce(),
    86  	)
    87  
    88  	ctx, err := h.getBlockContext()
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	return h.executeAndHandleCall(ctx, call, nil, false)
    93  }
    94  
    95  // AccountByAddress returns the account for the given address,
    96  // if isAuthorized is set, account is controlled by the FVM (COAs)
    97  func (h *ContractHandler) AccountByAddress(addr types.Address, isAuthorized bool) types.Account {
    98  	return newAccount(h, addr, isAuthorized)
    99  }
   100  
   101  // LastExecutedBlock returns the last executed block
   102  func (h *ContractHandler) LastExecutedBlock() *types.Block {
   103  	block, err := h.blockStore.LatestBlock()
   104  	panicOnError(err)
   105  	return block
   106  }
   107  
   108  // RunOrPanic runs an rlpencoded evm transaction and
   109  // collects the gas fees and pay it to the coinbase address provided.
   110  func (h *ContractHandler) RunOrPanic(rlpEncodedTx []byte, coinbase types.Address) {
   111  	res, err := h.run(rlpEncodedTx, coinbase)
   112  	panicOnErrorOrInvalidOrFailedState(res, err)
   113  }
   114  
   115  // Run tries to run an rlpencoded evm transaction and
   116  // collects the gas fees and pay it to the coinbase address provided.
   117  func (h *ContractHandler) Run(rlpEncodedTx []byte, coinbase types.Address) *types.ResultSummary {
   118  	res, err := h.run(rlpEncodedTx, coinbase)
   119  	panicOnError(err)
   120  	return res.ResultSummary()
   121  }
   122  
   123  // BatchRun tries to run batch of rlp-encoded transactions and
   124  // collects the gas fees and pay it to the coinbase address provided.
   125  // All transactions provided in the batch are included in a single block,
   126  // except for invalid transactions
   127  func (h *ContractHandler) BatchRun(rlpEncodedTxs [][]byte, coinbase types.Address) []*types.ResultSummary {
   128  	res, err := h.batchRun(rlpEncodedTxs, coinbase)
   129  	panicOnError(err)
   130  
   131  	resSummary := make([]*types.ResultSummary, len(res))
   132  	for i, r := range res {
   133  		resSummary[i] = r.ResultSummary()
   134  	}
   135  	return resSummary
   136  }
   137  
   138  func (h *ContractHandler) batchRun(rlpEncodedTxs [][]byte, coinbase types.Address) ([]*types.Result, error) {
   139  	// prepare block view used to run the batch
   140  	ctx, err := h.getBlockContext()
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  
   145  	ctx.GasFeeCollector = coinbase
   146  	blk, err := h.emulator.NewBlockView(ctx)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	bp, err := h.blockStore.BlockProposal()
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  
   156  	// decode all transactions and calculate total gas limit
   157  	var totalGasLimit types.GasLimit
   158  	batchLen := len(rlpEncodedTxs)
   159  	txs := make([]*gethTypes.Transaction, batchLen)
   160  
   161  	for i, rlpEncodedTx := range rlpEncodedTxs {
   162  		tx, err := h.decodeTransaction(rlpEncodedTx)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  
   167  		txs[i] = tx
   168  		totalGasLimit += types.GasLimit(tx.Gas())
   169  	}
   170  
   171  	// check if all transactions in the batch are below gas limit
   172  	err = h.checkGasLimit(totalGasLimit)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  
   177  	res, err := blk.BatchRunTransactions(txs)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  
   182  	// saftey check for result
   183  	if len(res) == 0 {
   184  		return nil, types.ErrUnexpectedEmptyResult
   185  	}
   186  
   187  	bp.PopulateReceiptRoot(res)
   188  
   189  	// meter all the transaction gas usage and append hashes to the block
   190  	for _, r := range res {
   191  		// meter gas anyway (even for invalid or failed states)
   192  		err = h.meterGasUsage(r)
   193  		if err != nil {
   194  			return nil, err
   195  		}
   196  
   197  		// include it in a block only if valid (not invalid)
   198  		if !r.Invalid() {
   199  			bp.AppendTxHash(r.TxHash)
   200  		}
   201  	}
   202  
   203  	blockHash, err := bp.Hash()
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	// if there were no valid transactions skip emitting events
   209  	// and commiting a new block
   210  	if len(bp.TransactionHashes) == 0 {
   211  		return res, nil
   212  	}
   213  
   214  	for i, r := range res {
   215  		if r.Invalid() { // don't emit events for invalid tx
   216  			continue
   217  		}
   218  		err = h.emitEvent(types.NewTransactionEvent(
   219  			r,
   220  			rlpEncodedTxs[i],
   221  			bp.Height,
   222  			blockHash,
   223  		))
   224  		if err != nil {
   225  			return nil, err
   226  		}
   227  	}
   228  
   229  	err = h.emitEvent(types.NewBlockEvent(bp))
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  
   234  	err = h.blockStore.CommitBlockProposal()
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	return res, nil
   240  }
   241  
   242  func (h *ContractHandler) run(
   243  	rlpEncodedTx []byte,
   244  	coinbase types.Address,
   245  ) (*types.Result, error) {
   246  	// step 1 - transaction decoding
   247  	tx, err := h.decodeTransaction(rlpEncodedTx)
   248  	if err != nil {
   249  		return nil, err
   250  	}
   251  
   252  	// step 2 - run transaction
   253  	err = h.checkGasLimit(types.GasLimit(tx.Gas()))
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  
   258  	ctx, err := h.getBlockContext()
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  	ctx.GasFeeCollector = coinbase
   263  	blk, err := h.emulator.NewBlockView(ctx)
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  
   268  	res, err := blk.RunTransaction(tx)
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  
   273  	// saftey check for result
   274  	if res == nil {
   275  		return nil, types.ErrUnexpectedEmptyResult
   276  	}
   277  
   278  	// meter gas anyway (even for invalid or failed states)
   279  	err = h.meterGasUsage(res)
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  
   284  	// if is invalid tx skip the next steps (forming block, ...)
   285  	if res.Invalid() {
   286  		return res, nil
   287  	}
   288  
   289  	// step 3 - update block proposal
   290  	bp, err := h.blockStore.BlockProposal()
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  
   295  	bp.AppendTxHash(res.TxHash)
   296  
   297  	// populate receipt root
   298  	bp.PopulateReceiptRoot([]*types.Result{res})
   299  	bp.CalculateGasUsage([]types.Result{*res})
   300  
   301  	blockHash, err := bp.Hash()
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  
   306  	// step 4 - emit events
   307  	err = h.emitEvent(types.NewTransactionEvent(res, rlpEncodedTx, bp.Height, blockHash))
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  
   312  	err = h.emitEvent(types.NewBlockEvent(bp))
   313  	if err != nil {
   314  		return nil, err
   315  	}
   316  
   317  	// step 5 - commit block proposal
   318  	err = h.blockStore.CommitBlockProposal()
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  	return res, nil
   323  }
   324  
   325  func (h *ContractHandler) DryRun(
   326  	rlpEncodedTx []byte,
   327  	from types.Address,
   328  ) *types.ResultSummary {
   329  	res, err := h.dryRun(rlpEncodedTx, from)
   330  	panicOnError(err)
   331  	return res.ResultSummary()
   332  }
   333  
   334  func (h *ContractHandler) dryRun(
   335  	rlpEncodedTx []byte,
   336  	from types.Address,
   337  ) (*types.Result, error) {
   338  	// step 1 - transaction decoding
   339  	encodedLen := uint(len(rlpEncodedTx))
   340  	err := h.backend.MeterComputation(environment.ComputationKindRLPDecoding, encodedLen)
   341  	if err != nil {
   342  		return nil, err
   343  	}
   344  
   345  	tx := gethTypes.Transaction{}
   346  	err = tx.UnmarshalBinary(rlpEncodedTx)
   347  	if err != nil {
   348  		return nil, err
   349  	}
   350  
   351  	ctx, err := h.getBlockContext()
   352  	if err != nil {
   353  		return nil, err
   354  	}
   355  
   356  	blk, err := h.emulator.NewBlockView(ctx)
   357  	if err != nil {
   358  		return nil, err
   359  	}
   360  
   361  	res, err := blk.DryRunTransaction(&tx, from.ToCommon())
   362  	if err != nil {
   363  		return nil, err
   364  	}
   365  
   366  	// saftey check for result
   367  	if res == nil {
   368  		return nil, types.ErrUnexpectedEmptyResult
   369  	}
   370  
   371  	return res, nil
   372  }
   373  
   374  func (h *ContractHandler) checkGasLimit(limit types.GasLimit) error {
   375  	// check gas limit against what has been left on the transaction side
   376  	if !h.backend.ComputationAvailable(environment.ComputationKindEVMGasUsage, uint(limit)) {
   377  		return types.ErrInsufficientComputation
   378  	}
   379  	return nil
   380  }
   381  
   382  // decodeTransaction decodes RLP encoded transaction payload and meters the resources used.
   383  func (h *ContractHandler) decodeTransaction(encodedTx []byte) (*gethTypes.Transaction, error) {
   384  	encodedLen := uint(len(encodedTx))
   385  	err := h.backend.MeterComputation(environment.ComputationKindRLPDecoding, encodedLen)
   386  	if err != nil {
   387  		return nil, err
   388  	}
   389  
   390  	tx := gethTypes.Transaction{}
   391  	if err := tx.UnmarshalBinary(encodedTx); err != nil {
   392  		return nil, err
   393  	}
   394  
   395  	return &tx, nil
   396  }
   397  
   398  func (h *ContractHandler) meterGasUsage(res *types.Result) error {
   399  	return h.backend.MeterComputation(environment.ComputationKindEVMGasUsage, uint(res.GasConsumed))
   400  }
   401  
   402  func (h *ContractHandler) emitEvent(event *types.Event) error {
   403  	location := common.NewAddressLocation(nil, common.Address(h.evmContractAddress), "EVM")
   404  	ev, err := event.Payload.ToCadence(location)
   405  	if err != nil {
   406  		return err
   407  	}
   408  	return h.backend.EmitEvent(ev)
   409  }
   410  
   411  func (h *ContractHandler) getBlockContext() (types.BlockContext, error) {
   412  	bp, err := h.blockStore.BlockProposal()
   413  	if err != nil {
   414  		return types.BlockContext{}, err
   415  	}
   416  	rand := gethCommon.Hash{}
   417  	err = h.backend.ReadRandom(rand[:])
   418  	if err != nil {
   419  		return types.BlockContext{}, err
   420  	}
   421  
   422  	return types.BlockContext{
   423  		ChainID:                types.EVMChainIDFromFlowChainID(h.flowChainID),
   424  		BlockNumber:            bp.Height,
   425  		BlockTimestamp:         bp.Timestamp,
   426  		DirectCallBaseGasUsage: types.DefaultDirectCallBaseGasUsage,
   427  		GetHashFunc: func(n uint64) gethCommon.Hash {
   428  			hash, err := h.blockStore.BlockHash(n)
   429  			panicOnError(err) // we have to handle it here given we can't continue with it even in try case
   430  			return hash
   431  		},
   432  		ExtraPrecompiles: h.precompiles,
   433  		Random:           rand,
   434  	}, nil
   435  }
   436  
   437  func (h *ContractHandler) executeAndHandleCall(
   438  	ctx types.BlockContext,
   439  	call *types.DirectCall,
   440  	totalSupplyDiff *big.Int,
   441  	deductSupplyDiff bool,
   442  ) (*types.Result, error) {
   443  	// execute the call
   444  	blk, err := h.emulator.NewBlockView(ctx)
   445  	if err != nil {
   446  		return nil, err
   447  	}
   448  
   449  	res, err := blk.DirectCall(call)
   450  	// check backend errors first
   451  	if err != nil {
   452  		return nil, err
   453  	}
   454  
   455  	// saftey check for result
   456  	if res == nil {
   457  		return nil, types.ErrUnexpectedEmptyResult
   458  	}
   459  
   460  	// gas meter even invalid or failed status
   461  	err = h.meterGasUsage(res)
   462  	if err != nil {
   463  		return nil, err
   464  	}
   465  
   466  	// if is invalid skip the rest of states
   467  	if res.Invalid() {
   468  		return res, nil
   469  	}
   470  
   471  	// update block proposal
   472  	bp, err := h.blockStore.BlockProposal()
   473  	if err != nil {
   474  		return nil, err
   475  	}
   476  
   477  	bp.AppendTxHash(res.TxHash)
   478  
   479  	// Populate receipt root
   480  	bp.PopulateReceiptRoot([]*types.Result{res})
   481  
   482  	if totalSupplyDiff != nil {
   483  		if deductSupplyDiff {
   484  			bp.TotalSupply = new(big.Int).Sub(bp.TotalSupply, totalSupplyDiff)
   485  			if bp.TotalSupply.Sign() < 0 {
   486  				return nil, types.ErrInsufficientTotalSupply
   487  			}
   488  		} else {
   489  			bp.TotalSupply = new(big.Int).Add(bp.TotalSupply, totalSupplyDiff)
   490  		}
   491  	}
   492  
   493  	blockHash, err := bp.Hash()
   494  	if err != nil {
   495  		return nil, err
   496  	}
   497  
   498  	// emit events
   499  	encoded, err := call.Encode()
   500  	if err != nil {
   501  		return nil, err
   502  	}
   503  
   504  	err = h.emitEvent(
   505  		types.NewTransactionEvent(res, encoded, bp.Height, blockHash),
   506  	)
   507  	if err != nil {
   508  		return nil, err
   509  	}
   510  
   511  	err = h.emitEvent(types.NewBlockEvent(bp))
   512  	if err != nil {
   513  		return nil, err
   514  	}
   515  
   516  	// commit block proposal
   517  	err = h.blockStore.CommitBlockProposal()
   518  	if err != nil {
   519  		return nil, err
   520  	}
   521  
   522  	return res, nil
   523  }
   524  
   525  func (h *ContractHandler) GenerateResourceUUID() uint64 {
   526  	uuid, err := h.backend.GenerateUUID()
   527  	panicOnError(err)
   528  	return uuid
   529  }
   530  
   531  type Account struct {
   532  	isAuthorized bool
   533  	address      types.Address
   534  	fch          *ContractHandler
   535  }
   536  
   537  // newAccount creates a new evm account
   538  func newAccount(fch *ContractHandler, addr types.Address, isAuthorized bool) *Account {
   539  	return &Account{
   540  		isAuthorized: isAuthorized,
   541  		fch:          fch,
   542  		address:      addr,
   543  	}
   544  }
   545  
   546  // Address returns the address associated with the account
   547  func (a *Account) Address() types.Address {
   548  	return a.address
   549  }
   550  
   551  // Nonce returns the nonce of this account
   552  //
   553  // Note: we don't meter any extra computation given reading data
   554  // from the storage already transalates into computation
   555  func (a *Account) Nonce() uint64 {
   556  	nonce, err := a.nonce()
   557  	panicOnError(err)
   558  	return nonce
   559  }
   560  
   561  func (a *Account) nonce() (uint64, error) {
   562  	ctx, err := a.fch.getBlockContext()
   563  	if err != nil {
   564  		return 0, err
   565  	}
   566  
   567  	blk, err := a.fch.emulator.NewReadOnlyBlockView(ctx)
   568  	if err != nil {
   569  		return 0, err
   570  	}
   571  
   572  	return blk.NonceOf(a.address)
   573  }
   574  
   575  // Balance returns the balance of this account
   576  //
   577  // Note: we don't meter any extra computation given reading data
   578  // from the storage already transalates into computation
   579  func (a *Account) Balance() types.Balance {
   580  	bal, err := a.balance()
   581  	panicOnError(err)
   582  	return bal
   583  }
   584  
   585  func (a *Account) balance() (types.Balance, error) {
   586  	ctx, err := a.fch.getBlockContext()
   587  	if err != nil {
   588  		return nil, err
   589  	}
   590  
   591  	blk, err := a.fch.emulator.NewReadOnlyBlockView(ctx)
   592  	if err != nil {
   593  		return nil, err
   594  	}
   595  
   596  	bl, err := blk.BalanceOf(a.address)
   597  	return types.NewBalance(bl), err
   598  }
   599  
   600  // Code returns the code of this account
   601  //
   602  // Note: we don't meter any extra computation given reading data
   603  // from the storage already transalates into computation
   604  func (a *Account) Code() types.Code {
   605  	code, err := a.code()
   606  	panicOnError(err)
   607  	return code
   608  }
   609  
   610  func (a *Account) code() (types.Code, error) {
   611  	ctx, err := a.fch.getBlockContext()
   612  	if err != nil {
   613  		return nil, err
   614  	}
   615  
   616  	blk, err := a.fch.emulator.NewReadOnlyBlockView(ctx)
   617  	if err != nil {
   618  		return nil, err
   619  	}
   620  	return blk.CodeOf(a.address)
   621  }
   622  
   623  // CodeHash returns the code hash of this account
   624  //
   625  // Note: we don't meter any extra computation given reading data
   626  // from the storage already transalates into computation
   627  func (a *Account) CodeHash() []byte {
   628  	codeHash, err := a.codeHash()
   629  	panicOnError(err)
   630  	return codeHash
   631  }
   632  
   633  func (a *Account) codeHash() ([]byte, error) {
   634  	ctx, err := a.fch.getBlockContext()
   635  	if err != nil {
   636  		return nil, err
   637  	}
   638  
   639  	blk, err := a.fch.emulator.NewReadOnlyBlockView(ctx)
   640  	if err != nil {
   641  		return nil, err
   642  	}
   643  	return blk.CodeHashOf(a.address)
   644  }
   645  
   646  // Deposit deposits the token from the given vault into the flow evm main vault
   647  // and update the account balance with the new amount
   648  func (a *Account) Deposit(v *types.FLOWTokenVault) {
   649  	res, err := a.deposit(v)
   650  	panicOnErrorOrInvalidOrFailedState(res, err)
   651  }
   652  
   653  func (a *Account) deposit(v *types.FLOWTokenVault) (*types.Result, error) {
   654  	bridge := a.fch.addressAllocator.NativeTokenBridgeAddress()
   655  	bridgeAccount := a.fch.AccountByAddress(bridge, false)
   656  
   657  	call := types.NewDepositCall(
   658  		bridge,
   659  		a.address,
   660  		v.Balance(),
   661  		bridgeAccount.Nonce(),
   662  	)
   663  	ctx, err := a.precheck(false, types.GasLimit(call.GasLimit))
   664  	if err != nil {
   665  		return nil, err
   666  	}
   667  
   668  	return a.fch.executeAndHandleCall(ctx, call, v.Balance(), false)
   669  }
   670  
   671  // Withdraw deducts the balance from the account and
   672  // withdraw and return flow token from the Flex main vault.
   673  func (a *Account) Withdraw(b types.Balance) *types.FLOWTokenVault {
   674  	res, err := a.withdraw(b)
   675  	panicOnErrorOrInvalidOrFailedState(res, err)
   676  
   677  	return types.NewFlowTokenVault(b)
   678  }
   679  
   680  func (a *Account) withdraw(b types.Balance) (*types.Result, error) {
   681  	call := types.NewWithdrawCall(
   682  		a.fch.addressAllocator.NativeTokenBridgeAddress(),
   683  		a.address,
   684  		b,
   685  		a.Nonce(),
   686  	)
   687  
   688  	ctx, err := a.precheck(true, types.GasLimit(call.GasLimit))
   689  	if err != nil {
   690  		return nil, err
   691  	}
   692  
   693  	// Don't allow withdraw for balances that has rounding error
   694  	if types.BalanceConvertionToUFix64ProneToRoundingError(b) {
   695  		return nil, types.ErrWithdrawBalanceRounding
   696  	}
   697  
   698  	return a.fch.executeAndHandleCall(ctx, call, b, true)
   699  }
   700  
   701  // Transfer transfers tokens between accounts
   702  func (a *Account) Transfer(to types.Address, balance types.Balance) {
   703  	res, err := a.transfer(to, balance)
   704  	panicOnErrorOrInvalidOrFailedState(res, err)
   705  }
   706  
   707  func (a *Account) transfer(to types.Address, balance types.Balance) (*types.Result, error) {
   708  	call := types.NewTransferCall(
   709  		a.address,
   710  		to,
   711  		balance,
   712  		a.Nonce(),
   713  	)
   714  	ctx, err := a.precheck(true, types.GasLimit(call.GasLimit))
   715  	if err != nil {
   716  		return nil, err
   717  	}
   718  
   719  	return a.fch.executeAndHandleCall(ctx, call, nil, false)
   720  }
   721  
   722  // Deploy deploys a contract to the EVM environment
   723  // the new deployed contract would be at the returned address
   724  // contained in the result summary as data and
   725  // the contract data is not controlled by the caller accounts
   726  func (a *Account) Deploy(code types.Code, gaslimit types.GasLimit, balance types.Balance) *types.ResultSummary {
   727  	res, err := a.deploy(code, gaslimit, balance)
   728  	panicOnError(err)
   729  	return res.ResultSummary()
   730  }
   731  
   732  func (a *Account) deploy(code types.Code, gaslimit types.GasLimit, balance types.Balance) (*types.Result, error) {
   733  	ctx, err := a.precheck(true, gaslimit)
   734  	if err != nil {
   735  		return nil, err
   736  	}
   737  
   738  	call := types.NewDeployCall(
   739  		a.address,
   740  		code,
   741  		uint64(gaslimit),
   742  		balance,
   743  		a.Nonce(),
   744  	)
   745  	return a.fch.executeAndHandleCall(ctx, call, nil, false)
   746  }
   747  
   748  // Call calls a smart contract function with the given data
   749  // it would limit the gas used according to the limit provided
   750  // given it doesn't goes beyond what Flow transaction allows.
   751  // the balance would be deducted from the OFA account and would be transferred to the target address
   752  func (a *Account) Call(to types.Address, data types.Data, gaslimit types.GasLimit, balance types.Balance) *types.ResultSummary {
   753  	res, err := a.call(to, data, gaslimit, balance)
   754  	panicOnError(err)
   755  	return res.ResultSummary()
   756  }
   757  
   758  func (a *Account) call(to types.Address, data types.Data, gaslimit types.GasLimit, balance types.Balance) (*types.Result, error) {
   759  	ctx, err := a.precheck(true, gaslimit)
   760  	if err != nil {
   761  		return nil, err
   762  	}
   763  	call := types.NewContractCall(
   764  		a.address,
   765  		to,
   766  		data,
   767  		uint64(gaslimit),
   768  		balance,
   769  		a.Nonce(),
   770  	)
   771  
   772  	return a.fch.executeAndHandleCall(ctx, call, nil, false)
   773  }
   774  
   775  func (a *Account) precheck(authroized bool, gaslimit types.GasLimit) (types.BlockContext, error) {
   776  	// check if account is authorized (i.e. is a COA)
   777  	if authroized && !a.isAuthorized {
   778  		return types.BlockContext{}, types.ErrUnAuthroizedMethodCall
   779  	}
   780  	err := a.fch.checkGasLimit(gaslimit)
   781  	if err != nil {
   782  		return types.BlockContext{}, err
   783  	}
   784  
   785  	return a.fch.getBlockContext()
   786  }
   787  
   788  func panicOnErrorOrInvalidOrFailedState(res *types.Result, err error) {
   789  
   790  	if res != nil && res.Invalid() {
   791  		panic(fvmErrors.NewEVMError(res.ValidationError))
   792  	}
   793  
   794  	if res != nil && res.Failed() {
   795  		panic(fvmErrors.NewEVMError(res.VMError))
   796  	}
   797  
   798  	// this should never happen
   799  	if err == nil && res == nil {
   800  		panic(fvmErrors.NewEVMError(types.ErrUnexpectedEmptyResult))
   801  	}
   802  
   803  	panicOnError(err)
   804  }
   805  
   806  // panicOnError errors panic on returned errors
   807  func panicOnError(err error) {
   808  	if err == nil {
   809  		return
   810  	}
   811  
   812  	if types.IsAFatalError(err) {
   813  		panic(fvmErrors.NewEVMFailure(err))
   814  	}
   815  
   816  	if types.IsABackendError(err) {
   817  		// backend errors doesn't need wrapping
   818  		panic(err)
   819  	}
   820  
   821  	// any other returned errors are non-fatal errors
   822  	panic(fvmErrors.NewEVMError(err))
   823  }