Skip to content

Commit

Permalink
Merge pull request #5538 from onflow/ramtin/5537-add-flow-token-bridg…
Browse files Browse the repository at this point in the history
…e-event

[Flow EVM] Adding FLOW token bridge event
  • Loading branch information
ramtinms authored Mar 21, 2024
2 parents 7af17df + 3f9a12c commit 02cdb60
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 10 deletions.
8 changes: 5 additions & 3 deletions fvm/evm/evm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -888,9 +888,11 @@ func setupCOA(
let vaultRef = account.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)
?? panic("Could not borrow reference to the owner's Vault!")
let vault <- vaultRef.withdraw(amount: amount) as! @FlowToken.Vault
cadenceOwnedAccount1.deposit(from: <-vault)
if amount > 0.0 {
let vault <- vaultRef.withdraw(amount: amount) as! @FlowToken.Vault
cadenceOwnedAccount1.deposit(from: <-vault)
}
account.save<@EVM.CadenceOwnedAccount>(<-cadenceOwnedAccount1,
to: /storage/coa)
account.link<&EVM.CadenceOwnedAccount{EVM.Addressable}>(/public/coa,
Expand Down
4 changes: 2 additions & 2 deletions fvm/evm/handler/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func TestHandler_TransactionRunOrPanic(t *testing.T) {
return result, nil
},
}
handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, bs, aa, backend, em)
handler := handler.NewContractHandler(flow.Emulator, rootAddr, flowTokenAddress, bs, aa, backend, em)

coinbase := types.NewAddress(gethCommon.Address{})

Expand Down Expand Up @@ -842,6 +842,6 @@ func SetupHandler(t testing.TB, backend types.Backend, rootAddr flow.Address) *h
aa := handler.NewAddressAllocator()
emulator := emulator.NewEmulator(backend, rootAddr)

