I successfully implemented a smart contract using remix in the Rinkeby testnet, and can interact with it from remix.
Now I'm building a simple frontend for it but although I have been able to obtain one of it's public variables, I'm not able to call a state changing function, Metamask returns
"Transaction Error. Exception thrown in contract code."
and when I send the transaction it fails. I looked all over the web and haven't found anything related. The abi looks ok, the contract is working and has the function correctly instantiated.
I'm currently using web3.js 0.20 and Chrome + Metamask, and I'm writing the function per web3's documentation. Follows the code:
My contract:
/// @title Contract Echos, prints the certificates
contract Echos is AccessControl {
event logPrintedCertificate(address contractAddress, string _name, string _course);
function printCertificate (string _name, string _course) public canAccess("printCertificate") whenNotPaused returns (address _certificateAddress) {
// creates certificate smart contract
address certificateAddr ess = new EchosCertificate(_name, _course);
// creates the event, to be used to query all the certificates
logPrintedCertificate(certificateAddress, _name, _course);
return certificateAddress;
}
/// @dev Invalidates a deployed certificate
function invalidateCertificate(address _certificateContract) external canAccess("printCertificate") {
EchosCertificate certContract = EchosCertificate(_certificateContract);
certContract.invalidate();
}
}
abi (obtained from remix):
[
{
"constant": true,
"inputs": [],
"name": "paused",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_user",
"type": "address"
},
{
"name": "_transaction",
"type": "string"
}
],
"name": "hasAccess",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_user",
"type": "address"
},
{
"name": "_transaction",
"type": "string"
}
],
"name": "grantAccess",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "tokenContract",
"type": "address"
}
],
"name": "withdrawTokens",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "unpause",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_certificateContract",
"type": "address"
}
],
"name": "invalidateCertificate",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "contractAddress",
"type": "address"
},
{
"indexed": false,
"name": "_name",
"type": "string"
},
{
"indexed": false,
"name": "_course",
"type": "string"
}
],
"name": "logPrintedCertificate",
"type": "event"
},
{
"constant": false,
"inputs": [],
"name": "pause",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "withdrawBalance",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_name",
"type": "string"
},
{
"name": "_course",
"type": "string"
}
],
"name": "printCertificate",
"outputs": [
{
"name": "_certificateAddress",
"type": "address"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_user",
"type": "address"
},
{
"name": "_transaction",
"type": "string"
}
],
"name": "revokeAccess",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
]
function to get public variable (working):
echosContract.paused.call(function(error, result) {
if (!error) {
console.log(result);
} else
console.error(error);
});
function to end transaction to state changing function (returns the aforementioned error):
echosContract.printCertificate.sendTransaction(name, course, {
gas: 30000,
from: web3.eth.coinbase
}, function(error, result) {
if (!error) {
console.log(result);
} else
console.error(error);
});
I also tried calling the contract without "sendTransaction" (both ways are available in the documentation) and without optional transaction parameters and get the same result.