In this tutorial, we will learn how to perform CRUD (Create, Read, Update and Delete) operations in a Flutter Dapp on the Polygon network by creating a To-do app.
This is what the dApp we will be creating looks like:
To successfully follow along with this tutorial, you will need basic knowledge and understanding of Blockchain technology, the Solidity programming language for smart contracts, and the Flutter framework.
- Truffle - Truffle provides a local development environment for creating and testing blockchain applications.
- Flutter - used to create an Android/iOS dApp.
- A code editor or IDE - VSCode is recommended for Flutter development.
- Figment DataHub account - We will be using DataHub's Polygon RPC URL to deploy the smart contract.
If you don't have a DataHub account, you can create a free account and get the API key for Polygon from the dashboard.
We will be using web3dart to interact with the blockchain in our Flutter application. web3dart is an alternative to the commonly used web3js for the Flutter ecosystem.
Run the following commands to install the packages and create the project directories:
npm install -g trufflewill install Truffle globally so that you can use Truffle from any directory.
This is how the folder structure will be after initial setup:
truffle initcommand creates the following directories:
contracts: All the smart contracts are stored in this directory.
migrations: All the scripts used by Truffle to deploy smart contracts are stored in this directory.
test: All the test scripts for smart contracts are stored in this directory.
truffle-config.js: Contains configuration settings for Truffle.
Create a new file called
contractsdirectory and add the following code:
taskCountis an unsigned public integer that stores the total number of to-do items in the smart contract.
struct Taskis a data structure to store information (metadata) about each to-do. This includes the id of the to-do, taskName, and isComplete boolean value for the to-do.
mapping(uint256 => Task) public todos;is a mapping that stores all the to-dos, where the key is the
idand value is the
TaskDeletedare the events emitted on the blockchain that our dApp can listen for and function accordingly.
createTaskfunction will accept the
_taskNamefor the to-do. We can create a new
_taskName, and assign it to the current
taskCountvalue in the
taskCount's value by one for the next to-do.
- Once everything is done, we have to emit the
updateTaskfunction accepts a
_taskIdof a to-do to be updated along with an updated
taskName. We can create a new
Taskstruct with these values and assign it to the
todosmap corresponding to the
- Note that while updating, we have to retain the
isCompletevalue of that to-do. First, fetch the current task from the map, then store it in a variable, then use its
isCompletevalue for the new Task object.
- Once everything is done, we have to emit the
_taskof the to-do to be deleted as the parameter. First, remove the
Taskobject from the
todosmap corresponding to the
_taskreceived, then emit the
_taskIdof to-do to be updated. We first fetch the
Taskobject from the
todosmap and then create a new
Taskobject with those values, with
isCompleteset as the opposite of the current
That's all for the smart contract, and now we can move forward with the compilation and migration process.
Now that we have our smart contract written, it's time to compile it. Open your terminal in the
smartcontractdirectory and run the following command:
Truffle will compile the smart contract, and you should see the output similar to:
For the migration of our contact to the blockchain, go to the
migrationsdirectory, create a new file called
2_todo_contract_migration.jsand add the following code:
- Before starting with the migration process, make sure you have Ganache installed. Start the Ganache GUI app in your system.
- Delete all the existing contents of
truffle-config.jsand replace it with the code below.
truffle-config.js, we are defining the basic configuration for Truffle. Currently, we will be deploying the smart contract to localhost:7545 where our Ganache blockchain is running.
- To deploy the smart contract on Ganache, run the command:
This will deploy the contract to the Ganache development blockchain and will give you output that looks similar to this:
The smart contract is created and deployed; we can start integrating it with our Flutter application.
pubspec.yamlfile and add the following dependencies:
TodoContract.jsonfile as an asset in
pubspec.yaml, generated by the
To get started with UI and data controllers, we will have to create three files in the
TodoListModel.dart- Contains data model, contract functions and notifier class to update UI.
TodoList.dart- Contains the main UI of our app.
TodoBottomSheet.dart- Contains create and update todo form.
- On top, we are importing all the required packages.
- Creating a class
- Setting Ganache's
_wsUrlfor the local environment.
- Setting the private key of any account from Ganache (you can get this by clicking on the Key icon in the Ganache UI).
Web3Client _clientis used to connect to the Polygon blockchain with WebSockets.
String _abiCodeis used to store the ABI of our smart contract.
Credentials _credentialscontains the
Credentialobject of the logged-in user.
EthereumAddress _ownAddressis used to store the public key of the logged-in user.
DeployedContract _contractis an instance of our smart contract, which will be eventually used to communicate with the smart contract.
_toggleCompleteare the functions of our deployed smart contract.
After all the variable declarations, add the following functions in the
In the constructor of the
TodoListModelclass, we are calling the asynchronous
initfunction contains the initialization of
_clientobject followed by calling
getAbifunction, we are fetching the ABI of our smart contract and extracting the address of deployed contract. In the
getCredentialsfunction, we create an instance of the
Credentialsclass by passing in our private key.
Note - It's recommended to store the private key in encrypted form in Flutter. For the simplicity of this tutorial, we are keeping the private key in a string format.
getCredentialsfunction, we will create an instance of our smart contract using
_contractAddress. Once we have a contract instance, we can create an instance of all the functions we have in the smart contract, as shown above in the code.
Now that we have initialized all our variables, it's time to implement CRUD operations. In the
TodoListModeladd following functions:
getTodos, we call the
_taskCountfunction which gives us the total number of to-dos, and then we use a loop to fetch all to-do items and add them to a list. Once we have all the to-dos, we can set
isLoadingto false and call
Providerpackage to update our UI.
addTask, we accept the task name as a parameter, set
isLoadingto true, and then call the
_contractobject and passing
taskNameDataas a parameter.
idof the task and the updated
taskNameDatato make a transaction using our credentials to the smart contract. Notice that we are sending
idas an instance of
BigIntbecause the web3dart package requires all the numbers in
deleteTaskfunction will accept the
idof the task to be deleted and call the
_deleteTaskfunction of our contract to delete that particular task from the
todosmapping in the smart contract.
toggleCompletefunction will accept the
idof a task, and it will toggle the value of the
isCompleteboolean value in our smart contract. At the end of the
toggleCompletefunction we are calling
getTodosto fetch the updated list of todos to update the UI. Alternatively, you can also update the local to-do list before calling the smart contract function to show the result instantaneously and update the list in the background.
Taskmodel class in
TodoListModelto store the list of to-dos.
Now that we are done with the logic part in Flutter let's move forward and create the UI for our app.
Here we are creating a stateless widget,
TodoList. In the build function, we are listening to
TodoListModeland rendering the UI accordingly. If the
TodoListModelis true, we are rendering the Loading widget; else, we are creating a
ListViewand looping over the length of
TodoListModel. In the
ListView, we return a checkbox to toggle the
isCompletevalue of the to-do and a container with the task name. We are also creating a floating action button to add a new task to the to-do list.
- This is how our list of to-dos should look:
We are creating two functions,
showTodoBottomSheetshows a bottom sheet where users can create, update and delete a task, and
buildButtonis a typical widget that returns a specifically designed button.
showTodoBottomSheet, we are accepting an optional parameter
task, and based on the value of
task, we are rendering the bottom sheet UI. If the value of
taskis null, we are rending UI to create a new Todo task, and if the
taskis not null, we will render the update and delete UI. When the user taps on the floating action button, then we will call
taskvalue as null, and when the user taps on and task item from
ListView, we are calling
showTodoBottomSheetwith task value being the task object user tapped on.
Deletebuttons are pressed, we call the respective smart contract function from our
This is how the bottom sheet should look:
The last remaining part is calling the
main.dartto render our app.
We can publish our smart contract to Polygon Mumbai testnet by adding provider details of testnet in
- Connect your Metamask to Matic Mumbai testnet and get the Secret Recovery Phrase from the Metamask.
- Create a
.secretfile in the
smartcontractdirectory and paste your Secret Recovery Phrase in that file. Make sure you have added the
.secretfile in your
- NOTE - Deploying a smart contract requires paying gas fees, but since we are deploying to testnet, you can get 0.1 Matic token from [Matic Faucet](Matic Faucet) in your account.
Run the following command to install
hdwallet-providerto pay gas fees via your account.
Once you have everything set up correctly, delete the content of
truffle-config.jsand add the following code.
truffle-config.js, run the following command to deploy your smart contract on Polygon testnet.
Truffle will deploy the contract to Mumbai using your account from Metamask.
You can find the complete source code of this project on Github.
Congratulations on finishing the tutorial! Thank you for taking the time to complete it. In this tutorial, you have learned how to create a Flutter dApp from scratch using
web3dart. Since Flutter is a multi-platform framework and the web3dart package supports all the platforms - Android, iOS, Linux, macOS, Web, and Windows you can use the same codebase to build multi-platform dApps very quickly.
I'm Viral Sangani, a tech enthusiast working on blockchain projects & love the Web3 community. Feel free to connect with me on Github.