Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Harmony support #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fly.toml
Dockerfile
.dockerignore
node_modules
.git
39 changes: 39 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# syntax = docker/dockerfile:1

# Adjust NODE_VERSION as desired
ARG NODE_VERSION=18.16.0
FROM node:${NODE_VERSION}-slim as base

LABEL fly_launch_runtime="NodeJS"

# NodeJS app lives here
WORKDIR /app

# Set production environment
ENV NODE_ENV=production


# Throw-away build stage to reduce size of final image
FROM base as build

# Install packages needed to build node modules
RUN apt-get update -qq && \
apt-get install -y python-is-python3 pkg-config build-essential

# Install node modules
COPY --link package.json package-lock.json .
RUN npm install

# Copy application code
COPY --link . .



# Final stage for app image
FROM base

# Copy built application
COPY --from=build /app /app

# Start the server by default, this can be overwritten at runtime
CMD [ "npm", "run", "start:prod" ]
25 changes: 25 additions & 0 deletions fly.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# fly.toml app configuration file generated for gmx-stats on 2024-06-14T23:28:35+03:00
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
#

app = 'gmx-stats'
primary_region = 'hkg'

[build]

[env]
PORT = '8080'

[http_service]
internal_port = 8080
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
processes = ['app']

[[vm]]
memory = '1gb'
cpu_kind = 'shared'
cpus = 1
34 changes: 21 additions & 13 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Route, Switch, NavLink, Redirect } from 'react-router-dom';
import { motion, AnimatePresence } from "framer-motion";
import cx from "classnames";
import Arbitrum from './views/Arbitrum';
import Harmony from './views/Harmony';
import Referrals from './views/Referrals';
import Avalanche from './views/Avalanche';
import Trading from './views/Trading';
Expand All @@ -22,16 +23,19 @@ function AppHeaderLinks({ mode, small, clickCloseIcon }) {
<div className="App-header-menu-icon-block" onClick={() => clickCloseIcon()}>
<FiX className="App-header-menu-icon" />
</div>
<NavLink exact activeClassName="active" className="App-header-link-main" to="/">
{/* <NavLink exact activeClassName="active" className="App-header-link-main" to="/">
<img src={logoIcon} alt="GMX Logo" />
</NavLink>
</NavLink> */}
</div>
}
<div className="App-header-link-container">
{/* <div className="App-header-link-container">
<NavLink to="/arbitrum" exact className="nav-link" activeClassName="active">Arbitrum</NavLink>
</div>
<div className="App-header-link-container">
<NavLink to="/avalanche" className="nav-link">Avalanche</NavLink>
</div> */}
<div className="App-header-link-container">
<NavLink to="/harmony" className="nav-link">Harmony</NavLink>
</div>
</div>
)
Expand Down Expand Up @@ -90,15 +94,16 @@ const App = () => {
{!isDrawerVisible && <RiMenuLine className="App-header-menu-icon" />}
{isDrawerVisible && <FaTimes className="App-header-menu-icon" />}
</div>
<a href="https://gmx.io" target="_blank" className="nav-logo">
{/* <a href="https://gmx.io" target="_blank" className="nav-logo">
<img width="87" src={mode == 'dark' ? darkLogoIcon : lightLogoIcon} />
</a>
<NavLink to="/arbitrum" exact className="nav-link" activeClassName="active">Arbitrum</NavLink>
<NavLink to="/avalanche" className="nav-link">Avalanche</NavLink>
</a> */}
{/* <NavLink to="/arbitrum" exact className="nav-link" activeClassName="active">Arbitrum</NavLink>
<NavLink to="/avalanche" className="nav-link">Avalanche</NavLink> */}
<NavLink to="/harmony" className="nav-link">Harmony</NavLink>
</div>
<div className="nav-right">
<a href="https://gmx.io" target="_blank" className="nav-link">APP</a>
<a href="https://gmxio.gitbook.io/gmx/" target="_blank" className="nav-link">DOCS</a>
{/* <a href="https://gmx.io" target="_blank" className="nav-link">APP</a>
<a href="https://gmxio.gitbook.io/gmx/" target="_blank" className="nav-link">DOCS</a> */}
<div className='modeselect' onClick={() => switchMode()}>
{mode == 'dark' ? <FaSun /> : <FaMoon />}
</div>
Expand All @@ -121,18 +126,21 @@ const App = () => {
</AnimatePresence>
<div className="content">
<Route path="/" exact>
<Redirect to="/arbitrum" />
<Redirect to="/harmony" />
</Route>
<Route exact path="/arbitrum" render={(props) => (
{/* <Route exact path="/arbitrum" render={(props) => (
<Arbitrum {...props} mode={mode} />
)} /> */}
<Route exact path="/harmony" render={(props) => (
<Harmony {...props} mode={mode} />
)} />
<Route exact path="/avalanche" render={(props) => (
{/* <Route exact path="/avalanche" render={(props) => (
<Avalanche {...props} mode={mode} />
)} />
<Route exact path="/referrals/:chainName" render={(props) => (
<Referrals {...props} mode={mode} />
)} />
<Route exact path="/trading" component={Trading} />
<Route exact path="/trading" component={Trading} /> */}
</div>
</div>
}
Expand Down
17 changes: 17 additions & 0 deletions src/addresses.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const BSC = 56
export const ARBITRUM = 42161
export const AVALANCHE = 43114
export const HARMONY = 1666600000

export const addresses = {
[BSC]: {
Expand All @@ -26,6 +27,22 @@ export const addresses = {
GlpManager: '0x321F653eED006AD1C29D174e17d96351BDe22649'
},

[HARMONY]: {
WONE: '0xcF664087a5bB0237a0BAd6742852ec6c8d69A27a',
ONE: '0xcF664087a5bB0237a0BAd6742852ec6c8d69A27a',
USDT: '0xF2732e8048f1a411C63e2df51d08f4f52E598005',
USDC: '0xBC594CABd205bD993e7FfA6F3e9ceA75c1110da5',
ETH: '0x4cC435d7b9557d54d6EF02d69Bbf72634905Bf11',
BTC: '0x118f50d23810c5E09Ebffb42d7D3328dbF75C2c2',

GXP: '0x7C54F8d25F224DeE7A0FA7583f621E9AebE24DfE',
GMX: '0x9D609c2c561e31dC0B9664F060590de7953a215A',

RewardReader: '0x820B9C96ac9afE46b4AfD8912A986f180e40df6b',
GLP: '0x1EE4a17871Aa61eF02B846795b7554aE7EAbb179',
GlpManager: '0xe51CB3361dE553fb7B75B49E5552e9D47B4aeDb0'
},

[AVALANCHE]: {
GMX: '0xfc5a1a6eb076a2c7ad06ed22c90d7e710e35ad0a',
AVAX: '0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7',
Expand Down
57 changes: 50 additions & 7 deletions src/dataProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import GlpManager from '../abis/GlpManager.json'
import Token from '../abis/v1/Token.json'

const providers = {
harmony: new JsonRpcProvider('https://api.harmony.one'),
arbitrum: new JsonRpcProvider('https://arb1.arbitrum.io/rpc'),
avalanche: new JsonRpcProvider('https://api.avax.network/ext/bc/C/rpc')
}
Expand Down Expand Up @@ -139,6 +140,11 @@ export const tokenDecimals = {
"0xfea7a6a0b346362bf88a9e4a88416b77a57d6c2a": 18, // MIM
"0x17fc002b466eec40dae837fc4be5c67993ddbd6f": 18, // FRAX
"0xda10009cbd5d07dd0cecc66161fc93d7c9000da1": 18, // DAI

// Harmony
"0x1Aa1F7815103c0700b98f24138581b88d4cf9769": 18, // BUSD
"0x218532a12a389a4a92fC0C5Fb22901D1c19198aA": 18, // LINK
"0xcF664087a5bB0237a0BAd6742852ec6c8d69A27a": 18, // WONE
}

export const tokenSymbols = {
Expand All @@ -154,6 +160,11 @@ export const tokenSymbols = {
'0x17fc002b466eec40dae837fc4be5c67993ddbd6f': 'FRAX',
'0xda10009cbd5d07dd0cecc66161fc93d7c9000da1': 'DAI',

// Harmony
"0x1Aa1F7815103c0700b98f24138581b88d4cf9769": 'BUSD',
"0x218532a12a389a4a92fC0C5Fb22901D1c19198aA": 'LINK',
"0xcF664087a5bB0237a0BAd6742852ec6c8d69A27a": 'WONE',

// Avalanche
'0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7': 'AVAX',
'0x49d5c2bdffac6ce2bfdb6640f4f80f226bc10bab': 'WETH.e',
Expand Down Expand Up @@ -194,6 +205,17 @@ const knownSwapSources = {
'0xc30141b657f4216252dc59af2e7cdb9d8792e1b0': 'socket.tech',
'0xdd94018f54e565dbfc939f7c44a16e163faab331': 'Odos Router'
},
harmony: {
'0x5D76ed731bC8Fb6eC50a0d4Bd39dA00A679E5a66': 'GMX Router', // Router
'0x45440437e3f8dF7B4b99f0CdCA6E14B46765d791': 'GMX OrderBook', // Orderbook
'0x98a00666cfcb2ba5a405415c2bf6547c63bf5491': 'GMX PositionManager A', // PositionManager old
'0x2500Fe3bb03B2B514b0BBF6d1Bd88A84298bBBee': 'GMX PositionManager B', // PositionManager
'0x75e42e6f01baf1d6022bea862a28774a9f8a4a0c': 'GMX PositionManager C', // PositionManager 12 oct 2022
'0x7119B1F55a949e4D5981c2C9d5dABd897f0feDfA': 'GMX PositionRouter C', // PositionRouter 12 oct 2022
'0xfa812ed63558f886d2F3Ac89984dfAe87E0D37f6': 'GMX OrderExecutor', // OrderExecutor
'0x820B9C96ac9afE46b4AfD8912A986f180e40df6b': 'GMX FastPriceFeed A', // FastPriceFeed
'0x1EE4a17871Aa61eF02B846795b7554aE7EAbb179': 'GMX PositionExecutor', // Position Executor
},
avalanche: {
'0x4296e307f108b2f583ff2f7b7270ee7831574ae5': 'GMX OrderBook',
'0x5f719c2f1095f7b9fc68a68e35b51194f4b6abe8': 'GMX Router',
Expand Down Expand Up @@ -277,21 +299,34 @@ function getImpermanentLoss(change) {
}

function getChainSubgraph(chainName) {
if(chainName === "harmony" ) {
return "gmx-h-stats"
}

return chainName === "arbitrum" ? "gmx-arbitrum-stats" : "gmx-avalanche-stats"
}

const SATSUMA_KEY = process.env.SATSUMA_KEY || ""; // "default" key

export function useGraph(querySource, { subgraph = null, subgraphUrl = null, chainName = "arbitrum" } = {}) {
const query = gql(querySource)

if (!subgraphUrl) {
if (!subgraph) {
subgraph = getChainSubgraph(chainName)
}
subgraphUrl = `https://subgraph.satsuma-prod.com/3b2ced13c8d9/gmx/${subgraph}/api`;

subgraphUrl = `https://api.studio.thegraph.com/query/${SATSUMA_KEY}/gmx-h-stats/v0.0.8`;
}

subgraphUrl = `https://api.studio.thegraph.com/query/${SATSUMA_KEY}/gmx-h-stats/v0.0.8`;

const client = new ApolloClient({
link: new HttpLink({ uri: subgraphUrl, fetch }),
link: new HttpLink({
uri: subgraphUrl,
credentials: 'same-origin',
fetch
}),
cache: new InMemoryCache()
})
const [data, setData] = useState()
Expand Down Expand Up @@ -426,8 +461,16 @@ export function useTradersData({ from = FIRST_DATE_TS, to = NOW_TS, chainName =
}
}) : null

if (data) {
const maxProfit = maxBy(data, item => item.profit).profit
if (data && data.length) {
let maxProfit;

try {
maxProfit = maxBy(data, item => item.profit).profit
} catch (e) {
console.error(e);
maxProfit = 0;
}

const maxLoss = minBy(data, item => item.loss).loss
const maxProfitLoss = Math.max(maxProfit, -maxLoss)

Expand Down Expand Up @@ -776,9 +819,9 @@ export function useFundingRateData({ from = FIRST_DATE_TS, to = NOW_TS, chainNam
const MOVING_AVERAGE_DAYS = 7
const MOVING_AVERAGE_PERIOD = 86400 * MOVING_AVERAGE_DAYS

export function useVolumeData({ from = FIRST_DATE_TS, to = NOW_TS, chainName = "arbitrum" } = {}) {
export function useVolumeData({ from = FIRST_DATE_TS, to = NOW_TS, chainName = "harmony" } = {}) {
const PROPS = 'margin liquidation swap mint burn'.split(' ')
const timestampProp = chainName === "arbitrum" ? "id" : "timestamp"
const timestampProp = chainName === "harmony" ? "id" : "timestamp"
const query = `{
volumeStats(
first: 1000,
Expand Down Expand Up @@ -1060,7 +1103,7 @@ export function useGlpPerformanceData(glpData, feesData, { from = FIRST_DATE_TS,
const feesDataById = feesData.reduce((memo, item) => {
memo[item.timestamp] = item
return memo
})
}, {})

let BTC_WEIGHT = 0
let ETH_WEIGHT = 0
Expand Down
26 changes: 21 additions & 5 deletions src/graph.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fetch from 'cross-fetch';
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client'

import { ARBITRUM, AVALANCHE } from './addresses'
import { ARBITRUM, AVALANCHE, HARMONY } from './addresses'

const apolloOptions = {
query: {
Expand All @@ -12,12 +12,18 @@ const apolloOptions = {
}
}

const SATSUMA_KEY = process.env.SATSUMA_KEY || "3b2ced13c8d9"; // "default" key
const SATSUMA_KEY = process.env.SATSUMA_KEY || ""; // "default" key

function getSubgraphUrl(name) {
return `https://subgraph.satsuma-prod.com/${SATSUMA_KEY}/gmx/${name}/api`
return `https://api.studio.thegraph.com/query/${SATSUMA_KEY}/${name}/version/latest`
}

const harmonyStatsClient = new ApolloClient({
link: new HttpLink({ uri: getSubgraphUrl("gmx-h-stats"), fetch }),
cache: new InMemoryCache(),
defaultOptions: apolloOptions
})

const arbitrumStatsClient = new ApolloClient({
link: new HttpLink({ uri: getSubgraphUrl("gmx-arbitrum-stats"), fetch }),
cache: new InMemoryCache(),
Expand All @@ -31,14 +37,22 @@ const avalancheStatsClient = new ApolloClient({
})

function getStatsClient(chainId) {
if (chainId === ARBITRUM) {
if (chainId === HARMONY) {
return harmonyStatsClient
} else if (chainId === ARBITRUM) {
return arbitrumStatsClient
} else if (chainId === AVALANCHE) {
return avalancheStatsClient
}
throw new Error(`Invalid chainId ${chainId}`)
}

const harmonyPricesClient = new ApolloClient({
link: new HttpLink({ uri: getSubgraphUrl("gmx-h-prices"), fetch }),
cache: new InMemoryCache(),
defaultOptions: apolloOptions
})

const arbitrumPricesClient = new ApolloClient({
link: new HttpLink({ uri: getSubgraphUrl("gmx-arbitrum-prices"), fetch }),
cache: new InMemoryCache(),
Expand All @@ -52,7 +66,9 @@ const avalanchePricesClient = new ApolloClient({
})

function getPricesClient(chainId) {
if (chainId === ARBITRUM) {
if (chainId === HARMONY) {
return harmonyPricesClient
} else if (chainId === ARBITRUM) {
return arbitrumPricesClient
} else if (chainId === AVALANCHE) {
return avalanchePricesClient
Expand Down
4 changes: 3 additions & 1 deletion src/middlewares.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export function csp(req, res, next) {
"https://api.avax.network",
"https://gmx-server-mainnet.uw.r.appspot.com",
"https://api.coingecko.com",
"https://subgraph.satsuma-prod.com"
"https://subgraph.satsuma-prod.com",
"https://api.studio.thegraph.com",
"https://api.harmony.one",
]
}
if (!IS_PRODUCTION) {
Expand Down
Loading