kopia lustrzana https://github.com/bugout-dev/moonstream
Merge branch 'main' into fix-state-crawler
commit
6a379c1b55
35
README.md
35
README.md
|
@ -1,21 +1,42 @@
|
|||
![github read me header](https://user-images.githubusercontent.com/8016073/203381867-f7b56861-04ca-4ae4-a5e6-53e97804817a.png)
|
||||
|
||||
# moonstream
|
||||
|
||||
\[[Live at https://moonstream.to/](https://moonstream.to)\] | \[[Join us on Discord](https://discord.gg/pYE65FuNSz)\]
|
||||
[Website](https://moonstream.to)
|
||||
|
||||
[Join our Discord](https://discord.gg/pYE65FuNSz)
|
||||
|
||||
## What is Moonstream?
|
||||
|
||||
Moonstream makes tools that help people build, manage, and maintain their blockchain economies.
|
||||
Moonstream creates economic infrastructure for web3 projects with a focus on blockchain games.
|
||||
|
||||
In order to provide this functionality, we build a lot of technology to crawl blockchains and makes sense of crawled transactions and events. This repository contains that code.
|
||||
This repository contains Moonstream's complete data analysis stack. The emphasis of it is on collecting actionable data related to the blockchain. The repository contains:
|
||||
|
||||
1. Database management tools
|
||||
2. Blockchain node management tools
|
||||
3. Blockchain data crawlers
|
||||
4. Access-controlled API which exposes collected data
|
||||
|
||||
## Important resources
|
||||
1. [Documentation](https://docs.moonstream.to/)
|
||||
2. [Status page](https://moonstream.to/status/)
|
||||
3. [On-chain mechanics](https://github.com/bugout-dev/engine)
|
||||
4. [How to create a dashboard to analyze a smart contract?](https://voracious-gerbil-120.notion.site/Creating-dashboard-for-a-smart-contract-288b1bfa64984b109b79895f69129fce)
|
||||
|
||||
## Who uses Moonstream?
|
||||
|
||||
Game designers and economists, data scientists, smart contract developers, backend engineers, and teams managing loyalty programs for blockchain projects.
|
||||
People from different backgrounds who are interested in data, crypto and code.
|
||||
Moonstream tools are often used by game designers and economists, data scientists, smart contract developers, backend engineers, and teams managing loyalty programs for blockchain projects.
|
||||
|
||||
Some of our prominents customers:
|
||||
Some projects currently using Moonstream:
|
||||
|
||||
1. [Laguna Games](https://laguna.games), makers of [Crypto Unicorns](https://cryptounicorns.fun)
|
||||
2. [RealtyBits](https://realtybits.com)
|
||||
2. [Game7](https://game7.io)
|
||||
3. [Champions Ascension](https://www.champions.io/)
|
||||
|
||||
Please read [the Game Master's Guide to Moonstream Solutions](https://docs.google.com/document/d/1mjfF8SgRrAZvtCVVxB2qNSUcbbmrH6dTEYSMfHKdEgc/view) if you want to know how Moonstream tools are applied in web3 games.
|
||||
|
||||
[Moonworm tool](https://github.com/bugout-dev/moonworm) is used to build datasets of on-chain data related to market activity. The dataset with on-chain activity from the Ethereum NFT market (April 1 to September 25, 2021) is available [on Kaggle](https://www.kaggle.com/datasets/simiotic/ethereum-nfts). The full report on it is published on [GitHub](https://github.com/bugout-dev/moonstream/blob/main/datasets/nfts/papers/ethereum-nfts.pdf).
|
||||
|
||||
## Free software
|
||||
|
||||
|
@ -62,4 +83,4 @@ docker-compose up --build
|
|||
|
||||
## Contributing
|
||||
|
||||
If you would like to contribute to Moonstream, please reach out to @zomglings on the [Moonstream Discord](https://discord.gg/pYE65FuNSz).
|
||||
We are working on contributing guidelines. In the meantime, please reach out to @zomglings on the [Moonstream Discord](https://discord.gg/pYE65FuNSz).
|
||||
|
|
|
@ -23,11 +23,9 @@ PIP="${PYTHON_ENV_DIR}/bin/pip"
|
|||
SCRIPT_DIR="$(realpath $(dirname $0))"
|
||||
SECRETS_DIR="${SECRETS_DIR:-/home/ubuntu/moonstream-secrets}"
|
||||
PARAMETERS_ENV_PATH="${SECRETS_DIR}/app.env"
|
||||
AWS_SSM_PARAMETER_PATH="${AWS_SSM_PARAMETER_PATH:-/moonstream/prod}"
|
||||
PARAMETERS_SCRIPT="${SCRIPT_DIR}/parameters.py"
|
||||
|
||||
# API server service file
|
||||
SERVICE_FILE="${SCRIPT_DIR}/moonstreamapi.service"
|
||||
MOONSTREAM_API_SERVICE_FILE="moonstream.service"
|
||||
|
||||
set -eu
|
||||
|
||||
|
@ -41,27 +39,21 @@ echo
|
|||
echo -e "${PREFIX_INFO} Installing Python dependencies"
|
||||
"${PIP}" install -e "${APP_BACKEND_DIR}/"
|
||||
|
||||
echo
|
||||
echo
|
||||
echo -e "${PREFIX_INFO} Retrieving deployment parameters"
|
||||
mkdir -p "${SECRETS_DIR}"
|
||||
AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}" "${PYTHON}" "${PARAMETERS_SCRIPT}" "${AWS_SSM_PARAMETER_PATH}" -o "${PARAMETERS_ENV_PATH}"
|
||||
|
||||
echo
|
||||
echo
|
||||
echo -e "${PREFIX_INFO} Install checkenv"
|
||||
HOME=/root /usr/local/go/bin/go install github.com/bugout-dev/checkenv@latest
|
||||
HOME=/home/ubuntu /usr/local/go/bin/go install github.com/bugout-dev/checkenv@latest
|
||||
|
||||
echo
|
||||
echo
|
||||
echo -e "${PREFIX_INFO} Retrieving addition deployment parameters"
|
||||
AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}" /root/go/bin/checkenv show aws_ssm+Product:moonstream >> "${PARAMETERS_ENV_PATH}"
|
||||
mkdir -p "${SECRETS_DIR}"
|
||||
AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}" /home/ubuntu/go/bin/checkenv show aws_ssm+moonstream:true > "${PARAMETERS_ENV_PATH}"
|
||||
|
||||
echo
|
||||
echo
|
||||
echo -e "${PREFIX_INFO} Replacing existing Moonstream API service definition with ${SERVICE_FILE}"
|
||||
chmod 644 "${SERVICE_FILE}"
|
||||
cp "${SERVICE_FILE}" /etc/systemd/system/moonstreamapi.service
|
||||
systemctl daemon-reload
|
||||
systemctl restart moonstreamapi.service
|
||||
systemctl status moonstreamapi.service
|
||||
echo -e "${PREFIX_INFO} Replacing existing Moonstream API service definition with ${MOONSTREAM_API_SERVICE_FILE}"
|
||||
chmod 644 "${SCRIPT_DIR}/${MOONSTREAM_API_SERVICE_FILE}"
|
||||
cp "${SCRIPT_DIR}/${MOONSTREAM_API_SERVICE_FILE}" "/home/ubuntu/.config/systemd/user/${MOONSTREAM_API_SERVICE_FILE}"
|
||||
XDG_RUNTIME_DIR="/run/user/1000" systemctl --user daemon-reload
|
||||
XDG_RUNTIME_DIR="/run/user/1000" systemctl --user restart "${MOONSTREAM_API_SERVICE_FILE}"
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
[Unit]
|
||||
Description=moonstreamapi-service
|
||||
After=network.target
|
||||
StartLimitIntervalSec=300
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
User=ubuntu
|
||||
Group=www-data
|
||||
WorkingDirectory=/home/ubuntu/moonstream/backend
|
||||
EnvironmentFile=/home/ubuntu/moonstream-secrets/app.env
|
||||
Restart=on-failure
|
||||
RestartSec=15s
|
||||
ExecStart=/home/ubuntu/moonstream-env/bin/uvicorn --proxy-headers --forwarded-allow-ips='127.0.0.1' --host 127.0.0.1 --port 7481 --workers 8 moonstreamapi.api:app
|
||||
SyslogIdentifier=moonstreamapi
|
||||
SyslogIdentifier=moonstream
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -22,9 +22,7 @@ PYTHON="${PYTHON_ENV_DIR}/bin/python"
|
|||
PIP="${PYTHON_ENV_DIR}/bin/pip"
|
||||
SECRETS_DIR="${SECRETS_DIR:-/home/ubuntu/moonstream-secrets}"
|
||||
PARAMETERS_ENV_PATH="${SECRETS_DIR}/app.env"
|
||||
AWS_SSM_PARAMETER_PATH="${AWS_SSM_PARAMETER_PATH:-/moonstream/prod}"
|
||||
SCRIPT_DIR="$(realpath $(dirname $0))"
|
||||
PARAMETERS_SCRIPT="${SCRIPT_DIR}/parameters.py"
|
||||
|
||||
# Service files
|
||||
MOONCRAWL_SERVICE_FILE="mooncrawl.service"
|
||||
|
@ -36,6 +34,7 @@ ETHEREUM_TRENDING_TIMER_FILE="ethereum-trending.timer"
|
|||
ETHEREUM_TXPOOL_SERVICE_FILE="ethereum-txpool.service"
|
||||
ETHEREUM_MISSING_SERVICE_FILE="ethereum-missing.service"
|
||||
ETHEREUM_MISSING_TIMER_FILE="ethereum-missing.timer"
|
||||
ETHEREUM_MOONWORM_CRAWLER_SERVICE_FILE="ethereum-moonworm-crawler.service"
|
||||
|
||||
# Polygon service files
|
||||
POLYGON_SYNCHRONIZE_SERVICE="polygon-synchronize.service"
|
||||
|
@ -51,6 +50,8 @@ POLYGON_STATE_CLEAN_SERVICE_FILE="polygon-state-clean.service"
|
|||
POLYGON_STATE_CLEAN_TIMER_FILE="polygon-state-clean.timer"
|
||||
POLYGON_METADATA_SERVICE_FILE="polygon-metadata.service"
|
||||
POLYGON_METADATA_TIMER_FILE="polygon-metadata.timer"
|
||||
POLYGON_CU_REPORTS_TOKENONOMICS_SERVICE_FILE="polygon-cu-reports-tokenonomics.service"
|
||||
POLYGON_CU_REPORTS_TOKENONOMICS_TIMER_FILE="polygon-cu-reports-tokenonomics.timer"
|
||||
|
||||
# Mumbai service files
|
||||
MUMBAI_SYNCHRONIZE_SERVICE="mumbai-synchronize.service"
|
||||
|
@ -86,12 +87,6 @@ echo
|
|||
echo -e "${PREFIX_INFO} Installing Python dependencies"
|
||||
"${PIP}" install -e "${APP_CRAWLERS_DIR}/mooncrawl/"
|
||||
|
||||
echo
|
||||
echo
|
||||
echo -e "${PREFIX_INFO} Retrieving deployment parameters"
|
||||
mkdir -p "${SECRETS_DIR}"
|
||||
AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}" "${PYTHON}" "${PARAMETERS_SCRIPT}" extract -p "${AWS_SSM_PARAMETER_PATH}" -o "${PARAMETERS_ENV_PATH}"
|
||||
|
||||
echo
|
||||
echo
|
||||
echo -e "${PREFIX_INFO} Install checkenv"
|
||||
|
@ -100,7 +95,8 @@ HOME=/root /usr/local/go/bin/go install github.com/bugout-dev/checkenv@latest
|
|||
echo
|
||||
echo
|
||||
echo -e "${PREFIX_INFO} Retrieving addition deployment parameters"
|
||||
AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}" /root/go/bin/checkenv show aws_ssm+Product:moonstream >> "${PARAMETERS_ENV_PATH}"
|
||||
mkdir -p "${SECRETS_DIR}"
|
||||
AWS_DEFAULT_REGION="${AWS_DEFAULT_REGION}" /root/go/bin/checkenv show aws_ssm+moonstream:true > "${PARAMETERS_ENV_PATH}"
|
||||
|
||||
echo
|
||||
echo
|
||||
|
@ -149,6 +145,14 @@ cp "${SCRIPT_DIR}/${ETHEREUM_MISSING_TIMER_FILE}" "/etc/systemd/system/${ETHEREU
|
|||
systemctl daemon-reload
|
||||
systemctl restart --no-block "${ETHEREUM_MISSING_TIMER_FILE}"
|
||||
|
||||
echo
|
||||
echo
|
||||
echo -e "${PREFIX_INFO} Replacing existing Ethereum moonworm crawler service definition with ${ETHEREUM_MOONWORM_CRAWLER_SERVICE_FILE}"
|
||||
chmod 644 "${SCRIPT_DIR}/${ETHEREUM_MOONWORM_CRAWLER_SERVICE_FILE}"
|
||||
cp "${SCRIPT_DIR}/${ETHEREUM_MOONWORM_CRAWLER_SERVICE_FILE}" "/etc/systemd/system/${ETHEREUM_MOONWORM_CRAWLER_SERVICE_FILE}"
|
||||
systemctl daemon-reload
|
||||
systemctl restart --no-block "${ETHEREUM_MOONWORM_CRAWLER_SERVICE_FILE}"
|
||||
|
||||
echo
|
||||
echo
|
||||
echo -e "${PREFIX_INFO} Replacing existing Polygon block with transactions syncronizer service definition with ${POLYGON_SYNCHRONIZE_SERVICE}"
|
||||
|
@ -276,3 +280,12 @@ cp "${SCRIPT_DIR}/${POLYGON_METADATA_SERVICE_FILE}" "/etc/systemd/system/${POLYG
|
|||
cp "${SCRIPT_DIR}/${POLYGON_METADATA_TIMER_FILE}" "/etc/systemd/system/${POLYGON_METADATA_TIMER_FILE}"
|
||||
systemctl daemon-reload
|
||||
systemctl restart --no-block "${POLYGON_METADATA_TIMER_FILE}"
|
||||
|
||||
echo
|
||||
echo
|
||||
echo -e "${PREFIX_INFO} Replacing existing Polygon CU reports tokenonomics service and timer with: ${POLYGON_CU_REPORTS_TOKENONOMICS_SERVICE_FILE}, ${POLYGON_CU_REPORTS_TOKENONOMICS_TIMER_FILE}"
|
||||
chmod 644 "${SCRIPT_DIR}/${POLYGON_CU_REPORTS_TOKENONOMICS_SERVICE_FILE}" "${SCRIPT_DIR}/${POLYGON_CU_REPORTS_TOKENONOMICS_TIMER_FILE}"
|
||||
cp "${SCRIPT_DIR}/${POLYGON_CU_REPORTS_TOKENONOMICS_SERVICE_FILE}" "/etc/systemd/system/${POLYGON_CU_REPORTS_TOKENONOMICS_SERVICE_FILE}"
|
||||
cp "${SCRIPT_DIR}/${POLYGON_CU_REPORTS_TOKENONOMICS_TIMER_FILE}" "/etc/systemd/system/${POLYGON_CU_REPORTS_TOKENONOMICS_TIMER_FILE}"
|
||||
systemctl daemon-reload
|
||||
systemctl restart --no-block "${POLYGON_CU_REPORTS_TOKENONOMICS_TIMER_FILE}"
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
[Unit]
|
||||
Description=Ethereum moonworm crawler
|
||||
After=network.target
|
||||
StartLimitIntervalSec=300
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
User=ubuntu
|
||||
Group=www-data
|
||||
WorkingDirectory=/home/ubuntu/moonstream/crawlers/mooncrawl
|
||||
EnvironmentFile=/home/ubuntu/moonstream-secrets/app.env
|
||||
Restart=on-failure
|
||||
RestartSec=15s
|
||||
ExecStart=/home/ubuntu/moonstream-env/bin/python -m mooncrawl.moonworm_crawler.cli --access-id "${NB_CONTROLLER_ACCESS_ID}" crawl -b ethereum
|
||||
CPUWeight=70
|
||||
SyslogIdentifier=ethereum-moonworm-crawler
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -2,7 +2,7 @@
|
|||
Description=Fill missing blocks at Mumbai database
|
||||
|
||||
[Timer]
|
||||
OnBootSec=30s
|
||||
OnBootSec=120s
|
||||
OnUnitActiveSec=15m
|
||||
|
||||
[Install]
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
[Unit]
|
||||
Description=Runs custom crawler for CU tokenonomics
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=ubuntu
|
||||
Group=www-data
|
||||
WorkingDirectory=/home/ubuntu/moonstream/crawlers/mooncrawl
|
||||
EnvironmentFile=/home/ubuntu/moonstream-secrets/app.env
|
||||
ExecStart=/home/ubuntu/moonstream-env/bin/python -m mooncrawl.cu_reports_crawler.cli cu-reports --moonstream-token "${MOONSTREAM_PUBLIC_QUERIES_DATA_ACCESS_TOKEN}" queries run-tokenonomics
|
||||
CPUWeight=60
|
||||
SyslogIdentifier=polygon-cu-reports-tokenonomics
|
|
@ -0,0 +1,9 @@
|
|||
[Unit]
|
||||
Description=Runs custom crawler for CU tokenonomics
|
||||
|
||||
[Timer]
|
||||
OnBootSec=60s
|
||||
OnUnitActiveSec=60m
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
|
@ -2,7 +2,7 @@
|
|||
Description=Fill missing blocks at Polygon database
|
||||
|
||||
[Timer]
|
||||
OnBootSec=30s
|
||||
OnBootSec=120s
|
||||
OnUnitActiveSec=15m
|
||||
|
||||
[Install]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Description=Fill missing blocks at XDai database
|
||||
|
||||
[Timer]
|
||||
OnBootSec=35s
|
||||
OnBootSec=120s
|
||||
OnUnitActiveSec=15m
|
||||
|
||||
[Install]
|
||||
|
|
|
@ -19,7 +19,7 @@ For a sample, view [`sample.env`](./sample.env).
|
|||
### Ethereum Signature Database
|
||||
|
||||
This crawler retrieves Ethereum function signatures from the Ethereum Signature Database at
|
||||
[https://4byte.directory](https://4byte.directory).
|
||||
[https://www.4byte.directory](https://www.4byte.directory).
|
||||
|
||||
#### Crawling ESD function signatures
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ async def queries_data_update_handler(
|
|||
|
||||
# request.params validations
|
||||
passed_params = {
|
||||
key: value
|
||||
key: queries.from_json_types(value)
|
||||
for key, value in request_data.params.items()
|
||||
if key in expected_query_parameters
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ async def queries_data_update_handler(
|
|||
query_id=f"{query_id}",
|
||||
file_type=request_data.file_type,
|
||||
query=valid_query,
|
||||
params=request_data.params,
|
||||
params=passed_params,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
@ -123,8 +123,6 @@ def add_block(db_session, block: Any, blockchain_type: AvailableBlockchainType)
|
|||
)
|
||||
if blockchain_type == AvailableBlockchainType.XDAI:
|
||||
block_obj.author = block.author
|
||||
block_obj.signature = block.signature
|
||||
block_obj.step = block.step
|
||||
|
||||
db_session.add(block_obj)
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ class TestDeploymentCrawler(TestCase):
|
|||
batch_size = 10
|
||||
result = get_batch_block_range(from_block, to_block, batch_size)
|
||||
|
||||
last_end: Optional[int] = None
|
||||
last_end: Optional[int] = None # type: ignore
|
||||
for batch_start, batch_end in result:
|
||||
if last_end is not None:
|
||||
self.assertEqual(batch_start, last_end + 1)
|
||||
|
@ -30,7 +30,7 @@ class TestDeploymentCrawler(TestCase):
|
|||
batch_size = 10
|
||||
result = get_batch_block_range(from_block, to_block, batch_size)
|
||||
|
||||
last_end: Optional[int] = None
|
||||
last_end: Optional[int] = None # type: ignore
|
||||
for batch_start, batch_end in result:
|
||||
if last_end is not None:
|
||||
self.assertEqual(batch_start, last_end - 1)
|
||||
|
|
|
@ -0,0 +1,635 @@
|
|||
import argparse
|
||||
import datetime
|
||||
import logging
|
||||
from moonstream.client import Moonstream # type: ignore
|
||||
import time
|
||||
import requests
|
||||
import json
|
||||
|
||||
from typing import Any, Dict, Union
|
||||
|
||||
from uuid import UUID
|
||||
|
||||
from .queries import tokenomics_queries, cu_bank_queries
|
||||
|
||||
from ..settings import (
|
||||
MOONSTREAM_S3_PUBLIC_DATA_BUCKET,
|
||||
MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX,
|
||||
)
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
addresess_erc20_721 = {
|
||||
"0x64060aB139Feaae7f06Ca4E63189D86aDEb51691": "ERC20", # UNIM
|
||||
"0x431CD3C9AC9Fc73644BF68bF5691f4B83F9E104f": "ERC20", # RBW
|
||||
"0xdC0479CC5BbA033B3e7De9F178607150B3AbCe1f": "NFT", # unicorns
|
||||
"0xA2a13cE1824F3916fC84C65e559391fc6674e6e8": "NFT", # lands
|
||||
"0xa7D50EE3D7485288107664cf758E877a0D351725": "NFT", # shadowcorns
|
||||
}
|
||||
|
||||
addresess_erc1155 = ["0x99A558BDBdE247C2B2716f0D4cFb0E246DFB697D"]
|
||||
|
||||
|
||||
def recive_S3_data_from_query(
|
||||
client: Moonstream,
|
||||
token: Union[str, UUID],
|
||||
query_name: str,
|
||||
params: Dict[str, Any],
|
||||
time_await: int = 2,
|
||||
max_retries: int = 30,
|
||||
) -> Any:
|
||||
|
||||
"""
|
||||
Await the query to be update data on S3 with if_modified_since and return new the data.
|
||||
"""
|
||||
|
||||
keep_going = True
|
||||
|
||||
repeat = 0
|
||||
|
||||
if_modified_since_datetime = datetime.datetime.utcnow()
|
||||
if_modified_since = if_modified_since_datetime.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
data_url = client.exec_query(
|
||||
token=token,
|
||||
name=query_name,
|
||||
params=params,
|
||||
) # S3 presign_url
|
||||
|
||||
while keep_going:
|
||||
time.sleep(time_await)
|
||||
try:
|
||||
data_response = requests.get(
|
||||
data_url.url,
|
||||
headers={"If-Modified-Since": if_modified_since},
|
||||
timeout=5,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
continue
|
||||
|
||||
if data_response.status_code == 200:
|
||||
break
|
||||
|
||||
repeat += 1
|
||||
|
||||
if repeat > max_retries:
|
||||
logger.info("Too many retries")
|
||||
break
|
||||
return data_response.json()
|
||||
|
||||
|
||||
def generate_report(
|
||||
client: Moonstream,
|
||||
token: Union[str, UUID],
|
||||
query_name: str,
|
||||
params: Dict[str, Any],
|
||||
bucket_prefix: str,
|
||||
bucket: str,
|
||||
key: str,
|
||||
):
|
||||
"""
|
||||
Generate the report.
|
||||
"""
|
||||
|
||||
try:
|
||||
|
||||
json_data = recive_S3_data_from_query(
|
||||
client=client,
|
||||
token=token,
|
||||
query_name=query_name,
|
||||
params=params,
|
||||
)
|
||||
|
||||
client.upload_query_results(
|
||||
json.dumps(json_data),
|
||||
bucket,
|
||||
f"{bucket_prefix}/{key}",
|
||||
)
|
||||
logger.info(
|
||||
f"Report generated and results uploaded at: https://{bucket}/{bucket_prefix}/{key}"
|
||||
)
|
||||
except Exception as err:
|
||||
logger.error(
|
||||
f"Cant recive or load data for s3, for query: {query_name}, bucket: {bucket}, key: {key}. End with error: {err}"
|
||||
)
|
||||
|
||||
|
||||
def create_user_query(
|
||||
client: Moonstream,
|
||||
token: Union[str, UUID],
|
||||
query_name: str,
|
||||
query: str,
|
||||
):
|
||||
"""
|
||||
Create a user query.
|
||||
"""
|
||||
|
||||
try:
|
||||
client.create_query(token=token, name=query_name, query=query)
|
||||
except Exception as err:
|
||||
logger.error(f"Cant create user query: {query_name}. End with error: {err}")
|
||||
|
||||
|
||||
def delete_user_query(client: Moonstream, token: str, query_name: str):
|
||||
"""
|
||||
Delete the user's queries.
|
||||
"""
|
||||
|
||||
id = client.delete_query(
|
||||
token=token,
|
||||
name=query_name,
|
||||
)
|
||||
|
||||
logger.info(f"Query with name:{query_name} and id: {id} was deleted")
|
||||
|
||||
|
||||
def init_game_bank_queries_handler(args: argparse.Namespace):
|
||||
|
||||
"""
|
||||
Create the game bank queries.
|
||||
"""
|
||||
|
||||
client = Moonstream()
|
||||
|
||||
for query in cu_bank_queries:
|
||||
|
||||
try:
|
||||
if args.overwrite:
|
||||
try:
|
||||
# delete
|
||||
delete_user_query(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query["name"],
|
||||
)
|
||||
except Exception as err:
|
||||
logger.error(err)
|
||||
# create
|
||||
created_entry = client.create_query(
|
||||
token=args.moonstream_token,
|
||||
name=query["name"],
|
||||
query=query["query"],
|
||||
)
|
||||
logger.info(
|
||||
f"Created query {query['name']} please validate it in the UI url {created_entry.journal_url}/entries/{created_entry.id}/"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
pass
|
||||
|
||||
|
||||
def init_tokenomics_queries_handler(args: argparse.Namespace):
|
||||
|
||||
"""
|
||||
Create the tokenomics queries.
|
||||
"""
|
||||
|
||||
client = Moonstream()
|
||||
|
||||
for query in tokenomics_queries:
|
||||
|
||||
try:
|
||||
if args.overwrite:
|
||||
try:
|
||||
# delete
|
||||
delete_user_query(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query["name"],
|
||||
)
|
||||
except Exception as err:
|
||||
logger.error(err)
|
||||
# create
|
||||
created_entry = client.create_query(
|
||||
token=args.moonstream_token,
|
||||
name=query["name"],
|
||||
query=query["query"],
|
||||
)
|
||||
logger.info(
|
||||
f"Created query {query['name']} please validate it in the UI url {created_entry.journal_url}/entries/{created_entry.id}/"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
pass
|
||||
|
||||
|
||||
def run_tokenomics_queries_handler(args: argparse.Namespace):
|
||||
|
||||
client = Moonstream()
|
||||
|
||||
query_name = "erc20_721_volume"
|
||||
|
||||
### Run voluem query
|
||||
|
||||
ranges = [
|
||||
{"time_format": "YYYY-MM-DD HH24", "time_range": "24 hours"},
|
||||
{"time_format": "YYYY-MM-DD HH24", "time_range": "7 days"},
|
||||
{"time_format": "YYYY-MM-DD", "time_range": "30 days"},
|
||||
]
|
||||
|
||||
# volume of erc20 and erc721
|
||||
|
||||
for address, type in addresess_erc20_721.items():
|
||||
for range in ranges:
|
||||
|
||||
params: Dict[str, Any] = {
|
||||
"address": address,
|
||||
"type": type,
|
||||
"time_format": range["time_format"],
|
||||
"time_range": range["time_range"],
|
||||
}
|
||||
|
||||
generate_report(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query_name,
|
||||
params=params,
|
||||
bucket_prefix=MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX,
|
||||
bucket=MOONSTREAM_S3_PUBLIC_DATA_BUCKET,
|
||||
key=f'{query_name}/{address}/{range["time_range"].replace(" ","_")}/data.json',
|
||||
)
|
||||
|
||||
# volume change of erc20 and erc721
|
||||
|
||||
query_name = "volume_change"
|
||||
|
||||
for address, type in addresess_erc20_721.items():
|
||||
for range in ranges:
|
||||
|
||||
params = {
|
||||
"address": address,
|
||||
"type": type,
|
||||
"time_range": range["time_range"],
|
||||
}
|
||||
|
||||
generate_report(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query_name,
|
||||
params=params,
|
||||
bucket_prefix=MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX,
|
||||
bucket=MOONSTREAM_S3_PUBLIC_DATA_BUCKET,
|
||||
key=f'{query_name}/{address}/{range["time_range"].replace(" ","_")}/data.json',
|
||||
)
|
||||
|
||||
query_name = "erc1155_volume"
|
||||
|
||||
# volume of erc1155
|
||||
|
||||
addresess_erc1155 = ["0x99A558BDBdE247C2B2716f0D4cFb0E246DFB697D"]
|
||||
|
||||
for address in addresess_erc1155:
|
||||
for range in ranges:
|
||||
|
||||
params = {
|
||||
"address": address,
|
||||
"time_format": range["time_format"],
|
||||
"time_range": range["time_range"],
|
||||
}
|
||||
|
||||
generate_report(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query_name,
|
||||
params=params,
|
||||
bucket_prefix=MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX,
|
||||
bucket=MOONSTREAM_S3_PUBLIC_DATA_BUCKET,
|
||||
key=f"{query_name}/{address}/{range['time_range'].replace(' ','_')}/data.json",
|
||||
)
|
||||
|
||||
# most_recent_sale
|
||||
|
||||
query_name = "most_recent_sale"
|
||||
|
||||
for address, type in addresess_erc20_721.items():
|
||||
if type == "NFT":
|
||||
for amount in [10, 100]:
|
||||
params = {
|
||||
"address": address,
|
||||
"amount": amount,
|
||||
}
|
||||
|
||||
generate_report(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query_name,
|
||||
params=params,
|
||||
bucket_prefix=MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX,
|
||||
bucket=MOONSTREAM_S3_PUBLIC_DATA_BUCKET,
|
||||
key=f"{query_name}/{address}/{amount}/data.json",
|
||||
)
|
||||
|
||||
# most_active_buyers
|
||||
|
||||
query_name = "most_active_buyers"
|
||||
|
||||
for address, type in addresess_erc20_721.items():
|
||||
|
||||
if type == "NFT":
|
||||
|
||||
for range in ranges:
|
||||
|
||||
params = {
|
||||
"address": address,
|
||||
"time_range": range["time_range"],
|
||||
}
|
||||
|
||||
generate_report(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query_name,
|
||||
params=params,
|
||||
bucket_prefix=MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX,
|
||||
bucket=MOONSTREAM_S3_PUBLIC_DATA_BUCKET,
|
||||
key=f"{query_name}/{address}/{range['time_range'].replace(' ','_')}/data.json",
|
||||
)
|
||||
|
||||
# most_active_sellers
|
||||
|
||||
query_name = "most_active_sellers"
|
||||
|
||||
for address, type in addresess_erc20_721.items():
|
||||
|
||||
if type == "NFT":
|
||||
|
||||
for range in ranges:
|
||||
|
||||
params = {
|
||||
"address": address,
|
||||
"time_range": range["time_range"],
|
||||
}
|
||||
|
||||
generate_report(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query_name,
|
||||
params=params,
|
||||
bucket_prefix=MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX,
|
||||
bucket=MOONSTREAM_S3_PUBLIC_DATA_BUCKET,
|
||||
key=f"{query_name}/{address}/{range['time_range'].replace(' ','_')}/data.json",
|
||||
)
|
||||
|
||||
# lagerst_owners
|
||||
|
||||
query_name = "lagerst_owners"
|
||||
for address, type in addresess_erc20_721.items():
|
||||
|
||||
if type == "NFT":
|
||||
|
||||
params = {
|
||||
"address": address,
|
||||
}
|
||||
|
||||
generate_report(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query_name,
|
||||
params=params,
|
||||
bucket_prefix=MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX,
|
||||
bucket=MOONSTREAM_S3_PUBLIC_DATA_BUCKET,
|
||||
key=f"{query_name}/{address}/data.json",
|
||||
)
|
||||
|
||||
# total_supply_erc721
|
||||
|
||||
query_name = "total_supply_erc721"
|
||||
|
||||
for address, type in addresess_erc20_721.items():
|
||||
|
||||
if type == "NFT":
|
||||
|
||||
params = {
|
||||
"address": address,
|
||||
}
|
||||
|
||||
generate_report(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query_name,
|
||||
params=params,
|
||||
bucket_prefix=MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX,
|
||||
bucket=MOONSTREAM_S3_PUBLIC_DATA_BUCKET,
|
||||
key=f"{query_name}/{address}/data.json",
|
||||
)
|
||||
|
||||
# total_supply_terminus
|
||||
|
||||
query_name = "total_supply_terminus"
|
||||
|
||||
for address in addresess_erc1155:
|
||||
|
||||
params = {
|
||||
"address": address,
|
||||
}
|
||||
|
||||
generate_report(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query_name,
|
||||
params=params,
|
||||
bucket_prefix=MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX,
|
||||
bucket=MOONSTREAM_S3_PUBLIC_DATA_BUCKET,
|
||||
key=f"{query_name}/{address}/data.json",
|
||||
)
|
||||
|
||||
logger.info("Done")
|
||||
|
||||
|
||||
def list_user_queries_handler(args: argparse.Namespace):
|
||||
"""
|
||||
List the user's queries.
|
||||
"""
|
||||
|
||||
client = Moonstream()
|
||||
|
||||
queries = client.list_queries(
|
||||
token=args.moonstream_token,
|
||||
)
|
||||
|
||||
for query in queries.queries:
|
||||
logger.info(query.name, query.id)
|
||||
|
||||
|
||||
def delete_user_query_handler(args: argparse.Namespace):
|
||||
"""
|
||||
Delete the user's queries.
|
||||
"""
|
||||
client = Moonstream()
|
||||
|
||||
delete_user_query(client=client, token=args.moonstream_token, query_name=args.name)
|
||||
|
||||
|
||||
def create_user_query_handler(args: argparse.Namespace):
|
||||
"""
|
||||
Create the user's queries.
|
||||
"""
|
||||
client = Moonstream()
|
||||
|
||||
for query in tokenomics_queries:
|
||||
|
||||
if query["name"] == args.name:
|
||||
|
||||
create_user_query(
|
||||
client=client,
|
||||
token=args.moonstream_token,
|
||||
query_name=query["name"],
|
||||
query=query["query"],
|
||||
)
|
||||
|
||||
|
||||
def generate_game_bank_report(args: argparse.Namespace):
|
||||
"""
|
||||
han
|
||||
Generate the game bank query.
|
||||
"""
|
||||
|
||||
client = Moonstream()
|
||||
|
||||
for query in client.list_queries(
|
||||
token=args.moonstream_token,
|
||||
).queries:
|
||||
|
||||
params = {}
|
||||
|
||||
if (
|
||||
query.name == "cu-bank-withdrawals-total"
|
||||
or query.name == "cu-bank-withdrawals-events"
|
||||
):
|
||||
blocktimestamp = int(time.time())
|
||||
params = {"block_timestamp": blocktimestamp}
|
||||
|
||||
keep_going = True
|
||||
|
||||
if_modified_since_datetime = datetime.datetime.utcnow()
|
||||
if_modified_since = if_modified_since_datetime.strftime(
|
||||
"%a, %d %b %Y %H:%M:%S GMT"
|
||||
)
|
||||
|
||||
data_url = client.exec_query(
|
||||
token=args.moonstream_token,
|
||||
query_name=query.name,
|
||||
params=params,
|
||||
) # S3 presign_url
|
||||
while keep_going:
|
||||
data_response = requests.get(
|
||||
data_url,
|
||||
headers={"If-Modified-Since": if_modified_since},
|
||||
timeout=10,
|
||||
)
|
||||
# push to s3
|
||||
|
||||
if data_response.status_code == 200:
|
||||
json.dumps(data_response.json())
|
||||
break
|
||||
else:
|
||||
time.sleep(2)
|
||||
continue
|
||||
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.set_defaults(func=lambda _: parser.print_help())
|
||||
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
cu_reports_parser = subparsers.add_parser("cu-reports", help="CU Reports")
|
||||
|
||||
cu_reports_subparsers = cu_reports_parser.add_subparsers()
|
||||
|
||||
cu_reports_parser.add_argument(
|
||||
"--moonstream-token",
|
||||
required=True,
|
||||
type=str,
|
||||
)
|
||||
queries_parser = cu_reports_subparsers.add_parser(
|
||||
"queries",
|
||||
help="Queries commands",
|
||||
)
|
||||
|
||||
queries_parser.set_defaults(func=lambda _: queries_parser.print_help())
|
||||
|
||||
queries_subparsers = queries_parser.add_subparsers()
|
||||
|
||||
queries_subparsers.add_parser(
|
||||
"list",
|
||||
help="List all queries",
|
||||
description="List all queries",
|
||||
).set_defaults(func=list_user_queries_handler)
|
||||
|
||||
init_game_bank_parser = queries_subparsers.add_parser(
|
||||
"init-game-bank",
|
||||
help="Create all predifind query",
|
||||
description="Create all predifind query",
|
||||
)
|
||||
|
||||
init_game_bank_parser.add_argument("--overwrite", type=bool, default=False)
|
||||
|
||||
init_game_bank_parser.set_defaults(func=init_game_bank_queries_handler)
|
||||
|
||||
init_tokenonomics_parser = queries_subparsers.add_parser(
|
||||
"init-tokenonomics",
|
||||
help="Create all predifind query",
|
||||
description="Create all predifind query",
|
||||
)
|
||||
|
||||
init_tokenonomics_parser.add_argument("--overwrite", type=bool, default=False)
|
||||
|
||||
init_tokenonomics_parser.set_defaults(func=init_tokenomics_queries_handler)
|
||||
|
||||
generate_report = queries_subparsers.add_parser(
|
||||
"run-tokenonomics",
|
||||
help="Run tokenomics queries and push to S3 public backet",
|
||||
description="Run tokenomics queries and push to S3 public backet",
|
||||
)
|
||||
|
||||
generate_report.set_defaults(func=run_tokenomics_queries_handler)
|
||||
|
||||
delete_query = queries_subparsers.add_parser(
|
||||
"delete",
|
||||
help="Delete all predifind query",
|
||||
description="Delete all predifind query",
|
||||
)
|
||||
|
||||
delete_query.add_argument(
|
||||
"--name",
|
||||
required=True,
|
||||
type=str,
|
||||
)
|
||||
|
||||
delete_query.set_defaults(func=delete_user_query_handler)
|
||||
|
||||
create_query = queries_subparsers.add_parser(
|
||||
"create",
|
||||
help="Create all predifind query",
|
||||
description="Create all predifind query",
|
||||
)
|
||||
|
||||
create_query.add_argument(
|
||||
"--name",
|
||||
required=True,
|
||||
type=str,
|
||||
)
|
||||
|
||||
create_query.set_defaults(func=create_user_query_handler)
|
||||
|
||||
cu_bank_parser = cu_reports_subparsers.add_parser(
|
||||
"generate-reports",
|
||||
help="Generate cu-bank state reports",
|
||||
)
|
||||
|
||||
cu_bank_parser.set_defaults(func=generate_game_bank_report)
|
||||
args = parser.parse_args()
|
||||
args.func(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,701 @@
|
|||
cu_bank_queries = [
|
||||
{
|
||||
"name": "cu-bank-blances",
|
||||
"query": """
|
||||
WITH game_contract as (
|
||||
SELECT
|
||||
*
|
||||
from
|
||||
polygon_labels
|
||||
where
|
||||
address = '0x94f557dDdb245b11d031F57BA7F2C4f28C4A203e'
|
||||
and label = 'moonworm-alpha'
|
||||
)
|
||||
SELECT
|
||||
address,
|
||||
div(sum(
|
||||
CASE
|
||||
WHEN result_balances.token_address = '0x64060aB139Feaae7f06Ca4E63189D86aDEb51691' THEN amount
|
||||
ELSE 0
|
||||
END
|
||||
), 10^18::decimal) as UNIM_BALANCE,
|
||||
div(sum(
|
||||
CASE
|
||||
WHEN result_balances.token_address = '0x431CD3C9AC9Fc73644BF68bF5691f4B83F9E104f' THEN amount
|
||||
ELSE 0
|
||||
END
|
||||
), 10^18::decimal) as RBW_BALANCE
|
||||
FROM
|
||||
(
|
||||
select
|
||||
transaction_hash,
|
||||
label_data -> 'args' ->> 'player' as address,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'tokenAddresses') ->> 0 as token_address,
|
||||
- jsonb_array_elements(label_data -> 'args' -> 'tokenAmounts') :: decimal as amount
|
||||
from
|
||||
game_contract
|
||||
where
|
||||
label_data ->> 'name' = 'UnstashedMultiple'
|
||||
union
|
||||
ALL
|
||||
select
|
||||
transaction_hash,
|
||||
label_data -> 'args' ->> 'player' as address,
|
||||
label_data -> 'args' ->> 'token' as token_address,
|
||||
-((label_data -> 'args' -> 'amount') :: decimal) as amount
|
||||
from
|
||||
game_contract
|
||||
where
|
||||
label_data ->> 'name' = 'Unstashed'
|
||||
union
|
||||
ALL
|
||||
select
|
||||
transaction_hash,
|
||||
label_data -> 'args' ->> 'player' as address,
|
||||
label_data -> 'args' ->> 'token' as token_address,
|
||||
(label_data -> 'args' ->> 'amount') :: decimal as amount
|
||||
from
|
||||
game_contract
|
||||
where
|
||||
label_data ->> 'name' = 'Stashed'
|
||||
union
|
||||
ALL
|
||||
select
|
||||
transaction_hash,
|
||||
label_data -> 'args' ->> 'player' as address,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'tokenAddresses') ->> 0 as token_address,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'tokenAmounts') :: decimal as amount
|
||||
from
|
||||
game_contract
|
||||
where
|
||||
label_data ->> 'name' = 'StashedMultiple'
|
||||
|
||||
) result_balances
|
||||
group by
|
||||
address
|
||||
ORDER BY
|
||||
UNIM_BALANCE DESC,
|
||||
RBW_BALANCE DESC
|
||||
""",
|
||||
},
|
||||
{
|
||||
"name": "cu-bank-withdrawals-total",
|
||||
"query": """
|
||||
WITH game_contract as (
|
||||
SELECT
|
||||
*
|
||||
from
|
||||
polygon_labels
|
||||
where
|
||||
address = '0x94f557dDdb245b11d031F57BA7F2C4f28C4A203e'
|
||||
and label = 'moonworm-alpha'
|
||||
block_timestamp >= :block_timestamp
|
||||
), withdoraws_total as (
|
||||
SELECT
|
||||
address,
|
||||
div(sum(
|
||||
CASE
|
||||
WHEN result_balances.token_address = '0x64060aB139Feaae7f06Ca4E63189D86aDEb51691' THEN amount
|
||||
ELSE 0
|
||||
END
|
||||
), 10^18::decimal) as UNIM_BALANCE,
|
||||
div(sum(
|
||||
CASE
|
||||
WHEN result_balances.token_address = '0x431CD3C9AC9Fc73644BF68bF5691f4B83F9E104f' THEN amount
|
||||
ELSE 0
|
||||
END
|
||||
), 10^18::decimal) as RBW_BALANCE
|
||||
FROM
|
||||
(
|
||||
select
|
||||
transaction_hash,
|
||||
label_data -> 'args' ->> 'player' as address,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'tokenAddresses') ->> 0 as token_address,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'tokenAmounts') :: decimal as amount
|
||||
from
|
||||
game_contract
|
||||
where
|
||||
label_data ->> 'name' = 'UnstashedMultiple'
|
||||
union
|
||||
ALL
|
||||
select
|
||||
transaction_hash,
|
||||
label_data -> 'args' ->> 'player' as address,
|
||||
label_data -> 'args' ->> 'token' as token_address,
|
||||
((label_data -> 'args' -> 'amount') :: decimal) as amount
|
||||
from
|
||||
game_contract
|
||||
where
|
||||
label_data ->> 'name' = 'Unstashed'
|
||||
) result_balances
|
||||
group by
|
||||
address
|
||||
ORDER BY
|
||||
UNIM_BALANCE DESC,
|
||||
RBW_BALANCE DESC
|
||||
)
|
||||
SELECT
|
||||
address,
|
||||
UNIM_BALANCE,
|
||||
RBW_BALANCE,
|
||||
UNIM_BALANCE + RBW_BALANCE as TOTAL
|
||||
FROM
|
||||
withdoraws_total
|
||||
ORDER BY
|
||||
TOTAL DESC;
|
||||
""",
|
||||
},
|
||||
{
|
||||
"name": "cu-bank-withdrawals-events",
|
||||
"query": """
|
||||
WITH game_contract as (
|
||||
SELECT
|
||||
*
|
||||
from
|
||||
polygon_labels
|
||||
where
|
||||
address = '0x94f557dDdb245b11d031F57BA7F2C4f28C4A203e'
|
||||
and label = 'moonworm-alpha'
|
||||
block_timestamp >= :block_timestamp
|
||||
), withdoraws_total as (
|
||||
SELECT
|
||||
address,
|
||||
CASE
|
||||
WHEN result_balances.token_address = '0x64060aB139Feaae7f06Ca4E63189D86aDEb51691' THEN 'UNIM'
|
||||
WHEN result_balances.token_address = '0x431CD3C9AC9Fc73644BF68bF5691f4B83F9E104f' THEN 'RBW'
|
||||
END as currency,
|
||||
div(amount, 10^18::decimal) as amount
|
||||
FROM
|
||||
(
|
||||
select
|
||||
transaction_hash,
|
||||
label_data -> 'args' ->> 'player' as address,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'tokenAddresses') ->> 0 as token_address,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'tokenAmounts') :: decimal as amount
|
||||
from
|
||||
game_contract
|
||||
where
|
||||
label_data ->> 'name' = 'UnstashedMultiple'
|
||||
union
|
||||
ALL
|
||||
select
|
||||
transaction_hash,
|
||||
label_data -> 'args' ->> 'player' as address,
|
||||
label_data -> 'args' ->> 'token' as token_address,
|
||||
((label_data -> 'args' -> 'amount') :: decimal) as amount
|
||||
from
|
||||
game_contract
|
||||
where
|
||||
label_data ->> 'name' = 'Unstashed'
|
||||
) result_balances
|
||||
)
|
||||
SELECT
|
||||
address,
|
||||
currency,
|
||||
amount,
|
||||
FROM
|
||||
withdoraws_total
|
||||
ORDER BY
|
||||
amount DESC
|
||||
""",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
tokenomics_queries = [
|
||||
{
|
||||
"name": "volume_change",
|
||||
"query": """
|
||||
with all_transfers as (
|
||||
select
|
||||
transaction_hash,
|
||||
CASE
|
||||
WHEN type: ='NFT' THEN 1
|
||||
ELSE (label_data->'args'->>'value')::decimal
|
||||
END as value,
|
||||
block_timestamp as block_timestamp
|
||||
from polygon_labels
|
||||
where label='moonworm-alpha'
|
||||
and address= :address
|
||||
and label_data->>'name'='Transfer'
|
||||
), after_range_transfer as (
|
||||
select
|
||||
*
|
||||
FROM
|
||||
all_transfers
|
||||
where block_timestamp >= extract(epoch from now() - interval :time_range)::int
|
||||
), current_volume as (
|
||||
SELECT
|
||||
sum(all_transfers.value) as value,
|
||||
sum(
|
||||
CASE
|
||||
WHEN to_address in ('0xF715bEb51EC8F63317d66f491E37e7BB048fCc2d','0xfede379e48C873C75F3cc0C81F7C784aD730a8F7','0x00000000006c3852cbef3e08e8df289169ede581')
|
||||
THEN 1
|
||||
else 0
|
||||
END
|
||||
) as os_sales
|
||||
from all_transfers
|
||||
LEFT JOIN polygon_transactions ON all_transfers.transaction_hash = polygon_transactions.hash
|
||||
), volume_different as (
|
||||
select
|
||||
sum(after_range_transfer.value) as value,
|
||||
sum(
|
||||
CASE
|
||||
WHEN to_address in ('0xF715bEb51EC8F63317d66f491E37e7BB048fCc2d','0xfede379e48C873C75F3cc0C81F7C784aD730a8F7','0x00000000006c3852cbef3e08e8df289169ede581')
|
||||
THEN 1
|
||||
else 0
|
||||
END
|
||||
) as os_sales
|
||||
from after_range_transfer
|
||||
LEFT JOIN polygon_transactions ON after_range_transfer.transaction_hash = polygon_transactions.hash
|
||||
)
|
||||
SELECT
|
||||
volume_different.value as diff,
|
||||
volume_different.os_sales as os_diff,
|
||||
current_volume.value as current,
|
||||
current_volume.os_sales as os_current
|
||||
from current_volume, volume_different
|
||||
""",
|
||||
},
|
||||
{
|
||||
"name": "erc20_721_volume",
|
||||
"query": """
|
||||
with interval_transfers as (
|
||||
select
|
||||
transaction_hash,
|
||||
CASE
|
||||
WHEN :type ='NFT' THEN 1
|
||||
ELSE (label_data->'args'->>'value')::decimal
|
||||
END as value,
|
||||
label_data->'args'->>'to' as buyer,
|
||||
label_data->'args'->>'from' as seller,
|
||||
to_char(to_timestamp(block_timestamp), :time_format) as time
|
||||
from polygon_labels
|
||||
where label='moonworm-alpha'
|
||||
and address= :address
|
||||
and label_data->>'name'='Transfer'
|
||||
and block_timestamp >= extract(epoch from now() - interval :time_range)::int
|
||||
)
|
||||
SELECT
|
||||
time as time,
|
||||
sum(interval_transfers.value) as value,
|
||||
sum(
|
||||
CASE
|
||||
WHEN to_address in ('0xF715bEb51EC8F63317d66f491E37e7BB048fCc2d','0xfede379e48C873C75F3cc0C81F7C784aD730a8F7','0x00000000006c3852cbef3e08e8df289169ede581')
|
||||
THEN 1
|
||||
else 0
|
||||
END
|
||||
) as os_sales
|
||||
from interval_transfers
|
||||
LEFT JOIN polygon_transactions ON interval_transfers.transaction_hash = polygon_transactions.hash
|
||||
GROUP BY time
|
||||
""",
|
||||
},
|
||||
{
|
||||
"name": "erc1155_volume",
|
||||
"query": """
|
||||
with labels_data as (
|
||||
select
|
||||
*
|
||||
from
|
||||
polygon_labels
|
||||
where address= :address
|
||||
AND label='moonworm-alpha'
|
||||
AND block_timestamp >= extract(epoch from now() - interval :time_range)::int
|
||||
),
|
||||
nfts_data as (
|
||||
select
|
||||
transaction_hash,
|
||||
label_data->'args'->>'to' as buyer,
|
||||
label_data->'args'->>'from' as seller,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'values') :: decimal as value,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'ids')->>0 as token_id,
|
||||
to_char(to_timestamp(block_timestamp), :time_format) as time
|
||||
from
|
||||
labels_data
|
||||
where
|
||||
label_data ->> 'name' = 'TransferBatch'
|
||||
UNION ALL
|
||||
select
|
||||
transaction_hash,
|
||||
label_data->'args'->>'to' as buyer,
|
||||
label_data->'args'->>'from' as seller,
|
||||
(label_data -> 'args' ->> 'value') :: decimal as value,
|
||||
label_data -> 'args' ->> 'id' as token_id,
|
||||
to_char(to_timestamp(block_timestamp), :time_format) as time
|
||||
from
|
||||
labels_data
|
||||
where
|
||||
label_data ->> 'name' = 'TransferSingle'
|
||||
)
|
||||
SELECT
|
||||
time as time,
|
||||
token_id as token_id,
|
||||
sum(nfts_data.value) as value,
|
||||
sum(
|
||||
CASE
|
||||
WHEN to_address in ('0xF715bEb51EC8F63317d66f491E37e7BB048fCc2d','0xfede379e48C873C75F3cc0C81F7C784aD730a8F7','0x00000000006c3852cbef3e08e8df289169ede581')
|
||||
THEN 1
|
||||
else 0
|
||||
END
|
||||
) as os_sales
|
||||
from nfts_data
|
||||
LEFT JOIN polygon_transactions ON nfts_data.transaction_hash = polygon_transactions.hash
|
||||
GROUP BY
|
||||
time,
|
||||
token_id
|
||||
ORDER BY token_id::int, time DESC
|
||||
""",
|
||||
},
|
||||
{
|
||||
"name": "most_recent_sale",
|
||||
"query": """
|
||||
with contract_erc721_transfers as (
|
||||
select
|
||||
transaction_hash,
|
||||
label_data->'args'->>'tokenId' as token_id,
|
||||
label_data->'args'->>'to' as buyer,
|
||||
label_data->'args'->>'from' as seller,
|
||||
block_timestamp as block_timestamp
|
||||
from polygon_labels
|
||||
where label='moonworm-alpha'
|
||||
and address= :address
|
||||
and label_data->>'name'='Transfer'
|
||||
order by block_number desc
|
||||
|
||||
)
|
||||
SELECT
|
||||
polygon_transactions.hash as transaction_hash,
|
||||
contract_erc721_transfers.block_timestamp as block_timestamp,
|
||||
contract_erc721_transfers.token_id as token_id,
|
||||
contract_erc721_transfers.buyer as buyer,
|
||||
contract_erc721_transfers.seller as seller
|
||||
from polygon_transactions
|
||||
inner JOIN contract_erc721_transfers ON contract_erc721_transfers.transaction_hash = polygon_transactions.hash
|
||||
where polygon_transactions.to_address in ('0xF715bEb51EC8F63317d66f491E37e7BB048fCc2d','0xfede379e48C873C75F3cc0C81F7C784aD730a8F7', '0x00000000006c3852cbef3e08e8df289169ede581')
|
||||
limit :amount
|
||||
""",
|
||||
},
|
||||
{
|
||||
"name": "most_active_buyers",
|
||||
"query": """
|
||||
with contracts_data as (
|
||||
select
|
||||
*
|
||||
from polygon_labels
|
||||
where label='moonworm-alpha'
|
||||
and address= :address
|
||||
and block_timestamp >= extract(epoch from now() - interval :time_range)::int
|
||||
), contract_nfts_transfers as (
|
||||
select
|
||||
transaction_hash,
|
||||
label_data->'args'->>'to' as buyer,
|
||||
label_data->'args'->>'from' as seller
|
||||
from contracts_data
|
||||
where label_data->>'name'='Transfer'
|
||||
UNION ALL
|
||||
select
|
||||
transaction_hash,
|
||||
label_data->'args'->>'to' as buyer,
|
||||
label_data->'args'->>'from' as seller
|
||||
from
|
||||
contracts_data
|
||||
where
|
||||
label_data ->> 'name' = 'TransferBatch'
|
||||
UNION ALL
|
||||
select
|
||||
transaction_hash,
|
||||
label_data->'args'->>'to' as buyer,
|
||||
label_data->'args'->>'from' as seller
|
||||
from
|
||||
contracts_data
|
||||
where
|
||||
label_data ->> 'name' = 'TransferSingle'
|
||||
|
||||
)
|
||||
SELECT
|
||||
contract_nfts_transfers.buyer as buyer,
|
||||
count(*) as sale_count
|
||||
from polygon_transactions
|
||||
inner JOIN contract_nfts_transfers ON contract_nfts_transfers.transaction_hash = polygon_transactions.hash
|
||||
where polygon_transactions.to_address in ('0xF715bEb51EC8F63317d66f491E37e7BB048fCc2d','0xfede379e48C873C75F3cc0C81F7C784aD730a8F7','0x00000000006c3852cbEf3e08E8dF289169EdE581')
|
||||
group by contract_nfts_transfers.buyer
|
||||
order by sale_count desc
|
||||
""",
|
||||
},
|
||||
{
|
||||
"name": "most_active_sellers",
|
||||
"query": """
|
||||
with contracts_data as (
|
||||
select
|
||||
*
|
||||
from polygon_labels
|
||||
where label='moonworm-alpha'
|
||||
and address= :address
|
||||
and block_timestamp >= extract(epoch from now() - interval :time_range)::int
|
||||
), contract_nfts_transfers as (
|
||||
select
|
||||
transaction_hash,
|
||||
label_data->'args'->>'to' as buyer,
|
||||
label_data->'args'->>'from' as seller
|
||||
from contracts_data
|
||||
where label_data->>'name'='Transfer'
|
||||
UNION ALL
|
||||
select
|
||||
transaction_hash,
|
||||
label_data->'args'->>'to' as buyer,
|
||||
label_data->'args'->>'from' as seller
|
||||
from
|
||||
contracts_data
|
||||
where
|
||||
label_data ->> 'name' = 'TransferBatch'
|
||||
UNION ALL
|
||||
select
|
||||
transaction_hash,
|
||||
label_data->'args'->>'to' as buyer,
|
||||
label_data->'args'->>'from' as seller
|
||||
from
|
||||
contracts_data
|
||||
where
|
||||
label_data ->> 'name' = 'TransferSingle'
|
||||
|
||||
)
|
||||
SELECT
|
||||
contract_nfts_transfers.seller as seller,
|
||||
count(*) as sale_count
|
||||
from polygon_transactions
|
||||
inner JOIN contract_nfts_transfers ON contract_nfts_transfers.transaction_hash = polygon_transactions.hash
|
||||
where polygon_transactions.to_address in ('0xF715bEb51EC8F63317d66f491E37e7BB048fCc2d','0xfede379e48C873C75F3cc0C81F7C784aD730a8F7','0x00000000006c3852cbEf3e08E8dF289169EdE581')
|
||||
group by contract_nfts_transfers.seller
|
||||
order by sale_count desc
|
||||
""",
|
||||
},
|
||||
{
|
||||
"name": "lagerst_owners",
|
||||
"query": """
|
||||
WITH erc_1155_721_contracts_transfers_with_trashhold as (
|
||||
SELECT
|
||||
label_data as label_data,
|
||||
block_timestamp as block_timestamp,
|
||||
address as address
|
||||
from
|
||||
polygon_labels
|
||||
WHERE
|
||||
polygon_labels.label = 'moonworm-alpha'
|
||||
AND polygon_labels.address = :address
|
||||
|
||||
),
|
||||
own_erc_1155_721_count as (
|
||||
Select
|
||||
difference.address,
|
||||
(
|
||||
difference.transfers_in - difference.transfers_out
|
||||
) as owned_nfts
|
||||
from
|
||||
(
|
||||
SELECT
|
||||
total.address,
|
||||
sum(total.transfer_out) as transfers_out,
|
||||
sum(total.transfer_in) as transfers_in
|
||||
from
|
||||
(
|
||||
SELECT
|
||||
label_data -> 'args' ->> 'from' as address,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'values') :: decimal as transfer_out,
|
||||
0 as transfer_in
|
||||
from
|
||||
erc_1155_721_contracts_transfers_with_trashhold
|
||||
where
|
||||
label_data ->> 'name' = 'TransferBatch'
|
||||
UNION
|
||||
ALL
|
||||
SELECT
|
||||
label_data -> 'args' ->> 'from' as address,
|
||||
(label_data -> 'args' ->> 'value') :: decimal as transfer_out,
|
||||
0 as transfer_in
|
||||
from
|
||||
erc_1155_721_contracts_transfers_with_trashhold
|
||||
where
|
||||
label_data ->> 'name' = 'TransferSingle'
|
||||
UNION
|
||||
ALL
|
||||
select
|
||||
label_data -> 'args' ->> 'to' as address,
|
||||
0 as transfer_out,
|
||||
(label_data -> 'args' ->>'value') :: decimal as transfer_in
|
||||
from
|
||||
erc_1155_721_contracts_transfers_with_trashhold
|
||||
where
|
||||
label_data ->> 'name' = 'TransferSingle'
|
||||
UNION
|
||||
ALL
|
||||
select
|
||||
label_data -> 'args' ->> 'to' as address,
|
||||
0 as transfer_out,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'values') :: decimal as transfer_in
|
||||
from
|
||||
erc_1155_721_contracts_transfers_with_trashhold
|
||||
where
|
||||
label_data ->> 'name' = 'TransferBatch'
|
||||
UNION
|
||||
ALL
|
||||
select
|
||||
label_data -> 'args' ->> 'from' as address,
|
||||
1 as transfer_out,
|
||||
0 as transfer_in
|
||||
from
|
||||
erc_1155_721_contracts_transfers_with_trashhold
|
||||
|
||||
where
|
||||
label_data ->> 'name' = 'Transfer'
|
||||
UNION
|
||||
ALL
|
||||
select
|
||||
label_data -> 'args' ->> 'to' as address,
|
||||
0 as transfer_out,
|
||||
1 as transfer_in
|
||||
from
|
||||
erc_1155_721_contracts_transfers_with_trashhold
|
||||
|
||||
where
|
||||
label_data ->> 'name' = 'Transfer'
|
||||
) as total
|
||||
group by
|
||||
address
|
||||
) difference
|
||||
order by
|
||||
owned_nfts desc
|
||||
)
|
||||
SELECT
|
||||
*
|
||||
from
|
||||
own_erc_1155_721_count
|
||||
WHERE
|
||||
address not in (
|
||||
'0x000000000000000000000000000000000000dEaD',
|
||||
'0x0000000000000000000000000000000000000000'
|
||||
)
|
||||
order by
|
||||
owned_nfts desc
|
||||
""",
|
||||
},
|
||||
{
|
||||
"name": "total_supply_erc721",
|
||||
"query": """
|
||||
select
|
||||
count(*) as total_supply
|
||||
from(
|
||||
SELECT DISTINCT ON((label_data->'args'->>'tokenId')::INT) (label_data->'args'->>'tokenId')::INT as token_id,
|
||||
label_data->'args'->>'to' as current_owner
|
||||
FROM polygon_labels
|
||||
WHERE address = :address
|
||||
AND (label = 'moonworm' or label = 'moonworm-alpha')
|
||||
AND block_number >= 21418707
|
||||
AND label_data->>'type' = 'event'
|
||||
AND label_data->>'name' = 'Transfer'
|
||||
AND label_data->'args'->>'to' != '0x8d528e98A69FE27b11bb02Ac264516c4818C3942'
|
||||
AND label_data->'args'->>'from' != '0x8d528e98A69FE27b11bb02Ac264516c4818C3942'
|
||||
ORDER BY (label_data->'args'->>'tokenId')::INT ASC,
|
||||
block_number::INT DESC,
|
||||
log_index::INT DESC
|
||||
) as total_supply
|
||||
where current_owner not in ('0x000000000000000000000000000000000000dEaD','0x0000000000000000000000000000000000000000')
|
||||
""",
|
||||
},
|
||||
{
|
||||
"name": "total_supply_terminus",
|
||||
"query": """
|
||||
WITH erc_1155_721_contracts_transfers_with_trashhold as (
|
||||
SELECT
|
||||
label_data as label_data,
|
||||
block_timestamp as block_timestamp,
|
||||
address as address
|
||||
from
|
||||
polygon_labels
|
||||
WHERE
|
||||
polygon_labels.label = 'moonworm-alpha'
|
||||
AND polygon_labels.address = :address
|
||||
),
|
||||
own_erc_1155_721_count as (
|
||||
Select
|
||||
|
||||
difference.address,
|
||||
token_id,
|
||||
(
|
||||
difference.transfers_in - difference.transfers_out
|
||||
) as owned_nfts
|
||||
from
|
||||
(
|
||||
SELECT
|
||||
total.address,
|
||||
token_id,
|
||||
sum(total.transfer_out) as transfers_out,
|
||||
sum(total.transfer_in) as transfers_in
|
||||
from
|
||||
(
|
||||
SELECT
|
||||
label_data -> 'args' ->> 'from' as address,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'ids')->>0 as token_id,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'values') :: decimal as transfer_out,
|
||||
0 as transfer_in
|
||||
from
|
||||
erc_1155_721_contracts_transfers_with_trashhold
|
||||
where
|
||||
label_data ->> 'name' = 'TransferBatch'
|
||||
UNION
|
||||
ALL
|
||||
SELECT
|
||||
label_data -> 'args' ->> 'from' as address,
|
||||
label_data -> 'args' ->> 'id' as token_id,
|
||||
(label_data -> 'args' ->> 'value') :: decimal as transfer_out,
|
||||
0 as transfer_in
|
||||
from
|
||||
erc_1155_721_contracts_transfers_with_trashhold
|
||||
where
|
||||
label_data ->> 'name' = 'TransferSingle'
|
||||
UNION
|
||||
ALL
|
||||
select
|
||||
label_data -> 'args' ->> 'to' as address,
|
||||
label_data -> 'args' ->> 'id' as token_id,
|
||||
0 as transfer_out,
|
||||
(label_data -> 'args' ->>'value') :: decimal as transfer_in
|
||||
from
|
||||
erc_1155_721_contracts_transfers_with_trashhold
|
||||
where
|
||||
label_data ->> 'name' = 'TransferSingle'
|
||||
UNION
|
||||
ALL
|
||||
select
|
||||
label_data -> 'args' ->> 'to' as address,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'ids')->>0 as token_id,
|
||||
0 as transfer_out,
|
||||
jsonb_array_elements(label_data -> 'args' -> 'values') :: decimal as transfer_in
|
||||
from
|
||||
erc_1155_721_contracts_transfers_with_trashhold
|
||||
where
|
||||
label_data ->> 'name' = 'TransferBatch'
|
||||
) as total
|
||||
group by
|
||||
address, token_id
|
||||
) difference
|
||||
order by
|
||||
owned_nfts desc
|
||||
)
|
||||
SELECT
|
||||
token_id as token_id,
|
||||
sum(owned_nfts) as total_supply
|
||||
from
|
||||
own_erc_1155_721_count
|
||||
WHERE
|
||||
address not in (
|
||||
'0x000000000000000000000000000000000000dEaD',
|
||||
'0x0000000000000000000000000000000000000000'
|
||||
)
|
||||
group by
|
||||
token_id
|
||||
order by
|
||||
token_id::int desc
|
||||
""",
|
||||
},
|
||||
]
|
|
@ -19,7 +19,7 @@ class MoonstreamHTTPException(HTTPException):
|
|||
status_code: int,
|
||||
detail: Any = None,
|
||||
headers: Optional[Dict[str, Any]] = None,
|
||||
internal_error: Exception = None,
|
||||
internal_error: Optional[Exception] = None,
|
||||
):
|
||||
super().__init__(status_code, detail, headers)
|
||||
if internal_error is not None:
|
||||
|
|
|
@ -252,6 +252,7 @@ def continuous_crawler(
|
|||
start_block = end_block + 1
|
||||
failed_count = 0
|
||||
except Exception as e:
|
||||
db_session.rollback()
|
||||
logger.error(f"Internal error: {e}")
|
||||
logger.exception(e)
|
||||
failed_count += 1
|
||||
|
|
|
@ -156,7 +156,7 @@ def get_crawl_job_entries(
|
|||
subscription_type: SubscriptionTypes,
|
||||
crawler_type: str,
|
||||
journal_id: str = MOONSTREAM_MOONWORM_TASKS_JOURNAL,
|
||||
created_at_filter: int = None,
|
||||
created_at_filter: Optional[int] = None,
|
||||
limit: int = 200,
|
||||
) -> List[BugoutSearchResult]:
|
||||
"""
|
||||
|
|
|
@ -193,3 +193,20 @@ multicall_contracts: Dict[AvailableBlockchainType, str] = {
|
|||
AvailableBlockchainType.MUMBAI: "0xe9939e7Ea7D7fb619Ac57f648Da7B1D425832631",
|
||||
AvailableBlockchainType.ETHEREUM: "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696",
|
||||
}
|
||||
|
||||
|
||||
# Custom Crawler
|
||||
|
||||
MOONSTREAM_S3_PUBLIC_DATA_BUCKET = os.environ.get(
|
||||
"MOONSTREAM_S3_PUBLIC_DATA_BUCKET", ""
|
||||
) # S3 bucket for storing custom crawler data
|
||||
|
||||
if MOONSTREAM_S3_PUBLIC_DATA_BUCKET == "":
|
||||
raise ValueError(
|
||||
"MOONSTREAM_S3_PUBLIC_DATA_BUCKET environment variable must be set"
|
||||
)
|
||||
|
||||
|
||||
MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX = os.environ.get(
|
||||
"MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX", "dev"
|
||||
)
|
||||
|
|
|
@ -64,6 +64,16 @@ def to_json_types(value):
|
|||
return str(value)
|
||||
|
||||
|
||||
def from_json_types(value):
|
||||
|
||||
if isinstance(value, (str, int, tuple, dict)):
|
||||
return value
|
||||
elif isinstance(value, list): # psycopg2 issue with list support
|
||||
return tuple(value)
|
||||
else:
|
||||
return str(value)
|
||||
|
||||
|
||||
def data_generate(
|
||||
bucket: str,
|
||||
query_id: str,
|
||||
|
@ -125,6 +135,7 @@ def data_generate(
|
|||
bucket=bucket,
|
||||
)
|
||||
except Exception as err:
|
||||
logger.error(f"Error while generating data: {err}")
|
||||
db_session.rollback()
|
||||
reporter.error_report(
|
||||
err,
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
Moonstream crawlers version.
|
||||
"""
|
||||
|
||||
MOONCRAWL_VERSION = "0.2.4"
|
||||
MOONCRAWL_VERSION = "0.2.5"
|
||||
|
|
|
@ -31,3 +31,9 @@ export MOONSTREAM_S3_QUERIES_BUCKET_PREFIX="dev"
|
|||
# 3rd parties environment variables
|
||||
export MOONSTREAM_ETHERSCAN_TOKEN="<Token_for_etherscan>"
|
||||
export COINMARKETCAP_API_KEY="<API_key_to_parse_conmarketcap>"
|
||||
|
||||
|
||||
# Custom crawler
|
||||
export MOONSTREAM_S3_PUBLIC_DATA_BUCKET="<public_bucket>"
|
||||
export MOONSTREAM_S3_PUBLIC_DATA_BUCKET_PREFIX="dev"
|
||||
export MOONSTREAM_PUBLIC_QUERIES_DATA_ACCESS_TOKEN="<access token for run queries for public dashboards>"
|
|
@ -38,6 +38,7 @@ setup(
|
|||
"chardet",
|
||||
"fastapi",
|
||||
"moonstreamdb>=0.3.2",
|
||||
"moonstream>=0.1.1",
|
||||
"moonworm[moonstream]>=0.5.2",
|
||||
"humbug",
|
||||
"pydantic==1.9.2",
|
||||
|
@ -64,6 +65,7 @@ setup(
|
|||
"statistics=mooncrawl.stats_worker.dashboard:main",
|
||||
"state-crawler=mooncrawl.state_crawler.cli:main",
|
||||
"metadata-crawler=mooncrawl.metadata_crawler.cli:main",
|
||||
"custom-crawler=mooncrawl.cu_reports_crawler.cli:main",
|
||||
]
|
||||
},
|
||||
)
|
||||
|
|
|
@ -41,3 +41,4 @@ package-lock.json
|
|||
# vercel
|
||||
.vercel
|
||||
|
||||
.todo
|
||||
|
|
|
@ -72,7 +72,7 @@ const Tokens = () => {
|
|||
<ScaleFade in>
|
||||
<Modal isOpen={isOpen} onClose={onClose} size="lg" trapFocus={false}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalContent bg="black.300">
|
||||
<ModalHeader>New API access token</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
|
@ -85,6 +85,7 @@ const Tokens = () => {
|
|||
<Stack direction={["column", "row", null]} w="100%">
|
||||
<InputGroup size="sm" variant="outline">
|
||||
<Input
|
||||
variant="bw"
|
||||
type="search"
|
||||
maxW="300px"
|
||||
flexBasis="50px"
|
||||
|
|
|
@ -36,7 +36,9 @@ const Contact = () => {
|
|||
mb={8}
|
||||
minHeight="100vh"
|
||||
textColor="black"
|
||||
bgColor="white"
|
||||
position="relative"
|
||||
pt="72px"
|
||||
>
|
||||
<Icon
|
||||
as={BiArrowBack}
|
||||
|
|
|
@ -160,7 +160,8 @@ const Analytics = () => {
|
|||
})
|
||||
}
|
||||
size="md"
|
||||
colorScheme="blue"
|
||||
color="orange.1000"
|
||||
borderColor="1000"
|
||||
variant="outline"
|
||||
icon={<BsGear />}
|
||||
/>
|
||||
|
|
|
@ -23,6 +23,7 @@ const Features = () => {
|
|||
id="container"
|
||||
maxW="container.xl"
|
||||
px={["10%", "10%", "7%", "0"]}
|
||||
mt="72px"
|
||||
>
|
||||
<Heading as="h1" hidden>
|
||||
Moonstream feautes
|
||||
|
|
|
@ -721,7 +721,7 @@ const Homepage = () => {
|
|||
<Heading {...HEADING_PROPS} textAlign="center" as="h2" pb={10}>
|
||||
FAQ
|
||||
</Heading>
|
||||
<Accordion defaultIndex={[0]} allowMultiple allowToggle>
|
||||
<Accordion defaultIndex={[-1]} allowMultiple allowToggle>
|
||||
<FAQCard
|
||||
heading="I’m a game designer. What can Moonstream engine do for me?"
|
||||
headingProps={HEADING_PROPS}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { DEFAULT_METATAGS } from "../../src/core/constants";
|
|||
import { getLayout, getLayoutProps } from "../../src/layouts/WideInfoPage";
|
||||
|
||||
const PrivacyPolicy = () => (
|
||||
<Box>
|
||||
<Box mt="72px">
|
||||
<Box px="1.5rem" m="auto" mb={8} maxWidth="1199.98px" minHeight="60vh">
|
||||
<Heading my={8} as="h1">
|
||||
Privacy Policy for Moonstream
|
||||
|
|
|
@ -6,7 +6,7 @@ import { getLayout, getLayoutProps } from "../../src/layouts/InfoPageLayout";
|
|||
const Status = () => {
|
||||
const healthyStatusText = "Available";
|
||||
const downStatusText = "Unavailable";
|
||||
const healthyStatusColor = "green.900";
|
||||
const healthyStatusColor = "green.1000";
|
||||
const downStatusColor = "red.600";
|
||||
|
||||
const { serverListStatusCache } = useStatus();
|
||||
|
@ -58,6 +58,7 @@ const Status = () => {
|
|||
px={12}
|
||||
py={2}
|
||||
borderTopRadius="xl"
|
||||
mt="72px"
|
||||
>
|
||||
{`Status page`}
|
||||
</Heading>
|
||||
|
|
|
@ -63,7 +63,8 @@ const Subscriptions = () => {
|
|||
<Flex
|
||||
h="3rem"
|
||||
w="100%"
|
||||
bgColor="blue.50"
|
||||
bgColor="black.300"
|
||||
borderColor="white"
|
||||
borderTopRadius="xl"
|
||||
justifyContent="flex-end"
|
||||
alignItems="center"
|
||||
|
|
|
@ -49,7 +49,7 @@ const Team = () => {
|
|||
alignItems="center"
|
||||
w="100%"
|
||||
>
|
||||
<Stack mx={margin} maxW="1700px" w="100%">
|
||||
<Stack mt="72px" mx={margin} maxW="1700px" w="100%">
|
||||
<SimpleGrid
|
||||
px={12}
|
||||
alignItems="start"
|
||||
|
|
|
@ -5,9 +5,9 @@ import { DEFAULT_METATAGS } from "../../src/core/constants";
|
|||
import { getLayout, getLayoutProps } from "../../src/layouts/WideInfoPage";
|
||||
|
||||
const TermsOfService = () => (
|
||||
<Box>
|
||||
<Box mt="72px">
|
||||
<Box px="1.5rem" m="auto" mb={8} maxWidth="1199.98px" minHeight="60vh">
|
||||
<Heading my={8} as="h1">
|
||||
<Heading textAlign="start" my={8} as="h1">
|
||||
Moonstream Terms of Service
|
||||
</Heading>
|
||||
<Text fontSize="md">
|
||||
|
|
|
@ -6,9 +6,11 @@ import { MdPictureAsPdf } from "react-icons/md";
|
|||
const Papers = () => {
|
||||
return (
|
||||
<VStack>
|
||||
<Heading py={12}>Whitepapers</Heading>
|
||||
<Heading pb={12} pt="72px">
|
||||
Whitepapers
|
||||
</Heading>
|
||||
<Link
|
||||
color="orange.900"
|
||||
color="orange.1000"
|
||||
href="https://github.com/bugout-dev/moonstream/blob/main/datasets/nfts/papers/ethereum-nfts.pdf"
|
||||
>
|
||||
An analysis of 7,020,950 NFT transactions on the Ethereum blockchain -
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
<g id="04-01-register" transform="translate(-895.000000, -362.000000)">
|
||||
<g id="Group" transform="translate(891.000000, 356.000000)">
|
||||
<rect id="Rectangle-Copy-5" x="0" y="0" width="24" height="24"></rect>
|
||||
<g id="Group-6" transform="translate(5.000000, 7.000000)" stroke="#83859E" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
|
||||
<g id="Group-6" transform="translate(5.000000, 7.000000)" stroke="#FFFFFF" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5">
|
||||
<path d="M0,5.09090909 C0,5.09090909 2.54545455,-2.57571742e-14 7,-2.57571742e-14 C11.4545455,-2.57571742e-14 14,5.09090909 14,5.09090909 C14,5.09090909 11.4545455,10.1818182 7,10.1818182 C2.54545455,10.1818182 0,5.09090909 0,5.09090909 Z" id="Path"></path>
|
||||
<circle id="Oval" cx="7" cy="5.09090909" r="1.90909091"></circle>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</svg>
|
||||
|
|
Przed Szerokość: | Wysokość: | Rozmiar: 1.1 KiB Po Szerokość: | Wysokość: | Rozmiar: 1.1 KiB |
|
@ -144,6 +144,30 @@ const variantWhiteOnOrange = () => {
|
|||
};
|
||||
};
|
||||
|
||||
const variantPlainOrange = () => {
|
||||
return {
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
border: "solid transparent",
|
||||
borderRadius: "30px",
|
||||
variant: "solid",
|
||||
fontSize: ["md", "md", "lg", "lg", "xl", "xl"],
|
||||
textColor: "white",
|
||||
bg: "#F56646",
|
||||
fontWeight: "700",
|
||||
padding: "10px 30px",
|
||||
_hover: {
|
||||
backgroundColor: "#F4532F",
|
||||
},
|
||||
_focus: {
|
||||
backgroundColor: "#F4532F",
|
||||
},
|
||||
_active: {
|
||||
backgroundColor: "#F4532F",
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const Button = {
|
||||
// 1. We can update the base styles
|
||||
baseStyle: () => ({
|
||||
|
@ -183,6 +207,7 @@ const Button = {
|
|||
link: variantLink,
|
||||
orangeAndBlue: variantOrangeAndBlue,
|
||||
whiteOnOrange: variantWhiteOnOrange,
|
||||
plainOrange: variantPlainOrange,
|
||||
},
|
||||
};
|
||||
export default Button;
|
||||
|
|
|
@ -21,6 +21,31 @@ const flushedVariant = (props) => {
|
|||
};
|
||||
};
|
||||
|
||||
const bwVariant = () => {
|
||||
return {
|
||||
field: {
|
||||
border: "1px solid white",
|
||||
borderRadius: "7px",
|
||||
color: "white",
|
||||
backgroundColor: "black.300",
|
||||
errorBorderColor: "#EE8686",
|
||||
_hover: {
|
||||
backgroundColor: "black.300",
|
||||
},
|
||||
_focus: {
|
||||
backgroundColor: "black.300",
|
||||
},
|
||||
_placeholder: { color: "#CDCDCD" },
|
||||
_autofill: {
|
||||
backgroundColor: "black.300",
|
||||
textFillColor: "white",
|
||||
boxShadow: "0 0 0px 1000px black.300 inset",
|
||||
transition: "background-color 5000s ease-in-out 0s",
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const outlineVariant = (props) => {
|
||||
const { colorScheme: c, theme } = props;
|
||||
const bgColor = transparentize(`${c}.50`, 0.8)(theme);
|
||||
|
@ -79,6 +104,7 @@ const Input = {
|
|||
flushed: flushedVariant,
|
||||
newTag: newTagVariant,
|
||||
filled: filledVariant,
|
||||
bw: bwVariant,
|
||||
},
|
||||
|
||||
defaultProps: {
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
const mobileVariant = () => {
|
||||
return {
|
||||
_active: {
|
||||
backgroundColor: "black.300",
|
||||
color: "white",
|
||||
textDecoration: "none",
|
||||
},
|
||||
_focus: {
|
||||
backgroundColor: "black.300",
|
||||
color: "white",
|
||||
textDecoration: "none",
|
||||
},
|
||||
color: "white",
|
||||
fontSize: "sm",
|
||||
margin: "0px",
|
||||
padding: "0px",
|
||||
};
|
||||
};
|
||||
|
||||
const MenuButton = {
|
||||
variants: {
|
||||
mobile: mobileVariant,
|
||||
},
|
||||
};
|
||||
|
||||
export default MenuButton;
|
|
@ -2,6 +2,7 @@ import { extendTheme } from "@chakra-ui/react";
|
|||
import Button from "./Button";
|
||||
import Tag from "./Tag";
|
||||
import Menu from "./Menu";
|
||||
import MenuButton from "./MenuButton";
|
||||
import Input from "./Input";
|
||||
// import Spinner from "./Spinner";
|
||||
import NumberInput from "./NumberInput";
|
||||
|
@ -59,6 +60,7 @@ const theme = extendTheme({
|
|||
Spinner,
|
||||
Tooltip,
|
||||
Heading,
|
||||
MenuButton,
|
||||
},
|
||||
|
||||
fonts: {
|
||||
|
@ -100,6 +102,7 @@ const theme = extendTheme({
|
|||
600: "#6469b1",
|
||||
700: "#4d54a6",
|
||||
800: "#373e9b",
|
||||
850: "#358BF5",
|
||||
900: "#212990",
|
||||
1000: "#1e2582",
|
||||
1100: "#1a2173",
|
||||
|
@ -165,6 +168,7 @@ const theme = extendTheme({
|
|||
700: "#fd7835",
|
||||
800: "#fd671b",
|
||||
900: "#FD5602",
|
||||
1000: "#F56646",
|
||||
},
|
||||
|
||||
green: {
|
||||
|
@ -179,11 +183,14 @@ const theme = extendTheme({
|
|||
700: "#a8d973",
|
||||
800: "#9dd562",
|
||||
900: "#92D050",
|
||||
1000: "#46C370",
|
||||
},
|
||||
|
||||
black: {
|
||||
100: "#333399",
|
||||
200: "#111442",
|
||||
300: "#1A1D22",
|
||||
400: "#292929",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
MenuList,
|
||||
MenuItem,
|
||||
MenuGroup,
|
||||
MenuDivider,
|
||||
IconButton,
|
||||
chakra,
|
||||
Portal,
|
||||
|
@ -33,20 +32,24 @@ const AccountIconButton = (props) => {
|
|||
/>
|
||||
<Portal>
|
||||
<MenuList
|
||||
zIndex="dropdown"
|
||||
width={["100vw", "100vw", "18rem", "20rem", "22rem", "24rem"]}
|
||||
borderRadius={0}
|
||||
color="black"
|
||||
zIndex={100}
|
||||
bg="#1A1D22"
|
||||
w="auto"
|
||||
minW="auto"
|
||||
borderRadius="10px"
|
||||
p="20px 20px 10px 20px"
|
||||
border="1px solid white"
|
||||
>
|
||||
<MenuGroup>
|
||||
<RouterLink href="/account/security" passHref>
|
||||
<MenuItem>Security</MenuItem>
|
||||
<div className="desktop-menu-item">Security</div>
|
||||
</RouterLink>
|
||||
<RouterLink href="/account/tokens" passHref>
|
||||
<MenuItem>API tokens</MenuItem>
|
||||
<div className="desktop-menu-item" title="API tokens">
|
||||
API tokens
|
||||
</div>
|
||||
</RouterLink>
|
||||
</MenuGroup>
|
||||
<MenuDivider />
|
||||
{ui.isMobileView &&
|
||||
SITEMAP.map((item, idx) => {
|
||||
if (item.type !== PAGETYPE.FOOTER_CATEGORY && item.children) {
|
||||
|
@ -54,7 +57,22 @@ const AccountIconButton = (props) => {
|
|||
<MenuGroup key={`AccountIconButton-MenuGroup-${idx}`}>
|
||||
{item.children.map((child, idx) => {
|
||||
return (
|
||||
<MenuItem key={`AccountIconButton-SITEMAP-${idx}`}>
|
||||
<MenuItem
|
||||
key={`AccountIconButton-SITEMAP-${idx}`}
|
||||
m={0}
|
||||
color="white"
|
||||
fontWeight="400"
|
||||
fontSize="16px"
|
||||
px="0px"
|
||||
mb="10px"
|
||||
h="22px"
|
||||
_hover={{
|
||||
backgroundColor: "#1A1D22",
|
||||
color: "#F56646",
|
||||
fontWeight: "700",
|
||||
}}
|
||||
_focus={{ backgroundColor: "#1A1D22" }}
|
||||
>
|
||||
<RouterLink href={child.path}>
|
||||
{child.title}
|
||||
</RouterLink>
|
||||
|
@ -65,14 +83,14 @@ const AccountIconButton = (props) => {
|
|||
);
|
||||
}
|
||||
})}
|
||||
<MenuDivider />
|
||||
<MenuItem
|
||||
<div
|
||||
className="desktop-menu-item"
|
||||
onClick={() => {
|
||||
logout();
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</MenuItem>
|
||||
</div>
|
||||
</MenuList>
|
||||
</Portal>
|
||||
</Menu>
|
||||
|
|
|
@ -107,9 +107,20 @@ const AppNavbar = () => {
|
|||
<>
|
||||
{!ui.isMobileView && (
|
||||
<>
|
||||
<Flex px={2}>
|
||||
<Flex px={2} minH="72px" maxH="72px" alignItems="center">
|
||||
<RouterLink href="/" passHref>
|
||||
<Image
|
||||
w="160px"
|
||||
py="0.75rem"
|
||||
pl={1}
|
||||
ml="15px"
|
||||
src={PRIMARY_MOON_LOGO_URL}
|
||||
alt="Moonstream To"
|
||||
cursor="pointer"
|
||||
/>
|
||||
</RouterLink>
|
||||
<Spacer />
|
||||
<Flex placeSelf="flex-end">
|
||||
<Flex h="100%" alignItems="center">
|
||||
<ButtonGroup variant="link" spacing={4}>
|
||||
{SITEMAP.map((item, idx) => {
|
||||
if (
|
||||
|
@ -133,11 +144,24 @@ const AppNavbar = () => {
|
|||
key={`menu-button-${idx}`}
|
||||
as={Button}
|
||||
rightIcon={<ChevronDownIcon />}
|
||||
color="white"
|
||||
fontWeight="500"
|
||||
_expanded={{ color: "white", fontWeight: "700" }}
|
||||
_focus={{ textDecoration: "none" }}
|
||||
_hover={{ textDecoration: "none", fontWeight: "700" }}
|
||||
>
|
||||
{item.title}
|
||||
</MenuButton>
|
||||
<Portal>
|
||||
<MenuList zIndex={100}>
|
||||
<MenuList
|
||||
zIndex={100}
|
||||
bg="#1A1D22"
|
||||
w="auto"
|
||||
minW="auto"
|
||||
borderRadius="10px"
|
||||
p="20px 20px 10px 20px"
|
||||
border="1px solid white"
|
||||
>
|
||||
{item.children.map((child, idx) => (
|
||||
<RouterLink
|
||||
shallow={true}
|
||||
|
@ -145,8 +169,23 @@ const AppNavbar = () => {
|
|||
href={child.path}
|
||||
passHref
|
||||
>
|
||||
<MenuItem key={`menu-${idx}`} as={"a"} m={0}>
|
||||
<Text color="black">{child.title}</Text>
|
||||
<MenuItem
|
||||
key={`menu-${idx}`}
|
||||
as={"a"}
|
||||
m={0}
|
||||
color="white"
|
||||
fontWeight="400"
|
||||
px="0px"
|
||||
mb="10px"
|
||||
h="22px"
|
||||
_hover={{
|
||||
backgroundColor: "black.300",
|
||||
color: "#F56646",
|
||||
fontWeight: "700",
|
||||
}}
|
||||
_focus={{ backgroundColor: "black.300" }}
|
||||
>
|
||||
{child.title}
|
||||
</MenuItem>
|
||||
</RouterLink>
|
||||
))}
|
||||
|
@ -164,7 +203,7 @@ const AppNavbar = () => {
|
|||
href={item.path}
|
||||
isActive={!!(router.nextRouter.pathname === item.path)}
|
||||
>
|
||||
{item.title}
|
||||
<Text color="white">{item.title}</Text>
|
||||
</RouteButton>
|
||||
);
|
||||
})}
|
||||
|
|
|
@ -53,8 +53,13 @@ const AutoCompleter = ({
|
|||
return (
|
||||
<Box pos="relative">
|
||||
<Box {...getRootProps({}, { suppressRefError: true })}>
|
||||
<InputGroup>
|
||||
<InputGroup
|
||||
border="1px solid white"
|
||||
bg="black.300"
|
||||
borderRadius="7px"
|
||||
>
|
||||
<InputLeftAddon
|
||||
borderStyle="none"
|
||||
isTruncated
|
||||
maxW="60px"
|
||||
fontSize={ui.isMobileView ? "xs" : "sm"}
|
||||
|
@ -75,6 +80,9 @@ const AutoCompleter = ({
|
|||
</InputLeftAddon>
|
||||
|
||||
<Input
|
||||
variant="bw"
|
||||
borderStyle="none none none"
|
||||
borderLeft="1px solid white"
|
||||
placeholder={placeholder}
|
||||
isTruncated
|
||||
fontSize="sm"
|
||||
|
@ -82,9 +90,10 @@ const AutoCompleter = ({
|
|||
// defaultValue: getDefaultValue(selectedItem),
|
||||
})}
|
||||
></Input>
|
||||
<InputRightAddon>
|
||||
<InputRightAddon bg="black.300">
|
||||
{" "}
|
||||
<button
|
||||
style={{ backgroundColor: "black.300" }}
|
||||
{...getToggleButtonProps()}
|
||||
aria-label={"toggle menu"}
|
||||
>
|
||||
|
@ -99,7 +108,7 @@ const AutoCompleter = ({
|
|||
direction="column"
|
||||
className="menuListTim"
|
||||
{...getMenuProps()}
|
||||
bgColor="gray.300"
|
||||
bgColor="black.300"
|
||||
borderRadius="md"
|
||||
boxShadow="lg"
|
||||
pos="absolute"
|
||||
|
@ -123,6 +132,7 @@ const AutoCompleter = ({
|
|||
px={4}
|
||||
py={1}
|
||||
alignItems="center"
|
||||
border="1px solid white"
|
||||
key={`autocomplete-item-${index}`}
|
||||
{...getItemProps({
|
||||
index,
|
||||
|
@ -130,13 +140,8 @@ const AutoCompleter = ({
|
|||
})}
|
||||
direction="row"
|
||||
w="100%"
|
||||
bgColor={
|
||||
index === highlightedIndex
|
||||
? "orange.900"
|
||||
: "inherit"
|
||||
}
|
||||
color={
|
||||
index === highlightedIndex ? "gray.100" : "inherit"
|
||||
fontWeight={
|
||||
index === highlightedIndex ? "600" : "inherit"
|
||||
}
|
||||
>
|
||||
{dropdownItem(item)}
|
||||
|
|
|
@ -28,7 +28,7 @@ const CheckboxGroupped = ({
|
|||
px={2}
|
||||
key={`list-item-checkbox-${idx}`}
|
||||
direction="row"
|
||||
bgColor={idx % 2 == 0 ? "gray.50" : "gray.100"}
|
||||
bgColor={idx % 2 == 0 ? "black.400" : "black.300"}
|
||||
>
|
||||
<Checkbox
|
||||
isChecked={isItemChecked(listItem)}
|
||||
|
|
|
@ -16,7 +16,7 @@ const ConfirmationRequest = (props) => {
|
|||
{({ onClose }) => (
|
||||
<Fragment>
|
||||
<PopoverTrigger>{props.children}</PopoverTrigger>
|
||||
<PopoverContent zIndex={100} bg="White">
|
||||
<PopoverContent zIndex={100} bg="White" color="Black">
|
||||
<PopoverCloseButton />
|
||||
<PopoverHeader fontWeight="bold">{props.header}</PopoverHeader>
|
||||
<PopoverBody fontSize="md">{props.bodyMessage}</PopoverBody>
|
||||
|
|
|
@ -222,12 +222,15 @@ const EntriesNavigation = () => {
|
|||
overflow="hidden"
|
||||
direction="column"
|
||||
flexGrow={1}
|
||||
mt="10px"
|
||||
mr="5px"
|
||||
ml="5px"
|
||||
>
|
||||
{streamCache && !eventsIsLoading ? (
|
||||
<>
|
||||
<Drawer onClose={onClose} isOpen={isOpen} size="lg">
|
||||
<DrawerOverlay />
|
||||
<DrawerContent bgColor="gray.100">
|
||||
<DrawerContent bgColor="gray.100" color="Black">
|
||||
<DrawerCloseButton />
|
||||
<DrawerHeader>{`Filter results`}</DrawerHeader>
|
||||
<DrawerBody>
|
||||
|
@ -433,7 +436,7 @@ const EntriesNavigation = () => {
|
|||
w="100%"
|
||||
//onScroll={(e) => handleScroll(e)}
|
||||
>
|
||||
<Stack direction="row" justifyContent="space-between">
|
||||
<Stack mt="5px" direction="row" justifyContent="space-around">
|
||||
{!loadNewerEventsIsFetching && !nextEventIsFetching ? (
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
@ -452,53 +455,53 @@ const EntriesNavigation = () => {
|
|||
colorScheme="green"
|
||||
></Button>
|
||||
)}
|
||||
</Stack>
|
||||
{streamCache
|
||||
.slice(
|
||||
cursor,
|
||||
streamCache.length <= cursor + PAGE_SIZE
|
||||
? streamCache.length
|
||||
: cursor + PAGE_SIZE
|
||||
)
|
||||
.map((entry, idx) => (
|
||||
<StreamEntry
|
||||
showOnboardingTooltips={false}
|
||||
key={`entry-list-${idx}`}
|
||||
entry={entry}
|
||||
disableDelete={!canDelete}
|
||||
disableCopy={!canCreate}
|
||||
filterCallback={handleFilterStateCallback}
|
||||
filterConstants={{ DIRECTIONS, CONDITION, FILTER_TYPES }}
|
||||
/>
|
||||
))}
|
||||
{previousEvent &&
|
||||
!loadOlderEventsIsFetching &&
|
||||
!previousEventIsFetching ? (
|
||||
<Center>
|
||||
<Button
|
||||
onClick={() => {
|
||||
loadPreviousEventHandler();
|
||||
}}
|
||||
variant="outline"
|
||||
colorScheme="green"
|
||||
>
|
||||
Load older events
|
||||
</Button>
|
||||
</Center>
|
||||
) : (
|
||||
<Center>
|
||||
{!previousEventIsFetching && !loadOlderEventsIsFetching ? (
|
||||
"Тransactions not found. You can subscribe to more addresses in Subscriptions menu."
|
||||
) : (
|
||||
{streamCache
|
||||
.slice(
|
||||
cursor,
|
||||
streamCache.length <= cursor + PAGE_SIZE
|
||||
? streamCache.length
|
||||
: cursor + PAGE_SIZE
|
||||
)
|
||||
.map((entry, idx) => (
|
||||
<StreamEntry
|
||||
showOnboardingTooltips={false}
|
||||
key={`entry-list-${idx}`}
|
||||
entry={entry}
|
||||
disableDelete={!canDelete}
|
||||
disableCopy={!canCreate}
|
||||
filterCallback={handleFilterStateCallback}
|
||||
filterConstants={{ DIRECTIONS, CONDITION, FILTER_TYPES }}
|
||||
/>
|
||||
))}
|
||||
{previousEvent &&
|
||||
!loadOlderEventsIsFetching &&
|
||||
!previousEventIsFetching ? (
|
||||
<Center>
|
||||
<Button
|
||||
isLoading
|
||||
loadingText="Loading"
|
||||
onClick={() => {
|
||||
loadPreviousEventHandler();
|
||||
}}
|
||||
variant="outline"
|
||||
colorScheme="green"
|
||||
></Button>
|
||||
)}
|
||||
</Center>
|
||||
)}
|
||||
>
|
||||
Load older events
|
||||
</Button>
|
||||
</Center>
|
||||
) : (
|
||||
<Center>
|
||||
{!previousEventIsFetching && !loadOlderEventsIsFetching ? (
|
||||
"Тransactions not found. You can subscribe to more addresses in Subscriptions menu."
|
||||
) : (
|
||||
<Button
|
||||
isLoading
|
||||
loadingText="Loading"
|
||||
variant="outline"
|
||||
colorScheme="green"
|
||||
></Button>
|
||||
)}
|
||||
</Center>
|
||||
)}
|
||||
</Stack>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</>
|
||||
|
|
|
@ -1,15 +1,7 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useToast, useForgotPassword } from "../core/hooks";
|
||||
import {
|
||||
FormControl,
|
||||
InputGroup,
|
||||
FormErrorMessage,
|
||||
Button,
|
||||
Input,
|
||||
InputRightElement,
|
||||
} from "@chakra-ui/react";
|
||||
import CustomIcon from "./CustomIcon";
|
||||
import { FormControl, InputGroup, Button, Input } from "@chakra-ui/react";
|
||||
import { MODAL_TYPES } from "../core/providers/OverlayProvider/constants";
|
||||
|
||||
const ForgotPassword = ({ toggleModal }) => {
|
||||
|
@ -19,34 +11,39 @@ const ForgotPassword = ({ toggleModal }) => {
|
|||
|
||||
useEffect(() => {
|
||||
if (!data) return;
|
||||
|
||||
toggleModal({ type: MODAL_TYPES.OFF });
|
||||
}, [data, toggleModal, toast]);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(forgotPassword)}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "18px",
|
||||
fontWeight: 400,
|
||||
color: errors.username ? "#EE8686" : "white",
|
||||
}}
|
||||
>
|
||||
{errors.email ? errors.email.message : "Email"}
|
||||
</div>
|
||||
<FormControl isInvalid={errors.email} my={4}>
|
||||
<InputGroup>
|
||||
<Input
|
||||
colorScheme="blue"
|
||||
variant="filled"
|
||||
placeholder="Your email here"
|
||||
variant="bw"
|
||||
placeholder="Enter your email"
|
||||
name="email"
|
||||
ref={register({ required: "Email is required!" })}
|
||||
autoComplete="email"
|
||||
ref={register({ required: "Email is required" })}
|
||||
/>
|
||||
<InputRightElement>
|
||||
<CustomIcon icon="name" />
|
||||
</InputRightElement>
|
||||
</InputGroup>
|
||||
<FormErrorMessage color="red.400" pl="1">
|
||||
{errors.email && errors.email.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<Button
|
||||
mt="30px"
|
||||
mb="10px"
|
||||
fontSize="lg"
|
||||
h="46px"
|
||||
type="submit"
|
||||
variant="solid"
|
||||
colorScheme="blue"
|
||||
width="100%"
|
||||
variant="plainOrange"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Send
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
import React, { useContext } from "react";
|
||||
import RouterLink from "next/link";
|
||||
import {
|
||||
Button,
|
||||
Image,
|
||||
ButtonGroup,
|
||||
Spacer,
|
||||
Link,
|
||||
Flex,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuList,
|
||||
MenuItem,
|
||||
Portal,
|
||||
Text,
|
||||
Box,
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
import { PAGETYPE, SITEMAP, PRIMARY_MOON_LOGO_URL } from "../core/constants";
|
||||
import { MODAL_TYPES } from "../core/providers/OverlayProvider/constants";
|
||||
import useModals from "../core/hooks/useModals";
|
||||
import UIContext from "../core/providers/UIProvider/context";
|
||||
import PlainButton from "./atoms/PlainButton";
|
||||
import ChakraAccountIconButton from "./AccountIconButton";
|
||||
|
||||
const LandingBarMobile = () => {
|
||||
const ui = useContext(UIContext);
|
||||
const { toggleModal } = useModals();
|
||||
return (
|
||||
<Flex
|
||||
h={ui.isAppView ? "72px" : "89px"}
|
||||
direction="column"
|
||||
width={"100%"}
|
||||
justifyContent={ui.isLoggedIn ? "center" : "space-between"}
|
||||
>
|
||||
<Flex
|
||||
width={"100%"}
|
||||
alignItems="center"
|
||||
flex="flex: 0 0 100%"
|
||||
pl="10px"
|
||||
pr="27px"
|
||||
mt={ui.isLoggedIn ? "0px" : "12px"}
|
||||
>
|
||||
<RouterLink href="/" passHref>
|
||||
<Link
|
||||
as={Image}
|
||||
w={"160px"}
|
||||
h={"23px"}
|
||||
justifyContent="left"
|
||||
src={PRIMARY_MOON_LOGO_URL}
|
||||
alt="Moonstream logo"
|
||||
/>
|
||||
</RouterLink>
|
||||
<Spacer />
|
||||
{!ui.isLoggedIn && (
|
||||
<PlainButton
|
||||
style={{
|
||||
marginRight: "12px",
|
||||
fontSize: "14px",
|
||||
padding: "2px 10px",
|
||||
}}
|
||||
onClick={() => toggleModal({ type: MODAL_TYPES.SIGNUP })}
|
||||
>
|
||||
Sign up
|
||||
</PlainButton>
|
||||
)}
|
||||
{!ui.isLoggedIn && (
|
||||
<Text
|
||||
color="white"
|
||||
bg="transparent"
|
||||
onClick={() => toggleModal({ type: MODAL_TYPES.LOGIN })}
|
||||
fontWeight="400"
|
||||
p="0px"
|
||||
m="0px"
|
||||
_focus={{ backgroundColor: "transparent" }}
|
||||
_hover={{ backgroundColor: "transparent" }}
|
||||
>
|
||||
Log in
|
||||
</Text>
|
||||
)}
|
||||
{ui.isLoggedIn && (
|
||||
<RouterLink href="/welcome" passHref>
|
||||
<Box
|
||||
bg="orange.1000"
|
||||
alignSelf={"center"}
|
||||
as={Link}
|
||||
color="white"
|
||||
size="sm"
|
||||
fontWeight="700"
|
||||
borderRadius="15px"
|
||||
w="47px"
|
||||
h="25px"
|
||||
textAlign="center"
|
||||
fontSize="14px"
|
||||
>
|
||||
<Text lineHeight="25px">App</Text>
|
||||
</Box>
|
||||
</RouterLink>
|
||||
)}
|
||||
{ui.isLoggedIn && ui.isMobileView && (
|
||||
<>
|
||||
<ChakraAccountIconButton variant="link" colorScheme="orange" />
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
<ButtonGroup
|
||||
justifyContent="center"
|
||||
w="100%"
|
||||
variant="link"
|
||||
spacing={4}
|
||||
flexGrow={0.5}
|
||||
>
|
||||
{SITEMAP.map((item, idx) => {
|
||||
return (
|
||||
<React.Fragment key={`Fragment-${idx}`}>
|
||||
{item.type !== PAGETYPE.FOOTER_CATEGORY && item.children && (
|
||||
<Menu>
|
||||
<MenuButton variant="mobile" mb="0px" p="0px" as={Button}>
|
||||
{item.title}
|
||||
</MenuButton>
|
||||
<Portal>
|
||||
<MenuList
|
||||
zIndex={100}
|
||||
bg="black.300"
|
||||
w="auto"
|
||||
minW="auto"
|
||||
borderRadius="10px"
|
||||
p="10px 20px 10px 20px"
|
||||
border="1px solid white"
|
||||
>
|
||||
{item.children.map((child, idx) => (
|
||||
<RouterLink
|
||||
shallow={true}
|
||||
key={`${idx}-${item.title}-menu-links`}
|
||||
href={child.path}
|
||||
passHref
|
||||
>
|
||||
<MenuItem
|
||||
color="white"
|
||||
key={`menu-${idx}`}
|
||||
as={"a"}
|
||||
m={0}
|
||||
fontSize="sm"
|
||||
_focus={{ backgroundColor: "black.300" }}
|
||||
_active={{ backgroundColor: "black.300" }}
|
||||
_hover={{ backgroundColor: "black.300" }}
|
||||
>
|
||||
{child.title}
|
||||
</MenuItem>
|
||||
</RouterLink>
|
||||
))}
|
||||
</MenuList>
|
||||
</Portal>
|
||||
</Menu>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default LandingBarMobile;
|
|
@ -4,70 +4,54 @@ import {
|
|||
Button,
|
||||
Image,
|
||||
ButtonGroup,
|
||||
Spacer,
|
||||
Link,
|
||||
IconButton,
|
||||
Flex,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuList,
|
||||
MenuItem,
|
||||
Portal,
|
||||
Box,
|
||||
Text,
|
||||
} from "@chakra-ui/react";
|
||||
import { ChevronDownIcon, HamburgerIcon } from "@chakra-ui/icons";
|
||||
import { ChevronDownIcon } from "@chakra-ui/icons";
|
||||
import useModals from "../core/hooks/useModals";
|
||||
import UIContext from "../core/providers/UIProvider/context";
|
||||
import ChakraAccountIconButton from "./AccountIconButton";
|
||||
import RouteButton from "./RouteButton";
|
||||
import {
|
||||
PAGETYPE,
|
||||
SITEMAP,
|
||||
PRIMARY_MOON_LOGO_URL,
|
||||
BACKGROUND_COLOR,
|
||||
} from "../core/constants";
|
||||
import { PAGETYPE, SITEMAP, PRIMARY_MOON_LOGO_URL } from "../core/constants";
|
||||
import router from "next/router";
|
||||
import { MODAL_TYPES } from "../core/providers/OverlayProvider/constants";
|
||||
import LandingBarMobile from "./LandingBarMobile";
|
||||
|
||||
const LandingNavbar = () => {
|
||||
const ui = useContext(UIContext);
|
||||
const { toggleModal } = useModals();
|
||||
return (
|
||||
<>
|
||||
{ui.isMobileView && (
|
||||
<>
|
||||
<IconButton
|
||||
alignSelf="flex-start"
|
||||
colorScheme="blackAlpha"
|
||||
bgColor={BACKGROUND_COLOR}
|
||||
variant="solid"
|
||||
onClick={() => ui.setSidebarToggled(!ui.sidebarToggled)}
|
||||
icon={<HamburgerIcon />}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Flex
|
||||
pl={ui.isMobileView ? 2 : "60px"}
|
||||
justifySelf="flex-start"
|
||||
h="48px"
|
||||
py={1}
|
||||
flexBasis="200px"
|
||||
flexGrow={0.6}
|
||||
id="Logo Container"
|
||||
alignItems="center"
|
||||
>
|
||||
<RouterLink href="/" passHref>
|
||||
<Link
|
||||
as={Image}
|
||||
w={"160px"}
|
||||
justifyContent="left"
|
||||
src={PRIMARY_MOON_LOGO_URL}
|
||||
alt="Moonstream logo"
|
||||
/>
|
||||
</RouterLink>
|
||||
</Flex>
|
||||
|
||||
{ui.isMobileView && <LandingBarMobile />}
|
||||
{!ui.isMobileView && (
|
||||
<>
|
||||
<Flex
|
||||
pl={ui.isMobileView ? 2 : "60px"}
|
||||
justifySelf="flex-start"
|
||||
h={ui.isMobileView && !ui.isAppView ? "89px" : "72px"}
|
||||
py={1}
|
||||
flexBasis="200px"
|
||||
flexGrow={0.6}
|
||||
id="Logo Container"
|
||||
alignItems="center"
|
||||
>
|
||||
<RouterLink href="/" passHref>
|
||||
<Link
|
||||
as={Image}
|
||||
w={"160px"}
|
||||
justifyContent="left"
|
||||
src={PRIMARY_MOON_LOGO_URL}
|
||||
alt="Moonstream logo"
|
||||
/>
|
||||
</RouterLink>
|
||||
</Flex>
|
||||
<ButtonGroup variant="link" spacing={4} pr={16} flexGrow={0.5}>
|
||||
{SITEMAP.map((item, idx) => {
|
||||
return (
|
||||
|
@ -78,18 +62,36 @@ const LandingNavbar = () => {
|
|||
variant="link"
|
||||
href={item.path}
|
||||
color="black"
|
||||
fontSize="16px"
|
||||
isActive={!!(router.pathname === item.path)}
|
||||
>
|
||||
{item.title}
|
||||
</RouteButton>
|
||||
)}
|
||||
{item.type !== PAGETYPE.FOOTER_CATEGORY && item.children && (
|
||||
<Menu colorScheme="blackAlpha">
|
||||
<MenuButton as={Button} rightIcon={<ChevronDownIcon />}>
|
||||
<Menu autoSelect="false">
|
||||
<MenuButton
|
||||
as={Button}
|
||||
rightIcon={<ChevronDownIcon />}
|
||||
color="white"
|
||||
fontWeight="500"
|
||||
fontSize="16px"
|
||||
_expanded={{ color: "white", fontWeight: "700" }}
|
||||
_focus={{ textDecoration: "none" }}
|
||||
_hover={{ textDecoration: "none", fontWeight: "700" }}
|
||||
>
|
||||
{item.title}
|
||||
</MenuButton>
|
||||
<Portal>
|
||||
<MenuList zIndex={100}>
|
||||
<MenuList
|
||||
zIndex={100}
|
||||
bg="black.300"
|
||||
w="auto"
|
||||
minW="auto"
|
||||
borderRadius="10px"
|
||||
p="20px 20px 10px 20px"
|
||||
border="1px solid white"
|
||||
>
|
||||
{item.children.map((child, idx) => (
|
||||
<RouterLink
|
||||
shallow={true}
|
||||
|
@ -97,7 +99,23 @@ const LandingNavbar = () => {
|
|||
href={child.path}
|
||||
passHref
|
||||
>
|
||||
<MenuItem key={`menu-${idx}`} as={"a"} m={0}>
|
||||
<MenuItem
|
||||
key={`menu-${idx}`}
|
||||
as={"a"}
|
||||
m={0}
|
||||
color="white"
|
||||
fontWeight="400"
|
||||
fontSize="16px"
|
||||
px="0px"
|
||||
mb="10px"
|
||||
h="22px"
|
||||
_hover={{
|
||||
backgroundColor: "black.300",
|
||||
color: "orange.1000",
|
||||
fontWeight: "700",
|
||||
}}
|
||||
_focus={{ backgroundColor: "black.300" }}
|
||||
>
|
||||
{child.title}
|
||||
</MenuItem>
|
||||
</RouterLink>
|
||||
|
@ -113,28 +131,38 @@ const LandingNavbar = () => {
|
|||
<ButtonGroup variant="link" spacing={4} pr={16}>
|
||||
{ui.isLoggedIn && (
|
||||
<RouterLink href="/welcome" passHref>
|
||||
<Button
|
||||
<Box
|
||||
bg="orange.1000"
|
||||
alignSelf={"center"}
|
||||
as={Link}
|
||||
colorScheme="orange"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
fontWeight="400"
|
||||
borderRadius="2xl"
|
||||
fontWeight="700"
|
||||
borderRadius="15px"
|
||||
w="51px"
|
||||
h="32px"
|
||||
textAlign="center"
|
||||
px="10px"
|
||||
cursor="pointer"
|
||||
_hover={{
|
||||
backgroundColor: "#F4532F",
|
||||
}}
|
||||
>
|
||||
App
|
||||
</Button>
|
||||
<Text fontSize="16px" lineHeight="32px">
|
||||
App
|
||||
</Text>
|
||||
</Box>
|
||||
</RouterLink>
|
||||
)}
|
||||
{!ui.isLoggedIn && (
|
||||
<Button
|
||||
bg="#F56646"
|
||||
bg="orange.1000"
|
||||
variant="solid"
|
||||
onClick={() => toggleModal({ type: MODAL_TYPES.SIGNUP })}
|
||||
size="sm"
|
||||
fontWeight="bold"
|
||||
fontWeight="700"
|
||||
borderRadius="2xl"
|
||||
textColor="white"
|
||||
_hover={{
|
||||
backgroundColor: "#F4532F",
|
||||
}}
|
||||
>
|
||||
Sign up
|
||||
</Button>
|
||||
|
@ -154,12 +182,6 @@ const LandingNavbar = () => {
|
|||
</ButtonGroup>
|
||||
</>
|
||||
)}
|
||||
{ui.isLoggedIn && ui.isMobileView && (
|
||||
<>
|
||||
<Spacer />
|
||||
<ChakraAccountIconButton variant="link" colorScheme="orange" />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ import LandingNavbar from "./LandingNavbar";
|
|||
const AppNavbar = React.lazy(() => import("./AppNavbar"));
|
||||
|
||||
const Navbar = () => {
|
||||
const { isAppView, isLoggedIn } = useContext(UIContext);
|
||||
const { isAppView, isLoggedIn, isMobileView } = useContext(UIContext);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
|
@ -15,8 +15,8 @@ const Navbar = () => {
|
|||
zIndex={1}
|
||||
alignItems="center"
|
||||
id="Navbar"
|
||||
minH="3rem"
|
||||
maxH="3rem"
|
||||
minH={isMobileView && !isAppView ? "89px" : "72px"}
|
||||
maxH={isMobileView && !isAppView ? "89px" : "72px"}
|
||||
bgColor={BACKGROUND_COLOR}
|
||||
borderBottom="1px solid white"
|
||||
direction="row"
|
||||
|
|
|
@ -4,7 +4,6 @@ import {
|
|||
FormLabel,
|
||||
Stack,
|
||||
Button,
|
||||
Badge,
|
||||
Spinner,
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
|
@ -13,6 +12,7 @@ import {
|
|||
AccordionIcon,
|
||||
Box,
|
||||
IconButton,
|
||||
Text,
|
||||
} from "@chakra-ui/react";
|
||||
import { useSubscriptions } from "../core/hooks";
|
||||
import color from "color";
|
||||
|
@ -78,7 +78,7 @@ const NewDashboardChart = () => {
|
|||
});
|
||||
}
|
||||
return (
|
||||
<AccordionItem key={`new-chart-component-${idx}`}>
|
||||
<AccordionItem pt="5px" key={`new-chart-component-${idx}`}>
|
||||
{subscribedItem?.subscription_id &&
|
||||
subscriptionItemFromCache && (
|
||||
<>
|
||||
|
@ -244,33 +244,25 @@ const NewDashboardChart = () => {
|
|||
</Button>
|
||||
)}
|
||||
dropdownItem={(item) => {
|
||||
const badgeColor = color(`${item.color}`);
|
||||
return (
|
||||
<>
|
||||
<Stack cursor="pointer" direction="row">
|
||||
<chakra.span whiteSpace="nowrap">
|
||||
{item.label}
|
||||
</chakra.span>
|
||||
<Badge
|
||||
size="sm"
|
||||
placeSelf="self-end"
|
||||
colorScheme={item.abi ? "green" : "gray"}
|
||||
<Text
|
||||
fontSize="md"
|
||||
color={item.abi ? "white" : "gray"}
|
||||
>
|
||||
ABI
|
||||
</Badge>
|
||||
<Badge
|
||||
</Text>
|
||||
<Text
|
||||
isTruncated
|
||||
size="sm"
|
||||
placeSelf="self-end"
|
||||
bgColor={item.color}
|
||||
color={
|
||||
badgeColor.isDark()
|
||||
? badgeColor.lighten(100).hex()
|
||||
: badgeColor.darken(0.6).hex()
|
||||
}
|
||||
fontSize="md"
|
||||
placeSelf="self-center"
|
||||
>
|
||||
{item.address}
|
||||
</Badge>
|
||||
</>
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
@ -299,7 +291,8 @@ const NewDashboardChart = () => {
|
|||
)}
|
||||
|
||||
<Button
|
||||
colorScheme="green"
|
||||
variant="plainOrange"
|
||||
fontSize="md"
|
||||
size="md"
|
||||
onClick={() =>
|
||||
ui.dispatchDashboardUpdate({
|
||||
|
|
|
@ -57,9 +57,12 @@ const NewDashboardName = (props) => {
|
|||
return (
|
||||
<>
|
||||
<Stack direction={["column", "row", null]}>
|
||||
<InputGroup>
|
||||
<InputLeftAddon>Name:</InputLeftAddon>
|
||||
<InputGroup border="1px solid white" borderRadius="7px">
|
||||
<InputLeftAddon bg="black.300">Name:</InputLeftAddon>
|
||||
<Input
|
||||
borderStyle="none none none"
|
||||
borderLeft="1px solid white"
|
||||
variant="bw"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder={placeholder}
|
||||
|
|
|
@ -158,12 +158,15 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
// style={comboboxStyles}
|
||||
{...getRootProps({}, { suppressRefError: true })}
|
||||
>
|
||||
<InputGroup>
|
||||
<InputGroup
|
||||
border="1px solid white"
|
||||
borderRadius="7px"
|
||||
>
|
||||
<InputLeftAddon
|
||||
isTruncated
|
||||
maxW="60px"
|
||||
fontSize="sm"
|
||||
bgColor={"gray.100"}
|
||||
bgColor="black.300"
|
||||
>
|
||||
<Image h="24px" src={selectedItem?.icon_url} />
|
||||
</InputLeftAddon>
|
||||
|
@ -172,15 +175,24 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
placeholder="What do you want to subscribe to"
|
||||
isTruncated
|
||||
fontSize="sm"
|
||||
variant="bw"
|
||||
{...getInputProps()}
|
||||
></Input>
|
||||
<InputRightAddon p={0}>
|
||||
<Button
|
||||
variant="outline"
|
||||
// variant="none"
|
||||
borderStyle="none"
|
||||
borderColor="black"
|
||||
w="100%"
|
||||
m={0}
|
||||
p={0}
|
||||
colorScheme="gray"
|
||||
bg="black.300"
|
||||
_hover={{
|
||||
backgroundColor: "black.300",
|
||||
}}
|
||||
_focus={{
|
||||
backgroundColor: "black.300",
|
||||
}}
|
||||
{...getToggleButtonProps({})}
|
||||
aria-label={"toggle menu"}
|
||||
>
|
||||
|
@ -194,7 +206,7 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
direction="column"
|
||||
className="menuListTim"
|
||||
{...getMenuProps()}
|
||||
bgColor="gray.300"
|
||||
bgColor="black.300"
|
||||
borderRadius="md"
|
||||
boxShadow="lg"
|
||||
pos="absolute"
|
||||
|
@ -213,6 +225,7 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
px={4}
|
||||
py={1}
|
||||
alignItems="center"
|
||||
cursor="pointer"
|
||||
key={item.value}
|
||||
{...getItemProps({
|
||||
key: item.value,
|
||||
|
@ -221,14 +234,9 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
})}
|
||||
direction="row"
|
||||
w="100%"
|
||||
bgColor={
|
||||
index === highlightedIndex
|
||||
? "orange.900"
|
||||
: "inherit"
|
||||
}
|
||||
color={
|
||||
index === highlightedIndex
|
||||
? "gray.100"
|
||||
? "#F56646"
|
||||
: "inherit"
|
||||
}
|
||||
justifyContent="space-between"
|
||||
|
@ -237,6 +245,11 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
h="24px"
|
||||
src={item.icon_url}
|
||||
alignSelf="flex-start"
|
||||
ml={
|
||||
index === highlightedIndex
|
||||
? "3px"
|
||||
: "inherit"
|
||||
}
|
||||
/>
|
||||
<chakra.span
|
||||
whiteSpace="nowrap"
|
||||
|
@ -272,8 +285,13 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
<VStack w="100%" spacing={0}>
|
||||
<Flex w="100%">
|
||||
<FormControl isInvalid={errors?.address}>
|
||||
<InputGroup my={2} fontSize="xs">
|
||||
<InputLeftAddon>
|
||||
<InputGroup
|
||||
my={2}
|
||||
fontSize="xs"
|
||||
border="1px solid white"
|
||||
borderRadius="7px"
|
||||
>
|
||||
<InputLeftAddon bg="black.300">
|
||||
<FormLabel
|
||||
fontWeight="600"
|
||||
// alignSelf="flex-start"
|
||||
|
@ -285,6 +303,7 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
<Input
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
variant="bw"
|
||||
placeholder="Address to subscribe to"
|
||||
name="address"
|
||||
value={address}
|
||||
|
@ -292,7 +311,7 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
ref={register({ required: "address is required!" })}
|
||||
></Input>
|
||||
</InputGroup>
|
||||
<FormErrorMessage color="red.400" pl="1">
|
||||
<FormErrorMessage color="#EE8686" pl="1">
|
||||
{errors?.address && errors?.address.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
|
@ -306,8 +325,13 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
<VStack w="100%" spacing={0}>
|
||||
<Flex w="100%">
|
||||
<FormControl isInvalid={errors?.label}>
|
||||
<InputGroup my={2} fontSize="xs">
|
||||
<InputLeftAddon>
|
||||
<InputGroup
|
||||
my={2}
|
||||
fontSize="xs"
|
||||
border="1px solid white"
|
||||
borderRadius="7px"
|
||||
>
|
||||
<InputLeftAddon bgColor="black.300">
|
||||
<FormLabel
|
||||
fontWeight="600"
|
||||
// alignSelf="flex-start"
|
||||
|
@ -319,6 +343,7 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
<Input
|
||||
type="text"
|
||||
autoComplete="off"
|
||||
variant="bw"
|
||||
placeholder="Name your label"
|
||||
name="label"
|
||||
value={label}
|
||||
|
@ -326,7 +351,7 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
ref={register({ required: "label is required!" })}
|
||||
></Input>
|
||||
</InputGroup>
|
||||
<FormErrorMessage color="red.400" pl="1">
|
||||
<FormErrorMessage color="#EE8686" pl="1">
|
||||
{errors?.label && errors?.label.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
|
@ -336,7 +361,7 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
)}
|
||||
|
||||
{type && (
|
||||
<FormControl isInvalid={errors?.color}>
|
||||
<FormControl isInvalid={errors?.color} bg="black.300">
|
||||
{!isModal ? (
|
||||
<Flex
|
||||
direction="row"
|
||||
|
@ -355,7 +380,6 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
>
|
||||
<IconButton
|
||||
size="md"
|
||||
// colorScheme="blue"
|
||||
color={"white.100"}
|
||||
_hover={{ bgColor: { color } }}
|
||||
bgColor={color}
|
||||
|
@ -364,6 +388,7 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
icon={<BiRefresh />}
|
||||
/>
|
||||
<Input
|
||||
variant="bw"
|
||||
type="input"
|
||||
placeholder="color"
|
||||
name="color"
|
||||
|
@ -401,6 +426,7 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
type="input"
|
||||
placeholder="color"
|
||||
name="color"
|
||||
variant="bw"
|
||||
ref={register({ required: "color is required!" })}
|
||||
value={color}
|
||||
onChange={() => null}
|
||||
|
@ -408,7 +434,20 @@ const _NewSubscription = ({ onClose, setIsLoading, isModal, initialValue }) => {
|
|||
></Input>
|
||||
</Stack>
|
||||
|
||||
<GithubPicker onChangeComplete={handleChangeColorComplete} />
|
||||
<GithubPicker
|
||||
styles={{
|
||||
default: {
|
||||
card: {
|
||||
background: "black.300",
|
||||
border: "1px solid white",
|
||||
},
|
||||
triangle: {
|
||||
borderBottomColor: "white",
|
||||
},
|
||||
},
|
||||
}}
|
||||
onChangeComplete={handleChangeColorComplete}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<FormErrorMessage color="red.400" pl="1">
|
||||
|
|
|
@ -27,10 +27,12 @@ const Scrollable = (props) => {
|
|||
}
|
||||
}
|
||||
|
||||
if (dir === -1) {
|
||||
document.getElementById("Navbar").style.top = "-48px";
|
||||
const navbar = document.getElementById("Navbar");
|
||||
|
||||
if (dir === -1 && e.target.scrollTop > 0) {
|
||||
navbar.style.top = `${-navbar.offsetHeight}px`;
|
||||
} else {
|
||||
document.getElementById("Navbar").style.top = "-0";
|
||||
navbar.style.top = "-0";
|
||||
}
|
||||
setY(currentScroll);
|
||||
if (currentScroll > scrollDepth) {
|
||||
|
@ -69,6 +71,7 @@ const Scrollable = (props) => {
|
|||
ref={scrollerRef}
|
||||
overflowY="scroll"
|
||||
onScroll={(e) => handleScroll(e)}
|
||||
// pt="72px"
|
||||
>
|
||||
{props.children}
|
||||
</Box>
|
||||
|
|
|
@ -2,35 +2,17 @@ import {
|
|||
ProSidebar,
|
||||
Menu,
|
||||
MenuItem,
|
||||
SidebarHeader,
|
||||
SidebarFooter,
|
||||
SidebarContent,
|
||||
} from "react-pro-sidebar";
|
||||
import { useContext } from "react";
|
||||
import RouterLink from "next/link";
|
||||
import {
|
||||
Flex,
|
||||
Image,
|
||||
IconButton,
|
||||
Divider,
|
||||
Text,
|
||||
Button,
|
||||
} from "@chakra-ui/react";
|
||||
import { Divider, Text, Button } from "@chakra-ui/react";
|
||||
import UIContext from "../core/providers/UIProvider/context";
|
||||
import React from "react";
|
||||
import {
|
||||
HamburgerIcon,
|
||||
ArrowLeftIcon,
|
||||
ArrowRightIcon,
|
||||
LockIcon,
|
||||
} from "@chakra-ui/icons";
|
||||
import { LockIcon } from "@chakra-ui/icons";
|
||||
import { MdSettings, MdDashboard, MdTimeline } from "react-icons/md";
|
||||
import {
|
||||
PRIMARY_MOON_LOGO_URL,
|
||||
SITEMAP,
|
||||
PAGETYPE,
|
||||
BACKGROUND_COLOR,
|
||||
} from "../core/constants";
|
||||
import { SITEMAP, PAGETYPE, BACKGROUND_COLOR } from "../core/constants";
|
||||
import useDashboard from "../core/hooks/useDashboard";
|
||||
import { MODAL_TYPES } from "../core/providers/OverlayProvider/constants";
|
||||
import OverlayContext from "../core/providers/OverlayProvider/context";
|
||||
|
@ -48,41 +30,8 @@ const Sidebar = () => {
|
|||
onToggle={ui.setSidebarToggled}
|
||||
collapsed={ui.sidebarCollapsed}
|
||||
hidden={!ui.sidebarVisible}
|
||||
className={ui.isMobileView ? "t40" : "t0"}
|
||||
>
|
||||
<SidebarHeader>
|
||||
<Flex>
|
||||
<IconButton
|
||||
ml={4}
|
||||
justifySelf="flex-start"
|
||||
colorScheme="blackAlpha"
|
||||
bgColor={BACKGROUND_COLOR}
|
||||
aria-label="App navigation"
|
||||
icon={
|
||||
ui.isMobileView ? (
|
||||
<HamburgerIcon />
|
||||
) : ui.sidebarCollapsed ? (
|
||||
<ArrowRightIcon />
|
||||
) : (
|
||||
<ArrowLeftIcon />
|
||||
)
|
||||
}
|
||||
onClick={() => {
|
||||
ui.isMobileView
|
||||
? ui.setSidebarToggled(!ui.sidebarToggled)
|
||||
: ui.setSidebarCollapsed(!ui.sidebarCollapsed);
|
||||
}}
|
||||
/>
|
||||
<RouterLink href="/" passHref>
|
||||
<Image
|
||||
w="160px"
|
||||
py="0.75rem"
|
||||
pl={1}
|
||||
src={PRIMARY_MOON_LOGO_URL}
|
||||
alt="Moonstream To"
|
||||
/>
|
||||
</RouterLink>
|
||||
</Flex>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
<Divider borderColor={BACKGROUND_COLOR} />
|
||||
<Menu iconShape="square">
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
import React, { useEffect } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import {
|
||||
Text,
|
||||
Stack,
|
||||
Box,
|
||||
FormControl,
|
||||
FormErrorMessage,
|
||||
InputGroup,
|
||||
Button,
|
||||
Input,
|
||||
InputRightElement,
|
||||
Button,
|
||||
} from "@chakra-ui/react";
|
||||
import CustomIcon from "./CustomIcon";
|
||||
import { useLogin } from "../core/hooks";
|
||||
import PasswordInput from "./PasswordInput";
|
||||
import { MODAL_TYPES } from "../core/providers/OverlayProvider/constants";
|
||||
|
||||
const SignIn = ({ toggleModal }) => {
|
||||
const { handleSubmit, errors, register } = useForm();
|
||||
const { login, isLoading, data } = useLogin();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) {
|
||||
|
@ -30,70 +29,87 @@ const SignIn = ({ toggleModal }) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Text color="gray.1200" fontSize="md">
|
||||
To your Moonstream account
|
||||
</Text>
|
||||
<form onSubmit={handleSubmit(login)}>
|
||||
<Stack width="100%" pt={4} spacing={3}>
|
||||
<Stack width="100%" spacing={3}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "18px",
|
||||
fontWeight: 400,
|
||||
color: errors.username ? "#EE8686" : "white",
|
||||
}}
|
||||
>
|
||||
{errors.username ? errors.username.message : "Username"}
|
||||
</div>
|
||||
<FormControl isInvalid={errors.username}>
|
||||
<InputGroup>
|
||||
<InputGroup bg="black">
|
||||
<Input
|
||||
_placeholder={{ textColor: "gray.1200" }}
|
||||
autoComplete="username"
|
||||
variant="filled"
|
||||
colorScheme="blue"
|
||||
placeholder="Your Moonstream username"
|
||||
variant="bw"
|
||||
placeholder="Enter your username or email"
|
||||
name="username"
|
||||
{...register("username", { required: true })}
|
||||
ref={register({ required: "Username is required!" })}
|
||||
ref={register({ required: "Username is required" })}
|
||||
/>
|
||||
<InputRightElement>
|
||||
<CustomIcon icon="name" />
|
||||
</InputGroup>
|
||||
</FormControl>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "18px",
|
||||
color: errors.password ? "#EE8686" : "white",
|
||||
}}
|
||||
>
|
||||
{errors.password ? errors.password.message : "Password"}
|
||||
</div>
|
||||
<FormControl isInvalid={errors.password}>
|
||||
<InputGroup bg="black">
|
||||
<Input
|
||||
autoComplete="current-password"
|
||||
variant="bw"
|
||||
placeholder="Enter your password"
|
||||
name="password"
|
||||
type={showPassword ? "text" : "password"}
|
||||
ref={register({ required: "Password is required" })}
|
||||
/>
|
||||
<InputRightElement
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<CustomIcon icon="password" />
|
||||
</InputRightElement>
|
||||
</InputGroup>
|
||||
<FormErrorMessage color="red.400" pl="1">
|
||||
{errors.username && errors.username.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl isInvalid={errors.password}>
|
||||
<PasswordInput
|
||||
placeholder="Your Moonstream password"
|
||||
name="password"
|
||||
ref={register({ required: "Password is required!" })}
|
||||
/>
|
||||
<FormErrorMessage color="red.400" pl="1">
|
||||
{errors.password && errors.password.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<Text textAlign="start" fontSize="18px">
|
||||
{" "}
|
||||
<Box
|
||||
cursor="pointer"
|
||||
color="#EE8686"
|
||||
as="span"
|
||||
onClick={() => toggleModal({ type: MODAL_TYPES.FORGOT })}
|
||||
>
|
||||
Forgot your password?
|
||||
</Box>
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<Button
|
||||
my={8}
|
||||
mt="30px"
|
||||
mb="10px"
|
||||
h="46px"
|
||||
fontSize="lg"
|
||||
variant="plainOrange"
|
||||
type="submit"
|
||||
width="100%"
|
||||
variant="solid"
|
||||
colorScheme="blue"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</form>
|
||||
<Text textAlign="center" fontSize="md" color="gray.1200">
|
||||
{" "}
|
||||
<Box
|
||||
cursor="pointer"
|
||||
color="blue.800"
|
||||
as="span"
|
||||
onClick={() => toggleModal({ type: MODAL_TYPES.FORGOT })}
|
||||
>
|
||||
Forgot your password?
|
||||
</Box>
|
||||
<Box height="1px" width="100%" background="#eaebf8" mb="1.875rem" />
|
||||
</Text>
|
||||
<Text textAlign="center" fontSize="md" color="gray.1200">
|
||||
|
||||
<Text textAlign="center" fontSize="md" color="white">
|
||||
Don`t have an account?{" "}
|
||||
<Box
|
||||
cursor="pointer"
|
||||
color="blue.800"
|
||||
color="#EE8686"
|
||||
as="span"
|
||||
onClick={() => toggleModal({ type: MODAL_TYPES.SIGNUP })}
|
||||
>
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import React, { useEffect } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import {
|
||||
Text,
|
||||
Stack,
|
||||
Box,
|
||||
FormControl,
|
||||
FormErrorMessage,
|
||||
InputGroup,
|
||||
Button,
|
||||
Input,
|
||||
|
@ -13,12 +12,12 @@ import {
|
|||
} from "@chakra-ui/react";
|
||||
import CustomIcon from "./CustomIcon";
|
||||
import { useSignUp } from "../core/hooks";
|
||||
import PasswordInput from "./PasswordInput";
|
||||
import { MODAL_TYPES } from "../core/providers/OverlayProvider/constants";
|
||||
|
||||
const SignUp = ({ toggleModal }) => {
|
||||
const { handleSubmit, errors, register } = useForm();
|
||||
const { signUp, isLoading, isSuccess } = useSignUp();
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (isSuccess) {
|
||||
|
@ -28,76 +27,94 @@ const SignUp = ({ toggleModal }) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Text color="gray.1200" fontSize="md">
|
||||
Sign up for free
|
||||
</Text>
|
||||
<form onSubmit={handleSubmit(signUp)}>
|
||||
<Stack width="100%" pt={4} spacing={3}>
|
||||
<Stack width="100%" spacing={3}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "18px",
|
||||
fontWeight: 400,
|
||||
color: errors.username ? "#EE8686" : "white",
|
||||
}}
|
||||
>
|
||||
{errors.username ? errors.username.message : "Username"}
|
||||
</div>
|
||||
<FormControl isInvalid={errors.username}>
|
||||
<InputGroup>
|
||||
<Input
|
||||
variant="filled"
|
||||
colorScheme="blue"
|
||||
placeholder="Your username here"
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
ref={register({ required: "Username is required!" })}
|
||||
variant="bw"
|
||||
placeholder="Enter your username or email"
|
||||
name="username"
|
||||
{...register("username", { required: true })}
|
||||
ref={register({ required: "Username is required" })}
|
||||
/>
|
||||
<InputRightElement>
|
||||
<CustomIcon icon="name" />
|
||||
</InputRightElement>
|
||||
</InputGroup>
|
||||
<FormErrorMessage color="red.400" pl="1">
|
||||
{errors.username && errors.username.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "18px",
|
||||
fontWeight: 400,
|
||||
color: errors.username ? "#EE8686" : "white",
|
||||
}}
|
||||
>
|
||||
{errors.email ? errors.email.message : "Email"}
|
||||
</div>
|
||||
<FormControl isInvalid={errors.email}>
|
||||
<InputGroup>
|
||||
<Input
|
||||
variant="filled"
|
||||
colorScheme="blue"
|
||||
placeholder="Your email here"
|
||||
variant="bw"
|
||||
placeholder="Enter your email"
|
||||
name="email"
|
||||
autoComplete="email"
|
||||
ref={register({ required: "Email is required!" })}
|
||||
ref={register({ required: "Email is required" })}
|
||||
/>
|
||||
<InputRightElement>
|
||||
<CustomIcon icon="name" />
|
||||
</InputGroup>
|
||||
</FormControl>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "18px",
|
||||
color: errors.password ? "#EE8686" : "white",
|
||||
}}
|
||||
>
|
||||
{errors.password ? errors.password.message : "Password"}
|
||||
</div>
|
||||
<FormControl isInvalid={errors.password}>
|
||||
<InputGroup bg="black">
|
||||
<Input
|
||||
autoComplete="current-password"
|
||||
variant="bw"
|
||||
placeholder="Enter your password"
|
||||
name="password"
|
||||
type={showPassword ? "text" : "password"}
|
||||
ref={register({ required: "Password is required" })}
|
||||
/>
|
||||
<InputRightElement
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<CustomIcon icon="password" />
|
||||
</InputRightElement>
|
||||
</InputGroup>
|
||||
<FormErrorMessage color="red.400" pl="1">
|
||||
{errors.email && errors.email.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
<FormControl isInvalid={errors.password}>
|
||||
<PasswordInput
|
||||
placeholder="Add password"
|
||||
name="password"
|
||||
autoComplete="new-password"
|
||||
ref={register({ required: "Password is required!" })}
|
||||
/>
|
||||
<FormErrorMessage color="red.400" pl="1">
|
||||
{errors.password && errors.password.message}
|
||||
</FormErrorMessage>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
<Button
|
||||
my={8}
|
||||
variant="solid"
|
||||
colorScheme="blue"
|
||||
width="100%"
|
||||
mt="30px"
|
||||
mb="10px"
|
||||
fontSize="lg"
|
||||
h="46px"
|
||||
type="submit"
|
||||
width="100%"
|
||||
variant="plainOrange"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Register
|
||||
</Button>
|
||||
</form>
|
||||
<Box height="1px" width="100%" background="#eaebf8" mb="1.875rem" />
|
||||
<Text textAlign="center" fontSize="md" color="gray.1200" pb={8}>
|
||||
<Text textAlign="center" fontSize="md" color="white">
|
||||
Already have an account?{" "}
|
||||
<Box
|
||||
cursor="pointer"
|
||||
color="blue.400"
|
||||
color="#EE8686"
|
||||
as="span"
|
||||
onClick={() => toggleModal({ type: MODAL_TYPES.LOGIN })}
|
||||
>
|
||||
|
|
|
@ -61,7 +61,6 @@ const SubscriptionCard = ({ subscription, isDesktopView, iconLink }) => {
|
|||
<>
|
||||
{!isDesktopView && (
|
||||
<AccordionItem
|
||||
bgColor="blue.50"
|
||||
borderBottomColor="blue.500"
|
||||
key={`token-row-${subscription.id}`}
|
||||
>
|
||||
|
@ -108,7 +107,7 @@ const SubscriptionCard = ({ subscription, isDesktopView, iconLink }) => {
|
|||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
</h2>
|
||||
<AccordionPanel pb={4} bgColor="blue.100" boxShadow="md">
|
||||
<AccordionPanel pb={4} boxShadow="md">
|
||||
<Stack>
|
||||
<Stack fontSize="sm" h="min-content" pr={0}>
|
||||
<Text placeSelf="flex-start">Address:</Text>
|
||||
|
|
|
@ -27,9 +27,8 @@ export default function SocialProfileSimple({
|
|||
maxW={"320px"}
|
||||
h="420px"
|
||||
w={"full"}
|
||||
bg={useColorModeValue("white.50", "gray.900")}
|
||||
boxShadow={"2xl"}
|
||||
rounded={"lg"}
|
||||
borderRadius="20px"
|
||||
border="1px solid white"
|
||||
p={6}
|
||||
textAlign={"center"}
|
||||
>
|
||||
|
@ -56,7 +55,7 @@ export default function SocialProfileSimple({
|
|||
<Heading fontSize={"2xl"} fontFamily={"body"}>
|
||||
{name}
|
||||
</Heading>
|
||||
<Text fontWeight={600} color={"gray.900"} mb={4}>
|
||||
<Text fontWeight={600} color={"blue.850"} mb={4}>
|
||||
{atName}
|
||||
</Text>
|
||||
<Text textAlign={"center"} px={3}>
|
||||
|
|
|
@ -64,6 +64,7 @@ const TokenRequest = ({ setNewToken, onClose }) => {
|
|||
<chakra.label for="pwd">API key label:</chakra.label>
|
||||
<Input
|
||||
w="100%"
|
||||
variant="bw"
|
||||
ref={register}
|
||||
name="token_note"
|
||||
placeholder="My API key label"
|
||||
|
@ -81,7 +82,7 @@ const TokenRequest = ({ setNewToken, onClose }) => {
|
|||
<Input
|
||||
id="pwd"
|
||||
colorScheme="blue"
|
||||
variant="filled"
|
||||
variant="bw"
|
||||
isDisabled={createToken.isLoading}
|
||||
placeholder="This action requires your password to confirm"
|
||||
name="password"
|
||||
|
@ -114,12 +115,7 @@ const TokenRequest = ({ setNewToken, onClose }) => {
|
|||
>
|
||||
Submit
|
||||
</Button>
|
||||
<Button
|
||||
variant="solid"
|
||||
colorScheme="red"
|
||||
type="submit"
|
||||
onClick={() => onClose()}
|
||||
>
|
||||
<Button variant="solid" colorScheme="red" onClick={() => onClose()}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Stack>
|
||||
|
|
|
@ -55,6 +55,7 @@ const MobileFiledInput = ({
|
|||
return (
|
||||
<>
|
||||
<Input
|
||||
variant="bw"
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={value}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
.button {
|
||||
background-color: #F56646;
|
||||
font-weight: 700;
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
justify-content: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
background-color: #F4532F;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
/* eslint-disable react/react-in-jsx-scope */
|
||||
import styles from "./PlainButton.module.css";
|
||||
|
||||
const PlainButton = (props) => {
|
||||
return (
|
||||
<div
|
||||
onClick={props.onClick}
|
||||
className={styles.button}
|
||||
style={props.style}
|
||||
type={props.type}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default PlainButton;
|
|
@ -77,7 +77,7 @@ export const SITEMAP = [
|
|||
children: [
|
||||
{
|
||||
title: "Docs",
|
||||
path: "/docs",
|
||||
path: "https://docs.moonstream.to/",
|
||||
type: PAGETYPE.CONTENT,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -30,7 +30,6 @@ import {
|
|||
AlertDialogOverlay,
|
||||
Button,
|
||||
Spinner,
|
||||
Divider,
|
||||
} from "@chakra-ui/react";
|
||||
import UIContext from "../UIProvider/context";
|
||||
import useDashboard from "../../hooks/useDashboard";
|
||||
|
@ -264,14 +263,26 @@ const OverlayProvider = ({ children }) => {
|
|||
<Modal
|
||||
isOpen={modalDisclosure.isOpen}
|
||||
onClose={() => toggleModal({ type: MODAL_TYPES.OFF })}
|
||||
size="2xl"
|
||||
size={modal.type === MODAL_TYPES.LOGIN ? "lg" : "2xl"}
|
||||
scrollBehavior="outside"
|
||||
trapFocus={false}
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalOverlay backdropFilter="auto" backdropBrightness="60%" />
|
||||
|
||||
<ModalContent textColor="black">
|
||||
<ModalHeader bgColor="white.200" py={2} fontSize="lg">
|
||||
<ModalContent
|
||||
bg="black.300"
|
||||
borderRadius="15px"
|
||||
border="1px white solid"
|
||||
p="30px"
|
||||
textColor="white"
|
||||
>
|
||||
<ModalHeader
|
||||
p="0px"
|
||||
fontSize="24px"
|
||||
lineHeight="24px"
|
||||
fontWeight="700"
|
||||
mb="30px"
|
||||
>
|
||||
{modal.type === MODAL_TYPES.NEW_SUBSCRIPTON &&
|
||||
"Subscribe to a new address"}
|
||||
{modal.type === MODAL_TYPES.FORGOT && "Forgot Password"}
|
||||
|
@ -283,9 +294,9 @@ const OverlayProvider = ({ children }) => {
|
|||
"Would you like to give it a name?"}
|
||||
{modal.type === MODAL_TYPES.MOBILE_INPUT_FIELD && modal.props.title}
|
||||
</ModalHeader>
|
||||
<Divider />
|
||||
<ModalCloseButton />
|
||||
<ModalCloseButton color="white" top="25px" right="25px" />
|
||||
<ModalBody
|
||||
p="0px"
|
||||
zIndex={100002}
|
||||
bgColor={
|
||||
modal.type === MODAL_TYPES.UPLOAD_ABI ? "white.200" : undefined
|
||||
|
@ -299,7 +310,9 @@ const OverlayProvider = ({ children }) => {
|
|||
{...modal.props}
|
||||
/>
|
||||
)}
|
||||
{modal.type === MODAL_TYPES.FORGOT && <ForgotPassword />}
|
||||
{modal.type === MODAL_TYPES.FORGOT && (
|
||||
<ForgotPassword toggleModal={toggleModal} />
|
||||
)}
|
||||
{modal.type === MODAL_TYPES.HUBSPOT && (
|
||||
<HubspotForm
|
||||
toggleModal={toggleModal}
|
||||
|
@ -344,8 +357,8 @@ const OverlayProvider = ({ children }) => {
|
|||
}
|
||||
}}
|
||||
>
|
||||
<DrawerOverlay />
|
||||
<DrawerContent overflowY="scroll" textColor="black">
|
||||
<DrawerOverlay backdropFilter="auto" backdropBrightness="60%" />
|
||||
<DrawerContent overflowY="scroll" textColor="white" bg="black.300">
|
||||
<DrawerCloseButton />
|
||||
<DrawerHeader borderBottomWidth="1px">
|
||||
{drawer.type === DRAWER_TYPES.NEW_DASHBOARD && "New dashboard"}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Flex, Spinner, Box } from "@chakra-ui/react";
|
||||
import { getLayout as getSiteLayout } from "./RootLayout";
|
||||
import React, { useContext, useEffect } from "react";
|
||||
import React, { Suspense, useContext, useEffect } from "react";
|
||||
import UIContext from "../core/providers/UIProvider/context";
|
||||
import AppNavbar from "../components/AppNavbar";
|
||||
import { BACKGROUND_COLOR } from "../core/constants";
|
||||
import Sidebar from "../components/Sidebar";
|
||||
|
||||
const AppLayout = ({ children }) => {
|
||||
const ui = useContext(UIContext);
|
||||
|
@ -25,6 +26,7 @@ const AppLayout = ({ children }) => {
|
|||
w="100%"
|
||||
overflow="hidden"
|
||||
direction="column"
|
||||
pb="85px"
|
||||
>
|
||||
{(!ui.isAppReady || !ui.isLoggedIn) && (
|
||||
<Spinner
|
||||
|
@ -55,7 +57,19 @@ const AppLayout = ({ children }) => {
|
|||
>
|
||||
<AppNavbar />
|
||||
</Flex>
|
||||
{ui.isAppReady && ui.isLoggedIn && children}
|
||||
<Flex
|
||||
direction="row"
|
||||
// id="Bugout"
|
||||
className="Main"
|
||||
w="100%"
|
||||
h="100%"
|
||||
maxH="100%"
|
||||
>
|
||||
<Suspense fallback="">
|
||||
<Sidebar />
|
||||
</Suspense>
|
||||
{ui.isAppReady && ui.isLoggedIn && children}
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { CloseIcon } from "@chakra-ui/icons";
|
||||
import { Flex, Center, Text, Link, IconButton } from "@chakra-ui/react";
|
||||
import React, { Suspense, useContext, useState } from "react";
|
||||
import React, { useContext, useState } from "react";
|
||||
import UIContext from "../core/providers/UIProvider/context";
|
||||
const Sidebar = React.lazy(() => import("../components/Sidebar"));
|
||||
|
||||
|
@ -17,9 +17,6 @@ const RootLayout = (props) => {
|
|||
h="100%"
|
||||
maxH="100%"
|
||||
>
|
||||
<Suspense fallback="">
|
||||
<Sidebar />
|
||||
</Suspense>
|
||||
<Flex
|
||||
direction="column"
|
||||
flexGrow={1}
|
||||
|
|
|
@ -29,6 +29,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
.t40 {
|
||||
top: 40px;
|
||||
}
|
||||
|
||||
.t0 {
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.pro-sidebar {
|
||||
height: 100%;
|
||||
width: 270px;
|
||||
|
|
|
@ -267,3 +267,32 @@ code {
|
|||
linear-gradient(to right, transparent 6px, white 6px),
|
||||
linear-gradient(to bottom, #444 1px, transparent 1px);
|
||||
}
|
||||
|
||||
|
||||
.desktop-menu-item {
|
||||
color: white;
|
||||
font-weight: 400;
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
margin-bottom: 10px;
|
||||
height: 22px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.desktop-menu-item:hover {
|
||||
color: #F56646;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* to dont change div size when bolding text.
|
||||
Need 'title' attr in the longest item's tag*/
|
||||
.desktop-menu-item::after {
|
||||
display: block;
|
||||
content: attr(title);
|
||||
font-weight: 700;
|
||||
height: 1px;
|
||||
color: transparent;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue