├── python ├── log.txt ├── VERSION ├── src │ ├── tests │ │ ├── __init__.py │ │ ├── models │ │ │ ├── __init__.py │ │ │ └── test_query_status.py │ │ ├── utils │ │ │ ├── __init__.py │ │ │ ├── mock_data │ │ │ │ ├── get_query_run.py │ │ │ │ └── get_sql_statement.py │ │ │ └── test_sleep.py │ │ └── integrations │ │ │ ├── __init__.py │ │ │ └── query_integration │ │ │ ├── __init__.py │ │ │ └── test_query_result_set_builder.py │ ├── utils │ │ ├── __init__.py │ │ └── sleep.py │ ├── models │ │ ├── compass │ │ │ ├── core │ │ │ │ ├── __init__.py │ │ │ │ ├── result_format.py │ │ │ │ ├── page.py │ │ │ │ ├── rpc_error.py │ │ │ │ ├── page_stats.py │ │ │ │ ├── column_metadata.py │ │ │ │ ├── rpc_request.py │ │ │ │ ├── tags.py │ │ │ │ ├── rpc_response.py │ │ │ │ ├── sql_statement.py │ │ │ │ ├── query_request.py │ │ │ │ └── query_run.py │ │ │ ├── __init__.py │ │ │ ├── cancel_query_run.py │ │ │ ├── get_sql_statement.py │ │ │ ├── get_query_run.py │ │ │ ├── create_query_run.py │ │ │ ├── query_results.py │ │ │ └── get_query_run_results.py │ │ ├── sleep_config.py │ │ ├── __init__.py │ │ ├── query_status.py │ │ ├── query_defaults.py │ │ ├── query_result_set.py │ │ ├── query.py │ │ └── query_run_stats.py │ ├── integrations │ │ ├── __init__.py │ │ └── query_integration │ │ │ ├── __init__.py │ │ │ ├── defaults.py │ │ │ └── query_result_set_builder.py │ ├── shroomdk.py │ ├── errors │ │ ├── base_error.py │ │ ├── sdk_error.py │ │ ├── __init__.py │ │ ├── server_error.py │ │ ├── api_error.py │ │ └── query_run_errors.py │ ├── __init__.py │ └── flipside.py ├── requirements.txt ├── requirements-dev.txt ├── setup.cfg ├── MANIFEST.in ├── README.md ├── LICENSE.txt ├── Makefile └── setup.py ├── r ├── shroomDK │ ├── .Rhistory │ ├── LICENSE │ ├── .Rbuildignore │ ├── NAMESPACE │ ├── shroomDK.Rproj │ ├── DESCRIPTION │ ├── LICENSE.md │ ├── man │ │ ├── get_query_status.Rd │ │ ├── cancel_query.Rd │ │ ├── clean_query.Rd │ │ ├── create_query_token.Rd │ │ ├── get_query_from_token.Rd │ │ └── auto_paginate_query.Rd │ ├── R │ │ ├── get_query_status.R │ │ ├── cancel_query.R │ │ ├── clean_query.R │ │ ├── create_query_token.R │ │ └── get_query_from_token.R │ └── renv.lock ├── shroomDK_0.1.1.tar.gz ├── shroomDK_0.2.0.tar.gz ├── shroomDK_0.2.1.tar.gz └── shroomDK_0.3.0.tar.gz ├── .isort.cfg ├── js ├── src │ ├── index.ts │ ├── integrations │ │ ├── index.ts │ │ └── query-integration │ │ │ └── query-result-set-builder.ts │ ├── types │ │ ├── compass │ │ │ ├── core │ │ │ │ ├── page.type.ts │ │ │ │ ├── result-format.type.ts │ │ │ │ ├── rpc-error.type.ts │ │ │ │ ├── tags.type.ts │ │ │ │ ├── column-metadata.type.ts │ │ │ │ ├── page-stats.type.ts │ │ │ │ ├── sql-statement.type.ts │ │ │ │ ├── query-request.type.ts │ │ │ │ ├── rpc-request.type.ts │ │ │ │ ├── rpc-response.type.ts │ │ │ │ ├── index.ts │ │ │ │ └── query-run.type.ts │ │ │ ├── index.ts │ │ │ ├── get-sql-statement.type.ts │ │ │ ├── get-query-run.type.ts │ │ │ ├── cancel-query-run.type.ts │ │ │ ├── compass-api-client.type.ts │ │ │ ├── query-results.type.ts │ │ │ ├── create-query-run.type.ts │ │ │ └── get-query-run-results.type.ts │ │ ├── query-result-record.type.ts │ │ ├── sleep-config.type.ts │ │ ├── index.ts │ │ ├── sdk-defaults.type.ts │ │ ├── query-run-stats.type.ts │ │ ├── query-status.type.ts │ │ ├── query.type.ts │ │ └── query-result-set.type.ts │ ├── tests │ │ ├── mock-data │ │ │ ├── index.ts │ │ │ ├── cancel-query-run.ts │ │ │ ├── get-query-run.ts │ │ │ ├── get-sql-statement.ts │ │ │ └── create-query-run.ts │ │ ├── query-status.test.ts │ │ ├── time.test.ts │ │ ├── error-types.test.ts │ │ ├── mocks │ │ │ └── api-mocks.ts │ │ └── sleep.test.ts │ ├── errors │ │ ├── index.ts │ │ ├── base-error.ts │ │ ├── sdk-errors.ts │ │ ├── error-types.ts │ │ ├── user-errors.ts │ │ ├── server-errors.ts │ │ ├── query-run-errors.ts │ │ └── api-error.ts │ ├── utils │ │ ├── time.ts │ │ └── sleep.ts │ ├── defaults.ts │ └── flipside.ts ├── .eslintrc.js ├── vite.config.ts ├── LICENSE └── package.json ├── .trunk ├── .gitignore └── trunk.yaml ├── .prettierrc ├── .coverage ├── examples ├── js │ └── react-app │ │ ├── src │ │ ├── react-app-env.d.ts │ │ ├── setupTests.ts │ │ ├── App.test.tsx │ │ ├── components │ │ │ ├── error-msg.tsx │ │ │ ├── input.tsx │ │ │ ├── nav.tsx │ │ │ ├── query-stats.tsx │ │ │ ├── retro-loader.tsx │ │ │ ├── retro-buttons.tsx │ │ │ └── query-result-table.tsx │ │ ├── reportWebVitals.ts │ │ ├── App.tsx │ │ ├── App.css │ │ ├── index.tsx │ │ ├── index.css │ │ ├── queries │ │ │ ├── nft-queries.tsx │ │ │ ├── ens-queries.tsx │ │ │ └── xmetric-queries.tsx │ │ ├── logo.svg │ │ └── routes │ │ │ └── xmetric.tsx │ │ ├── public │ │ ├── robots.txt │ │ ├── favicon.png │ │ ├── fonts │ │ │ ├── Cartridge-Bold.woff2 │ │ │ ├── Cartridge-Regular.woff2 │ │ │ └── SimplonMono-Regular.otf │ │ ├── manifest.json │ │ └── index.html │ │ ├── .eslintrc.js │ │ ├── craco.config.js │ │ ├── .gitignore │ │ ├── tailwind.config.js │ │ ├── tsconfig.json │ │ ├── package.json │ │ └── README.md └── python │ ├── notebooks │ ├── sql │ │ ├── nft_sales.sql │ │ ├── xmetric_eth_holdings.sql │ │ ├── xmetric_leaderboard.sql │ │ ├── minter_sales_agg.sql │ │ └── collector_sales.sql │ └── intro.ipynb │ ├── nft_sales.py │ └── nft_sales_viz.py ├── .vscode └── settings.json ├── .flake8 ├── .markdownlint.yaml ├── .pylintrc ├── .gitignore ├── .github └── workflows │ ├── ci_js.yml │ ├── ci_js_end_to_end.yml │ └── ci_python.yml ├── DESCRIPTION └── README.md /python/log.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /python/VERSION: -------------------------------------------------------------------------------- 1 | 2.1.0 -------------------------------------------------------------------------------- /r/shroomDK/.Rhistory: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /python/src/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /python/src/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /python/src/tests/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /python/src/tests/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | profile=black 3 | -------------------------------------------------------------------------------- /python/src/models/compass/core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /python/src/tests/integrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /js/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./flipside"; 2 | -------------------------------------------------------------------------------- /.trunk/.gitignore: -------------------------------------------------------------------------------- 1 | *out 2 | *logs 3 | external 4 | -------------------------------------------------------------------------------- /python/requirements.txt: -------------------------------------------------------------------------------- 1 | pydantic==2.10.0 2 | requests==2.32.0 -------------------------------------------------------------------------------- /python/src/tests/integrations/query_integration/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "semi": true 4 | } 5 | -------------------------------------------------------------------------------- /.coverage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlipsideCrypto/sdk/HEAD/.coverage -------------------------------------------------------------------------------- /js/src/integrations/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./query-integration"; 2 | -------------------------------------------------------------------------------- /r/shroomDK/LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2022 2 | COPYRIGHT HOLDER: Carlos Mercado 3 | -------------------------------------------------------------------------------- /examples/js/react-app/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /python/requirements-dev.txt: -------------------------------------------------------------------------------- 1 | pytest==6.2.4 2 | freezegun==1.1.0 3 | requests-mock==1.11.0 -------------------------------------------------------------------------------- /python/setup.cfg: -------------------------------------------------------------------------------- 1 | 2 | # Inside of setup.cfg 3 | [metadata] 4 | description-file = README.md -------------------------------------------------------------------------------- /python/src/models/compass/__init__.py: -------------------------------------------------------------------------------- 1 | from .get_query_run_results import Filter, SortBy 2 | -------------------------------------------------------------------------------- /python/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include requirements.txt 2 | include requirements-dev.txt 3 | include VERSION -------------------------------------------------------------------------------- /r/shroomDK_0.1.1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlipsideCrypto/sdk/HEAD/r/shroomDK_0.1.1.tar.gz -------------------------------------------------------------------------------- /r/shroomDK_0.2.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlipsideCrypto/sdk/HEAD/r/shroomDK_0.2.0.tar.gz -------------------------------------------------------------------------------- /r/shroomDK_0.2.1.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlipsideCrypto/sdk/HEAD/r/shroomDK_0.2.1.tar.gz -------------------------------------------------------------------------------- /r/shroomDK_0.3.0.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlipsideCrypto/sdk/HEAD/r/shroomDK_0.3.0.tar.gz -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { "python.analysis.typeCheckingMode": "basic", "python.formatting.provider": "black"} -------------------------------------------------------------------------------- /python/src/integrations/__init__.py: -------------------------------------------------------------------------------- 1 | from .query_integration import CompassQueryIntegration # noqa: F401 2 | -------------------------------------------------------------------------------- /r/shroomDK/.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^renv$ 2 | ^renv\.lock$ 3 | ^.*\.Rproj$ 4 | ^\.Rproj\.user$ 5 | ^LICENSE\.md$ 6 | -------------------------------------------------------------------------------- /python/src/shroomdk.py: -------------------------------------------------------------------------------- 1 | from .flipside import Flipside 2 | 3 | 4 | class ShroomDK(Flipside): 5 | pass 6 | -------------------------------------------------------------------------------- /examples/js/react-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /js/src/types/compass/core/page.type.ts: -------------------------------------------------------------------------------- 1 | export interface Page { 2 | number: number; 3 | size: number; 4 | } 5 | -------------------------------------------------------------------------------- /js/src/types/compass/core/result-format.type.ts: -------------------------------------------------------------------------------- 1 | export enum ResultFormat { 2 | csv = "csv", 3 | json = "json", 4 | } 5 | -------------------------------------------------------------------------------- /examples/js/react-app/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlipsideCrypto/sdk/HEAD/examples/js/react-app/public/favicon.png -------------------------------------------------------------------------------- /python/src/integrations/query_integration/__init__.py: -------------------------------------------------------------------------------- 1 | from .compass_query_integration import CompassQueryIntegration # noqa: F401 2 | -------------------------------------------------------------------------------- /js/src/types/compass/core/rpc-error.type.ts: -------------------------------------------------------------------------------- 1 | export interface RpcError { 2 | code: number; 3 | message: string; 4 | data: any | null; 5 | } 6 | -------------------------------------------------------------------------------- /js/src/types/query-result-record.type.ts: -------------------------------------------------------------------------------- 1 | export type QueryResultRecord = Record< 2 | string, 3 | string | number | null | boolean 4 | >; 5 | -------------------------------------------------------------------------------- /js/src/types/sleep-config.type.ts: -------------------------------------------------------------------------------- 1 | export type SleepConfig = { 2 | attempts: number; 3 | timeoutMinutes: number; 4 | intervalSeconds?: number; 5 | }; 6 | -------------------------------------------------------------------------------- /python/src/models/compass/core/result_format.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class ResultFormat(str, Enum): 5 | csv = "csv" 6 | json = "json" 7 | -------------------------------------------------------------------------------- /examples/js/react-app/public/fonts/Cartridge-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlipsideCrypto/sdk/HEAD/examples/js/react-app/public/fonts/Cartridge-Bold.woff2 -------------------------------------------------------------------------------- /examples/js/react-app/public/fonts/Cartridge-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlipsideCrypto/sdk/HEAD/examples/js/react-app/public/fonts/Cartridge-Regular.woff2 -------------------------------------------------------------------------------- /examples/js/react-app/public/fonts/SimplonMono-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlipsideCrypto/sdk/HEAD/examples/js/react-app/public/fonts/SimplonMono-Regular.otf -------------------------------------------------------------------------------- /js/src/types/compass/core/tags.type.ts: -------------------------------------------------------------------------------- 1 | export interface Tags { 2 | sdk_package: string | null; 3 | sdk_version: string | null; 4 | sdk_language: string | null; 5 | } 6 | -------------------------------------------------------------------------------- /python/src/errors/base_error.py: -------------------------------------------------------------------------------- 1 | class BaseError(Exception): 2 | """ 3 | Base error class for all errors in the flipsidecrypto package. 4 | """ 5 | 6 | pass 7 | -------------------------------------------------------------------------------- /js/src/types/compass/core/column-metadata.type.ts: -------------------------------------------------------------------------------- 1 | export interface ColumnMetadata { 2 | types: string[]; 3 | columns: string[]; 4 | colTypeMap: Record; 5 | } 6 | -------------------------------------------------------------------------------- /python/src/__init__.py: -------------------------------------------------------------------------------- 1 | from .flipside import Flipside # noqa: F401 2 | from .models import * 3 | from .rpc import RPC # noqa: F401 4 | from .shroomdk import ShroomDK # noqa: F401 5 | -------------------------------------------------------------------------------- /python/src/models/compass/core/page.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Page(BaseModel): 7 | number: int 8 | size: int 9 | -------------------------------------------------------------------------------- /js/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('@types/eslint').Linter.Config} 3 | */ 4 | module.exports = { 5 | root: true, 6 | ignorePatterns: ["node_modules", "dist", "public"], 7 | }; 8 | -------------------------------------------------------------------------------- /js/src/types/compass/core/page-stats.type.ts: -------------------------------------------------------------------------------- 1 | export interface PageStats { 2 | currentPageNumber: number; 3 | currentPageSize: number; 4 | totalRows: number; 5 | totalPages: number; 6 | } 7 | -------------------------------------------------------------------------------- /examples/js/react-app/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('@types/eslint').Linter.Config} 3 | */ 4 | module.exports = { 5 | root: true, 6 | ignorePatterns: ["node_modules", "dist", "public"], 7 | }; 8 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | # Autoformatter friendly flake8 config (all formatting rules disabled) 2 | [flake8] 3 | max-line-length = 160 4 | max-complexity = 15 5 | exclude = tests/* 6 | extend-ignore = D1, D2, E1, E2, E3, E501, W1, W2, W3, W5 -------------------------------------------------------------------------------- /js/src/tests/mock-data/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./cancel-query-run"; 2 | export * from "./create-query-run"; 3 | export * from "./get-query-results"; 4 | export * from "./get-query-run"; 5 | export * from "./get-sql-statement"; 6 | -------------------------------------------------------------------------------- /js/src/errors/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./error-types"; 2 | export * from "./server-errors"; 3 | export * from "./sdk-errors"; 4 | export * from "./query-run-errors"; 5 | export * from "./user-errors"; 6 | export * from "./api-error"; 7 | -------------------------------------------------------------------------------- /examples/js/react-app/craco.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | style: { 3 | postcssOptions: { 4 | plugins: [ 5 | require('tailwindcss'), 6 | require('autoprefixer'), 7 | ], 8 | }, 9 | }, 10 | } -------------------------------------------------------------------------------- /python/src/models/compass/core/rpc_error.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class RpcError(BaseModel): 7 | code: int 8 | message: str 9 | data: Optional[Any] = None 10 | -------------------------------------------------------------------------------- /python/src/models/compass/core/page_stats.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, List 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class PageStats(BaseModel): 7 | currentPageNumber: int 8 | currentPageSize: int 9 | totalRows: int 10 | totalPages: int 11 | -------------------------------------------------------------------------------- /python/src/models/compass/core/column_metadata.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, List, Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class ColumnMetadata(BaseModel): 7 | types: List[str] 8 | columns: List[str] 9 | colTypeMap: Dict[str, str] 10 | -------------------------------------------------------------------------------- /python/src/models/sleep_config.py: -------------------------------------------------------------------------------- 1 | from typing import Optional, Union 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class SleepConfig(BaseModel): 7 | attempts: int 8 | timeout_minutes: Union[int, float] 9 | interval_seconds: Optional[float] = None 10 | -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Autoformatter friendly markdownlint config (all formatting rules disabled) 2 | default: true 3 | blank_lines: false 4 | bullet: false 5 | html: false 6 | indentation: false 7 | line_length: false 8 | spaces: false 9 | url: false 10 | whitespace: false 11 | -------------------------------------------------------------------------------- /python/src/models/compass/core/rpc_request.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, List, Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class RpcRequest(BaseModel): 7 | jsonrpc: str = "2.0" 8 | method: str 9 | params: List[Dict[str, Any]] 10 | id: int = 1 11 | -------------------------------------------------------------------------------- /.trunk/trunk.yaml: -------------------------------------------------------------------------------- 1 | version: 0.1 2 | cli: 3 | version: 0.15.0-beta 4 | lint: 5 | enabled: 6 | - actionlint@1.6.15 7 | - black@22.6.0 8 | # - git-diff-check@SYSTEM 9 | # - gitleaks@8.8.12 10 | - isort@5.10.1 11 | # - markdownlint@0.32.0 12 | - prettier@2.7.1 13 | -------------------------------------------------------------------------------- /examples/js/react-app/src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /r/shroomDK/NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(auto_paginate_query) 4 | export(cancel_query) 5 | export(clean_query) 6 | export(create_query_token) 7 | export(get_query_from_token) 8 | export(get_query_status) 9 | import(httr) 10 | import(jsonlite) 11 | -------------------------------------------------------------------------------- /python/src/models/compass/core/tags.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Dict, List, Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class Tags(BaseModel): 8 | sdk_package: Optional[str] = None 9 | sdk_version: Optional[str] = None 10 | sdk_language: Optional[str] = None 11 | -------------------------------------------------------------------------------- /js/src/errors/base-error.ts: -------------------------------------------------------------------------------- 1 | import { ERROR_TYPES } from "./error-types"; 2 | 3 | export class BaseError extends Error { 4 | errorType: string; 5 | data: Record; 6 | constructor(message: string) { 7 | super(message); 8 | this.errorType = ERROR_TYPES.default; 9 | this.data = {}; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /js/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./query.type"; 2 | export * from "./sdk-defaults.type"; 3 | export * from "./query-status.type"; 4 | export * from "./query-result-set.type"; 5 | export * from "./query-run-stats.type"; 6 | export * from "./query-result-record.type"; 7 | export * from "./sleep-config.type"; 8 | export * from "./compass"; 9 | -------------------------------------------------------------------------------- /python/src/integrations/query_integration/defaults.py: -------------------------------------------------------------------------------- 1 | from ...models import QueryDefaults 2 | 3 | DEFAULTS: QueryDefaults = QueryDefaults( 4 | ttl_minutes=60, 5 | cached=True, 6 | timeout_minutes=20, 7 | retry_interval_seconds=0.5, 8 | page_size=100000, 9 | page_number=1, 10 | max_age_minutes=5, 11 | ) 12 | -------------------------------------------------------------------------------- /examples/js/react-app/src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render, screen } from '@testing-library/react'; 3 | import App from './App'; 4 | 5 | test('renders learn react link', () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /js/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // Configure Vitest (https://vitest.dev/config/) 4 | 5 | import { defineConfig } from "vite"; 6 | 7 | export default defineConfig({ 8 | test: { 9 | /* for example, use global to avoid globals imports (describe, test, expect): */ 10 | // globals: true, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /python/src/errors/sdk_error.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from .base_error import BaseError 4 | 5 | 6 | class SDKError(BaseError): 7 | """ 8 | Base class for all SDK errors. 9 | """ 10 | 11 | def __init__(self, message: Union[str, None]): 12 | self.message = message 13 | super().__init__(self.message) 14 | -------------------------------------------------------------------------------- /js/src/errors/sdk-errors.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from "./base-error"; 2 | import { ERROR_TYPES } from "./error-types"; 3 | 4 | export class UnexpectedSDKError extends BaseError { 5 | constructor(message: string) { 6 | const errorType = ERROR_TYPES.sdk_error; 7 | super(`${errorType}: ${message}`); 8 | this.errorType = errorType; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /python/src/models/compass/core/rpc_response.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, Optional, Union 2 | 3 | from pydantic import BaseModel 4 | 5 | from .rpc_error import RpcError 6 | 7 | 8 | class RpcResponse(BaseModel): 9 | jsonrpc: str 10 | id: int 11 | result: Union[Optional[Dict[str, Any]], None] = None 12 | error: Optional[RpcError] = None 13 | -------------------------------------------------------------------------------- /js/src/types/compass/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./cancel-query-run.type"; 2 | export * from "./create-query-run.type"; 3 | export * from "./get-query-run-results.type"; 4 | export * from "./get-query-run.type"; 5 | export * from "./get-sql-statement.type"; 6 | export * from "./query-results.type"; 7 | export * from "./core"; 8 | export * from "./compass-api-client.type"; 9 | -------------------------------------------------------------------------------- /js/src/utils/time.ts: -------------------------------------------------------------------------------- 1 | export function msToMin(ms: number): number { 2 | return ms / 1000 / 60; 3 | } 4 | 5 | export function minToMs(min: number): number { 6 | return min * 60 * 1000; 7 | } 8 | 9 | export function msToSec(ms: number): number { 10 | return ms / 1000; 11 | } 12 | 13 | export function secToMs(sec: number): number { 14 | return sec * 1000; 15 | } 16 | -------------------------------------------------------------------------------- /examples/python/notebooks/sql/nft_sales.sql: -------------------------------------------------------------------------------- 1 | SELECT 2 | date_trunc('day', block_timestamp) AS date, 3 | avg(price) as avg_eth_price, 4 | count(1) as num_sales 5 | FROM ethereum.core.ez_nft_sales 6 | WHERE 7 | nft_address = LOWER('0x23581767a106ae21c074b2276d25e5c3e136a68b') 8 | AND block_timestamp >= GETDATE() - interval'120 days' 9 | GROUP BY 1 10 | ORDER BY 1 ASC -------------------------------------------------------------------------------- /js/src/types/compass/core/sql-statement.type.ts: -------------------------------------------------------------------------------- 1 | import { ColumnMetadata } from "./column-metadata.type"; 2 | import { Tags } from "./tags.type"; 3 | 4 | export interface SqlStatement { 5 | id: string; 6 | statementHash: string; 7 | sql: string; 8 | columnMetadata: ColumnMetadata | null; 9 | userId: string; 10 | tags: Tags; 11 | createdAt: string; 12 | updatedAt: string; 13 | } 14 | -------------------------------------------------------------------------------- /js/src/types/sdk-defaults.type.ts: -------------------------------------------------------------------------------- 1 | export type SdkDefaults = { 2 | apiBaseUrl: string; 3 | ttlMinutes: number; 4 | maxAgeMinutes: number; 5 | dataSource: string; 6 | dataProvider: string; 7 | cached: boolean; 8 | timeoutMinutes: number; 9 | retryIntervalSeconds: number; 10 | pageSize: number; 11 | pageNumber: number; 12 | sdkPackage: string; 13 | sdkVersion: string; 14 | }; 15 | -------------------------------------------------------------------------------- /python/src/errors/__init__.py: -------------------------------------------------------------------------------- 1 | from .api_error import ApiError # noqa: F401 2 | from .query_run_errors import ( # noqa: F401 3 | QueryRunCancelledError, 4 | QueryRunExecutionError, 5 | QueryRunInvalidStateToCancel, 6 | QueryRunRateLimitError, 7 | QueryRunTimeoutError, 8 | ) 9 | from .sdk_error import SDKError # noqa: F401 10 | from .server_error import ServerError # noqa: F401 11 | -------------------------------------------------------------------------------- /python/src/models/__init__.py: -------------------------------------------------------------------------------- 1 | from .compass import Filter, SortBy # noqa: F401 2 | from .query import Query # noqa: F401 3 | from .query_defaults import QueryDefaults # noqa: F401 4 | from .query_result_set import QueryResultSet # noqa: F401 5 | from .query_run_stats import QueryRunStats # noqa: F401 6 | from .query_status import QueryStatus # noqa: F401 7 | from .sleep_config import SleepConfig # noqa: F401 8 | -------------------------------------------------------------------------------- /js/src/types/compass/core/query-request.type.ts: -------------------------------------------------------------------------------- 1 | import { Tags } from "./tags.type"; 2 | 3 | export interface QueryRequest { 4 | id: string; 5 | sqlStatementId: string; 6 | userId: string; 7 | tags: Tags; 8 | maxAgeMinutes: number; 9 | resultTTLHours: number; 10 | userSkipCache: boolean; 11 | triggeredQueryRun: boolean; 12 | queryRunId: string; 13 | createdAt: string; 14 | updatedAt: string; 15 | } 16 | -------------------------------------------------------------------------------- /js/src/errors/error-types.ts: -------------------------------------------------------------------------------- 1 | export const ERROR_TYPES = { 2 | default: "GENERIC_FLIPSIDE_ERROR", 3 | sdk_error: "UNEXPECTED_SDK_ERROR", 4 | server_error: "SERVER_ERROR", 5 | query_run_rate_limit_error: "QUERY_RUN_RATE_LIMIT_ERROR", 6 | query_run_timeout_error: "QUERY_RUN_TIMEOUT_ERROR", 7 | query_run_execution_error: "QUERY_RUN_EXECUTION_ERROR", 8 | user_error: "USER_ERROR", 9 | api_error: "API_ERROR", 10 | }; 11 | -------------------------------------------------------------------------------- /examples/js/react-app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "ShroomDK Example React App", 3 | "name": "ShroomDK Example React App", 4 | "icons": [ 5 | { 6 | "src": "favicon.png", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /examples/js/react-app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /python/src/errors/server_error.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from .base_error import BaseError 4 | 5 | 6 | class ServerError(BaseError): 7 | """ 8 | Base class for all server errors. 9 | """ 10 | 11 | def __init__(self, status_code: int, message: Union[str, None]): 12 | self.message = f"unexpected server error occured with status code: {status_code}, msg: {message}" 13 | super().__init__(self.message) 14 | -------------------------------------------------------------------------------- /js/src/types/query-run-stats.type.ts: -------------------------------------------------------------------------------- 1 | export type QueryRunStats = { 2 | startedAt: Date; 3 | endedAt: Date; 4 | elapsedSeconds: number; 5 | queryExecStartedAt: Date; 6 | queryExecEndedAt: Date; 7 | streamingStartedAt: Date; 8 | streamingEndedAt: Date; 9 | queuedSeconds: number; 10 | streamingSeconds: number; 11 | queryExecSeconds: number; 12 | bytes: number; // the number of bytes returned by the query 13 | recordCount: number; 14 | }; 15 | -------------------------------------------------------------------------------- /js/src/errors/user-errors.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from "./base-error"; 2 | import { ERROR_TYPES } from "./error-types"; 3 | 4 | export class UserError extends BaseError { 5 | constructor(statusCode: number, message: string) { 6 | const errorType = ERROR_TYPES.user_error; 7 | super( 8 | `${errorType}: user error occured with statusCode: ${statusCode} and msg: '${message}' 9 | ` 10 | ); 11 | this.errorType = errorType; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /python/src/models/compass/core/sql_statement.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, List, Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | from .column_metadata import ColumnMetadata 6 | from .tags import Tags 7 | 8 | 9 | class SqlStatement(BaseModel): 10 | id: str 11 | statementHash: str 12 | sql: str 13 | columnMetadata: Optional[ColumnMetadata] = None 14 | userId: str 15 | tags: Tags 16 | createdAt: str 17 | updatedAt: str 18 | -------------------------------------------------------------------------------- /js/src/types/compass/core/rpc-request.type.ts: -------------------------------------------------------------------------------- 1 | export interface RpcRequest { 2 | jsonrpc: string; 3 | method: string; 4 | params: T[]; 5 | id: number; 6 | } 7 | 8 | export abstract class BaseRpcRequest implements RpcRequest { 9 | jsonrpc: string = "2.0"; 10 | abstract method: string; 11 | params: T[]; 12 | id: number; 13 | 14 | constructor(params: T[], id: number = 1) { 15 | this.params = params; 16 | this.id = id; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /js/src/errors/server-errors.ts: -------------------------------------------------------------------------------- 1 | import { BaseError } from "./base-error"; 2 | import { ERROR_TYPES } from "./error-types"; 3 | 4 | export class ServerError extends BaseError { 5 | constructor(statusCode: number, message: string) { 6 | const errorType = ERROR_TYPES.server_error; 7 | super( 8 | `${errorType}: an unexpected server error occured with statusCode: ${statusCode} and msg: '${message}' 9 | ` 10 | ); 11 | this.errorType = errorType; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /python/src/models/compass/core/query_request.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Dict, List, Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | from .tags import Tags 6 | 7 | 8 | class QueryRequest(BaseModel): 9 | id: str 10 | sqlStatementId: str 11 | userId: str 12 | tags: Tags 13 | maxAgeMinutes: int 14 | resultTTLHours: int 15 | userSkipCache: bool 16 | triggeredQueryRun: bool 17 | queryRunId: str 18 | createdAt: str 19 | updatedAt: str 20 | -------------------------------------------------------------------------------- /js/src/defaults.ts: -------------------------------------------------------------------------------- 1 | import { version } from "../package.json"; 2 | import { SdkDefaults } from "./types"; 3 | 4 | export const DEFAULTS: SdkDefaults = { 5 | apiBaseUrl: "https://api-v2.flipsidecrypto.xyz", 6 | ttlMinutes: 60, 7 | maxAgeMinutes: 0, 8 | cached: true, 9 | dataProvider: "flipside", 10 | dataSource: "snowflake-default", 11 | timeoutMinutes: 20, 12 | retryIntervalSeconds: 0.5, 13 | pageSize: 100000, 14 | pageNumber: 1, 15 | sdkPackage: "js", 16 | sdkVersion: version, 17 | }; 18 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | disable= 3 | format, # Handled by Black autoformatter 4 | E0401, # Unable to import X; import errors are highly environment dependant 5 | C0114, # Missing module docstring 6 | C0115, # Missing class docstring 7 | C0116, # Missing function or method docstring 8 | C0411, # Import order handled by isort 9 | 10 | [MESSAGES CONTROL] 11 | disable = C0330, C0326 # Black compatible 12 | 13 | [flake8] 14 | max-line-length = 160 15 | max-complexity = 15 16 | exclude = tests/* -------------------------------------------------------------------------------- /examples/js/react-app/src/components/error-msg.tsx: -------------------------------------------------------------------------------- 1 | import { QueryResultSet } from "@flipsidecrypto/sdk"; 2 | 3 | type Props = { 4 | queryResultSet: QueryResultSet | null; 5 | }; 6 | 7 | export function ErrorMsg({ queryResultSet }: Props) { 8 | if (!queryResultSet) { 9 | return <>; 10 | } 11 | 12 | if (!queryResultSet.error) { 13 | return <>; 14 | } 15 | return ( 16 |
17 |

