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 fix React routing loopholes with the React Router Middleware

How to fix React routing loopholes with the React Router Middleware

Learn how React Router’s Middleware API fixes leaky redirects and redundant data fetching in protected routes.

Ikeh Akinyemi
Nov 13, 2025 ⋅ 3 min read
How I used Mastra to build a prize-winning RAG agent

How I used Mastra to build a prize-winning RAG agent

A developer’s retrospective on creating an AI video transcription agent with Mastra, an open-source TypeScript framework for building AI agents.

Chinwike Maduabuchi
Nov 13, 2025 ⋅ 12 min read

Ensuring frontend data integrity with TanStack DB transactions

Learn how TanStack DB transactions ensure data consistency on the frontend with atomic updates, rollbacks, and optimistic UI in a simple order manager app.

Emmanuel John
Nov 13, 2025 ⋅ 11 min read
the replay november 12

The Replay (11/12/25): Stop making these useEffect mistakes

Discover what’s new in The Replay, LogRocket’s newsletter for dev and engineering leaders, in the November 5th issue.

Matt MacCormack
Nov 12, 2025 ⋅ 33 sec 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

Would you be interested in joining LogRocket's developer community?

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