.@armaniferrante recently published a great repository of 10 vulnerabilities to avoid when writing Solana programs.

Here's the quick rundown if you don't feel like digging into the code 👇

ImageImageImage
1) Signer authorization

If your instruction takes in an "authority" account, make sure the account has signed the transaction.

Why? Because only the owner of the "authority" account can sign for it—but anyone can pass in the account as a non-signer.
Don't do this—authority is not required to be a signer. Image
Instead, do this—authority IS required to be a signer! Image
2) Account data matching

Make sure that passed-in accounts contain valid data.

For example, if your instruction expects a token account, the token account should contain an owner, mint, amount, etc.

Otherwise, you may be operating with the wrong type of account!
Don't do this—the token account can contain arbitrary, invalid data. Image
Instead, do this—Anchor checks that the token account contains valid data, and that its owner is the signer of the transaction. Image
3) Checking account ownership

Make sure the passed-in accounts are owned by the correct program.

For example, if your instruction expects a token account, it should be owned by the token program.
Don't do this—this code doesn't check to make sure the token account is owned by the SPL token program, so it could be invalid. Image
Instead, do this—Anchor will verify account ownership for you! Image
4) Type cosplay

Make sure one account type (e.g. User) can't be confused for another account type (e.g. Metadata).

This one is a bit confusing, the examples should make it clearer.
Don't do this—you can't tell a deserialized User account from a deserialized Metadata account Image
The manual way to fix this is by adding a "discriminant" to both accounts, i.e. something that allows you to distinguish between them Image
The recommended way to fix this is by just using Anchor's #[account] macro, which will automatically add an 8-byte discriminator to the start of the account. Much easier! Image
5) Account initialization

This is similar to the previous vulnerability—when initializing accounts, make sure you account for the discriminator.

E.g., you don't want to initialize the wrong type of account. And you may not want to re-initialize an already initialized account.
Don't do this—the user account could be another account type (since there is no discriminator).

And this also lets people re-initialize previously initialized accounts. Image
Instead, do this—using #[account(init)] will create a new account and set its account discriminator. Image
6) Arbitrary CPI

When performing CPIs, make sure you're invoking the correct program.
Don't do this—the token program account gets passed in by the user, and could actually be some other program. Image
The manual way to fix this is checking to make sure the token program account has the right address. Image
The recommended way to fix this is by using Anchor's wrapper of the SPL token program. Image
7) Duplicate mutable accounts

If your program takes in two mutable accounts of the same type, make sure people don't pass in the same account twice.
Don't do this—user_a and user_b may be the same account. Image
Instead, use Anchor to verify that the two accounts are different. Image
8) Bump seed canonicalization

Often, you want to have a single PDA associated with a program ID + a set of seeds.

For example, associated token accounts (ATAs).

Thus, when verifying PDAs, you should use find_program_address instead of create_program_address.
Don't do this—since the bump is passed in by the user (and not verified), set_value could operate on multiple PDAs associated with the program ID + the set of seeds. Image
Instead, do this—both the PDA address and bump are verified, which means set_value will only operate on one "canonical" PDA. Image
9) PDA sharing

You should use a unique PDA for each "authority domain" (H/T @armaniferrante).

The example in the repo is a bit confusing, so let's consider a different one.
Let's say you have a bunch of liquidity pools, and each one has a PDA as an authority.

Instead of using the same PDA as the authority for each pool, it's more secure to use a unique PDA for each pool (e.g. derived from the two token mints the pool is for).
10) Closing accounts

If you no longer need an account, you should close it to reclaim its rent.

However, it turns out that closing an account is pretty tricky.
I'm not going to walk through all the complexities, because there are a lot.

Simply put, if you want to close an account, just use this Anchor macro Image
Hopefully all this made sense! If I made any errors, or if you have any questions, please let me know.
Lastly, I hear @armaniferrante (who understands this stuff much better than me) is working on a presentation to explain all these vulnerabilities more thoroughly, so stay tuned for that 👀

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with pencilflip.sol 🍄

pencilflip.sol 🍄 Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @pencilflip

Jan 16
The @metaplex team is working on a new metadata standard for both fungible and non-fungible tokens.

It's backwards compatible and has official support for on-chain collections. And it's currently being tested in devnet.

For more details, see below 👇
1/ First, and perhaps most importantly, this new standard is backwards compatible.

This means NFTs that use the old standard will still function properly (e.g. be displayed properly in Phantom) once the new standard rolls out.
2/ So, what changes does the new standard introduce?

First, let's look at the old on-chain metadata struct. Image
Read 14 tweets
Dec 30, 2021
If you're writing Solana instructions involving tokens/NFTs, please require the token's mint account to be passed!

Otherwise, if you query for the mint's transactions, transactions that include your instruction may not show up... more on this 👇
For example—the regular "Transfer" instruction of the SPL Token Program does not take in the mint account.

Thus, if you transfer an NFT using this instruction, it WON'T show up on that NFT's Solana Explorer page. Image
That's why @phantom uses the "Transfer Checked" instruction, which does take in the mint account.

And that's why NFT transfers conducted via Phantom will always show up in Solana Explorer for the token mint account. Image
Read 7 tweets
Dec 12, 2021
Solana vs. Ethereum L2s, a UX comparison
1/ A lot of people are excited about ZK-rollups, and for good reason.

However, from a UX experience, ZK-rollups aren't too different than existing L2s. E.g. Polygon already offers low fees and fast transactions.

Let's look at Solana vs. L2s, and see why one might be preferred.
2/ To simplify things, I'll mainly be looking at Polygon.

Yes, I know that ZK-rollups are more secure than Polygon's sidechain.

But really, most users don't care about that 🤷‍♂️. Users care about things like low fees and fast transactions, e.g. how good the UX is.
Read 14 tweets
Dec 10, 2021
How do Solana CPIs work?

That is, how do Solana programs call into other Solana programs?

Here's a quick 6 tweet explanation 👇
1/ If you're unfamiliar with Solana transactions/instructions, you might want to take a look at this first.

2/ Calling between programs is achieved by one program invoking an instruction of the other.

Here's how that looks in practice.

The first arg is the instruction to be invoked, and the second arg is the array of accounts required by that instruction.
Read 9 tweets
Dec 4, 2021
Is Solana centralized?

There are three main reasons why people say Solana is centralized:

1. Expensive to run a validator
2. Token distribution
3. Only one blockchain software client

Let's take a look at each of these reasons 👇
1/ IMO it doesn't matter how much it costs to be a validator—it matters how many validators there actually are, and what the Nakamoto coefficient is.

Turns out Solana's Nakamoto coefficient is pretty high (19 validators required to halt the network).

2/ 19 may not sound like a huge number, but it's higher than Ethereum's Nakamoto coefficient.

The NC for PoW Ethereum is 3 (etherchain.org/miner), and for PoS Ethereum it's 4 (source is a bit outdated, not sure exactly what it is now).

Read 20 tweets
Nov 23, 2021
Here's a diagram that shows all the different parts of a Solana transaction.

More details below 👇
1/ Each Solana transaction contains a message, and the first part of each message is its header.

The header is simple, it just contains the numbers described in the diagram.
2/ The next part of the transaction message is an array of accounts. They are ordered based on whether they require a signature and whether they are writable.

This array also contains the addresses of the programs used by the instructions.
Read 8 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us on Twitter!

:(