I am using web3.js module for ethereum. While executing a transaction I am getting error response.
Error:
"Error: Invalid JSON RPC response: ""
at Object.InvalidResponse (/home/akshay/WS/ethereum/node_modules/web3-core-helpers/src/errors.js:42:16)
at XMLHttpRequest.request.onreadystatechange (/home/akshay/WS/ethereum/node_modules/web3-providers-http/src/index.js:73:32)
at XMLHttpRequestEventTarget.dispatchEvent (/home/akshay/WS/ethereum/node_modules/xhr2/lib/xhr2.js:64:18)
at XMLHttpRequest._setReadyState (/home/akshay/WS/ethereum/node_modules/xhr2/lib/xhr2.js:354:12)
at XMLHttpRequest._onHttpResponseEnd (/home/akshay/WS/ethereum/node_modules/xhr2/lib/xhr2.js:509:12)
at IncomingMessage.<anonymous> (/home/akshay/WS/ethereum/node_modules/xhr2/lib/xhr2.js:469:24)
at emitNone (events.js:111:20)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)"
I am using ropsten test network url for testing my smart contract:
https://ropsten.infura.io/API_KEY_HERE
When I call the balanceOf function, it works fine but when I try to call function transfer it send me this error. The code is mentioned below:
router.post('/transfer', (req, res, next)=>{
contractInstance.methods.transfer(req.body.address, req.body.amount).send({from:ownerAccountAddress})
.on('transactionHash',(hash)=>{
console.log(hash)
}).on('confirmation',(confirmationNumber, receipt)=>{
console.log(confirmationNumber)
console.log(receipt)
}).on('receipt', (receipt)=>{
console.log(receipt)
}).on('error',(err)=>{
console.log(err)
})
})
Please let me know where I am wrong.
EDIT: I am using web3js version "web3": "^1.0.0-beta.34"
To add to what maptuhec said, while calling a "state-changing" function in Web3 or a state-changing transaction, it MUST be SIGNED!
Below is an example of when you're trying to call a public function (or even a public contract variable), which is only reading (or "view"ing) and returning a value from your smart contract and NOT changing its state, in this we don't need to necessarily specify a transaction body and then sign it as a transaction, because it doesn't change the state of our contract.
contractInstance.methods.aPublicFunctionOrVariableName().call().then( (result) => {console.log(result);})
**
State-Changing Transactions
**
Now, consider the example below, here we're trying to invoke a "state-changing" function and hence we'll be specifying a proper transaction structure for it.
web3.eth.getTransactionCount(functioncalleraddress).then( (nonce) => {
let encodedABI = contractInstance.methods.statechangingfunction().encodeABI();
contractInstance.methods.statechangingfunction().estimateGas({ from: calleraddress }, (error, gasEstimate) => {
let tx = {
to: contractAddress,
gas: gasEstimate,
data: encodedABI,
nonce: nonce
};
web3.eth.accounts.signTransaction(tx, privateKey, (err, resp) => {
if (resp == null) {console.log("Error!");
} else {
let tran = web3.eth.sendSignedTransaction(resp.rawTransaction);
tran.on('transactionHash', (txhash) => {console.log("Tx Hash: "+ txhash);});
For more on signTransaction, sendSignedTransaction, getTransactionCount and estimateGas
when using Web3.js you should sign the transactions. When you call functions which are non-constant, like transfer, you should sign the transaction and after that send the signed transaction (there is a method called sendSignedTransaction). This is very hard using web3js, I recommend using ehtersjs, with it everything is a lot easier.
in my case, it's the network problem.
I set the HTTP_PROXY and HTTPS_PROXY in my terminal and can successfully curl google.com, however I got this error.
solution:
I ssh to another server (located in HK where network is good to connect everywhere in the world ) and everything is fine.
Related
I have deployed my ERC721 contract on polygon testnet from owner(ox43b....81). I have created a small node server to interact with my contract through web3. I m using truffle config
//truffle-config.js
polygon-testnet: {
provider: new HDWalletProvider(privateKey, https://rpc-mumbai.maticvigil.com),
network_id: 80001,
gas: 6000000,
gasPrice: 10000000000,
confirmations: 2,
timeoutBlocks: 200,
skipDryRun: true
}
//index.js file
function test(){
const owner = await myContract.methods.owner().call()
console.log('contract owner', owner) //ox43b....81
//miniting token
const mint = await myContract.methods
.safeMint(owner,1001, 'google.com')
.send({ from: owner, gas: 100000 }) // is this the write way of calling ??
//token transfer
const transfer = await myContract.methods
.safeTransferFrom(acc1, acc2, 1003)
.send({ from: acc1, gas: 1000000 }) // is this the write way of calling ??
}
bcz i m getting err in both function calling: Error: Returned error: unknown account.
NOTE: I am not calling my contract func from truffle console. I m calling through a JS api file index.js
I know there is another way by using web3.eth.accounts.signTransaction() to mint & transfer the token.
Q.1 Is signing is reqd? Can't we access the contract method directly as i did above ?
Q.2 By using web3.eth.accounts.signTransaction() method i can able to mint the tokens successfully but i am facing issue in token transfer (using safeTransferFrom()). There are two cases:
case 1: i am transferring the token which is created/minted by contract owner(ox43b....81) to any other individual user address.
const fromAddress = 'ox43b....81' //owner of the contract
const toAddress = '0x26....7D'
const tokenId = 10001 // created by owner(ox43b....81)
const tx = {
from: ownerAddress, // ox43b....81 --> owner who created contract
to: contractAddress,// 0xfe.....24
nonce: nonce, // nonce with the no of transactions from our owner address
gas: 1000000, // fee estimate to complete the transaction
data: await myContract.methods
.safeTransferFrom(fromAddress, toAddress, tokenId)
.encodeABI()
}
// do signing stuff & send it
so in this case i m able to transfer the token successfully.
case 2: i am transferring the token which is created/minted by another(not contract owner) user(0x26....7D) to any other individual user address / or to owner.
const fromAddress = '0x26....7D' (not the owner of contract)
const toAnyAddress = '0x5e....5a' // any other user
const tokenId = 10002 // created by user '0x26....7D' (not the owner of contract)
const nonce = await web3.eth.getTransactionCount(fromAddress, 'latest')
const tx = {
from: fromAddress, // 0x26....7D -> is this right? or i put contract owner adr?
to: contractAddress,// 0xfe.....24
nonce: nonce,
gas: 1000000, // fee estimate to complete the transaction
data: await this.myContract.methods
.safeTransferFrom(fromAddress, toAnyAddress, tokenId)
.encodeABI()
}
// do signing stuff & send it
so in this case i m getting err - Fail with error 'ERC721: transfer caller is not owner nor approved'.
I need solution for my case 2. Is there something related with locked/unlocked accounts? How can i fix it?
Please help! Thanks in advance.
Q.1 Is signing is reqd? Can't we access the contract method directly as i did above ?
The .send() method of the web3 Contract instance performs/requests the signature in the background. So it's always signed - just not with an explicit "sign" keyword in the code in this case.
Q.2 There are two cases:
This is not related to the way you sign the transaction.
The second case fails because the token holder has not approved the spender (i.e. the transaction sender) to spend their tokens.
You need to invoke the approve(<spender>, <tokenId>) function from the token holder address first, to be able to successfully use the transferFrom().
// assuming `acc1` is holder of the token ID `1003`
// approve the `owner` to spend the `acc1`'s token
await myContract.methods.approve(owner, 1003).send({from: acc1});
// transfer token `1003` held by `acc1` ... and send the transaction from the `owner` address
await myContract.methods.transferFrom(acc1, recipient, 1003).send({from: owner});
I have a Lex Bot setup and working fine with Android. But when I try to access the same from react native, I get the following error:
NotFoundException: There is no alias named test for the bot named test_bot_name. Choose another alias.
I am using the aws-sdk-react-native package. My call to Lex looks like this:
sendToLex(message) {
let params = {
botAlias: 'test',
botName: 'test_bot_name',
inputText: message,
userId: lexUserId,
}
lexRunTime.postText(params, (err, data) => {
if(err) {
// TODO SHOW ERROR ON MESSAGES
console.log("[ERROR] Error: " + err);
console.log("[ERROR] Data: " + data);
}
if (data) {
console.log("Data " + data);
this.showResponse(data)
}
})
}
The same botAlias and botName parameters work fine on Android. But does not work on react native. The AWS config credentials look fine as I am not getting errors relating to the identity pool and region.
If it does indeed work in Android as you say then I would suggest the following:-
Ensure that the credentials are for the correct account
Ensure that you're pointing to the correct region
Try creating another alias and testing that to discount any funnies in the system.
Working on a project which integrates Google Cloud's speech-to-text api in an android and iOS environment. Ran through the example code provided (https://cloud.google.com/speech-to-text/docs/samples) and was able to get it to run. Used them as a template to add voice into my app, however there is a serious danger in the samples, specifically in generating the AccessToken (Android snippet below):
// ***** WARNING *****
// In this sample, we load the credential from a JSON file stored in a raw resource
// folder of this client app. You should never do this in your app. Instead, store
// the file in your server and obtain an access token from there.
// *******************
final InputStream stream = getResources().openRawResource(R.raw.credential);
try {
final GoogleCredentials credentials = GoogleCredentials.fromStream(stream)
.createScoped(SCOPE);
final AccessToken token = credentials.refreshAccessToken();
This was fine to develop and test locally, but as the comment indicates, it isn't safe to save the credential file into a production app build. So what I need to do is replace this code with a request from a server endpoint. Additionally i need to write the endpoint that will take the request and pass back a token. Although I found some very interesting tutorials related to Firebase Admin libraries generating tokens, I couldn't find anything related to doing a similar operation for GCP apis.
Any suggestions/documentation/examples that could point me in the right direction are appreciated!
Note: The server endpoint will be a Node.js environment.
Sorry for the delay, I was able to get it all to work together and am now only circling back to post an extremely simplified how-to. To start, I installed the following library on the server endpoint project https://www.npmjs.com/package/google-auth-library
The server endpoint in this case is lacking any authentication/authorization etc for simplicity's sake. I'll leave that part up to you. We are also going to pretend this endpoint is reachable from https://www.example.com/token
The expectation being, calling https://www.example.com/token will result in a response with a string token, a number for expires, and some extra info about how the token was generated:
ie:
{"token":"sometoken", "expires":1234567, "info": {... additional stuff}}
Also for this example I used a ServiceAccountKey file which will be stored on the server,
The suggested route is to set up a server environment variable and use https://cloud.google.com/docs/authentication/production#finding_credentials_automatically however this is for the examples sake, and is easy enough for a quick test. These files look something like the following: ( honor system don't steal my private key )
ServiceAccountKey.json
{
"type": "service_account",
"project_id": "project-id",
"private_key_id": "378329234klnfgdjknfdgh9fgd98fgduiph",
"private_key": "-----BEGIN PRIVATE KEY-----\nThisIsTotallyARealPrivateKeyPleaseDontStealIt=\n-----END PRIVATE KEY-----\n",
"client_email": "project-id#appspot.gserviceaccount.com",
"client_id": "12345678901234567890",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/project-id%40appspot.gserviceaccount.com"
}
So here it is a simple endpoint that spits out an AccessToken and a number indicating when the token expires (so you can call for a new one later).
endpoint.js
const express = require("express");
const auth = require("google-auth-library");
const serviceAccount = require("./ServiceAccountKey.json");
const googleauthoptions = {
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
credentials: serviceAccount
};
const app = express();
const port = 3000;
const auth = new auth.GoogleAuth(googleauthoptions);
auth.getClient().then(client => {
app.get('/token', (req, res) => {
client
.getAccessToken()
.then((clientresponse) => {
if (clientresponse.token) {
return clientresponse.token;
}
return Promise.reject('unable to generate an access token.');
})
.then((token) => {
return client.getTokenInfo(token).then(info => {
const expires = info.expiry_date;
return res.status(200).send({ token, expires, info });
});
})
.catch((reason) => {
console.log('error: ' + reason);
res.status(500).send({ error: reason });
});
});
app.listen(port, () => {
console.log(`Server is listening on https://www.example.com:${port}`);
});
return;
});
Almost done now, will use android as an example. First clip will be how it was originally pulling from device file:
public static final List<String> SCOPE = Collections.singletonList("https://www.googleapis.com/auth/cloud-platform");
final GoogleCredentials credentials = GoogleCredentials.fromStream(this.mContext.getResources().openRawResource(R.raw.credential)).createScoped(SCOPE);
final AccessToken token = credentials.refreshAccessToken();
final string token = accesstoken.getTokenValue();
final long expires = accesstoken.getExpirationTime().getTime()
final SharedPreferences prefs = getSharedPreferences(PREFS, Context.MODE_PRIVATE);
prefs.edit().putString(PREF_ACCESS_TOKEN_VALUE, value).putLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME, expires).apply();
fetchAccessToken();
Now we got our token from the endpoint over the internet (not shown), with token and expires information in hand, we handle it in the same manner as if it was generated on the device:
//
// lets pretend endpoint contains the results from our internet request against www.example.com/token
final string token = endpoint.token;
final long expires = endpoint.expires
final SharedPreferences prefs = getSharedPreferences(PREFS, Context.MODE_PRIVATE);
prefs.edit().putString(PREF_ACCESS_TOKEN_VALUE, value).putLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME, expires).apply();
fetchAccessToken();
Anyway hopefully that is helpful if anyone has a similar need.
===== re: AlwaysLearning comment section =====
Compared to the original file credential based solution:
https://github.com/GoogleCloudPlatform/android-docs-samples/blob/master/speech/Speech/app/src/main/java/com/google/cloud/android/speech/SpeechService.java
In my specific case I am interacting with a secured api endpoint that is unrelated to google via the react-native environment ( which sits on-top of android and uses javascript ).
I already have a mechanism to securely communicate with the api endpoint I created.
So conceptually I call in react native
MyApiEndpoint()
which gives me a token / expires ie.
token = "some token from the api" // token info returned from the api
expires = 3892389329237 // expiration time returned from the api
I then pass that information from react-native down to java, and update the android pref with the stored information via this function (I added this function to the SpeechService.java file)
public void setToken(String value, long expires) {
final SharedPreferences prefs = getSharedPreferences(PREFS, Context.MODE_PRIVATE);
prefs.edit().putString(PREF_ACCESS_TOKEN_VALUE, value).putLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME, expires).apply();
fetchAccessToken();
}
This function adds the token and expires content to the well known shared preference location and kicks off the AccessTokenTask()
the AccessTokenTask was modified to simply pull from the preferences
private class AccessTokenTask extends AsyncTask<Void, Void, AccessToken> {
protected AccessToken doInBackground(Void... voids) {
final SharedPreferences prefs = getSharedPreferences(PREFS, Context.MODE_PRIVATE);
String tokenValue = prefs.getString(PREF_ACCESS_TOKEN_VALUE, null);
long expirationTime = prefs.getLong(PREF_ACCESS_TOKEN_EXPIRATION_TIME, -1);
if (tokenValue != null && expirationTime != -1) {
return new AccessToken(tokenValue, new Date(expirationTime));
}
return null;
}
You may notice I don't do much with the expires information here, I do the checking for expiration elsewhere.
Here you have a couple of useful links:
Importing the Google Cloud Storage Client library in Node.js
Cloud Storage authentication
Presently, I have a smart contract successfully deployed to the Rinkeby testnet, I'm having trouble accessing the method in question using web3 version 1.0.
Here's my web3 code, which instantiates a contract instance and calls a contract method:
const contractInstance = new web3.eth.Contract(abiDefinition, contractAddress);
var value = web3.utils.toWei('1', 'ether')
var sentTransaction = contractInstance.methods.initiateScoreRetrieval().send({value: value, from: fromAddress})
console.log('event sent, now set listeners')
sentTransaction.on('confirmation', function(confirmationNumber, receipt){
console.log('method confirmation', confirmationNumber, receipt)
})
sentTransaction.on('error', console.error);
And here is my smart contract, or rather a version of it stripped down to the relevant bits:
contract myContract {
address private txInitiator;
uint256 private amount;
function initiateScoreRetrieval() public payable returns(bool) {
require(msg.value >= coralFeeInEth);
amount = msg.value;
txInitiator = msg.sender;
return true;
}
}
I am not able to get to the console.log that is setting the event listeners on the web3 side, and I am not getting an error of any kind thrown. I'm certainly not getting the consoles from the actual event listeners. I am guessing something is wrong with the way I'm sending the transaction, but I think I am correctly following the pattern documented below: https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#methods-mymethod-send
Does anyone have any insight on how to use web3 1.0 to make contract method calls correctly? Am I doing something wrong with how I'm passing options, etc.?
Thanks!
I believe you forgot to specify your HttpProvider for your web3, thus you're not connecting to live Rinkeby network, and by default web3 is running on you local host, which is why even if you provide the right contract address, there's nothing there.
To connect to live network, I would strongly encourage you to use Infura Node by ConsenSys.
const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("https://rinkeby.infura.io"));
Then by now, everything should work perfectly fine.
First, you need to generate your transaction ABI using encodeABI(), here is an example:
let tx_builder = contractInstance.methods.myMethod(arg1, arg2, ...);
let encoded_tx = tx_builder.encodeABI();
let transactionObject = {
gas: amountOfGas,
data: encoded_tx,
from: from_address,
to: contract_address
};
Then you have to sign the transaction using signTransaction() using private key of sender. Later you can sendSignedTransaction()
web3.eth.accounts.signTransaction(transactionObject, private_key, function (error, signedTx) {
if (error) {
console.log(error);
// handle error
} else {
web3.eth.sendSignedTransaction(signedTx.rawTransaction)
.on('receipt', function (receipt) {
//do something
});
}
I have Lambda function tranportKickoff which receives an input and then sends/proxies that input forward into a Step Function. The code below does run and I am getting no errors but at the same time the step function is NOT executing.
Also critical to the design, I do not want the transportKickoff function to wait around for the step function to complete as it can be quite long running. I was, however, expecting that any errors in the calling of the Step Function would be reported back synchronously. Maybe this thought is at fault and I'm somehow missing out on an error that is thrown somewhere. If that's the case, however, I'd like to find a way which is able to achieve the goal of having the kickoff lambda function exit as soon as the Step Function has started execution.
note: I can execute the step function independently and I know that it works correctly
const stepFn = new StepFunctions({ apiVersion: "2016-11-23" });
const stage = process.env.AWS_STAGE;
const name = `transport-steps ${message.command} for "${stage}" environment at ${Date.now()}`;
const params: StepFunctions.StartExecutionInput = {
stateMachineArn: `arn:aws:states:us-east-1:999999999:stateMachine:transportion-${stage}-steps`,
input: JSON.stringify(message),
name
};
const request = stepFn.startExecution(params);
request.send();
console.info(
`startExecution request for step function was sent, context sent was:\n`,
JSON.stringify(params, null, 2)
);
callback(null, {
statusCode: 200
});
I have also checked from the console that I have what I believe to be the right permissions to start the execution of a step function:
I've now added more permissions (see below) but still experiencing the same problem:
'states:ListStateMachines'
'states:CreateActivity'
'states:StartExecution'
'states:ListExecutions'
'states:DescribeExecution'
'states:DescribeStateMachineForExecution'
'states:GetExecutionHistory'
Ok I have figured this one out myself, hopefully this answer will be helpful for others:
First of all, the send() method is not a synchronous call but it does not return a promise either. Instead you must setup listeners on the Request object before sending so that you can appropriate respond to success/failure states.
I've done this with the following code:
const stepFn = new StepFunctions({ apiVersion: "2016-11-23" });
const stage = process.env.AWS_STAGE;
const name = `${message.command}-${message.upc}-${message.accountName}-${stage}-${Date.now()}`;
const params: StepFunctions.StartExecutionInput = {
stateMachineArn: `arn:aws:states:us-east-1:837955377040:stateMachine:transportation-${stage}-steps`,
input: JSON.stringify(message),
name
};
const request = stepFn.startExecution(params);
// listen for success
request.on("extractData", req => {
console.info(
`startExecution request for step function was sent and validated, context sent was:\n`,
JSON.stringify(params, null, 2)
);
callback(null, {
statusCode: 200
});
});
// listen for error
request.on("error", (err, response) => {
console.warn(
`There was an error -- ${err.message} [${err.code}, ${
err.statusCode
}] -- that blocked the kickoff of the ${message.command} ITMS command for ${
message.upc
} UPC, ${message.accountName} account.`
);
callback(err.statusCode, {
message: err.message,
errors: [err]
});
});
// send request
request.send();
Now please bear in mind there is a "success" event but I used "extractData" to capture success as I wanted to get a response as quickly as possible. It's possible that success would have worked equally as well but looking at the language in the Typescript typings it wasn't entirely clear and in my testing I'm certain that the "extractData" method does work as expected.
As for why I was not getting any execution on my step functions ... it had to the way I was naming the function ... you're limited to a subset of characters in the name and I'd stepped over that restriction but didn't realize until I was able to capture the error with the code above.
For anyone encountering issues executing state machines from Lambda's make sure the permission 'states:StartExecution' is added to the Lambda permissions and the regions match up.
Promise based version:
import { StepFunctions } from 'aws-sdk';
const clients = {
stepFunctions: new StepFunctions();
}
const createExecutor = ({ clients }) => async (event) => {
console.log('Executing media pipeline job');
const params = {
stateMachineArn: '<state-machine-arn>',
input: JSON.stringify({}),
name: 'new-job',
};
const result = await stepFunctions.startExecution(params).promise();
// { executionArn: "string", startDate: number }
return result;
};
const startExecution = createExecutor({ clients });
// Pass in the event from the Lambda e.g S3 Put, SQS Message
await startExecution(event);
Result should contain the execution ARN and start date (read more)