handler := handler.NewContractHandler(flow.Testnet, rootAddr, flowTokenAddress, bs, aa, backend, emulator)
handler := handler.NewContractHandler(flow.Emulator, rootAddr, flowTokenAddress, bs, aa, backend, emulator)
return handler
}
27 changes: 27 additions & 0 deletions fvm/evm/stdlib/contract.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ contract EVM {
access(all)
event CadenceOwnedAccountCreated(addressBytes: [UInt8; 20])

/// FLOWTokensDeposited is emitted when FLOW tokens is bridged
/// into the EVM environment. Note that this event is not emitted
/// for transfer of flow tokens between two EVM addresses.
access(all)
event FLOWTokensDeposited(addressBytes: [UInt8; 20], amount: UFix64)

/// FLOWTokensWithdrawn is emitted when FLOW tokens are bridged
/// out of the EVM environment. Note that this event is not emitted
/// for transfer of flow tokens between two EVM addresses.
access(all)
event FLOWTokensWithdrawn(addressBytes: [UInt8; 20], amount: UFix64)

/// EVMAddress is an EVM-compatible address
access(all)
struct EVMAddress {
Expand Down Expand Up @@ -56,10 +68,15 @@ contract EVM {
/// Deposits the given vault into the EVM account with the given address
access(all)
fun deposit(from: @FlowToken.Vault) {
let amount = from.balance
if amount == 0.0 {
panic("calling deposit function with an empty vault is not allowed")
}
InternalEVM.deposit(
from: <-from,
to: self.bytes
)
emit FLOWTokensDeposited(addressBytes: self.bytes, amount: amount)
}
}

Expand Down Expand Up @@ -100,6 +117,12 @@ contract EVM {
fun inAttoFLOW(): UInt {
return self.attoflow
}

/// Returns true if the balance is zero
access(all)
fun isZero(): Bool {
return self.attoflow == 0
}
}

/// reports the status of evm execution.
Expand Down Expand Up @@ -220,10 +243,14 @@ contract EVM {
/// rounding error, this function would fail.
access(all)
fun withdraw(balance: Balance): @FlowToken.Vault {
if balance.isZero() {
panic("calling withdraw function with zero balance is not allowed")
}
let vault <- InternalEVM.withdraw(
from: self.addressBytes,
amount: balance.attoflow
) as! @FlowToken.Vault
emit FLOWTokensWithdrawn(addressBytes: self.addressBytes, amount: balance.inFLOW())
return <-vault
}

Expand Down
65 changes: 61 additions & 4 deletions fvm/evm/stdlib/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2987,8 +2987,10 @@ func TestEVMCreateCadenceOwnedAccount(t *testing.T) {
false,
)

// Run script
// reset events
events = make([]cadence.Event, 0)

// Run script
actual, err := rt.ExecuteScript(
runtime.Script{
Source: script,
Expand Down Expand Up @@ -3018,6 +3020,20 @@ func TestEVMCreateCadenceOwnedAccount(t *testing.T) {
))

require.Equal(t, expected, actual)

// check deposit event
expectedEventTypes := []string{
"EVM.CadenceOwnedAccountCreated",
"EVM.CadenceOwnedAccountCreated",
}
CheckCadenceEventTypes(t, events, expectedEventTypes)

// check cadence owned account created events
expectedCoaAddress := types.Address{3}
require.Equal(t, expectedCoaAddress.ToCadenceValue().ToGoValue(), events[0].Fields[0].ToGoValue())

expectedCoaAddress = types.Address{4}
require.Equal(t, expectedCoaAddress.ToCadenceValue().ToGoValue(), events[1].Fields[0].ToGoValue())
}

func TestCadenceOwnedAccountCall(t *testing.T) {
Expand Down Expand Up @@ -3270,10 +3286,12 @@ func TestCOADeposit(t *testing.T) {

var deposited bool

var expectedCoaAddress = types.Address{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

handler := &testContractHandler{

accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account {
assert.Equal(t, types.Address{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress)
assert.Equal(t, expectedCoaAddress, fromAddress)
assert.False(t, isAuthorized)

return &testFlowAccount{
Expand Down Expand Up @@ -3358,6 +3376,9 @@ func TestCOADeposit(t *testing.T) {

// Run script

// reset events before script execution
events = make([]cadence.Event, 0)

_, err = rt.ExecuteScript(
runtime.Script{
Source: script,
Expand All @@ -3371,6 +3392,22 @@ func TestCOADeposit(t *testing.T) {
require.NoError(t, err)

require.True(t, deposited)

// check deposit event
expectedEventTypes := []string{
"FlowToken.MinterCreated",
"FlowToken.TokensMinted",
"EVM.CadenceOwnedAccountCreated",
"EVM.FLOWTokensDeposited",
}
CheckCadenceEventTypes(t, events, expectedEventTypes)

// token deposit event
tokenDepositEvent := events[3]
// check address
require.Equal(t, expectedCoaAddress.ToCadenceValue().ToGoValue(), tokenDepositEvent.Fields[0].ToGoValue())
// check amount
require.Equal(t, expectedBalance.ToGoValue(), tokenDepositEvent.Fields[1].ToGoValue())
}

func TestCadenceOwnedAccountWithdraw(t *testing.T) {
Expand All @@ -3390,10 +3427,12 @@ func TestCadenceOwnedAccountWithdraw(t *testing.T) {

var nextUUID uint64 = 1

var expectedCoaAddress = types.Address{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

handler := &testContractHandler{
flowTokenAddress: common.Address(contractsAddress),
accountByAddress: func(fromAddress types.Address, isAuthorized bool) types.Account {
assert.Equal(t, types.Address{5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, fromAddress)
assert.Equal(t, expectedCoaAddress, fromAddress)
assert.Equal(t, deposited, isAuthorized)

return &testFlowAccount{
Expand Down Expand Up @@ -3498,8 +3537,9 @@ func TestCadenceOwnedAccountWithdraw(t *testing.T) {
false,
)

// reset events
events = make([]cadence.Event, 0)
// Run script

result, err := rt.ExecuteScript(
runtime.Script{
Source: script,
Expand All @@ -3517,6 +3557,23 @@ func TestCadenceOwnedAccountWithdraw(t *testing.T) {
assert.Equal(t, expectedWithdrawBalance, result)

assert.Equal(t, []string{"1"}, logs)

// check deposit event
expectedEventTypes := []string{
"FlowToken.MinterCreated",
"FlowToken.TokensMinted",
"EVM.CadenceOwnedAccountCreated",
"EVM.FLOWTokensDeposited",
"EVM.FLOWTokensWithdrawn",
}
CheckCadenceEventTypes(t, events, expectedEventTypes)

// token deposit event
tokenWithdrawEvent := events[4]
// check address
require.Equal(t, expectedCoaAddress.ToCadenceValue().ToGoValue(), tokenWithdrawEvent.Fields[0].ToGoValue())
// check amount
require.Equal(t, expectedWithdrawBalance.ToGoValue(), tokenWithdrawEvent.Fields[1].ToGoValue())
}

func TestCadenceOwnedAccountDeploy(t *testing.T) {
Expand Down
9 changes: 9 additions & 0 deletions fvm/evm/testutils/cadence.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strconv"
"strings"
"sync/atomic"
"testing"
"time"

"github.com/onflow/atree"
Expand All @@ -20,6 +21,7 @@ import (
"github.com/onflow/cadence/runtime/interpreter"
"github.com/onflow/cadence/runtime/sema"
cadenceStdlib "github.com/onflow/cadence/runtime/stdlib"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/attribute"
)

Expand Down Expand Up @@ -715,3 +717,10 @@ func (i *TestRuntimeInterface) InteractionUsed() (uint64, error) {

return i.OnInteractionUsed()
}

func CheckCadenceEventTypes(t testing.TB, events []cadence.Event, expectedTypes []string) {
require.Equal(t, len(events), len(expectedTypes))
for i, ev := range events {
require.Equal(t, expectedTypes[i], ev.EventType.QualifiedIdentifier)
}
}
2 changes: 1 addition & 1 deletion fvm/fvm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3325,7 +3325,7 @@ func TestEVM(t *testing.T) {

require.NoError(t, err)
require.NoError(t, output.Err)
require.Len(t, output.Events, 6)
require.Len(t, output.Events, 7)

evmLocation := types.EVMLocation{}
txExe, blockExe := output.Events[4], output.Events[5]
Expand Down

0 comments on commit 02cdb60

Please sign in to comment.