2021-12-22
1963
#blockchain#flutter
Eshiet Ekemini
82978
Dec 22, 2021 ⋅ 7 min read

Building your first DApp with Flutter and Solidity

Eshiet Ekemini A graduate of University of Uyo and a tech enthusiast, Ekemini has been building for mobile for two years, with a particular focus on Kotlin and Flutter.

Recent posts:

How to build agentic AI when your data can’t leave the network

Large hosted LLMs aren’t always an option. Learn how to build agentic AI with small, local models that preserve privacy and scale.

Rosario De Chiara
Dec 23, 2025 ⋅ 5 min read
frontend wrapped top stories of 2025

Frontend Wrapped 2025: The 10 storylines that defined the year

What storylines defined 2025 in frontend development? We power rank them all, from AI advancements to supply chain attacks and framework breakthroughs.

Chizaram Ken
Dec 23, 2025 ⋅ 6 min read
Getting Started With NativeWind: Tailwind For React Native

Getting started with NativeWind: Tailwind for React Native

Learn how to style React Native apps with Tailwind using NativeWind v4.

Chinwike Maduabuchi
Dec 22, 2025 ⋅ 14 min read
The 10 Best React Native Component Libraries You Should Know

The 10 best React Native UI libraries of 2026

A practical guide to the best React Native UI libraries in 2026, with comparisons across performance, theming, accessibility, and Expo compatibility.

Aman Mittal
Dec 22, 2025 ⋅ 12 min read
View all posts

