Skip to content

Commit

Permalink
README fixes
Browse files Browse the repository at this point in the history
 - Add a table of contents and a tool to generate it. Saves us having to tell people what's missing!
 - Prioritise Anchor, deprioritize Seahorse, and spell 'onchain' correctly.
 - Move note re: not needing to make onchain programs up. Remove unnecessary detail.
 - Mention onchain programs are called smart contracts on other blockchains for SEO purposes
  • Loading branch information
mikemaccana committed Jun 13, 2024
1 parent 2c4cb8f commit 22be08c
Show file tree
Hide file tree
Showing 2 changed files with 233 additions and 29 deletions.
208 changes: 179 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,197 @@
# Program Examples

### :crab: Rust. :snake: Python. :link: All on-chain.
## Onchain program examples for :anchor: Anchor :crab: Native Rust, Solidity and :snake: Python

## Navigating this Repo
This repo contains Solana onchain programs (referred to as 'Smart Contracts' in other blockchains).

:file_folder: Each example contains four folders:
Note - if you're new to Solana, you don't need to create your own programs to perform basic things like making accounts, creating tokens, or minting NFTs. These common tasks are handled with existing programs, for example the System Program (for making account or transferring SOL) or the token program (for creating tokens and NFTs). See [Solana Developer](https://solana.com/developers) to learn more.

- `native` - Written using Solana's native Rust crates and vanilla Rust.
- `anchor` - Written using Anchor's `anchor_lang` Rust crate and the associated Anchor framework to build & deploy.
- `seahorse` - Written using the Python framework Seahorse, which converts your Python code to Anchor Rust.
## Using this repo

:wrench: How to build & run:
Each folder includes examples for one or more of the following

- Before running anything in any folder make sure you pull in the dependencies with `yarn install`.
- `native` - Use `cicd.sh` to build & deploy the program. Run `yarn run test` to test it.
- `anchor` - Use `anchor build && anchor deploy` to build & deploy the program. Run `anchor run test` to test it.
- `seahorse` - Use `seahorse build && anchor deploy` to build & deploy the program. Run `anchor run test` to test it.
- `anchor` - Written using [Anchor](https://www.anchor-lang.com/), the most popular framework for Solana Development, which uses Rust. Use `anchor build && anchor deploy` to build & deploy the program. Run `anchor run test` to test it.
- `native` - Written using Solana's native Rust crates and vanilla Rust. Use `cicd.sh` to build & deploy the program. Run `yarn run test` to test it.
- `seahorse` - Written using the [Seahorse framework](https://seahorse-lang.org/), which converts your Python code to Anchor Rust. Use `seahorse build && anchor deploy` to build & deploy the program. Run `anchor run test` to test it.
- `solidity` - Written using Solidity.

If a given example

## basics

### account-data

[anchor](./basics/account-data/anchor), [native](./basics/account-data/native)

### checking-accounts

[anchor](./basics/checking-accounts/anchor), [native](./basics/checking-accounts/native)

### close-account

[anchor](./basics/close-account/anchor), [native](./basics/close-account/native)

### counter

[anchor](./basics/counter/anchor), [native](./basics/counter/native), [seahorse](./basics/counter/seahorse)

### create-account

[anchor](./basics/create-account/anchor), [native](./basics/create-account/native)

### cross-program-invocation

[anchor](./basics/cross-program-invocation/anchor), [native](./basics/cross-program-invocation/native)

### favorites

[anchor](./basics/favorites/anchor)

### hello-solana

[anchor](./basics/hello-solana/anchor), [native](./basics/hello-solana/native), [seahorse](./basics/hello-solana/seahorse)

### pda-rent-payer

[anchor](./basics/pda-rent-payer/anchor), [native](./basics/pda-rent-payer/native)

### processing-instructions

[anchor](./basics/processing-instructions/anchor), [native](./basics/processing-instructions/native)

### program-derived-addresses

[anchor](./basics/program-derived-addresses/anchor), [native](./basics/program-derived-addresses/native)

### realloc

[anchor](./basics/realloc/anchor), [native](./basics/realloc/native)

### rent

[anchor](./basics/rent/anchor), [native](./basics/rent/native)

### repository-layout

[anchor](./basics/repository-layout/anchor), [native](./basics/repository-layout/native)

### transfer-sol

[anchor](./basics/transfer-sol/anchor), [native](./basics/transfer-sol/native), [seahorse](./basics/transfer-sol/seahorse)

## tokens

### create-token

[anchor](./tokens/create-token/anchor), [native](./tokens/create-token/native)

### escrow

[anchor](./tokens/escrow/anchor)

### nft-minter

[anchor](./tokens/nft-minter/anchor), [native](./tokens/nft-minter/native)

### pda-mint-authority

[anchor](./tokens/pda-mint-authority/anchor), [native](./tokens/pda-mint-authority/native)

### spl-token-minter

[anchor](./tokens/spl-token-minter/anchor), [native](./tokens/spl-token-minter/native)

### token-swap

[anchor](./tokens/token-swap/anchor)

### transfer-tokens

[anchor](./tokens/transfer-tokens/anchor), [native](./tokens/transfer-tokens/native), [seahorse](./tokens/transfer-tokens/seahorse)

## tokens/token-2022

### basics

[anchor](./tokens/token-2022/basics/anchor)

### cpi-guard

[anchor](./tokens/token-2022/cpi-guard/anchor)

### default-account-state

[anchor](./tokens/token-2022/default-account-state/anchor), [native](./tokens/token-2022/default-account-state/native)

### group

[anchor](./tokens/token-2022/group/anchor)

### immutable-owner

[anchor](./tokens/token-2022/immutable-owner/anchor)

### interest-bearing

[anchor](./tokens/token-2022/interest-bearing/anchor)

### memo-transfer

[anchor](./tokens/token-2022/memo-transfer/anchor)

### metadata

[anchor](./tokens/token-2022/metadata/anchor)

### mint-close-authority

[anchor](./tokens/token-2022/mint-close-authority/anchor), [native](./tokens/token-2022/mint-close-authority/native)

### multiple-extensions

[native](./tokens/token-2022/multiple-extensions/native)

### non-transferable

[anchor](./tokens/token-2022/non-transferable/anchor), [native](./tokens/token-2022/non-transferable/native)

### permanent-delegate

[anchor](./tokens/token-2022/permanent-delegate/anchor)

### transfer-fee

[anchor](./tokens/token-2022/transfer-fee/anchor), [native](./tokens/token-2022/transfer-fee/native)

## compression

### cnft-burn

[anchor](./compression/cnft-burn/anchor)

### cnft-vault

[anchor](./compression/cnft-vault/anchor)

### cutils

[anchor](./compression/cutils/anchor)

## oracles

### pyth

[anchor](./oracles/pyth/anchor), [seahorse](./oracles/pyth/seahorse)

## Examples We'd Love to See!

- Examples needed for Native:
- Token2022
- Token Extensions
- Examples needed for Anchor:
- Additional Accounts & Resolving Accounts
- Examples needed for Seahorse
- Any existing example missing a `seahorse` folder
- New examples needed for Solidity, Anchor, Native & Seahorse:
- New examples needed for Anchor, Native, Solidity & Seahorse:
- Token lending
- Token swapping
- Escrow
Expand All @@ -38,19 +204,3 @@
- Merkle trees (compression)

---

## If You're New To Solana Please Read

Most system-level operations on Solana involve already-existing Solana programs.

For example, to create a **system account** you use the **system program** and to create a **token mint** you use the **token program**.

So, you'll notice that these operations are in fact conducting what's called a **cross-program invocation** - which is a fancy way of saying it calls other Solana programs to do business. You can see this in action whenever you see `invoke` or `invoke_signed` in the `native` examples, or `CpiContext` in the `anchor` examples.

Deciding when to use cross-program invocation instead of invoking the programs directly from the client is completely up to you as the builder. It depends on how your application is designed.

- Maybe you want to add some checks - such as minimum balance required, allowed ownership, etc.
- Maybe you want to assert that an account has a certain data type.
- Perhaps you want to send only one instruction from your client for a handful of sequential operations.
- The list goes on.
Regardless of what you may want to add on top of existing Solana programs, the number one use case for writing your own program is for using accounts with a **Program Derived Address (PDA)**. Crack open the `pdas` folder to see why.
54 changes: 54 additions & 0 deletions make-table-of-contents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Usage: esrun make-table-of-contents.ts
import { readdir } from 'node:fs/promises';
const log = console.log;

// A serial async map function (because we like do things in order and performance doesn't matter)
const asyncMap = async (array, asyncFunction) => {
for (const item of array) {
await asyncFunction(item);
}
};

const PROJECT_TYPES = ['anchor', 'native', 'solidity', 'seahorse'];
const CATEGORIES = ['basics', 'tokens', 'tokens/token-2022', 'compression', 'oracles'];

interface LinkMap {
[key: string]: boolean;
}

// Loop through the folders in CATEGORIES and for each folder, find child directories that contain a folder matching a project type
await asyncMap(CATEGORIES, async (category) => {
const path = `./${category}`;
const exampleFolders = (await readdir(path, { withFileTypes: true })).filter((item) => item.isDirectory()).map((dir) => dir.name);
// Loop through the folders and log each folder
log(`\n\n## ${category}`);
await asyncMap(exampleFolders, async (exampleFolder) => {
// Check if the folder has a subfolder that matches a project type
const projectTypeFolders = (await readdir(`./${category}/${exampleFolder}`, { withFileTypes: true }))
.filter((item) => item.isDirectory())
.filter((dir) => PROJECT_TYPES.includes(dir.name));

// If there are no subfolders that match a project type, we can skip this folder - it's not example code
if (projectTypeFolders.length === 0) {
return;
}
log(`\n### ${exampleFolder}`);

// We can now create a map of the project types that are present in the example folder
const linkMap: LinkMap = {};
PROJECT_TYPES.forEach((projectType) => {
linkMap[projectType] = projectTypeFolders.some((dir) => dir.name === projectType);
});

const links: Array<string> = [];
// Go through the link map and log a markdown link to the folder if the linkmap value is true
// otherwise log 'create me' as a placeholder
for (const [projectType, exists] of Object.entries(linkMap)) {
const link = `./${category}/${exampleFolder}/${projectType}`;
if (exists) {
links.push(`[${projectType}](${link})`);
}
}
log(links.join(', '));
});
});

0 comments on commit 22be08c

Please sign in to comment.