web3dart
web3dart copied to clipboard
Tried to call a transaction that modifys state
Error Log
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: Exception: Tried to call a transaction that modifys state
#0 FinalizedTransaction.call (package:web3dart/src/transaction.dart:124:4)
#1 _MyHomePageState._getSmartCoursesContract (package:flutter_token/main.dart:94:32)
<asynchronous suspension>
#2 _MyHomePageState.initState (package:flutter_token/main.dart:170:5)
#3 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3846:58)
#4 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3711:5)
#5 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2956:14)
#6 Element.updateChild (package:flutter/src/widgets/framework.dart:2759:12)
#7 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4876:14)
#8 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2956:14)
#9 Element.updateChild (package:flutter/src/widgets/framework.dart:2759:12)
#10 ComponentElement.performR<…>
Contract ABI
const List coursesABI = [
{
"constant": true,
"inputs": [
{"name": "_address", "type": "address"}
],
"name": "getInstructor",
"outputs": [
{"name": "", "type": "string"},
{"name": "", "type": "string"},
{"name": "", "type": "uint256"}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "getInstructors",
"outputs": [
{"name": "", "type": "address[]"}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{"name": "_address", "type": "address"},
{"name": "_fname", "type": "string"},
{"name": "_lname", "type": "string"},
{"name": "_age", "type": "uint256"}
],
"name": "setInstructor",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "countInstructors",
"outputs": [
{"name": "", "type": "uint256"}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{"name": "", "type": "uint256"}
],
"name": "instructorAccounts",
"outputs": [
{"name": "", "type": "address"}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
];
My function
void _getSmartCoursesContract() async {
String courseContractABI = json.encode(coursesABI);
print(courseContractABI);
String tokenAddress = "0x8b373636Ff3147FCc01B40b57114eC282e77E2df";
String privateKeyHex =
"79FD6A46633A4AF7B1C3C1CA1D5EDFEC35245D42A5A3661B29AFFD8263E32853";
var httpClient = new Client();
var ethClient = new Web3Client(apiUrl, httpClient);
var credentials = Credentials.fromPrivateKeyHex(privateKeyHex);
var contractHelloABI =
ContractABI.parseFromJSON(courseContractABI, "Courses");
var coursesContract = new DeployedContract(contractHelloABI,
new EthereumAddress(tokenAddress), ethClient, credentials);
var getCoursesFn =
coursesContract.findFunctionsByName("countInstructors").first;
var listTokenFn = coursesContract.functions;
print(listTokenFn[2].name);
// for (FunctionParameter fp in getCoursesFn.parameters) {
// print("Function ${getCoursesFn.name} ---- Parameters ${fp.name}");
// }
//
// for (int a = 0; a < listTokenFn.length; a++) {
// print(listTokenFn[a].name);
// }
// for (ContractFunction fn in listTokenFn) {
// for (FunctionParameter fp in fn.parameters) {
// print("Function ${fn.name} ---- Parameters ${fp.name}");
// }
// }
var age = new BigInt.from(24);
var coursesResponse = new Transaction(keys: credentials, maximumGas: 0);
FinalizedTransaction finalizedTransaction = coursesResponse.prepareForCall(
coursesContract,
listTokenFn[2],
[credentials.address.number, "Maugost", "Okore", age],
);
await finalizedTransaction.call(ethClient).then((result) {
//print(result);
});
}
You're trying to call setInstructor on the smart contract, right? Here, "modifies state" means that calling the function will write data onto the Blockchain: The function has a mutability of nonPayable, which means that the contract can still change its internal state.
Call-ing a transaction means that it will be executed as read-only. This means that the transaction is not actually sent to the network. Instead, the node you're connected with will execute the called function locally, which is free to use. Of course, this can't work when you're writing data, as that needs to be properly synchronized around the network. What you'll want to use instead is await finalizedTransaction.send(ethClient). Notice that writes won't work with a maximum gas of 0, you'll have to spend some Ether on that operation.
Please let me know if that doesn't answer your question, thanks.
Thanks for your swift reply
I get this error
Performing hot restart...
Syncing files to device iPhone X...
Restarted application in 5,929ms.
flutter: getInstructors
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: RPCError: got code -32000 with msg "invalid sender".
#0 JsonRPC.call (package:web3dart/src/io/jsonrpc.dart:47:4)
<asynchronous suspension>
#1 Web3Client._makeRPCCall (package:web3dart/src/web3client.dart:29:30)
<asynchronous suspension>
#2 Web3Client.sendRawTransaction (package:web3dart/src/web3client.dart:184:10)
#3 FinalizedTransaction.send.<anonymous closure> (package:web3dart/src/transaction.dart:115:18)
#4 _rootRunUnary (dart:async/zone.dart:1132:38)
#5 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
#6 _FutureListener.handleValue (dart:async/future_impl.dart:126:18)
#7 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:639:45)
#8 Future._propagateToListeners (dart:async/future_impl.dart:668:32)
#9 Future._complete (dart:async/future_impl.dart:473:7)
#10 _SyncCompleter.complete (dart:async/future_impl.dart:51:12)
#11 _AsyncAwaitCompleter.complete (dart:a<…>
with re writing the code this way
void _getSmartCoursesContract() async {
String courseContractABI = json.encode(coursesABI);
String tokenAddress = "0x8b373636Ff3147FCc01B40b57114eC282e77E2df";
String privateKeyHex =
"79FD6A46633A4AF7B1C3C1CA1D5EDFEC35245D42A5A3661B29AFFD8263E32853";
var httpClient = new Client();
var ethClient = new Web3Client(apiUrl, httpClient);
var credentials = Credentials.fromPrivateKeyHex(privateKeyHex);
var contractHelloABI =
ContractABI.parseFromJSON(courseContractABI, "Courses");
var coursesContract = new DeployedContract(contractHelloABI,
new EthereumAddress(tokenAddress), ethClient, credentials);
var getCoursesFn =
coursesContract.findFunctionsByName("countInstructors").first;
var listTokenFn = coursesContract.functions;
print(listTokenFn[1].name);
// for (FunctionParameter fp in getCoursesFn.parameters) {
// print("Function ${getCoursesFn.name} ---- Parameters ${fp.name}");
// }
//
// for (int a = 0; a < listTokenFn.length; a++) {
// print(listTokenFn[a].name);
// }
// for (ContractFunction fn in listTokenFn) {
// for (FunctionParameter fp in fn.parameters) {
// print("Function ${fn.name} ---- Parameters ${fp.name}");
// }
// }
var age = new BigInt.from(24);
var coursesResponse =
new Transaction(keys: credentials, maximumGas: 127489);
FinalizedTransaction finalizedTransaction = coursesResponse.prepareForCall(
coursesContract,
listTokenFn[2],
[credentials.address.number, "Maugost", "Okore", age],
);
await finalizedTransaction.send(ethClient).then((result) {
print(result);
});
}
Please how to i resolve this and also
- How do i read a method from a smart contract 2.How do i write to a method from a smart contract
As for getting ether balance on the address I can it works perfectly well..
it works fine when i specify a chaidID
void _getSmartCoursesContract() async {
String courseContractABI = json.encode(coursesABI);
String privateKeyHex =
"79FD6A46633A4AF7B1C3C1CA1D5EDFEC35245D42A5A3661B29AFFD8263E32853";
var httpClient = new Client();
var ethClient = new Web3Client(apiUrl, httpClient);
var credentials = Credentials.fromPrivateKeyHex(privateKeyHex);
var contractABI = ContractABI.parseFromJSON(courseContractABI, "Courses");
var coursesContract = new DeployedContract(
contractABI,
new EthereumAddress(credentials.address.toString()),
ethClient,
credentials);
var listTokenFn = coursesContract.functions;
ContractFunction getInstructor = listTokenFn[0];
ContractFunction getInstructors = listTokenFn[1];
ContractFunction setInstructor = listTokenFn[2];
ContractFunction countInstructor = listTokenFn[3];
ContractFunction instructorAccounts = listTokenFn[4];
//setting instructors
var age = new BigInt.from(24);
var setInstructorResponse =
new Transaction(keys: credentials, maximumGas: 127489);
FinalizedTransaction setInstructorTransaction =
setInstructorResponse.prepareForCall(
coursesContract,
setInstructor,
[credentials.address.number, "Maugost", "Okore", age],
);
await setInstructorTransaction.send(ethClient, chainId: 4).then((result) {
print(result);
});
//getting instructor
var getInstructorResponse =
new Transaction(keys: credentials, maximumGas: 127489);
FinalizedTransaction getInstructorTransaction =
getInstructorResponse.prepareForCall(
coursesContract,
getInstructor,
[credentials.address.number],
);
await getInstructorTransaction.send(ethClient, chainId: 4).then((result) {
print(result);
});
}

Transactions are being recorded on ether scan but now i get a little confuse sir..please what's the difference between the call(), and the send() in finalized transactions? Please help??
Hm that's weird, perhaps the first issue (transactions only work when specifying a chain id) is related to #28, I'll have to look into that some more.
To answer your questions on whether to use call or send:
- Use
callfor functions that don't write data to the Blockchain. These functions either havepureorviewset in theirstateMutabilityfield in the contract ABI. - Basically, use
sendfor all others. Calling methods withsendwill create a transaction that can write state and will show up on etherscan as they should.