kopia lustrzana https://github.com/bugout-dev/moonstream
Merge branch 'main' into cards-improvement
commit
5a8a9c7095
59
README.md
59
README.md
|
@ -1,2 +1,59 @@
|
|||
# moonstream
|
||||
The Bugout blockchain inspector
|
||||
|
||||
\[[Live at https://moonstream.to/](https://moonstream.to)\] | \[[Join us on Discord](https://discord.gg/pYE65FuNSz)\]
|
||||
|
||||
## What is Moonstream?
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
They can use this information to execute transactions directly from the Moonstream frontend or they
|
||||
can set up programs which execute (on- or off-chain) when their stream meets certain conditions.
|
||||
|
||||
## Who uses Moonstream?
|
||||
|
||||
1. **Development teams deploying decentralized applications.** They use Moonstream to analyze how
|
||||
users are calling their dapps, and set up alerts for suspicious activity.
|
||||
2. **Algorithmic funds.** They use Moonstream to execute transactions directly on-chain under
|
||||
prespecified conditions.
|
||||
3. **Crypto traders.** They use Moonstream to evaluate trading strategies based on data from
|
||||
centralized exchanges, the blockchain, and the transaction pool.
|
||||
|
||||
## Free software
|
||||
|
||||
Proprietary technologies are not inclusive technologies, and we believe in inclusion.
|
||||
|
||||
All of our technology is open source. This repository contains all the code that powers
|
||||
https://moonstream.to. The code is licensed with the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
||||
You are and _will always be_ free to host your own instance of Moonstream.
|
||||
|
||||
## Architecture
|
||||
|
||||
This monorepo contains the following components:
|
||||
|
||||
1. [`frontend`](./frontend): A web frontend for Moonstream. Allows users to perform API operations
|
||||
through a visual interface. The frontend also offers charting and analysis functionality. Built
|
||||
in [React](https://reactjs.org/).
|
||||
2. [`backend`'](./backend): The Moonstream API. This portion of the code base implements a REST API
|
||||
through which users can manage the events that show up in their stream and actually consume their
|
||||
stream data. Built in [Python](https://www.python.org/) using [Fast API](https://fastapi.tiangolo.com/).
|
||||
3. [`crawlers`](./crawlers): This part of the code base contains workers which extract data from
|
||||
blockchains, transaction pools, and other sources. Currently contains a single [Python](https://www.python.org/)
|
||||
package but we will soon be addding crawlers implemented in other languages: [Go](https://golang.org/),
|
||||
[Rust](https://www.rust-lang.org/)), and [Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript).
|
||||
4. [`db`](./db): Moonstream stores blockchain data in [Postgres](https://www.postgresql.org/). This
|
||||
directory contains the code we use to manage the schema in our Postgres database. For sources that
|
||||
send higher volumes of data, we use a separate Postgres database and interface with it using
|
||||
[Bugout](https://bugout.dev). For more information on how that data is processed, check how the API
|
||||
inserts events from those sources into a stream.
|
||||
|
||||
## Contributing
|
||||
|
||||
If you would like to contribute to Moonstream, please reach out to @zomglings on the [Moonstream Discord](https://discord.gg/pYE65FuNSz).
|
||||
|
|
|
@ -84,6 +84,8 @@ async def get_transaction_in_blocks(
|
|||
.filter(filters)
|
||||
)
|
||||
|
||||
ethereum_transactions = ethereum_transactions_in_subscriptions
|
||||
|
||||
# If not start_time and end_time not present
|
||||
# Get latest transaction
|
||||
if boundaries.end_time == 0:
|
||||
|
@ -92,10 +94,11 @@ async def get_transaction_in_blocks(
|
|||
text("timestamp desc")
|
||||
).limit(1)
|
||||
).one_or_none()
|
||||
boundaries.end_time = ethereum_transaction_start_point[-1]
|
||||
boundaries.start_time = (
|
||||
ethereum_transaction_start_point[-1] - DEFAULT_STREAM_TIMEINTERVAL
|
||||
)
|
||||
if ethereum_transaction_start_point:
|
||||
boundaries.end_time = ethereum_transaction_start_point[-1]
|
||||
boundaries.start_time = (
|
||||
ethereum_transaction_start_point[-1] - DEFAULT_STREAM_TIMEINTERVAL
|
||||
)
|
||||
|
||||
if boundaries.start_time != 0 and boundaries.end_time != 0:
|
||||
if boundaries.start_time > boundaries.end_time:
|
||||
|
@ -105,7 +108,7 @@ async def get_transaction_in_blocks(
|
|||
)
|
||||
|
||||
if boundaries.end_time:
|
||||
ethereum_transactions = ethereum_transactions_in_subscriptions.filter(
|
||||
ethereum_transactions = ethereum_transactions.filter(
|
||||
include_or_not_lower(
|
||||
EthereumBlock.timestamp, boundaries.include_end, boundaries.end_time
|
||||
)
|
||||
|
|
|
@ -60,10 +60,10 @@ app.add_middleware(BroodAuthMiddleware, whitelist=whitelist_paths)
|
|||
async def search_transactions(
|
||||
request: Request,
|
||||
q: str = Query(""),
|
||||
start_time: Optional[int] = Query(0), # Optional[int] = Query(0), #
|
||||
end_time: Optional[int] = Query(0), # Optional[int] = Query(0), #
|
||||
include_start: bool = Query(False),
|
||||
include_end: bool = Query(False),
|
||||
start_time: Optional[int] = Query(0),
|
||||
end_time: Optional[int] = Query(0),
|
||||
include_start: Optional[bool] = Query(False),
|
||||
include_end: Optional[bool] = Query(False),
|
||||
db_session: Session = Depends(db.yield_db_session),
|
||||
):
|
||||
|
||||
|
@ -87,8 +87,6 @@ async def search_transactions(
|
|||
for resource in user_subscriptions_resources.resources
|
||||
}
|
||||
|
||||
# transactions: List[Any] = []
|
||||
|
||||
boundaries = data.PageBoundary(
|
||||
start_time=start_time,
|
||||
end_time=end_time,
|
||||
|
@ -97,17 +95,14 @@ async def search_transactions(
|
|||
include_start=include_start,
|
||||
include_end=include_end,
|
||||
)
|
||||
print(boundaries)
|
||||
|
||||
if address_to_subscriptions:
|
||||
print("address_to_subscriptions")
|
||||
response = await actions.get_transaction_in_blocks(
|
||||
db_session=db_session,
|
||||
query=q,
|
||||
user_subscriptions_resources_by_address=address_to_subscriptions,
|
||||
boundaries=boundaries,
|
||||
)
|
||||
print(response.boundaries)
|
||||
|
||||
return response
|
||||
else:
|
||||
|
|
|
@ -335,7 +335,7 @@ const Homepage = () => {
|
|||
</SimpleGrid>
|
||||
<Center>
|
||||
<Heading pt="160px" pb="60px">
|
||||
Moonstream is ment for you if
|
||||
Moonstream is meant for you if
|
||||
</Heading>
|
||||
</Center>
|
||||
<Flex
|
||||
|
|
|
@ -175,7 +175,7 @@ const EntriesNavigation = () => {
|
|||
useEffect(() => {
|
||||
if (
|
||||
subscriptionsCache.data?.subscriptions[0]?.id &&
|
||||
newFilterState[0].value === null
|
||||
newFilterState[0]?.value === null
|
||||
) {
|
||||
setFilterProps(0, {
|
||||
value: subscriptionsCache?.data?.subscriptions[0]?.address,
|
||||
|
@ -525,17 +525,19 @@ const EntriesNavigation = () => {
|
|||
"" // some strange behaivior without else condition return 0 wich can see on frontend page
|
||||
)}
|
||||
</Stack>
|
||||
{entries.map((entry, idx) => (
|
||||
<StreamEntry
|
||||
key={`entry-list-${idx}`}
|
||||
entry={entry}
|
||||
disableDelete={!canDelete}
|
||||
disableCopy={!canCreate}
|
||||
filterCallback={handleFilterStateCallback}
|
||||
filterConstants={{ DIRECTIONS, CONDITION, FILTER_TYPES }}
|
||||
/>
|
||||
))}
|
||||
{streamBoundary.previous_event_time || isFetching ? (
|
||||
{entries
|
||||
?.sort((a, b) => b.timestamp - a.timestamp) // TODO(Andrey) improve that for bi chunks of data sorting can take time
|
||||
.map((entry, idx) => (
|
||||
<StreamEntry
|
||||
key={`entry-list-${idx}`}
|
||||
entry={entry}
|
||||
disableDelete={!canDelete}
|
||||
disableCopy={!canCreate}
|
||||
filterCallback={handleFilterStateCallback}
|
||||
filterConstants={{ DIRECTIONS, CONDITION, FILTER_TYPES }}
|
||||
/>
|
||||
))}
|
||||
{streamBoundary.previous_event_time && !isFetching ? (
|
||||
<Center>
|
||||
<Button
|
||||
onClick={() => {
|
||||
|
@ -553,9 +555,20 @@ const EntriesNavigation = () => {
|
|||
</Button>
|
||||
</Center>
|
||||
) : (
|
||||
""
|
||||
<Center>
|
||||
{!isFetching ? (
|
||||
"Тransactions not found. You can subscribe to more addresses in Subscriptions menu."
|
||||
) : (
|
||||
<Button
|
||||
isLoading
|
||||
loadingText="Loading"
|
||||
variant="outline"
|
||||
colorScheme="suggested"
|
||||
></Button>
|
||||
)}
|
||||
</Center>
|
||||
)}
|
||||
{streamBoundary.previous_event_time && isLoading && (
|
||||
{streamBoundary.previous_event_time && isLoading ? (
|
||||
<Center>
|
||||
<Spinner
|
||||
//hidden={!isFetchingMore}
|
||||
|
@ -567,6 +580,8 @@ const EntriesNavigation = () => {
|
|||
speed="1.5s"
|
||||
/>
|
||||
</Center>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
|
|
@ -59,7 +59,7 @@ const SubscriptionsList = () => {
|
|||
{subscriptionsCache.data.subscriptions.map((subscription) => {
|
||||
let iconLink;
|
||||
switch (subscription.subscription_type_id) {
|
||||
case "1":
|
||||
case "0":
|
||||
iconLink =
|
||||
"https://ethereum.org/static/c48a5f760c34dfadcf05a208dab137cc/31987/eth-diamond-rainbow.png";
|
||||
break;
|
||||
|
|
|
@ -41,6 +41,7 @@ const useJournalEntries = ({
|
|||
//refetchInterval: refreshRate,
|
||||
...queryCacheProps,
|
||||
keepPreviousData: true,
|
||||
retry: 3,
|
||||
onSuccess: (response) => {
|
||||
// response is object which return condition in getStream
|
||||
// TODO(andrey): Response should send page parameters inside "boundary" object (can be null).
|
||||
|
|
|
@ -28,7 +28,7 @@ const UIProvider = ({ children }) => {
|
|||
});
|
||||
|
||||
const { modal, toggleModal } = useContext(ModalContext);
|
||||
const [searchTerm, setSearchTerm] = useQuery("q", " ", true, false);
|
||||
const [searchTerm, setSearchTerm] = useQuery("q", "", true, false);
|
||||
|
||||
const [searchBarActive, setSearchBarActive] = useState(false);
|
||||
|
||||
|
|
|
@ -9,15 +9,26 @@ export const getStream = ({
|
|||
end_time,
|
||||
include_start,
|
||||
include_end,
|
||||
}) =>
|
||||
http({
|
||||
}) => {
|
||||
let params = {
|
||||
q: searchTerm,
|
||||
};
|
||||
if (start_time || start_time === 0) {
|
||||
params.start_time = start_time;
|
||||
}
|
||||
if (end_time || end_time === 0) {
|
||||
params.end_time = end_time;
|
||||
}
|
||||
if (include_start) {
|
||||
params.include_start = include_start;
|
||||
}
|
||||
if (include_end) {
|
||||
params.include_end = include_end;
|
||||
}
|
||||
|
||||
return http({
|
||||
method: "GET",
|
||||
url: `${API}/streams/`,
|
||||
params: {
|
||||
q: searchTerm,
|
||||
start_time: start_time,
|
||||
end_time: end_time,
|
||||
include_start: include_start,
|
||||
include_end: include_end,
|
||||
},
|
||||
params,
|
||||
});
|
||||
};
|
||||
|
|
Ładowanie…
Reference in New Issue