Solana is a new blockchain focusing on performance. It supports smart contracts like Ethereum which they call Programs. You can develop those in Rust, but there's also a new project now to compile Solidity to Solana. In other words you can deploy your contracts written in Solidity now to Solana!

And of course the costs of transactions on Solana are a fraction of those in Ethereum. So how does it all work?


Solana Meme

Transaction Ordering (Proof of History)

Proof of History uses a sequential hash chain as a clock and ordering mechanism. Computing one step depends on the previous result, so it cannot be parallelized in the same way as trying many independent proof-of-work nonces. Its relationship to elapsed time still depends on assumptions about hardware throughput; it is not an absolute guarantee that faster hardware can never exist.

Proof of History Example 1
Proof of History Example 2

Historical context: This comparison reflects the 2021 roadmap. Ethereum’s proof-of-stake consensus does not use the hypothetical “ETH2 VDF” described here. PoH provides a clock/ordering input for Solana’s consensus; it does not replace consensus by itself.

So when a node receives transactions signed with hash300, it will know those transactions are to be placed after hash200, but before hash400 (assuming 100 hashes as delay). This is quite similar to the concept of Verifiable Delay Functions (VDFs) which are also used for ETH2.0. The one difference lies in proof verification which for VDFs can be done in significantly less complex steps than proof creation, while for PoH requires every single hash to be calculated again. So how can PoH verification be done efficiently?

Luckily PoH proof verification, unlike the PoH proof creation, can be parallelized. The proof will have to contain every intermediate hash where then each intermediate hash calculation can be verified in parallel. This is possible very efficiently on modern GPUs. Of course the downside for this is very large proof sizes and generally high Solana validator hardware requirements. The upside is performance, because it reduces messaging overhead + latency due to providing a predetermined transaction order.

New transactions bundled in a batch and optimistically streamed via UDP from the current leader to all other validators where each validator receives a different data part of the bundle. In the next step validators are sharing the missing sets between each other, all of this happens concurrently, non-stop and streamed resulting in very high performance.

Consensus on Solana (Proof of Stake)

In the original Tower BFT explanation, later votes increase earlier votes’ lockouts exponentially. The familiar 32-vote example corresponds to a very long lockout measured in slots. It describes the voting rules for switching forks; it does not mean that an adversary must spend 54 years recomputing hashes to reverse the chain. The security argument depends on the validator voting and stake assumptions.

Other features of Solana include:

  • Turbine — a block propagation protocol
  • Gulf Stream — Mempool-less transaction forwarding protocol
  • Sealevel — Parallel smart contracts run-time
  • Pipelining — a Transaction Processing Unit for validation optimization
  • Cloudbreak — Horizontally-Scaled Accounts Database
  • Replicators — Distributed ledger store

If you want to learn more, check out Solana's docs, whitepaper and blog posts.

Deploying ERC-20 Token to Solana

Deploying an ERC-20 to Solana from Solidity requires installing all tools and running a deploy script.

1. Installing Solang

The best way to install Solang is using the VS Code extension. It will automatically install the correct solang binary along with the dependencies. Alternatively you can download the binary directly and manually install the dependencies. The VS Code extension will also give you compiling capabilities for Solang, the regular Solidity extension wouldn't be quite accurate due to the differences in the supported features.

To make the extension work properly, you only need to more steps:

1. Make sure to choose Solana as target in the extension settings.

VS Code Solang Target

2. Disable the solidity extension for the workspace.

VS Code Solang Extensions

Now let's take an ERC20 contract, the code here is almost a 1:1 copy from Openzeppelin.

You'll also want to initialize the package and install required dependencies:

Terminal / configuration
<p><strong>Historical context:</strong> The package and deployment script below belong to the archived <a href="https://github.com/solana-labs/solana-solidity.js"><code>@solana/solidity</code> integration</a>. They are retained to document this experiment. For new work, use the <a href="https://solang.readthedocs.io/en/latest/targets/solana.html">maintained Solang target documentation</a> and test its supported client/ABI combination.</p>$ npm init
$ npm install @solana/solidity @solana/web3.js

2. Installing Solana Tool Suite

Next up install the Solana test suite. If you're running on Mac OS, it's as simple as running:

Terminal / configuration
# Historical Solana 1.8.5 installer, paired with the original 2021 example.
# This is not the current installation path; see the maintained Solana installation guide.
$ sh -c "$(curl -sSfL https://release.solana.com/v1.8.5/install)"

3. Create the ERC-20 contract

Now let's take an ERC20 contract as ERC20.sol in our package root, the code here is almost a 1:1 copy from Openzeppelin.

4. Compile Solidity -> Solana

Next up install the Solana test suite. If you're running on Mac OS, it's as simple as running:

Terminal / configuration
$ solang ERC20.sol --target solana --output build

This will produce

  • build/ERC20.abi: Just as you know from Ethereum, the ABI for our contract is generated.
  • build/bundle.so: New here is the compiled Solana Program.

5. Deploy the ERC-20 contract

Now create the following deploy-erc20.js script:

javascript
const { Connection, LAMPORTS_PER_SOL, Keypair } = require('@solana/web3.js')
const { Contract, publicKeyToHex } = require('@solana/solidity')
const { readFileSync } = require('fs')