7 Replies to "Building your first DApp with Flutter and Solidity"

  1. Hi! Very good article!
    i have an app flutter Voting and writed smart contract but not connect and not show input smart counteract
    class ResultScreen extends StatelessWidget {
    final Map votes;
    final VotingService votingService = VotingService(); // ایجاد نمونه از کلاس VotingService

    ResultScreen({required this.votes});

    @override
    Widget build(BuildContext context) {
    return Scaffold(
    appBar: AppBar(
    title: Text(
    ‘Show Result’,
    style: TextStyle(fontSize: 30, fontWeight: FontWeight.w600),
    ),
    backgroundColor: Colors.deepPurple,
    ),
    body: Stack(
    children: [
    // Background image
    Container(
    decoration: BoxDecoration(
    image: DecorationImage(
    image: AssetImage(‘assets/image/5908835613371647683.jpg’),
    fit: BoxFit.cover,
    ),
    ),
    ),
    // FutureBuilder برای نمایش لیست کاندیداها
    FutureBuilder<List>(
    future: votingService.getCandidateNames(), // فراخوانی تابع دریافت اسامی از نمونه votingService
    builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
    return Center(
    child: CircularProgressIndicator()); // نمایش در حال بارگذاری
    } else if (snapshot.hasError) {
    return Center(child: Text(‘Error: ${snapshot.error}’,style: TextStyle(color: Colors.amber),));
    } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
    return Center(child: Text(‘No candidates found’));
    } else {
    // نمایش کاندیداها
    final candidates = snapshot.data!;
    return ListView.builder(
    itemCount: candidates.length,
    itemBuilder: (context, index) {
    final candidateName = candidates[index];
    return ListTile(
    title: Text(
    candidateName,
    style: TextStyle(
    fontSize: 22,
    color: Colors.cyanAccent,
    fontWeight: FontWeight.bold,
    ),
    ),
    trailing: ElevatedButton(
    onPressed: () {
    votingService.vote(index); // رای به کاندیدا با استفاده از instance votingService
    },
    child: Text(‘Vote’),
    ),
    );
    },
    );
    }
    },
    ),
    ],
    ),
    );
    }
    }

    class VotingService {

    final String rpcUrl =
    ‘https://api.polygonscan.com/api?module=account&action=balance&address=&apikey=’;
    final String contractAddress =
    ‘–‘; // آدرس قرارداد
    final String abi = ”'[
    {
    “inputs”: [],
    “name”: “endVoting”,
    “outputs”: [],
    “stateMutability”: “nonpayable”,
    “type”: “function”
    },
    {
    “inputs”: [
    {
    “internalType”: “uint256”,
    “name”: “durationInMinutes”,
    “type”: “uint256”
    },
    {
    “internalType”: “string[]”,
    “name”: “proposalNames”,
    “type”: “string[]”
    }
    ],
    “stateMutability”: “nonpayable”,
    “type”: “constructor”
    },
    {
    “inputs”: [
    {
    “internalType”: “uint256”,
    “name”: “proposalId”,
    “type”: “uint256”
    }
    ],
    “name”: “vote”,
    “outputs”: [],
    “stateMutability”: “nonpayable”,
    “type”: “function”
    },
    {
    “anonymous”: false,
    “inputs”: [
    {
    “indexed”: false,
    “internalType”: “address”,
    “name”: “voter”,
    “type”: “address”
    },
    {
    “indexed”: false,
    “internalType”: “uint256”,
    “name”: “proposalId”,
    “type”: “uint256”
    }
    ],
    “name”: “VoteCasted”,
    “type”: “event”
    },
    {
    “anonymous”: false,
    “inputs”: [
    {
    “indexed”: false,
    “internalType”: “uint256”,
    “name”: “endTime”,
    “type”: “uint256”
    }
    ],
    “name”: “VotingEnded”,
    “type”: “event”
    },
    {
    “inputs”: [],
    “name”: “getResults”,
    “outputs”: [
    {
    “components”: [
    {
    “internalType”: “string”,
    “name”: “name”,
    “type”: “string”
    },
    {
    “internalType”: “uint256”,
    “name”: “voteCount”,
    “type”: “uint256”
    }
    ],
    “internalType”: “struct TimedVoting.Proposal[]”,
    “name”: “”,
    “type”: “tuple[]”
    }
    ],
    “stateMutability”: “view”,
    “type”: “function”
    },
    {
    “inputs”: [
    {
    “internalType”: “address”,
    “name”: “”,
    “type”: “address”
    }
    ],
    “name”: “hasVoted”,
    “outputs”: [
    {
    “internalType”: “bool”,
    “name”: “”,
    “type”: “bool”
    }
    ],
    “stateMutability”: “view”,
    “type”: “function”
    },
    {
    “inputs”: [
    {
    “internalType”: “uint256”,
    “name”: “”,
    “type”: “uint256”
    }
    ],
    “name”: “proposals”,
    “outputs”: [
    {
    “internalType”: “string”,
    “name”: “name”,
    “type”: “string”
    },
    {
    “internalType”: “uint256”,
    “name”: “voteCount”,
    “type”: “uint256”
    }
    ],
    “stateMutability”: “view”,
    “type”: “function”
    },
    {
    “inputs”: [],
    “name”: “totalVotes”,
    “outputs”: [
    {
    “internalType”: “uint256”,
    “name”: “”,
    “type”: “uint256”
    }
    ],
    “stateMutability”: “view”,
    “type”: “function”
    },
    {
    “inputs”: [],
    “name”: “votingEndTime”,
    “outputs”: [
    {
    “internalType”: “uint256”,
    “name”: “”,
    “type”: “uint256”
    }
    ],
    “stateMutability”: “view”,
    “type”: “function”
    },
    {
    “inputs”: [],
    “name”: “votingStarted”,
    “outputs”: [
    {
    “internalType”: “bool”,
    “name”: “”,
    “type”: “bool”
    }
    ],
    “stateMutability”: “view”,
    “type”: “function”
    }
    ]”’; // ABI قرارداد به صورت JSON
    final String privateKey =
    “–“; // کلید خصوصی
    late Web3Client _client;
    late DeployedContract _contract;
    late ContractFunction _voteFunction;
    late ContractFunction _getResultsFunction;
    late ContractFunction _endVotingFunction;
    late Credentials _credentials;

    VotingService() {
    _client = Web3Client(rpcUrl, Client());
    _loadCredentials(); // بارگذاری اطلاعات قرارداد و توابع
    }

    Future _loadCredentials() async {

    _credentials = await _client.credentialsFromPrivateKey(privateKey);

    //// تبدیل رشته JSON به لیست داینامیک
    // final List abiJson = jsonDecode(abi);

    // تبدیل رشته JSON به لیست داینامیک
    final abiJson = jsonDecode(abi) as List;
    // ایجاد شیء DeployedContract با استفاده از ABI و آدرس قرارداد
    _contract = DeployedContract(
    ContractAbi.fromJson(jsonEncode(abiJson).toString(), ‘TimedVoting’),_contract as EthereumAddress);
    EthereumAddress.fromHex(contractAddress);

    // بارگذاری توابع قرارداد
    _voteFunction = _contract.function(‘vote’);
    _getResultsFunction = _contract.function(‘getResults’);
    _endVotingFunction = _contract.function(‘endVoting’);
    }
    Future someFunction() async {
    final function = _contract.function(‘vote’);
    await _client.sendTransaction(
    _credentials,
    Transaction.callContract(
    contract: _contract,
    function: function,
    parameters: [/* parameters here */],
    ),
    );
    }
    Future vote(int option) async {
    final result = await _client.sendTransaction(
    _credentials,
    Transaction.callContract(
    contract: _contract,
    function: _voteFunction,
    parameters: [BigInt.from(option)],
    ),
    chainId: 1,
    );
    return result;
    }

    Future<List> getCandidateNames() async {
    final results = await _client.call(
    contract: _contract,
    function: _getResultsFunction,
    params: [],
    );

    List candidates = [];
    for (var result in results[0]) {
    candidates.add(result[‘name’]);
    }
    return candidates;
    }

    Future<List> getResults() async {
    final result = await _client.call(
    contract: _contract,
    function: _getResultsFunction,
    params: [],
    );
    return result[0] as List;
    }

    Future endVoting() async {
    await _client.sendTransaction(
    _credentials,
    Transaction.callContract(
    contract: _contract,
    function: _endVotingFunction,
    parameters: [],
    ),
    chainId: 1,
    );
    }
    }flutter code and solidity code contract TimedVoting {
    uint256 public votingEndTime;
    bool public votingStarted = false;

    struct Proposal {
    string name;
    uint256 voteCount;
    }

    event VotingEnded(uint256 endTime);

    Proposal[] public proposals;
    mapping(address => bool) public hasVoted;
    uint256 public totalVotes;

    // Event to notify about new votes
    event VoteCasted(address voter, uint256 proposalId);

    // Constructor to initialize voting with proposals
    constructor(uint256 durationInMinutes, string[] memory proposalNames) {
    require(!votingStarted, “Voting already started”);
    votingEndTime = block.timestamp + durationInMinutes * 1 minutes;
    votingStarted = true;

    for (uint256 i = 0; i < proposalNames.length; i++) {
    proposals.push(Proposal({
    name: proposalNames[i],
    voteCount: 0
    }));
    }
    }

    // Vote for a proposal
    function vote(uint256 proposalId) public {
    require(votingStarted, "Voting has not started yet");
    require(block.timestamp < votingEndTime, "Voting period has ended");
    require(!hasVoted[msg.sender], "You have already voted");
    require(proposalId < proposals.length, "Invalid proposal ID");

    hasVoted[msg.sender] = true;
    proposals[proposalId].voteCount += 1;
    totalVotes += 1;

    emit VoteCasted(msg.sender, proposalId);
    }

    // End the voting period manually
    function endVoting() public {
    require(votingStarted, "Voting has not started yet");
    require(block.timestamp = votingEndTime, “Voting period has not ended yet”);
    return proposals;
    }
    }

Leave a Reply

Hey there, want to help make our blog better?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now