Skip to content

Commit

Permalink
Update verifiable-randomness-functions and serialize-instruction-data…
Browse files Browse the repository at this point in the history
…-frontend (#382)

* refactor(): replaced .then with trycatch block

* chore(): fixed course redirect link

* fix(): fixed push changes

* chore(): updated project urls

* chore(): removed unnecessary imports

* chore(): included safe error access and flexible error check. also replaced outdated methods

* chore(): replaced single letter with fullname

* fix(): fixed the complicated error value

* fix(): made changes as specified in the PR review

* fix(): minor variable fix

* chore(): minor fix

---------

Co-authored-by: Onyewuchi Emeka <[email protected]>
  • Loading branch information
EmekaManuel and Onyewuchi Emeka authored Sep 4, 2024
1 parent f98ca0a commit 9959ff8
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ to interact with and respond to real-world events. The Switchboard network is
made up of many different individual oracles run by third parties to provide
external data and service requests onchain. To learn more about Switchboard’s
Oracle network, please refer to our
[Oracle lesson](/developers/courses/connecting-to-offchain-data/oracles).
[Oracle lesson](/content/courses/connecting-to-offchain-data/oracles.md)

Switchboard's VRF allows users to request an oracle to produce a randomness
output onchain. Once an oracle has been assigned the request, the proof of the
Expand Down Expand Up @@ -1311,9 +1311,9 @@ describe("burry-escrow-vrf", () => {
// Check whether the data onchain is equal to local 'data'
assert(failUnlockPrice == newAccount.unlockPrice);
assert(escrowBalance > 0);
} catch (e) {
console.log(e);
assert.fail(e);
} catch (error) {
console.log(error);
assert.fail(error);
}
});

Expand Down Expand Up @@ -1341,13 +1341,14 @@ describe("burry-escrow-vrf", () => {

await provider.connection.confirmTransaction(tx, "confirmed");
console.log("Your transaction signature", tx);
} catch (e) {
// verify tx returns expected error
} catch (error) {
didFail = true;
console.log(e.error.errorMessage);

assert(
e.error.errorMessage ==
error.message.includes(
"Current SOL price is not above Escrow unlock price.",
),
"Unexpected error message: " + error.message,
);
}

Expand Down Expand Up @@ -1517,8 +1518,8 @@ it("Roll till you can withdraw", async () => {
})
.signers([payer])
.rpc();
} catch (e) {
console.log(e);
} catch (error) {
console.log(error);
assert.fail();
}

