Neon Proxy: Facilitating Seamless Transactions on Neon EVM

Neon Labs
Neon Labs
Published in
10 min readFeb 22, 2022

--

Neon Labs’ goal is to bring Solana’s scalability and low costs to the ecosystem of Ethereum dApps, developers, and end-users. Our solution, Neon EVM, is a Solana native EVM-compatibility tool that allows Solidity smart contracts launched on the platform to interact with traditional SPL tokens and “SPL-wrapped” ERC20 tokens. One of our main tenets is to deliver the capabilities of Neon EVM in a way that does not disrupt developer or end-user experience. In short, we want to deliver as native of an EVM experience as possible while operating on Solana.

To make Neon EVM more “user-friendly” for both developers and end-users, we created the Neon Web3 Proxy — an optional infrastructure component for the Neon ecosystem. The proxy packs Ethereum-like transactions, called Neon transactions, into Solana transactions, removing the burden of implementing conversion logic from developers. This allows project teams to focus on building their products/services rather than worry about compatibility between their Solidity smart contracts and Solana. It also allows project teams to move their existing Solidity smart contract source code into Neon EVM with no changes. For end-users, the proxy dismisses the need for them to manually structure transactions for correct execution on Neon EVM. They can continue using Solidity dApps normally without any additional steps.

To overcome compatibility issues between Ethereum and Solana transactions, three key considerations for the Neon Web3 Proxy solution design were:

  1. Solana’s compute budget of 200,000 BPF instructions per transaction. The compute budget is enforced to “prevent a program from abusing computation resources.”
  2. Solana’s transaction size limit of 1232 bytes. The transaction size limit is enforced to “ensure fast and reliable network transmission of cluster info over UDP.”
  3. Ethereum’s large transaction sizes. Ethereum transactions are not confined by the two Solana constraints above and can become large in size and instruction count.

When the Neon Web3 Proxy takes in a Neon transaction, it will attempt to pack the Neon transaction into a single Solana transaction (we’ll refer to these as non-iterative transactions throughout the article) for execution by Neon EVM. Non-iterative transactions contain the following information:

  • Neon EVM as the target smart contract executing the transaction
  • Serialized Transaction Data containing, but not limited to:
    - Neon EVM function flag. This tells Neon EVM how to execute the transaction.
    - Transaction sender.
    - Smart contract name.
    - Transaction data from the requested Neon transaction.
    - dApp end-user’s signature for the Neon transaction.
  • A list of accounts impacted by the transaction in a read/write capacity

However, if the non-iterative transaction is too large to be processed, the proxy will generate multiple iterative Solana transactions representing the original Neon transaction. These iterative transactions follow Solana’s compute budget and size guidelines and can be executed successfully by Neon EVM on the Solana network.

How Iterative Transactions are Structured and Why they are Important

Iterative transactions are a series of transactions with identical data that can be executed sequentially to achieve the same result as a non-iterative transaction. The Neon Web3 Proxy identifies the need for iterative transactions when translating a Neon transaction into the initial non-iterative transaction.

Iterative transactions are necessary if either of the following scenarios is true:

  • The non-iterative transaction created from the requested Neon transaction is larger than 1232 bytes.
  • The non-iterative transaction created from the requested Neon transaction contains more than 200,000 BPF instructions.

There are two ways iterative transactions can be structured:

First. Suppose the original, non-iterative transaction created from the requested Neon transaction is less than 1232 bytes but contains more than 200,000 BPF instructions. In that case, the Neon Web3 Proxy will generate multiple iterative Solana transactions that contain nearly the same information as the original non-iterative transaction. The entire set of instructions will be held on every one of the individual iterative transactions. Each iterative transaction will contain the following data:

  • Neon EVM as the target smart contract executing the transaction.
  • Serialized Transaction Data containing, but not limited to:
    - Neon EVM function flag. This tells Neon EVM how to execute the transaction. In this case, the flag will let Neon EVM know that the transaction is to be executed iteratively.
    - Transaction sender.
    - Smart contract name.
    - Transaction data from the requested Neon transaction.
    - Signature for the Neon transaction.
    - The max number of Opcodes (operation codes) to be executed until the transaction is halted and the Neon EVM state is saved into the specified state account. This allows the transaction to execute on Solana despite having more than 200,000 BPF instructions.
  • A list of accounts impacted by the transaction in a read/write capacity. This account list will contain an additional special account (State Account) used to save the state of Neon EVM in between the execution of the iterative transactions.

