What is composability?
In the current blockchain landscape where fragmentation is increasingly becoming a problem, more and more projects focus on cross-chain communication. But today we will look into another approach of solving the fragmentation problem, called composability.
So, what does the word composability mean?
In general composability refers to the ability for different components or elements to be combined or connected in various ways to create larger, more complex systems or structures.
In the blockchain context, composability means the seamless interaction between different protocols, smart contracts, or applications. This article delves into Neon-to-Solana composability and explores how it works under the hood.
Core Solana Terminology
Before diving deeper, it's essential to establish some core terminology related to Solana, which will help in understanding the inner workings of composability.
Solana programs are stateless; therefore, data on Solana is stored in what are known as accounts. Each account is uniquely identified by a 32-byte address formatted as an Ed25519 PublicKey, acting as the account's unique identifier.
Every account in Solana has a structure called AccountInfo
, which includes the following fields:
-data
: A byte array that holds the state of an account. If the account is a program (smart contract), it contains the executable program code. This field is commonly known as "account data."
-executable
: A boolean flag indicating whether the account is a program.
-lamports
: A numerical representation of the account's balance in lamports, the smallest unit of SOL (1 SOL = 1 billion lamports).
-owner
: Indicates the public key (program ID) of the program that owns the account.
Solana account types can be divided into two broad categories:
- Executable Accounts: Accounts that store only the immutable smart contract or program code on Solana.
- Non-Executable Accounts: Accounts that store the data required by the related program, such as variables, states, and assets.
Transactions and Instructions
On Solana, transactions are sent to interact with the network. Each transaction consists of one or more instructions, each representing a specific operation to be executed. An instruction includes:
- Program Address: Specifies the program being called.
- Accounts: Lists all accounts that the instruction will read from or write to, including other programs, using the AccountMeta struct.
- Instruction Data: A byte array that indicates which instruction handler on the program to invoke, along with any additional data required by the instruction handler (function arguments).
An instruction is a request to perform a specific action on-chain and represents the smallest unit of execution logic within a program.
Cross-Program Invocation (CPI)
CPI occurs when one program calls the instructions of another program. This mechanism enables the composability of Solana programs. Key points about CPI:
- Direct Calls Between Programs: CPIs allow Solana program instructions to directly call instructions on another program.
- Extended Signer Privileges: Signer privileges from the calling program are extended to the called program.
- Program Derived Addresses (PDAs): When performing a CPI, programs can "sign" on behalf of PDAs derived from their own program ID.
- Call Depth Limit: The called program can make additional CPIs to other programs, with a maximum depth of 4.
Core Neon Components
Neon consists of multiple core components that work together to bridge Ethereum-like transactions to Solana. The key components include:
- Neon Proxy: Acts as a gateway that accepts users' Ethereum-like transactions. It wraps the Ethereum transaction as a Solana transaction and passes the wrapped transaction to the Neon EVM program hosted on Solana.
- Neon EVM Program: Executes the Ethereum-like transactions inside Berkeley Packet Filter (BPF) within the Solana environment.
How These Components Enable Composability
Neon EVM allows composability via the ICallSolana
interface. This interface enables smart contracts deployed on Neon to interact with Solana programs. The interface contract ICallSolana.sol
can be found in this Github Repository.
A precompile of the ICallSolana contract is deployed on Neon EVM at the 0xFF00000000000000000000000000000000000006 address.
- TestCallSolana.sol - This is a solidity smart contract which interacts with the precompile 0xFF00000000000000000000000000000000000006 via the ICallSolana.sol interface contract described in details here. So when a contract on Neon communicates with this interface, it looks like this:
When a contract on Neon communicates with this interface, the interaction looks like this:
- Solidity Contract Interaction: The process begins when a Solidity smart contract on Neon calls a function that needs to interact with Solana. In the example, this is done using the CALLSOLANAPRECOMPILE.execute() method.
- Precompile Usage: The CALLSOLANAPRECOMPILE is a special precompiled contract in the Neon EVM. It acts as a bridge between the Ethereum-style environment of Neon and Solana's native environment.
- Execution Flow: The Solidity contract calls the precompile, which then communicates with the Neon EVM program. The Neon EVM program, in turn, interacts with the Solana program specified in the instruction.
In simple terms, to interact with Solana programs, a Solidity smart contract deployed on Neon can call the ICallSolana precompile inside the Neon EVM. This precompile can communicate with other Solana programs, thus connecting the Solidity smart contract on Neon with Solana.
Transferring SOL between accounts using composability.
Let's go through a practical example step by step. Suppose we want to transfer SOL between two accounts. We have two Solana accounts:
- Account 1: Funded with 2 SOL (we own this account).
- Account 2: Has 0 SOL.
We want to send 1 SOL from Account 1 to Account 2.
Standard SOL Transfer on Solana
In Solana, transferring SOL between accounts involves the following steps:
- Instruction Creation: Account 1 creates a transfer instruction by calling the transfer function on the system program.
- Transaction Submission: The instruction is added to a transaction, signed by Account 1, and submitted to the network.
- Execution: Solana validators process the transaction, transferring 1 SOL from Account 1 to Account 2.
When we want to transfer sol between accounts on Solana, we can just call the transfer function of the system program directly.
Transferring SOL from Neon Using Composability
Now, we want to achieve the same transfer from Neon using composability. Here's how:
- Prepare the Solana Instruction: We create the Solana transfer instruction within our Solidity contract.
- Call the Solidity Contract: We call the execute function of the TestCallSolana.sol contract deployed on Neon, passing the prepared instruction as input.
- Interact with the Precompile: The Solidity contract interacts with the ICallSolana precompile inside the Neon EVM.
- Forward the Call: Through the Neon EVM program, the call is forwarded to the Solana system program's transfer function.
- Execute the Transfer: The system program transfers 1 SOL from Account 1 to Account 2 on Solana.
Important Considerations
- Account Ownership: Account 1 must be accessible from Neon, meaning it should be controlled through a Neon account or properly authorized.
- Signer Privileges: The Neon EVM extends signer privileges to the Solana program being called.
- Limitations: Currently, it is not possible to execute iterative transactions in this mode.
To call the same function from Neon on Solana, we need to call execute function of the ICallSolana precompile and include all the relevant data like accounts, program_id, etc. We call the precompile through the Solidity contract deployed on Neon.
Practical Example: Transferring SPL Tokens Between Accounts Using Composability
Suppose we want to transfer Solana USDC (an SPL token) between two accounts:
- Account 1: We own this account, and it holds USDC tokens.
- Account 2: The recipient account, which also has an associated token account for USDC.
Standard SPL Token Transfer on Solana
Transferring an SPL token on Solana involves:
- Token Accounts: Ensure both sender and receiver have token accounts for the specific SPL token.
- Instruction Creation: Create a transfer instruction specifying:
- Sender's token account address.
- Receiver's token account address.
- Amount of tokens to transfer.
- Token mint address (identifies the token).
- Transaction Building: Add the instruction to a transaction.
- Signing and Submission: Sign the transaction with the sender's private key and submit it to the Solana network.
- Execution: Validators process the transaction, updating token balances accordingly.
To perform the same transfer from Neon:
- Prepare the Token Transfer Instruction: Within the Solidity contract on Neon, create the instruction for transferring USDC tokens.
- Call the Solidity Contract: Invoke the execute function of the TestCallSolana.sol contract, passing the token transfer instruction.
- Interact with the Precompile: The Solidity contract communicates with the ICallSolana precompile.
- Forward the Call: The precompile forwards the call through the Neon EVM program to the Solana token program.
- Execute the Transfer: The token program processes the transfer, moving 10 USDC from Account 1 to Account 2 on Solana.
Note, that Account 1 on Solana is a PDA created by Neon EVM program and controlled by Neon account through the Neon EVM program.
- Associated Token Accounts: Both accounts must have associated token accounts for USDC.
- Account Control: Account 1 on Solana is a Program Derived Address (PDA) created by the Neon EVM program and controlled by a Neon account through the Neon EVM program.
Composability enables developers to build more complex and interconnected applications by allowing smart contracts on Neon to interact directly with Solana programs. This opens up possibilities for seamless integration between Ethereum-like environments and Solana's high-performance blockchain. To explore more, head over to our documentation and check out code examples.