
@@ -159,28 +138,21 @@ Once confirmed, you should be able to see WFLOW balance in your tokens list in M
#### 2. Approve WFLOW Transfer
-Now that you have your WFLOW, you'll need to approve the `MaybeMintERC721` contract to transfer your WFLOW. From the
-same WFLOW page in Flowscan, click on the `approve` method. This time, you'll need to input the `MaybeMintERC721`
-contract address - `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2` - and the amount of WFLOW you want to approve - again `1
-000 000 000 000 000 000` WFLOW.
+Now that you have your WFLOW, you'll need to approve the `MaybeMintERC721` contract to transfer your WFLOW. From the same WFLOW page in Flowscan, click the `approve` method. This time, you'll need to input the `MaybeMintERC721` contract address - `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2` - and the amount of WFLOW you want to approve - again `1 000 000 000 000 000 000` WFLOW.

-Click `Write` to submit the transaction. To be clear, this does not complete a transfer, but allows the
-`MaybeMintERC721` contract to transfer your WFLOW on your behalf which will execute in the next step.
+Click `Write` to submit the transaction. To be clear, this does not complete a transfer, but allows the `MaybeMintERC721` contract to transfer your WFLOW on your behalf which will execute in the next step.
#### 3. Mint ERC721 Token
-Finally, we'll attempt to mint the ERC721 token using the `MaybeMintERC721` contract. Navigate to the `MaybeMintERC721`
-contract on Flowscan: [MaybeMintERC721].
+Finally, we'll attempt to mint the ERC721 token using the `MaybeMintERC721` contract. Navigate to the `MaybeMintERC721` contract on Flowscan: [MaybeMintERC721].
-Again, you'll be met with the contract functions on the `Write Contract` tab. Click on the `mint` function which takes
-no arguments - just click on `Write` and then `Confirm` in the resulting MetaMask window.
+Again, you'll see the contract functions on the `Write Contract` tab. Click the `mint` function which takes no arguments - just click `Write` and then `Confirm` in the MetaMask window.
-This contract has a 50% chance of failing on mint using onchain randomness. If it fails, simply mint again until it
-succeeds.
+This contract has a 50% chance of failing on mint using onchain randomness. If it fails, simply mint again until it succeeds.
-On success, you can click on your NFTs in MetaMask to see your newly minted token.
+When it succeeds, you can click your NFTs in MetaMask to see your newly minted token.

