From e6627e7e4ccc7911fe68f5e2e6d92ce3a501636c Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 1 Dec 2023 14:42:59 +0100 Subject: [PATCH 01/12] add contract balance --- fvm/evm/stdlib/contract.cdc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fvm/evm/stdlib/contract.cdc b/fvm/evm/stdlib/contract.cdc index 60f544a68b0..ff73dad4844 100644 --- a/fvm/evm/stdlib/contract.cdc +++ b/fvm/evm/stdlib/contract.cdc @@ -62,6 +62,12 @@ contract EVM { return EVMAddress(bytes: self.addressBytes) } + /// Get balance of the bridged account + access(all) + fun balance(): Balance { + return self.address().balance() + } + /// Deposits the given vault into the bridged account's balance access(all) fun deposit(from: @FlowToken.Vault) { From bcb30ac5e5d620cb17d942057f2867d3ce3a9d81 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 1 Dec 2023 15:23:27 +0100 Subject: [PATCH 02/12] add balance to address --- fvm/evm/stdlib/contract.cdc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fvm/evm/stdlib/contract.cdc b/fvm/evm/stdlib/contract.cdc index ff73dad4844..e65745bf505 100644 --- a/fvm/evm/stdlib/contract.cdc +++ b/fvm/evm/stdlib/contract.cdc @@ -24,6 +24,12 @@ contract EVM { to: self.bytes ) } + + fun balance(): UFix64 { + return InternalEVM.balance( + address: self.bytes + ) + } } access(all) @@ -64,7 +70,7 @@ contract EVM { /// Get balance of the bridged account access(all) - fun balance(): Balance { + fun balance(): UFix64 { return self.address().balance() } From 1de70a82345ace90c1062e6acc85d9121b713b59 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 1 Dec 2023 15:28:25 +0100 Subject: [PATCH 03/12] add balance function and definitions --- fvm/evm/stdlib/contract.go | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/fvm/evm/stdlib/contract.go b/fvm/evm/stdlib/contract.go index e66fa8a6787..b3b8853e4fb 100644 --- a/fvm/evm/stdlib/contract.go +++ b/fvm/evm/stdlib/contract.go @@ -359,6 +359,53 @@ func newInternalEVMTypeDepositFunction( ) } +const internalEVMTypeBalanceFunctionName = "balance" + +var internalEVMTypeBalanceFunctionType = &sema.FunctionType{ + Parameters: []sema.Parameter{ + { + Label: "address", + TypeAnnotation: sema.NewTypeAnnotation(evmAddressBytesType), + }, + }, + ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.UFix64Type), +} + +func newInternalEVMTypeBalanceFunction( + 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 + + addressValue, ok := invocation.Arguments[0].(*interpreter.ArrayValue) + if !ok { + panic(errors.NewUnreachableError()) + } + + address, err := AddressBytesArrayValueToEVMAddress(inter, locationRange, addressValue) + if err != nil { + panic(err) + } + + const isAuthorized = false + account := handler.AccountByAddress(address, isAuthorized) + + // todo return the Balance type + return interpreter.NewUFix64Value(gauge, func() (balance uint64) { + errors.WrapPanic(func() { + balance = account.Balance().ToAttoFlow().Uint64() + }) + return + }) + }, + ) +} + const internalEVMTypeWithdrawFunctionName = "withdraw" var internalEVMTypeWithdrawFunctionType = &sema.FunctionType{ @@ -538,6 +585,7 @@ func NewInternalEVMContractValue( internalEVMTypeDepositFunctionName: newInternalEVMTypeDepositFunction(gauge, handler), internalEVMTypeWithdrawFunctionName: newInternalEVMTypeWithdrawFunction(gauge, handler), internalEVMTypeDeployFunctionName: newInternalEVMTypeDeployFunction(gauge, handler), + internalEVMTypeBalanceFunctionName: newInternalEVMTypeBalanceFunction(gauge, handler), }, nil, nil, @@ -590,6 +638,12 @@ var InternalEVMContractType = func() *sema.CompositeType { internalEVMTypeDeployFunctionType, "", ), + sema.NewUnmeteredPublicFunctionMember( + ty, + internalEVMTypeBalanceFunctionName, + internalEVMTypeBalanceFunctionType, + "", + ), }) return ty }() From c739bcb4840996d04bc20f8113a399b5bb6c5cec Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 1 Dec 2023 15:56:40 +0100 Subject: [PATCH 04/12] use ufix value directly --- fvm/evm/stdlib/contract.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fvm/evm/stdlib/contract.go b/fvm/evm/stdlib/contract.go index b3b8853e4fb..71bc25fadc5 100644 --- a/fvm/evm/stdlib/contract.go +++ b/fvm/evm/stdlib/contract.go @@ -396,12 +396,7 @@ func newInternalEVMTypeBalanceFunction( account := handler.AccountByAddress(address, isAuthorized) // todo return the Balance type - return interpreter.NewUFix64Value(gauge, func() (balance uint64) { - errors.WrapPanic(func() { - balance = account.Balance().ToAttoFlow().Uint64() - }) - return - }) + return interpreter.UFix64Value(account.Balance()) }, ) } From 9611186a494996310e123656d7e309d14e4beefb Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 1 Dec 2023 15:56:47 +0100 Subject: [PATCH 05/12] add test for balance --- fvm/evm/stdlib/contract_test.go | 100 ++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/fvm/evm/stdlib/contract_test.go b/fvm/evm/stdlib/contract_test.go index 2ba15c3eb16..4bc657b9c50 100644 --- a/fvm/evm/stdlib/contract_test.go +++ b/fvm/evm/stdlib/contract_test.go @@ -1143,3 +1143,103 @@ func TestBridgedAccountDeploy(t *testing.T) { require.True(t, deployed) } + +func TestEVMAccountBalance(t *testing.T) { + + t.Parallel() + + contractsAddress := flow.BytesToAddress([]byte{0x1}) + + expectedBalance, err := cadence.NewUFix64FromParts(1, 1337000) + require.NoError(t, err) + + var handler *testContractHandler + 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.False(t, isAuthorized) + + return &testFlowAccount{ + address: fromAddress, + balance: func() types.Balance { + return types.Balance(expectedBalance) + }, + } + }, + } + + transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress) + scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress) + + rt := runtime.NewInterpreterRuntime(runtime.Config{}) + + script := []byte(` + import EVM from 0x1 + + access(all) + fun main(): UFix64 { + let bridgedAccount <- EVM.createBridgedAccount() + let balance = bridgedAccount.balance() + destroy bridgedAccount + 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, + transactionEnvironment, + nextTransactionLocation, + ) + + // Run script + + actual, err := rt.ExecuteScript( + runtime.Script{ + Source: script, + }, + runtime.Context{ + Interface: runtimeInterface, + Environment: scriptEnvironment, + Location: nextScriptLocation(), + }, + ) + require.NoError(t, err) + + require.NoError(t, err) + require.Equal(t, expectedBalance, actual) +} From 239dad32f396d387b546db9263999ef51952e7b7 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 1 Dec 2023 15:56:56 +0100 Subject: [PATCH 06/12] add access modifier --- fvm/evm/stdlib/contract.cdc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fvm/evm/stdlib/contract.cdc b/fvm/evm/stdlib/contract.cdc index e65745bf505..09757e632c3 100644 --- a/fvm/evm/stdlib/contract.cdc +++ b/fvm/evm/stdlib/contract.cdc @@ -25,6 +25,8 @@ contract EVM { ) } + /// Balance of the address + access(all) fun balance(): UFix64 { return InternalEVM.balance( address: self.bytes From 93daaf456e9de47192e24934447708442ae6790e Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Fri, 1 Dec 2023 17:20:50 +0100 Subject: [PATCH 07/12] resolve merge --- fvm/transactionInvoker.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fvm/transactionInvoker.go b/fvm/transactionInvoker.go index e381f7f464a..1092cea97ab 100644 --- a/fvm/transactionInvoker.go +++ b/fvm/transactionInvoker.go @@ -4,6 +4,8 @@ import ( "fmt" "strconv" + "github.com/onflow/flow-go/fvm/systemcontracts" + "github.com/onflow/cadence/runtime" "github.com/onflow/cadence/runtime/common" "github.com/rs/zerolog" @@ -184,12 +186,13 @@ func (executor *transactionExecutor) preprocessTransactionBody() error { // setup evm if executor.ctx.EVMEnabled { chain := executor.ctx.Chain + sc := systemcontracts.SystemContractsForChain(chain.ChainID()) err := evm.SetupEnvironment( chain.ChainID(), executor.env, executor.cadenceRuntime.TxRuntimeEnv, chain.ServiceAddress(), - FlowTokenAddress(chain), + sc.FlowToken.Address, ) if err != nil { return err From 999c67768a4e931edf55b0f8c97d973e301bae9f Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 4 Dec 2023 14:37:07 +0100 Subject: [PATCH 08/12] return balance type --- fvm/evm/stdlib/contract.cdc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fvm/evm/stdlib/contract.cdc b/fvm/evm/stdlib/contract.cdc index 09757e632c3..ab3cf4c06c6 100644 --- a/fvm/evm/stdlib/contract.cdc +++ b/fvm/evm/stdlib/contract.cdc @@ -27,10 +27,12 @@ contract EVM { /// Balance of the address access(all) - fun balance(): UFix64 { - return InternalEVM.balance( + fun balance(): Balance { + let balance = InternalEVM.balance( address: self.bytes ) + + return Balance(flow: balance) } } @@ -72,7 +74,7 @@ contract EVM { /// Get balance of the bridged account access(all) - fun balance(): UFix64 { + fun balance(): Balance { return self.address().balance() } From 02299b6cf3f0e9b7c26af0401738870cfdfc5742 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 4 Dec 2023 14:38:06 +0100 Subject: [PATCH 09/12] add comment --- fvm/evm/stdlib/contract.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fvm/evm/stdlib/contract.go b/fvm/evm/stdlib/contract.go index 71bc25fadc5..22f18fab434 100644 --- a/fvm/evm/stdlib/contract.go +++ b/fvm/evm/stdlib/contract.go @@ -371,6 +371,7 @@ var internalEVMTypeBalanceFunctionType = &sema.FunctionType{ ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.UFix64Type), } +// newInternalEVMTypeBalanceFunction returns the Flow balance of the account func newInternalEVMTypeBalanceFunction( gauge common.MemoryGauge, handler types.ContractHandler, @@ -395,7 +396,6 @@ func newInternalEVMTypeBalanceFunction( const isAuthorized = false account := handler.AccountByAddress(address, isAuthorized) - // todo return the Balance type return interpreter.UFix64Value(account.Balance()) }, ) From c47cd13b2165fa892e8df5a52b91ed1bb6e69b6a Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 4 Dec 2023 14:38:31 +0100 Subject: [PATCH 10/12] tidy --- integration/go.mod | 2 +- integration/go.sum | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/integration/go.mod b/integration/go.mod index b43f7a9d2ef..257f2407d2b 100644 --- a/integration/go.mod +++ b/integration/go.mod @@ -25,7 +25,7 @@ require ( github.com/onflow/flow-emulator v0.58.1-0.20231129190600-e2b8ff840867 github.com/onflow/flow-go v0.32.7 github.com/onflow/flow-go-sdk v0.41.16 - github.com/onflow/flow-go/crypto v0.24.9 + github.com/onflow/flow-go/crypto v0.24.10 github.com/onflow/flow-go/insecure v0.0.0-00010101000000-000000000000 github.com/onflow/flow/protobuf/go/flow v0.3.2-0.20231124194313-106cc495def6 github.com/plus3it/gorecurcopy v0.0.1 diff --git a/integration/go.sum b/integration/go.sum index 21e79dd6c5d..9e2e450a139 100644 --- a/integration/go.sum +++ b/integration/go.sum @@ -1410,6 +1410,7 @@ github.com/onflow/flow-go-sdk v0.41.16/go.mod h1:bVrVNoJKiwB6vW5Qbm5tFAfJBQ5we4u github.com/onflow/flow-go/crypto v0.21.3/go.mod h1:vI6V4CY3R6c4JKBxdcRiR/AnjBfL8OSD97bJc60cLuQ= github.com/onflow/flow-go/crypto v0.24.9 h1:0EQp+kSZYJepMIiSypfJVe7tzsPcb6UXOdOtsTCDhBs= github.com/onflow/flow-go/crypto v0.24.9/go.mod h1:fqCzkIBBMRRkciVrvW21rECKq1oD7Q6u+bCI78lfNX0= +github.com/onflow/flow-go/crypto v0.24.10/go.mod h1:O7jjGhgJEp94t9qXfBWdwW5BArm5L5gYa6XoBJiTdHc= github.com/onflow/flow-nft/lib/go/contracts v1.1.0 h1:rhUDeD27jhLwOqQKI/23008CYfnqXErrJvc4EFRP2a0= github.com/onflow/flow-nft/lib/go/contracts v1.1.0/go.mod h1:YsvzYng4htDgRB9sa9jxdwoTuuhjK8WYWXTyLkIigZY= github.com/onflow/flow/protobuf/go/flow v0.2.2/go.mod h1:gQxYqCfkI8lpnKsmIjwtN2mV/N2PIwc1I+RUK4HPIc8= From 20d26cef303731d255bca02cf9d20b2323e3d09b Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 4 Dec 2023 16:05:54 +0100 Subject: [PATCH 11/12] fix test to check balance type --- fvm/evm/stdlib/contract_test.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fvm/evm/stdlib/contract_test.go b/fvm/evm/stdlib/contract_test.go index 4bc657b9c50..c203b51a8ed 100644 --- a/fvm/evm/stdlib/contract_test.go +++ b/fvm/evm/stdlib/contract_test.go @@ -1150,7 +1150,11 @@ func TestEVMAccountBalance(t *testing.T) { contractsAddress := flow.BytesToAddress([]byte{0x1}) - expectedBalance, err := cadence.NewUFix64FromParts(1, 1337000) + expectedBalanceValue, err := cadence.NewUFix64FromParts(1, 1337000) + expectedBalance := cadence. + NewStruct([]cadence.Value{expectedBalanceValue}). + WithType(stdlib.NewBalanceCadenceType(common.Address(contractsAddress))) + require.NoError(t, err) var handler *testContractHandler @@ -1163,7 +1167,7 @@ func TestEVMAccountBalance(t *testing.T) { return &testFlowAccount{ address: fromAddress, balance: func() types.Balance { - return types.Balance(expectedBalance) + return types.Balance(expectedBalanceValue) }, } }, @@ -1178,7 +1182,7 @@ func TestEVMAccountBalance(t *testing.T) { import EVM from 0x1 access(all) - fun main(): UFix64 { + fun main(): EVM.Balance { let bridgedAccount <- EVM.createBridgedAccount() let balance = bridgedAccount.balance() destroy bridgedAccount From 4472290a60783559ae45be8e5006f97389a9c7a9 Mon Sep 17 00:00:00 2001 From: Gregor Gololicic Date: Mon, 11 Dec 2023 13:54:41 +0100 Subject: [PATCH 12/12] fix variable dec --- fvm/evm/stdlib/contract_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fvm/evm/stdlib/contract_test.go b/fvm/evm/stdlib/contract_test.go index c203b51a8ed..ec4b8249cbb 100644 --- a/fvm/evm/stdlib/contract_test.go +++ b/fvm/evm/stdlib/contract_test.go @@ -1157,8 +1157,7 @@ func TestEVMAccountBalance(t *testing.T) { require.NoError(t, err) - var handler *testContractHandler - handler = &testContractHandler{ + 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)