Skip to content

Commit 987f8c9

Browse files
committed
feat: finish pt 2 quiz + undo new routes for v1
1 parent 4241233 commit 987f8c9

File tree

9 files changed

+112
-103
lines changed

9 files changed

+112
-103
lines changed

src/contexts/AppContext.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ interface IAppContext {
55
completedQuizzesIds: string[];
66
projects: Project[];
77
fundamentals: Fundamental[];
8-
ethIntro: EthIntro[];
98
allLessonsData: any[];
109
refetchCompletedQuizzesAll?: () => Promise<any>;
1110
}
@@ -14,7 +13,6 @@ export const AppContext = createContext<IAppContext>({
1413
completedQuizzesIds: [],
1514
projects: [],
1615
fundamentals: [],
17-
ethIntro: [],
1816
allLessonsData: [],
1917
refetchCompletedQuizzesAll: () => Promise.resolve(),
2018
});

src/contexts/AppContextProvider.tsx

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ interface IProps {
2222
export function AppContextProvider({ children }: IProps) {
2323
const [fundamentals, setFundamentals] = useState<Fundamental[]>([]);
2424
const [projects, setProjects] = useState<Project[]>([]);
25-
const [ethIntro, setEthIntro] = useState<EthIntro[]>([]);
2625
const [completedQuizzesIds, setCompletedQuizzesIds] = useState<string[]>([]);
2726
const [sessionDataUser, setSessionDataUser] = useState<any>(null);
2827

@@ -88,7 +87,6 @@ export function AppContextProvider({ children }: IProps) {
8887

8988
setFundamentals(lessonsFormatResult.fundamentals);
9089
setProjects(lessonsFormatResult.projects);
91-
setEthIntro(lessonsFormatResult["eth-intro"]);
9290
};
9391

9492
useEffect(() => {
@@ -100,31 +98,6 @@ export function AppContextProvider({ children }: IProps) {
10098
refetchOnWindowFocus: false,
10199
});
102100

103-
useEffect(() => {
104-
if (allLessonsData && ethIntro && completedQuizzesIds.length !== 0) {
105-
const lessonsWithCompleteStatus = ethIntro.map((lesson) => {
106-
const currentLessonId = allLessonsData.find(
107-
(lessonData) =>
108-
lessonData.projectLessonNumber?.toString() ===
109-
lesson.slug.toString(), // DEV_NOTE: forcing .toString() to avoid type errors
110-
)?.id;
111-
112-
const completed = currentLessonId
113-
? completedQuizzesIds.includes(currentLessonId)
114-
: false; // DEV_NOTE: if the lesson is not found, it is not completed
115-
return { ...lesson, completed };
116-
});
117-
118-
setEthIntro(lessonsWithCompleteStatus);
119-
} else if (allLessonsData && ethIntro && completedQuizzesIds.length === 0) {
120-
const lessonsWithCompleteStatus = ethIntro.map((lesson) => {
121-
return { ...lesson, completed: false };
122-
});
123-
setEthIntro(lessonsWithCompleteStatus);
124-
}
125-
// eslint-disable-next-line react-hooks/exhaustive-deps
126-
}, [completedQuizzesIds]);
127-
128101
useEffect(() => {
129102
if (allLessonsData && projects && completedQuizzesIds.length !== 0) {
130103
const projectsWithCompleteStatus = projects.map((lesson) => {
@@ -185,7 +158,6 @@ export function AppContextProvider({ children }: IProps) {
185158
completedQuizzesIds,
186159
projects,
187160
fundamentals,
188-
ethIntro,
189161
allLessonsData: allLessonsData || [],
190162
refetchCompletedQuizzesAll,
191163
}}

src/interfaces/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ export interface Lessons {
1515
export interface IFormatedLessons {
1616
projects: Project[];
1717
fundamentals: Fundamental[];
18-
ethIntro: EthIntro[];
1918
}
2019

2120
export interface Fundamental {

src/pages/getting-started.tsx

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import type { Lessons, Lesson } from "@/interfaces";
2424
import { useAppContext } from "@/contexts/AppContext";
2525

2626
const GettingStartedPage: NextPageWithLayout<Lessons> = () => {
27-
const { ethIntro, projects, fundamentals } = useAppContext();
27+
const { projects, fundamentals } = useAppContext();
2828
const [isMobile] = useMediaQuery("(max-width: 768px)", {
2929
ssr: true,
3030
fallback: true, // return false on the server, and re-evaluate on the client side
@@ -74,54 +74,6 @@ const GettingStartedPage: NextPageWithLayout<Lessons> = () => {
7474
>
7575
Current Lessons
7676
</Heading>
77-
<UnorderedList listStyleType="none" textAlign="center" as="div">
78-
<Heading size="md" color="yellow.300">
79-
{`INTRO TO ETHEREUM`}
80-
</Heading>
81-
<>
82-
{ethIntro.map((lesson: Lesson, idx: number) => (
83-
<ListItem key={idx} my="2" py="2" maxW="40vw" margin="0 auto">
84-
<Link
85-
as={NextLink}
86-
href={`/lessons/${lesson.path}/${lesson.slug}`}
87-
passHref
88-
>
89-
<Button
90-
height="auto"
91-
style={{
92-
whiteSpace: "normal",
93-
wordWrap: "break-word",
94-
padding: "0.5rem",
95-
width: "100%",
96-
fontSize: "xl",
97-
}}
98-
>
99-
<Flex direction={!isMobile ? "row" : "column"}>
100-
<Box>{lesson.frontMatter.title}</Box>
101-
<Box>
102-
{lesson &&
103-
lesson.completed &&
104-
lesson.completed === true ? (
105-
<>
106-
<Badge
107-
ml="1"
108-
alignItems={"flex-end"}
109-
colorScheme="green"
110-
position={!isMobile ? "absolute" : "relative"}
111-
right={3}
112-
>
113-
Completed
114-
</Badge>
115-
</>
116-
) : null}
117-
</Box>
118-
</Flex>
119-
</Button>
120-
</Link>
121-
</ListItem>
122-
))}
123-
</>
124-
</UnorderedList>
12577
<UnorderedList listStyleType="none" textAlign="center" as="div">
12678
<Heading size="md" color="yellow.300">
12779
{`PROJECT: BUILD AN NFT COLLECTION`}
File renamed without changes.

src/pages/lessons/eth-intro/2.mdx renamed to src/pages/lessons/fundamentals/2.mdx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ In [8]: tx_hash = w3.eth.send_transaction({
138138
})
139139
```
140140

141-
142141
This transaction will execute immediately, but some important details are hidden from view. web3.py is smart enough to know that `EthereumTesterProvider` is managing `acct_one` and that we're using a test environment. For our convenience, `acct_one` is "unlocked," meaning transactions from the account are approved (signed) by default.
143142

144143
So, what does a transaction look like if not from an unlocked account? To find out, let's send some ether from `acct_two` – an account not managed by `EthereumTesterProvider`. This more manual process takes three steps: 1) specify the transaction details, 2) sign the transaction, then 3) broadcast the transaction to the network.
@@ -162,7 +161,7 @@ In[11]: tx_hash = w3.eth.send_raw_transaction(signed.rawTransaction)
162161

163162
Let's break that down. Step 1 defines a Python dictionary with the required transaction fields. We briefly learned about gas (transaction fees) in Part 1, but nonce may be new territory. In Ethereum, a **nonce** is simply the transaction count of the account. The Ethereum protocol keeps track of this value to prevent double-spending.
164163

165-
Since this is the first transaction being made by acct_two, its nonce is zero. If you supply the wrong value, the result is an invalid transaction and is rejected by web3.py:
164+
Since this is the first transaction being made by `acct_two`, its nonce is zero. If you supply the wrong value, the result is an invalid transaction and is rejected by web3.py:
166165

167166
```bash
168167
ValidationError: Invalid transaction nonce: Expected 0, but got 4
@@ -261,22 +260,18 @@ Data mining isn't going away, but this new account ownership model enables a hea
261260

262261
### New software architectures
263262

264-
An interesting wrinkle in the definition of your business model will be what to handle on-chain vs. off-chain. As we've discussed, message signing requires no on-chain interaction. There's also nothing stopping you from using a private database for some of your data and the Ethereum blockchain for other bits of data or functionality. There are plenty of tradeoffs to consider: usability, cost, transparency, decentralization, privacy, and so on.
263+
An interesting wrinkle in the definition of your business model will be what to handle onchain vs. offchain. As we've discussed, message signing requires no onchain interaction. There's also nothing stopping you from using a private database for some of your data and the Ethereum blockchain for other bits of data or functionality. There are plenty of tradeoffs to consider: usability, cost, transparency, decentralization, privacy, and so on.
265264

266265
## And breathe
267266

268267
Did all that sink in? Test yourself:
269268

270-
- How do Ethereum accounts differ from those in Web 2.0?
271-
- In what ways can Ethereum accounts be used?
272-
- What are the implications of Ethereum accounts for app developers?
273-
274-
There's no limit to the number of accounts you can generate and you're free to use the same account for several apps or create a new account for every app. This is partly what is meant when a public blockchain is described as **permissionless**: there is no gatekeeper between you and the network. Don't wait for anyone to give you permission to build.
275-
276269
<br />
277270
<QuizStatusChecker quiz="quiz-eth-intro-2" />
278271

279-
When you're ready to forge ahead, Part 3 introduces the next actor in the system: smart contracts.
272+
There's no limit to the number of accounts you can generate and you're free to use the same account for several apps or create a new account for every app. This is partly what is meant when a public blockchain is described as **permissionless**: there is no gatekeeper between you and the network. Don't wait for anyone to give you permission to build.
273+
274+
When you're ready to forge ahead, Part 3 more deeply introduces the next actor in the system: smart contracts.
280275

281276
import { ContributorFooter } from "../../../components/mdx/ContributorFooter";
282277

File renamed without changes.

src/pages/lessons/index.tsx

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,12 @@ import { useAppContext } from "@/contexts/AppContext";
1010
import { type Lesson } from "@/interfaces";
1111

1212
const LessonsPage: NextPageWithLayout = () => {
13-
const { projects, fundamentals, ethIntro } = useAppContext();
13+
const { projects, fundamentals } = useAppContext();
1414

1515
return (
1616
<Flex py={5} px={[4, 10, 16]} direction="column" minH="90vh">
1717
<Stack spacing={5} direction="column">
1818
<>
19-
<Box>
20-
<Heading size="lg" color="yellow.300">
21-
{`INTRO TO ETHEREUM`}
22-
</Heading>
23-
{ethIntro.map((lesson: Lesson, idx: number) => {
24-
return (
25-
<Box marginTop="4" key={idx}>
26-
<ContentBanner lesson={lesson} idx={idx} />
27-
</Box>
28-
);
29-
})}
30-
</Box>
3119
<Box>
3220
<Heading size="lg" color="yellow.300">
3321
{`PROJECTS`}

src/utils/quizzes/quiz-eth-intro-2.json

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,111 @@
8484
"correct": true
8585
}
8686
]
87+
},
88+
{
89+
"question": "What can you do with an account?",
90+
"options": [
91+
{
92+
"answer": "Deploy a smart contract",
93+
"correct": true
94+
},
95+
{
96+
"answer": "Send and receive ether",
97+
"correct": true
98+
},
99+
{
100+
"answer": "Interact with a smart contract",
101+
"correct": true
102+
},
103+
{
104+
"answer": "A password for your account",
105+
"correct": true
106+
},
107+
{
108+
"answer": "Sign transactions",
109+
"correct": true
110+
}
111+
]
112+
},
113+
{
114+
"question": "In a production environment, web3.py automatically signs and sends your transactions",
115+
"options": [
116+
{
117+
"answer": "True"
118+
},
119+
{
120+
"answer": "False",
121+
"correct": true
122+
}
123+
]
124+
},
125+
{
126+
"question": "What is a nonce?",
127+
"options": [
128+
{
129+
"answer": "The transaction count of an account",
130+
"correct": true
131+
},
132+
{
133+
"answer": "A transaction hash"
134+
},
135+
{
136+
"answer": "A block hash"
137+
},
138+
{
139+
"answer": "Random data added to a transaction"
140+
}
141+
]
142+
},
143+
{
144+
"question": "A transaction to deploy a new contract omits which value?",
145+
"options": [
146+
{
147+
"answer": "data"
148+
},
149+
{
150+
"answer": "from"
151+
},
152+
{
153+
"answer": "to",
154+
"correct": true
155+
},
156+
{
157+
"answer": "nonce"
158+
}
159+
]
160+
},
161+
{
162+
"question": "What is true of message signing?",
163+
"options": [
164+
{
165+
"answer": "The signer's private key is revealed"
166+
},
167+
{
168+
"answer": "No gas fee is required to sign a message",
169+
"correct": true
170+
},
171+
{
172+
"answer": "The address of the signer can later be proven",
173+
"correct": true
174+
},
175+
{
176+
"answer": "Message signing may be used to authenticate a user",
177+
"correct": true
178+
}
179+
]
180+
},
181+
{
182+
"question": "To build an Ethereum app, your entire technology stack must be open sourced",
183+
"options": [
184+
{
185+
"answer": "True"
186+
},
187+
{
188+
"answer": "False",
189+
"correct": true
190+
}
191+
]
87192
}
88193
]
89194
}

0 commit comments

Comments
 (0)