Web3js raw transaction is being sent twice - express

I am sending a raw transaction to Ropsten test network with web3js module in node. The web3s code lives on an express back end. Here is the code:
var express = require("express");
var router = express.Router();
var Tx = require("ethereumjs-tx");
const Web3 = require("web3");
const web3 = new Web3(
"https://ropsten.infura.io/v3/d55489f8ea264a1484c293b05ed7eb85"
);
const abi = [...];
const contractAddress = "0x15E1ff7d97CB0D7C054D19bCF579e3147FC9009b";
const myAccount = "0x59f568176e21EF86017EfED3660625F4397A2ecE";
const privateKey1 = new Buffer(
"...",
"hex"
);
hashValue = "newly updated value";
router.post("/", function(req, res, next) {
const hashValue = req.body.hash,
fileName = req.body.fileName,
value = req.body.value;
const contract = new web3.eth.Contract(abi, contractAddress, {
from: myAccount
});
web3.eth.getTransactionCount(myAccount, (err, txCount) => {
//Smart contract data
const data = contract.methods
.setHashValue(value + fileName + hashValue)
.encodeABI();
// Build the transaction
const txObject = {
nonce: web3.utils.toHex(txCount),
gasLimit: web3.utils.toHex(1000000),
gasPrice: 20000000000,
data: data,
from: myAccount,
to: contractAddress
};
// Sign the transaction
const tx = new Tx(txObject);
tx.sign(privateKey1);
const serializedTx = tx.serialize();
// const raw = '0x' + serializedTx.toString('hex')
// Broadcast the transaction
web3.eth
.sendSignedTransaction("0x" + serializedTx.toString("hex"))
.on("receipt", console.log, receipt => {
callback(receipt);
})
.then(() => {
res.json({ transactionHash });
})
.catch(() => {
// fail
});
});
});
module.exports = router;
The .post looks like this
axios.post(
"http://compute.amazonaws.com:3000/users",
{
value: "value",
fileName: "fileName",
hash: "hash"
}
);
The transaction is successful and returns a json with all relevant block data. about 2-3 minutes later, the same transaction is sent and mined on Ropsten. About the time that the second transaction is mined, my console (the request is sent through an http from browser) shows the following errors:
POST http://ec2-54-67-28-69.us-west-1.compute.amazonaws.com:3000/users net::ERR_EMPTY_RESPONSE
createError.js:17 Uncaught (in promise) Error: Network Error
at createError (createError.js:17)
at XMLHttpRequest.handleError (xhr.js:87)
This didn't happen until I added
const hashValue = req.body.hash,
fileName = req.body.fileName,
value = req.body.value;
to the code.
Any ideas?

This doesn't answer why the double transaction was happening, but a work around is to put next() at the end of the code.

Related

Unable to set state variables during staging test on Goerli using Hardhat

