Merge branch 'main' into change-navbar-logo

pull/156/head
Tim Pechersky 2021-08-24 18:06:08 +02:00
commit ed641fb67d
18 zmienionych plików z 424 dodań i 308 usunięć

Wyświetl plik

@ -19,9 +19,9 @@ jobs:
- name: Install test requirements
working-directory: ./backend
run: pip install -r requirements.txt
# - name: Mypy type check
# working-directory: ./backend
# run: mypy moonstream/
- name: Mypy type check
working-directory: ./backend
run: mypy moonstream/
- name: Black syntax check
working-directory: ./backend
run: black --check moonstream/

Wyświetl plik

@ -19,9 +19,9 @@ jobs:
- name: Install test requirements
working-directory: ./crawlers
run: pip install -e .[dev]
# - name: Mypy type check
# working-directory: ./crawlers
# run: mypy mooncrawl/
- name: Mypy type check
working-directory: ./crawlers
run: mypy mooncrawl/
- name: Black syntax check
working-directory: ./crawlers
run: black --check mooncrawl/

Wyświetl plik

@ -19,9 +19,9 @@ jobs:
- name: Install test requirements
working-directory: ./db
run: pip install -e .[dev]
# - name: Mypy type check
# working-directory: ./db
# run: mypy moonstreamdb/
- name: Mypy type check
working-directory: ./db
run: mypy moonstreamdb/
- name: Black syntax check
working-directory: ./db
run: black --check moonstreamdb/

Wyświetl plik

