First time trying to deploy Smart Contract: Error HH100: Network polygon_mumbai doesn't exist - solidity

I am trying to deploy my first contract for Polygon Mumbai but I am getting the erro message Error HH100: Network polygon_mumbai doesn't exist
How should i fix
Here is my hardhat configure
/** #type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.17",
};
/**
* #type import('hardhat/config').HardhatUserConfig
*/
require('dotenv').config();
require("#nomiclabs/hardhat-ethers");
const { API_URL, PRIVATE_KEY } = process.env;
module.exports = {
solidity: "0.8.9",
defaultNetwork: "polygon_mumbai",
networks: {
hardhat: {},
polygon_mumbai: {
url: API_URL,
accounts: [`0x${PRIVATE_KEY}`]
}
},
}
this is what my deployjs file looks like
async function main() {
const GoodMorning = await ethers.getContractFactory("GoodMorning");
// Start deployment, returning a promise that resolves to a contract object
const good_morning = await GoodMorning.deploy("gm everyone");
console.log("Contract deployed to address:", good_morning.address);
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});

Related

Shopify App hosted on fly.io oAuth/Auth callbacks failing

Currently I am trying to deploy my Shopify Custom App to Fly.io. Installing this app is succeeding on my development store but I get an error right after with the oAuth callback with status code 400. This is the URL it shows upon installing:
https://appname.fly.dev/api/auth/callback?code=71bfdaadd63b87eb72d9d3dc516ea1ea&hmac=1efd4ff63ebca8f28c733f464ded354ba2f0995aeb1910114e0139eaefd4cce3&host=YWRtaW4uc2hvcGlmeS5jb20vc3RvcmUvc2hvb3B5bG9vcHkx&shop=shoopyloopy1.myshopify.com&state=920113322594675&timestamp=1676563785
With text in body: Invalid OAuth callback.
The app works with all the callbacks working with a ngrok tunnel during development. Just not when deployed to fly.io. The apps frontend also works after deployment to fly.io, but all the api and auth callbacks fail to work. I get the following response on those API calls:
On performing API calls on the /api/ route I get the following error in the return of the api call:
Failed to parse session token 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczpcL1wvc2hvb3B5bG9vcHkxLm15c2hvcGlmeS5jb21cL2FkbWluIiwiZGVzdCI6Imh0dHBzOlwvXC9zaG9vcHlsb29weTEubXlzaG9waWZ5LmNvbSIsImF1ZCI6IjU4YTAzZjkwZTk4Yjc5NGRlZmE5NDZlMWZiNmVlMzRiIiwic3ViIjoiNzQ3NzAxNTM2NjEiLCJleHAiOjE2NzY1NjQyMjYsIm5iZiI6MTY3NjU2NDE2NiwiaWF0IjoxNjc2NTY0MTY2LCJqdGkiOiI0OTcyNDEwOC0zNWQ2LTRjODEtOWJkNS0wZWRkMWM4MWIxMDYiLCJzaWQiOiIxOGZmZjg5NTMyZGRiODdiOWQ3OTBhYmY1M2EwOTZiMDNkNmE4ZWU1ZTA0ZmRjZmFmOWUxOWM2OGQxZGFjN2Q2In0.XeuA5W95YjjVLZYOvmRJ9a90xpPNEukhNQ1_z4Kw_xA': signature verification failed
My fly.toml file:
app = "appname"
kill_signal = "SIGINT"
kill_timeout = 5
processes = []
[env]
PORT = "8081"
HOST = "https://appname.fly.dev"
SHOPIFY_API_KEY = "58a03f90e98b794defa946e1fb6ee34b"
SCOPES = "write_products,read_script_tags,write_script_tags"
[experimental]
auto_rollback = true
[[services]]
http_checks = []
internal_port = 8081
processes = ["app"]
protocol = "tcp"
script_checks = []
[services.concurrency]
hard_limit = 25
soft_limit = 20
type = "connections"
[[services.ports]]
force_https = true
handlers = ["http"]
port = 80
[[services.ports]]
handlers = ["tls", "http"]
port = 443
[[services.tcp_checks]]
grace_period = "1s"
interval = "15s"
restart_limit = 0
timeout = "2s"
My index.js file starting up express:
// #ts-check
import { join } from "path";
import { readFileSync } from "fs";
import express from "express";
import serveStatic from "serve-static";
import shopify from "./shopify.js";
import productCreator from "./product-creator.js";
import GDPRWebhookHandlers from "./gdpr.js";
import {addScriptTag, deleteScriptTag, getProductInfo, getProductsFromIds, getScriptTags} from "./graph-functions.js";
const PORT = parseInt(process.env.BACKEND_PORT || process.env.PORT, 10);
const STATIC_PATH =
process.env.NODE_ENV === "production"
? `${process.cwd()}/frontend/dist`
: `${process.cwd()}/frontend/`;
const app = express();
// Set up Shopify authentication and webhook handling
app.get(shopify.config.auth.path, shopify.auth.begin());
app.get(
shopify.config.auth.callbackPath,
shopify.auth.callback(),
shopify.redirectToShopifyOrAppRoot()
);
app.post(
shopify.config.webhooks.path,
shopify.processWebhooks({ webhookHandlers: GDPRWebhookHandlers })
);
// All endpoints after this point will require an active session
app.use("/api/*", shopify.validateAuthenticatedSession());
app.use(express.json());
app.get("/api/products/count", async (_req, res) => {
const countData = await shopify.api.rest.Product.count({
session: res.locals.shopify.session,
});
res.status(200).send(countData);
});
app.get("/api/get-product", async (_req, res) => {
const products = await getProductInfo(res.locals.shopify.session, _req.query.id);
res.status(200).send(products);
});
app.get("/api/get-products", async (_req, res) => {
const products = await getProductsFromIds(res.locals.shopify.session,_req.query.ids);
res.status(200).send(products);
});
app.get("/api/add-script", async (_req, res) => {
const data = await addScriptTag(res.locals.shopify.session,_req.query.src);
console.log(_req.query.ids);
res.status(200).send(data);
});
app.get("/api/get-scripts", async (_req, res) => {
const data = await getScriptTags(res.locals.shopify.session);
res.status(200).send(data?.body?.data ? data?.body?.data : data);
});
app.get("/api/delete-script", async (_req, res) => {
const data = await deleteScriptTag(res.locals.shopify.session,_req.query.id);
res.status(200).send(data);
});
app.get("/api/products/create", async (_req, res) => {
let status = 200;
let error = null;
try {
await productCreator(res.locals.shopify.session);
} catch (e) {
console.log(`Failed to process products/create: ${e.message}`);
status = 500;
error = e.message;
}
res.status(status).send({ success: status === 200, error });
});
app.use(serveStatic(STATIC_PATH, { index: false }));
app.use("/*", shopify.ensureInstalledOnShop(), async (_req, res, _next) => {
return res
.status(200)
.set("Content-Type", "text/html")
.send(readFileSync(join(STATIC_PATH, "index.html")));
});
app.listen(PORT);
Any help would be highly appreciated.
I followed the official documentation: Shopify Official Docs
The Dockerfile has the same port 8081 as assigned to in the fly.toml file.
Edit (Added shopify app implementation with Database):
import { LATEST_API_VERSION } from "#shopify/shopify-api";
import { shopifyApp } from "#shopify/shopify-app-express";
import { SQLiteSessionStorage } from "#shopify/shopify-app-session-storage-sqlite";
import { restResources } from "#shopify/shopify-api/rest/admin/2023-01";
const DB_PATH = `${process.cwd()}/database.sqlite`;
const shopify = shopifyApp({
api: {
apiVersion: LATEST_API_VERSION,
restResources,
billing: undefined, // or replace with billingConfig above to enable example billing
},
auth: {
path: "/api/auth",
callbackPath: "/api/auth/callback",
},
webhooks: {
path: "/api/webhooks",
},
// This should be replaced with your preferred storage strategy
sessionStorage: new SQLiteSessionStorage(DB_PATH),
});
export default shopify;

