Skip to content

Working with Predicates

This guide builds on the Creating a Fuel dApp guide. Once you've gotten the dApp there up and running, then you can continue here via clicking the Predicate Example link. We will modify the predicate we created in the previous guide. The final result will look like this:

End result of this guide

Adding a Configurable pin

The current predicate functionality we have is a simple one that checks if the user has a pin. We will modify this predicate to accept a configurable pin. This will allow the user to set their own pin.

  1. Modifying the Predicate Contract

The first step is to modify the predicate contract to accept a configurable pin. We will use the configurable keyword to create an updatable constant to store the pin. We will also modify the main function to check this constant instead of a hardcoded pin.

rust
predicate;

configurable {
    PIN: u64 = 1337,
}

fn main(pin: u64) -> bool {
    return PIN == pin;
}
See code in context
  1. Modifying the Frontend

We will now add new button to the frontend that will update the pin in the predicate when clicked. To do this, we will modify the ./src/pages/predicate.tsx file.

We will add a function called changePin, which will use the current pin in state to update the pin in the predicate as well as transfer 1000 to the predicate.

ts
const changePin = async () => {
  if (!wallet) {
    return toast.error("Wallet not loaded");
  }
  if (!predicate) {
    return toast.error("Predicate not loaded");
  }

  if (walletBalance?.eq(0)) {
    return toast.error(
      "Your wallet does not have enough funds. Please click the 'Top-up Wallet' button in the top right corner, or use the local faucet."
    );
  }

  if (!pin) {
    return toast.error("Please enter a pin");
  }

  const configurable = { PIN: bn(pin) };
  // instantiate predicate with configurable constants
  const reInitializePredicate = TestPredicateAbi__factory.createInstance(wallet.provider, [bn(configurable.PIN)], configurable);

  if (!reInitializePredicate) {
    return toast.error("Failed to initialize predicate");
  }

  // transferring funds to the predicate
  const tx = await wallet.transfer(reInitializePredicate.address, 1000, baseAssetId, {
    gasLimit: 10_000,
  });

  const { isStatusSuccess } = await tx.wait();

  if (!isStatusSuccess) {
    toast.error("Failed to update pin in  predicate");
    return;
  }

  if (isStatusSuccess) {
    toast.success("Predicate pin updated");
  }

  await refreshWalletBalance?.();
};
See code in context

It would also be useful to change the placeholder text to say "Enter a new pin" instead of "Hint - the correct pin is 1337".

tsx
<Input
  className="w-[300px] mt-8"
  value={pin as string}
  onChange={(e) => setPin(e.target.value)}
  placeholder="Enter a new pin"
/>

Finally, we will add a button that calls the changePin function when clicked.

tsx
<Button onClick={changePin}>Change Pin</Button>

Congratulations! That's all. You should now be able to see the modified predicate dApp running at http://localhost:3000 with our newly added change pin functionality.

You can find the complete source code of the dApp we built here.

Next Steps

  • Now that you have a predicate dApp running and have the npm create fuels workflow powering you, you can start building more complex dApps using the Fuel Stack. A good place to start for ideas and reference code is the Sway Applications Repo.

  • If you have any questions or need help, feel free to reach out to us on the Official Fuel Forum.

  • If you want to learn more about the Fuel Stack, check out the Fuel Docs.