Second. Suppose the original, non-iterative transaction created from the requested Neon transaction is more than 1232 bytes. In that case, regardless of the number of BPF instructions, the proxy will request the creation of a new Solana account, called a Holder Account. The proxy will then break the original transaction data into smaller pieces less than 1232 bytes. That data is saved into the recently created Holder Account. In parallel, the proxy will create identical iterative transactions with the following data:

  • Neon EVM as the target smart contract executing the transaction
  • Serialized Transaction Data containing, but not limited to:
    - Neon EVM function flag. In this case, the flag will tell Neon EVM to execute the transaction iteratively using the data in the Holder Account.
    - The max number of Opcodes (operation codes) to be executed until the transaction is halted and the Neon EVM state is saved into the specified state account.
  • A list of accounts impacted by the transaction in a read/write capacity. Included in this list are (1) the special account (State Account) used to save the state of Neon EVM in between the execution of the iterative transactions and (2) the Holder Account with the transaction data to be executed.

In addition to the information above, both the non-iterative and iterative Solana transactions will also contain the following payments logistic data (Neon Operators will be further explained in the next section):

  • The Neon EVM operator account that will pay and sign for the Solana transaction.
  • The Neon EVM operator account that the end-user’s payment will be sent to pay for Operator services
  • The Neon EVM account where funds will be deposited to be spent on iterative execution of a transaction

On Solana, there is no way to know which order the iterative transactions will be executed. For this reason, there is no benefit for iterative transactions to only contain a specific portion of the instructions to be executed. There is a very low chance the iterative transactions are executed in the correct order to successfully process the entire Neon transaction correctly. Rather, each transaction will contain the whole instruction set and tell Neon EVM the number of instructions to execute. Neon EVM will use the State Account as a “bookmark” to remember which instructions it has already processed. Whenever an iterative transaction starts to execute, Neon EVM will check the State Account and start executing the defined number of instructions, picking up from where the last transaction was halted.

The iterative transaction model is integral to making Ethereum-like transactions possible on Solana without requiring project teams to rewrite any smart contracts. The feature enables the Neon Web3 Proxy to facilitate seamless transactions on Neon EVM.

Under the Hood of the Neon Web3 Proxy

As mentioned before, the Neon Web3 Proxy is an optional component for using Neon EVM. Developers have the option of implementing the proxy logic directly within their dApps. The tool is meant to be an out-of-the-box solution that makes transacting with Neon EVM dApps as similar to Ethereum as possible.

The proxy’s functions are carried out with the help of Neon Operators. Operators are participants in the Neon ecosystem that support the execution of Solana transactions generated by the Neon Web3 Proxy. When a Neon transaction is signed and sent to the proxy by a dApp end-user, it’s packed into a single non-iterative Solana transaction or multiple iterative Solana transactions depending on size and instruction count. To identify the size and instruction count, the proxy will run transactions through an internal EVM emulator. Along with transaction size and instruction count, the emulator also helps identify costs and Solana accounts accessed. The number of iterative transactions created is roughly equal to the total number of opcodes returned by the internal emulator, divided by the number of opcodes specified per iterative transaction. These iterative Solana transactions are signed and paid for by Neon Operators and sent all at once to Neon EVM for execution.

To confirm the successful execution of an entire Neon transaction, the Web3 Proxy will review transaction receipts sent back by Neon EVM after the execution of all iterative transactions. The proxy checks for two things:

  • Whether each individual iterative transaction has been executed and confirmed to the Solana blockchain.
  • If any of the transaction receipts include a “completion” flag. The “completion” flag is only set by Neon EVM once the original Neon transaction has been executed.

The Web3 Proxy counts the number of transactions that are not confirmed to Solana, if any. It then sends a second wave of iterative transactions to Neon EVM to complete the execution of the entire Neon transaction. The number of transactions in the second wave is equal to the number of transactions that were not confirmed to Solana in the first attempt. Each of the additional iterative transactions contains data identical to the iterative transactions dispatched in the first attempt.