Shopify node.js and react.js plugin with vite.js not working

I've created a plugin in shopify using node.js & vite.js.
shopify app create node
After running using npm run dev, it generates a url like this: https://b136-0000-7400-56-bc78-5000-178b-d6f3-6000.ngrok.io/login?shop=shopname.myshopify.com
When I open this link, it start reloading infinite with error
This is my index.js:
import { resolve } from "path";
import express from "express";
import cookieParser from "cookie-parser";
import { Shopify, LATEST_API_VERSION } from "#shopify/shopify-api";
import "dotenv/config";
import applyAuthMiddleware from "./middleware/auth.js";
import verifyRequest from "./middleware/verify-request.js";
const USE_ONLINE_TOKENS = true;
const TOP_LEVEL_OAUTH_COOKIE = "shopify_top_level_oauth";
const PORT = parseInt(process.env.PORT || "8081", 10);
const isTest = process.env.NODE_ENV === "test" || !!process.env.VITE_TEST_BUILD;
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: LATEST_API_VERSION,
IS_EMBEDDED_APP: true,
// This should be replaced with your preferred storage strategy
SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});
// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS = {};
Shopify.Webhooks.Registry.addHandler("APP_UNINSTALLED", {
path: "/webhooks",
webhookHandler: async (topic, shop, body) => {
delete ACTIVE_SHOPIFY_SHOPS[shop];
},
});
// export for test use only
export async function createServer(
root = process.cwd(),
isProd = process.env.NODE_ENV === "production"
) {
const app = express();
app.set("top-level-oauth-cookie", TOP_LEVEL_OAUTH_COOKIE);
app.set("active-shopify-shops", ACTIVE_SHOPIFY_SHOPS);
app.set("use-online-tokens", USE_ONLINE_TOKENS);
app.use(cookieParser(Shopify.Context.API_SECRET_KEY));
applyAuthMiddleware(app);
app.post("/webhooks", async (req, res) => {
try {
await Shopify.Webhooks.Registry.process(req, res);
console.log(`Webhook processed, returned status code 200`);
} catch (error) {
console.log(`Failed to process webhook: ${error}`);
if (!res.headersSent) {
res.status(500).send(error.message);
}
}
});
app.get("/products-count", verifyRequest(app), async (req, res) => {
const session = await Shopify.Utils.loadCurrentSession(
req,
res,
app.get("use-online-tokens")
);
const { Product } = await import(
`#shopify/shopify-api/dist/rest-resources/${Shopify.Context.API_VERSION}/index.js`
);
const countData = await Product.count({ session });
res.status(200).send(countData);
});
app.post("/graphql", verifyRequest(app), async (req, res) => {
try {
const response = await Shopify.Utils.graphqlProxy(req, res);
res.status(200).send(response.body);
} catch (error) {
res.status(500).send(error.message);
}
});
app.use(express.json());
app.use((req, res, next) => {
const shop = req.query.shop;
if (Shopify.Context.IS_EMBEDDED_APP && shop) {
res.setHeader(
"Content-Security-Policy",
`frame-ancestors https://${shop} https://admin.shopify.com;`
);
} else {
res.setHeader("Content-Security-Policy", `frame-ancestors 'none';`);
}
next();
});
app.use("/*", (req, res, next) => {
const { shop } = req.query;
// Detect whether we need to reinstall the app, any request from Shopify will
// include a shop in the query parameters.
if (app.get("active-shopify-shops")[shop] === undefined && shop) {
res.redirect(`/auth?${new URLSearchParams(req.query).toString()}`);
} else {
next();
}
});
/**
* #type {import('vite').ViteDevServer}
*/
let vite;
if (!isProd) {
vite = await import("vite").then(({ createServer }) =>
createServer({
root,
logLevel: isTest ? "error" : "info",
server: {
port: PORT,
hmr: {
protocol: "ws",
host: "localhost",
port: 64999,
clientPort: 64999,
},
middlewareMode: "html",
},
})
);
app.use(vite.middlewares);
} else {
const compression = await import("compression").then(
({ default: fn }) => fn
);
const serveStatic = await import("serve-static").then(
({ default: fn }) => fn
);
const fs = await import("fs");
app.use(compression());
app.use(serveStatic(resolve("dist/client")));
app.use("/*", (req, res, next) => {
// Client-side routing will pick up on the correct route to render, so we always render the index here
res
.status(200)
.set("Content-Type", "text/html")
.send(fs.readFileSync(`${process.cwd()}/dist/client/index.html`));
});
}
return { app, vite };
}
if (!isTest) {
createServer().then(({ app }) => app.listen(PORT));
}
The app is installing fine but it's getting refreshed again and again due to failed connection to ws (as mentioned in the screenshot). I tried a few things around changing the settings of the HMR but doesn't seem to be connecting.