const ERC20_ABI = JSON.parse(readFileSync('./build/ERC20.abi', 'utf8'))
const BUNDLE_SO = readFileSync('./build/bundle.so')

;(async function () {
    console.log('Connecting to your local Solana node ...')
    const connection = new Connection(
        // works only for localhost at the time of writing
        // see https://github.com/solana-labs/solana-solidity.js/issues/8
        'http://localhost:8899', // "https://api.devnet.solana.com",
        'confirmed'
    )

    const payer = Keypair.generate()
    while (true) {
        console.log('Airdropping (from faucet) SOL to a new wallet ...')
        await connection.requestAirdrop(payer.publicKey, 1 * LAMPORTS_PER_SOL)
        await new Promise((resolve) => setTimeout(resolve, 1000))
        if (await connection.getBalance(payer.publicKey)) break
    }

    const address = publicKeyToHex(payer.publicKey)
    const program = Keypair.generate()
    const storage = Keypair.generate()

    const contract = new Contract(connection, program.publicKey, storage.publicKey, ERC20_ABI, payer)

    console.log('Deploying the Solang-compiled ERC20 program ...')
    await contract.load(program, BUNDLE_SO)

    console.log('Program deployment finished, deploying ERC20 ...')
    await contract.deploy('ERC20', ['MyToken', 'MTO', '1000000000000000000'], program, storage, 4096 * 8)

    console.log('Contract deployment finished, invoking contract functions ...')
    const symbol = await contract.symbol()
    const balance = await contract.balanceOf(address)

    console.log(`ERC20 contract for ${symbol} deployed!`)
    console.log(`Wallet at ${address} has a balance of ${balance}.`)

    contract.addEventListener(function (event) {
        console.log(`${event.name} event emitted!`)
        console.log(
            `${event.args[0]} sent ${event.args[2]} tokens to
       ${event.args[1]}`
        )
    })

    console.log('Sending tokens will emit a "Transfer" event ...')
    const recipient = Keypair.generate()
    await contract.transfer(publicKeyToHex(recipient.publicKey), '1000000000000000000')

    process.exit(0)
})()

Here we are making use of


If you are Dapp developer and want to connect a wallet, have a look at Solana wallet adapter instead.

Now we're ready to run your own local Solana chain:

Terminal / configuration
$ solana-test-validator --reset --quiet

And in a separate tab run our script:

Terminal / configuration
$ node deploy-erc20.js

We just deployed the ERC-20 token to our local Solana chain! 🎉🎉🎉

So what exactly is Solang?

Historical context: The compiler capabilities listed below describe the 2021 version. Current Solang targets and Solidity compatibility have changed; consult its chain-specific documentation rather than treating this list as current.

In their own words: With Solang you can compile smart contracts written in Solidity for Solana, Parity Substrate, and Ethereum ewasm. It uses the llvm compiler framework to produce WebAssembly (wasm) or BPF contract code.

How does it compare to projects cloning the EVM like Moonbeam and Evmos? Since EVM cloning keeps all the overhead from running the EVM, the solution with Solang should scale much more efficiently since it's running natively on the chain, but there are some caveats to it:

Solang aims to be compatible with Solidity 0.7, however there are some key differences:

Historical context: Apart from the fee correction below, this list reflects the original Solang version. Builtins, account passing and ABI behavior must be checked against the current Solana target reference.

  • Libraries are always statically linked into the contract code.
  • Solang generates WebAssembly or BPF rather than EVM. This means that the assembly {} statement using EVM instructions is not supported.
  • Solana meters execution with compute units rather than Ethereum gas. Transactions pay a base fee and can also pay a priority fee tied to the requested compute-unit limit and price; the historical claim of no compute-related fee is no longer accurate.
    • The gas cannot be set on Solana for external calls.
    • tx.gasprice is not available.
    • gasleft() is not available.
  • block.number gives the slot number rather than the block height.
  • You can print output for debugging using print().
  • selfdestruct and tx.origin are not available.
  • Solana addresses are base58 encoded, not hexadecimal. An address literal can be specified with the special syntax address"<account>".
    address foo = address"5GBWmgdFAMqm8ZgAHGobqDqX6tjLxJhv53ygjNtaaAn3sjeZ";
  • The size of the new account can be specified using space. By default, the new account is created with a size of 1 kilobyte (1024 bytes) plus the size required for any fixed-size fields. When you specify space, this is the space in addition to the fixed-size fields (like strings in the state). So, if you specify space: 0, then there is no space for any dynamicially allocated fields.
solidity
contract Hatchling {
    string name;

    constructor(string id) payable {
        require(id != "", "name must be provided");
        name = id;
    }
}

contract Adult {
    function test() public {
        Hatchling h = new Hatchling{space: 10240}("luna");
    }
}
  • Is this ready to use? This is a historical compiler experiment, not a newly tested production template. A production application needs a current supported compiler/client combination and a review of its Solana account and authorization model.
  • Is a compiled ERC-20 automatically an SPL token? No. Compiling Ethereum-style Solidity does not make its interface or storage a native SPL token. Solang documents a SplToken library for calling the native token program; see its Solana target documentation.