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 use the Next.js Image component to optimize images

How to use the Next.js Image component to optimize images

Explore automatic image optimization using Next Image, the built-in image optimization solution for Next.js.

Adebiyi Adedotun
Apr 23, 2025 ⋅ 7 min read

The right way to implement AI into your frontend development workflow

Discover how to integrate frontend AI tools for faster, more efficient development without sacrificing quality.

Wisdom Ekpotu
Apr 23, 2025 ⋅ 5 min read
React Hook Form Vs. React 19: Should You Still Use RHF In 2025?

React Hook Form vs. React 19: Should you still use RHF in 2025?

Is React Hook Form still worth using? In this guide, you will learn the differences, advantages, and best use cases of React Hook Form.

Vijit Ail
Apr 23, 2025 ⋅ 20 min read
deploying react apps to github pages

How to deploy React apps to GitHub Pages

Walk through the process of deploying a Create React App project to GitHub Pages, customizing your domain, and automating deployments with GitHub Actions.

Nelson Michael
Apr 22, 2025 ⋅ 10 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