Nextjs API inaccessiable in production

I am trying to host a NextJS app and everything seems to be working fine locally. I am able to get the data from the site and I can go to the site and see the raw json that is being returned, but when I try to get things working on production the API is completely inaccessible through the browser and through the Axios requests.
The server just returns 500 or Internal Server Error.
I have tried deploying on DigitalOcean App Platform and AWS Amplify, but both fail to connect to the API routes.
I followed this tutorial for the NextJS SSR method that says to build and start using
// next.config.js
const path = require('path')
const Dotenv = require('dotenv-webpack')
require('dotenv').config()
module.exports = {
webpack: (config) => {
config.plugins = config.plugins || []
config.module.rules.push({
test: /\.svg$/,
use: ["#svgr/webpack"]
});
config.plugins = [
...config.plugins,
// Read the .env file
new Dotenv({
path: path.join(__dirname, '.env'),
systemvars: true
})
]
return config
},
sassOptions: {
includePaths: [path.join(__dirname, 'styles')]
}
}
// package.json
...
"scripts": {
"dev": "next dev",
"build": "next build",
"digitalocean": "next start -H 0.0.0.0 -p ${PORT:-8080}",
"start": "next start"
},
...
// api.js
const axios = require('axios')
const {getS3URL} = require('./aws')
require('dotenv').config()
export default async (req, res) => {
const config = {
bucket: 'bucket',
key: 'folder/data.json'
}
const request = await axios.get(await getS3URL(config));
try {
res.status(200).json(JSON.stringify(request.data))
} catch {
res.status(500).json({ error: '500', response })
res.status(400).json({ error: '400', response })
}
}
// frontend.js
...
const getData = async () => {
console.log(`${host}api/daily-trip-stats`)
const trips = await axios.get(`${host}api/daily-trip-stats`)
const routes = await axios.get(`${host}api/daily-route-stats`)
const stops = await axios.get(`${host}api/daily-stops-routes`)
const cleanUp = async (data) => {
return await data.map(fea => fea.properties)
}
return {
routes: await cleanUp(routes.data.features),
trips: await cleanUp(trips.data.features),
stops: await cleanUp(stops.data.features)
}
};
...
Checked the server logs and found that the default region was not being set properly.
var { S3Client, GetObjectCommand, Config} = require('#aws-sdk/client-s3');
import { getSignedUrl } from "#aws-sdk/s3-request-presigner";
const getS3URL = async ({bucket, key}) => {
const client = new S3Client({
region: 'us-east-1' // !!! FORGOT TO SET THE DEFAULT REGION
})
var params = {
Bucket: bucket,
Key: key,
Expires: 60,
ContentType: 'blob'
};
const s3Data = new GetObjectCommand(params);
const url = await getSignedUrl(client, s3Data, { expiresIn: 3600 });
return url
};
module.exports = {getS3URL}

