Skip to content

Commit

Permalink
Merge pull request #1640 from ten-protocol/jennifer/new-scan-config-s…
Browse files Browse the repository at this point in the history
…etup

Obscuroscan#2323
  • Loading branch information
Jennievon authored Nov 23, 2023
2 parents d37c0c7 + 507e17a commit 8712e26
Show file tree
Hide file tree
Showing 122 changed files with 13,596 additions and 0 deletions.
84 changes: 84 additions & 0 deletions .github/workflows/manual-deploy-obscuro-scan-3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Deploys Ten Scan on Azure for Testnet
# Builds the Ten Scan image, pushes the image to dockerhub and starts the Ten Scan on Azure

name: "[M] Deploy Ten Scan 3 Testnet"
run-name: "[M] Deploy Ten Scan Testnet ( ${{ github.event.inputs.testnet_type }} )"
on:
workflow_dispatch:
inputs:
testnet_type:
description: "Testnet Type"
required: true
default: "dev-testnet"
type: choice
options:
- "dev-testnet"
- "uat-testnet"
- "sepolia-testnet"

jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment:
name: ${{ github.event.inputs.testnet_type }}
steps:
- name: "Print GitHub variables"
# This is a useful record of what the environment variables were at the time the job ran, for debugging and reference
run: |
echo "GitHub Variables = ${{ toJSON(vars) }}"
- uses: actions/checkout@v3

- name: "Set up Docker"
uses: docker/setup-buildx-action@v1

- name: "Login to Azure docker registry"
uses: azure/docker-login@v1
with:
login-server: testnetobscuronet.azurecr.io
username: testnetobscuronet
password: ${{ secrets.REGISTRY_PASSWORD }}

- name: "Login via Azure CLI"
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}

- name: Build and Push Docker FE Image
run: |
DOCKER_BUILDKIT=1 docker build -t ${{ vars.DOCKER_BUILD_TAG_SCAN_FE }} -f ./tools/obscuroscan_v3/frontend/Dockerfile .
docker push ${{ vars.DOCKER_BUILD_TAG_SCAN_FE }}
- name: Build and Push Docker API Image
run: |
DOCKER_BUILDKIT=1 docker build -t ${{ vars.DOCKER_BUILD_TAG_SCAN_API }} -f ./tools/obscuroscan_v2/backend/Dockerfile .
docker push ${{ vars.DOCKER_BUILD_TAG_SCAN_API }}
- name: "Deploy FE to Azure Container Instances"
uses: "azure/aci-deploy@v1"
with:
resource-group: ${{ secrets.RESOURCE_GROUP }}
dns-name-label: ${{ github.event.inputs.testnet_type }}-obscuro-scan
image: ${{ vars.DOCKER_BUILD_TAG_SCAN_FE }}
name: ${{ github.event.inputs.testnet_type }}-fe-obscuro-scan
location: "uksouth"
restart-policy: "Never"
environment-variables: NEXT_PUBLIC_API_HOST=https://${{ github.event.inputs.testnet_type }}-api.obscuroscan.io NEXT_PUBLIC_FE_VERSION=${{ GITHUB.RUN_NUMBER }}-${{ GITHUB.SHA }}
command-line: npm run start
ports: "80"
cpu: 2
memory: 2

- name: "Deploy API to Azure Container Instances"
uses: "azure/aci-deploy@v1"
with:
resource-group: ${{ secrets.RESOURCE_GROUP }}
dns-name-label: ${{ github.event.inputs.testnet_type }}-api-obscuro-scan-v3
image: ${{ vars.DOCKER_BUILD_TAG_SCAN_API }}
name: ${{ github.event.inputs.testnet_type }}-api-obscuro-scan-v3
location: "uksouth"
restart-policy: "Never"
command-line: ./cmd/backend --nodeHostAddress http://${{ vars.L2_RPC_URL_VALIDATOR }}:80 --serverAddress 0.0.0.0:80
ports: "80"
cpu: 2
memory: 2
3 changes: 3 additions & 0 deletions tools/obscuroscan_v3/frontend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
36 changes: 36 additions & 0 deletions tools/obscuroscan_v3/frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
9 changes: 9 additions & 0 deletions tools/obscuroscan_v3/frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM node:18-buster as runner
# setup container data structure
RUN mkdir -p /home/obscuro/go-obscuro/tools/obscuroscan_v3/
COPY ./tools/obscuroscan_v3/frontend /home/obscuro/go-obscuro/tools/obscuroscan_v3/frontend

