Full lesson
Sav3ana
What it does
From the project README:
Our app, as we mentioned before, aims to increase crypto adoption, improve the financial health of users, and give them more access to services without all the hassles of traditional banks.1
- Original
- altaga/Sav3ana
- SuperStack fork
- Blockchains/Sav3ana @
2365a37 - Stars
- 2
- Last push (original)
- 2024-10-09
- Languages
- JavaScript, Rust, Kotlin, Objective-C, Ruby, Objective-C++
- Detected stack
- web3.js
- Categories
- Other
- Licence
- MIT
Architecture
62 source files. By extension: .js ×60, .tsx ×1, .rs ×1.
| Top-level directory | Source files |
|---|---|
Sav3ana | 48 |
Programs | 10 |
Cloud | 4 |
Dapp: deploying
This fork is queued for its own live dapp on Sol.College, with a Devnet/Mainnet switch. It appears here, at /dapps/sav3ana/, once it is deployed and checked on devnet. Until then, run it locally with the commands below.
Key code, explained
Excerpts chosen automatically where the code uses the most Solana concepts, pinned to the fork's commit.
Sav3ana/src/screens/topUp/topUp.js L85–108 @ 2365a37 · MIT · original true, ); tx.add( createTransferInstruction( tokenAccountFrom, tokenAccountTo, new PublicKey(this.context.value.publicKey), tokenAmount, ), ); } const privateKey = await getEncryptedStorageValue('privateKey'); const wallet = Keypair.fromSecretKey( Uint8Array.from(privateKey.split(',')), ); const recentBlockhash = (await this.provider.getLatestBlockhash()) .blockhash; tx.recentBlockhash = recentBlockhash; tx.feePayer = wallet.publicKey; tx.sign(wallet); await this.provider.sendRawTransaction(tx.serialize(), { maxRetries: 5, }); const myHeaders = new Headers();- Line 88
createTransferInstruction(: An SPL token transfer through the Token Program. - Line 100
const recentBlockhash = (await this.provider.getLatestBlockhash()): Fetches a recent blockhash. Transactions expire if it gets too old.
Sav3ana/src/screens/main/tabs/tab3.js L277–300 @ 2365a37 · MIT · original amount: this.state.amount, tokenSymbol: this.state.tokenSelected.symbol, // Bulk Display labelBulk, toBulk, amountBulk, tokenSymbolBulk, }, }); } async setupCard() { await this.setupChainCard(); await this.setupCloudCard(); } async createCard() { const programId = new PublicKey(SolanaCardProgramID); const owner = new PublicKey(this.context.value.publicKey); let [pda, bump] = await PublicKey.findProgramAddressSync( [Buffer.from('card'), owner.toBuffer()], programId, ); const kind = ProgramInstruction.CreateCard;- Line 296
let [pda, bump] = await PublicKey.findProgramAddressSync(: Derives a PDA from seeds and the program ID and returns the address with its canonical bump. - Line 296
let [pda, bump] = await PublicKey.findProgramAddressSync(: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
Cloud/CardTransaction/index.js L49–72 @ 2365a37 · MIT · original const toAddress = req.body.toAddress; const amount = req.body.amount; const tokenAddress = req.body.tokenAddress; const decimals = req.body.decimals; const concept = req.body.concept; const query = await Accounts.where( "cardHash", "==", decrypted.toString() ).get(); if (query.empty) { throw "Query Empty"; } else { let transactionSignature; const owner = new PublicKey(query.docs[0].data().pubKey); const to = new PublicKey(toAddress); let [pda,bump] = await PublicKey.findProgramAddressSync( [Buffer.from("card"), owner.toBuffer()], programId ); let tx = new Transaction() if(tokenAddress ==='So11111111111111111111111111111111111111112'){ const payload = { instruction: ProgramInstruction.Purchase,- Line 65
let [pda,bump] = await PublicKey.findProgramAddressSync(: Derives a PDA from seeds and the program ID and returns the address with its canonical bump. - Line 65
let [pda,bump] = await PublicKey.findProgramAddressSync(: Uses the bump seed, the extra byte that pushes the derived address off the ed25519 curve.
Cloud/TopUp/index.js L97–120 @ 2365a37 · MIT · original tx.add( createAssociatedTokenAccountInstruction( new PublicKey(feePayer.publicKey), tokenAccountTo, new PublicKey(publicKey), new PublicKey(tokenAddress), TOKEN_PROGRAM_ID, ), ); } tx.add( createTransferInstruction( tokenAccountFrom, tokenAccountTo, new PublicKey(feePayer.publicKey), Math.round(tokenAmount*Math.pow(10,decimals)), ), ) } const recentBlockhash = (await connection.getLatestBlockhash()).blockhash; tx.recentBlockhash = recentBlockhash; tx.feePayer = feePayer.publicKey; tx.sign(feePayer) await connection.sendRawTransaction(- Line 108
createTransferInstruction(: An SPL token transfer through the Token Program. - Line 116
const recentBlockhash = (await connection.getLatestBlockhash()).blockhash;: Fetches a recent blockhash. Transactions expire if it gets too old.
How to run, build and test
These commands come from the repo's own manifests (package.json scripts, Anchor.toml, Cargo, go.mod, Makefile). Check the README for prerequisites and environment variables.
| Directory | Command | Runs |
|---|---|---|
Sav3ana | npm run start | react-native start |
Sav3ana | npm run build | cd android && gradlew assembleRelease && cd .. |
Sav3ana | npm run test | jest |
Sav3ana | npm run lint | eslint . |
Sav3ana | npm run deploy | cd android && gradlew :app:assembleRelease && adb install -r app/build/outputs/apk/release/app-release.apk |
Programs/client | npm run test | echo "Error: no test specified" && exit 1 |
What you could build from it
- Fork the SuperStack copy and extend it within the Other gaps listed on the idea page.
- Learn the pattern first: Program Derived Addresses (PDAs)
- Learn the pattern first: Cross-Program Invocations (CPIs)