Apollo Server & 4xx status codes

Currently, my Apollo Server(running on HapiJS) returns HTTP 200 for every request, including failed ones.
I would like the GraphQL server to return HTTP 4xx for unsuccessful requests. The primary reason for it is that I want to set up monitoring for my ELB.
I know that Apollo Server has an engine platform, but I want to implement it using my current infrastructure.
Any ideas of how I could accomplish that? I tried to capture 'onPreResponse' event for my HapiJS server but I couldn't modify status code there.
After reading this answer. Here is a solution by modifying the hapijs plugin graphqlHapi of hapiApollo.ts file.
server.ts:
import { makeExecutableSchema } from 'apollo-server';
import { ApolloServer, gql } from 'apollo-server-hapi';
import Hapi from 'hapi';
import { graphqlHapi } from './hapiApollo';
const typeDefs = gql`
type Query {
_: String
}
`;
const resolvers = {
Query: {
_: () => {
throw new Error('some error');
},
},
};
const schema = makeExecutableSchema({ typeDefs, resolvers });
const port = 3000;
async function StartServer() {
const app = new Hapi.Server({ port });
graphqlHapi.register(app, { path: '/graphql', graphqlOptions: { schema } });
app.ext('onPreResponse', (request: any, h: any) => {
const response = request.response;
if (!response.isBoom) {
return h.continue;
}
return h.response({ message: response.message }).code(400);
});
await app.start();
}
StartServer()
.then(() => {
console.log(`apollo server is listening on http://localhost:${port}/graphql`);
})
.catch((error) => console.log(error));
hapiApollo.ts:
import Boom from 'boom';
import { Server, Request, RouteOptions } from 'hapi';
import { GraphQLOptions, runHttpQuery, convertNodeHttpToRequest } from 'apollo-server-core';
import { ValueOrPromise } from 'apollo-server-types';
export interface IRegister {
(server: Server, options: any, next?: Function): void;
}
export interface IPlugin {
name: string;
version?: string;
register: IRegister;
}
export interface HapiOptionsFunction {
(request?: Request): ValueOrPromise<GraphQLOptions>;
}
export interface HapiPluginOptions {
path: string;
vhost?: string;
route?: RouteOptions;
graphqlOptions: GraphQLOptions | HapiOptionsFunction;
}
const graphqlHapi: IPlugin = {
name: 'graphql',
register: (server: Server, options: HapiPluginOptions, next?: Function) => {
if (!options || !options.graphqlOptions) {
throw new Error('Apollo Server requires options.');
}
server.route({
method: ['GET', 'POST'],
path: options.path || '/graphql',
vhost: options.vhost || undefined,
options: options.route || {},
handler: async (request, h) => {
try {
const { graphqlResponse, responseInit } = await runHttpQuery([request, h], {
method: request.method.toUpperCase(),
options: options.graphqlOptions,
query:
request.method === 'post'
? // TODO type payload as string or Record
(request.payload as any)
: request.query,
request: convertNodeHttpToRequest(request.raw.req),
});
// add our custom error handle logic
const graphqlResponseObj = JSON.parse(graphqlResponse);
if (graphqlResponseObj.errors && graphqlResponseObj.errors.length) {
throw new Error(graphqlResponseObj.errors[0].message);
}
const response = h.response(graphqlResponse);
Object.keys(responseInit.headers as any).forEach((key) =>
response.header(key, (responseInit.headers as any)[key]),
);
return response;
} catch (error) {
// handle our custom error
if (!error.name) {
throw Boom.badRequest(error.message);
}
if ('HttpQueryError' !== error.name) {
throw Boom.boomify(error);
}
if (true === error.isGraphQLError) {
const response = h.response(error.message);
response.code(error.statusCode);
response.type('application/json');
return response;
}
const err = new Boom(error.message, { statusCode: error.statusCode });
if (error.headers) {
Object.keys(error.headers).forEach((header) => {
err.output.headers[header] = error.headers[header];
});
}
// Boom hides the error when status code is 500
err.output.payload.message = error.message;
throw err;
}
},
});
if (next) {
next();
}
},
};
export { graphqlHapi };
Now, when the GraphQL resolver throws an error, the client-side will receive our custom response with Http status code 400 instead of 200 status code with GraphQL errors response.
General from the browser:
Request URL: http://localhost:3000/graphql
Request Method: POST
Status Code: 400 Bad Request
Remote Address: 127.0.0.1:3000
Referrer Policy: no-referrer-when-downgrade
The response body is: {"message":"some error"}