@@ -188,19 +160,15 @@ On success, you can click on your NFTs in MetaMask to see your newly minted toke
#### Recap
-This process is cumbersome and requires multiple transactions, each of which could fail. Given the intent of the process -
-minting an NFT - if this were a case where the NFT was a limited edition or time-sensitive, you'd be left with WFLOW
-wrapped and approved for transfer, but no NFT and would need to manually unwind the process.
+This process is cumbersome and requires multiple transactions, each of which could fail. Given the intent of the process - minting an NFT - if this were a case where the NFT was a limited edition or time-sensitive, you'd be left with WFLOW wrapped and approved for transfer, but no NFT and would need to manually unwind the process.
Or you could just use Cadence to batch these transactions and revert everything if the mint fails. Let's do that.
-### Using Flow Wallet
+### Use Flow Wallet
-Before diving into the "how", let's execute the batched version of everything we just did using Flow Wallet. This will
-give you a sense of the power of Cadence and the Flow blockchain.
+Before we dive into the "how", let's execute the batched version of everything we just did with Flow Wallet. This will give you a sense of the power of Cadence and the Flow blockchain.
-The transaction below, like all Cadence transactions, is scripted, allowing us to execute a series of actions. It may
-look like a lot at first, but we will break it down step by step in the following sections.
+The transaction below, like all Cadence transactions, is scripted, allowing us to execute a series of actions. It may look like a lot at first, but we will break it down step by step in the following sections.
@@ -352,57 +320,42 @@ transaction(wflowAddressHex: String, maybeMintERC721AddressHex: String) {
-You can run the transaction at the following link using the community-developed Flow Runner tool: [`wrap_and_mint.cdc`].
+You can run the transaction at the following link with the community-developed Flow Runner tool: [`wrap_and_mint.cdc`].
This transaction takes two arguments:
- WFLOW contract address: `0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e`
- MaybeMintERC721 contract address: `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2`
-Before running, ensure that the network section - bottom right corner - displays Testnet. If not, click and select
-`Testnet` as your network and refresh. Once you've confirmed you're Flow Runner is targeting Testnet, copy these
-addresses and paste them into the respective fields on the Flow Runner page. Click `Run` on the top left and follow the
-prompts to connect your Flow Wallet and sign the transaction.
+Before you run the tool, ensure that the network section - bottom right corner - displays Testnet. If not, click and select `Testnet` as your network and refresh. Once you've confirmed you're Flow Runner is targeting Testnet, copy these addresses and paste them into the respective fields on the Flow Runner page. Click `Run` on the top left and follow the prompts to connect your Flow Wallet and sign the transaction.
:::warning
-Although we are running a manual transaction for the purposes of this walkthrough, you should always be careful to
-review the transaction details before signing and submitting.
+Although we are running a manual transaction for the purposes of this walkthrough, always be careful to review the transaction details before you sign and submit.
:::
-Again, since the ERC721 has a 50% chance of failing, you may need to run the transaction multiple times until it
-succeeds. However note that if the mint fails, the entire transaction will revert, unwinding the wrapped FLOW and
-approval.
+Again, since the ERC721 has a 50% chance of failing, you may need to run the transaction multiple times until it succeeds. However, note that if the mint fails, the entire transaction will revert, unwinding the wrapped FLOW and approval.
-Again, since the ERC721 has a 50% chance of failure and the success of the transaction is conditioned on successfully
-minting, your transaction may fail. If it does fail, importantly the entire transaction reverts, unwinding the wrapped
+Again, since the ERC721 has a 50% chance of failure and the success of the transaction is conditioned on successfully minting, your transaction may fail. If it does fail, importantly the entire transaction reverts, unwinding the wrapped
FLOW deposit and approval - the wrapping and approval transactions **do not execute** in the event of mint failure! This
-is the main takeaway of this guide, that you embed a whole sequence of EVM transactions into one atomic operation using
-Cadence and if the primary intent (or intents) does not execute, everything else is reverted as well.
+is the main takeaway of this guide, that you embed a whole sequence of EVM transactions into one atomic operation using Cadence and if the primary intent (or intents) does not execute, everything else is reverted as well.
-In our case, you'll want to submit a transaction until one succeeds. Once you submit a successful transaction, you'll
-see a transaction ID with event logs in the Flow Runner output. Let's take a closer look at the transaction and its
-results in the Flowscan block explorer.
+In our case, you'll want to submit a transaction until one succeeds. After you submit a successful transaction, you'll see a transaction ID with event logs in the Flow Runner output. Let's take a closer look at the transaction and its results in the Flowscan block explorer.

Copy your transaction ID and go to the Flowscan Testnet Cadence block explorer: [Flowscan Cadence].
-Pasting your transaction ID into the search bar will show you the transaction details, including the Cadence script,
-execution status, and event logs. Click on the `EVM` tab to view the EVM transactions batched in the Cadence
-transaction.
+When you paste your transaction ID into the search bar, you'll see the transaction details, such as the Cadence script, execution status, and event logs. Click the `EVM` tab to view the EVM transactions batched in the Cadence transaction.

-Clicking on the transactions will open up the EVM transaction in Flowscan's EVM block explorer. If you view the EVM
-transactions in order, you'll notice that they aggregate the same actions we took manually in the MetaMask section, but
-this time in a single Cadence transaction!
+Click the transactions to open up the EVM transaction in Flowscan's EVM block explorer. If you view the EVM transactions in order, you'll notice that they aggregate the same actions we took manually in the MetaMask section, but this time in a single Cadence transaction!
-## Breaking it Down
+## Breaking it down
-Now that we can relate to the pain of manually executing these transactions and we've seen the magic you can work with
-Cadence, let's understand what's going on under the hood.
+Now that we can relate to the pain of manually executing these transactions and we've seen the magic you can work with Cadence, let's understand what's going on under the hood.
To recap, our Cadence transaction does the following, reverting if any step fails:
@@ -410,27 +363,17 @@ To recap, our Cadence transaction does the following, reverting if any step fail
2. Approves the `MaybeMintERC721` contract to move WFLOW
3. Attempts to mint a `MaybeMintERC721` token
-But how does our Flow account interact with EVM from the Cadence runtime? As you'll recall from the [Interacting with
-COA](./interacting-with-coa.md) guide, we use a Cadence-owned account (COA) to interact with EVM contracts from Cadence.
+But how does our Flow account interact with EVM from the Cadence runtime? As you'll recall from the [Interacting with COA](./interacting-with-coa.md) guide, we use a Cadence-owned account (COA) to interact with EVM contracts from Cadence.
-A COA is a [resource] providing an interface through which Cadence can interact with the EVM runtime. This is
-importantly **_in addition_** to the traditional routes you'd normally access normal EVMs - e.g. via the JSON-RPC API.
-And with this interface, we can take advantage of all of the benefits of Cadence - namely here scripted transactions and
-conditional execution.
+A COA is a [resource] providing an interface through which Cadence can interact with the EVM runtime. This is **_in addition to_** to the traditional routes you'd normally access normal EVMs - such as via the JSON-RPC API. And with this interface, we can take advantage of all of the benefits of Cadence - namely here scripted transactions and conditional execution.
-So in addition to the above steps, our transaction first configures a COA in the signer's account if one doesn't already
-exist. It then funds the COA with enough FLOW to cover the mint cost, sourcing funds from the signing Flow account's
-Cadence Vault. Finally, it wraps FLOW as WFLOW, approves the ERC721 contract to move the mint amount, and attempts to
-mint the ERC721 token.
+So, in addition to the above steps, our transaction first configures a COA in the signer's account if one doesn't already exist. It then funds the COA with enough FLOW to cover the mint cost, sourcing funds from the signing Flow account's Cadence Vault. Finally, it wraps FLOW as WFLOW, approves the ERC721 contract to move the mint amount, and attempts to mint the ERC721 token.
Let's see what each step looks like in the transaction code.
### COA Configuration
-The first step in our transaction is to configure a COA in the signer's account if one doesn't already exist. This is
-done by creating a new COA resource and saving it to the signer account's storage. A public Capability on the COA is
-then issued and published on the signer's account, allowing anyone to deposit FLOW into the COA, affecting its EVM
-balance.
+The first step in our transaction is to configure a COA in the signer's account if one doesn't already exist. To do this, create a new COA resource and save it to the signer account's storage. A public Capability on the COA is then issued and published on the signer's account, allowing anyone to deposit FLOW into the COA, affecting its EVM balance.
```cadence
/* COA configuration & assignment */
@@ -456,21 +399,17 @@ self.coa = signer.storage.borrow
(from:
.concat(" - ensure the COA Resource is created and saved at this path to enable EVM interactions"))
```
-At the end of this section, the transaction now has an reference authorized with the `EVM.Call` [entitlement] to use in
-the `execute` block which can be used call into EVM.
+At the end of this section, the transaction now has an reference authorized with the `EVM.Call` [entitlement] to use in the `execute` block which can be used call into EVM.
You can run a transaction that does just this step here: [`setup_coa.cdc`]
-Since you ran the all-in-one transaction previously, your account already has a COA configured in which case the linked
-transaction won't do anything. You can lookup your Testnet account's EVM address with the script below to confirm you
-have a COA configured. Simply input your Testnet Flow address and click `Run`.
+Since you ran the all-in-one transaction previously, your account already has a COA configured in which case the linked transaction won't do anything. You can lookup your Testnet account's EVM address with the script below to confirm you have a COA configured. Simply input your Testnet Flow address and click `Run`.
-### Funding the COA
+### Fund the COA
-Next, we fund the COA with enough FLOW to cover the mint cost. This is done by withdrawing FLOW from the signer's
-FlowToken Vault and depositing it into the COA.
+Next, we fund the COA with enough FLOW to cover the mint cost. To do this, withdraw FLOW from the signer's FlowToken Vault and deposit it into the COA.
```cadence
/* Fund COA with cost of mint */
@@ -499,19 +438,15 @@ pre {
}
```
-This isn't absolutely necessary as successive steps would fail on this condition, but helps provide enhanced error
-messages in the event of insufficient funds.
+This isn't absolutely necessary as successive steps would fail on this condition, but helps provide enhanced error messages in the event of insufficient funds.
-You can run the above block in a transaction here which will move 1 FLOW from your account's Cadence FLOW balance to
-your account's EVM balance, depositing it directly to your pre-configured COA: [`fund_coa.cdc`]
+You can run the above block in a transaction here which will move one FLOW from your account's Cadence FLOW balance to your account's EVM balance and deposit it directly to your pre-configured COA: [`fund_coa.cdc`]
-After running the linked transaction, you can check your COA's FLOW balance with the script below, just enter your COA's
-EVM address (which you can get from the previous script). The resulting balance should be 1.0 (unless you've funded your
-COA prior to this walkthrough).
+After you run the linked transaction, you can check your COA's FLOW balance with the script below, just enter your COA's EVM address (which you can get from the previous script). The balance should be 1.0 (unless you've funded your COA prior to this walkthrough).
-### Setting our EVM Contract Targets
+### Setting our EVM contract argets
The last step in our transaction's `prepare` block is to deserialize the provided WFLOW and ERC721 contract addresses
from hex strings to EVM addresses.
@@ -531,9 +466,7 @@ self.erc721Address = EVM.addressFromString(maybeMintERC721AddressHex)
### Wrapping FLOW as WFLOW
-Next, we're on to the first EVM interaction - wrapping FLOW as WFLOW. This is done by encoding the `deposit()` function
-call and setting the call value to the mint cost. The COA then calls the WFLOW contract with the encoded calldata, gas
-limit, and value.
+Next, we're on to the first EVM interaction - wrapping FLOW as WFLOW. To do this, encode the `deposit()` function call and sett the call value to the mint cost. The COA then calls the WFLOW contract with the encoded calldata, gas limit, and value.
```cadence
/* Wrap FLOW in EVM as WFLOW */
@@ -555,7 +488,7 @@ assert(
)
```
-Setting the value of the call transmits FLOW along with the call to the contract, accessible in solidity as `msg.value`.
+When you set the value of the call, it transmits FLOW along with the call to the contract, accessible in solidity as `msg.value`.
:::tip
@@ -565,35 +498,27 @@ You'll notice a general pattern among all EVM calls in this transaction:
2. Calling the contract
3. Asserting the call was successful
-Here we're just interested in a successful call, but we could access return data if it were expected and relevant for
-our Cadence transaction. This returned data is accessible from the `data` field on the `EVM.Result` object returned from
-`coa.call(...)`. This data would then be decoded using `EVM.decodeABI(...)`. More on this in later guides.
+Here we're just interested in a successful call, but we could access return data if it were expected and relevant for our Cadence transaction. This returned data is accessible from the `data` field on the `EVM.Result` object returned from `coa.call(...)`. This data would then be decoded with `EVM.decodeABI(...)`. More on this in later guides.
:::
You can run the above code as a transaction here: [`wrap_flow.cdc`]
-After running the transaction, your COA should have a WFLOW balance of 1.0 WFLOW. Confirm your WFLOW balance by running
-the script below, providing your Flow account address, the WFLOW address of `0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e`
-and your COA's EVM address (retrieved from a previous script):
+After you run the transaction, your COA should have a WFLOW balance of 1.0 WFLOW. To confirm your WFLOW balance, run the script below, and provide your Flow account address, the WFLOW address of `0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` and your COA's EVM address (retrieved from a previous script):
-Since Solidity does not support decimal precision, the returned balance will look like a large number. In the case of
-WFLOW, we can recover the decimals by shifting the decimal place 18 digits to the left. Your account should have `1`
-WFLOW or `1000000000000000000` as returned.
+Since Solidity does not support decimal precision, the returned balance will look like a large number. In the case of WFLOW, to recover the decimals, shift the decimal place 18 digits to the left. Your account should have `1` WFLOW or `1000000000000000000` as returned.
:::warning
-Note that the number of places to shift varies by ERC20 implementation -- the default value is 18, but it's not safe to
-assume this value. You can check a token's decimal places by calling `ERC20.decimals()(uint8)`.
+The number of places to shift varies by ERC20 implementation -- the default value is 18, but it's not safe to assume this value. To check a token's decimal places, call `ERC20.decimals()(uint8)`.
:::
-### Approving the ERC721 Contract
+### Approve the ERC721 contract
-Once the FLOW is wrapped as WFLOW, we approve the ERC721 contract to move the mint amount. This is done by encoding the
-`approve(address,uint256)` calldata and calling the WFLOW contract with the encoded calldata.
+After the FLOW is wrapped as WFLOW, we approve the ERC721 contract to move the mint amount. To do this, encode the `approve(address,uint256)` calldata and call the WFLOW contract with the encoded calldata.
```cadence
/* Approve the ERC721 address for the mint amount */
@@ -616,23 +541,19 @@ assert(
)
```
-You can run this approval using the transaction, passing the WFLOW address of
-`0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` and MaybeMintERC721 address of `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2`
+You can run this approval with the transaction. Passing the WFLOW address of `0xd3bF53DAC106A0290B0483EcBC89d40FcC961f3e` and MaybeMintERC721 address of `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2`
: [`approve_maybe_mint_erc721.cdc`]
-The linked transaction will perform the approval step, authorizing the ERC721 to transfer WFLOW to cover the mint cost
-when `mint()` is called. Confirm the contract allowance by running the script below. Pass your Flow address, WFLOW
+The linked transaction will perform the approval step, which authorizes the ERC721 to transfer WFLOW to cover the mint cost when `mint()` is called. Confirm the contract allowance by running the script below. Pass your Flow address, WFLOW
address, ERC721 address, and your COA's EVM address.
-The result is the amount of your WFLOW balance the ERC721 is allowed to transfer, which after the transaction should be
-`1` WFLOW, or `1000000000000000000` as returned.
+The result is the amount of your WFLOW balance the ERC721 is allowed to transfer, which after the transaction should be `1` WFLOW, or `1000000000000000000` as returned.
-### Minting the ERC721 Token
+### Mint the ERC721 Token
-Finally, we attempt to mint the ERC721 token. This is done by encoding the `mint()` calldata and calling the ERC721
-contract with the encoded calldata. If the mint fails, the entire transaction is reverted.
+Finally, we attempt to mint the ERC721 token. To do this, encode the `mint()` calldata and call the ERC721 contract with the encoded calldata. If the mint fails, the entire transaction is reverted.
```cadence
/* Attempt to mint ERC721 */
@@ -653,55 +574,42 @@ assert(
)
```
-You can run the minting transaction here, passing the ERC721 address of `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2`:
+You can run the minting transaction here. Pass the ERC721 address of `0x2E2Ed0Cfd3AD2f1d34481277b3204d807Ca2F8c2`:
[`mint.cdc`]
-Again, this transaction may fail. But if you executed all the prior stepwise transactions according to the walkthrough,
-you can try again until the mint succeeds. Recall that you can view your transaction details using Cadence [Flowscan]
-which will also let you view the embedded EVM transactions in the `EVM` tab. Try it out, and see if you can figure out
-how to get your minted NFT's URI with the script below.
+Again, this transaction may fail. But if you executed all the prior stepwise transactions according to the walkthrough, you can try again until the mint succeeds. Recall that you can view your transaction details using Cadence [Flowscan] which will also let you view the embedded EVM transactions in the `EVM` tab. Try it out, and see if you can figure out how to get your minted NFT's URI with the script below.
### Recap
-All of the stepwise transactions you just executed are compiled in the first Cadence transaction we ran. Hopefully,
-going through the process step by step illuminates the power and flexibility of Cadence, allowing you to write
-transactions as simple or as complex as you want.
+All of the stepwise transactions you just executed are compiled in the first Cadence transaction we ran. Hopefully, going through the process step by step illuminates the power and flexibility of Cadence, allowing you to write transactions as simple or as complex as you want.
-While lengthy transactions can be intimidating and even a bit verbose at times, the flexibility afforded by the language
-means you are only limited by your imagination. Cadence transactions allow you to support the most streamlined of
-experiences, incorporating as many contracts as needed to support your use case.
+While lengthy transactions can be intimidating and even a bit verbose at times, the flexibility afforded by the language means you are only limited by your imagination. Cadence transactions allow you to support the most streamlined of experiences, incorporating as many contracts as needed to support your use case.
## Conclusion
-In this guide, we've demonstrated how to batch EVM transactions using Cadence, allowing you to conditionally execute
-multiple EVM transactions in a single Cadence transaction. While this guide focused on relatively simple EVM operations,
-the principles can be applied to much more complex and interesting applications.
+In this guide, we've demonstrated how to batch EVM transactions using Cadence, allowing you to conditionally execute multiple EVM transactions in a single Cadence transaction. While this guide focused on relatively simple EVM operations, the principles can be applied to much more complex and interesting applications.
In the process, you learned how to:
-- Read and write from smart contract functions on EVM Flowscan
-- Run a Cadence transaction from the browser using [Flow Runner]
-- Execute batched EVM transactions via a COA in a Cadence transaction
-- Condition final transaction execution on success of all EVM transactions
-- Inspect multiple EVM transactions embedded in a Cadence transaction with [Flowscan] block explorer
+- Read and write from smart contract functions on EVM Flowscan.
+- Run a Cadence transaction from the browser using [Flow Runner].
+- Execute batched EVM transactions via a COA in a Cadence transaction.
+- Condition final transaction execution on success of all EVM transactions.
+- Inspect multiple EVM transactions embedded in a Cadence transaction with [Flowscan] block explorer.
-The biggest takeaway here isn't the specific actions taken in this walkthrough, but the overarching concept that you can
-use **Cadence as an orchestration layer** to **extend existing EVM contracts**, creating unique user experiences with
-the power **to differentiate your Web3 application**.
+The biggest takeaway here isn't the specific actions taken in this walkthrough, but the overarching concept that you can use **Cadence as an orchestration layer** to **extend existing EVM contracts**, which allows you to create unique user experiences with the power **to differentiate your Web3 application**.
-With these basics in hand, you're ready to start building more complex applications that leverage the power of Cadence
-and the Flow blockchain. How will you use these features to build Web3's next killer app?
+With these basics in hand, you're ready to start building more complex applications that leverage the power of Cadence and the Flow blockchain. How will you use these features to build Web3's next killer app?
## Further Reading
-Now that you've experienced the power of Cadence and EVM interactions firsthand, we recommend checking out the following
-guides to deepen your understanding:
+Now that you've experienced the power of Cadence and EVM interactions firsthand, we recommend checking out the following guides to deepen your understanding:
-- [How Flow EVM Works] - Learn more about the Flow EVM and how it differs from traditional EVM platforms
-- [Interacting with COAs] - Get a fuller picture of how Cadence interacts with EVM contracts via Cadence-owned accounts
-- [Cadence Transactions] - Learn more about the Cadence transaction model
+- [How Flow EVM Works] - Learn more about the Flow EVM and how it differs from traditional EVM platforms.
+- [Interacting with COAs] - Get a fuller picture of how Cadence interacts with EVM contracts via Cadence-owned accounts.
+- [Cadence Transactions] - Learn more about the Cadence transaction model.
Ready to level up your Cadence skills? Take a look at [these Cadence tutorials].
diff --git a/docs/blockchain-development-tutorials/cross-vm-apps/direct-calls.md b/docs/blockchain-development-tutorials/cross-vm-apps/direct-calls.md
index 28d7edde25..07398e7ac1 100644
--- a/docs/blockchain-development-tutorials/cross-vm-apps/direct-calls.md
+++ b/docs/blockchain-development-tutorials/cross-vm-apps/direct-calls.md
@@ -4,11 +4,13 @@ sidebar_label: Direct Calls to Flow EVM
sidebar_position: 4
---
-Direct calls from Cadence to Flow EVM are essential for enabling Cadence smart contracts to interact seamlessly with the EVM environment hosted on the Flow blockchain. These calls facilitate a range of functionalities including state queries and transaction initiations, allowing Cadence contracts to leverage EVM-based tools and assets.
+# Direct Calls from Cadence to Flow EVM
-## Making Direct Calls
+Direct calls from Cadence to Flow EVM are essential to allow Cadence smart contracts to interact seamlessly with the EVM environment hosted on the Flow blockchain. These calls facilitate a range of functionalities including state queries and transaction initiations, allowing Cadence contracts to leverage EVM-based tools and assets.
-### Accessing Flow EVM
+## Make direct calls
+
+### Access Flow EVM
To interact with Flow EVM, Cadence contracts must first import `EVM` from its service address:
@@ -16,15 +18,15 @@ To interact with Flow EVM, Cadence contracts must first import `EVM` from its se
import EVM from
```
-Next, create an `EVMAddress` with a sequence of 20 bytes representing the EVM address:
+Next, create an `EVMAddress` with a sequence of 20 bytes that represents the EVM address:
```js
let addr = EVM.EVMAddress(bytes: bytes)
```
-Once you have access to an `EVMAddress`, you can query various pieces of state information such as:
+After you can access an `EVMAddress`, you can query various pieces of state information such as:
-- `balance() EVM.Balance` provides the balance of the address. It returns a balance object rather than a basic type to avoid errors when converting from flow to atto-flow.
+- `balance() EVM.Balance` provides the balance of the address. It returns a balance object rather than a basic type to avoid errors when it converts from flow to atto-flow.
- `nonce() UInt64` retrieves the nonce associated with the address.
- `code(): [UInt8]` fetches the code at the address; it returns the smart contract code if applicable, and is empty otherwise.
@@ -51,9 +53,9 @@ fun main(addressHex: String): UFix64 {
}
```
-### Sending Transactions to Flow EVM
+### Send transactions to Flow EVM
-To send transactions to Flow EVM, use the `run` function which executes RLP-encoded transactions. RLP (Recursive Length Prefix) encoding is used to efficiently encode data into a byte-array format, suitable for Ethereum-based environments. Here's an example of wrapping and sending a transaction:
+To send transactions to Flow EVM, use the `run` function which executes RLP-encoded transactions. RLP (Recursive Length Prefix) encoding is used to efficiently encode data into a byte-array format, suitable for Ethereum-based environments. Here's an example of how to wrap and send a transaction:
```cadence
import EVM from
@@ -71,28 +73,28 @@ transaction(rlpEncodedTransaction: [UInt8], coinbaseBytes: [UInt8; 20]) {
}
```
-Using `run` restricts an EVM block to a single EVM transaction, while a future `batchRun` will offer the capability to execute multiple EVM transactions in a batch.
+When you `run`, it restricts an EVM block to a single EVM transaction, while a future `batchRun` will offer the capability to execute multiple EVM transactions in a batch.
-### Handling Transaction Responses
+### Handle transaction responses
-Handling responses correctly is crucial to manage the state changes or errors that occur during `EVM` transactions:
+It's crucial that your function handles responses correctly to manage the state changes or errors that occur during `EVM` transactions:
-When calling `EVM.run`, it's important to understand that this method does not revert the outer Flow transaction. Developers must therefore carefully handle the response based on the `result.Status` of the EVM transaction execution. There are three main outcomes to consider:
+When you call `EVM.run`, it's important to understand that this method does not revert the outer Flow transaction. Developers must therefore carefully handle the response based on the `result.Status` of the EVM transaction execution. There are three main outcomes to consider:
-- `Status.invalid`: This status indicates that the transaction or call failed at the validation step, such as due to a nonce mismatch. Transactions with this status are not executed or included in a block, meaning no state change occurs.
-- `Status.failed`: This status is assigned when the transaction has technically succeeded in terms of being processable, but the EVM reports an error as the outcome, such as running out of gas. Importantly, a failed transaction or call is still included in a block. Attempting to resubmit a failed transaction will result in an `invalid` status on the second try due to a now incorrect nonce.
-- `Status.successful`: This status is given when the transaction or call is successfully executed and no errors are reported by the EVM.
+- `Status.invalid`: This status indicates that the transaction or call failed at the validation step, such as due to a nonce mismatch. Transactions with this status are not executed or included in a block, which means no state change occurs.
+- `Status.failed`: This status is assigned when the transaction has technically succeeded in terms of being processable, but the EVM reports an error as the outcome, such as running out of gas. Importantly, a failed transaction or call is still included in a block. Any attempt to resubmit a failed transaction results in an `invalid` status on the second try due to a now incorrect nonce.
+- `Status.successful`: This status appears when the transaction or call is successfully executed and the EVM doesn't report errors.
-For scenarios where transaction validity is critical, developers may choose to use the `mustRun` variation, which reverts the transaction in the case of a validation failure, providing an added layer of error handling.
+For scenarios where transaction validity is critical, developers may choose to use the `mustRun` variation, which reverts the transaction in the case of a validation failure. This provides an added layer of error handling.
-### Understanding Gas Usage in EVM Transactions
+### Understanding gas usage in EVM transactions
-Direct calls to Flow EVM require gas, it's important to understand how gas usage is calculated and billed. During the execution of methods that interact with the EVM:
+Direct calls to Flow EVM require gas. It's important to understand how gas usage is calculated and billed. During the execution of methods that interact with the EVM:
-- **Gas Aggregation**: The gas used by each call is aggregated throughout the transaction.
-- **Gas Adjustment**: The total gas used is then adjusted based on a multiplier. This multiplier is determined by the network and can be adjusted by the service account to reflect operational costs and network conditions.
-- **Payment of Gas Fees**: The adjusted total gas amount is added to the overall computation fees of the Flow transaction. These fees are paid by the transaction initiator, commonly referred to as the payer.
+- **Gas Aggregation**: The gas that each call uses is aggregated throughout the transaction.
+- **Gas Adjustment**: The total gas used is then adjusted based on a multiplier. This multiplier is determined by the network and the service account can adjust it to reflect operational costs and network conditions.
+- **Payment of Gas Fees**: The adjusted total gas amount is added to the overall computation fees of the Flow transaction. The transaction initiator, commonly referred to as the payer, pays these fees.
-## Keep Learning
+## Keep learning
For more information and a deeper dive into the `EVMAddress`, `Result`, and `Status` objects, see [the contract here](https://github.com/onflow/flow-go/blob/master/fvm/evm/stdlib/contract.cdc).
diff --git a/docs/blockchain-development-tutorials/cross-vm-apps/index.md b/docs/blockchain-development-tutorials/cross-vm-apps/index.md
index e5b408666e..e02c0ba187 100644
--- a/docs/blockchain-development-tutorials/cross-vm-apps/index.md
+++ b/docs/blockchain-development-tutorials/cross-vm-apps/index.md
@@ -14,39 +14,39 @@ keywords:
- cross-VM bridge
---
-# Cross-VM App Tutorials
+# Cross-VM App tutorials
-This series covers how to build cross-VM applications that integrate Flow EVM with Flow Cadence, unlocking new capabilities by combining both environments. Flow's unique architecture enables seamless interaction between Cadence smart contracts and EVM-compatible contracts, allowing developers to leverage the best features of both virtual machines in a single application.
+This series covers how to build cross-VM applications that integrate Flow EVM with Flow Cadence, which combines new environments and unlocks new capabilities. Flow's unique architecture allows seamless interaction between Cadence smart contracts and EVM-compatible contracts, which allows developers to leverage the best features of both virtual machines in a single application.
## Tutorials
### [Batched Transactions]
-Learn to create hybrid applications using FCL, wagmi, and RainbowKit that connect simultaneously to Flow EVM and Flow Cadence. This comprehensive tutorial demonstrates building "Click to Mint," a game where users can mint ERC-20 tokens individually or batch 10 transactions with a single signature using Cadence's powerful multi-call functionality. You'll integrate traditional EVM development tools with Flow's advanced features while maintaining familiar wagmi/viem patterns. The tutorial covers project setup, wallet integration, smart contract interaction, and UI/UX improvements for cross-VM applications.
+Learn to create hybrid applications with Flow Command Line (FCL), wagmi, and RainbowKit that connect simultaneously to Flow EVM and Flow Cadence. This comprehensive tutorial demonstrates how to build "Click to Mint," a game where users can mint ERC-20 tokens individually or batch 10 transactions with a single signature with Cadence's powerful multi-call functionality. You'll integrate traditional EVM development tools with Flow's advanced features while maintaining familiar wagmi/viem patterns. The tutorial covers project setup, wallet integration, smart contract interaction, and UI/UX improvements for cross-VM applications.
### [Add Flow Cadence to Your wagmi App]
-Discover how to enhance your existing wagmi/RainbowKit applications by integrating Flow Cadence functionality without rebuilding from scratch. This guide shows you how to add FCL to your current EVM-based dApp to enable advanced features like batched transactions, native randomness, and account abstraction. You'll learn to manage concurrent connections to both Flow EVM and Cadence environments while maintaining your existing user interface and development workflows. The tutorial provides step-by-step integration strategies and best practices for hybrid application architecture.
+Discover how to enhance your wagmi/RainbowKit applications. You can integrate Flow Cadence functionality and not rebuild them from scratch. This guide shows you how to add FCL to your current EVM-based dApp to allow advanced features like batched transactions, native randomness, and account abstraction. You'll learn to manage concurrent connections to both Flow EVM and Cadence environments and maintain your current user interface and development workflows. The tutorial provides step-by-step integration strategies and best practices for hybrid application architecture.
### [Interacting with COAs]
-Master the creation and management of Cadence Owned Accounts (COAs), which enable Cadence smart contracts to control EVM accounts on Flow. This tutorial covers setting up COAs, understanding their permissions model, and implementing secure interactions between Cadence and EVM environments. You'll learn how to deploy and manage EVM contracts from Cadence, handle cross-VM asset transfers, and implement proper access controls for hybrid applications.
+Master how to create and manage Cadence Owned Accounts (COAs), which allow Cadence smart contracts to control EVM accounts on Flow. This tutorial covers how to set up COAs, details their permissions model, and shows how to implement secure interactions between Cadence and EVM environments. You'll learn how to deploy and manage EVM contracts from Cadence, handle cross-VM asset transfers, and implement proper access controls for hybrid applications.
### [Batched EVM Transactions]
-Explore advanced techniques for executing multiple EVM transactions atomically within a single Cadence transaction. This guide demonstrates how to batch complex EVM operations like multi-step DeFi protocols, NFT minting sequences, or arbitrage strategies while maintaining transaction atomicity. You'll learn to handle transaction failures gracefully, optimize gas usage across batched calls, and implement error handling for complex multi-transaction workflows.
+Explore advanced techniques for how to execute multiple EVM transactions atomically within a single Cadence transaction. This guide demonstrates how to batch complex EVM operations like multi-step DeFi protocols, NFT minting sequences, or arbitrage strategies and maintain transaction atomicity. You'll learn to handle transaction failures gracefully, optimize gas usage across batched calls, and implement error handling for complex multi-transaction workflows.
### [Direct Calls to Flow EVM]
-Learn how Cadence smart contracts can directly interact with Flow EVM without requiring separate user transactions. This technical guide covers making direct calls from Cadence to query EVM state, execute EVM transactions programmatically, and handle responses and errors appropriately. You'll understand gas calculation models, transaction status handling, and best practices for integrating direct EVM calls into your Cadence contracts.
+Learn how Cadence smart contracts can directly interact with Flow EVM without the need to separate user transactions. This technical guide covers how to make direct calls from Cadence to query EVM state, execute EVM transactions programmatically, and handle responses and errors appropriately. You'll understand gas calculation models, transaction status handling, and best practices for how to integrate direct EVM calls into your Cadence contracts.
### [Cross-VM Bridge]
-Explore the automated bridging of fungible and non-fungible tokens between Flow Cadence and Flow EVM environments. This comprehensive guide covers the Cross-VM Bridge protocol, which enables atomic movement of ERC-20, ERC-721, and Flow native tokens between virtual machines. You'll learn to onboard tokens to the bridge, implement custom token associations, handle bridging fees, and design tokens that work seamlessly across both Cadence and EVM environments.
+Explore the automated bridging of fungible and non-fungible tokens between Flow Cadence and Flow EVM environments. This comprehensive guide covers the Cross-VM Bridge protocol, which allows atomic movement of ERC-20, ERC-721, and Flow native tokens between virtual machines. You'll learn to onboard tokens to the bridge, implement custom token associations, handle bridging fees, and design tokens that work seamlessly across both Cadence and EVM environments.
## Conclusion
-Cross-VM applications represent the future of blockchain development on Flow, combining Cadence's innovative resource-oriented programming with EVM's ecosystem compatibility. These tutorials provide the foundation for building sophisticated applications that leverage both virtual machines, enabling developers to create unique experiences that wouldn't be possible on single-VM blockchains while maintaining compatibility with existing Ethereum tooling and user expectations.
+Cross-VM applications represent the future of blockchain development on Flow, which combines Cadence's innovative resource-oriented programming with EVM's ecosystem compatibility. These tutorials provide the foundation for you to build sophisticated applications that leverage both virtual machines, which allows developers to create unique experiences that wouldn't be possible on single-VM blockchains and maintain compatibility with current Ethereum tooling and user expectations.
[Batched Transactions]: ./introduction.md
[Add Flow Cadence to Your wagmi App]: ./add-to-wagmi.md
diff --git a/docs/blockchain-development-tutorials/cross-vm-apps/interacting-with-coa.md b/docs/blockchain-development-tutorials/cross-vm-apps/interacting-with-coa.md
index 665ba94b20..4d11c89e63 100644
--- a/docs/blockchain-development-tutorials/cross-vm-apps/interacting-with-coa.md
+++ b/docs/blockchain-development-tutorials/cross-vm-apps/interacting-with-coa.md
@@ -4,22 +4,19 @@ sidebar_label: Interacting with COAs
sidebar_position: 5
---
-[Cadence Owned Accounts (COAs)](../../build/evm/accounts.md#cadence-owned-accounts) are EVM accounts owned by a Cadence resource and
-are used to interact with Flow EVM from Cadence.
+# Interacting with COAs from Cadence
-COAs expose two interfaces for interaction: one on the Cadence side and one on the EVM side. In this guide, we will
-focus on how to interact with COAs with Cadence.
+[Cadence Owned Accounts (COAs)](../../build/evm/accounts.md#cadence-owned-accounts) are EVM accounts that a Cadence resouce owns, and are used to interact with Flow EVM from Cadence.
-In this guide we will walk through some basic examples creating and interacting with a COA in Cadence. Your specific
-usage of the COA resource will depend on your own application's requirements (e.g. the COA resource may not live
-directly in `/storage/evm` as in these examples, but may instead be a part of a more complex resource structure).
+COAs expose two interfaces for interaction: one on the Cadence side and one on the EVM side. In this guide, we focuses on how to interact with COAs with Cadence.
+
+In this guide, we will walk through some basic examples that create and and interact with a COA in Cadence. Your specific usage of the COA resource will depend on your own application's requirements (for example, the COA resource may not live directly in `/storage/evm` as in these examples, but may instead be a part of a more complex resource structure).
## COA Interface
-To begin, we can take a look at a simplified version of the `EVM` contract, highlighting parts specific to COAs.
+To begin, we can take a look at a simplified version of the `EVM` contract, and highlight parts specific to COAs.
-You can learn more about the `EVM` contract [here](../../build/cadence/core-contracts/13-evm.md) and the full contract code can
-be found on [GitHub](https://github.com/onflow/flow-go/tree/master/fvm/evm/stdlib/contract.cdc).
+You can learn more about the `EVM` contract [here](../../build/cadence/core-contracts/13-evm.md) and find the full contract code on [GitHub](https://github.com/onflow/flow-go/tree/master/fvm/evm/stdlib/contract.cdc).
```cadence EVM.cdc
access(all)
@@ -80,14 +77,11 @@ contract EVM {
}
```
-## Importing the EVM Contract
+## Import the EVM contract
-The `CadenceOwnedAccount` resource is a part of the `EVM` system contract, so to use any of these functions, you will
-need to begin by importing the `EVM` contract into your Cadence code.
+The `CadenceOwnedAccount` resource is a part of the `EVM` system contract, so to use any of these functions, you will need to import the `EVM` contract into your Cadence code.
-To import the `EVM` contract into your Cadence code using the simple import syntax, you can use the following format
-(learn more about configuring contracts in `flow.json`
-[here](../../build/tools/flow-cli/flow.json/configuration.md#contracts)):
+To import the `EVM` contract into your Cadence code using the simple import syntax, you can use the following format (learn more about configuring contracts in `flow.json` [here](../../build/tools/flow-cli/flow.json/configuration.md#contracts)):
```cadence
// This assumes you are working in the in the Flow CLI, FCL, or another tool that supports this syntax
@@ -104,16 +98,14 @@ import EVM from 0x1234
// ...
```
-To find the deployment addresses of the `EVM` contract, you can refer to the [EVM contract
-documentation](../../build/cadence/core-contracts/13-evm.md).
+To find the deployment addresses of the `EVM` contract, you can refer to the [EVM contract documentation](../../build/cadence/core-contracts/13-evm.md).
-## Creating a COA
+## Create a COA
To create a COA, we can use the `createCadenceOwnedAccount` function from the `EVM` contract. This function takes no
-arguments and returns a new `CadenceOwnedAccount` resource which represents this newly created EVM account.
+arguments and returns a new `CadenceOwnedAccount` resource which represents this newly-created EVM account.
-For example, we can create this COA in a transaction, saving it to the user's storage and publishing a public capability
-to its reference:
+For example, we can create this COA in a transaction, save it to the user's storage, and publish a public capability to its reference:
```cadence create_coa.cdc
import "EVM"
@@ -135,17 +127,17 @@ transaction() {
}
```
-### Creating a Cadence Account and COA together
+### Create a Cadence account and COA together
-It is possible to create a new Cadence account and COA within the same transaction. This transaction will need to be signed and paid for by another account, but any account will do. A common process is to set up a backend service to handle this function.
+It is possible to create a new Cadence account and COA within the same transaction. Another account will need to sign and pay for this transaction, but any account will do. A common process is to set up a backend service to handle this function.
:::info
-During the singular transaction in which an account is created, the `AuthAccount` object for the newly created account is present. As a result, the creating account can access and modify the new account's storage **only** during this transaction.
+During the singular transaction in which an account is created, the `AuthAccount` object for the newly-created account is present. As a result, the creating account can access and modify the new account's storage **only** during this transaction.
:::
-First, you'll need to use the CLI to [generate keys](../../build/tools/flow-cli/keys/generate-keys.md) for the new account. Then, simply run the following transaction to create the Cadence Account and COA at once.
+First, you'll need to use the CLI to [generate keys](../../build/tools/flow-cli/keys/generate-keys.md) for the new account. Then, run the following transaction to create the Cadence Account and COA at one time.
:::warning
@@ -174,11 +166,9 @@ transaction(publicKeys: [Crypto.KeyListEntry]) {
}
```
-## Getting the EVM Address of a COA
+## Retrieve the EVM Address of a COA
-To get the EVM address of a COA, you can use the `address` function from the `EVM` contract. This function returns the
-EVM address of the COA as an `EVM.Address` struct. This struct is used to represent addresses within Flow EVM and can
-also be used to query the balance, code, nonce, etc. of an account.
+To get the EVM address of a COA, you can use the `address` function from the `EVM` contract. This function returns the EVM address of the COA as an `EVM.Address` struct. This struct is used to represent addresses within Flow EVM and you cna also use it to query the balance, code, nonce, and so on of an account.
For our example, we could query the address of the COA we just created with the following script:
@@ -201,19 +191,17 @@ fun main(address: Address): EVM.EVMAddress {
}
```
-If you'd prefer the hex representation of the address, you instead return using the `EVMAddress.toString()` function:
+If you'd prefer the hex representation of the address, you instead return with the `EVMAddress.toString()` function:
```cadence
return coa.address().toString()
```
-The above will return the EVM address as a string; however note that Cadence does not prefix hex strings with `0x`.
+The above will return the EVM address as a string; however, Cadence does not prefix hex strings with `0x`.
-## Getting the Flow Balance of a COA
+## Retrieve the Flow balance of a COA
-Like any other Flow EVM or Cadence account, COAs possess a balance of FLOW tokens. To get the current balance of our
-COA, we can use the COA's `balance` function. It will return a `EVM.Balance` struct for the account - these are used to
-represent balances within Flow EVM.
+Like any other Flow EVM or Cadence account, COAs possess a balance of FLOW tokens. To get the current balance of our COA, we can use the COA's `balance` function. It will return a `EVM.Balance` struct for the account - these are used to represent balances within Flow EVM.
This script will query the current balance of our newly created COA:
@@ -250,16 +238,13 @@ fun main(addressHex: String): UFix64 {
The above script is helpful if you already know the COA address and can provide the hex representation directly.
-## Depositing and Withdrawing Flow Tokens
+## Deposit and withdraw Flow tokens
-Tokens can be seamlessly transferred between the Flow EVM and Cadence environment using the `deposit` and `withdraw`
-functions provided by the COA resource. Anybody with a valid reference to a COA may deposit Flow tokens into a it,
-however only someone with the `Owner` or `Withdraw` entitlements can withdraw tokens.
+You can seamlessly transfer tokens between the Flow EVM and Cadence environment with the `deposit` and `withdraw` functions that the COA resource provides. Anybody with a valid reference to a COA may deposit Flow tokens into a it, however only someone with the `Owner` or `Withdraw` entitlements can withdraw tokens.
-### Depositing Flow Tokens
+### Deposit Flow tokens
-The `deposit` function takes a `FlowToken.Vault` resource as an argument, representing the tokens to deposit. It will
-transfer the tokens from the vault into the COA's balance.
+The `deposit` function takes a `FlowToken.Vault` resource as an argument, which represents the tokens to deposit. It will transfer the tokens from the vault into the COA's balance.
This transaction will withdraw Flow tokens from a user's Cadence vault and deposit them into their COA:
@@ -295,18 +280,15 @@ transaction(amount: UFix64) {
:::info
-This is a basic example which only transfers tokens between a single user's COA & Flow account. It can be easily
-modified to transfer these tokens between any arbitrary accounts.
+This is a basic example which only transfers tokens between a single user's COA & Flow account. You can easily modify it to transfer these tokens between any arbitrary accounts.
-You can also deposit tokens directly into other types of EVM accounts using the `EVM.EVMAddress.deposit` function. See
-the [EVM contract documentation](../../build/cadence/core-contracts/13-evm.md) for more information.
+You can also deposit tokens directly into other types of EVM accounts with the `EVM.EVMAddress.deposit` function. See the [EVM contract documentation](../../build/cadence/core-contracts/13-evm.md) for more information.
:::
-### Withdrawing Flow Tokens
+### Withdraw Flow tokens
-The `withdraw` function takes a `EVM.Balance` struct as an argument, representing the amount of Flow tokens to withdraw,
-and returns a `FlowToken.Vault` resource with the withdrawn tokens.
+The `withdraw` function takes a `EVM.Balance` struct as an argument, which represents the amount of Flow tokens to withdraw, and returns a `FlowToken.Vault` resource with the withdrawn tokens.
We can run the following transaction to withdraw Flow tokens from a user's COA and deposit them into their Flow vault:
@@ -424,10 +406,9 @@ more interpretable and therefore transparent transaction.
:::
-### Transferring FLOW in EVM
+### Transfer FLOW in EVM
-Similar to transferring ETH and other native value in other EVMs, you'll want to call to the target EVM address with
-empty calldata and providing the transfer value.
+Similar to when you trasnfer ETH and other native value in other EVMs, you'll want to call to the target EVM address with empty calldata and provide the transfer value.
```cadence transfer_evm_flow.cdc
import "EVM"
@@ -476,8 +457,7 @@ transaction(to: String, amount: UInt) {
### Transfer ERC20
-Below is an example transaction demonstrating the common ERC20 transfer. A similar pattern can be used for other
-arbitrary EVM calls.
+Below is an example transaction demonstrating the common ERC20 transfer. You can use a similar pattern for other arbitrary EVM calls.
```cadence erc20_transfer_from.cdc
import "EVM"
@@ -572,12 +552,9 @@ transaction(erc721AddressHex: String, to: String, id: UInt256) {
}
```
-#### Bulk Transfer ERC721
+#### Bulk transfer ERC721
-As covered in the [Batched EVM transactions walkthrough](./batched-evm-transactions.md), you can script multiple EVM
-calls in a single Cadence transaction. Compared to the single ERC721 transfer, bulk sending multiple tokens isn't much
-more code and allows for greater utility out of a single transaction. Below is an example of a bulk ERC721 token
-transfer.
+As covered in the [Batched EVM transactions walkthrough](./batched-evm-transactions.md), you can script multiple EVM calls in a single Cadence transaction. Compared to the single ERC721 transfer, to bulk send multiple tokens isn't much more code and allows for greater utility out of a single transaction. Below is an example of a bulk ERC721 token transfer.
```cadence erc721_bulk_transfer.cdc
import "EVM"
@@ -630,12 +607,11 @@ transaction(erc721AddressHex: String, to: String, ids: [UInt256]) {
}
```
-## Deploying a Contract to Flow EVM
+## Deploy a contract to Flow EVM
-To deploy a contract to the EVM, you can use the `deploy` function provided by the COA resource. This function takes the
-contract code, gas limit, and value you want to send. It will return the EVM address of the newly deployed contract.
+To deploy a contract to the EVM, you can use the `deploy` function that the COA resource provides. This function takes the contract code, gas limit, and value you want to send. It will return the EVM address of the newly deployed contract.
-This transaction will deploy a contract with the given code using the signer's COA:
+This transaction will deploy a contract with the given code with the signer's COA:
```cadence deploy_evm_contract.cdc
import "EVM"
@@ -662,11 +638,10 @@ transaction(bytecode: String) {
}
```
-## More Information
+## More information
-For more information about Cadence Owned Accounts, see [Flow EVM Accounts](../../build/evm/accounts.md).
+For more information about Cadence-owned Accounts, see [Flow EVM Accounts](../../build/evm/accounts.md).
-Other useful snippets for interacting with COAs can be found [here](https://fw-internal-doc.gitbook.io/evm).
+Other useful snippets to use when you interact with COAs can be found [here](https://fw-internal-doc.gitbook.io/evm).
-Check out the [Batched EVM Transactions walkthrough](./batched-evm-transactions.md) for details on transaction batching
-using Cadence.
+Check out the [Batched EVM Transactions walkthrough](./batched-evm-transactions.md) for details on transaction batching with Cadence.
diff --git a/docs/blockchain-development-tutorials/cross-vm-apps/introduction.md b/docs/blockchain-development-tutorials/cross-vm-apps/introduction.md
index 3d7e2b3cdc..796b073cb3 100644
--- a/docs/blockchain-development-tutorials/cross-vm-apps/introduction.md
+++ b/docs/blockchain-development-tutorials/cross-vm-apps/introduction.md
@@ -22,51 +22,53 @@ keywords:
- supercharge your EVM app with Cadence
---
-Ever since the launch of Flow EVM, it's been possible to _supercharge_ your EVM apps by using Flow Cadence features and contracts. Some benefits, such as [native VRF] and inexpensive gas without compromising security are built in and either easy or automatic to use. Others, such as the ability to use [Cadence] to [structure and call EVM transactions], are powerful but complicated to configure and use. They also require developers to manage concurrent connections to both networks.
+# Batched Tx From Scaffold
+
+Ever since we launched Flow EVM, you can _supercharge_ your EVM apps with Flow Cadence features and contracts. Some benefits, such as [native VRF] and inexpensive gas that won't compromise security, are built in and either easy to use or automatic. Others, such as the ability to use [Cadence] to [structure and call EVM transactions], are powerful but complicated to configure and use. They also require developers to manage concurrent connections to both networks.
[FLIP 316] improves the [Flow Client Library (FCL)] to support cross-VM functionality between Flow EVM and Flow Cadence.
For EVM developers, this means that you can use the familiar [wagmi], [viem], and [RainbowKit] stack you're used to, add FCL, and get features like **multi-call write** with one signature for users with a Cadence-compatible [wallet].
-In this tutorial, you'll learn how to create [Click to Mint], a simple game that allows players to mint an ERC-20 token by clicking a button. With the power of Flow, they can also click a button, and **complete 10 separate transactions with just one approval!**
+In this tutorial, you'll learn how to create [Click to Mint], a simple game that allows players to click a button to mint an ERC-20 token. With the power of Flow, they can also click a button and **complete 10 separate transactions with just one approval!**

:::warning
-The FCL functionality described in this tutorial is in alpha. Some steps may change. We'll keep the tutorial updated, but please [create an issue] or let us know on [Discord] if something isn't working for you.
+The FCL functionality described in this tutorial is in alpha. Some steps may change. We'll keep the tutorial updated, but please [create an issue] or let us know on [Discord] if something doesn't ork for you.
:::
## Objectives
-After completing this guide, you'll be able to:
+After you complete this guide, you'll be able to:
-- Build an app that seamlessly integrates Flow Cadence and Flow EVM connections
-- Add Cadence features to your [Rainbowkit]/[wagmi]/[viem] app
-- Utilize [Flow Client Library (FCL)] to enable multi-call contract writes to Flow EVM
+- Build an app that seamlessly integrates Flow Cadence and Flow EVM connections.
+- Add Cadence features to your [Rainbowkit]/[wagmi]/[viem] app.
+- Use [Flow Client Library (FCL)] to turn on multi-call contract writes to Flow EVM.
## Prerequisites
-### Next.js and Modern Frontend Development
+### Next.js and modern frontend development
-This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development using a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. If you don't have your own preference, you can just follow along with us and use [npm].
+This tutorial uses [Next.js]. You don't need to be an expert, but it's helpful to be comfortable with development with a current React framework. You'll be on your own to select and use a package manager, manage Node versions, and other frontend environment tasks. If you don't have your own preference, you can just follow along with us and use [npm].
-### Solidity and Cadence Smart Contract Development
+### Solidity and Cadence smart contract development
-Apps using the hybrid approach can interact with both [Cadence] and [Solidity] smart contracts. You don't need to be an expert in either of these, but it's helpful to be familiar with how smart contracts work in at least one of these languages.
+Apps that use the hybrid approach can interact with both [Cadence] and [Solidity] smart contracts. You don't need to be an expert in either of these, but it's helpful to be familiar with how smart contracts work in at least one of these languages.
-### Onchain App Frontends
+### Onchain app frontends
-We're assuming you're familiar with [wagmi], [viem], and [RainbowKit]. If you're coming from the Cadence, you might want to take a quick look at the getting started guides for these platforms. They're all excellent and will rapidly get you up to speed on how the EVM world commonly connects their apps to their contracts.
+We assume you're familiar with [wagmi], [viem], and [RainbowKit]. If you come from the Cadence, you might want to take a quick look at the getting started guides for these platforms. They're all excellent and will rapidly get you up to speed on how the EVM world commonly connects their apps to their contracts.
-## Getting Started
+## Get started
-For this tutorial, we'll be starting from a fork of the [FCL + RainbowKit + Wagmi Integration Demo] built by the team.
+For this tutorial, we'll start from a fork of the [FCL + RainbowKit + Wagmi Integration Demo] built by the team.
Fork the repo so you can push your work freely to your own copy, then follow the setup instructions.
-## Project Overview
+## Project overview
Open the cross-vm app scaffold in your editor, run it, and view the site in your browser:
@@ -86,7 +88,7 @@ In a production app, you'll want to manage this process carefully. Non-Cadence E
:::
-## Send Batch Transactions
+## Send batch transactions
The first demo built into this scaffold is **multi-call contract write**.
@@ -104,11 +106,11 @@ Currently, the Flow wallet sponsors all gas for all transactions signed with the
:::
-### Cadence Parent Transaction
+### Cadence parent transaction
-The first line is the transaction id of the Flow Cadence transaction that calls **both** of the EVM transactions. Search for it in [Testnet Cadence Flowscan].
+The first line is the transaction ID of the Flow Cadence transaction that calls **both** of the EVM transactions. Search for it in [Testnet Cadence Flowscan].
-Cadence transactions are more complicated than those in Solidity contracts. Rather than being restricted to running functions present on the contract, they can run arbitrary code as long as the caller has access to all of the resources required by the transaction.
+Cadence transactions are more complicated than those in Solidity contracts. Rather than being restricted to run functions present on the contract, they can run arbitrary code as long as the caller has access to all of the resources required by the transaction.
You can see the code of the transaction in the `Script` tab, but we've included it here for convenience:
@@ -153,19 +155,19 @@ transaction(calls: [{String: AnyStruct}], mustPass: Bool) {
}
```
-In this case, it's checking that the caller of the Cadence transaction has permission to control to the EVM account, which is built in for [Cadence Owned Accounts]. The `execute` phase then iterates through the EVM transactions and uses the Cadence accounts own permissions to sign the EVM transactions.
+In this case, it checks that the caller of the Cadence transaction has permission to control to the EVM account, which is built in for [Cadence Owned Accounts]. The `execute` phase then iterates through the EVM transactions and uses the Cadence accounts own permissions to sign the EVM transactions.
The loop also handles a check for the optional flag to cancel all of the transactions if any one of them fails. **In other words, you could set up a 20 transaction arbitrage attempt and unwind everything if it fails at any step!**
-### EVM Child Transactions
+### EVM child transactions
-The next two lines show the transaction hashes for the EVM transactions. You can view this in [Testnet EVM Flowscan] by searching for the transaction hashes, the same as any other.
+The next two lines show the transaction hashes for the EVM transactions. To view this in [Testnet EVM Flowscan], search for the transaction hashes, the same as any other.
Look up both transactions.
-The first is calling the `deposit()` function to wrap FLOW and move it to EVM.
+The first calls the `deposit()` function to wrap FLOW and move it to EVM.
-The second is calling the ERC-20 `approve()` function to give another address the authority to spend those tokens.
+The second calls the ERC-20 `approve()` function to give another address the authority to spend those tokens.
For the demo, the code for this is hard-coded into `src/app/page.tsx`:
@@ -212,7 +214,7 @@ const calls: EVMBatchCall[] = [
It's called with the `useBatchTransaction` hook via the `sendBatchTransaction(calls)` function.
-## Code Evaluator
+## Code evaluator
The demo also has an embedded code evaluator that you can use to experiment with snippets of code from `fcl` or `wagmi`.
@@ -232,15 +234,15 @@ return block.height;
Returns the current Cadence VM block number.
-## Calling Your Own Contract
+## Calling Your own contract
Next, we'll update the starter to connect to and call functions in our own contract. For this, we'll use a simple [Button Clicker Contract]. You can deploy your own copy, or use the one deployed at [`0xA7Cf2260e501952c71189D04FAd17c704DFB36e6`].
-## Set Up Contract Imports
+## Set Up contract imports
:::info
-The following steps assume deployment with Hardhat Ignition. If you are using a different deployment method, import the contract address and abi as appropriate.
+The following steps assume deployment with Hardhat Ignition. If you use a different deployment method, import the contract address and abi as appropriate.
:::
@@ -260,9 +262,9 @@ export const clickToken = {
};
```
-## Build Traditional Functionality
+## Build traditional functionality
-This isn't a wagmi tutorial, so we'll give you some components to speed up the process. Add a folder called `components` inside `src` and add the following files.
+This isn't a wagmi tutorial, so we'll give you some components to speed up the process. Add a folder called `components` inside `src` and add the following files:
`TheButton.tsx`
@@ -522,7 +524,7 @@ You'll now see the button and scoreboard from the contract. Test it out and earn

-## Supercharge your EVM App With Cadence
+## Supercharge your EVM app With Cadence
Now let's supercharge it. With the power of Cadence, you can use multi-call write and give your users way more tokens with a single click and single signature!
@@ -541,7 +543,7 @@ const calls: EVMBatchCall[] = [
];
```
-Try clicking the `Send Batch Transaction Example` button again. You'll have to **manually refresh** the page when the EVM transaction hash appears to see the score update. We haven't wired in the query invalidation yet.
+Click the `Send Batch Transaction Example` button again. You'll have to **manually refresh** the page when the EVM transaction hash appears to see the score update. We haven't wired in the query invalidation yet.
Next, use some JavaScript to put 10 copies of the transaction call into the array:
@@ -554,19 +556,19 @@ const calls: EVMBatchCall[] = Array.from({ length: 10 }, () => ({
}));
```
-Click the button again and **manually** refresh page once the transaction hashes appear.
+Click the button again and **manually** refresh page after the transaction hashes appear.
**You just minted 10 tokens from 10 transactions with one signature!**
## Improve the UI/UX
-While we've got the batched transactions feature working, we've got a few flaws in the user experience that we'll need to resolve, and we should make this a bit nicer looking.
+While the batched transactions feature works, we've got a few flaws in the user experience that we'll need to resolve, and we should make this look a bit nicer.
### Install Tailwind
:::warning
-We initially tried getting an AI friend to install this for us and it got very confused. Next.js and Tailwind have both had a lot of change recently. As a result, the LLMs don't seem to have caught up just yet.
+We initially tried getting an AI friend to install this for us and it got very confused. `Next.js` and Tailwind have both had a lot of change recently. As a result, the LLMs don't seem to have caught up just yet.
Do this part the old-fashioned way.
@@ -597,9 +599,9 @@ Then, add the following to the top of `src/styles/global.css`:
Run the app and make sure you see some styling. It won't look nice yet. We'll help you reorganize the components and hook up state monitoring, but it will be up to you to style the app how you'd like. You can check out the [reference repo] for inspiration, but it's far from perfect or beautiful.
-### Update State Display
+### Update state display
-The first thing we'll need to fix is that the user has to refresh the window manually to see the results of the batched transaction in the scoreboard. Start by moving the functionality in `page.tsx` into a new component, called `SuperButton.tsx`. Note that we're mimicking the pattern in `TheButton.tsx` where the blockchain state is managed in `Content.tsx` and we're passing in the relevant information and functions as props:
+The first thing we'll need to fix is that the user has to refresh the window manually to see the results of the batched transaction in the scoreboard. To start, move the functionality in `page.tsx` into a new component, called `SuperButton.tsx`. We mimic the pattern in `TheButton.tsx` where the blockchain state is managed in `Content.tsx`, and we pass in the relevant information and functions as props:
```tsx
'use client';
@@ -680,7 +682,7 @@ export default function SuperButton({
}
```
-You should end up with a vastly simplified `page.tsx`:
+You will end up with a vastly simplified `page.tsx`:
```tsx
import Content from '../components/Content';
@@ -772,9 +774,9 @@ return (
### Testing
-Run the app and make sure it's working as expected, even if in a rather ugly fashion.
+Run the app and make sure it works as expected, even if in a rather ugly fashion.
-### Add UI Hints
+### Add UI hints
With this kind of app, you're likely to have two types of users. Those that have upgraded to the [Flow Wallet] can take advantage of advanced features such as batched transactions, and those who haven't cannot.
@@ -795,13 +797,13 @@ It's up to you to make the app pretty. If you need inspiration, you can always c
## Conclusion
-In this tutorial, you reviewed the demo starter for building hybrid applications that utilize a common EVM stack and integrate with Flow Cadence. You then added functionality to interface with another contract that mints ERC-20 tokens. Finally, you supercharged your app by using the power of Cadence for EVM multi-call contract writes.
+In this tutorial, you reviewed the demo starter for building hybrid applications that use a common EVM stack and integrate with Flow Cadence. You then added functionality to interface with another contract that mints ERC-20 tokens. Finally, you supercharged your app by using the power of Cadence for EVM multi-call contract writes.
-Now that you have completed the tutorial, you should be able to:
+Now that you have completed the tutorial, you will be able to:
-- Build an app that seamlessly integrates Flow Cadence and Flow EVM connections
-- Add Cadence features to your [Rainbowkit]/[wagmi]/[viem] app
-- Utilize [Flow Client Library (FCL)] to enable multi-call contract writes to Flow EVM
+- Build an app that seamlessly integrates Flow Cadence and Flow EVM connections.
+- Add Cadence features to your [Rainbowkit]/[wagmi]/[viem] app.
+- Use [Flow Client Library (FCL)] to enable multi-call contract writes to Flow EVM.
diff --git a/docs/blockchain-development-tutorials/cross-vm-apps/vm-bridge.md b/docs/blockchain-development-tutorials/cross-vm-apps/vm-bridge.md
index 5ce7f44884..0e8bb1b700 100644
--- a/docs/blockchain-development-tutorials/cross-vm-apps/vm-bridge.md
+++ b/docs/blockchain-development-tutorials/cross-vm-apps/vm-bridge.md
@@ -6,38 +6,27 @@ sidebar_position: 6
# Cross-VM Bridge
-Flow provides the [Cross-VM Bridge](https://www.github.com/onflow/flow-evm-bridge) which enables the movement of
-fungible and non-fungible tokens between Flow-Cadence & Flow-EVM. The Cross-VM Bridge is a contract-based protocol enabling the
-automated and atomic bridging of tokens from Cadence into EVM with their corresponding ERC-20 and ERC-721 token types.
-In the opposite direction, it supports bridging of arbitrary ERC-20 and ERC-721 tokens from EVM to Cadence as their
-corresponding FT or NFT token types.
-
-By default, when a user onboards a new token to the bridge,
-the bridge will deploy a standard token contract in the other VM that only the core bridge
-protocol contracts retain limited control over. This bridge-deployed contract handles basic
-minting and metadata operations that are required for usage in the needed environment.
-If a developer wants to define and connect the NFT contracts on both sides of the bridge,
-they can have each contract point to each other to indicate that they are associated and then
-register that association with the bridge so the token moves between VMs as either definition.
-
-The Cross-VM Bridge internalizes the capabilities to deploy new token contracts in either VM state as needed, resolving
-access to, and maintaining links between associated contracts. It additionally automates account and contract calls to
-enforce source VM asset burn or lock, and target VM token mint or unlock.
-
-Developers wishing to use the Cross-VM Bridge will be required to use a Cadence transaction. Cross-VM bridging
-functionality is not currently available natively in Flow EVM. By extension, this means that the EVM account bridging
-from EVM to Cadence must be a [`CadenceOwnedAccount` (COA)](./interacting-with-coa.md) as this is the only EVM account
-type that can be controlled from the Cadence runtime.
-
-This [FLIP-233](https://github.com/onflow/flips/pull/233) outlines the architecture and implementation of the VM bridge.
-An additional [FLIP-318](https://github.com/onflow/flips/blob/main/application/20250131-cross-vm-nft-support.md) describes how developers can create custom associations
+Flow provides the [Cross-VM Bridge](https://www.github.com/onflow/flow-evm-bridge) which allows the movement of fungible and non-fungible tokens between Flow-Cadence & Flow-EVM. The Cross-VM Bridge is a contract-based protocol which allows the automated and atomic bridging of tokens from Cadence into EVM with their corresponding ERC-20 and ERC-721 token types.
+
+In the opposite direction, it supports bridging of arbitrary ERC-20 and ERC-721 tokens from EVM to Cadence as their corresponding FT or NFT token types.
+
+By default, when a user onboards a new token to the bridge, the bridge will deploy a standard token contract in the other VM that only the core bridge protocol contracts retain limited control over. This bridge-deployed contract handles basic minting and metadata operations that are required for usage in the needed environment.
+
+If a developer wants to define and connect the NFT contracts on both sides of the bridge, they can have each contract point to each other to indicate that they are associated and then register that association with the bridge so the token moves between VMs as either definition.
+
+The Cross-VM Bridge internalizes the capabilities to deploy new token contracts in either VM state as needed, resolves access to and maintains links between associated contracts. It also automates account and contract calls to enforce source VM asset burn or lock, and target VM token mint or unlock.
+
+Developers who want to use the Cross-VM Bridge must use a Cadence transaction. Cross-VM bridging functionality is not currently available natively in Flow EVM. By extension, this means that the EVM account bridging
+from EVM to Cadence must be a [`CadenceOwnedAccount` (COA)](interacting-with-coa.md) as this is the only EVM account type that can be controlled from the Cadence runtime.
+
+This [FLIP-233](https://github.com/onflow/flips/pull/233) outlines the architecture and implementation of the VM bridge. An additional [FLIP-318](https://github.com/onflow/flips/blob/main/application/20250131-cross-vm-nft-support.md) describes how developers can create custom associations
between NFTs they define and control in each VM.
-This document will focus on how to use the Cross-VM Bridge and considerations for fungible and non-fungible token
-projects deploying to either Cadence or EVM.
+
+This document will focus on how to use the Cross-VM Bridge and considerations for fungible and non-fungible token projects that deploy to either Cadence or EVM.
## Deployments
-The core bridge contracts can be found at the following addresses:
+You can find the core bridge contracts at the following addresses:
| Contracts | Testnet | Mainnet |
| ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
@@ -59,81 +48,50 @@ as you'll find the Cadence contracts (see above).
:::info
-All bridging activity in either direction is orchestrated via Cadence on COA EVM accounts. This means that all bridging
-activity must be initiated via a Cadence transaction, not an EVM transaction regardless of the directionality of the
-bridge request. For more information on the interplay between Cadence and EVM, see [How Flow EVM
+All bridging activity in either direction is orchestrated via Cadence on COA EVM accounts. This means that all bridging activity must be initiated via a Cadence transaction, not an EVM transaction regardless of the directionality of the bridge request. For more information on the interplay between Cadence and EVM, see [How Flow EVM
Works](../../build/evm/how-it-works.md).
:::
## Overview
-The Flow EVM bridge allows both fungible and non-fungible tokens to move atomically between Cadence and EVM. In the
-context of EVM, fungible tokens are defined as ERC20 tokens, and non-fungible tokens as ERC721 tokens. In Cadence,
-fungible tokens are defined by contracts implementing
-[the `FungibleToken` interface](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc)
-and non-fungible tokens implement
-[the `NonFungibleToken` interface](https://github.com/onflow/flow-nft/blob/master/contracts/NonFungibleToken.cdc).
-
-You can find full guides for creating these projects [here](../tokens/nft-cadence.md).
+The Flow EVM bridge allows both fungible and non-fungible tokens to move atomically between Cadence and EVM. In EVM, fungible tokens are defined as ERC20 tokens, and non-fungible tokens as ERC721 tokens. In Cadence, fungible tokens are defined by contracts that implement [the `FungibleToken` interface](https://github.com/onflow/flow-ft/blob/master/contracts/FungibleToken.cdc)
+and non-fungible tokens implement [the `NonFungibleToken` interface](https://github.com/onflow/flow-nft/blob/master/contracts/NonFungibleToken.cdc).
+You can find full guides to create these projects [here](../tokens/nft-cadence.md).
-Like all operations on Flow, there are native fees associated with both computation and storage. To prevent spam and
-sustain the bridge account's storage consumption, fees are charged for both onboarding assets and bridging assets. In
-the case where storage consumption is expected, fees are charged based on the storage consumed at the current network
-storage rate.
+Like all operations on Flow, there are native fees associated with both computation and storage. To prevent spam and sustain the bridge account's storage consumption, fees are charged for both onboarding assets and bridging assets. In the case where storage consumption is expected, fees are charged based on the storage consumed at the current network storage rate.
-## Onboarding Your token to the Bridge
+## Onboard your token to the bridge
-For the purpose of this guide, we are assuming that the developer has already deployed
-a token smart contract to their preferred VM (Flow-Cadence or Flow-EVM) and wants
-to bridge it to the other (target) VM.
+For the purpose of this guide, we assume that the developer already deployed a token smart contract to their preferred VM (Flow-Cadence or Flow-EVM) and wants to bridge it to the other (target) VM.
-In order for the developer's token to be usable in the target VM, there must be a contract
-that defines the asset and how it behaves in the target VM that also enables the bridge to
-fulfill the asset from Cadence to EVM and vice versa. This contract is separate from the
-contract in the native VM, but they are "associated" with each other by the mechanisms of
-the Flow VM bridge.
+For the developer to use their token in the target VM, there must be a contract that defines the asset and how it behaves in the target VM that also allows the bridge to fulfill the asset from Cadence to EVM and vice versa. This contract is separate from the contract in the native VM, but they are "associated" with each other by the mechanisms of the Flow VM bridge.
-To create this association, the asset must be "onboarded" to the bridge
-before bridging operations can be fulfilled. This can happen in two ways:
+To create this association, the asset must be "onboarded" to the bridge before bridging operations can be fulfilled. This can happen in two ways:
-### Option 1: Automatic Onboarding
+### Option 1: automatic onboarding
-Any user registers the native token contract with the bridge and the bridge deploys
-a basic templated version of the contract in the target VM. This basic contract is automatically
-associated with the native contract and is used for bridging. The developer has no direct control
-over this bridge-deployed contract because it is controlled by the bridge.
+Any user registers the native token contract with the bridge and the bridge deploys a basic templated version of the contract in the target VM. This basic contract is automatically associated with the native contract and is used for bridging. The developer has no direct control over this bridge-deployed contract because the bridge controls it.
This method is covered in the [Automatic Onboarding Section](#automatic-onboarding)
-### Option 2: Custom Association Onboarding
+### Option 2: custom association onboarding
-With this option (available for only for NFTs) developers can deploy their own contract to the
-target VM and declare a custom association between it and the native contract. This allows
-them to have more control over both contracts, enabling them to include more sophisticated
-features and mechanisms in their bridged token contracts such as ERC-721C, unique metadata
-views, and more that aren't included in the default bridged template versions.
+With this option (available for only for NFTs), developers can deploy their own contract to the target VM and declare a custom association between it and the native contract. This allows them to have more control over both contracts, which lets them to include more sophisticated features and mechanisms in their bridged token contracts such as ERC-721C, unique metadata views, and more that aren't included in the default bridged template versions.
This method is covered in the [Custom Association Section](#custom-association-onboarding)
:::info
-Before continuing with onboarding your token, you should review
-the [Prep Your Assets for Bridging](#prep-your-assets-for-bridging) section of this document.
-This describes some steps you should follow to make sure that your native asset and/or
-bridged asset are properly set up for you to register them with the bridge.
+Before you continue to onboard your token, review the [Prep Your Assets for Bridging](#prep-your-assets-for-bridging) section of this document. This describes some steps you should follow to make sure that your native asset or bridged asset are properly set up for you to register them with the bridge.
:::
-## Automatic Onboarding
+## Automatic onboarding
-Moving from a Cadence-native asset to EVM, automatic onboarding can occur on the fly,
-deploying a template contract in the same transaction as
-the asset is bridged to EVM if the transaction so specifies.
+To move from a Cadence-native asset to EVM, automatic onboarding can occur on the fly, where a template contract deploys in the same transaction as the asset is bridged to EVM if the transaction so specifies.
-Moving from EVM to Cadence, however, requires that onboarding occur in a separate transaction due to the fact that a
-Cadence contract is initialized at the end of a transaction and isn't available in the runtime until after the
-transaction has executed.
+To move from EVM to Cadence, however, requires that onboarding occur in a separate transaction due to the fact that a Cadence contract is initialized at the end of a transaction and isn't available in the runtime until after the transaction has executed.
Below are transactions relevant to automatically onboarding assets native to either VM:
@@ -159,24 +117,16 @@ Below are transactions relevant to automatically onboarding assets native to eit
-## Custom Association Onboarding
+## Custom association onboarding
With [Custom Associations](https://github.com/onflow/flips/blob/main/application/20250131-cross-vm-nft-support.md),
-developers can deploy NFT contracts in both VMs and associate them with each other,
-allowing them to retain control of the contracts in both VMs as well as implement custom
-use-case specific functionality.
+developers can deploy NFT contracts in both VMs and associate them with each other, which allows them to retain control of the contracts in both VMs as well as implement custom use-case specific functionality.
-In order to do this, each contract must implement a special interface
-that tells the bridge what the associated contract is in the other VM.
-The fact that both point to each other validates the intended association,
-preventing spoofing. If the contracts do not point to each other this way,
-they will not be able to be registered as a custom association.
+To do this, each contract must implement a special interface that tells the bridge what the associated contract is in the other VM. The fact that both point to each other validates the intended association, which prevents spoofing. If the contracts do not point to each other this way, you can't register them as a custom association.
-Review the [Preparing Custom Associations](#preparing-custom-associations) section
-to learn how to set up each of your contracts for a custom association.
+Review the [Preparing Custom Associations](#preparing-custom-associations) section to learn how to set up each of your contracts for a custom association.
-Below is the transaction for onboarding NFTs for a custom association.
-Remember that both the Cadence and the Solidity contract need to be deployed
+Below is the transaction for onboarding NFTs for a custom association. Remember that both the Cadence and the Solidity contract need to be deployed
and include the special interface conformances to point to each other before registration!
**Onboard an NFT Custom Association:**
@@ -192,10 +142,9 @@ and include the special interface conformances to point to each other before reg
## Bridging
-Once an asset has been onboarded, either by automatic or custom association, it can be bridged in either
-direction, referred to by its Cadence type. For Cadence-native assets, this is simply its native type. For EVM-native
-assets, this is in most cases a templated Cadence contract deployed to the bridge account, the name of which is derived
-from the EVM contract address. For instance, an ERC721 contract at address `0x1234` would be onboarded to the bridge as
+After an asset gets onboarded, either by automatic or custom association, it can be bridged in either direction, referred to by its Cadence type. For Cadence-native assets, this is simply its native type.
+
+For EVM-native assets, this is in most cases a templated Cadence contract deployed to the bridge account, the name of which is derived from the EVM contract address. For instance, an ERC721 contract at address `0x1234` would be onboarded to the bridge as
`EVMVMBridgedNFT_0x1234`, making its type identifier `A..EVMVMBridgedNFT_0x1234.NFT`.
To get the type identifier for a given NFT, you can use the following code:
@@ -205,7 +154,7 @@ To get the type identifier for a given NFT, you can use the following code:
nft.getType().identifier
```
-You may also retrieve the type associated with a given EVM contract address using the following script:
+You may also retrieve the type associated with a given EVM contract address with the following script:
@@ -217,8 +166,7 @@ You may also retrieve the type associated with a given EVM contract address usin
-Alternatively, given some onboarded Cadence type, you can retrieve the associated EVM address using the following
-script:
+Alternatively, given some onboarded Cadence type, you can retrieve the associated EVM address with the following script:
@@ -232,9 +180,7 @@ script:
#### NFTs
-Any Cadence NFTs bridging to EVM are escrowed in the bridge account and either minted in a bridge-deployed ERC721
-contract or transferred from escrow to the calling COA in EVM. On the return trip, NFTs are escrowed in EVM - owned by
-the bridge's COA - and either unlocked from escrow if locked or minted from a bridge-owned NFT contract.
+Any Cadence NFTs taht bridge to EVM are escrowed in the bridge account and either minted in a bridge-deployed ERC721 contract or transferred from escrow to the calling COA in EVM. On the return trip, NFTs are escrowed in EVM - owned by the bridge's COA - and either unlocked from escrow if locked or minted from a bridge-owned NFT contract.
Below are transactions relevant to bridging NFTs:
@@ -258,19 +204,11 @@ Below are transactions relevant to bridging NFTs:
-#### Fungible Tokens
+#### Fungible tokens
-Any Cadence fungible tokens bridging to EVM are escrowed in the bridge account only if they are Cadence-native. If the
-bridge defines the tokens, they are burned. On the return trip the pattern is similar, with the bridge burning
-bridge-defined tokens or escrowing them if they are EVM-native. In all cases, if the bridge has authority to mint on one
-side, it must escrow on the other as the native VM contract is owned by an external party.
+Any Cadence fungible tokens bridging to EVM are escrowed in the bridge account only if they are Cadence-native. If the bridge defines the tokens, they are burned. On the return trip the pattern is similar, as the bridge burns bridge-defined tokens or escrows them if they are EVM-native. In all cases, if the bridge has authority to mint on one side, it must escrow on the other as the native VM contract is owned by an external party.
-With fungible tokens in particular, there may be some cases where the Cadence contract is not deployed to the bridge
-account, but the bridge still follows a mint/burn pattern in Cadence. These cases are handled via
-[`TokenHandler`](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/bridge/interfaces/FlowEVMBridgeHandlerInterfaces.cdc)
-implementations. Also know that moving $FLOW to EVM is built into the `EVMAddress` object so any requests bridging $FLOW
-to EVM will simply leverage this interface; however, moving $FLOW from EVM to Cadence must be done through the COA
-resource.
+With fungible tokens in particular, there may be some cases where the Cadence contract is not deployed to the bridge account, but the bridge still follows a mint/burn pattern in Cadence. These cases are handled via [`TokenHandler`](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/bridge/interfaces/FlowEVMBridgeHandlerInterfaces.cdc) implementations. Also know that moving $FLOW to EVM is built into the `EVMAddress` object so any requests to bridge $FLOW to EVM will simply leverage this interface; however, moving $FLOW from EVM to Cadence must be done through the COA resource.
Below are transactions relevant to bridging fungible tokens:
@@ -294,23 +232,15 @@ Below are transactions relevant to bridging fungible tokens:
-## Prep Your Assets for Bridging
+## Prep your assets for bridging
### Context
-To maximize utility to the ecosystem, this bridge is permissionless and open to any fungible or non-fungible token as
-defined by the respective Cadence standards and limited to ERC20 and ERC721 Solidity standards. Ultimately, a project
-does not have to do anything for users to be able to bridge their assets between VMs. However, there are some
-considerations developers may take to enhance the representation of their assets in non-native VMs. These largely relate
-to asset metadata and ensuring that bridging does not compromise critical user assumptions about asset ownership.
+To maximize utility to the ecosystem, this bridge is permissionless and open to any fungible or non-fungible token as defined by the respective Cadence standards and limited to ERC20 and ERC721 Solidity standards. Ultimately, a project does not have to do anything for users to bridge their assets between VMs. However, there are some considerations developers may take to enhance the representation of their assets in non-native VMs. These largely relate to asset metadata and ensuring that bridging does not compromise critical user assumptions about asset ownership.
### EVMBridgedMetadata
-Proposed in [@onflow/flow-nft/pull/203](https://github.com/onflow/flow-nft/pull/203), the `EVMBridgedMetadata` view
-presents a mechanism to both represent metadata from bridged EVM assets as well as enable Cadence-native projects to
-specify the representation of their assets in EVM. Implementing this view is not required for assets to be bridged, but
-the bridge does default to it when available as a way to provide projects greater control over their EVM asset
-definitions within the scope of ERC20 and ERC721 standards.
+Proposed in [@onflow/flow-nft/pull/203](https://github.com/onflow/flow-nft/pull/203), the `EVMBridgedMetadata` view presents a mechanism to both represent metadata from bridged EVM assets as well as allow Cadence-native projects to specify the representation of their assets in EVM. It isn'trequired to implement this view to bridge asets, but the bridge does default to it when available as a way to provide projects greater control over their EVM asset definitions within the scope of ERC20 and ERC721 standards.
The interface for this view is as follows:
@@ -337,60 +267,36 @@ access(all) struct EVMBridgedMetadata {
}
```
-This uri value could be a pointer to some offchain metadata if you expect your metadata to be static. Or you could
-couple the `uri()` method with the utility contract below to serialize the onchain metadata on the fly. Alternatively,
-you may choose to host a metadata proxy which serves the requested token URI content.
+This uri value could be a pointer to some offchain metadata if you expect your metadata to be static. Or you could couple the `uri()` method with the utility contract below to serialize the onchain metadata on the fly. Alternatively, you may choose to host a metadata proxy which serves the requested token URI content.
### SerializeMetadata
-The key consideration with respect to metadata is the distinct metadata storage patterns between ecosystem. It's
-critical for NFT utility that the metadata be bridged in addition to the representation of the NFTs ownership. However,
-it's commonplace for Cadence NFTs to store metadata onchain while EVM NFTs often store an onchain pointer to metadata
-stored offchain. In order for Cadence NFTs to be properly represented in EVM platforms, the metadata must be bridged in
-a format expected by those platforms and be done in a manner that also preserves the atomicity of bridge requests. The
-path forward on this was decided to be a commitment of serialized Cadence NFT metadata into formats popular in the EVM
-ecosystem.
+The key consideration with respect to metadata is the distinct metadata storage patterns between ecosystem. It's critical for NFT utility that the metadata be bridged in addition to the representation of the NFTs ownership. However, it's commonplace for Cadence NFTs to store metadata onchain while EVM NFTs often store an onchain pointer to metadata stored offchain.
+
+For Cadence NFTs to be properly represented in EVM platforms, the metadata must be bridged in
+a format expected by those platforms and be done in a manner that also preserves the atomicity of bridge requests. The path forward on this was decided to be a commitment of serialized Cadence NFT metadata into formats popular in the EVM ecosystem.
-For assets that do not implement `EVMBridgedMetadata`, the bridge will attempt to serialize the metadata of the asset as
-a JSON data URL string. This is done via the [`SerializeMetadata`
-contract](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/utils/SerializeMetadata.cdc) which
-serializes metadata values into a JSON blob compatible with the OpenSea metadata standard. The serialized metadata is
-then committed as the ERC721 `tokenURI` upon bridging Cadence-native NFTs to EVM. Since Cadence NFTs can easily update
-onchain metadata either by field or by the ownership of sub-NFTs, this serialization pattern enables token URI updates
-on subsequent bridge requests.
+For assets that do not implement `EVMBridgedMetadata`, the bridge will attempt to serialize the metadata of the asset as a JSON data URL string. This is done via the [`SerializeMetadata` contract](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/utils/SerializeMetadata.cdc) which serializes metadata values into a JSON blob compatible with the OpenSea metadata standard. The serialized metadata is then committed as the ERC721 `tokenURI` upon bridging Cadence-native NFTs to EVM. Since Cadence NFTs can easily update onchain metadata either by field or by the ownership of sub-NFTs, this serialization pattern enables token URI updates on subsequent bridge requests.
-### Preparing Custom Associations
+### Prepar custom associations
-If you are a developer who wants to deploy and manage NFT contracts in both VMs
-and have tokens from each be exchangable for each other,
-you'll have to add some code to your contracts so they point to each other,
-indicating that they each represent the same token in their respective VMs.
+If you are a developer who wants to deploy and manage NFT contracts in both VMs and have tokens from each be exchangable for each other, you'll have to add some code to your contracts which indicate that they each represent the same token in their respective VMs so they point to each other.
-For the purposes of these instructions, an NFT is native to a VM if that VM
-is the main source of truth for the contracts and where they are originally minted.
+For the purposes of these instructions, an NFT is native to a VM if that VM is the main source of truth for the contracts and where they are originally minted.
This feature is not available for Fungible Tokens at the moment, but may be in the future.
:::warning
-Note that the bridge only supports a single custom association declaration. This
-means that once you register an association between your Cadence NFT & EVM
-contract, the association cannot be updated. If you wish to retain some upgradeability
-to your registered implementations, it's recommended that you both retain keys on
-your Cadence NFT contract account **and ** implement an upgradeable Solidity pattern
-when deploying your ERC721, then register the association between your Cadence NFT
-Type & ERC721 proxy (not the implementation address).
+The bridge only supports a single custom association declaration. This means that once you register an association between your Cadence NFT & EVM contract, the association cannot be updated. If you wish to retain some upgradeability to your registered implementations, we recommend that you both retain keys on your Cadence NFT contract account **and ** implement an upgradeable Solidity pattern when deploying your ERC721, then register the association between your Cadence NFT Type & ERC721 proxy (not the implementation address).
:::
#### Cadence
-All Cadence NFT contracts implement [Metadata Views](../../build/cadence/advanced-concepts/metadata-views.md)
-that return metadata about their NFTs in standard ways
-via the `{Contract}.resolveContractView()` and `{NFT}.resolveView()` methods.
+All Cadence NFT contracts implement [Metadata Views](../../build/cadence/advanced-concepts/metadata-views.md) that return metadata about their NFTs in standard ways via the `{Contract}.resolveContractView()` and `{NFT}.resolveView()` methods.
-The following new view (`CrossVMMetadataViews.EVMPointer`) **must** be resolved at the contract level (`ViewResolver.resolveContractView()`) for a given Type
-**and** at the NFT level (`ViewResolver.Resolver.resolveView()`)
+The following new view (`CrossVMMetadataViews.EVMPointer`) **must** be resolved at the contract level (`ViewResolver.resolveContractView()`) for a given Type **and** at the NFT level (`ViewResolver.Resolver.resolveView()`)
```cadence
/// View resolved at contract & resource level pointing to the associated EVM implementation
@@ -408,24 +314,15 @@ access(all) struct EVMPointer {
This view allows a Cadence contract to specify which Solidity contract it is associated with.
-You can see an example of how this view is implemented in
-[the `ExampleNFT` contract](https://github.com/onflow/flow-nft/blob/master/contracts/ExampleNFT.cdc#L173-L195)
-in the Flow Non-Fungible Token repo.
+You can see an example of how this view is implemented in [the `ExampleNFT` contract](https://github.com/onflow/flow-nft/blob/master/contracts/ExampleNFT.cdc#L173-L195) in the Flow Non-Fungible Token repo.
-If your EVM contract expects metadata to be passed from Cadence at the time of
-bridging, you must implement the `CrossVMMetadataViews.EVMBytesMetadata`
-view. You'll find this useful for Cadence-native NFTs with dynamic metadata.
-This view will be resolved by the bridge and passed to your EVM contract
-when the `fulfillToEVM` method is called.
+If your EVM contract expects metadata to be passed from Cadence at the time of bridging, you must implement the `CrossVMMetadataViews.EVMBytesMetadata` view. You'll find this useful for Cadence-native NFTs with dynamic metadata. This view will be resolved by the bridge and passed to your EVM contract when the `fulfillToEVM` method is called.
-How you handle the bridged bytes in your ERC721 implementation will be a matter
-of overriding the `_beforeFulfillment` and/or `_afterFulfillment` hooks included in the
-`CrossVMBridgeERC721Fulfillment` base contract.
+How you handle the bridged bytes in your ERC721 implementation will be a matter of overriding the `_beforeFulfillment` and/or `_afterFulfillment` hooks included in the `CrossVMBridgeERC721Fulfillment` base contract.
**Flow EVM-Native NFTs**
-If the NFT being onboarded to the bridge is native to Flow-EVM, then the associated contract's
-minter resource must implement the `FlowEVMBridgeCustomAssociationTypes.NFTFulfillmentMinter` interface:
+If the NFT being onboarded to the bridge is native to Flow-EVM, then the associated contract's minter resource must implement the `FlowEVMBridgeCustomAssociationTypes.NFTFulfillmentMinter` interface:
```cadence
/// Resource interface used by EVM-native NFT collections allowing for the fulfillment of NFTs from EVM into Cadence
@@ -459,18 +356,15 @@ minter resource must implement the `FlowEVMBridgeCustomAssociationTypes.NFTFulfi
}
```
-You can see an example of an implementation of this interface in
-the [Flow EVM bridge repo ExampleNFT contract](https://github.com/onflow/flow-evm-bridge/blob/flip-318/cadence/contracts/example-assets/cross-vm-nfts/ExampleEVMNativeNFT.cdc#L352-L377).
+You can see an example of an implementation of this interface in the [Flow EVM bridge repo ExampleNFT contract](https://github.com/onflow/flow-evm-bridge/blob/flip-318/cadence/contracts/example-assets/cross-vm-nfts/ExampleEVMNativeNFT.cdc#L352-L377).
-A Capability with the `FulfillFromEVM` entitlement is required at the time of registration so the bridge
-can fulfill NFTs bridged from EVM for the first time.
+A Capability with the `FulfillFromEVM` entitlement is required at the time of registration so the bridge can fulfill NFTs bridged from EVM for the first time.
#### Solidity
For custom associations, the following interface **must** be implemented in the IERC721-conforming Solidity contract.
-This provides functionality to point to the address and type
-of the associated Cadence NFT.
+This provides functionality to point to the address and type of the associated Cadence NFT.
```solidity
interface ICrossVM {
@@ -485,14 +379,9 @@ interface ICrossVM {
}
```
-As an example, [`ICrossVM` is already
-implemented](https://github.com/onflow/flow-evm-bridge/blob/main/solidity/src/interfaces/ICrossVM.sol)
-and in use in the bridged [ERC721](https://github.com/onflow/flow-evm-bridge/blob/flip-318/solidity/src/templates/FlowEVMBridgedERC721.sol#L37-L43)
-and [ERC20](https://github.com/onflow/flow-evm-bridge/blob/flip-318/solidity/src/templates/FlowEVMBridgedERC20.sol#L13-L40) templates.
+As an example, [`ICrossVM` is already implemented](https://github.com/onflow/flow-evm-bridge/blob/main/solidity/src/interfaces/ICrossVM.sol) and in use in the bridged [ERC721](https://github.com/onflow/flow-evm-bridge/blob/flip-318/solidity/src/templates/FlowEVMBridgedERC721.sol#L37-L43) and [ERC20](https://github.com/onflow/flow-evm-bridge/blob/flip-318/solidity/src/templates/FlowEVMBridgedERC20.sol#L13-L40) templates.
-If you are registering a custom association for an NFT that is native to Cadence, meaning that your project distributes NFTs to users on the Cadence side,
-then your ERC721 contract will need to implement the `CrossVMBridgeERC721Fulfillment` contract. This is
-a required conformance that does three primary things:
+If you want to register a custom association for an NFT that is native to Cadence, which means that your project distributes NFTs to users on the Cadence side, then your ERC721 contract must implement the `CrossVMBridgeERC721Fulfillment` contract. This is a required conformance that does three primary things:
1. Implements the mint/escrow pattern expected by the VM bridge
2. Allows for the passing of arbitrary abi-encodable metadata from the Cadence NFT at the time of bridging
@@ -603,45 +492,26 @@ abstract contract CrossVMBridgeERC721Fulfillment is ICrossVMBridgeERC721Fulfillm
}
```
-Note the `_beforeFulfillment()` and `_afterFulfillment()` hooks are `virtual`, allowing implementations
-to optionally override the methods and handle the provided metadata passed from your NFT if
-`EVMBytesMetadata` is resolved at the time of bridging. Also, notice that the `fulfillToEVM` method
-is `onlyVMBridge`, allowing on the VM bridge to call the method either minting the NFT if it does not
-exist or transferring the NFT from escrow in a manner consistent with the bridge's mint/escrow pattern.
+The `_beforeFulfillment()` and `_afterFulfillment()` hooks are `virtual`, which allows implementations to optionally override the methods and handle the provided metadata passed from your NFT if `EVMBytesMetadata` is resolved at the time of bridging. Also, notice that the `fulfillToEVM` method is `onlyVMBridge`, which allows the VM bridge to call the method either minting the NFT if it does not exist or transfer the NFT from escrow in a manner consistent with the bridge's mint/escrow pattern.
-### Opting Out
+### Opt Out
-It's also recognized that the logic of some use cases may actually be compromised by the act of bridging, particularly
-in such a unique partitioned runtime environment. Such cases might include those that do not maintain ownership
-assumptions implicit to ecosystem standards.
+It's also recognized that the logic of some use cases may actually be compromised by the act of bridging, particularly in such a unique partitioned runtime environment. Such cases might include those that do not maintain ownership assumptions implicit to ecosystem standards.
-For instance, an ERC721 implementation may reclaim a user's assets after a month of inactivity. In such a case, bridging
-that ERC721 to Cadence would decouple the representation of ownership of the bridged NFT from the actual ownership in
-the defining ERC721 contract after the token had been reclaimed - there would be no NFT in escrow for the bridge to
-transfer on fulfillment of the NFT back to EVM. In such cases, projects may choose to opt-out of bridging, but
-**importantly must do so before the asset has been onboarded to the bridge**.
+For instance, an ERC721 implementation may reclaim a user's assets after a month of inactivity. In such a case, bridging that ERC721 to Cadence would decouple the representation of ownership of the bridged NFT from the actual ownership in the defining ERC721 contract after the token had been reclaimed - there would be no NFT in escrow for the bridge to transfer on fulfillment of the NFT back to EVM. In such cases, projects may choose to opt-out of bridging, but **importantly must do so before the asset has been onboarded to the bridge**.
-For Solidity contracts, opting out is as simple as extending the [`BridgePermissions.sol` abstract
-contract](https://github.com/onflow/flow-evm-bridge/blob/main/solidity/src/interfaces/BridgePermissions.sol) which
-defaults `allowsBridging()` to `false`. The bridge explicitly checks for the implementation of `IBridgePermissions` and
-the value of `allowsBridging()` to validate that the contract has not opted out of bridging.
+For Solidity contracts, opting out is as simple as extending the [`BridgePermissions.sol` abstract contract](https://github.com/onflow/flow-evm-bridge/blob/main/solidity/src/interfaces/BridgePermissions.sol) which defaults `allowsBridging()` to `false`. The bridge explicitly checks for the implementation of `IBridgePermissions` and the value of `allowsBridging()` to validate that the contract has not opted out of bridging.
-Similarly, Cadence contracts can implement the [`IBridgePermissions.cdc` contract
-interface](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/bridge/interfaces/IBridgePermissions.cdc).
-This contract has a single method `allowsBridging()` with a default implementation returning `false`. Again, the bridge
-explicitly checks for the implementation of `IBridgePermissions` and the value of `allowsBridging()` to validate that
-the contract has not opted out of bridging. Should you later choose to enable bridging, you can simply override the
-default implementation and return `true`.
+Similarly, Cadence contracts can implement the [`IBridgePermissions.cdc` contract interface](https://github.com/onflow/flow-evm-bridge/blob/main/cadence/contracts/bridge/interfaces/IBridgePermissions.cdc). This contract has a single method `allowsBridging()` with a default implementation returning `false`. Again, the bridge explicitly checks for the implementation of `IBridgePermissions` and the value of `allowsBridging()` to validate that the contract has not opted out of bridging. Should you later choose to turn on bridging, you can simply override the default implementation and return `true`.
-In both cases, `allowsBridging()` gates onboarding to the bridge. Once onboarded - **a permissionless operation anyone
-can execute** - the value of `allowsBridging()` is irrelevant and assets can move between VMs permissionlessly.
+In both cases, `allowsBridging()` gates onboarding to the bridge. After the onboard occurs - **a permissionless operation anyone can execute** - the value of `allowsBridging()` is irrelevant and assets can move between VMs permissionlessly.
-## Under the Hood
+## Under the hood
For an in-depth look at the high-level architecture of the bridge, see [FLIP
#237](https://github.com/onflow/flips/blob/main/application/20231222-evm-vm-bridge.md)
-### Additional Resources
+### Additional resources
For the current state of Flow EVM across various task paths, see the following resources: