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:

i tried kiro and here is what i learned

I tried out Kiro: Here’s what I learned

Check out Kiro, AWS’s AI-powered IDE, see what makes it different from other AI coding tools, and explore whether it lives up to the hype.

Elijah Asaolu
Aug 28, 2025 ⋅ 5 min read
Go Design Pattern Article Image With Logo

Why Go design patterns still matter

Here’s how three design patterns solved our Go microservices scaling problems without sacrificing simplicity.

Peter Aideloje
Aug 28, 2025 ⋅ 2 min read
how to protect your ai agent from prompt injection attacks

How to protect your AI agent from prompt injection attacks

Explore six principled design patterns (with real-world examples) to help you protect your LLM agents from prompt injection attacks.

Rosario De Chiara
Aug 27, 2025 ⋅ 5 min read
Don’t Let AI Erase The Next Generation Of Dev Leaders

Don’t let AI erase the next generation of dev leaders

As AI tools take over more routine coding work, some companies are cutting early-career dev roles — a short-sighted move that could quietly erode the next generation of tech leaders if we aren’t careful.

Jack Herrington
Aug 26, 2025 ⋅ 6 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