Bundling express.js and next.js app throwing Error: Cannot find module next.config.js'

I have setup a express.js + next.js app, which is running fine in development environment. When I am trying to run its webpack bundle, Its throwing error
Error: Cannot find module '/Users/user/workspace/project/next.config.js'
I am trying to run its bundle as aws-lamda is not allowing me to upload zip size more than 50MB.
// server.js
const express = require('express');
const argv = require('yargs').argv;
const nextApp = require('./nextApp.js');
const handle = nextApp.getRequestHandler();
const pageRoutes = require('./routes/pages/index.js');
const port = argv.port || 3000;
const server = express();
// route to next.js web pages
server.use('/', pageRoutes);
server.get('*', (req, res) => {
return handle(req, res)
});
nextApp.prepare()
.then(() => {
server.listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
});
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
});
module.exports = server;
So far I have found that we can/should extends next.config.js for adding additional bundle entries instead of creating a separate webpack.config.js. Following config will create a serverbundle.js file in build/server directory.
const merge = require('webpack-merge');
module.exports = {
distDir: 'build',
webpack (config, {isServer}) {
if (isServer) {
return merge(config, {
entry () {
return config.entry().then((entry) => {
return Object.assign({}, entry, { serverbundle: './server' })
})
},
output: {
filename: '[name].js'
}
});
}
return config;
}
}