Im very new to ethereum i have set up a private network using the pantheon client. i have successfully deployed a contract to the network and all interactions with the contract work when using through remix.
I am trying to set up a relay where a transaction is signed client side, sent to a nodeJs server and then the server proxies the transaction to the contract. however when i pass the signed transaction to sendSignedTransaction() i get the error Invalid params, to me this is very vague and i am unsure what i'm doing wrong / what the invalid params are. (any advice on how to debug this?)
UPDATE
using web3 v1.2.0
Error
Error: Returned error: Invalid params
at Object.ErrorResponse (/Users/ghost/node_modules/web3-core-helpers/src/errors.js:29:16)
at Object.<anonymous> (/Users/ghost/node_modules/web3-core-requestmanager/src/index.js:140:36)
at /Users/ghost/node_modules/web3-providers-ws/src/index.js:121:44
at Array.forEach (<anonymous>)
at W3CWebSocket.WebsocketProvider.connection.onmessage (/Users/ghost/node_modules/web3-providers-ws/src/index.js:98:36)
at W3CWebSocket._dispatchEvent [as dispatchEvent] (/Users/ghost/node_modules/yaeti/lib/EventTarget.js:107:17)
at W3CWebSocket.onMessage (/Users/ghost/node_modules/websocket/lib/W3CWebSocket.js:234:14)
at WebSocketConnection.<anonymous> (/Users/ghost/node_modules/websocket/lib/W3CWebSocket.js:205:19)
at WebSocketConnection.emit (events.js:188:13)
at WebSocketConnection.processFrame (/Users/ghost/node_modules/websocket/lib/WebSocketConnection.js:552:26)
at /Users/ghost/node_modules/websocket/lib/WebSocketConnection.js:321:40
at process.internalTickCallback (internal/process/next_tick.js:70:11)
Contract
pragma solidity ^0.5.1;
import "./Ownable.sol";
contract Entry is Ownable {
mapping (address => string) hash;
function addEntry(string memory _hash) public {
hash[msg.sender] = _hash;
}
function getHash() public view returns(string memory){
return hash[msg.sender];
}
}
Relay Server
const Web3 = require('web3');
const express = require('express')
const app = express()
const port = 3003
const bodyParser = require('body-parser');
const cors = require('cors')
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json())
app.use(cors())
var web3 = new Web3(Web3.givenProvider || "ws://localhost:7002");
app.post('/transaction/send', async (req, res) => {
const {tx, data} = req.body;
web3.eth.sendSignedTransaction(tx, function (err, transactionHash) {
if(err) console.log(err);
console.log(transactionHash);
});
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
Front end
import React from 'react';
import './App.css';
import Web3 from 'web3';
import request from 'request-promise';
const Tx = require('ethereumjs-tx').Transaction;
const web3 = new Web3("http://localhost:8545");
const privKey = '[My Priv key here]';
const contractADDRESS = "0x4261d524bc701da4ac49339e5f8b299977045ea5";
const addressFrom = '0x627306090abaB3A6e1400e9345bC60c78a8BEf57';
const contractABI = [{"constant":false,"inputs":[{"name":"_hash","type":"string"}],"name":"addEntry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getHash","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}];
function App() {
async function sendTx(){
const data = await extraData();
web3.eth.getTransactionCount(addressFrom).then(txCount => {
const txData = {
nonce: web3.utils.toHex(txCount),
gasLimit: web3.utils.toHex(25000),
gasPrice: web3.utils.toHex(10e9),
to: contractADDRESS,
from: addressFrom,
data: data
}
sendSigned(txData, function(err, result) {
if (err) return console.log('error', err)
console.log('sent', result)
})
})
}
async function sendSigned(txData, cb) {
const privateKey = new Buffer(privKey, 'hex')
const transaction = new Tx(txData)
transaction.sign(privateKey)
const serializedTx = transaction.serialize().toString('hex')
const response = request({
method: 'POST',
uri: 'http://127.0.0.1:3003/transaction/send',
body: {
tx: serializedTx,
data: 'somehashhh'
},
json: true,
});
}
async function extraData() {
const contractInstance = new web3.eth.Contract(contractABI, contractADDRESS);
return await contractInstance.methods.addEntry('somehashhh').encodeABI();
}
return (
<div className="App">
<header className="App-header">
<div onClick={() => sendTx()}>Submit transaction</div>
</header>
</div>
);
}
export default App;
This is the txData sent from front end
{
data: "0x17ce42bd0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a736f6d6568617368686800000000000000000000000000000000000000000000"
from: "0x627306090abaB3A6e1400e9345bC60c78a8BEf57"
gasLimit: "0x61a8"
gasPrice: "0x2540be400"
nonce: "0x0"
to: "0x4261d524bc701da4ac49339e5f8b299977045ea5"
}
After a lot of trail and error an 0 suggestions on stack overflow working, i have got the transaction signing working!. In the end i came away from using ethereumjs-tx (which for some reason is recommended by a lot of people) and used just pure Web3.
Front end client
async function sendTx(){
const { address: from } = web3.eth.accounts.privateKeyToAccount(PRIVATE_KEY)
const contract = new web3.eth.Contract(CONTRACT_ABI, CONTRACT_ADDRESS)
const query = await contract.methods.updateCount();
const signed = await web3.eth.accounts.signTransaction({
to: CONTRACT_ADDRESS,
from,
value: '0',
data: query.encodeABI(),
gasPrice: web3.utils.toWei('20', 'gwei'),
gas: Math.round((await query.estimateGas({ from })) * 1.5),
nonce: await web3.eth.getTransactionCount(from, 'pending')
}, PRIVATE_KEY)
const response = await request({
method: 'POST', json: true,
uri: 'http://127.0.0.1:3003/transaction/send',
body: {
tx: signed.rawTransaction,
data: 'some data'
}
});
console.log(response);
}
Relay Server
const Web3 = require('web3');
const express = require('express')
const app = express()
const port = 3003
const bodyParser = require('body-parser');
const cors = require('cors')
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json())
app.use(cors())
var web3 = new Web3(Web3.givenProvider || "ws://localhost:7002");
app.post('/transaction/send', async (req, res) => {
const {tx, data} = req.body;
web3.eth.sendSignedTransaction(tx)
.on('transactionHash', (txHash) => res.json({txHash}))
.on('error', console.log)
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
hopefully this can help someone else
👍
Related
I am developping an api on spotify.
I want to retrieve clients credentials. I set up my app on the dashboard.
My client_id and secret are correct.
But I have the same error at the end when I try to retrieve this client credential: "error":"invalid_client"
I look for my problem on web but no one correspond to my problem.
Here is my code:
`
const express = require("express");
const path = require("path");
const cors = require("cors");
const fetch = (...args) =>
import('node-fetch').then(({default: fetch}) => fetch(...args));
const request = "https://accounts.spotify.com/api/token";
const code = Buffer.from(client_id + ":" + client_secret).toString("base64");
const app = express();
const optionsTOKEN = {
method: "POST",
body: "grant_type=client_credentials",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic" +code
},
// json: true,
};
app.get("/code", async (req, res) => {
const data = await retrieveCode(request, optionsTOKEN);
console.log(res.statusCode)
res.send(data);
});
app.listen(8888, () => {
console.log("server running on port 8888");
});
async function retrieveCode(URlRequest, options) {
try {
const res = await fetch(URlRequest, options);
console.log(res);
const data = await res.json();
console.log("la data vaut" + data);
return data
} catch (err) {
console.log(`L'erreur: ${err}`);
}
}
`
Thank you for your help
I try to modify the parameters in my options, set up a new project on my dahsboard, change my port.
I am expecting to retrieve the access token
You needs to add a space between "Basic" and code
before
"Basic" +code
After
"Basic " +code
#1 With this code
This full test code with hide client_id and client_secret
const express = require("express");
const fetch = (...args) =>
import('node-fetch').then(({ default: fetch }) => fetch(...args));
const request = "https://accounts.spotify.com/api/token";
const client_id = "32-your-client-id-7b";
const client_secret = "ab-your-client_secret-9e";
const code = Buffer.from(client_id + ":" + client_secret).toString("base64");
const app = express();
const optionsTOKEN = {
method: "POST",
body: "grant_type=client_credentials",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic " + code
},
// json: true,
};
app.get("/code", async (req, res) => {
const data = await retrieveCode(request, optionsTOKEN);
console.log(res.statusCode)
res.send(data);
});
app.listen(8888, () => {
console.log("server running on port 8888");
});
async function retrieveCode(URlRequest, options) {
try {
const res = await fetch(URlRequest, options);
console.log(res);
const data = await res.json();
console.log("la data vaut" + JSON.stringify(data));
return data
} catch (err) {
console.log(`L'erreur: ${err}`);
}
}
#2 Using this dependencies
package.json for npm install
{
"dependencies": {
"express": "^4.18.2",
"node-fetch": "^3.3.0"
}
}
#3 npm install
#4 npm start
#5 access from browser http://localhost:8888/code
Response in console
la data vaut{"access_token":"BQCuVhXlpVQGKGxqK-remove-some-string-nX6sQp8uPSYBMh5lsU","token_type":"Bearer","expires_in":3600}
200
In Browser,
My app is successfully deployed on Heroku- it works when I have VSCode open and do npm run start manually, however when I close VSCode it is no longer able to successfully call any APIs on the backend and the console shows me a bunch of errors like the one in the title.
my console (ONLY happens when I close VSCode):
my code in the backend:
const PORT = 8000
const express = require('express')
const cors = require('cors')
const {TwitterApi} = require('twitter-api-v2')
const axios = require('axios')
const cheerio = require('cheerio')
require('dotenv').config()
const snoowrap = require('snoowrap')
const linkPreviewGenerator = require('link-preview-generator')
const spotify = require('spotify-web-api-node')
const fetch = require('node-fetch')
var request = require('request')
const app = express()
app.use(cors())
app.get('/', async (req, res) => {
const client = new TwitterApi(process.env.twt_bearer_token)
const trendsInternational = await client.v1.trendsByPlace(1);
const trendList = []
for (const {trends} of trendsInternational) {
for (const trend of trends) {
trendList.push({
name: trend.name,
url: trend.url
})
}
}
res.json(trendList)
})
app.get('/reddit', async (req, res) => {
const r = new snoowrap({
userAgent: process.env.user_agent,
clientId: process.env.client_id,
clientSecret: process.env.client_secret,
refreshToken: process.env.refresh_token
})
topPosts = []
;(await r.getHot()).forEach(post => {
topPosts.push({
title: post.title,
url: post.url
})
})
res.json(topPosts);
})
app.get('/news', async (req, res) => {
const news_url = 'https://www.theguardian.com/international'
axios(news_url)
.then(response => {
const html = response.data;
const $ = cheerio.load(html);
const articles = [];
const values = new Set();
$('.fc-item__title', html).each(function () { //<-- cannot be a function expression
const title = $(this).text().trim();
const url = $(this).find('a').attr('href');
if (!values.has(url)) {
values.add(url);
articles.push({
title,
url
});
}
})
res.json(articles)
}).catch(err => console.log(err))
})
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`))```
Heroku runs on its own port, try setting port like this
const PORT = Number(process.env["PORT"]) || 8000
I have a frontend JS script that takes text input from an HTML text box and sends it to an expressjs server. The body of the POST request, though, is always undefined, or depending on how I tweak things, returning as "{ }" if I view it via console.log( ). As I'm new to this, I can't seem to see what's going wrong.
Front end js:
async function submitCity(){
let x = document.getElementById("wg_input").value;
console.log("Successfully captured city name:", x);
let toWeather = JSON.stringify(x);
console.log("Input data successfully converted to JSON string:", toWeather);
const options = {
method: 'POST',
mode: 'cors',
headers: {'Content-Type': 'text/plain'},
body: toWeather
}
fetch('http://localhost:3000', options)
.then(res => console.log(res))
.catch(error => console.log(error))
}
Backend:
// Dependencies
const express = require('express');
const bp = require("body-parser");
const request = require("request");
const jimp = require('jimp');
const cors = require('cors');
const wgServer = express();
const port = 3000;
// Dotenv package
require("dotenv").config();
// OpenWeatherMap API_KEY
const apiKey = `${process.env.API_KEY}`;
// Basic server initialization
wgServer.use(cors())
wgServer.use(bp.json())
wgServer.use(bp.urlencoded({ extended: true }))
wgServer.listen(port, function() {
console.log(`Example app listening on port ${port}!`)
});
wgServer.post('/', async function (req, res) {
res.set('Content-Type', 'text/plain');
console.log(req.body)
res.send('Hello World');
//const data = await req.body;
// let jsonData = JSON.stringify(req.body);
// res.status(201);
//res.json();
});
The returned data is supposed to be a string of about 15 characters, give or take a few (a city and state). I thank you in advance.
I'm trying to connect from Nodejs to DialogFlow. I have completed all the steps to configure the user agent, the intent, etc. If I lunch with NODEMON the app, all its ok, but when I send a GET or POST request I get this error:
"UnhandledPromiseRejectionWarning: TypeError: sessionClient.projectAgentSessionPath" and more. But I think the most relevant mistake is this.
The code I used it's the same as the APi docs. I don't know why I get this error.
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const dialogflow = require('#google-cloud/dialogflow');
const uuid = require('uuid');
//const sendReq = require('./reqDialogFlow');
async function runSample(projectId = 'helpcenter-qwoj') {
// A unique identifier for the given session
const sessionId = uuid.v4();
// Create a new session
const sessionClient = new dialogflow.SessionsClient();
const sessionPath = sessionClient.projectAgentSessionPath(projectId, sessionId);
console.log(sessionPath);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
// The query to send to the dialogflow agent
text: 'hello',
// The language used by the client (en-US)
languageCode: 'it',
},
},
};
// Send request and log result
const responses = await sessionClient.detectIntent(request);
console.log('Detected intent');
const result = responses[0].queryResult;
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
if (result.intent) {
console.log(` Intent: ${result.intent.displayName}`);
} else {
console.log(` No intent matched.`);
}
};
app.get('/', (req, res) => {
res.send({ "hello": "Daniele Asteggiante" })
});
app.post('/api/textAPIE', (req, res) => {
res.send({ "text": "CIAO" });
runSample();
});
app.use(bodyParser.json());
const PORT = process.env.PORT || 5000;
app.listen(PORT);
i had the same error.
i had installed
npm i dialogflow
instead of
npm install #google-cloud/dialogflow
I tried to change the Express Version version with an earlier version 4.17.0 instead 4.17.1.
Now it goes.
change "sessionClient.projectAgentSessionPath" -> "sessionClient.sessionPath"
Found this solution on github:https://github.com/googleapis/nodejs-dialogflow/issues/127
I'm developing a billboard app to learn new technologies and i'm currently having problems trying to test the DELETE method of the API using Mocha.
I've been trying different approaches for it, but i couldn't find a solution yet. I'm using NodeJs and Hapi for the back-end server
const mongoose = require('mongoose')
const chai = require('chai')
const hapiServer = require('../../../index')
const expect = require('chai').expect
const should = chai.should()
chai.use(require('chai-http'))
before(async () => {
const server = await hapiServer()
global.url = 'http://localhost:3000'
})
after(async () => {
await mongoose.connection.close()
//await mongoose.connection.db.dropCollection()
})
const id = new mongoose.Types.ObjectId('5cd8a0eefc06344accd62a76')
describe('Movies API', () => {
it('Should DELETE a single movie', async () => {
const response = await chai.request(global.url)
.delete('/api/movies/' + '5cd8a0eefc06344accd62a77')
response.should.have.status(202)
})
})
Here's the index.js
const Hapi = require('#hapi/hapi')
const Inert = require('#hapi/inert')
const Vision = require('#hapi/vision')
const HapiSwagger = require('hapi-swagger')
const mongoose = require('mongoose')
const mongo = require('./config/mongo')
const Pack = require('./package')
const start = async () => {
const server = await new Hapi.Server({
host: 'localhost',
port: 3000,
})
// MongoDB Connection
try{
await mongoose
.connect(mongo.configuration.getUri(process.env.NODE_ENV), {useNewUrlParser: true})
console.log('MongoDB Connected...')
} catch(err) {
console.log(err)
}
const swaggerOptions = {
info: {
title: 'Billboard API Documentation',
version: Pack.version,
},
}
await server.register([
Inert,
Vision,
{
plugin: HapiSwagger,
options: swaggerOptions
}
]);
try {
await server.start()
console.log('Server running at:', server.info.uri)
} catch(err) {
console.log(err)
}
// Register Plugins
const moviesRoutes = require('./plugins/movies/routes')
server.route(moviesRoutes)
}
start()
module.exports = start
So, the the rest of the api tests are similar and they work excelent. But when i try to test this method i get this response:
error: Error: cannot DELETE /api/movies/5cd8a0eefc06344accd62a77 (404)
at Response.toError (C:\Users\lucas\billboard-backend\node_modules\superagent\lib\node\response.js:94:15)
at ResponseBase._setStatusProperties (C:\Users\lucas\billboard-backend\node_modules\superagent\lib\response-base.js:123:16)
at new Response (C:\Users\lucas\billboard-backend\node_modules\superagent\lib\node\response.js:41:8)
at Test.Request._emitResponse (C:\Users\lucas\billboard-backend\node_modules\superagent\lib\node\index.js:752:20)
at C:\Users\lucas\billboard-backend\node_modules\superagent\lib\node\index.js:916:38
at IncomingMessage.<anonymous> (C:\Users\lucas\billboard-backend\node_modules\superagent\lib\node\parsers\json.js:19:7)
at IncomingMessage.emit (events.js:201:15)
at endReadableNT (_stream_readable.js:1130:12)
at processTicksAndRejections (internal/process/task_queues.js:84:9) {
status: 404,
text: '{"statusCode":404,"error":"Not Found","message":"Not Found"}',
method: 'DELETE',
path: '/api/movies/5cd8a0eefc06344accd62a77'
Any ideas of why is this happening?
You need to add a route like this in your routes file assuming you're using controllers
const express = require('express')
const router = express.Router()
const movieController = require('../controllers/movie.controller')
router.delete('/api/movies/:movieId', movieController.deleteMovie)
module.exports = router