@ -1,14 +1,11 @@
from datetime import datetime
import json
import logging
from typing import Dict, Any, List, Optional
from typing import Dict, Any, List, Optional, Union
from sqlalchemy.engine.base import Transaction
import boto3 # type: ignore
from moonstreamdb.models import (
EthereumBlock,
EthereumTransaction,
EthereumPendingTransaction,
EthereumAddress,
EthereumLabel,
)
@ -16,12 +13,10 @@ from sqlalchemy import or_, and_, text
from sqlalchemy.orm import Session
from . import data
from .settings import DEFAULT_STREAM_TIMEINTERVAL, ETHERSCAN_SMARTCONTRACTS_BUCKET
import boto3
import json
logger = logging.getLogger(__name__)
ETHERSCAN_SMARTCONTRACT_LABEL_NAME = "etherscan_smartcontract"
async def get_transaction_in_blocks(
@ -264,7 +259,7 @@ def parse_search_query_to_sqlalchemy_filters(q: str, allowed_addresses: List[str
return constructed_filters
def get_source_code(
def get_contract_source_info(
db_session: Session, contract_address: str
) -> Optional[data.EthereumSmartContractSourceInfo]:
query = db_session.query(EthereumAddress.id).filter(
@ -278,7 +273,7 @@ def get_source_code(
)
for label in labels:
if label.label == "etherscan_smartcontract":
if label.label == ETHERSCAN_SMARTCONTRACT_LABEL_NAME:
object_uri = label.label_data["object_uri"]
key = object_uri.split("s3://etherscan-smart-contracts/")[1]
s3 = boto3.client("s3")
@ -294,13 +289,13 @@ def get_source_code(
)
return contract_source_info
except:
logger.error(f"Failed to load smart contract {contract_address}")
logger.error(f"Failed to load smart contract {object_uri}")
return None
def get_address_labels(
db_session: Session, start: int, limit: int, addresses: Optional[List[str]] = None
) -> List[EthereumAddress]:
db_session: Session, start: int, limit: int, addresses: Optional[str] = None
) -> data.AddressListLabelsResponse:
"""
Attach labels to addresses.
"""

Wyświetl plik

@ -84,11 +84,13 @@ async def txinfo_ethereum_blockchain_handler(
if smart_contract is not None:
response.is_smart_contract_deployment = True
else:
response.smart_contract_info = actions.get_source_code(
source_info = actions.get_contract_source_info(
db_session, txinfo_request.tx.to_address
)
response.smart_contract_address = txinfo_request.tx.to_address
response.is_smart_contract_call = True
if source_info is not None:
response.smart_contract_info = source_info
response.smart_contract_address = txinfo_request.tx.to_address
response.is_smart_contract_call = True
return response
@ -97,8 +99,8 @@ async def txinfo_ethereum_blockchain_handler(
)
async def addresses_labels_handler(
addresses: Optional[str] = Query(None),
start: Optional[int] = Query(0),
limit: Optional[int] = Query(100),
start: int = Query(0),
limit: int = Query(100),
db_session: Session = Depends(yield_db_session),
) -> data.AddressListLabelsResponse:
"""
@ -110,11 +112,11 @@ async def addresses_labels_handler(
status_code=406, detail="The limit cannot exceed 100 addresses"
)
try:
addresses = actions.get_address_labels(
addresses_response = actions.get_address_labels(
db_session=db_session, start=start, limit=limit, addresses=addresses
)
except Exception as err:
logger.error(f"Unable to get info about Ethereum addresses {err}")
raise HTTPException(status_code=500)
return addresses
return addresses_response

Wyświetl plik

@ -16,8 +16,8 @@ MOONSTREAM_DATA_JOURNAL_ID = os.environ.get("MOONSTREAM_DATA_JOURNAL_ID")
if MOONSTREAM_DATA_JOURNAL_ID is None:
raise ValueError("MOONSTREAM_DATA_JOURNAL_ID environment variable must be set")
MOONSTREAM_ADMIN_ACCESS_TOKEN = os.environ.get("MOONSTREAM_ADMIN_ACCESS_TOKEN")
if MOONSTREAM_ADMIN_ACCESS_TOKEN is None:
MOONSTREAM_ADMIN_ACCESS_TOKEN = os.environ.get("MOONSTREAM_ADMIN_ACCESS_TOKEN", "")
if MOONSTREAM_ADMIN_ACCESS_TOKEN == "":
raise ValueError("MOONSTREAM_ADMIN_ACCESS_TOKEN environment variable must be set")
# Origin
@ -43,4 +43,6 @@ for path in MOONSTREAM_OPENAPI_LIST:
DEFAULT_STREAM_TIMEINTERVAL = 5 * 60
# S3 Bucket
ETHERSCAN_SMARTCONTRACTS_BUCKET = "etherscan-smart-contracts"
ETHERSCAN_SMARTCONTRACTS_BUCKET = os.environ.get("AWS_S3_SMARTCONTRACT_BUCKET")
if ETHERSCAN_SMARTCONTRACTS_BUCKET is None:
raise ValueError("AWS_S3_SMARTCONTRACT_BUCKET is not set")

Wyświetl plik

@ -5,5 +5,6 @@ export MOONSTREAM_DATA_JOURNAL_ID="<bugout_journal_id_to_store_blockchain_data>"
export MOONSTREAM_DB_URI="postgresql://<username>:<password>@<db_host>:<db_port>/<db_name>"
export MOONSTREAM_POOL_SIZE=0
export MOONSTREAM_ADMIN_ACCESS_TOKEN="<Access token to application resources>"
export AWS_S3_SMARTCONTRACT_BUCKET=""
export BUGOUT_BROOD_URL="https://auth.bugout.dev"
export BUGOUT_SPIRE_URL="https://spire.bugout.dev"

Wyświetl plik

@ -91,6 +91,8 @@ def ethcrawler_blocks_sync_handler(args: argparse.Namespace) -> None:
starting_block: int = args.start
while True:
bottom_block_number, top_block_number = get_latest_blocks(args.confirmations)
if bottom_block_number is None:
raise ValueError("Variable bottom_block_number can't be None")
bottom_block_number = max(bottom_block_number + 1, starting_block)
if bottom_block_number >= top_block_number:
print(

Wyświetl plik

@ -44,9 +44,11 @@ def connect(web3_uri: Optional[str] = MOONSTREAM_IPC_PATH):
return web3_client
def add_block(db_session, block: BlockData) -> None:
def add_block(db_session, block: Any) -> None:
"""
Add block if doesn't presented in database.
block: web3.types.BlockData
"""
block_obj = EthereumBlock(
block_number=block.number,
@ -70,9 +72,11 @@ def add_block(db_session, block: BlockData) -> None:
db_session.add(block_obj)
def add_block_transactions(db_session, block: BlockData) -> None:
def add_block_transactions(db_session, block: Any) -> None:
"""
Add block transactions.
block: web3.types.BlockData
"""
for tx in block.transactions:
tx_obj = EthereumTransaction(
@ -188,7 +192,7 @@ def crawl_blocks_executor(
Returns nothing, but if there was an error processing the given blocks it raises an EthereumBlocksCrawlError.
The error message is a list of all the things that went wrong in the crawl.
"""
errors: List[Exception] = []
errors: List[BaseException] = []
def record_error(f: Future) -> None:
error = f.exception()
@ -196,7 +200,7 @@ def crawl_blocks_executor(
errors.append(error)
worker_indices = range(MOONSTREAM_CRAWL_WORKERS)
worker_job_lists = [[] for _ in worker_indices]
worker_job_lists: List[List[Any]] = [[] for _ in worker_indices]
for i, block_number in enumerate(block_numbers_list):
worker_job_lists[i % MOONSTREAM_CRAWL_WORKERS].append(block_number)
@ -290,6 +294,7 @@ def trending(
end_timestamp = int(date_range.end_time.timestamp())
def make_query(
db_session: Session,
identifying_column: Column,
statistic_column: Column,
aggregate_func: Callable,
@ -328,6 +333,7 @@ def trending(
try:
transactions_out_query = make_query(
db_session,
EthereumTransaction.from_address,
EthereumTransaction.hash,
func.count,
@ -339,6 +345,7 @@ def trending(
]
transactions_in_query = make_query(
db_session,
EthereumTransaction.to_address,
EthereumTransaction.hash,
func.count,
@ -350,6 +357,7 @@ def trending(
]
value_out_query = make_query(
db_session,
EthereumTransaction.from_address,
EthereumTransaction.value,
func.sum,
@ -361,6 +369,7 @@ def trending(
]
value_in_query = make_query(
db_session,
EthereumTransaction.to_address,
EthereumTransaction.value,
func.sum,

Wyświetl plik

@ -1,21 +1,22 @@
import argparse
import boto3
import sys
import time
from datetime import datetime
from typing import Any, List, Optional, Dict
from dataclasses import dataclass
import csv
import codecs
import json
import os
from sqlalchemy.orm import Session
import boto3 # type: ignore
from moonstreamdb.db import yield_db_session_ctx
import sys
import time
from datetime import datetime
from typing import Any, List, Optional, Tuple, Dict
from dataclasses import dataclass
from sqlalchemy.sql.expression import label, text
from .version import MOONCRAWL_VERSION
from moonstreamdb.models import EthereumAddress, EthereumLabel
import requests
from sqlalchemy.orm import Session
from sqlalchemy.sql.expression import text
from .version import MOONCRAWL_VERSION
from .settings import MOONSTREAM_ETHERSCAN_TOKEN
if MOONSTREAM_ETHERSCAN_TOKEN is None:

Wyświetl plik

@ -1,13 +1,13 @@
import unittest
from . import cli
from . import ethcrawler
class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_descending_10_6_step_4(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"10-6", block_step=4
)
]
@ -16,7 +16,7 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_descending_10_6_step_3(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"10-6", block_step=3
)
]
@ -25,8 +25,8 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_descending_10_6_descending_step_3(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
"10-6", cli.ProcessingOrder.DESCENDING, 3
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"10-6", ethcrawler.ProcessingOrder.DESCENDING, 3
)
]
self.assertListEqual(partition, [[10, 9, 8], [7, 6]])
@ -34,8 +34,8 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_descending_10_6_descending_step_10(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
"10-6", cli.ProcessingOrder.DESCENDING, 10
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"10-6", ethcrawler.ProcessingOrder.DESCENDING, 10
)
]
self.assertListEqual(partition, [[10, 9, 8, 7, 6]])
@ -43,7 +43,7 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_descending_6_10_step_4(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"6-10", block_step=4
)
]
@ -52,7 +52,7 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_descending_6_10_step_3(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"6-10", block_step=3
)
]
@ -61,8 +61,8 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_descending_6_10_descending_step_3(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
"6-10", cli.ProcessingOrder.DESCENDING, 3
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"6-10", ethcrawler.ProcessingOrder.DESCENDING, 3
)
]
self.assertListEqual(partition, [[10, 9, 8], [7, 6]])
@ -70,8 +70,8 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_descending_6_10_descending_step_10(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
"6-10", cli.ProcessingOrder.DESCENDING, 10
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"6-10", ethcrawler.ProcessingOrder.DESCENDING, 10
)
]
self.assertListEqual(partition, [[10, 9, 8, 7, 6]])
@ -79,8 +79,8 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_ascending_10_6_ascending_step_3(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
"10-6", cli.ProcessingOrder.ASCENDING, 3
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"10-6", ethcrawler.ProcessingOrder.ASCENDING, 3
)
]
self.assertListEqual(partition, [[6, 7, 8], [9, 10]])
@ -88,8 +88,8 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_ascending_10_6_ascending_step_10(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
"10-6", cli.ProcessingOrder.ASCENDING, 10
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"10-6", ethcrawler.ProcessingOrder.ASCENDING, 10
)
]
self.assertListEqual(partition, [[6, 7, 8, 9, 10]])
@ -97,8 +97,8 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_ascending_6_10_ascending_step_4(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
"6-10", cli.ProcessingOrder.ASCENDING, 4
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"6-10", ethcrawler.ProcessingOrder.ASCENDING, 4
)
]
self.assertListEqual(partition, [[6, 7, 8, 9], [10]])
@ -106,8 +106,8 @@ class TestYieldBlockNumbersLists(unittest.TestCase):
def test_yield_ascending_6_10_ascending_step_10(self):
partition = [
block_numbers_list
for block_numbers_list in cli.yield_blocks_numbers_lists(
"6-10", cli.ProcessingOrder.ASCENDING, 10
for block_numbers_list in ethcrawler.yield_blocks_numbers_lists(
"6-10", ethcrawler.ProcessingOrder.ASCENDING, 10
)
]
self.assertListEqual(partition, [[6, 7, 8, 9, 10]])

Wyświetl plik

@ -40,7 +40,9 @@ setup(
"web3",
"boto3",
],
extras_require={"dev": ["black", "mypy", "types-requests"]},
extras_require={
"dev": ["black", "mypy", "types-requests", "types-python-dateutil"]
},
entry_points={
"console_scripts": [
"ethcrawler=mooncrawl.ethcrawler:main",

Wyświetl plik

@ -1,4 +1,4 @@
import React, { useEffect, useState, useLayoutEffect, useContext } from "react";
import React, { useEffect, useState, useLayoutEffect } from "react";
import {
Heading,
Text,
@ -9,10 +9,9 @@ import {
useMediaQuery,
UnorderedList,
ListItem,
useBreakpointValue,
} from "@chakra-ui/react";
import { DEFAULT_METATAGS, AWS_ASSETS_PATH } from "../../src/core/constants";
import UIContext from "../../src/core/providers/UIProvider/context";
export async function getStaticProps() {
return {
props: { metaTags: { ...DEFAULT_METATAGS } },
@ -20,14 +19,13 @@ export async function getStaticProps() {
}
const assets = {
background720: `${AWS_ASSETS_PATH}/blog-background-720x405.png`,
background1920: `${AWS_ASSETS_PATH}/blog-background-720x405.png`,
background2880: `${AWS_ASSETS_PATH}/blog-background-720x405.png`,
background3840: `${AWS_ASSETS_PATH}/blog-background-720x405.png`,
background720: `${AWS_ASSETS_PATH}/product-background-720x405.png`,
background1920: `${AWS_ASSETS_PATH}/product-background-720x405.png`,
background2880: `${AWS_ASSETS_PATH}/product-background-720x405.png`,
background3840: `${AWS_ASSETS_PATH}/product-background-720x405.png`,
};
const Product = () => {
const ui = useContext(UIContext);
const [background, setBackground] = useState("background720");
const [backgroundLoaded720, setBackgroundLoaded720] = useState(false);
const [backgroundLoaded1920, setBackgroundLoaded1920] = useState(false);
@ -47,16 +45,18 @@ const Product = () => {
]);
useEffect(() => {
assets["background720"] = `${AWS_ASSETS_PATH}/blog-background-720x405.png`;
assets[
"background720"
] = `${AWS_ASSETS_PATH}/product-background-720x405.png`;
assets[
"background1920"
] = `${AWS_ASSETS_PATH}/blog-background-1920x1080.png`;
] = `${AWS_ASSETS_PATH}/product-background-1920x1080.png`;
assets[
"background2880"
] = `${AWS_ASSETS_PATH}/blog-background-2880x1620.png`;
] = `${AWS_ASSETS_PATH}/product-background-2880x1620.png`;
assets[
"background3840"
] = `${AWS_ASSETS_PATH}/blog-background-3840x2160.png`;
] = `${AWS_ASSETS_PATH}/product-background-3840x2160.png`;
}, []);
useLayoutEffect(() => {
@ -82,7 +82,7 @@ const Product = () => {
useLayoutEffect(() => {
const imageLoader720 = new Image();
imageLoader720.src = `${AWS_ASSETS_PATH}/blog-background-720x405.png`;
imageLoader720.src = `${AWS_ASSETS_PATH}/product-background-720x405.png`;
imageLoader720.onload = () => {
setBackgroundLoaded720(true);
};
@ -90,7 +90,7 @@ const Product = () => {
useLayoutEffect(() => {
const imageLoader1920 = new Image();
imageLoader1920.src = `${AWS_ASSETS_PATH}/blog-background-1920x1080.png`;
imageLoader1920.src = `${AWS_ASSETS_PATH}/product-background-1920x1080.png`;
imageLoader1920.onload = () => {
setBackgroundLoaded1920(true);
};
@ -98,7 +98,7 @@ const Product = () => {
useLayoutEffect(() => {
const imageLoader2880 = new Image();
imageLoader2880.src = `${AWS_ASSETS_PATH}/blog-background-2880x1620.png`;
imageLoader2880.src = `${AWS_ASSETS_PATH}/product-background-2880x1620.png`;
imageLoader2880.onload = () => {
setBackgroundLoaded2880(true);
};
@ -106,13 +106,20 @@ const Product = () => {
useLayoutEffect(() => {
const imageLoader3840 = new Image();
imageLoader3840.src = `${AWS_ASSETS_PATH}/blog-background-3840x2160.png`;
imageLoader3840.src = `${AWS_ASSETS_PATH}/product-background-3840x2160.png`;
imageLoader3840.onload = () => {
setBackgroundLoaded3840(true);
};
}, []);
const margin = ui.isMobileView ? "7%" : "25%";
const margin = useBreakpointValue({
base: "1%",
sm: "2%",
md: "3%",
lg: "15%",
xl: "20%",
"2xl": "25%",
});
return (
<Flex
@ -124,36 +131,63 @@ const Product = () => {
minH="100vh"
direction="column"
alignItems="center"
pb={24}
>
<Stack mx={margin} my={12} maxW="1700px">
<Heading as="h2" size="md" w="100%" px={12} py={2} borderTopRadius="xl">
Vision
{`Why you'll love moonstream`}
</Heading>
<chakra.span pl={2} px={12} py={2}>
<Text mb={2}>
Our goal is to provide a live view of the transactions taking place
on <b>every</b> public blockchain.
We strive for financial inclusion. With cryptocurrencies becoming
mainstream, now is the time for anyone with a computer and access to
the Internet to utilize this opportunity to make passive income.
Were here to make it easier.
</Text>
<Text mb={2}>
We aim to go far beyond raw transaction information, enriching our
view with context from centralized exchanges, the news, social
media, and smart contract analysis.
Right now our source of data is Ethereum blockchain. Our goal is to
provide a live view of the transactions taking place on every public
blockchain - from the activity of specific accounts or smart
contracts to updates about general market movements.
</Text>
<Text mb={2}>
Data is only as good as the decisions it informs. We are building
Moonstream to be much more than a database. We are building
Moonstream to be an execution engine, where anyone can set up
triggers based on Moonstream events. Triggers can submit
transactions to any blockchain or they can call external APIs via
webhooks.
This information comes from the blockchains themselves, from their
mempools/transaction pools, and from centralized exchanges, social
media, and the news. This forms a stream of information tailored to
your specific needs.
</Text>
<Text mb={2}>
Moonstream will be accessible to humans through our dashboard and
notification system.
Were giving you a macro view of the crypto market with direct
access from Moonstream dashboards to execute transactions. You can
also set up programs which execute (on- or off-chain) when your
stream meets certain conditions.
</Text>
<Text mb={2}>
Moonstream will be accessible to software through our API and
webhooks.
Moonstream is accessible through dashboard, API and webhooks.
</Text>
<Text mb={2}>
Moonstreams financial inclusion goes beyond providing access to
data. All of our work is open source as we do not believe that
proprietary technologies are financially inclusive.
</Text>
<Text mb={2}>
You can read{" "}
<Link
textColor="primary.500"
isExternal
href="https://github.com/bugout-dev/moonstream"
>
our code on GitHub.
</Link>{" "}
and keep track of our progress using{" "}
<Link
textColor="primary.500"
isExternal
href="https://github.com/bugout-dev/moonstream/milestones"
>
the Moonstream milestones
</Link>
.
</Text>
</chakra.span>
</Stack>
@ -177,9 +211,9 @@ const Product = () => {
Moonstream users can subscribe to events from any blockchain - from
the activity of specific accounts or smart contracts to updates
about general market movements. This information comes from the
blockchains themselves, from their mempools/transaction pools, and
from centralized exchanges, social media, and the news. This forms a
stream of information tailored to their specific needs.
blockchains themselves, from their <b>mempools/transaction</b>{" "}
pools, and from centralized exchanges, social media, and the news.
This forms a stream of information tailored to their specific needs.
</Text>
<Text mb={2}>
They can use this information to execute transactions directly from

Wyświetl plik

@ -9,6 +9,8 @@ import {
useMediaQuery,
UnorderedList,
ListItem,
Box,
SimpleGrid,
} from "@chakra-ui/react";
import { DEFAULT_METATAGS, AWS_ASSETS_PATH } from "../../src/core/constants";
import UIContext from "../../src/core/providers/UIProvider/context";
@ -18,6 +20,7 @@ const assets = {
background1920: `${AWS_ASSETS_PATH}/blog-background-720x405.png`,
background2880: `${AWS_ASSETS_PATH}/blog-background-720x405.png`,
background3840: `${AWS_ASSETS_PATH}/blog-background-720x405.png`,
team: `${AWS_ASSETS_PATH}/Team-page-illustration.png`,
};
const Product = () => {
@ -119,36 +122,56 @@ const Product = () => {
alignItems="center"
w="100%"
>
<Stack mx={margin} my={6} maxW="1700px">
<Heading as="h2" size="md" w="100%" px={12} py={2} borderTopRadius="xl">
Meet The Moonstream Team
</Heading>
<chakra.span pl={2} px={12} py={2}>
<Text mb={2}>
We are a distributed team of nerds with very strong expertise in
math, software engineering, machine learning, and cryptography.
Members of our team worked at Google, at OpenAI and other great
companies.
</Text>
<Text mb={2}>
We believe that the crypto world opens opportunities for financial
inclusion. Meaning that people from all walks of life and financial
situations can have a new source of income. We are passionate about
developing technology that helps people become active participants
in this field and take advantage of this opportunity. Were striving
to debunk harmful stereotypes and make the crypto field more
inclusive.
</Text>
</chakra.span>
<Stack mx={margin} maxW="1700px" w="100%">
<SimpleGrid
px={12}
alignItems="start"
columns={{ base: 1, md: 2 }}
// mb={24}
spacingY={{ base: 10, md: 32 }}
spacingX={{ base: 10, md: 24 }}
>
<Box>
<Heading as="h2" size="md" w="100%" py={6} borderTopRadius="xl">
Meet The Moonstream Team
</Heading>
<chakra.span pl={2} py={2}>
<Text mb={2}>
We are a distributed team of nerds with very strong expertise in
math, software engineering, machine learning, and cryptography.
Members of our team worked at Google, at OpenAI and other great
companies.
</Text>
<Text mb={2}>
We believe that the crypto world opens opportunities for
financial inclusion. Meaning that people from all walks of life
and financial situations can have a new source of income. We are
passionate about developing technology that helps people become
active participants in this field and take advantage of this
opportunity. Were striving to debunk harmful stereotypes and
make the crypto field more inclusive.
</Text>
</chakra.span>
</Box>
<Box
w="full"
h="full"
py={48}
backgroundImage={`url(${assets[`team`]})`}
backgroundSize="cover"
bgPos="bottom"
bgColor="transparent"
></Box>
</SimpleGrid>
</Stack>
<Stack mx={margin} my={6} maxW="1700px">
<Stack mx={margin} mb={6} mt={0} maxW="1700px" w="100%">
<Heading
as="h2"
size="md"
w="100%"
// bgColor="gray.200"
px={12}
py={2}
pb={2}
pt={0}
borderTopRadius="xl"
>
Values that we share within our team:
@ -156,7 +179,10 @@ const Product = () => {
<chakra.span pl={2} px={12} py={2}>
<UnorderedList w="75%" pl={4}>
<ListItem>
<b> Be bold</b>
<b>Be bold</b>
</ListItem>
<ListItem>
<b>Be curious</b>
</ListItem>
<ListItem>
<b>Dont be an ass</b>
@ -178,43 +204,35 @@ const Product = () => {
</Text>
</chakra.span>
</Stack>
<Stack mx={margin} mb={12} maxW="1700px">
<Heading
as="h2"
size="md"
w="100%"
// bgColor="gray.200"
px={12}
py={2}
borderTopRadius="xl"
>
<Stack mx={margin} mb={12} maxW="1700px" w="100%">
<Heading as="h2" size="md" w="100%" px={12} py={2} borderTopRadius="xl">
Our engineering team
</Heading>
<chakra.span pl={2} px={12} py={2}>
<UnorderedList w="75%" pl={4} spacing={2}>
<ListItem>
<b>zomglings,</b> Founder. Number theorist. Loves playing chess
while programming. Fan of GO, backgammon, and video games.
<b>zomglings{". "}</b> Founder. Number theorist. Loves playing
chess while programming. Fan of GO, backgammon, and video games.
</ListItem>
<ListItem>
<b>kompotkot -</b>Keeper of Secrets. Likes information security
since childhood, loves mountains and goes hiking from time to
time. Had a close call with a wild bear in a forest once.
<b>kompotkot{". "}</b>Keeper of Secrets. Likes information
security since childhood, loves mountains and goes hiking from
time to time. Had a close call with a wild bear in a forest once.
</ListItem>
<ListItem>
<b>wizarikus -</b>Wizard. Loves mountains, bicycling, and hiking.
A practicing Python wizard. Also likes to cook and play the guitar
in between data witchcraft.
<b>wizarikus{". "}</b>Wizard. Loves mountains, bicycling, and
hiking. A practicing Python wizard. Also likes to cook and play
the guitar in between data witchcraft.
</ListItem>
<ListItem>
<b>peersky -</b>
<b>peersky{". "}</b>
{`Spectral hopper. Perceives the world as a
spectrum interacting with and within the observer's mind. Loves
to shift in time domain to spend some of it doing fire
performances, surfing, and connecting with nature.`}
</ListItem>
<ListItem>
<b>yhtyyar -</b>
<b>yhtyyar{". "}</b>
{`Wunderkind. Interested in Math, NLP. Loves
programming language parsing and Algorithms & Data structures.
Implementing his own dialect of LISP programming language for
@ -223,25 +241,25 @@ const Product = () => {
</UnorderedList>
</chakra.span>
</Stack>
<Stack mx={margin} mb={12} maxW="1700px">
<Stack mx={margin} mb={12} maxW="1700px" w="100%">
<Heading as="h2" size="md" w="100%" px={12} py={2} borderTopRadius="xl">
Our marketing and growth team
</Heading>
<chakra.span pl={2} px={12} py={2}>
<UnorderedList w="75%" pl={4}>
<ListItem>
<b>Pahita.</b> Dreamer. An alien who pretends to be a human. So
far so good. Loves ecstatic dance, being alone in nature and
<b>Pahita{". "}</b> Dreamer. An alien who pretends to be a human.
So far so good. Loves ecstatic dance, being alone in nature and
dreaming.
</ListItem>
<ListItem>
<b>In_technicolor,</b>Mediator. Loves stand-up comedy and crying
at nights. Volunteered at a horse farm once. Portrait artist, puts
the pain in painting.
<b>In_technicolor{". "}</b>Mediator. Loves stand-up comedy and
crying at nights. Volunteered at a horse farm once. Portrait
artist, puts the pain in painting.
</ListItem>
<ListItem>
<b>Nanaland.</b>Progress and Enthusiasm. Traveled to the North
Korean border at the age of 19. Half German. Counseling
<b>Nanaland{". "}</b>Progress and Enthusiasm. Traveled to the
North Korean border at the age of 19. Half German. Counseling
psychologist who switched to tech marketing and sales.
</ListItem>
</UnorderedList>

Wyświetl plik

@ -18,6 +18,11 @@ import {
Flex,
IconButton,
Tooltip,
Accordion,
AccordionItem,
AccordionButton,
AccordionPanel,
AccordionIcon,
} from "@chakra-ui/react";
import StepProgress from "../src/components/StepProgress";
import { ArrowLeftIcon, ArrowRightIcon } from "@chakra-ui/icons";
@ -31,7 +36,6 @@ import router from "next/router";
import { FaFilter } from "react-icons/fa";
const Welcome = () => {
console.count("render welcome!");
const { subscriptionsCache } = useSubscriptions();
const ui = useContext(UIContext);
const { mixpanel, isLoaded, MIXPANEL_PROPS } = useContext(AnalyticsContext);
@ -99,22 +103,19 @@ const Welcome = () => {
py={4}
>
<Heading as="h4" size="md">
Greetings traveller!
Greetings traveler!
</Heading>
<Text fontWeight="semibold" pl={2}>
{" "}
We are very excited to see you onboard!
</Text>
<Text fontWeight="semibold" pl={2}>
Moonstream is a product which helps anyone participate in
decentralized finance. From the most sophisticated flash
arbitrageurs to people looking for yield from currency that
would otherwise lie dormant in their exchange accounts.
decentralized finance.
</Text>
<Text fontWeight="semibold" pl={2}>
Moonstream is ment to give you critical insights needed to
succeed in your crypto quest!
Moonstream is meant to give you critical insights youll need
to succeed in your crypto quest!
</Text>
</Stack>
<Stack
@ -125,38 +126,54 @@ const Welcome = () => {
boxShadow="xl"
py={4}
>
<Heading as="h4" size="md">
How does Moonstream work?
</Heading>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
We run nodes
</Text>{" "}
- Now get most precise and accurate data you can just query
our database. You {`don't`} need to maintain your node, and
still have data that miners have access to!
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
We crawl data
</Text>{" "}
We analyze millions of transactions, data, smart contract code
to link all them together
</chakra.span>
<Accordion allowToggle>
<AccordionItem borderWidth={0}>
<h2>
<AccordionButton borderWidth={0}>
<Heading as="h4" size="md">
How does Moonstream work?
</Heading>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4} borderWidth={0}>
<Stack direction="column">
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
We run nodes
</Text>{" "}
- Get precise and accurate data by querying our
database. Youre getting the same data miners have
access to and you dont have to maintain your own
node.
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
We crawl data
</Text>{" "}
- We analyze millions of transactions, data, and smart
contract code to link them together.
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
We provide data
</Text>{" "}
We allow you to fetch data trough the website or trough API
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
We provide data
</Text>
- You can fetch data through our front end or through
API.
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
We analyze data
</Text>{" "}
We find most interesting stuff and show it to you!
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
We analyze data
</Text>
- We find the most interesting information and
highlight it
</chakra.span>
</Stack>
</AccordionPanel>
</AccordionItem>
</Accordion>
</Stack>
<Stack
px={12}
@ -166,55 +183,71 @@ const Welcome = () => {
boxShadow="xl"
py={4}
>
<Heading as="h4" size="md">
UI 101?
</Heading>
<Text fontWeight="semibold" pl={2}>
On the left side corner there is sidebar that you can use to
navigate across the website. There are following views you can
navigate to:
</Text>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
Subscriptions
</Text>{" "}
- Use this screen to set up addresses you would like to
monitor to.{" "}
<i>
NB: Without setting up subscriptions moonstream will have
quite empty feel!{" "}
</i>{" "}
No worries, we will help you to set up your subscriptions in
the next steps!
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
Stream
</Text>{" "}
This view is somewhat similar to a bank statement where you
can define time range and see what happened in that time over
your subscriptions. In next steps we will show how you can
apply filters to it!
</chakra.span>
<Accordion allowToggle>
<AccordionItem borderWidth={0}>
<h2>
<AccordionButton borderWidth={0}>
<Heading as="h4" size="md">
UI navigation basics
</Heading>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4} borderWidth={0}>
<Stack dir="column">
<Text fontWeight="semibold" pl={2}>
Use the sidebar on the left for navigation:
</Text>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
Subscriptions
</Text>
Set up addresses you would like to monitor.{" "}
<i>
NB: Without any subscriptions, Moonstream will feel
quite empty!
</i>{" "}
No worries, we will help you set up your
subscriptions.
<i>
NB: Without setting up subscriptions moonstream will
have quite empty feel!{" "}
</i>{" "}
No worries, we will help you to set up your
subscriptions in the next steps!
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
Stream
</Text>{" "}
This view is similar to a bank statement. You can
define a date range and see what happened with your
subscriptions during that time. You can also apply
filters to it.
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
Stream Entry
</Text>{" "}
You can see detailed view of stream cards with very specific
and essential data, like methods called in smart contracts
etc!!
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
Stream Entry
</Text>{" "}
- See a detailed view of stream cards with specific
and essential data, like methods called in smart
contracts etc
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
Analytics
</Text>{" "}
This section is under construction yet. Soon you will be able
to create your dashboard with data of your interest. We will
really appretiate if you visit that section, and fill up form
describing what analytical tools you would love to see there!
</chakra.span>
<chakra.span fontWeight="semibold" pl={2}>
<Text fontWeight="bold" display="inline">
Analytics
</Text>{" "}
- This section is under construction. Soon you will be
able to create dashboards there. Right now you can
fill out a form to tell us what analytical tools youd
want to see. Wed really appreciate that :)
</chakra.span>
</Stack>
</AccordionPanel>
</AccordionItem>
</Accordion>
</Stack>
<Stack
@ -226,25 +259,32 @@ const Welcome = () => {
py={4}
>
<Heading as="h4" size="md">
Tell us more about your needs?
Tell us more about your needs
</Heading>
<Text fontWeight="semibold" pl={2}>
In order to fetch best possible experience, we would like to
know some details about you
In order to create the best possible experience, we would love
to find out some more about you.
</Text>
<Text fontWeight="semibold" pl={2}>
Please tell us what profile describes you best?{" "}
Please tell us what profile describes you best.{" "}
<i>
This is purely analytical data, you can change it anytime
later
later.
</i>
</Text>
<RadioGroup
position="relative"
onChange={setProfile}
value={profile}
fontWeight="bold"
// fontWeight="bold"
colorScheme="secondary"
// py={0}
// my={0}
>
<Stack direction="row" justifyContent="space-evenly">
<Stack
direction={["column", "row", null]}
justifyContent="space-evenly"
>
<Radio value="trader">I am trading crypto currency</Radio>
<Radio value="fund">I represent investment fund</Radio>
<Radio value="developer">I am developer</Radio>
@ -270,24 +310,26 @@ const Welcome = () => {
Subscriptions
</Heading>
<chakra.span fontWeight="semibold" pl={2}>
Subscriptions is essential tool of Moonstream. We gather data
for you based on addresses you have subscribed for.
Subscriptions are an essential tool of Moonstream. We gather
data for you based on addresses you have subscribed to.
<br />
Subscribe to any addres which you are interested in and they
will become part of your stream!
Subscribe to any address you are interested in and it will
become part of your stream.
<br />
Name of subscription (you can change it later).
<UnorderedList>
<ListItem>
Color - you can define color to easily identify this
Color - you can set colors to easily identify a
subscription in your stream
</ListItem>
<ListItem>Address - thing you subscribe to</ListItem>
<ListItem>Address - the address you subscribe to</ListItem>
<ListItem>
Label - Its good idea to use human readible name that
represents address
Label - we recommend using a human-readable name that
represents the subscription
</ListItem>
<ListItem>
Source - In Alpha we support only Ethereum blockchain,
more sources are coming soon!
Source - In Alpha were only supporting Ethereum
blockchain, but more sources are coming soon!
</ListItem>
</UnorderedList>
</chakra.span>
@ -342,35 +384,32 @@ const Welcome = () => {
<chakra.span fontWeight="semibold" pl={2}>
We are almost done!
<br />
{`Stream is where you can read data you've subscribed for. Here
you have different cards for different subscription types.`}
{`Stream is where you can read data you've subscribed to. There are different cards for different subscription types.`}
<br />
If card has some extra details - there will be orange button
on right hand side inviting you to see more!
If the card has some extra details, there will be an orange
button on the right hand side inviting you to see more!
<br />
Below is typical card for ethereum blockchain event. Useful
information right on the card:
Below is a typical card for an Ethereum blockchain event.
Useful information right on the card:
<UnorderedList py={2}>
<ListItem>Hash - unique ID of the event </ListItem>
<ListItem>Hash - Unique ID of the event</ListItem>
<ListItem>
From - sender address. If it is one of your subscription
addresses - will appear in color and with label{" "}
From - Sender address. If it is one of your subscription
addresses, it will appear in color with a label
</ListItem>
<ListItem>
To - receiver address. If it is one of your subscription
addresses - will appear in color and with label{" "}
To - Receiver address. If it is one of your subscription
addresses, it will appear in color with a label
</ListItem>
<ListItem>
Nonce - Counter how many transactions address has sent. It
also determines sequence of transaction!{" "}
Nonce - Counter how many transaction addresses have been
sent. It also determines the sequence of transactions!
</ListItem>
<ListItem>
Gas Price - this is how much ether is being paid per gas
Gas Price - This is how much ether is being paid per gas
unit
</ListItem>
<ListItem>
Gas - Ammount of gas this event consumes
</ListItem>
<ListItem>Gas - Amount of gas this event consumes</ListItem>
</UnorderedList>
</chakra.span>
</Stack>
@ -402,6 +441,7 @@ const Welcome = () => {
<StreamEntry
mt={20}
entry={{
event_type: "ethereum_blockchain",
from_address: "this is address from",
to_address: "this is to address",
hash: "this is hash",
@ -422,9 +462,10 @@ const Welcome = () => {
Applying filters
</Heading>
<chakra.span fontWeight="semibold" pl={2}>
You can apply various filters by clicking filter menu button
You can apply various filters by clicking the filter menu
button.
<br />
{`Right now you can use it to select address from and to, we are adding more complex queries soon, stay tuna! `}
{`Right now you can use it to select addresses from and to, and we are adding more complex queries soon — stay tuned!`}
<br />
</chakra.span>
</Stack>
@ -444,20 +485,30 @@ const Welcome = () => {
scrollRef?.current?.scrollIntoView();
}}
>
Previous
Go back
</Button>
<Spacer />
<Button
colorScheme="secondary"
variant="solid"
rightIcon={<ArrowRightIcon />}
// hidden={!(ui.onboardingStep < ui.onboardingSteps.length - 1)}
// disabled={!(ui.onboardingStep < ui.onboardingSteps.length - 1)}
colorScheme={
ui.onboardingStep < ui.onboardingSteps.length - 1
? `secondary`
: `suggested`
}
variant={
ui.onboardingStep < ui.onboardingSteps.length - 1
? `solid`
: `outline`
}
rightIcon={
ui.onboardingStep < ui.onboardingSteps.length - 1 && (
<ArrowRightIcon />
)
}
onClick={() => handleNextClick()}
>
{ui.onboardingStep < ui.onboardingSteps.length - 1
? `Next`
: `Finish `}
: `Finish and move to stream`}
</Button>
</ButtonGroup>
</Stack>

Wyświetl plik

@ -1,6 +1,7 @@
import React from "react";
import { Flex, Text, Link } from "@chakra-ui/react";
import { Flex, Text, Link, Heading } from "@chakra-ui/react";
import CustomIcon from "../components/CustomIcon";
import RouterLink from "next/link";
const ICONS = [
{
@ -22,6 +23,11 @@ const SITEMAP_FLEX_PROPS = {
mr: 12,
};
const LINKS_SIZES = {
fontWeight: "300",
fontSize: "lg",
};
const Footer = () => (
<Flex
bg="brand.200"
@ -42,31 +48,28 @@ const Footer = () => (
maxW="40rem"
>
<Flex {...SITEMAP_FLEX_PROPS}>
{/* <Heading pb={8} size="md">
<Heading pb={8} size="md">
About
</Heading> */}
{/* <RouterLink passHref href="/team">
</Heading>{" "}
<RouterLink passHref href="/team">
<Link {...LINKS_SIZES}>Team</Link>
</RouterLink> */}
{/* <RouterLink passHref href="/events">
<Link {...LINKS_SIZES}>Events</Link>
</RouterLink>
<RouterLink passHref href="http://blog.bugout.dev">
<Link {...LINKS_SIZES}>Blog</Link>
</RouterLink> */}
<RouterLink passHref href="/product">
<Link {...LINKS_SIZES}>Product</Link>
</RouterLink>
</Flex>
<Flex {...SITEMAP_FLEX_PROPS}>
{/* <Heading pb={8} size="md">
Legal
<Heading pb={8} size="md">
News
</Heading>
<RouterLink href="/tos" passHref>
<Link {...LINKS_SIZES}>Terms of service</Link>
</RouterLink> */}
<RouterLink passHref href="http://blog.moonstream.to">
<Link {...LINKS_SIZES}>Blog</Link>
</RouterLink>
{/* <RouterLink passHref href="/privacy-policy">
<Link {...LINKS_SIZES}>Privacy policy</Link>
</RouterLink> */}
</Flex>
{/* <Flex {...SITEMAP_FLEX_PROPS}>
<Heading pb={8} size="md">
Product
@ -94,7 +97,7 @@ const Footer = () => (
fontSize="xl"
fontWeight="500"
>
Stay in touch{` `}
All the crypto data you care about{` `}
<span role="img" aria-label="heart">
💙
</span>

Wyświetl plik

@ -129,7 +129,6 @@ const NewSubscription = ({ isFreeOption, onClose }) => {
</Text>{" "}
<IconButton
size="md"
// colorScheme="primary"
color={"white.100"}
_hover={{ bgColor: { color } }}
bgColor={color}
@ -148,10 +147,7 @@ const NewSubscription = ({ isFreeOption, onClose }) => {
></Input>
</Stack>
<GithubPicker
// color={this.state.background}
onChangeComplete={handleChangeColorComplete}
/>
<GithubPicker onChangeComplete={handleChangeColorComplete} />
<FormErrorMessage color="unsafe.400" pl="1">
{errors.color && errors.color.message}

Wyświetl plik

@ -73,7 +73,7 @@ const _NewSubscription = ({ isFreeOption, onClose, setIsLoading }) => {
my={2}
type="text"
autoComplete="off"
placeholder="Meaningful name of your subscription"
placeholder="Name of subscription (you can change it later)"
name="label"
ref={register({ required: "label is required!" })}
></Input>