Error

18 |
{queryResultSet?.error.message}
19 |
20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /examples/js/react-app/src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /r/shroomDK/shroomDK.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageCheckArgs: --as-cran --no-manual 22 | -------------------------------------------------------------------------------- /examples/js/react-app/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'], 3 | darkMode: false, // or 'media' or 'class' 4 | theme: { 5 | extend: {}, 6 | fontFamily: { 7 | title: ["Syne", "sans-serif"], 8 | heading: ["Poppins", "sans-serif"], 9 | mono: ["Simplon Mono", "monospace"], 10 | retro: ["VT323", "monospace"], 11 | cartridge: ["Cartridge", "Poppins", "sans-serif"], 12 | }, 13 | }, 14 | variants: { 15 | extend: {}, 16 | }, 17 | plugins: [], 18 | } 19 | -------------------------------------------------------------------------------- /r/shroomDK/DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: shroomDK 2 | Type: Package 3 | Title: Accessing the Flipside Crypto ShroomDK API 4 | Version: 0.3.0 5 | Author: Carlos Mercado 6 | Maintainer: Carlos Mercado 7 | Description: Programmatic access to Flipside Crypto data via the Compass RPC API: . As simple as auto_paginate_query() but with core functions as needed for troubleshooting. Note, 0.1.1 support deprecated 2023-05-31. 8 | Imports: jsonlite, httr 9 | License: MIT + file LICENSE 10 | Encoding: UTF-8 11 | RoxygenNote: 7.2.1 12 | -------------------------------------------------------------------------------- /js/src/types/compass/core/rpc-response.type.ts: -------------------------------------------------------------------------------- 1 | import { RpcError } from "./rpc-error.type"; 2 | 3 | export interface RpcResponse { 4 | jsonrpc: string; 5 | id: number; 6 | result: T | null; 7 | error: RpcError | null; 8 | } 9 | 10 | export abstract class BaseRpcResponse implements RpcResponse { 11 | jsonrpc: string = "2.0"; 12 | id: number; 13 | result: T | null; 14 | error: RpcError | null; 15 | 16 | constructor(id: number, result: T | null, error: RpcError | null) { 17 | this.id = id; 18 | this.result = result; 19 | this.error = error; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /js/src/types/compass/core/index.ts: -------------------------------------------------------------------------------- 1 | // Export classes from core 2 | export { Page } from "./page.type"; 3 | export { PageStats } from "./page-stats.type"; 4 | export { QueryRun } from "./query-run.type"; 5 | export { QueryRequest } from "./query-request.type"; 6 | export { ResultFormat } from "./result-format.type"; 7 | export { RpcRequest, BaseRpcRequest } from "./rpc-request.type"; 8 | export { RpcResponse, BaseRpcResponse } from "./rpc-response.type"; 9 | export { SqlStatement } from "./sql-statement.type"; 10 | export { Tags } from "./tags.type"; 11 | export { RpcError } from "./rpc-error.type"; 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | js/dist 3 | js/dist/ 4 | node_modules/ 5 | js/node_modules 6 | *.DS_STORE 7 | .DS_STORE 8 | __pycache__ 9 | *.pyc 10 | *.pem 11 | *.crt 12 | *.idea 13 | 14 | node_modules 15 | 16 | .cache 17 | .env 18 | .vercel 19 | .output 20 | build/ 21 | *.egg-info/ 22 | .history/ 23 | 24 | /build/ 25 | /public/build 26 | /api/index.js 27 | 28 | js/coverage 29 | run-query-example.py 30 | examples/python/scratch/* 31 | .Rproj.user 32 | r/shroomDK_0.1.0.tar.gz 33 | python-sdk-example.py 34 | r/shroomDK/api_key.txt 35 | r/shroomDK/test_of_page2_issue.R 36 | python/venv/ 37 | venv/ 38 | tokens.txt 39 | -------------------------------------------------------------------------------- /js/src/tests/query-status.test.ts: -------------------------------------------------------------------------------- 1 | import { assert, describe, it } from "vitest"; 2 | import { 3 | QueryStatusError, 4 | QueryStatusFinished, 5 | QueryStatusPending, 6 | } from "../types"; 7 | 8 | describe("queryStatus checks", () => { 9 | it("QueryStatusFinished === finished", async () => { 10 | assert.equal(QueryStatusFinished, "finished"); 11 | }); 12 | it("QueryStatusPending === pending", async () => { 13 | assert.equal(QueryStatusPending, "pending"); 14 | }); 15 | it("QueryStatusError === error", async () => { 16 | assert.equal(QueryStatusError, "error"); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /js/src/tests/time.test.ts: -------------------------------------------------------------------------------- 1 | import { assert, it } from "vitest"; 2 | import { minToMs, msToMin, msToSec, secToMs } from "../utils/time"; 3 | 4 | it("milliseconds to minutes", () => { 5 | const minutes = msToMin(60000); 6 | assert.equal(minutes, 1); 7 | }); 8 | 9 | it("minutes to milliseconds", () => { 10 | const ms = minToMs(1); 11 | assert.equal(ms, 60000); 12 | }); 13 | 14 | it("milliseconds to seconds", () => { 15 | const seconds = msToSec(60000); 16 | assert.equal(seconds, 60); 17 | }); 18 | 19 | it("seconds to milliseconds", () => { 20 | const ms = secToMs(60); 21 | assert.equal(ms, 60000); 22 | }); 23 | -------------------------------------------------------------------------------- /python/src/models/query_status.py: -------------------------------------------------------------------------------- 1 | QueryStatusReady = "QUERY_STATE_READY" 2 | QueryStatusRunning = "QUERY_STATE_RUNNING" 3 | QueryStatusStreamingResults = "QUERY_STATE_STREAMING_RESULTS" 4 | QueryStatusSuccess = "QUERY_STATE_SUCCESS" 5 | QueryStatusFailed = "QUERY_STATE_FAILED" 6 | QueryStatusCanceled = "QUERY_STATE_CANCELED" 7 | 8 | 9 | class QueryStatus(object): 10 | Ready: str = QueryStatusReady 11 | Running: str = QueryStatusRunning 12 | StreamingResults: str = QueryStatusStreamingResults 13 | Success: str = QueryStatusSuccess 14 | Failed: str = QueryStatusFailed 15 | Canceled: str = QueryStatusCanceled 16 | -------------------------------------------------------------------------------- /js/src/flipside.ts: -------------------------------------------------------------------------------- 1 | import { Api } from "./api"; 2 | import { QueryIntegration } from "./integrations"; 3 | import { QueryResultSet } from "./types"; 4 | import { DEFAULTS } from "./defaults"; 5 | 6 | export class Flipside { 7 | query: QueryIntegration; 8 | 9 | constructor(apiKey: string, apiBaseUrl: string = DEFAULTS.apiBaseUrl) { 10 | // Setup API, which will be passed to integrations 11 | const api = new Api(apiBaseUrl, apiKey); 12 | 13 | // declare integrations on Flipside client 14 | this.query = new QueryIntegration(api); 15 | } 16 | } 17 | 18 | export * from "./types"; 19 | export * from "./errors"; 20 | 21 | export { QueryResultSet }; 22 | -------------------------------------------------------------------------------- /examples/js/react-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /examples/js/react-app/src/App.tsx: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | import { Routes, Route } from "react-router-dom"; 3 | import { NftMints } from "./routes/nft-mints"; 4 | import { Nav } from "./components/nav"; 5 | import { Toaster } from "react-hot-toast"; 6 | import { XMetric } from "./routes/xmetric"; 7 | 8 | function App() { 9 | return ( 10 | <> 11 |