WORKDIR /home/obscuro/go-obscuro/tools/obscuroscan_v3/frontend
RUN npm install

EXPOSE 80
62 changes: 62 additions & 0 deletions tools/obscuroscan_v3/frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Tenscan: Blockchain Explorer for The Encryption Network (TEN)

Tenscan is a Next.js and Tailwind CSS-powered application that serves as a Blockchain Explorer for The Encryption Network (TEN). This explorer allows users to interact with and explore the blocks, transactions, batches, resources, and personal data on the TEN blockchain. Tenscan is built using the Shadcn-UI Component Library for a consistent and visually appealing user interface.

## Folder Structure

```
📁 Tenscan
├── 📁 api - Contains server-side code, such as API routes or server logic
├── 📁 pages - Typically used for Next.js pages. Each .tsx or .js file in this directory becomes a route in your application
├── 📁 public - This directory is used to serve static assets. Files inside this directory can be referenced in your code with a URL path
├── 📁 src - Main source code directory for this project
│ ├── 📁 components - Contains reusable React components used throughout the application
│ ├── 📁 hooks - Custom React hooks that can be shared and reused across components
│ ├── 📁 lib - Utility functions or modules that provide common functionalities across the application
│ ├── 📁 routes - Route-related logic or configuration can be placed in this directory
│ ├── 📁 services - Used for services that interact with external APIs or handle other data-related tasks
│ └── 📁 types - Type definitions (.d.ts files or TypeScript files) for TypeScript, describing the shape of data and objects used in the application
└── 📁 styles - Global styles, stylesheets, or styling-related configurations for this project
```

## Getting Started

1. **Clone the Repository:**
```bash
git clone https://github.com/ten-protocol/go-ten.git
cd go-ten/tools/obscuroscan_v3/frontend
```

2. **Install Dependencies:**
```bash
npm install
```

3. **Run the Development Server:**
```bash
npm run dev
```