Key functions of the proxy include:

  • Receiving requests over Web3 API protocol (When a dApp user requests a transaction via client UI, the generated transaction is sent to the proxy via Web3 API protocol).
  • Shaping responses using Web3 API protocol.
  • Packaging Neon transactions into a Solana transaction.
  • Executing read-only Solidity methods of contracts.
  • Providing a method for accessing SPL token contracts via Neon transactions.
  • An EVM emulator used to “test run” Solana transactions generated from Neon transactions. The “test run” identifies Solana accounts that will be accessed by the Neon transaction and the estimated cost of the Neon transaction.
  • Giving users a method to execute a Neon transaction without a “test run.”

How the Proxy works with Neon EVM

Let’s dive into how the proxy facilitates transactions in an end-to-end walkthrough.

The process is initiated by an end-user requesting a transaction while interacting with a Neon EVM dApp via their client. The dApp client generates an Ethereum-like transaction (Neon transaction), requests the user’s signature (via MetaMask), and sends the transaction to the Neon Web3 Proxy. The Neon transaction sent to the proxy contains the same type of information found in a standard Ethereum transaction.

The proxy will take the Neon transaction and perform a “test run” using its internal EVM emulator. The “test run” will identify the list of accounts accessed by the transaction along with the following attributes of each account:

  • Flag indicating whether it’s an existing account or a new account created as part of the transaction
  • Flag indicating whether the transaction will read or write to the account

The emulator will also count the number of Opcodes used in the “test run”, this will inform the proxy of how many iterative instructions are needed to complete the Neon transaction. In addition, the “test run” will estimate the overall cost of the transaction.

After the “test run” the proxy will generate a non-iterative Solana transaction and send it to Neon EVM to attempt execution. The transaction is created with information from the original Neon transaction along with the account list compiled during the “test run.” If the transaction fails due to size limit or compute budget, multiple iterative Solana transactions will be created. The number of iterative transactions created is equal to the total opcodes needed, divided by the number of opcodes specified per iterative transaction.

All of the iterative transactions are sent to Neon EVM simultaneously for execution. Neon EVM will execute an iterative transaction for the prescribed number of instructions and save its state to the State Account when halted. Then, it moves onto the next iterative transaction. Using information from the State Account, the EVM determines at which point in the instruction list to start executing. The EVM will start performing instructions until it reaches the instruction limit specified in the iterative transaction data.

Once all sent iterative transactions have been processed, the proxy requests transaction receipts from Neon EVM. The proxy reviews all receipts to check if any of the iterative transactions weren’t confirmed on the Solana blockchain. If there were any unconfirmed iterative transactions, the proxy will send a second wave of iterative transactions to complete the overall Neon transaction. The number of iterative transactions in the second wave is equal to the number of unconfirmed transactions from the first batch sent.

In certain scenarios, the proxy will find all iterative transactions confirmed on the Solana network but without a “completed flag” present in any transaction receipts. This occurs if more BFP instructions are needed than initially estimated. In these cases, the Neon Web3 Proxy will send additional iterative transactions one-by-one to the EVM until a “completed flag” is triggered to complete the Neon transaction.

When the proxy finally locates a “completed flag” in one of the iterative transaction receipts, it notes that the entire Neon transaction has finished. The end-user that initiated the Neon transaction pays the Neon Operator for their services and for the Solana transaction fees incurred. From a user’s perspective, payment is similar to paying for dApps via MetaMask. All the logistics of Neon transaction fees are handled by the Web3 Proxy.

Next Steps

If you have any remaining questions or are looking for more details regarding Neon Web3 Proxy or Iterative transactions, take a look at our developer documents linked below:

If this article or the docs linked above leave you with further questions, reach out to our team via Discord. We’ll be more than happy to help you understand how the Web3 Proxy and iterative transactions facilitate seamless transactions on Neon EVM. Lastly, if you’re interested in becoming a Neon Operator or learning more about the Neon Operator economy, check out our Quick Operator’s Guide.

--

--