Hedera browser app: Can execute but cannot query contract functions

184 views Asked by At

I am developing a dApp on Hedera where the user connects via Hedera wallet (I am using HashPack for this) and am using the HashConnect library to setup the connection.

Deploying a contract through the browser works, executing a function from the contract works, but querying I cannot get to work. The thing I find strange is that all functionality of the Hedera SDK as far as I use utilizes the signer from the hashconnect login to execute transactions, but calling a contract does not. It only has the function execute that expect a client as a parameter (see docs), and this client can only be instantiated when I have a private key. But I of course do not have direct access to the user's private key. (btw, there is a 'privatekey' property that I get from hashconnect, but it's just a UUID. And also the publickey property is a UUID. I don't understand why those are set and can't find anything about that in their documentation.)

The functions of my contract being irrelevant (the call does not even reach the contract, it errors client side) I won't mention the contract itself;

Execute contract (works)

const provider = hashconnect.getProvider("testnet", topic, accountId);
const signer = hashconnect.getSigner(provider);
const tx = await new ContractExecuteTransaction()
                .setContractId(contractId)
                .setGas(3000000)
                .setFunction('somefunction', new ContractFunctionParameters().addString("Bob").addUint256(12345))
                .freezeWithSigner(signer);
const sign = await tx.signWithSigner(signer);
submit = await sign.executeWithSigner(signer);

Call contract (doesn't work without actually providing a private key)

const provider = hashconnect.getProvider("testnet", topic, accountId);
const signer = hashconnect.getSigner(provider);
tx = new ContractCallQuery()
                .setContractId(contractId)
                .setGas(100000)
                .setFunction('somefunction', new ContractFunctionParameters().addString("Bob"));
const operatorId = AccountId.fromString('0.0.12345');
const operatorKey = PrivateKey.fromString('4e30e4.......................................d6fa');
const client = Client.forTestnet().setOperator(operatorId, operatorKey);
submit = await tx.execute(client);

So the above code works only with access to the user's private key. But I want to run the call just as everything else through the wallet connection. How do I do that? Do I really need to instantiate a 'client' for it or is there another way that is according to the format of the other transaction methods?
I also saw there's another way to instantiate a client with function setOperatorWith but it seems that one also needs a private key as input. Although I must say I can't be completely certain as I find the Hedera docs vague and the hashconnect object even more vague ('private' and 'public' keys are used as property names for the same values and mixed back and forth while not even containing private or public keys as values; they're UUIDs...)

1

There are 1 answers

0
Greg Scullard On BEST ANSWER

queries to contracts consume resources on the nodes and consequently are subject to a query fee which requires your wallet to sign.

Hedera added a json/rpc relay (https://hashio.io) which makes it possible to query contracts using libraries such as ethers.js through a simple JSONRpcProvider, hashio is subsidising the cost of the queries for now.

Moving forwards, mirror nodes will replicate smart contract state from consensus nodes so queries to smart contracts will be directed towards mirror nodes and will be free (subject to the mirror node operator's implementation).