I am able to set variables during my unit tests on the local Hardhat Node, however the same test fails on Goerli.
This is the code for my test:
const { getNamedAccounts, deployments, ethers, network } = require("hardhat")
const { developmentChains, networkConfig } = require("../../helper-hardhat-config")
const { assert, expect } = require("chai")
const fs = require("fs")
const path = require("path")
developmentChains.includes(network.name)
? describe.skip
: describe("Whoopy Staging Tests", function () {
let whoopy,
deployer,
player,
cloneAddress,
clonedContract,
txReceipt,
tx,
accountConnectedClone,
manager,
create
const chainId = network.config.chainId
beforeEach(async function () {
accounts = await ethers.getSigners()
deployer = accounts[0]
player = accounts[1]
await deployments.fixture(["all"])
const dir = path.resolve(
__dirname,
"/Users/boss/hardhat-smartcontract-whoopy/artifacts/contracts/Whoopy.sol/Whoopy.json"
)
const file = fs.readFileSync(dir, "utf8")
const json = JSON.parse(file)
const abi = json.abi
whoopy = await ethers.getContract("Whoopy", deployer)
manager = await ethers.getContract("VRFv2SubscriptionManager", deployer)
wf = await ethers.getContract("WhoopyFactory", deployer)
tx = await (await wf.connect(player).createClone(player.address))
txReceipt = await tx.wait(1)
cloneAddress = await txReceipt.events[1].args._instance
clonedContract = new ethers.Contract(cloneAddress, abi, player)
accountConnectedClone = clonedContract.connect(player)
})
describe("Whoopy Tests", function () {
beforeEach(async function () {
create = await accountConnectedClone.createWhoopy(
"Test",
1,
{
value: ethers.utils.parseUnits("10000000000000000", "wei"),
gasLimit: 3000000
})
console.log(create)
})
it("creates Whoopy correctly", async function () {
const whoopyName = await accountConnectedClone.getWhoopyName()
const num = await accountConnectedClone.getNum()
expect(whoopyName).to.equal("Test")
expect(num).to.equal(1)
})
})
Here is the function I am testing:
function createWhoopy( //to be created only once
string memory s_whoopyName,
uint256 s_num,
) public payable restricted {
whoopyName = s_whoopyName;
num = s_num;
}
Seems pretty straight forward but don't know why it's not working. My accounts have enough test eth and goerli is correctly set up in Hardhat config. The test reverts as follows:
AssertionError: expected '' to equal 'Test'
+ expected - actual
+Test
Any guidance would be appreciated! Thanks!
I figured it out. It was something stupid (as I thought it would be). I forgot to put await create.wait(6) which was needed to wait for the blocks to mine the transaction.
It went through on Hardhat because Hardhat mines blocks immediately, but since Goerli is a live Testnet you need to wait for the transaction to be mined.

Stripe Error: No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe?

So first what i want to say, is that none of the public questions on stackoverflow did not helped me with this error. I am running the Stripe CLI on my local machine like this : stripe listen --forward-to localhost:4242/webhook , but weirdly when i try to proccess all the events inside i get the error :
No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing
I have already tried using request.rawBody , but it didn't fix my issue.
I am posting all of the code, so maybe someone will see what i can't and help me fixing it
router.js :
let express = require('express');
let router = express.Router();
let bodyParser = require('body-parser')
let postMong = require('./post')
require("dotenv").config()
router.use(express.json());
const YOUR_DOMAIN = 'http://localhost:4242';
const stripe = require('stripe')(process.env.PUBLIC_KEY);
router.post('/checkout/create-order', async (req, res) => {
const price = req.body.order.stripe_price || undefined,
product = req.body.order.stripe_product || undefined
const session = await stripe.checkout.sessions.create({
shipping_address_collection: {
allowed_countries: ['US', 'CA'],
},
shipping_options: [
{
shipping_rate_data: {
type: 'fixed_amount',
fixed_amount: {
amount: 2499,
currency: 'usd',
},
display_name: 'International Shipping',
// Delivers between 5-7 business days
delivery_estimate: {
minimum: {
unit: 'week',
value: 2,
},
}
}
},
],
line_items: [
{
price: price,
quantity: 1,
},
],
payment_method_types: ["card", 'us_bank_account'],
mode: 'payment',
success_url: `${YOUR_DOMAIN}/success.html`,
cancel_url: `${YOUR_DOMAIN}/index.html`,
});
res.json({url: session.url})
});
router.post('/posts/add', async (req,res)=>{
try{
const {author, id, name, picture, pixels, price, size, stripe_price, stripe_product} = req.body
const pos = await postMong.create( {author, id, name, picture, pixels, price, size, stripe_price, stripe_product})
res.json(pos)
} catch(e){
res.status(500).json(e)
}
})
router.get('/ideas', async (req,res)=>{
try{
const posts = await postMong.find()
return res.json(posts);
} catch(e){
reject(res.status(500).json(e))
}
})
const endpointSecret = 'whsec_****';
const fulfillOrder = (session) => {
// TODO: fill me in
console.log("Fulfilling order", session);
}
router.use(bodyParser.json());
router.post('/webhook', (request, response) => {
const payload = request.body;
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.rawBody, sig, endpointSecret);
console.log(event)
} catch (err) {
console.log(err.message)
return response.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the checkout.session.completed event
if (event.type === 'checkout.session.completed') {
const session = event.data.object;
// Fulfill the purchase...
fulfillOrder(session);
}
response.status(200);
});
module.exports = router
server.js :
const router = require("./router");
const account = require("./routerAccount");
const express = require('express');
const mongoose = require("mongoose")
const app = express();
const cors = require('cors')
var session = require('express-session');
require("dotenv").config()
const db_url = process.env.MONGO_URL
app.use(session({
cookie: {
httpOnly: true
},
rolling: true,
resave: true,
saveUninitialized: true,
secret: '~~~~~'
}));
app.set('view engine','ejs');
app.use(express.static('public'));
//app.use(express.json());
app.use(cors())
app.use('/', router)
app.use('/', account)
async function startApp(){
try{
await mongoose.connect(db_url, {
useUnifiedTopology: true,
useNewUrlParser:true
})
app.listen(4242, () => {console.log("server is working")})
} catch(e) {
console.log("some error appearead" + e)
}
}
startApp()
Normally when you see this error, it means that, either the HTTP request body Stripe sent to your webhook handler has been altered in some way or You may not be using the correct webhook secret.
The most likely reason it is throwing an exception is because your router is parsing body as JSON with router.use(express.json()). constructEvent requires the raw, unparsed body you receive from the request to verify the signature. To verify you have the raw body you can print it out and see if you get something like <Buffer 28 72 10..>
You can tell your router to keep the request body raw by setting something like this on your route router.use('/webhook', express.raw({type: "*/*"}))
I found the solution for my problem.
What i added is
app.use( "/webhook",express.raw({ type: "*/*" }))
in my server.js file.

req.body is undefined after installing express-static-gzip

I recently added express-static-gzip to my server and have since noticed that my req.body is undefined in my router.post when submitting a form.
Previously it was working without issue but now I am getting a POST 500 internal server error, a Cannot read property "name" of undefined & a Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 error.
here is my form submission:
const handleSubmit = async (e) => {
e.preventDefault();
setStatus("Sending...");
const { name, email, message } = e.target.elements;
let details = {
name: name.value,
email: email.value,
message: message.value,
};
console.log(typeof JSON.stringify(details))
let response = await fetch("/api/v1/mail", {
method: "POST",
headers: {
"Content-Type": "application/json;charset=utf-8"
},
body: JSON.stringify(details),
});
setStatus("Send Message");
let result = await response.json();
alert(result.status);
};
here is my server setup, the route in question is '/api/v1/mail':
const express = require('express')
const path = require('path')
const router = express.Router();
const cors = require("cors");
var expressStaticGzip = require("express-static-gzip")
const mailRoutes = require('./routes/mail');
const server = express()
server.use('/api/v1/mail', mailRoutes)
server.use(cors())
server.use(express.json())
server.use("/", router)
server.use(expressStaticGzip(path.join(__dirname, 'public'), {
enableBrotli: true
}))
server.use(express.static(path.join(__dirname, 'public')))
and here is my POST request:
router.post("/", (req, res) => {
const name = req.body.name;
const email = req.body.email;
const orderId = req.body.orderId
const message = req.body.message;
const mail = {
from: name,
to: "info#example.com ",
subject: "Contact Form Submission",
html: `<p>Name: ${name}</p>
<p>Email: ${email}</p>
<p>Order ID: ${orderId}
<p>Message: ${message}</p>`,
};
contactEmail.sendMail(mail, (error) => {
if (error) {
res.json({ status: "ERROR" , req});
} else {
res.json({ status: "Message Sent" });
}
});
});
})
If the route you're trying to use req.body.name in is this one:
server.use('/api/v1/mail', mailRoutes)
Then, you have to move this:
server.use(express.json())
to be BEFORE that route definition.
As it is, you're trying to handle the route request before your middleware has read and parsed the JSON. Route handlers and middleware are matched and executed in the order they are registered. So, any middleware that needs to execute for a route handler to function must be registered before the route handler itself is registered.

