Skip to content

Commit

Permalink
Merge pull request onflow#5473 from onflow/ramtin/5468-part2-deposit-…
Browse files Browse the repository at this point in the history
…for-all-evm-addresses

[Flow EVM] make deposit available for all EVM addresses
  • Loading branch information
ramtinms authored Mar 5, 2024
2 parents d3d48b1 + db5594c commit 61ee9b4
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 4 deletions.
61 changes: 61 additions & 0 deletions fvm/evm/evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,67 @@ func TestEVMRun(t *testing.T) {
}

func TestEVMAddressDeposit(t *testing.T) {

t.Parallel()
chain := flow.Emulator.Chain()
sc := systemcontracts.SystemContractsForChain(chain.ChainID())
RunWithNewEnvironment(t,
chain, func(
ctx fvm.Context,
vm fvm.VM,
snapshot snapshot.SnapshotTree,
testContract *TestContract,
testAccount *EOATestAccount,
) {

code := []byte(fmt.Sprintf(
`
import EVM from %s
import FlowToken from %s
transaction(addr: [UInt8; 20]) {
prepare(account: AuthAccount) {
let admin = account.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)!
let minter <- admin.createNewMinter(allowedAmount: 1.0)
let vault <- minter.mintTokens(amount: 1.0)
destroy minter
let address = EVM.EVMAddress(addr)
address.deposit(from: <-vault)
}
}
`,
sc.EVMContract.Address.HexWithPrefix(),
sc.FlowToken.Address.HexWithPrefix(),
))

addr := RandomAddress(t)

tx := fvm.Transaction(
flow.NewTransactionBody().
SetScript(code).
AddAuthorizer(sc.FlowServiceAccount.Address).
AddArgument(json.MustEncode(cadence.NewArray(
ConvertToCadence(addr.Bytes()),
).WithType(stdlib.EVMAddressBytesCadenceType))),
0)

execSnap, output, err := vm.Run(
ctx,
tx,
snapshot)
require.NoError(t, err)
require.NoError(t, output.Err)

snapshot = snapshot.Append(execSnap)

expectedBalance := types.OneFlowBalance
bal := getEVMAccountBalance(t, ctx, vm, snapshot, addr)
require.Equal(t, expectedBalance, bal)
})
}

func TestCOAAddressDeposit(t *testing.T) {
t.Parallel()

chain := flow.Emulator.Chain()
Expand Down
14 changes: 10 additions & 4 deletions fvm/evm/stdlib/contract.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ contract EVM {
address: self.bytes
)
}

/// Deposits the given vault into the EVM account with the given address
access(all)
fun deposit(from: @FlowToken.Vault) {
InternalEVM.deposit(
from: <-from,
to: self.bytes
)
}
}

access(all)
Expand Down Expand Up @@ -201,10 +210,7 @@ contract EVM {
/// Deposits the given vault into the cadence owned account's balance
access(all)
fun deposit(from: @FlowToken.Vault) {
InternalEVM.deposit(
from: <-from,
to: self.addressBytes
)
self.address().deposit(from: <-from)
}

/// Withdraws the balance from the cadence owned account's balance
Expand Down
114 changes: 114 additions & 0 deletions fvm/evm/stdlib/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3143,6 +3143,120 @@ func TestEVMAddressDeposit(t *testing.T) {

t.Parallel()

expectedBalanceInUFix64, err := cadence.NewUFix64FromParts(1, 23000000)
require.NoError(t, err)
expectedBalance := types.NewBalanceFromUFix64(expectedBalanceInUFix64)

var deposited bool

handler := &testContractHandler{

accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account {
assert.Equal(t, types.Address{2, 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,
deposit: func(vault *types.FLOWTokenVault) {
deposited = true
assert.Equal(
t,
types.Balance(expectedBalance),
vault.Balance(),
)
},
}
},
}

contractsAddress := flow.BytesToAddress([]byte{0x1})

transactionEnvironment := newEVMTransactionEnvironment(handler, contractsAddress)
scriptEnvironment := newEVMScriptEnvironment(handler, contractsAddress)

rt := runtime.NewInterpreterRuntime(runtime.Config{})

script := []byte(`
import EVM from 0x1
import FlowToken from 0x1
access(all)
fun main() {
let admin = getAuthAccount(0x1)
.borrow<&FlowToken.Administrator>(from: /storage/flowTokenAdmin)!
let minter <- admin.createNewMinter(allowedAmount: 1.23)
let vault <- minter.mintTokens(amount: 1.23)
destroy minter
let address = EVM.EVMAddress(
bytes: [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
)
address.deposit(from: <-vault)
}
`)

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: LocationResolver,
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,
false,
)

// Run script

_, err = rt.ExecuteScript(
runtime.Script{
Source: script,
},
runtime.Context{
Interface: runtimeInterface,
Environment: scriptEnvironment,
Location: nextScriptLocation(),
},
)
require.NoError(t, err)

require.True(t, deposited)
}

func TestCOADeposit(t *testing.T) {

t.Parallel()

expectedBalance, err := cadence.NewUFix64FromParts(1, 23000000)
require.NoError(t, err)

Expand Down

0 comments on commit 61ee9b4

Please sign in to comment.