What to learn first?
To get up to speed, I suggest skipping learning about internals like Proof of History, etc., which are academically interesting but not practically useful in dapp development. Instead, familiarize yourself first with:
Transfer
instruction on the built-in Token
program will transfer tokens from one account to another.Then, I’d probably start writing some basic stuff using web3js. For instance, initialize a Keypair
(account) and airdrop some Solana to it on devnet or localhost. Learn how to create a token from scratch using spl-token.
FAQ
Why do validators need so much processing power?
What’s the different between wallets and accounts?
Are there smart contracts on Solana?
What’s the difference between owners and authorities?
transfer
also refer to a transfer_authority
— which could be the token account’s owner — but could also be an approved delegate.Why do we have to pass so many accounts to each transaction, including the programs we use?
But what if someone passes in a fake account to a transaction?
What’s the point of program derived addresses? (PDAs)
The PDA on the program side could have its seeds based on the signer’s public key, and the token mint ID. In Anchor, that looks something like this:
seeds = [signer.key().as_ref(), mint.key().as_ref()]
Therefore, if I know those on the client side, I can easily figure out the address and look up the data (which is useful for showing details in front end, etc.). e.g. in Anchor JS:
const [tokenPDA, _tokenPDABump] =
await anchor.web3.PublicKey.findProgramAddress(
[
provider.wallet.publicKey.toBuffer(),
tokenMintPubKey.toBuffer(),
],
program.programId
);
What is a bump in PDAs?
A bump is used to “bump” a seeded PDA off the ed25519 curve. Otherwise, the PDA might have a corresponding private key, which would be a security vulnerability.
You must have the corresponding bump available to sign a transaction involving a PDA.
In Anchor, this is available in the passed Context<T>
for the instruction. By default, having bump,
in your #[account(...)]
macro for the instruction’s struct field, will make it available in ctx.bumps.get
with that field’s name.
let foo_bump = *ctx.bumps.get("foo").unwrap();
More details here.
How do you sign a transaction involving a PDA?
#[account(init,
token::mint = foo_mint,
token::authority = foo, // foo also a PDA
seeds = [foo.key().as_ref(), b"foo_tokens"],
bump,
payer = authority
)]
pub foo_tokens: Box<Account<'info, TokenAccount>>,
let transfer_inst = Transfer {
from: foo_tokens.to_account_info(),
to: user_tokens.to_account_info(),
authority: authority.to_account_info(),
};
// These are the same as the struct, plus the bump.
let seeds = &[
foo.to_account_info().key.as_ref(),
b"foo_tokens",
&[foo.bump], // we stored the bump in the account struct
];
let signer: &[&[&[u8]]] = &[&seeds[..]]; // must coerce to proper type
let cpi_ctx = CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
transfer_inst,
signer,
);
token::transfer(cpi_ctx, amount)?;
What is an NFT in Solana?
Transfer
instruction in token program.How do people create collections of NFTs?
How do you write contracts that deal with both native Solana and tokens interchangeably?