mirror of
https://github.com/FlipsideCrypto/sdk.git
synced 2026-02-06 10:46:43 +00:00
merge / resolve conflicts w/ main
This commit is contained in:
commit
bf728ca685
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"semi": true
|
||||
}
|
||||
@ -19,6 +19,6 @@ More Details at [ShroomDK](https://sdk.flipsidecrypto.xyz)
|
||||
|
||||
| Language | Version | Status |
|
||||
| ------------------------ | ------- | ---------------------------------------------------------------------------------- |
|
||||
| ✅ [JS/TypeScript](./js) | 1.0.0 |  |
|
||||
| ✅ [JS/TypeScript](./js) | 1.1.1 |  |
|
||||
| ✅ [Python](./python/) | 1.0.2 | [](https://github.com/FlipsideCrypto/sdk/actions/workflows/ci_python.yml) |
|
||||
| ✅ [R](./r/shroomDK/) | 0.1.1 | available on CRAN |
|
||||
|
||||
7
examples/js/react-app/.eslintrc.js
Normal file
7
examples/js/react-app/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* @type {import('@types/eslint').Linter.Config}
|
||||
*/
|
||||
module.exports = {
|
||||
root: true,
|
||||
ignorePatterns: ["node_modules", "dist", "public"],
|
||||
};
|
||||
29304
examples/js/react-app/package-lock.json
generated
29304
examples/js/react-app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.3.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/eslint": "^8.4.8",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^16.11.45",
|
||||
"@types/react": "^18.0.15",
|
||||
|
||||
@ -12,7 +12,7 @@ interface ButtonProps {
|
||||
function getBg(color: string) {
|
||||
let bgColor = "bg-[#7C7C7C]";
|
||||
let bgColorHover = "hover:bg-[#BCBCca]";
|
||||
if (color == "blue") {
|
||||
if (color === "blue") {
|
||||
bgColor = "bg-[#2A3492]";
|
||||
bgColorHover = "hover:bg-[#2A34ca]";
|
||||
} else if (color === "green") {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
import { QueryResultSet } from "@flipsidecrypto/sdk";
|
||||
import { Input } from "../components/input";
|
||||
import { RetroButton } from "../components/retro-buttons";
|
||||
|
||||
@ -1885,6 +1885,14 @@
|
||||
"@types/estree" "*"
|
||||
"@types/json-schema" "*"
|
||||
|
||||
"@types/eslint@^8.4.8":
|
||||
version "8.4.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.8.tgz#720dd6a32b8219b9aba1a07b13e9d03b622695fd"
|
||||
integrity sha512-zUCKQI1bUCTi+0kQs5ZQzQ/XILWRLIlh15FXWNykJ+NG3TMKMVvwwC6GP3DR1Ylga15fB7iAExSzc4PNlR5i3w==
|
||||
dependencies:
|
||||
"@types/estree" "*"
|
||||
"@types/json-schema" "*"
|
||||
|
||||
"@types/estree@*":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz"
|
||||
|
||||
147
examples/r/shroomDK_BAYC_example.Rmd
Normal file
147
examples/r/shroomDK_BAYC_example.Rmd
Normal file
@ -0,0 +1,147 @@
|
||||
---
|
||||
title: "shroomDK-Example"
|
||||
author: "Charliemarketplace"
|
||||
date: '2022-10-06'
|
||||
output: html_document
|
||||
---
|
||||
|
||||
```{r setup, include=FALSE}
|
||||
knitr::opts_chunk$set(echo = TRUE)
|
||||
```
|
||||
|
||||
# Intro to ShroomDK
|
||||
|
||||
The shroomDK package has full access to all the data within Flipside Crypto. You just need your own API-key,
|
||||
which is free at: https://sdk.flipsidecrypto.xyz/shroomdk
|
||||
|
||||
For this documentation, you can use this API key to test things out in R. **But it is capped at 10,000 queries a day among all public users**: `2a4caf06-d503-4c96-a30e-a13dc34792d0`
|
||||
|
||||
It is highly recommended you get your own key for free at https://sdk.flipsidecrypto.xyz/shroomdk - but just to get you off the ground you can use the shared key at first.
|
||||
|
||||
Here is some example code to get you started!
|
||||
|
||||
Let's look at Bored Ape Yacht Club NFT transfers over time. First, we'll set a Block_Number
|
||||
maximum to make our analysis reproducible. Let's use Block_Number = 15680000
|
||||
|
||||
This query was made within the flipsidecrypto.xyz SQL tool and we can copy this query to use within R
|
||||
by storing the query in a character (i.e., double quotes: "").
|
||||
|
||||
Notice that the NFT Address is made lowercase to conform to how Flipside's Snowflake database stores them.
|
||||
The EZ_NFT_Transfers table has sales, mints, and other forms of transfer of 1,000s of NFTs!
|
||||
|
||||
```{r, warning = FALSE, message = FALSE}
|
||||
library(plotly)
|
||||
library(dplyr)
|
||||
bayc_transfers_query <- "
|
||||
SELECT BLOCK_NUMBER, BLOCK_TIMESTAMP, NFT_ADDRESS, PROJECT_NAME, NFT_TO_ADDRESS, TOKENID
|
||||
FROM ethereum.core.ez_nft_transfers
|
||||
WHERE BLOCK_NUMBER <= 15680000 AND
|
||||
NFT_ADDRESS = LOWER('0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D')
|
||||
ORDER BY BLOCK_NUMBER DESC
|
||||
"
|
||||
```
|
||||
|
||||
If you haven't installed shroomDK, scroll up to the beginning of the docs to find install instructions.
|
||||
shroomDK is in processing to be added to CRAN! So, soon, install.packages('shroomDK') will work within R.
|
||||
|
||||
```{r, warning = FALSE, message = FALSE}
|
||||
# Get your API key for free at sdk.flipsidecrypto.xyz/shroomdk
|
||||
bayc_transfers <- shroomDK::auto_paginate_query(query = bayc_transfers_query,
|
||||
api_key = "2a4caf06-d503-4c96-a30e-a13dc34792d0") # get your own API Key to avoid rate limits!
|
||||
```
|
||||
This query returns over 86,000 historical transfers!
|
||||
|
||||
With R you can group by block_timestamp at the day level and plot transfers over time! Here we'll use the
|
||||
dplyr and plotly packages.
|
||||
```{r}
|
||||
daily_transfers <- bayc_transfers %>%
|
||||
dplyr::mutate(day = as.Date(BLOCK_TIMESTAMP)) %>%
|
||||
dplyr::group_by(day) %>%
|
||||
dplyr::summarise(num_transfers = n())
|
||||
```
|
||||
|
||||
The plot shows that May 1, 2021 was the most popular transfer day (likely the day the public mint went viral);
|
||||
but there are other pockets are many transfers including May 1, 2022, a highly volatile time for all of crypto.
|
||||
|
||||
```{r}
|
||||
plotly::plot_ly(data = daily_transfers, x = ~day, y = ~num_transfers, mode = 'lines', type = 'scatter')
|
||||
```
|
||||
|
||||
What if we were curious who the current holders of each token id are?
|
||||
|
||||
With R it's simple!
|
||||
|
||||
Group by token_id, order by block_number DESCENDING (recent blocks up top), and
|
||||
pick the most recent transfer recipient (the person who most recently received token id is by
|
||||
definition the owner of that token id as of our block number).
|
||||
|
||||
```{r, warning = FALSE, message = FALSE}
|
||||
bayc_holders <- bayc_transfers %>%
|
||||
dplyr::mutate(TOKENID = as.numeric(TOKENID)) %>%
|
||||
dplyr::group_by(TOKENID) %>%
|
||||
dplyr::arrange( desc(BLOCK_NUMBER) ) %>%
|
||||
dplyr::summarise(current_holder = first(NFT_TO_ADDRESS))
|
||||
```
|
||||
|
||||
Are there BAYCs being held in "cold storage"? Wallets that hold tokens/NFTs but have never initiated
|
||||
a transaction?
|
||||
|
||||
With this bayc_holders list, we can *ask shroomDK* for activity from these addresses!
|
||||
|
||||
First, let's template the query and use R to swap in parameters (including large ones like 10,000
|
||||
addresses in the WHERE clause).
|
||||
|
||||
We'll swap: ADRRESSLIST, _MIN_BLOCK_, and _MAX_BLOCK_ using R's gsub function.
|
||||
```{r, warning = FALSE, message = FALSE}
|
||||
activity_query <- {
|
||||
"
|
||||
with select_tx AS (
|
||||
SELECT BLOCK_TIMESTAMP, TX_HASH, FROM_ADDRESS as ADDRESS FROM ethereum.core.fact_transactions
|
||||
WHERE FROM_ADDRESS IN ('ADDRESSLIST') AND
|
||||
BLOCK_NUMBER >= _MIN_BLOCK_ AND
|
||||
BLOCK_NUMBER <= _MAX_BLOCK_
|
||||
ORDER BY BLOCK_NUMBER DESC
|
||||
)
|
||||
SELECT ADDRESS, COUNT(*) as num_tx,
|
||||
count(DISTINCT(date_trunc('DAY', block_timestamp))) as num_days,
|
||||
MAX(block_timestamp) as last_tx_date FROM
|
||||
select_tx
|
||||
GROUP BY ADDRESS
|
||||
"
|
||||
}
|
||||
|
||||
# paste together the unique addresses from our 10,000 BAYC NFTs to work with SQL.
|
||||
|
||||
alist <- paste0(tolower(unique(bayc_holders$current_holder)), collapse = "','")
|
||||
|
||||
# swap parameters
|
||||
activity_query <- gsub('ADDRESSLIST', replacement = alist, x = activity_query)
|
||||
activity_query <- gsub('_MIN_BLOCK_', replacement = 0, x = activity_query)
|
||||
activity_query <- gsub('_MAX_BLOCK_', replacement = 15680000, x = activity_query)
|
||||
```
|
||||
|
||||
Our activity_query is now HUGE. It has 1,000s of addresses in its where clause. But shroomDK doesn't care!
|
||||
|
||||
```{r, warning = FALSE, message = FALSE}
|
||||
bayc_holder_activity <- shroomDK::auto_paginate_query(activity_query, api_key = "2a4caf06-d503-4c96-a30e-a13dc34792d0")
|
||||
```
|
||||
|
||||
As of block 15680000, there are 6,079 unique BAYC holders with at least 1 transaction.
|
||||
Let's FULL join these tables in R and see if there are any bayc_holders with NA transactions (i.e., they are cold
|
||||
storage addresses that have never initiated a transaction!).
|
||||
```{r}
|
||||
bayc_holders <- merge(bayc_holders, bayc_holder_activity,
|
||||
all.x = TRUE, all.y = TRUE, by.x = 'current_holder', by.y = 'ADDRESS')
|
||||
|
||||
bayc_holders$status <- ifelse(is.na(bayc_holders$NUM_TX), "Cold", "Active")
|
||||
```
|
||||
Note, some addresses hold multiple tokens, so each row here is only unique at the token level.
|
||||
While "Cold Storage" is the terminology used, technically BAYC can be held within contracts (e.g., fractionalized NFTs Vaults or gnosis safes) or be burnt (held by 0x0000....0000dead).
|
||||
|
||||
```{r}
|
||||
plotly::plot_ly(bayc_holders, x = ~status, type = 'histogram')
|
||||
```
|
||||
|
||||
1,024 of the 10,000 BAYC NFTs are held in either contracts or cold storage addresses!
|
||||
|
||||
With shroomDK we can query flipside crypto's blockchain data with even advanced queries that ask for information on 1,000s of addresses in a single WHERE clause - and bring it directly into R for advanced plotting.
|
||||
2447
examples/r/shroomDK_BAYC_example.html
Normal file
2447
examples/r/shroomDK_BAYC_example.html
Normal file
File diff suppressed because one or more lines are too long
7
js/.eslintrc.js
Normal file
7
js/.eslintrc.js
Normal file
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* @type {import('@types/eslint').Linter.Config}
|
||||
*/
|
||||
module.exports = {
|
||||
root: true,
|
||||
ignorePatterns: ["node_modules", "dist", "public"],
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@flipsidecrypto/sdk",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"description": "The official Flipside Crypto SDK",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@ -30,6 +30,7 @@
|
||||
"author": "dev@flipsidecrypto.com",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/eslint": "^8.4.8",
|
||||
"axios": "^0.27.2"
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,9 +15,13 @@ const PARSE_ERROR_MSG =
|
||||
export class API implements ApiClient {
|
||||
#baseUrl: string;
|
||||
#headers: Record<string, string>;
|
||||
#sdkVersion: string;
|
||||
#sdkPackage: string;
|
||||
|
||||
constructor(baseUrl: string, apiKey: string) {
|
||||
constructor(baseUrl: string, sdkPackage: string, sdkVersion: string, apiKey: string) {
|
||||
this.#baseUrl = baseUrl;
|
||||
this.#sdkPackage = sdkPackage;
|
||||
this.#sdkVersion = sdkVersion;
|
||||
this.#headers = {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
@ -38,6 +42,8 @@ export class API implements ApiClient {
|
||||
sql: query.sql,
|
||||
ttl_minutes: query.ttlMinutes,
|
||||
cached: query.cached,
|
||||
sdk_package: this.#sdkPackage,
|
||||
sdk_version: this.#sdkVersion,
|
||||
},
|
||||
{ headers: this.#headers }
|
||||
);
|
||||
|
||||
@ -1,14 +1,18 @@
|
||||
import { API } from "./api";
|
||||
import { QueryIntegration } from "./integrations";
|
||||
import { version } from '../package.json';
|
||||
|
||||
|
||||
const API_BASE_URL = "https://api.flipsidecrypto.com";
|
||||
const SDK_PACKAGE = "js";
|
||||
const SDK_VERSION = version;
|
||||
|
||||
export class Flipside {
|
||||
query: QueryIntegration;
|
||||
|
||||
constructor(apiKey: string, apiBaseUrl: string = API_BASE_URL) {
|
||||
// Setup API, which will be passed to integrations
|
||||
const api = new API(apiBaseUrl, apiKey);
|
||||
const api = new API(apiBaseUrl, SDK_PACKAGE, SDK_VERSION, apiKey);
|
||||
|
||||
// declare integrations on Flipside client
|
||||
this.query = new QueryIntegration(api);
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files */
|
||||
"resolveJsonModule": true, /* Enable importing .json files */
|
||||
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
|
||||
18
js/yarn.lock
18
js/yarn.lock
@ -47,11 +47,29 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.1.tgz#e2c6e73e0bdeb2521d00756d099218e9f5d90a04"
|
||||
integrity sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==
|
||||
|
||||
"@types/eslint@^8.4.8":
|
||||
version "8.4.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.8.tgz#720dd6a32b8219b9aba1a07b13e9d03b622695fd"
|
||||
integrity sha512-zUCKQI1bUCTi+0kQs5ZQzQ/XILWRLIlh15FXWNykJ+NG3TMKMVvwwC6GP3DR1Ylga15fB7iAExSzc4PNlR5i3w==
|
||||
dependencies:
|
||||
"@types/estree" "*"
|
||||
"@types/json-schema" "*"
|
||||
|
||||
"@types/estree@*":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2"
|
||||
integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==
|
||||
|
||||
"@types/istanbul-lib-coverage@^2.0.1":
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44"
|
||||
integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==
|
||||
|
||||
"@types/json-schema@*":
|
||||
version "7.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
|
||||
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
|
||||
|
||||
"@vitest/ui@latest":
|
||||
version "0.12.6"
|
||||
resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-0.12.6.tgz#6dba9bd6781ce1280452e4b25160b3914eb5e435"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user