'Why is a transaction consuming gas for a public view function?

I deployed the following smart contract on Ropsten ethereum test network and afterwards I tried making a transaction using @alch/alchemy-web3 npm package (Yes, I am using Alchemy API) but as you can see I got a fee on the transaction. Why is that? Aren't public view function calls supposed to cost 0 gas?

deployed smart contract

// SPDX-Lincense-Identifier: MIT
pragma solidity ^0.8.11;

contract VendingMachine {
    address public owner;
    mapping(address => uint256) public donutBalances;

    constructor() {
        owner = msg.sender;
        donutBalances[address(this)] = 100;
    }

    function getVendingMachineBalance() public view returns (uint256) {
        return donutBalances[address(this)];
    }

    function restock(uint amount) public {
        require(msg.sender == owner, "Only the owner can restock this machine.");
        donutBalances[address(this)] += amount;
    }

    function purchase(uint amount) public payable {
        require(msg.sender == owner, "Only the owner can restock this machine.");
        require(donutBalances[address(this)] >= amount, "Not enough donuts in stock to fulfill purchase request.");
        require(msg.value >= amount*2 ether, "You must pay at least 2 ether / donut.");
        donutBalances[address(this)] -= amount;
        donutBalances[msg.sender] += amount;
    }  
}

transaction code javascript

    const { API_URL, METAMASK_ACCOUNT_PRIVATE_KEY, METAMASK_ACCOUNT_PUBLIC_KEY } = process.env;
    const { createAlchemyWeb3 } = require("@alch/alchemy-web3");
    const web3 = createAlchemyWeb3(`${API_URL}`);

    const contractAddress = '0xc7E286A86e4c5b8F7d52fA3F4Fe7D9DE6601b6F9'
    const contractAPI = new web3.eth.Contract(contract.abi, contractAddress)

    const nonce = await web3.eth.getTransactionCount(METAMASK_ACCOUNT_PUBLIC_KEY, 'latest');

    const transaction = {
        to: contractAddress, // faucet address to return eth
        gas: 500000,
        nonce: nonce,
        data: contractAPI.methods.getVendingMachineBalance().encodeABI()
        // optional data field to send message or execute smart contract
    };

    const signedTx = await web3.eth.accounts.signTransaction(transaction, METAMASK_ACCOUNT_PRIVATE_KEY)

    web3.eth.sendSignedTransaction(signedTx.rawTransaction, function (error, hash) {
        if (!error) {
            console.log("🎉 The hash of your transaction is: ", hash, "\n Check Alchemy's Mempool to view the status of your transaction!");
        } else {
            console.log("❗Something went wrong while submitting your transaction:", error)
        }
    });

Transaction: https://ropsten.etherscan.io/tx/0x8ce3a288072809a804adac2206dc566dfb3eb3ddba3330bcb52ca6be71963b71



Solution 1:[1]

There are two ways to interact with a smart contract. A transaction (read-write, costs gas fees) and a call (read-only, gas free).

Your JS snippet sends a transaction. If you want to invoke the getVendingMachineBalance() function using a (gas free) call, you can use the .call() web3js method.

const contractAPI = new web3.eth.Contract(contract.abi, contractAddress);
const response = await contractAPI.methods.getVendingMachineBalance().call();

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Petr Hejda