Slackbot not able to pick up messages

I'm trying to create a simple slackbot and I can get the thing to run on start and almost anything else, but it will not pick up incoming messages from any channel. It's not generating any errors what so ever which makes it very frusterating.
things I've tried so far:
adding the bot to the channel
console logging inside the message block
adding a catch
No matter what I do the bot seems to just outright ignore the prompt "on.message". I don't get it. My code is below.
require("dotenv").config();
const { WebClient } = require("#slack/web-api");
const { createEventAdapter } = require("#slack/events-api");
const slackEvents = createEventAdapter(process.env.SLACK_SIGNING_SECRET);
const { RTMClient } = require("#slack/rtm-api");
const axios = require('axios')
const sgMail = require("#sendgrid/mail");
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const express = require("express");
const bodyParser = require("body-parser");
const pool = require("./pool");
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("build"));
let config = {
headers: {
"X-Auth-Client": process.env.BG_AUTH_CLIENT,
"X-Auth-Token": process.env.BG_AUTH_TOKEN,
},
};
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
console.log("server running on: ", PORT);
});
const token = process.env.SLACK_TOKEN;
const web = new WebClient(token);
const conversationId = "C0139RJPUEM";
// The client is initialized and then started to get an active connection to the platform
const rtm = new RTMClient(token);
slackEvents.on('error', console.error);
slackEvents.start().then(() => {
(async () => {
const res = await web.chat.postMessage({
icon_emoji: ":email:",
channel: conversationId,
text: "Testing connection",
});
message
console.log("Message sent: ", res.ts);
})();
console.log("bot listening on port", PORT);
});
slackEvents.on("message", (event) => {
console.log(
`Received a message event: user ${event.user} in channel ${event.channel} says ${event.text}`
);
(async () => {
// See: https://api.slack.com/methods/chat.postMessage
const res = await web.chat.postMessage({
icon_emoji: ":email:",
channel: conversationId,
text: "Testing message",
});
// `res` contains information about the posted message
console.log("Message sent: ", res.ts);
})();
// }
});
I think I got it, I was using a library that was not compatible, plus I didn't set up API event subscriptions and a few other dumb things. Oh well. Hopefully this will help someone who might casually come across this.

