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:

Wasm 3 Before GTA 6 LogRocket Article

We got Wasm 3.0 before GTA 6: Meet the web’s new engine

Discover how WebAssembly 3.0’s garbage collector, exception handling, and Memory64 transform Wasm into a true mainstream web platform.

Ikeh Akinyemi
Oct 3, 2025 ⋅ 2 min read

How to use AI to build accurate ShadCN components

AI agents often break shadcn/ui components with outdated docs or made-up props. The MCP server fixes this by giving live access to registries. In this tutorial, we’ll set it up and build a Kanban board to show it in action.

Chizaram Ken
Oct 3, 2025 ⋅ 5 min read
Rust Project for Web Services LogRocket Article

The best way to structure Rust web services

Learn how to structure Rust web services with clean architecture, Cargo workspaces, and modular crates for scalable, maintainable backends.

Jude Miracle
Oct 2, 2025 ⋅ 2 min read
andrew evans headshot

A spec-first workflow for building with agentic AI

Andrew Evans gives his take on agentic AI and walks through a step-by-step method to build a spec-first workflow using Claude Code.

Andrew Evans
Oct 1, 2025 ⋅ 18 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