Skip to content

Commit

Permalink
docs: add more comments around the create-fuels template app (#2772)
Browse files Browse the repository at this point in the history
* docs: add more comments around the `create-fuels` template app

* replicate changes to the counter example

* add changeset
  • Loading branch information
Dhaiwat10 committed Jul 19, 2024
1 parent 99794e4 commit f3e89d2
Show file tree
Hide file tree
Showing 31 changed files with 149 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/slow-moles-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-fuels": patch
---

docs: add more comments around the `create-fuels` template app
5 changes: 3 additions & 2 deletions apps/create-fuels-counter-guide/fuels.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ dotenv.config({
path: ['.env.local', '.env'],
});

// If your node is running on a port other than 4000, you can set it here
const fuelCorePort = +(process.env.NEXT_PUBLIC_FUEL_NODE_PORT as string) || 4000;

export default createConfig({
workspace: './sway-programs',
output: './src/sway-api',
workspace: './sway-programs', // Path to your Sway workspace
output: './src/sway-api', // Where your generated types will be saved
fuelCorePort,
providerUrl: NODE_URL,
});
Expand Down
3 changes: 3 additions & 0 deletions apps/create-fuels-counter-guide/src/app/faucet/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { useEffect, useState } from "react";
import toast from "react-hot-toast";

export default function Faucet() {
// Get the faucet wallet instance from the useFaucet hook
const { faucetWallet } = useFaucet();

const { wallet, refreshWalletBalance } = useActiveWallet();

const [receiverAddress, setReceiverAddress] = useState<string>("");
Expand All @@ -34,6 +36,7 @@ export default function Faucet() {
return toast.error("Amount cannot be empty");
}

// Transfer the specified amount of ETH to the receiver address
const tx = await faucetWallet.transfer(
receiverAddress,
bn.parseUnits(amountToSend.toString()),
Expand Down
15 changes: 15 additions & 0 deletions apps/create-fuels-counter-guide/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import {
import { NODE_URL } from "@/lib";
import { ActiveWalletProvider } from "@/hooks/useActiveWallet";

/**
* react-query is a peer dependency of @fuels/react, so we set it up here.
* See https://docs.fuel.network/docs/wallet/dev/getting-started/#installation-1
*/
const queryClient = new QueryClient();

interface RootLayoutProps {
Expand All @@ -25,12 +29,18 @@ interface RootLayoutProps {

export default function RootLayout({ children }: RootLayoutProps) {
const [isMounted, setIsMounted] = useState(false);

/**
* Create a Provider instance.
* We memoize it to avoid creating a new instance on every render.
*/
const providerToUse = useMemo(() => Provider.create(NODE_URL), [NODE_URL]);

useEffect(() => {
setIsMounted(true);
}, []);

// Only render the component if the page has been mounted.
if (!isMounted) return null;

return (
Expand All @@ -40,6 +50,11 @@ export default function RootLayout({ children }: RootLayoutProps) {
<QueryClientProvider client={queryClient}>
<FuelProvider
fuelConfig={{
/**
* The list of wallet connectors.
* You can add or remove connectors from here based on your needs.
* See https://wallet.fuel.network/docs/dev/connectors/
*/
connectors: [
new FuelWalletConnector(),
new BurnerWalletConnector({
Expand Down
6 changes: 6 additions & 0 deletions apps/create-fuels-counter-guide/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ export default function Home() {
*/
useAsync(async () => {
if (wallet) {
// Create a new instance of the contract
const testContract = TestContractAbi__factory.connect(contractId, wallet);
setContract(testContract);

// Read the current value of the counter
const { value } = await testContract.functions.get_count().get();
setCounter(value.toNumber());
}
Expand All @@ -50,7 +53,10 @@ export default function Home() {
);
}

// Call the increment_counter function on the contract
const { waitForResult } = await contract.functions.increment_counter(bn(1)).call();

// Wait for the transaction to be mined, and then read the value returned
const { value } = await waitForResult();
setCounter(value.toNumber());

Expand Down
7 changes: 7 additions & 0 deletions apps/create-fuels-counter-guide/src/app/predicate/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default function PredicateExample() {
useAsync(async () => {
if (wallet) {
baseAssetId = wallet.provider.getBaseAssetId();
// Initialize a new predicate instance
const predicate = TestPredicateAbi__factory.createInstance(
wallet.provider,
);
Expand Down Expand Up @@ -63,6 +64,7 @@ export default function PredicateExample() {
return toast.error("Wallet not loaded");
}

// Initialize a new predicate instance with the entered pin
const reInitializePredicate = TestPredicateAbi__factory.createInstance(
wallet.provider,
[bn(pin)],
Expand All @@ -72,6 +74,11 @@ export default function PredicateExample() {
return toast.error("Failed to initialize predicate");
}

/*
Try to 'unlock' the predicate and transfer the funds back to the wallet.
If the pin is correct, this transfer transaction will succeed.
If the pin is incorrect, this transaction will fail.
*/
const tx = await reInitializePredicate.transfer(
wallet.address,
amount,
Expand Down
5 changes: 4 additions & 1 deletion apps/create-fuels-counter-guide/src/app/script/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default function ScriptExample() {

useAsync(async () => {
if (wallet) {
// Initialize script instance
const script = TestScriptAbi__factory.createInstance(wallet);
setScript(script);
}
Expand All @@ -31,7 +32,9 @@ export default function ScriptExample() {
return toast.error("Script not loaded");
}

const { value } = await script.functions.main(bn(input)).call();
// Call the script with the input value
const { waitForResult } = await script.functions.main(bn(input)).call();
const { value } = await waitForResult();

setResult(value.toString());
} catch (error) {
Expand Down
5 changes: 5 additions & 0 deletions apps/create-fuels-counter-guide/src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export const Layout = ({ children }: { children: React.ReactNode }) => {
return console.error("Unable to topup wallet because wallet is not set.");
}

/**
* If the current environment is local, transfer 5 ETH to the wallet
* from the local faucet wallet
*/
if (CURRENT_ENVIRONMENT === "local") {
if (!faucetWallet) {
return toast.error("Faucet wallet not found.");
Expand All @@ -45,6 +49,7 @@ export const Layout = ({ children }: { children: React.ReactNode }) => {
return await refreshWalletBalance?.();
}

// If the current environment is testnet, open the testnet faucet link in a new tab
if (CURRENT_ENVIRONMENT === "testnet") {
return window.open(
`${TESTNET_FAUCET_LINK}?address=${wallet.address.toAddress()}`,
Expand Down
3 changes: 3 additions & 0 deletions apps/create-fuels-counter-guide/src/hooks/useActiveWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { AppWallet } from "@/lib";
/**
* burner -> a burner wallet embedded inside of the template app and stored in local storage
* browser -> a wallet connected via a browser extension like the Fuel Wallet
*
* Whenever a browser wallet is connected, this hook will return an instance of the browser wallet.
* Otherwise, it will return an instance of a local burner wallet.
*/
type WalletTypes = "burner" | "browser";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ interface BrowserWallet extends AppWallet {
network: any;
}

/**
* This hook returns an instance of the browser wallet connected via
* any of the supported connectors.
**/
export const useBrowserWallet: () => BrowserWallet = () => {
const { wallet } = useWallet();
const [browserWalletBalance, setBrowserWalletBalance] = useState<BN>();
Expand Down
3 changes: 3 additions & 0 deletions apps/create-fuels-counter-guide/src/hooks/useBurnerWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import useAsync from "react-use/lib/useAsync";

const BURNER_WALLET_LOCAL_STORAGE_KEY = "create-fuels-burner-wallet-pk";

/**
* This hook returns an instance of a burner wallet that lives in local storage.
*/
export const useBurnerWallet: () => AppWallet = () => {
const [burnerWallet, setBurnerWallet] = useState<WalletUnlocked>();
const [burnerWalletBalance, setBurnerWalletBalance] = useState<BN>();
Expand Down
4 changes: 4 additions & 0 deletions apps/create-fuels-counter-guide/src/hooks/useFaucet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { Provider, Wallet, WalletUnlocked } from "fuels";
import { useState } from "react";
import useAsync from "react-use/lib/useAsync";

/**
* This hook returns an instance of a faucet wallet.
* The value of `FAUCET_PRIVATE_KEY` depends on your chain config.
*/
export const useFaucet = () => {
const [faucetWallet, setFaucetWallet] = useState<WalletUnlocked>();

Expand Down
7 changes: 7 additions & 0 deletions apps/create-fuels-counter-guide/src/lib.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import { Account, BN, TESTNET_NETWORK_URL } from 'fuels';

// #region deploying-dapp-to-testnet-lib-current-environment
// The two environments for the dapp are local and testnet.
export const Environments = {
LOCAL: 'local',
TESTNET: 'testnet',
} as const;
type Environment = (typeof Environments)[keyof typeof Environments];

/**
* The current environment is determined by the
* `NEXT_PUBLIC_DAPP_ENVIRONMENT` environment variable.
* If it's not set, the default is `local`.
*/
export const CURRENT_ENVIRONMENT: Environment =
(process.env.NEXT_PUBLIC_DAPP_ENVIRONMENT as Environment) || Environments.LOCAL;
// #endregion deploying-dapp-to-testnet-lib-current-environment

// The node URL is determined by the current environment too.
export const NODE_URL =
CURRENT_ENVIRONMENT === Environments.LOCAL
? `http://127.0.0.1:${process.env.NEXT_PUBLIC_FUEL_NODE_PORT || 4000}/v1/graphql`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
contract;

// #region create-fuels-counter-guide-abi
// The abi defines the blueprint for the contract.
abi Counter {
#[storage(read)]
fn get_count() -> u64;
Expand All @@ -13,24 +14,29 @@ abi Counter {
}
// #endregion create-fuels-counter-guide-abi

/// The storage variables for the contract.
/// In this case, there is only one variable called `counter` which is initialized to 0.
storage {
counter: u64 = 0,
}

// #region create-fuels-counter-guide-impl
impl Counter for Contract {
// The `get_count` function returns the current value of the counter.
#[storage(read)]
fn get_count() -> u64 {
storage.counter.read()
}

// The `increment_counter` function increments the counter by the given amount.
#[storage(write, read)]
fn increment_counter(amount: u64) -> u64 {
let current = storage.counter.read();
storage.counter.write(current + amount);
storage.counter.read()
}

// The `decrement_counter` function decrements the counter by the given amount.
#[storage(read, write)]
fn decrement_counter(amount: u64) -> u64 {
let current = storage.counter.read();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ configurable {
PIN: u64 = 1337,
}

/// This is a predicate that checks if the given pin is correct.
/// If it is, the predicate is 'unlocked' and the transaction is allowed to proceed.
/// Otherwise, it is reverted.
fn main(pin: u64) -> bool {
return PIN == pin;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
script;

// This script simply returns the input value.
fn main(input: u64) -> u64 {
return input;
}
5 changes: 3 additions & 2 deletions templates/nextjs/fuels.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ dotenv.config({
path: ['.env.local', '.env'],
});

// If your node is running on a port other than 4000, you can set it here
const fuelCorePort = +(process.env.NEXT_PUBLIC_FUEL_NODE_PORT as string) || 4000;

export default createConfig({
workspace: './sway-programs',
output: './src/sway-api',
workspace: './sway-programs', // Path to your Sway workspace
output: './src/sway-api', // Where your generated types will be saved
fuelCorePort,
providerUrl: NODE_URL,
forcPath: 'fuels-forc',
Expand Down
3 changes: 3 additions & 0 deletions templates/nextjs/src/app/faucet/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { useEffect, useState } from "react";
import toast from "react-hot-toast";

export default function Faucet() {
// Get the faucet wallet instance from the useFaucet hook
const { faucetWallet } = useFaucet();

const { wallet, refreshWalletBalance } = useActiveWallet();

const [receiverAddress, setReceiverAddress] = useState<string>("");
Expand All @@ -34,6 +36,7 @@ export default function Faucet() {
return toast.error("Amount cannot be empty");
}

// Transfer the specified amount of ETH to the receiver address
const tx = await faucetWallet.transfer(
receiverAddress,
bn.parseUnits(amountToSend.toString()),
Expand Down
15 changes: 15 additions & 0 deletions templates/nextjs/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import {
import { NODE_URL } from "@/lib";
import { ActiveWalletProvider } from "@/hooks/useActiveWallet";

/**
* react-query is a peer dependency of @fuels/react, so we set it up here.
* See https://docs.fuel.network/docs/wallet/dev/getting-started/#installation-1
*/
const queryClient = new QueryClient();

interface RootLayoutProps {
Expand All @@ -25,12 +29,18 @@ interface RootLayoutProps {

export default function RootLayout({ children }: RootLayoutProps) {
const [isMounted, setIsMounted] = useState(false);

/**
* Create a Provider instance.
* We memoize it to avoid creating a new instance on every render.
*/
const providerToUse = useMemo(() => Provider.create(NODE_URL), [NODE_URL]);

useEffect(() => {
setIsMounted(true);
}, []);

// Only render the component if the page has been mounted.
if (!isMounted) return null;

return (
Expand All @@ -40,6 +50,11 @@ export default function RootLayout({ children }: RootLayoutProps) {
<QueryClientProvider client={queryClient}>
<FuelProvider
fuelConfig={{
/**
* The list of wallet connectors.
* You can add or remove connectors from here based on your needs.
* See https://wallet.fuel.network/docs/dev/connectors/
*/
connectors: [
new FuelWalletConnector(),
new BurnerWalletConnector({
Expand Down
5 changes: 5 additions & 0 deletions templates/nextjs/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ export default function Home() {
*/
useAsync(async () => {
if (wallet) {
// Create a new instance of the contract
const testContract = TestContractAbi__factory.connect(contractId, wallet);
setContract(testContract);

// Read the current value of the counter
const { value } = await testContract.functions.get_count().get();
setCounter(value.toNumber());
}
Expand All @@ -48,10 +51,12 @@ export default function Home() {
);
}

// Call the increment_counter function on the contract
const { waitForResult } = await contract.functions
.increment_counter(bn(1))
.call();

// Wait for the transaction to be mined, and then read the value returned
const { value } = await waitForResult();

setCounter(value.toNumber());
Expand Down
Loading

0 comments on commit f3e89d2

Please sign in to comment.