The application will be accessible at [http://localhost:3000](http://localhost:3000).

## Usage

- Visit the different sections of the explorer through the navigation links in the UI.
- Explore the different blocks, transactions, batches, resources, and personal data on the TEN.
- View the details of each batch by their hash.

## Built With

- [Next.js](https://nextjs.org/)
- [Tailwind CSS](https://tailwindcss.com/)
- [Shadcn-UI](https://shadcn.com/)
- [TypeScript](https://www.typescriptlang.org/)


## Contributing

Contributions are welcome! Please follow our [contribution guidelines](/docs/_docs/community/contributions.md).

## License

This project is licensed under the [GNU Affero General Public License v3.0](/LICENSE).
38 changes: 38 additions & 0 deletions tools/obscuroscan_v3/frontend/api/batches.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { httpRequest } from ".";
import { apiRoutes } from "@/src/routes";
import { pathToUrl } from "@/src/routes/router";
import { ResponseDataInterface } from "@/src/types/interfaces";
import {
Batch,
BatchDetails,
BatchResponse,
} from "@/src/types/interfaces/BatchInterfaces";

export const fetchBatches = async (
payload?: Record<string, any>
): Promise<ResponseDataInterface<BatchResponse>> => {
return await httpRequest<ResponseDataInterface<BatchResponse>>({
method: "get",
url: pathToUrl(apiRoutes.getBatches),
searchParams: payload,
});
};

export const fetchLatestBatch = async (
payload?: Record<string, any>
): Promise<ResponseDataInterface<Batch>> => {
return await httpRequest<ResponseDataInterface<Batch>>({
method: "get",
url: pathToUrl(apiRoutes.getLatestBatch),
searchParams: payload,
});
};

export const fetchBatchByHash = async (
hash: string
): Promise<ResponseDataInterface<BatchDetails>> => {
return await httpRequest<ResponseDataInterface<BatchDetails>>({
method: "get",
url: pathToUrl(apiRoutes.getBatchByHash, { hash }),
});
};
14 changes: 14 additions & 0 deletions tools/obscuroscan_v3/frontend/api/blocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { httpRequest } from ".";
import { apiRoutes } from "@/src/routes";
import { pathToUrl } from "@/src/routes/router";
import { ResponseDataInterface } from "@/src/types/interfaces";

export const fetchBlocks = async (
payload?: Record<string, any>
): Promise<ResponseDataInterface<any>> => {
return await httpRequest<ResponseDataInterface<any>>({
method: "get",
url: pathToUrl(apiRoutes.getBlocks),
searchParams: payload,
});
};
25 changes: 25 additions & 0 deletions tools/obscuroscan_v3/frontend/api/contracts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { httpRequest } from ".";
import { apiRoutes } from "@/src/routes";
import { pathToUrl } from "@/src/routes/router";
import { ResponseDataInterface } from "@/src/types/interfaces";
import { ContractCount } from "@/src/types/interfaces/ContractInterface";

export const fetchContractCount = async (
payload?: Record<string, any>
): Promise<ContractCount> => {
return await httpRequest<ContractCount>({
method: "get",
url: pathToUrl(apiRoutes.getContractCount),
searchParams: payload,
});
};

export const fetchVerifiedContracts = async (
payload?: Record<string, any>
): Promise<ResponseDataInterface<any>> => {
return await httpRequest<ResponseDataInterface<any>>({
method: "get",
url: pathToUrl(apiRoutes.getVerifiedContracts),
searchParams: payload,
});
};
90 changes: 90 additions & 0 deletions tools/obscuroscan_v3/frontend/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { apiHost } from "@/src/lib/constants";
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";

type HttpMethod = "get" | "post" | "put" | "patch" | "delete";

interface HttpOptions {
method?: HttpMethod;
url: string;
data?: Record<string, any>;
params?: Record<string, any>;
headers?: Record<string, any>;
timeout?: number;
responseType?:
| "json"
| "arraybuffer"
| "blob"
| "document"
| "text"
| undefined;
download?: boolean;
searchParams?: Record<string, any>;
}

const baseConfig: AxiosRequestConfig = {
baseURL: apiHost,
timeout: 10000,
};

const https: AxiosInstance = axios.create(baseConfig);

export const httpRequest = async <ResponseData>(
options: HttpOptions,
config: AxiosRequestConfig = {}
): Promise<ResponseData> => {
const {
method = "get",
url,
data,
params,
headers,
timeout,
responseType,
searchParams,
} = options;
let query = "";
if (searchParams) {
const filteredParams = Object.fromEntries(
Object.entries(searchParams).filter(
([, value]) => value !== undefined && value !== null && value !== ""
)
);
if (Object.keys(filteredParams).length) {
query = new URLSearchParams(filteredParams).toString();
}
}

const httpConfig: AxiosRequestConfig = {
method,
url: query ? `${url}?${query}` : url,
data,
params,
headers: { ...(headers || {}) },
timeout,
responseType: responseType,
...config,
};
try {
const response = await https(httpConfig);
return response.data as ResponseData;
} catch (error) {
handleHttpError(error);
throw error;
}
};

// Centralized error handling function
const handleHttpError = (error: any) => {
// if the error is a server error (status code 5xx) before handling
if (isAxiosError(error) && error.response && error.response.status >= 500) {
console.error("Server error:", error);
} else {
// other errors
console.error("An error occurred:", error);
}
};

// Type guard to check if the error is an AxiosError
const isAxiosError = (error: any): error is import("axios").AxiosError => {
return error.isAxiosError === true;
};
26 changes: 26 additions & 0 deletions tools/obscuroscan_v3/frontend/api/rollups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { httpRequest } from ".";
import { apiRoutes } from "@/src/routes";
import { pathToUrl } from "@/src/routes/router";
import { ResponseDataInterface } from "@/src/types/interfaces";

export const fetchRollups = async (
payload?: Record<string, any>
): Promise<ResponseDataInterface<any>> => {
return await httpRequest<ResponseDataInterface<any>>({
method: "get",
url: pathToUrl(apiRoutes.getRollups),
searchParams: payload,
});
};

export const decryptEncryptedRollup = async ({
StrData,
}: {
StrData: string;
}): Promise<ResponseDataInterface<any>> => {
return await httpRequest<ResponseDataInterface<any>>({
method: "post",
url: pathToUrl(apiRoutes.decryptEncryptedRollup),
data: { StrData },
});
};
Loading

0 comments on commit 8712e26

Please sign in to comment.