Display live statistics from on-chain program
This commit is contained in:
parent
ed3aaf0240
commit
63c807a35b
|
@ -0,0 +1,24 @@
|
|||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
margin: 5px;
|
||||
padding: 20px;
|
||||
background-color: #141026;
|
||||
border: 1px solid #584f81;
|
||||
border-radius: 9px;
|
||||
`;
|
||||
|
||||
export default function FloatingElement({ children, style = undefined, stretchVertical = false }) {
|
||||
return (
|
||||
<Wrapper
|
||||
style={{
|
||||
height: stretchVertical ? 'calc(100% - 10px)' : undefined,
|
||||
...style,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
import { Col, Row, Divider } from 'antd';
|
||||
import { useEffect, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { IDS, MangoClient } from '@blockworks-foundation/mango-client';
|
||||
import { PublicKey, Connection } from '@solana/web3.js';
|
||||
|
||||
import FloatingElement from './FloatingElement';
|
||||
|
||||
const CLUSTER = 'mainnet-beta';
|
||||
const DEFAULT_MANGO_GROUP = 'BTC_ETH_USDT';
|
||||
|
||||
const icons = {
|
||||
BTC: '/tokens/btc.svg',
|
||||
ETH: '/tokens/eth.svg',
|
||||
USDT:'/tokens/usdt.svg'};
|
||||
|
||||
const stubStats = {
|
||||
depositInterest: 0,
|
||||
borrowInterest: 0,
|
||||
totalDeposits: 0,
|
||||
totalBorrows: 0,
|
||||
utilization: '0',
|
||||
};
|
||||
|
||||
|
||||
const useMangoStats = () => {
|
||||
|
||||
const [stats, setStats] = useState(Object.keys(icons).
|
||||
map(s => ({symbol: s, ...stubStats})));
|
||||
|
||||
useEffect(() => {
|
||||
const getStats = async () => {
|
||||
const client = new MangoClient();
|
||||
const connection = new Connection(IDS.cluster_urls[CLUSTER], 'singleGossip');
|
||||
const assets = IDS[CLUSTER].mango_groups?.[DEFAULT_MANGO_GROUP]?.symbols;
|
||||
const mangoGroupId = IDS[CLUSTER].mango_groups?.[DEFAULT_MANGO_GROUP]?.mango_group_pk;
|
||||
if (!mangoGroupId) return;
|
||||
const mangoGroupPk = new PublicKey(mangoGroupId);
|
||||
const mangoGroup = await client.getMangoGroup(connection, mangoGroupPk);
|
||||
const latestStats = Object.keys(assets).map((symbol, index) => {
|
||||
const totalDeposits = mangoGroup.getUiTotalDeposit(index);
|
||||
const totalBorrows = mangoGroup.getUiTotalBorrow(index);
|
||||
console.log('assets', symbol, index, totalDeposits, totalBorrows);
|
||||
|
||||
return {
|
||||
time: new Date(),
|
||||
symbol,
|
||||
totalDeposits,
|
||||
totalBorrows,
|
||||
depositInterest: mangoGroup.getDepositRate(index),
|
||||
borrowInterest: mangoGroup.getBorrowRate(index),
|
||||
utilization: totalDeposits > 0.0 ? totalBorrows / totalDeposits : 0.0,
|
||||
};
|
||||
});
|
||||
setStats(latestStats);
|
||||
};
|
||||
|
||||
getStats();
|
||||
}, []);
|
||||
|
||||
return { stats };
|
||||
};
|
||||
|
||||
|
||||
const Wrapper = styled.div`
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px 16px;
|
||||
.borderNone .ant-select-selector {
|
||||
border: none !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const SizeTitle = styled(Row)`
|
||||
color: #9490A6;
|
||||
`;
|
||||
|
||||
|
||||
export default function StatsPanel() {
|
||||
const { stats } = useMangoStats();
|
||||
|
||||
return (
|
||||
<Wrapper style={{ paddingTop: 10 }}>
|
||||
<Row justify="center">
|
||||
<Col lg={24} xl={18} xxl={12}>
|
||||
<FloatingElement>
|
||||
<React.Fragment>
|
||||
<Divider style={{color: "#EEEEEE" }}>Mango Stats</Divider>
|
||||
<SizeTitle>
|
||||
<Col span={4}>Asset</Col>
|
||||
<Col span={4}>Total Deposits</Col>
|
||||
<Col span={4}>Total Borrows</Col>
|
||||
<Col span={4}>Deposit Interest</Col>
|
||||
<Col span={4}>Borrow Interest</Col>
|
||||
<Col span={4}>Utilization</Col>
|
||||
</SizeTitle>
|
||||
{stats.map((stat, i) => (
|
||||
<div key={stat.symbol}>
|
||||
<Divider />
|
||||
<Row>
|
||||
<Col span={1}>
|
||||
<img src={icons[stat.symbol]} alt={stat.symbol} width="14px" />
|
||||
</Col>
|
||||
<Col span={3}>{stat.symbol}</Col>
|
||||
<Col span={4}>{stat.totalDeposits.toFixed(2-i)}</Col>
|
||||
<Col span={4}>{stat.totalBorrows.toFixed(2-i)}</Col>
|
||||
<Col span={4}>{stat.depositInterest.toFixed(2)}%</Col>
|
||||
<Col span={4}>{stat.borrowInterest.toFixed(2)}%</Col>
|
||||
<Col span={4}>{(parseFloat(stat.utilization) * 100).toFixed(2)}%</Col>
|
||||
</Row>
|
||||
</div>
|
||||
))}
|
||||
</React.Fragment>
|
||||
</FloatingElement>
|
||||
</Col>
|
||||
</Row>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
"type-check": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blockworks-foundation/mango-client": "^0.1.2",
|
||||
"@zeit/next-less": "^1.0.1",
|
||||
"antd": "^4.12.3",
|
||||
"babel-plugin-import": "^1.13.3",
|
||||
|
@ -16,7 +17,8 @@
|
|||
"next": "latest",
|
||||
"null-loader": "^4.0.1",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0"
|
||||
"react-dom": "^16.12.0",
|
||||
"styled-components": "^5.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.12.21",
|
||||
|
|
|
@ -2,6 +2,7 @@ import Head from 'next/head'
|
|||
import { Divider, Button, Layout, Space, Row, Col, Image } from 'antd';
|
||||
import Logo from '../components/Logo';
|
||||
import Navigation from '../components/Navigation';
|
||||
import StatsPanel from '../components/StatsPanel';
|
||||
|
||||
const { Header, Footer, Sider, Content } = Layout;
|
||||
|
||||
|
@ -32,8 +33,7 @@ const IndexPage = () => (
|
|||
</Col>
|
||||
<Col xs={24} lg={14}>
|
||||
<div style={{ padding: "2em" }}>
|
||||
|
||||
<img src="/previews/stats.png" />
|
||||
<StatsPanel />
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
@ -54,7 +54,7 @@ const IndexPage = () => (
|
|||
<p style={{ fontSize: 36 }}>
|
||||
Lend
|
||||
</p>
|
||||
<p style={{ width: 400 }}>
|
||||
<p>
|
||||
Earn maximal interest on deposits, protect against inflation, and utilize idle investments. Always maintain custody of your funds.
|
||||
</p>
|
||||
</div>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 36 KiB |
|
@ -0,0 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<circle cx="16" cy="16" r="16" fill="#F7931A"/>
|
||||
<path fill="#FFF" fill-rule="nonzero" d="M23.189 14.02c.314-2.096-1.283-3.223-3.465-3.975l.708-2.84-1.728-.43-.69 2.765c-.454-.114-.92-.22-1.385-.326l.695-2.783L15.596 6l-.708 2.839c-.376-.086-.746-.17-1.104-.26l.002-.009-2.384-.595-.46 1.846s1.283.294 1.256.312c.7.175.826.638.805 1.006l-.806 3.235c.048.012.11.03.18.057l-.183-.045-1.13 4.532c-.086.212-.303.531-.793.41.018.025-1.256-.313-1.256-.313l-.858 1.978 2.25.561c.418.105.828.215 1.231.318l-.715 2.872 1.727.43.708-2.84c.472.127.93.245 1.378.357l-.706 2.828 1.728.43.715-2.866c2.948.558 5.164.333 6.097-2.333.752-2.146-.037-3.385-1.588-4.192 1.13-.26 1.98-1.003 2.207-2.538zm-3.95 5.538c-.533 2.147-4.148.986-5.32.695l.95-3.805c1.172.293 4.929.872 4.37 3.11zm.535-5.569c-.487 1.953-3.495.96-4.47.717l.86-3.45c.975.243 4.118.696 3.61 2.733z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 973 B |
|
@ -0,0 +1,13 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<circle cx="16" cy="16" r="16" fill="#627EEA"/>
|
||||
<g fill="#FFF" fill-rule="nonzero">
|
||||
<path fill-opacity=".602" d="M16.498 4v8.87l7.497 3.35z"/>
|
||||
<path d="M16.498 4L9 16.22l7.498-3.35z"/>
|
||||
<path fill-opacity=".602" d="M16.498 21.968v6.027L24 17.616z"/>
|
||||
<path d="M16.498 27.995v-6.028L9 17.616z"/>
|
||||
<path fill-opacity=".2" d="M16.498 20.573l7.497-4.353-7.497-3.348z"/>
|
||||
<path fill-opacity=".602" d="M9 16.22l7.498 4.353v-7.701z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 592 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><g fill="none" fill-rule="evenodd"><circle cx="16" cy="16" r="16" fill="#26A17B"/><path fill="#FFF" d="M17.922 17.383v-.002c-.11.008-.677.042-1.942.042-1.01 0-1.721-.03-1.971-.042v.003c-3.888-.171-6.79-.848-6.79-1.658 0-.809 2.902-1.486 6.79-1.66v2.644c.254.018.982.061 1.988.061 1.207 0 1.812-.05 1.925-.06v-2.643c3.88.173 6.775.85 6.775 1.658 0 .81-2.895 1.485-6.775 1.657m0-3.59v-2.366h5.414V7.819H8.595v3.608h5.414v2.365c-4.4.202-7.709 1.074-7.709 2.118 0 1.044 3.309 1.915 7.709 2.118v7.582h3.913v-7.584c4.393-.202 7.694-1.073 7.694-2.116 0-1.043-3.301-1.914-7.694-2.117"/></g></svg>
|
After Width: | Height: | Size: 651 B |
|
@ -6,8 +6,8 @@
|
|||
@error-color: #E54033;
|
||||
@text-color: #EEEEEE;
|
||||
@text-color-secondary: #9490A6;
|
||||
@border-color-base: #F0EDFF;
|
||||
@divider-color: #F0EDFF;
|
||||
@border-color-base: #584f81;
|
||||
@divider-color: #584f81;
|
||||
@btn-primary-color: #141026;
|
||||
@body-background: #141026;
|
||||
@component-background: #141026;
|
||||
|
|
Loading…
Reference in New Issue