diff --git a/fvm/evm/emulator/emulator.go b/fvm/evm/emulator/emulator.go index 9371562ef63..3896c83e9b3 100644 --- a/fvm/evm/emulator/emulator.go +++ b/fvm/evm/emulator/emulator.go @@ -235,8 +235,11 @@ func (proc *procedure) withdrawFrom(address types.Address, amount *big.Int) (*ty // while this method is only called from bridged accounts // it might be the case that someone creates a bridged account // and never transfer tokens to and call for withdraw + // TODO: we might revisit this apporach and + // return res, types.ErrAccountDoesNotExist + // instead if !proc.state.Exist(addr) { - return res, types.ErrAccountDoesNotExist + proc.state.CreateAccount(addr) } // check the source account balance diff --git a/fvm/evm/evm.go b/fvm/evm/evm.go index 0bda4dfb767..2d3e1288ae2 100644 --- a/fvm/evm/evm.go +++ b/fvm/evm/evm.go @@ -2,6 +2,7 @@ package evm import ( "github.com/onflow/cadence/runtime" + "github.com/onflow/cadence/runtime/common" "github.com/onflow/flow-go/fvm/environment" evm "github.com/onflow/flow-go/fvm/evm/emulator" @@ -21,6 +22,7 @@ func SetupEnvironment( backend types.Backend, env runtime.Environment, service flow.Address, + flowToken flow.Address, ) error { // TODO: setup proper root address based on chainID evmRootAddress, err := RootAccountAddress(chainID) @@ -45,7 +47,7 @@ func SetupEnvironment( return err } - contractHandler := handler.NewContractHandler(bs, aa, backend, em) + contractHandler := handler.NewContractHandler(common.Address(flowToken), bs, aa, backend, em) stdlib.SetupEnvironment(env, contractHandler, service) diff --git a/fvm/evm/evm_test.go b/fvm/evm/evm_test.go index 9d54d02fc9b..e216505c822 100644 --- a/fvm/evm/evm_test.go +++ b/fvm/evm/evm_test.go @@ -109,7 +109,7 @@ func RunWithNewTestVM(t *testing.T, chain flow.Chain, f func(fvm.Context, fvm.VM f(fvm.NewContextFromParent(ctx, fvm.WithEVMEnabled(true)), vm, snapshotTree) } -// TODO: test with actual amount +// TODO: deposit non-zero amount func TestEVMAddressDeposit(t *testing.T) { t.Parallel() @@ -156,3 +156,52 @@ func TestEVMAddressDeposit(t *testing.T) { }) }) } + +// TODO: deposit non-zero amount +func TestBridgedAccountWithdraw(t *testing.T) { + + t.Parallel() + + RunWithTestBackend(t, func(backend types.Backend) { + RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { + RunWithDeployedContract(t, backend, rootAddr, func(testContract *TestContract) { + RunWithEOATestAccount(t, backend, rootAddr, func(testAccount *EOATestAccount) { + chain := flow.Emulator.Chain() + RunWithNewTestVM(t, chain, func(ctx fvm.Context, vm fvm.VM, snapshot snapshot.SnapshotTree) { + + code := []byte(fmt.Sprintf( + ` + import EVM from %s + import FlowToken from %s + + access(all) + fun main(): UFix64 { + let bridgedAccount <- EVM.createBridgedAccount() + let vault <- bridgedAccount.withdraw(balance: EVM.Balance(flow: 0.0)) + let balance = vault.balance + destroy bridgedAccount + destroy vault + return balance + } + `, + chain.ServiceAddress().HexWithPrefix(), + fvm.FlowTokenAddress(chain).HexWithPrefix(), + )) + + script := fvm.Script(code) + + executionSnapshot, output, err := vm.Run( + ctx, + script, + snapshot) + require.NoError(t, err) + require.NoError(t, output.Err) + + // TODO: + _ = executionSnapshot + }) + }) + }) + }) + }) +} diff --git a/fvm/evm/handler/handler.go b/fvm/evm/handler/handler.go index c66644d1363..55905ad5aef 100644 --- a/fvm/evm/handler/handler.go +++ b/fvm/evm/handler/handler.go @@ -5,6 +5,7 @@ import ( gethTypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" + "github.com/onflow/cadence/runtime/common" "github.com/onflow/flow-go/fvm/environment" "github.com/onflow/flow-go/fvm/errors" @@ -22,21 +23,28 @@ import ( // in the future we might benefit from a view style of access to db passed as // a param to the emulator. type ContractHandler struct { + flowTokenAddress common.Address blockstore types.BlockStore + addressAllocator types.AddressAllocator backend types.Backend emulator types.Emulator - addressAllocator types.AddressAllocator +} + +func (h *ContractHandler) FlowTokenAddress() common.Address { + return h.flowTokenAddress } var _ types.ContractHandler = &ContractHandler{} func NewContractHandler( + flowTokenAddress common.Address, blockstore types.BlockStore, addressAllocator types.AddressAllocator, backend types.Backend, emulator types.Emulator, ) *ContractHandler { return &ContractHandler{ + flowTokenAddress: flowTokenAddress, blockstore: blockstore, addressAllocator: addressAllocator, backend: backend, @@ -131,6 +139,7 @@ func (h *ContractHandler) emitEvent(event *types.Event) { // TODO add extra metering for rlp encoding encoded, err := event.Payload.Encode() handleError(err) + err = h.backend.EmitFlowEvent(event.Etype, encoded) handleError(err) } diff --git a/fvm/evm/handler/handler_test.go b/fvm/evm/handler/handler_test.go index 29fae749a74..f612f979a25 100644 --- a/fvm/evm/handler/handler_test.go +++ b/fvm/evm/handler/handler_test.go @@ -11,9 +11,11 @@ import ( gethTypes "github.com/ethereum/go-ethereum/core/types" gethParams "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" + "github.com/onflow/cadence/runtime/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/onflow/flow-go/fvm" "github.com/onflow/flow-go/fvm/errors" "github.com/onflow/flow-go/fvm/evm/emulator" "github.com/onflow/flow-go/fvm/evm/emulator/database" @@ -25,10 +27,14 @@ import ( // TODO add test for fatal errors +var flowTokenAddress = common.Address(fvm.FlowTokenAddress(flow.Emulator.Chain())) + func TestHandler_TransactionRun(t *testing.T) { t.Parallel() t.Run("test - transaction run (happy case)", func(t *testing.T) { + t.Parallel() + testutils.RunWithTestBackend(t, func(backend types.Backend) { testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { testutils.RunWithEOATestAccount(t, backend, rootAddr, func(eoa *testutils.EOATestAccount) { @@ -55,8 +61,7 @@ func TestHandler_TransactionRun(t *testing.T) { return result, nil }, } - - handler := handler.NewContractHandler(bs, aa, backend, em) + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, em) coinbase := types.NewAddress(gethCommon.Address{}) @@ -104,6 +109,8 @@ func TestHandler_TransactionRun(t *testing.T) { }) t.Run("test - transaction run (unhappy cases)", func(t *testing.T) { + t.Parallel() + testutils.RunWithTestBackend(t, func(backend types.Backend) { testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { testutils.RunWithEOATestAccount(t, backend, rootAddr, func(eoa *testutils.EOATestAccount) { @@ -119,7 +126,7 @@ func TestHandler_TransactionRun(t *testing.T) { return &types.Result{}, types.NewEVMExecutionError(fmt.Errorf("some sort of error")) }, } - handler := handler.NewContractHandler(bs, aa, backend, em) + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, em) coinbase := types.NewAddress(gethCommon.Address{}) @@ -164,6 +171,8 @@ func TestHandler_TransactionRun(t *testing.T) { }) t.Run("test running transaction (with integrated emulator)", func(t *testing.T) { + t.Parallel() + testutils.RunWithTestBackend(t, func(backend types.Backend) { testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { @@ -178,7 +187,7 @@ func TestHandler_TransactionRun(t *testing.T) { emulator := emulator.NewEmulator(db) - handler := handler.NewContractHandler(bs, aa, backend, emulator) + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, emulator) eoa := testutils.GetTestEOAAccount(t, testutils.EOATestAccount1KeyHex) @@ -230,6 +239,8 @@ func TestHandler_OpsWithoutEmulator(t *testing.T) { t.Parallel() t.Run("test last executed block call", func(t *testing.T) { + t.Parallel() + testutils.RunWithTestBackend(t, func(backend types.Backend) { testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { bs, err := handler.NewBlockStore(backend, rootAddr) @@ -242,7 +253,8 @@ func TestHandler_OpsWithoutEmulator(t *testing.T) { require.NoError(t, err) emulator := emulator.NewEmulator(db) - handler := handler.NewContractHandler(bs, aa, backend, emulator) + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, emulator) + // test call last executed block without initialization b := handler.LastExecutedBlock() require.Equal(t, types.GenesisBlock, b) @@ -262,6 +274,8 @@ func TestHandler_OpsWithoutEmulator(t *testing.T) { }) t.Run("test address allocation", func(t *testing.T) { + t.Parallel() + testutils.RunWithTestBackend(t, func(backend types.Backend) { testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { blockchain, err := handler.NewBlockStore(backend, rootAddr) @@ -270,7 +284,8 @@ func TestHandler_OpsWithoutEmulator(t *testing.T) { aa, err := handler.NewAddressAllocator(backend, rootAddr) require.NoError(t, err) - handler := handler.NewContractHandler(blockchain, aa, backend, nil) + handler := handler.NewContractHandler(flowTokenAddress, blockchain, aa, backend, nil) + foa := handler.AllocateAddress() require.NotNil(t, foa) @@ -284,6 +299,8 @@ func TestHandler_OpsWithoutEmulator(t *testing.T) { func TestHandler_BridgedAccount(t *testing.T) { t.Run("test deposit/withdraw (with integrated emulator)", func(t *testing.T) { + t.Parallel() + testutils.RunWithTestBackend(t, func(backend types.Backend) { testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { bs, err := handler.NewBlockStore(backend, rootAddr) @@ -297,7 +314,8 @@ func TestHandler_BridgedAccount(t *testing.T) { emulator := emulator.NewEmulator(db) - handler := handler.NewContractHandler(bs, aa, backend, emulator) + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, emulator) + foa := handler.AccountByAddress(handler.AllocateAddress(), true) require.NotNil(t, foa) @@ -360,6 +378,8 @@ func TestHandler_BridgedAccount(t *testing.T) { }) t.Run("test withdraw (unhappy case)", func(t *testing.T) { + t.Parallel() + testutils.RunWithTestBackend(t, func(backend types.Backend) { testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { testutils.RunWithEOATestAccount(t, backend, rootAddr, func(eoa *testutils.EOATestAccount) { @@ -372,7 +392,8 @@ func TestHandler_BridgedAccount(t *testing.T) { // Withdraw calls are only possible within FOA accounts assertPanic(t, types.IsAUnAuthroizedMethodCallError, func() { em := &testutils.TestEmulator{} - handler := handler.NewContractHandler(bs, aa, backend, em) + + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), false) account.Withdraw(types.Balance(1)) @@ -385,8 +406,10 @@ func TestHandler_BridgedAccount(t *testing.T) { return &types.Result{}, types.NewEVMExecutionError(fmt.Errorf("some sort of error")) }, } - handler := handler.NewContractHandler(bs, aa, backend, em) + + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), true) + account.Withdraw(types.Balance(1)) }) @@ -397,8 +420,10 @@ func TestHandler_BridgedAccount(t *testing.T) { return &types.Result{}, types.NewEVMExecutionError(fmt.Errorf("some sort of error")) }, } - handler := handler.NewContractHandler(bs, aa, backend, em) + + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), true) + account.Withdraw(types.Balance(0)) }) @@ -409,8 +434,10 @@ func TestHandler_BridgedAccount(t *testing.T) { return &types.Result{}, types.NewFatalError(fmt.Errorf("some sort of fatal error")) }, } - handler := handler.NewContractHandler(bs, aa, backend, em) + + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), true) + account.Withdraw(types.Balance(0)) }) }) @@ -419,6 +446,8 @@ func TestHandler_BridgedAccount(t *testing.T) { }) t.Run("test deposit (unhappy case)", func(t *testing.T) { + t.Parallel() + testutils.RunWithTestBackend(t, func(backend types.Backend) { testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { testutils.RunWithEOATestAccount(t, backend, rootAddr, func(eoa *testutils.EOATestAccount) { @@ -435,8 +464,10 @@ func TestHandler_BridgedAccount(t *testing.T) { return &types.Result{}, types.NewEVMExecutionError(fmt.Errorf("some sort of error")) }, } - handler := handler.NewContractHandler(bs, aa, backend, em) + + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), true) + account.Deposit(types.NewFlowTokenVault(1)) }) @@ -447,8 +478,10 @@ func TestHandler_BridgedAccount(t *testing.T) { return &types.Result{}, types.NewFatalError(fmt.Errorf("some sort of fatal error")) }, } - handler := handler.NewContractHandler(bs, aa, backend, em) + + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, em) account := handler.AccountByAddress(testutils.RandomAddress(t), true) + account.Deposit(types.NewFlowTokenVault(1)) }) }) @@ -457,6 +490,8 @@ func TestHandler_BridgedAccount(t *testing.T) { }) t.Run("test deploy/call (with integrated emulator)", func(t *testing.T) { + t.Parallel() + // TODO update this test with events, gas metering, etc testutils.RunWithTestBackend(t, func(backend types.Backend) { testutils.RunWithTestFlowEVMRootAddress(t, backend, func(rootAddr flow.Address) { @@ -471,7 +506,8 @@ func TestHandler_BridgedAccount(t *testing.T) { emulator := emulator.NewEmulator(db) - handler := handler.NewContractHandler(bs, aa, backend, emulator) + handler := handler.NewContractHandler(flowTokenAddress, bs, aa, backend, emulator) + foa := handler.AccountByAddress(handler.AllocateAddress(), true) require.NotNil(t, foa) diff --git a/fvm/evm/stdlib/contract.cdc b/fvm/evm/stdlib/contract.cdc index 4469353025f..286f06e5ca9 100644 --- a/fvm/evm/stdlib/contract.cdc +++ b/fvm/evm/stdlib/contract.cdc @@ -70,11 +70,17 @@ contract EVM { self.address().deposit(from: <-from) } + /// Withdraws the balance from the bridged account's balance + access(all) + fun withdraw(balance: Balance): @FlowToken.Vault { + let vault <- InternalEVM.withdraw( + from: self.addressBytes, + amount: balance.flow + ) as! @FlowToken.Vault + return <-vault + } + // TODO: - // /// Withdraws the balance from the bridged account's balance - // access(all) - // fun withdraw(balance: Balance): @FlowToken.Vault - // // /// Deploys a contract to the EVM environment. // /// Returns the address of the newly deployed contract // access(all) diff --git a/fvm/evm/stdlib/contract.go b/fvm/evm/stdlib/contract.go index 3c66b97441d..359405ae1eb 100644 --- a/fvm/evm/stdlib/contract.go +++ b/fvm/evm/stdlib/contract.go @@ -332,7 +332,7 @@ func newInternalEVMTypeDepositFunction( amount := types.Balance(amountValue) - // Call + // Deposit const isAuthorized = false account := handler.AccountByAddress(toAddress, isAuthorized) @@ -343,6 +343,81 @@ func newInternalEVMTypeDepositFunction( ) } +const internalEVMTypeWithdrawFunctionName = "withdraw" + +var internalEVMTypeWithdrawFunctionType = &sema.FunctionType{ + Parameters: []sema.Parameter{ + { + Label: "from", + TypeAnnotation: sema.NewTypeAnnotation(evmAddressBytesType), + }, + { + Label: "amount", + TypeAnnotation: sema.NewTypeAnnotation(sema.UFix64Type), + }, + }, + ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.AnyResourceType), +} + +func newInternalEVMTypeWithdrawFunction( + gauge common.MemoryGauge, + handler types.ContractHandler, +) *interpreter.HostFunctionValue { + return interpreter.NewHostFunctionValue( + gauge, + internalEVMTypeCallFunctionType, + func(invocation interpreter.Invocation) interpreter.Value { + inter := invocation.Interpreter + locationRange := invocation.LocationRange + + // Get from address + + fromAddressValue, ok := invocation.Arguments[0].(*interpreter.ArrayValue) + if !ok { + panic(errors.NewUnreachableError()) + } + + fromAddress, err := AddressBytesArrayValueToEVMAddress(inter, locationRange, fromAddressValue) + if err != nil { + panic(err) + } + + // Get amount + + amountValue, ok := invocation.Arguments[1].(interpreter.UFix64Value) + if !ok { + panic(errors.NewUnreachableError()) + } + + amount := types.Balance(amountValue) + + // Withdraw + + const isAuthorized = true + account := handler.AccountByAddress(fromAddress, isAuthorized) + vault := account.Withdraw(amount) + + // TODO: improve: maybe call actual constructor + return interpreter.NewCompositeValue( + inter, + locationRange, + common.NewAddressLocation(gauge, handler.FlowTokenAddress(), "FlowToken"), + "FlowToken.Vault", + common.CompositeKindResource, + []interpreter.CompositeField{ + { + Name: "balance", + Value: interpreter.NewUFix64Value(gauge, func() uint64 { + return uint64(vault.Balance()) + }), + }, + }, + common.ZeroAddress, + ) + }, + ) +} + func NewInternalEVMContractValue( gauge common.MemoryGauge, handler types.ContractHandler, @@ -357,6 +432,7 @@ func NewInternalEVMContractValue( internalEVMTypeCreateBridgedAccountFunctionName: newInternalEVMTypeCreateBridgedAccountFunction(gauge, handler), internalEVMTypeCallFunctionName: newInternalEVMTypeCallFunction(gauge, handler), internalEVMTypeDepositFunctionName: newInternalEVMTypeDepositFunction(gauge, handler), + internalEVMTypeWithdrawFunctionName: newInternalEVMTypeWithdrawFunction(gauge, handler), }, nil, nil, @@ -397,6 +473,12 @@ var InternalEVMContractType = func() *sema.CompositeType { internalEVMTypeDepositFunctionType, "", ), + sema.NewUnmeteredPublicFunctionMember( + ty, + internalEVMTypeWithdrawFunctionName, + internalEVMTypeWithdrawFunctionType, + "", + ), }) return ty }() diff --git a/fvm/evm/stdlib/contract_test.go b/fvm/evm/stdlib/contract_test.go index 8be075f1d07..86a2497de57 100644 --- a/fvm/evm/stdlib/contract_test.go +++ b/fvm/evm/stdlib/contract_test.go @@ -20,6 +20,7 @@ import ( ) type testContractHandler struct { + flowTokenAddress common.Address allocateAddress func() types.Address addressIndex uint64 accountByAddress func(types.Address, bool) types.Account @@ -27,6 +28,10 @@ type testContractHandler struct { run func(tx []byte, coinbase types.Address) } +func (t *testContractHandler) FlowTokenAddress() common.Address { + return t.flowTokenAddress +} + var _ types.ContractHandler = &testContractHandler{} func (t *testContractHandler) AllocateAddress() types.Address { @@ -714,6 +719,7 @@ func TestBridgedAccountCall(t *testing.T) { require.Equal(t, expected, actual) } +// TODO: deposit non-zero amount func TestEVMAddressDeposit(t *testing.T) { t.Parallel() @@ -730,7 +736,7 @@ func TestEVMAddressDeposit(t *testing.T) { address: fromAddress, deposit: func(vault *types.FLOWTokenVault) { deposited = true - assert.Zero(t, vault.Balance()) + assert.Equal(t, types.Balance(0), vault.Balance()) }, } }, @@ -807,3 +813,101 @@ func TestEVMAddressDeposit(t *testing.T) { require.True(t, deposited) } + +func TestBridgedAccountWithdraw(t *testing.T) { + + t.Parallel() + + var withdrew bool + + contractsAddress := flow.BytesToAddress([]byte{0x1}) + + handler := &testContractHandler{ + flowTokenAddress: common.Address(contractsAddress), + accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account { + assert.Equal(t, types.Address{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress) + assert.True(t, isAuthorized) + + return &testFlowAccount{ + address: fromAddress, + withdraw: func(balance types.Balance) *types.FLOWTokenVault { + assert.Equal(t, types.Balance(0), balance) + withdrew = true + return types.NewFlowTokenVault(balance) + }, + } + }, + } + + env := runtime.NewBaseInterpreterEnvironment(runtime.Config{}) + + stdlib.SetupEnvironment(env, handler, contractsAddress) + + rt := runtime.NewInterpreterRuntime(runtime.Config{}) + + script := []byte(` + import EVM from 0x1 + import FlowToken from 0x1 + + access(all) + fun main(): UFix64 { + let bridgedAccount <- EVM.createBridgedAccount() + let vault <- bridgedAccount.withdraw(balance: EVM.Balance(flow: 0.0)) + let balance = vault.balance + destroy bridgedAccount + destroy vault + return balance + } + `) + + accountCodes := map[common.Location][]byte{} + var events []cadence.Event + + runtimeInterface := &TestRuntimeInterface{ + Storage: NewTestLedger(nil, nil), + OnGetSigningAccounts: func() ([]runtime.Address, error) { + return []runtime.Address{runtime.Address(contractsAddress)}, nil + }, + OnResolveLocation: SingleIdentifierLocationResolver(t), + OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { + accountCodes[location] = code + return nil + }, + OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { + code = accountCodes[location] + return code, nil + }, + OnEmitEvent: func(event cadence.Event) error { + events = append(events, event) + return nil + }, + OnDecodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { + return json.Decode(nil, b) + }, + } + + nextTransactionLocation := NewTransactionLocationGenerator() + nextScriptLocation := NewScriptLocationGenerator() + + // Deploy contracts + + deployContracts(t, rt, contractsAddress, runtimeInterface, env, nextTransactionLocation) + + // Run script + + result, err := rt.ExecuteScript( + runtime.Script{ + Source: script, + }, + runtime.Context{ + Interface: runtimeInterface, + Environment: env, + Location: nextScriptLocation(), + }, + ) + require.NoError(t, err) + + require.Equal(t, cadence.UFix64(0), result) + + require.True(t, withdrew) +} diff --git a/fvm/evm/types/handler.go b/fvm/evm/types/handler.go index d3775f7987a..3badb5c6175 100644 --- a/fvm/evm/types/handler.go +++ b/fvm/evm/types/handler.go @@ -2,6 +2,7 @@ package types import ( gethCommon "github.com/ethereum/go-ethereum/common" + "github.com/onflow/cadence/runtime/common" "github.com/onflow/flow-go/fvm/environment" ) @@ -37,6 +38,8 @@ type ContractHandler interface { // Run runs a transaction in the evm environment, // collects the gas fees, and transfers the gas fees to the given coinbase account. Run(tx []byte, coinbase Address) + + FlowTokenAddress() common.Address } // Backend passes the FVM functionality needed inside the handler @@ -57,7 +60,7 @@ type BlockStore interface { // LatestBlock returns the latest appended block LatestBlock() (*Block, error) - // returns the hash of the block at the given height + // BlockHash returns the hash of the block at the given height BlockHash(height int) (gethCommon.Hash, error) // BlockProposal returns the block proposal @@ -66,6 +69,6 @@ type BlockStore interface { // CommitBlockProposal commits the block proposal and update the chain of blocks CommitBlockProposal() error - // Resets the block proposal + // ResetBlockProposal resets the block proposal ResetBlockProposal() error } diff --git a/fvm/script.go b/fvm/script.go index d91f759caef..b8ae36c755e 100644 --- a/fvm/script.go +++ b/fvm/script.go @@ -206,6 +206,7 @@ func (executor *scriptExecutor) executeScript() error { executor.env, rt.ScriptRuntimeEnv, chain.ServiceAddress(), + FlowTokenAddress(chain), ) if err != nil { return err diff --git a/fvm/transactionInvoker.go b/fvm/transactionInvoker.go index cd2ce7a89a4..03ba76878e5 100644 --- a/fvm/transactionInvoker.go +++ b/fvm/transactionInvoker.go @@ -233,6 +233,7 @@ func (executor *transactionExecutor) ExecuteTransactionBody() error { executor.env, executor.cadenceRuntime.TxRuntimeEnv, chain.ServiceAddress(), + FlowTokenAddress(chain), ) if err != nil { return err