Request origin cannot be verified - Shopify

I'm developing an app for Shopify. Currently under development stage. Until now, I have successfully managed to authorise the app and then redirect it back to admin page using the Embedded App SDK. However, when I return to the admin page, it gives me an error saying Request origin cannot be verified.
The console shows Failed to load resource: the server responded with a status of 403 (Forbidden)
The URL in the console is something like this https://myshop.myshopify.com/admin/apps/dfdjf4343343434343434bfdf/shopify/shopify/callback?code=ffdfdffd&hmac=fdfdfdfdfdfdfdfdfddfdfdfdfdf&shop=myshop.myshopify.com&state=151193864548800&timestamp=1511938648
The fdfdfdfdfdfdfdfdfddfdfdfdfdf are just random characters that I've replaced instead of a hash. FYI - I've removed the app name and user profile name and avatar from the image.
This is happening because, you are unable to match state, that is set in cookie, while responding with redirect url
const ShopifyToken = require('shopify-token')
const forwardingAddress = process.env.HOST
const shopifyToken = new ShopifyToken({
sharedSecret: process.env.SHOPIFY_API_SECRET,
redirectUri: forwardingAddress + '/shopify/callback',
apiKey: process.env.SHOPIFY_API_KEY
})
const shopify = {
// use this for authentication
auth: (req, res, next) => {
const shop = req.query.shop
if (!shop) {
return res.status(400).send('Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request')
}
const shopRegex = /^([\w-]+)\.myshopify\.com/i
const shopName = shopRegex.exec(shop)[1]
const state = shopifyToken.generateNonce()
const url = shopifyToken.generateAuthUrl(shopName, scopes, state)
res.cookie('state', state)
res.redirect(url)
},
// use this as your callback function
authCallback: async (req, res) => {
const { shop, hmac, code, state } = req.query
const stateCookie = cookie.parse(req.headers.cookie).state
if (state !== stateCookie) {
// you are unable to set proper state ("nonce") in this case, thus you are getting this error
return res.status(403).send('Request origin cannot be verified')
}
if (!shop || !hmac || !code) {
res.status(400).send('Required parameters missing')
}
let hmacVerified = shopifyToken.verifyHmac(req.query)
console.log(`verifying -> ${hmacVerified}`)
// DONE: Validate request is from Shopify
if (!hmacVerified) {
return res.status(400).send('HMAC validation failed')
}
const accessToken = await shopifyToken.getAccessToken(shop, code)
const shopRequestUrl = 'https://' + shop + '/admin/shop.json'
const shopRequestHeaders = {
'X-Shopify-Access-Token': accessToken
}
try {
const shopResponse = await request.get(shopRequestUrl, { headers: shopRequestHeaders })
res.status(200).end(shopResponse)
} catch (error) {
res.status(error.statusCode).send(error.error.error_description)
}
}
}
Simple as this is, also make sure that the protocol matches from what you typed in to start the app install.
If you accidentally use http for http://you.ngrok.io/ but your callback redirects to https (i.e. https://you.ngrok.io/auth/callback), the OAuth handshake will fail.
const express = require('express');
const router = express.Router();
const dotenv = require('dotenv').config();
const cookie = require('cookie');
const requestPromise = require('request-promise');
const ShopifyToken = require('shopify-token');
const scopes = "write_products";
const forwardingAddress = process.env.HOST;
var shopifyToken = new ShopifyToken({
sharedSecret: process.env.SHOPIFY_API_SECRET,
redirectUri: forwardingAddress + '/shopify/callback',
apiKey: process.env.SHOPIFY_API_KEY
})
router.get('/shopify', (req, res) => {
const shop = req.query.shop;
if (!shop) {
return res.status(400).send('Missing shop parameter. Please add ?shop=your-development-shop.myshopify.com to your request')
}
const shopRegex = /^([\w-]+)\.myshopify\.com/i
const shopName = shopRegex.exec(shop)[1]
const state = shopifyToken.generateNonce();
const url = shopifyToken.generateAuthUrl(shopName, scopes, state);
res.cookie('state', state);
res.redirect(url);
});
router.get('/shopify/callback', (req, res) => {
const { shop, hmac, code, state } = req.query;
const stateCookie = cookie.parse(req.headers.cookie).state;
if (state !== stateCookie) {
// you are unable to set proper state ("nonce") in this case, thus you are getting this error
return res.status(403).send('Request origin cannot be verified')
}
if (!shop || !hmac || !code) {
res.status(400).send('Required parameters missing')
}
let hmacVerified = shopifyToken.verifyHmac(req.query)
console.log(`verifying -> ${hmacVerified}`)
// DONE: Validate request is from Shopify
if (!hmacVerified) {
return res.status(400).send('HMAC validation failed')
}
const accessToken = shopifyToken.getAccessToken(shop, code);
const shopRequestUrl = 'https://' + shop + '/admin/products.json'
const shopRequestHeaders = {
'X-Shopify-Access-Token': accessToken
}
try {
const shopResponse = requestPromise.get(shopRequestUrl, { headers: shopRequestHeaders })
res.status(200).send(shopResponse)
} catch (error) {
res.status(error.statusCode).send(error.error.error_description)
}
});
module.exports = router;