feat: dev environment backend setup (#278)
* feat: add anvil (qanet) to hardhat config networks. * chore: deploy contract to anvil testnet. * chore: sepolia deployment. * merge: authentication sls. * feat: separate the issignaturevalid function from handlers. * feat: update subgraph config to match the qa network. * feat: add app specific prisma schema to deploy script copy command. * fix: merge conflict * feat: remove unnecessary conditions. --------- Co-authored-by: Nima Rasooli <nimarasooli1@gmail.com>
This commit is contained in:
parent
948f926c92
commit
86907836ae
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"FleekERC721": [
|
||||
{
|
||||
"address": "0x1CfD8455F189c56a4FBd81EB7D4118DB04616BA8",
|
||||
"timestamp": "6/16/2023, 8:51:33 AM"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"FleekERC721": [
|
||||
{
|
||||
"address": "0x40208b6aFfCc39CD42A25EC47B410Cfe117837D6",
|
||||
"timestamp": "6/16/2023, 12:21:27 PM"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -25,6 +25,7 @@ const {
|
|||
ETH_GOERLI_API_URL,
|
||||
MAINNET_API_KEY,
|
||||
COINMARKETCAP_KEY,
|
||||
QANET_RPC_URL,
|
||||
} = process.env;
|
||||
|
||||
const config: HardhatUserConfig = {
|
||||
|
|
@ -59,6 +60,11 @@ const config: HardhatUserConfig = {
|
|||
accounts: PRIVATE_KEY ? [PRIVATE_KEY] : [],
|
||||
chainId: 1,
|
||||
},
|
||||
qanet: {
|
||||
url: QANET_RPC_URL ? QANET_RPC_URL : '',
|
||||
accounts: PRIVATE_KEY ? [PRIVATE_KEY] : [],
|
||||
chainId: 31337,
|
||||
},
|
||||
local: {
|
||||
url: 'http://localhost:8545',
|
||||
accounts: PRIVATE_KEY ? [PRIVATE_KEY] : [],
|
||||
|
|
|
|||
|
|
@ -5,12 +5,11 @@
|
|||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "yarn tsc",
|
||||
"invoke:build": "yarn build && serverless invoke local --function submitBuildInfo",
|
||||
"prisma:generate": "npx prisma generate",
|
||||
"prisma:pull": "npx prisma db pull --force",
|
||||
"start": "yarn build && serverless offline",
|
||||
"generate:layers": "./scripts/prepare-prisma-client-lambda-layer.sh && ./scripts/prepare-libs-lambda-layer.sh && ./scripts/prepare-node-modules-lambda-layer.sh",
|
||||
"deploy:dev": "yarn build && yarn generate:layers && yarn sls deploy --stage dev"
|
||||
"deploy:dev": "sh ./scripts/deploy.sh dev",
|
||||
"deploy:prd": "sh ./scripts/deploy.sh prd"
|
||||
},
|
||||
"author": "fleek",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
|
|
@ -79,12 +79,16 @@ echo "${bold}Copying the Prisma schema file to function directories${normal}"
|
|||
cp prisma/schema.prisma dist/src/functions/builds/
|
||||
cp prisma/schema.prisma dist/src/functions/mints/
|
||||
|
||||
echo "${bold}Generating Prisma Client${normal}"
|
||||
yarn prisma:generate
|
||||
|
||||
echo "${bold}Running the build command${normal}"
|
||||
yarn build
|
||||
|
||||
echo "${bold}Copying the rhel openssl engine to dist/${normal}"
|
||||
cp node_modules/.prisma/client/libquery_engine-rhel-openssl-1.0.x.so.node dist/src/functions/mints
|
||||
cp node_modules/.prisma/client/libquery_engine-rhel-openssl-1.0.x.so.node dist/src/functions/builds
|
||||
cp node_modules/.prisma/client/libquery_engine-rhel-openssl-1.0.x.so.node dist/src/functions/apps
|
||||
|
||||
echo "${bold}Copying the .env file to dist/${normal}"
|
||||
cp .env src/
|
||||
|
|
@ -95,9 +99,7 @@ cp src/libs/FleekERC721.json dist/src/libs/
|
|||
echo "${bold}Copying the Prisma schema file to function directories${normal}"
|
||||
cp prisma/schema.prisma dist/src/functions/builds/
|
||||
cp prisma/schema.prisma dist/src/functions/mints/
|
||||
|
||||
echo "${bold}Generating Prisma Client${normal}"
|
||||
yarn prisma:generate
|
||||
cp prisma/schema.prisma dist/src/functions/apps/
|
||||
|
||||
echo "${bold}Creating layer zip files${normal}"
|
||||
/bin/bash ./scripts/prepare-libs-lambda-layer.sh
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ provider:
|
|||
runtime: nodejs18.x
|
||||
stage: ${opt:stage, 'prd'}
|
||||
region: ${opt:region, 'us-west-2'}
|
||||
timeout: 40
|
||||
apiGateway:
|
||||
minimumCompressionSize: 1024
|
||||
shouldStartNameWithService: true
|
||||
|
|
@ -88,7 +87,7 @@ functions:
|
|||
- { Ref: TopicPrismaAwsPrismaClientLambdaLayer }
|
||||
|
||||
verifyAccessPoint:
|
||||
handler: src/functions/apps/handler.verifyApp
|
||||
handler: ./dist/src/functions/apps/handler.verifyApp
|
||||
events:
|
||||
- http:
|
||||
path: verifyApp
|
||||
|
|
@ -96,7 +95,7 @@ functions:
|
|||
cors: true
|
||||
|
||||
submitAppInfo:
|
||||
handler: src/functions/apps/handler.submitAppInfo
|
||||
handler: ./dist/src/functions/apps/handler.submitAppInfo
|
||||
events:
|
||||
- http:
|
||||
path: app
|
||||
|
|
|
|||
|
|
@ -9,24 +9,7 @@ import {
|
|||
CreatePullZoneMethodArgs,
|
||||
LoadFreeCertificateMethodArgs,
|
||||
} from '@libs/bunnyCDN';
|
||||
import * as crypto from "crypto";
|
||||
|
||||
function isTheSignatureValid(
|
||||
body: string, // must be raw string body, not json transformed version of the body
|
||||
signature: string, // the "lambda-signature" from header
|
||||
signingKey: string, // signing secret key for front-end
|
||||
) {
|
||||
const hmac = crypto.createHmac("sha256", signingKey); // Create a HMAC SHA256 hash using the signing key
|
||||
hmac.update(body, "utf8"); // Update the token hash with the request body using utf8
|
||||
const digest = hmac.digest("hex");
|
||||
if (signature !== digest) {
|
||||
// the request is not valid
|
||||
return formatJSONResponse({
|
||||
status: 401,
|
||||
message: 'Unauthorized',
|
||||
});
|
||||
}
|
||||
}
|
||||
import { isTheSignatureValid } from '@libs/verify-signature';
|
||||
|
||||
export const verifyApp = async (
|
||||
event: APIGatewayEvent
|
||||
|
|
@ -34,7 +17,7 @@ export const verifyApp = async (
|
|||
try {
|
||||
// Check the parameters and environment variables
|
||||
dotenv.config();
|
||||
if (event.body === null || process.env.BUNNY_CDN_ACCESS_KEY == undefined) {
|
||||
if (event.body === null || process.env.BUNNY_CDN_ACCESS_KEY === undefined) {
|
||||
return formatJSONResponse({
|
||||
status: 422,
|
||||
message: 'Required parameters were not passed.',
|
||||
|
|
@ -43,10 +26,23 @@ export const verifyApp = async (
|
|||
|
||||
// Check the lambda-signature and confirm the value of the FE_SIGNING_KEY env variable.
|
||||
// If both are valid, verify the authenticity of the request.
|
||||
if (event.headers["lambda-signature"] === undefined) throw Error("Header field 'lambda-signature' was not found.");
|
||||
|
||||
if (process.env.FE_SIGNING_KEY === undefined) throw Error("FE_SIGNING_KEY env variable not found.");
|
||||
else { isTheSignatureValid(event.body, event.headers["lambda-signature"], process.env.FE_SIGNING_KEY); };
|
||||
if (event.headers['lambda-signature'] === undefined)
|
||||
throw Error("Header field 'lambda-signature' was not found.");
|
||||
|
||||
if (process.env.FE_SIGNING_KEY === undefined)
|
||||
throw Error('FE_SIGNING_KEY env variable not found.');
|
||||
else if (
|
||||
!isTheSignatureValid(
|
||||
event.body,
|
||||
event.headers['lambda-signature'],
|
||||
process.env.FE_SIGNING_KEY
|
||||
)
|
||||
) {
|
||||
return formatJSONResponse({
|
||||
status: 401,
|
||||
message: 'Unauthorized',
|
||||
});
|
||||
}
|
||||
|
||||
// Set up constants
|
||||
const bunnyCdn = new BunnyCdn(process.env.BUNNY_CDN_ACCESS_KEY);
|
||||
|
|
@ -75,7 +71,7 @@ export const submitAppInfo = async (
|
|||
try {
|
||||
// Check the parameters and environment variables
|
||||
dotenv.config();
|
||||
if (event.body === null || process.env.BUNNY_CDN_ACCESS_KEY == undefined || event.headers.originUrl === undefined) {
|
||||
if (event.body === null || process.env.BUNNY_CDN_ACCESS_KEY === undefined) {
|
||||
return formatJSONResponse({
|
||||
status: 422,
|
||||
message: 'Required parameters were not passed.',
|
||||
|
|
@ -84,10 +80,23 @@ export const submitAppInfo = async (
|
|||
|
||||
// Check the lambda-signature and confirm the value of the FE_SIGNING_KEY env variable.
|
||||
// If both are valid, verify the authenticity of the request.
|
||||
if (event.headers["lambda-signature"] === undefined) throw Error("Header field 'lambda-signature' was not found.");
|
||||
|
||||
if (process.env.FE_SIGNING_KEY === undefined) throw Error("FE_SIGNING_KEY env variable not found.");
|
||||
else { isTheSignatureValid(event.body, event.headers["lambda-signature"], process.env.FE_SIGNING_KEY); };
|
||||
if (event.headers['lambda-signature'] === undefined)
|
||||
throw Error("Header field 'lambda-signature' was not found.");
|
||||
|
||||
if (process.env.FE_SIGNING_KEY === undefined)
|
||||
throw Error('FE_SIGNING_KEY env variable not found.');
|
||||
else if (
|
||||
!isTheSignatureValid(
|
||||
event.body,
|
||||
event.headers['lambda-signature'],
|
||||
process.env.FE_SIGNING_KEY
|
||||
)
|
||||
) {
|
||||
return formatJSONResponse({
|
||||
status: 401,
|
||||
message: 'Unauthorized',
|
||||
});
|
||||
}
|
||||
|
||||
// Set up constants
|
||||
const bunnyCdn = new BunnyCdn(process.env.BUNNY_CDN_ACCESS_KEY);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export const submitBuildInfo = async (
|
|||
domain: data.domain,
|
||||
verificationTransactionHash: 'Not verified.',
|
||||
};
|
||||
|
||||
|
||||
// Add build record to the database, if it's not already added
|
||||
const buildRecord = await prisma.builds.findMany({
|
||||
where: {
|
||||
|
|
@ -37,10 +37,9 @@ export const submitBuildInfo = async (
|
|||
domain: buildInfo.domain,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
if (buildRecord.length == 0) {
|
||||
|
||||
|
||||
await prisma.builds.create({
|
||||
data: {
|
||||
githubRepository: buildInfo.githubRepository,
|
||||
|
|
|
|||
|
|
@ -7,24 +7,8 @@ import { formatJSONResponse } from '@libs/api-gateway';
|
|||
import { v4 } from 'uuid';
|
||||
import { initPrisma, prisma } from '@libs/prisma';
|
||||
import { contractInstance, web3 } from '@libs/nfa-contract';
|
||||
import * as crypto from "crypto";
|
||||
|
||||
function isTheSignatureValid(
|
||||
body: string, // must be raw string body, not json transformed version of the body
|
||||
signature: string, // the "x-alchemy-signature" from header
|
||||
signingKey: string, // taken from dashboard for specific webhook
|
||||
) {
|
||||
const hmac = crypto.createHmac("sha256", signingKey); // Create a HMAC SHA256 hash using the signing key
|
||||
hmac.update(body, "utf8"); // Update the token hash with the request body using utf8
|
||||
const digest = hmac.digest("hex");
|
||||
if (signature !== digest) {
|
||||
// the request is not valid
|
||||
return formatJSONResponse({
|
||||
status: 401,
|
||||
message: 'Unauthorized',
|
||||
});
|
||||
}
|
||||
}
|
||||
import { isTheSignatureValid } from '@libs/verify-signature';
|
||||
import { ethers } from 'ethers';
|
||||
|
||||
export const submitMintInfo = async (
|
||||
event: APIGatewayEvent
|
||||
|
|
@ -40,14 +24,39 @@ export const submitMintInfo = async (
|
|||
|
||||
// Check the alchemy signature and confirm the value of the ALCHEMY_SIGNING_KEY env variable.
|
||||
// If both are valid, verify the authenticity of the request.
|
||||
if (event.headers["x-alchemy-signature"] === undefined) throw Error("Header field 'x-alchemy-signature' was not found.");
|
||||
|
||||
if (process.env.ALCHEMY_SIGNING_KEY === undefined) throw Error("ALCHEMY_SIGNING_KEY env variable not found.");
|
||||
else { isTheSignatureValid(event.body, event.headers["x-alchemy-signature"], process.env.ALCHEMY_SIGNING_KEY); };
|
||||
if (event.headers['x-alchemy-signature'] === undefined)
|
||||
throw Error("Header field 'x-alchemy-signature' was not found.");
|
||||
|
||||
if (process.env.ALCHEMY_SIGNING_KEY === undefined)
|
||||
throw Error('ALCHEMY_SIGNING_KEY env variable not found.');
|
||||
else if (
|
||||
!isTheSignatureValid(
|
||||
event.body,
|
||||
event.headers['x-alchemy-signature'],
|
||||
process.env.ALCHEMY_SIGNING_KEY
|
||||
)
|
||||
) {
|
||||
return formatJSONResponse({
|
||||
status: 401,
|
||||
message: 'Unauthorized',
|
||||
});
|
||||
}
|
||||
|
||||
const id = v4();
|
||||
|
||||
const eventBody = JSON.parse(event.body);
|
||||
|
||||
if (
|
||||
eventBody.event.data.block.logs[1].topics[0] !=
|
||||
ethers.utils.id(
|
||||
'NewMint(uint256,string,string,string,string,string,string,string,string,uint24,bool,address,address,address)'
|
||||
) // The first topic should be equal to the hash of the event name and its parameter types
|
||||
) {
|
||||
throw Error(
|
||||
'The emitted event is not `NewMint`. This request is ignored.'
|
||||
);
|
||||
}
|
||||
|
||||
const topics = eventBody.event.data.block.logs[1].topics.slice(1, 4);
|
||||
const hexCalldata = eventBody.event.data.block.logs[1].data;
|
||||
const decodedLogs = web3.eth.abi.decodeLog(
|
||||
|
|
@ -150,7 +159,7 @@ export const submitMintInfo = async (
|
|||
owner: decodedLogs.owner,
|
||||
ipfsHash: decodedLogs.ipfsHash,
|
||||
domain: decodedLogs.externalURL,
|
||||
verificationTransactionHash: 'Not verified'
|
||||
verificationTransactionHash: 'Not verified',
|
||||
};
|
||||
|
||||
initPrisma();
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
|||
import axios, { AxiosRequestConfig, AxiosError } from 'axios';
|
||||
import axios, { AxiosRequestConfig } from 'axios';
|
||||
|
||||
type BunnyCdnErrorOptions = {
|
||||
name: string;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
import * as crypto from 'crypto';
|
||||
|
||||
export function isTheSignatureValid(
|
||||
body: string, // must be raw string body, not json transformed version of the body
|
||||
signature: string, // the "lambda-signature" from header
|
||||
signingKey: string // signing secret key for front-end
|
||||
): boolean {
|
||||
const hmac = crypto.createHmac('sha256', signingKey); // Create a HMAC SHA256 hash using the signing key
|
||||
hmac.update(body, 'utf8'); // Update the token hash with the request body using utf8
|
||||
const digest = hmac.digest('hex');
|
||||
return signature === digest; // returns true for valid and false for invalid
|
||||
}
|
||||
|
|
@ -3,11 +3,11 @@ schema:
|
|||
dataSources:
|
||||
- kind: ethereum
|
||||
name: FleekNFA
|
||||
network: goerli
|
||||
network: mainnet # Works with the Anvil QA network also
|
||||
source:
|
||||
address: "0x8795608346Eb475E42e69F1281008AEAa522479D" # <- Proxy Contract
|
||||
address: "0x1CfD8455F189c56a4FBd81EB7D4118DB04616BA8" # <- Proxy Contract
|
||||
abi: FleekNFA
|
||||
startBlock: 8671990
|
||||
# startBlock: 8671990
|
||||
mapping:
|
||||
kind: ethereum/events
|
||||
apiVersion: 0.0.7
|
||||
|
|
@ -32,7 +32,7 @@ dataSources:
|
|||
- ChangeAccessPointAutoApproval
|
||||
abis:
|
||||
- name: FleekNFA
|
||||
file: ../contracts/artifacts/contracts/FleekERC721.sol/FleekERC721.json
|
||||
file: ../contracts/deployments/qanet/FleekERC721.json
|
||||
eventHandlers:
|
||||
- event: Approval(indexed address,indexed address,indexed uint256)
|
||||
handler: handleApproval
|
||||
|
|
|
|||
Loading…
Reference in New Issue