Expand Down Expand Up @@ -1580,8 +1581,8 @@ it("Roll till you can withdraw", async () => {
console.log("Resetting die...");
await delay(5000);
}
} catch (e) {
console.log(e);
} catch (error) {
console.log(error);
assert.fail();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ description: How to deserialize data fetched from Solana accounts.
### Transactions

<Callout type="note">This course requires completing
[Introduction to Solana](/developers/courses/intro-to-solana) or equivalent
[Introduction to Solana](/content/courses/intro-to-solana) or equivalent
knowledge. It's also aimed at advanced developers that prefer more control over
the ease of use and safe defaults Anchor provides. If you're new to developing
onchain programs you may prefer
[Anchor](/developers/courses/onchain-development)</Callout>
[Anchor](/content/courses/onchain-development)</Callout>

In [Introduction to Solana](/developers/courses/intro-to-solana) we learned how
to create transactions with instructions for common Solana programs.
In [Introduction to Solana](/content/courses/intro-to-solana) we learned how to
create transactions with instructions for common Solana programs.

This lessons shows how to create instructions for our own native Solana
programs, which we will develop in a few lessons. Specifically, we're going to
Expand Down Expand Up @@ -195,7 +195,7 @@ equipPlayerSchema.encode(
buffer,
);

const instructionBuffer = buffer.slice(0, equipPlayerSchema.getSpan(buffer));
const instructionBuffer = buffer.subarray(0, equipPlayerSchema.getSpan(buffer));
```

Once a buffer is properly created and the data serialized, all that’s left is
Expand All @@ -211,7 +211,14 @@ lessons. The example below assumes that:

```typescript
import * as borsh from "@coral-xyz/borsh";
import * as web3 from "@solana/web3.js";
import {
clusterApiUrl,
Connection,
SystemProgram,
Transaction,
TransactionInstruction,
sendAndConfirmTransaction,
} from "@solana/web3.js";

const equipPlayerSchema = borsh.struct([
borsh.u8("variant"),
Expand All @@ -225,13 +232,13 @@ equipPlayerSchema.encode(
buffer,
);

const instructionBuffer = buffer.slice(0, equipPlayerSchema.getSpan(buffer));
const instructionBuffer = buffer.subarray(0, equipPlayerSchema.getSpan(buffer));

const endpoint = web3.clusterApiUrl("devnet");
const connection = new web3.Connection(endpoint);
const endpoint = clusterApiUrl("devnet");
const connection = new Connection(endpoint);

const transaction = new web3.Transaction();
const instruction = new web3.TransactionInstruction({
const transaction = new Transaction();
const instruction = new TransactionInstruction({
keys: [
{
pubkey: player.publicKey,
Expand All @@ -244,7 +251,7 @@ const instruction = new web3.TransactionInstruction({
isWritable: true,
},
{
pubkey: web3.SystemProgram.programId,
pubkey: SystemProgram.programId,
isSigner: false,
isWritable: false,
},
Expand All @@ -255,11 +262,17 @@ const instruction = new web3.TransactionInstruction({

transaction.add(instruction);

web3.sendAndConfirmTransaction(connection, transaction, [player]).then(txid => {
console.log(
`Transaction submitted: https://explorer.solana.com/tx/${txid}?cluster=devnet`,
try {
const transactionId = await sendAndConfirmTransaction(
connection,
transaction,
[player],
);
});
const explorerLink = getExplorerLink("transaction", transactionId, "devnet");
console.log(`Transaction submitted: ${explorerLink}`);
} catch (error) {
alert(error);
}
```

## Lab
Expand All @@ -269,7 +282,7 @@ submit a movie review and have it stored on Solana’s network. We’ll build th
app a little bit at a time over the next few lessons, adding new functionality
each lesson.

![Movie review frontend](/public/assets/courses/unboxed/movie-reviews-frontend.png)
![Movie review frontend](/public/assets/courses/movie-review-dapp.png)

Here's a quick diagram of the program we'll build:

Expand All @@ -281,7 +294,7 @@ The public key of the Solana program we’ll use for this application is
#### 1. Download the starter code

Before we get started, go ahead and download the
[starter code](https://github.com/Unboxed-Software/solana-movie-frontend/tree/starter).
[starter code](https://github.com/solana-developers/movie-review-frontend/tree/starter).

The project is a fairly simple Next.js application. It includes the
`WalletContextProvider` we created in the Wallets lesson, a `Card` component for
Expand Down Expand Up @@ -359,9 +372,14 @@ export class Movie {
])

serialize(): Buffer {
const buffer = Buffer.alloc(1000)
this.borshInstructionSchema.encode({ ...this, variant: 0 }, buffer)
return buffer.slice(0, this.borshInstructionSchema.getSpan(buffer))
try {
const buffer = Buffer.alloc(1000);
this.borshInstructionSchema.encode({ ...this, variant: 0 }, buffer);
return buffer.subarray(0, this.borshInstructionSchema.getSpan(buffer));
} catch (error) {
console.error('Serialization error:', error);
return Buffer.alloc(0);
}
}
}
```
Expand Down Expand Up @@ -391,19 +409,12 @@ import { FC } from "react";
import { Movie } from "../models/Movie";
import { useState } from "react";
import {
Box,
Button,
FormControl,
FormLabel,
Input,
NumberDecrementStepper,
NumberIncrementStepper,
NumberInput,
NumberInputField,
NumberInputStepper,
Textarea,
} from "@chakra-ui/react";
import * as web3 from "@solana/web3.js";
Connection,
PublicKey,
SystemProgram,
Transaction,
TransactionInstruction,
} from "@solana/web3.js";
import { useConnection, useWallet } from "@solana/wallet-adapter-react";
```

Expand All @@ -415,9 +426,15 @@ Next, before the `handleSubmit` function, call `useConnection()` to get a
import { FC } from 'react'
import { Movie } from '../models/Movie'
import { useState } from 'react'
import { Box, Button, FormControl, FormLabel, Input, NumberDecrementStepper, NumberIncrementStepper, NumberInput, NumberInputField, NumberInputStepper, Textarea } from '@chakra-ui/react'
import * as web3 from '@solana/web3.js'
import {
Connection,
PublicKey,
SystemProgram,
Transaction,
TransactionInstruction,
} from "@solana/web3.js"
import { useConnection, useWallet } from '@solana/wallet-adapter-react'
import { getExplorerLink } from "@solana-developers/helpers";

const MOVIE_REVIEW_PROGRAM_ID = 'CenYq6bDRB7p73EjsPEpiYN7uveyPUTdXkDkgUduboaN'

Expand Down Expand Up @@ -465,7 +482,7 @@ const handleTransactionSubmit = async (movie: Movie) => {
}

const buffer = movie.serialize();
const transaction = new web3.Transaction();
const transaction = new Transaction();
};
```

Expand All @@ -477,14 +494,14 @@ the following, where `pda` is the address to the account where data will be
stored:

```typescript
const [pda] = await web3.PublicKey.findProgramAddress(
const [pda] = await PublicKey.findProgramAddressSync(
[publicKey.toBuffer(), Buffer.from(movie.title)],
new web3.PublicKey(MOVIE_REVIEW_PROGRAM_ID),
new PublicKey(MOVIE_REVIEW_PROGRAM_ID),
);
```

In addition to this account, the program will also need to read from
`SystemProgram`, so our array needs to include `web3.SystemProgram.programId` as
`SystemProgram`, so our array needs to include `SystemProgram.programId` as
well.

With that, we can finish the remaining steps:
Expand All @@ -497,14 +514,14 @@ const handleTransactionSubmit = async (movie: Movie) => {
}

const buffer = movie.serialize();
const transaction = new web3.Transaction();
const transaction = new Transaction();

const [pda] = await web3.PublicKey.findProgramAddress(
const [pda] = await PublicKey.findProgramAddressSync(
[publicKey.toBuffer(), new TextEncoder().encode(movie.title)],
new web3.PublicKey(MOVIE_REVIEW_PROGRAM_ID),
new PublicKey(MOVIE_REVIEW_PROGRAM_ID),
);

const instruction = new web3.TransactionInstruction({
const instruction = new TransactionInstruction({
keys: [
{
pubkey: publicKey,
Expand All @@ -517,24 +534,27 @@ const handleTransactionSubmit = async (movie: Movie) => {
isWritable: true,
},
{
pubkey: web3.SystemProgram.programId,
pubkey: SystemProgram.programId,
isSigner: false,
isWritable: false,
},
],
data: buffer,
programId: new web3.PublicKey(MOVIE_REVIEW_PROGRAM_ID),
programId: new PublicKey(MOVIE_REVIEW_PROGRAM_ID),
});

transaction.add(instruction);

try {
let txid = await sendTransaction(transaction, connection);
console.log(
`Transaction submitted: https://explorer.solana.com/tx/${txid}?cluster=devnet`,
let transactionId = await sendTransaction(transaction, connection);
const explorerLink = getExplorerLink(
"transaction",
transactionId,
"devnet",
);
} catch (e) {
alert(JSON.stringify(e));
console.log(`Transaction submitted: ${explorerLink}`);
} catch (error) {
alert(error);
}
};
```
Expand All @@ -546,18 +566,18 @@ successful.

If you need a bit more time with this project to feel comfortable, have a look
at the complete
[solution code](https://github.com/Unboxed-Software/solana-movie-frontend/tree/solution-serialize-instruction-data).
[solution code](https://github.com/solana-developers/movie-review-frontend/tree/solution-serialize-instruction-data).

## Challenge

Now it’s your turn to build something independently. Create an application that
lets students of this course introduce themselves! The Solana program that
supports this is at `HdE95RSVsdb315jfJtaykXhXY478h53X6okDupVfY9yf`.

![Student Intros frontend](/public/assets/courses/unboxed/student-intros-frontend.png)
![Student Intros frontend](/public/assets/courses/student-intros-frontend.png)

1. You can build this from scratch or you can
[download the starter code](https://github.com/Unboxed-Software/solana-student-intros-frontend/tree/starter).
[download the starter code](https://github.com/solana-developers/solana-student-intro-frontend/tree/starter).
2. Create the instruction buffer layout in `StudentIntro.ts`. The program
expects instruction data to contain:
1. `variant` as an unsigned, 8-bit integer representing the instruction to
Expand All @@ -575,7 +595,7 @@ supports this is at `HdE95RSVsdb315jfJtaykXhXY478h53X6okDupVfY9yf`.
Explorer to verify that it worked.

If you get stumped, you can
[check out the solution code](https://github.com/Unboxed-Software/solana-student-intros-frontend/tree/solution-serialize-instruction-data).
[check out the solution code](https://github.com/solana-developers/solana-student-intro-frontend/tree/solution-serialize-instruction-data).

Feel free to get creative with these challenges and take them even further. The
instructions aren't here to hold you back!
Expand Down

0 comments on commit 9959ff8

Please sign in to comment.