Solana India Fellowship - Week[3]

This post is a part of a series of posts documenting my experience as a fellow in the Solana India Fellowship. You can find other posts in this series here.


Introducing Aureus

Aureus cover

Look at that sick logo

Last week, I described my idea of building out a BNPL financing protocol on top of Solana pay. Well, the project now has a website and twitter. It is still pretty bare-bones and I am still figuring out the finer details, I will iterate on it till I find something which works well.

Payment channel

This week’s exercise focused on building a bi-directional payment channel on-chain.

The classic way of doing this on ETH requires signature verification on-chain. However, the Solana compute budget is much more limited and you cannot even verify a single ECDSA signature on-chain before running out of compute units.

// Mind the budget
ComputeBudget {
    max_units: 200_000,
    log_64_units: 100,
    create_program_address_units: 1500,
    invoke_units: 1000,
    max_invoke_depth: 4,
    sha256_base_cost: 85,
    sha256_byte_cost: 1,
    max_call_depth: 64,
    stack_frame_size: 4_096,
    log_pubkey_units: 100,
    max_cpi_instruction_size: 1280, // IPv6 Min MTU size
    cpi_bytes_per_unit: 250,        // ~50MB at 200,000 units
    sysvar_base_cost: 100,
    secp256k1_recover_cost: 25_000,
    syscall_base_cost: 100,
    heap_size: None,
    heap_cost: 8,

Solana does signature verification on the transaction with accounts marked as isSigner before the on-chain program even runs. Thus, we can simply store the current balances on-chain, make Alice and Bob both sign when they want to update these balances. Then, any single signer can close the channel when they want.

This kind of defeats the purpose of a payment channel, which is to avoid fees, but due of weird Solana quirks, there is no other obvious way of doing this. (Also a bi-directional payment channel doesn’t make much sense on Solana anyways, you can do 10,000 transactions on-chain and your total transaction fee will be around $2)

Some nonce shenanigans

Solana transactions do not have a nonce field like ethereum, so to prevent replay attacks, each transaction has a recent_blockchash field which needs to be populated with a blockhash which is less than ~2min old. If the blockhash is older than 2 minutes, the transaction will be rejected. This is a fine replacement for a nonce field, but leads to annoying problems if you want to co-ordinate multiple offline signers who are geographically apart.

The solution to this is to use a durable nonce, which is an onchain program which replicates the Ethereum nonce semantics. A new on-chain account is initialized with the pubkey of the user and a nonce value with the InitializeNonceAccount call on SystemProgram. This the only time I have used the recent_blockhashes sysvar.

Then, you can create a transaction with the AdvanceNonceAccount instruction before your actual instruction and you can attach the nonce to this whole transaction.