From e35255a8c55fbd9a39089758801a598346287814 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Wed, 26 May 2021 16:55:28 -0400 Subject: [PATCH 01/32] updated manage pool page --- README.md | 17 +++++ config/config.ts | 14 ++++- package.json | 2 +- src/locales/en-US/menu.ts | 2 + src/pages/joinPool/index.tsx | 20 ++++++ src/pages/managePool/index.tsx | 111 +++++++++++++++++++++++++++++++++ src/pages/sysConf/index.tsx | 2 +- 7 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 src/pages/joinPool/index.tsx create mode 100644 src/pages/managePool/index.tsx diff --git a/README.md b/README.md index 8319617..4b35644 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,20 @@ Please Visit [Mining-Bot Documentation](https://daemon-technologies.github.io/do - [WSL Tutorial Video](https://www.youtube.com/watch?v=FXifFx0Akzc) - [MacOS](https://www.youtube.com/watch?v=TCtCTttsSeI) + + +## Pooling + +### Manage Pool + +On this page, you can manage a stacks mining pool. You should be able to: +- Define the btc address you want to pool on. Other people will send their btc to this address. +- See who has contributed to your pool. +- See how much time left in the "cycle". + +### Join Pool + +On this page, you can see the mining pool you joined. You should be able to: +- enter a bitcoin address to join their pool +- you can also specify how many bitcoin you want to send every "cycle" +- see how much remaining time for this "cycle" \ No newline at end of file diff --git a/config/config.ts b/config/config.ts index fc57d22..78ae47f 100644 --- a/config/config.ts +++ b/config/config.ts @@ -53,7 +53,7 @@ export default defineConfig({ { path: '/wallet', name: 'wallet', - icon: 'TeamOutlined', + icon: 'WalletOutlined', component: './wallet', }, { @@ -68,6 +68,18 @@ export default defineConfig({ icon: 'UnorderedListOutlined', component: './sysConf', }, + { + path: '/managePool', + name: 'managePool', + icon: 'TeamOutlined', + component: './managePool' + }, + { + path: '/joinPool', + name: 'joinPool', + icon: 'UserAddOutlined', + component: './joinPool' + }, { path: '/', redirect: `/publicData`, diff --git a/package.json b/package.json index 5d32cca..c867593 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "jsdom-global": "^3.0.2", "lint-staged": "^10.0.0", "mockjs": "^1.0.1-beta3", - "prettier": "^2.0.1", + "prettier": "2.3.0", "pro-download": "1.0.1", "puppeteer-core": "^5.0.0", "stylelint": "^13.0.0" diff --git a/src/locales/en-US/menu.ts b/src/locales/en-US/menu.ts index dbf113f..f4d2895 100644 --- a/src/locales/en-US/menu.ts +++ b/src/locales/en-US/menu.ts @@ -3,6 +3,8 @@ export default { 'menu.wallet': 'Wallet', 'menu.client': 'Mining Client', 'menu.sysConf': 'System Configuration', + 'menu.managePool': 'Manage Pool', + 'menu.joinPool': 'Join Pool', 'menu.welcome': 'Welcome', 'menu.more-blocks': 'More Blocks', diff --git a/src/pages/joinPool/index.tsx b/src/pages/joinPool/index.tsx new file mode 100644 index 0000000..1bf4b61 --- /dev/null +++ b/src/pages/joinPool/index.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { PageContainer } from '@ant-design/pro-layout'; +import { ConfigProvider } from 'antd'; + +import { switchConfigProviderLocale } from '@/services/locale'; + +const TableList: React.FC<{}> = () => { + + return ( + + +
joinPool
+
+
+ ); +}; + +export default TableList; diff --git a/src/pages/managePool/index.tsx b/src/pages/managePool/index.tsx new file mode 100644 index 0000000..9d87864 --- /dev/null +++ b/src/pages/managePool/index.tsx @@ -0,0 +1,111 @@ +import React, { useEffect, useState } from "react"; +import { PageContainer } from "@ant-design/pro-layout"; +import { + Button, + Card, + ConfigProvider, + Divider, + Form, + Input, + Select, + Switch, +} from "antd"; + +import { queryAccount } from "@/services/wallet/account"; +import { Account } from "@/services/wallet/data"; +import { showMessage, switchConfigProviderLocale } from "@/services/locale"; +import FormItem from "antd/lib/form/FormItem"; +import { FormattedMessage } from "react-intl"; + +export interface FormValueType { + poolBtcAddress: string; +} + +const TableList: React.FC<{}> = () => { + const { Option } = Select; + const [formVals, setFormVals] = useState({ + poolBtcAddress: localStorage.getItem("pooledBtcAddress") ?? "", + }); + + const [accounts, setAccounts] = useState([]); + const [loadingAccounts, setLoadingAccounts] = useState(true); + + const onSubmit = async () => { + const fieldsValue: FormValueType = await form.validateFields(); + setFormVals({ ...formVals, ...fieldsValue }); + localStorage.setItem("pooledBtcAddress", fieldsValue.poolBtcAddress); + }; + + const [isPooling, setIsPooling] = useState(false); + + useEffect(() => { + queryAccount(1).then(({ data }) => { + setAccounts(data); + setLoadingAccounts(false); + }); + }, []); + + const renderForm = () => { + return ( + <> + +
+ + + {/* */} + + + + +
+ + ); + }; + + const [form] = Form.useForm(); + return ( + + + + setIsPooling(!isPooling)} /> + {isPooling + ? showMessage("TODO", "Pooling is On") + : showMessage("TODO", "Pooling is Off")} + {isPooling && renderForm()} + + + + ); +}; + +export default TableList; diff --git a/src/pages/sysConf/index.tsx b/src/pages/sysConf/index.tsx index dad2487..f3ccfc9 100644 --- a/src/pages/sysConf/index.tsx +++ b/src/pages/sysConf/index.tsx @@ -187,7 +187,7 @@ const TableList: React.FC<{}> = () => { > {showMessage('这将清空你所有的账户信息,请慎重!' - , 'Attention plaese! This operation will clear all your account info.')} + , 'Attention please! This operation will clear all your account info.')} From 972fe272597348d90d8b005cd6a25e854437cadf Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Wed, 26 May 2021 16:58:48 -0400 Subject: [PATCH 02/32] update manage pool switch --- src/pages/managePool/index.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/pages/managePool/index.tsx b/src/pages/managePool/index.tsx index 9d87864..6c8038e 100644 --- a/src/pages/managePool/index.tsx +++ b/src/pages/managePool/index.tsx @@ -36,7 +36,9 @@ const TableList: React.FC<{}> = () => { localStorage.setItem("pooledBtcAddress", fieldsValue.poolBtcAddress); }; - const [isPooling, setIsPooling] = useState(false); + const [isPooling, setIsPooling] = useState( + localStorage.getItem("isPooling") === "true" ?? false + ); useEffect(() => { queryAccount(1).then(({ data }) => { @@ -97,7 +99,14 @@ const TableList: React.FC<{}> = () => { - setIsPooling(!isPooling)} /> + { + setIsPooling(!isPooling); + localStorage.setItem("isPooling", (!isPooling).toString()); + }} + /> {isPooling ? showMessage("TODO", "Pooling is On") : showMessage("TODO", "Pooling is Off")} From 9ac1386bee4854464934b7b20bda4c10e4ee5705 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Sun, 30 May 2021 21:13:45 -0400 Subject: [PATCH 03/32] add utility functions for bitcoin --- src/pages/joinPool/index.tsx | 41 +++++++-- src/pages/managePool/index.tsx | 77 +++++++++-------- src/services/constants.ts | 3 + src/services/managePool/data.d.ts | 21 +++++ src/services/managePool/managePool.ts | 118 ++++++++++++++++++++++++++ src/services/sysConf/conf.ts | 1 + src/services/wallet/account.ts | 4 +- 7 files changed, 216 insertions(+), 49 deletions(-) create mode 100644 src/services/managePool/data.d.ts create mode 100644 src/services/managePool/managePool.ts diff --git a/src/pages/joinPool/index.tsx b/src/pages/joinPool/index.tsx index 1bf4b61..a03fe23 100644 --- a/src/pages/joinPool/index.tsx +++ b/src/pages/joinPool/index.tsx @@ -1,19 +1,42 @@ -import React from 'react'; -import { PageContainer } from '@ant-design/pro-layout'; -import { ConfigProvider } from 'antd'; +import React, { useEffect, useState } from "react"; +import { PageContainer } from "@ant-design/pro-layout"; +import { ConfigProvider } from "antd"; -import { switchConfigProviderLocale } from '@/services/locale'; +import { switchConfigProviderLocale } from "@/services/locale"; +import { + getCurrentCycle, + getCycleBlocks, + getPoolContributors, +} from "@/services/managePool/managePool"; const TableList: React.FC<{}> = () => { + const [currentCycle, setCurrentCycle] = useState(-1); + useEffect(() => { + getCurrentCycle().then(({ cycle }) => { + if (cycle) { + setCurrentCycle(cycle!); + } + }); + }, []); + useEffect(() => { + getPoolContributors(currentCycle).then((transactions) => { + if (transactions) { + console.log(transactions); + } + }); + }, [currentCycle]); return ( - -
joinPool
+ +
joinPool
+
Cycle #{currentCycle}
+
+ From block {getCycleBlocks(currentCycle).startBlock} to + {getCycleBlocks(currentCycle).endBlock} +
-
+
); }; diff --git a/src/pages/managePool/index.tsx b/src/pages/managePool/index.tsx index 6c8038e..27ac57e 100644 --- a/src/pages/managePool/index.tsx +++ b/src/pages/managePool/index.tsx @@ -51,45 +51,44 @@ const TableList: React.FC<{}> = () => { return ( <> -
- + - - {/* */} - - - - -
+ + + + + + + + ); }; @@ -110,8 +109,8 @@ const TableList: React.FC<{}> = () => { {isPooling ? showMessage("TODO", "Pooling is On") : showMessage("TODO", "Pooling is Off")} - {isPooling && renderForm()} + {isPooling && renderForm()} ); diff --git a/src/services/constants.ts b/src/services/constants.ts index e8453fc..4cb6f34 100644 --- a/src/services/constants.ts +++ b/src/services/constants.ts @@ -46,4 +46,7 @@ module.exports = { // address type btcType: 1, stxType: 2, + + // pooling + firstStackingBlock: 668050 } diff --git a/src/services/managePool/data.d.ts b/src/services/managePool/data.d.ts new file mode 100644 index 0000000..01ced61 --- /dev/null +++ b/src/services/managePool/data.d.ts @@ -0,0 +1,21 @@ +// https://www.blockcypher.com/dev/bitcoin/#txref +export interface TXRef { + address?: string; + block_height: number; + tx_hash: string; + tx_input_n: number; + tx_output_n: number; + value: number; + prference: string; + spent: boolean; + double_spend: boolean; + confirmations: boolean; + script?: string; + ref_balance?: number; + confidence?: number; + confirmed?: time; + spent_by?: string; + received?: time; + receive_count?: number; + double_of?: string; +} diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts new file mode 100644 index 0000000..3741a3b --- /dev/null +++ b/src/services/managePool/managePool.ts @@ -0,0 +1,118 @@ +import { getNetworkFromStorage } from "@/utils/utils"; +import request from "umi-request"; +import { TXRef } from "./data"; + +const { + sidecarURLXenon, + sidecarURLMainnet, + bitcoinTestnet3, + bitcoinMainnet, + firstStackingBlock, +} = require("@/services/constants"); + +export async function getCurrentCycle() { + let baseURL = sidecarURLXenon; + + switch (getNetworkFromStorage()) { + case "Xenon": { + baseURL = bitcoinTestnet3; + return request(`${baseURL}`, { method: "GET", timeout: 6000 }) + .then((resp) => { + let height: number = resp.height; + return { cycle: Math.ceil((height - firstStackingBlock) / 2100) }; + }) + .catch((err) => { + console.log(err); + return { cycle: null }; + }); + } + case "Mainnet": { + baseURL = "https://api.blockcypher.com/v1/btc/main"; + return request(`${baseURL}`, { + method: "GET", + timeout: 6000, + }) + .then((resp) => { + console.log(resp); + let height: number = resp.height; + return { cycle: Math.ceil((height - firstStackingBlock) / 2100) }; + }) + .catch((err) => { + console.log(err); + return { cycle: null }; + }); + } + default: + break; + } + return { cycle: null }; +} + +export function getCycleBlocks(cycle: number) { + return { + startBlock: firstStackingBlock + (cycle - 1) * 2100, + endBlock: firstStackingBlock + cycle * 2100, + }; +} + +export function getPoolContributors(cycle: number) { + if ( + localStorage.getItem("isPooling") !== "true" || + !localStorage.getItem("pooledBtcAddress") + ) { + return new Promise((resolve, reject) => { + reject("Pooling must be on and a pooled btc address must be specified"); + }); + } + + let baseURL = sidecarURLXenon; + let balanceCoef = 1; + + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress"); + + const { startBlock, endBlock } = getCycleBlocks(cycle); + + switch (getNetworkFromStorage()) { + case "Xenon": { + //TODO: remember to add before and after + // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}&limit=2000`; + baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?limit=2000`; + console.log(baseURL); + balanceCoef = 100000000; + return request(`${baseURL}`, { method: "GET", timeout: 6000 }) + .then((resp) => { + if (resp.txrefs) { + let transactions: TXRef[] = resp.txrefs; + console.log(transactions); + return { transactions: transactions }; + } + return { transactions: null }; + }) + .catch((err) => { + console.log(err); + return {}; + }); + break; + } + case "Mainnet": { + baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}`; + balanceCoef = 100000000; + return request(`${baseURL}`, { method: "GET", timeout: 6000 }) + .then((resp) => { + let transactions: TXRef[] = resp.txrefs; + console.log(transactions); + return { transactions: transactions }; + }) + .catch((err) => { + console.log(err); + return {}; + }); + break; + } + default: + break; + } + return new Promise((resolve, reject) => { + resolve({ transactions: null }); + }); +} diff --git a/src/services/sysConf/conf.ts b/src/services/sysConf/conf.ts index 73afc56..44dc707 100644 --- a/src/services/sysConf/conf.ts +++ b/src/services/sysConf/conf.ts @@ -115,6 +115,7 @@ export async function getNodeInfo() { } export function resetLockPassword() { + //TODO: reset pooling stuff localStorage.removeItem(MiningPasswordAuthorization); localStorage.removeItem('BTC'); localStorage.removeItem('STX'); diff --git a/src/services/wallet/account.ts b/src/services/wallet/account.ts index 5901490..7ca3119 100644 --- a/src/services/wallet/account.ts +++ b/src/services/wallet/account.ts @@ -86,7 +86,9 @@ export async function getBtcBalance(btcAddress: string) { return { 'balance': 'NaN' }; }); } - default: break; + default: { + return {'balance': 'NaN'} + }; } From 90e25782809949d43b24151b1e5dc839bd270d1f Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Thu, 10 Jun 2021 16:40:58 -0400 Subject: [PATCH 04/32] added pool contributer table --- src/pages/joinPool/index.tsx | 2 +- .../component/PoolContributerTable.tsx | 41 +++++++++++++++++++ src/pages/managePool/index.tsx | 4 +- .../managePool/models/poolContributerInfo.ts | 25 +++++++++++ src/pages/publicData/locales/en-US.ts | 5 ++- src/pages/publicData/locales/zh-CN.ts | 5 ++- src/services/managePool/data.d.ts | 7 ++++ src/services/managePool/managePool.ts | 27 ++++++------ 8 files changed, 96 insertions(+), 20 deletions(-) create mode 100644 src/pages/managePool/component/PoolContributerTable.tsx create mode 100644 src/pages/managePool/models/poolContributerInfo.ts diff --git a/src/pages/joinPool/index.tsx b/src/pages/joinPool/index.tsx index a03fe23..51ff524 100644 --- a/src/pages/joinPool/index.tsx +++ b/src/pages/joinPool/index.tsx @@ -32,7 +32,7 @@ const TableList: React.FC<{}> = () => {
joinPool
Cycle #{currentCycle}
- From block {getCycleBlocks(currentCycle).startBlock} to + From block {getCycleBlocks(currentCycle).startBlock} to {getCycleBlocks(currentCycle).endBlock}
diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx new file mode 100644 index 0000000..a95d9b7 --- /dev/null +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -0,0 +1,41 @@ +import React from "react"; +import ProTable, { ProColumns } from "@ant-design/pro-table"; +import { FormattedMessage, useModel } from "umi"; +import { BlockInfo, TxInfo } from "@/services/publicdata/data"; +import { Tag } from "antd"; +import { getBlockInfo, getTxsInfo } from "@/services/publicdata/chainInfo"; +import { PoolContributerInfo } from "@/services/managePool/data"; + +const PoolContributerTable: React.FC<{}> = () => { + const { queryPoolContributerInfo } = useModel( + "managePool.poolContributerInfo" + ); + const poolContributerColumns: ProColumns[] = [ + { + title: , + dataIndex: "address", + }, + { + title: ( + + ), + dataIndex: "contribution", + }, + ]; + + return ( + + headerTitle={ + + } + columns={poolContributerColumns} + //TODO: finish rest of this table like request and rowkey + request={() => queryPoolContributerInfo()} + /> + ); +}; + +export default PoolContributerTable; diff --git a/src/pages/managePool/index.tsx b/src/pages/managePool/index.tsx index 27ac57e..5d1f7c0 100644 --- a/src/pages/managePool/index.tsx +++ b/src/pages/managePool/index.tsx @@ -16,7 +16,7 @@ import { Account } from "@/services/wallet/data"; import { showMessage, switchConfigProviderLocale } from "@/services/locale"; import FormItem from "antd/lib/form/FormItem"; import { FormattedMessage } from "react-intl"; - +import PoolContributerTable from "./component/PoolContributerTable"; export interface FormValueType { poolBtcAddress: string; } @@ -111,6 +111,8 @@ const TableList: React.FC<{}> = () => { : showMessage("TODO", "Pooling is Off")} {isPooling && renderForm()} + {isPooling && } + {isPooling && } ); diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts new file mode 100644 index 0000000..fbc86b5 --- /dev/null +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -0,0 +1,25 @@ +import { PoolContributerInfo } from "@/services/managePool/data"; +import { + getCurrentCycle, + getPoolContributors, +} from "@/services/managePool/managePool"; +import { useState } from "react"; +export interface PoolContributerInfoState { + poolContributerInfoList: PoolContributerInfo[]; +} +export default () => { + let [poolContributerInfoState, setPoolcontributerInfoState] = + useState(); + const queryPoolContributerInfo = async () => { + const { cycle } = await getCurrentCycle(); + const poolContributers = await getPoolContributors(cycle); + if (poolContributers.transactions) { + console.log(poolContributers); + } + }; + + return { + poolContributerInfoState, + queryPoolContributerInfo, + }; +}; diff --git a/src/pages/publicData/locales/en-US.ts b/src/pages/publicData/locales/en-US.ts index 35aaa92..f1e2f5e 100644 --- a/src/pages/publicData/locales/en-US.ts +++ b/src/pages/publicData/locales/en-US.ts @@ -18,6 +18,7 @@ export default { 'block.info.status.pending': 'Pending', 'block.info.feeRate': 'Fee Rate', 'block.info.txType': 'TX Type', - - + 'pool.address': "Address", + 'pool.contribution': "Contribution", + 'pool.title': "Pool Contributors" }; \ No newline at end of file diff --git a/src/pages/publicData/locales/zh-CN.ts b/src/pages/publicData/locales/zh-CN.ts index bb8327b..465f58a 100644 --- a/src/pages/publicData/locales/zh-CN.ts +++ b/src/pages/publicData/locales/zh-CN.ts @@ -18,7 +18,10 @@ export default { 'block.info.status.pending': '待处理', 'block.info.feeRate': '交易费率', 'block.info.txType': '交易类型', - + // TODO + 'pool.address': "", + 'pool.contribution': "", + 'pool.title': "" }; \ No newline at end of file diff --git a/src/services/managePool/data.d.ts b/src/services/managePool/data.d.ts index 01ced61..6c7927b 100644 --- a/src/services/managePool/data.d.ts +++ b/src/services/managePool/data.d.ts @@ -19,3 +19,10 @@ export interface TXRef { receive_count?: number; double_of?: string; } + +export interface PoolContributerInfo { + address: string; + contribution: number; + lastCycleContribution?: number; + lastBlockContribution?: number; +} \ No newline at end of file diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 3741a3b..4da259c 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -23,7 +23,7 @@ export async function getCurrentCycle() { }) .catch((err) => { console.log(err); - return { cycle: null }; + return { cycle: -1 }; }); } case "Mainnet": { @@ -39,13 +39,13 @@ export async function getCurrentCycle() { }) .catch((err) => { console.log(err); - return { cycle: null }; + return { cycle: -1 }; }); } default: break; } - return { cycle: null }; + return { cycle: -1 }; } export function getCycleBlocks(cycle: number) { @@ -55,14 +55,13 @@ export function getCycleBlocks(cycle: number) { }; } -export function getPoolContributors(cycle: number) { +export async function getPoolContributors(cycle: number) { if ( localStorage.getItem("isPooling") !== "true" || - !localStorage.getItem("pooledBtcAddress") + !localStorage.getItem("pooledBtcAddress") || + cycle < 0 ) { - return new Promise((resolve, reject) => { - reject("Pooling must be on and a pooled btc address must be specified"); - }); + return {}; } let baseURL = sidecarURLXenon; @@ -79,7 +78,7 @@ export function getPoolContributors(cycle: number) { baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?limit=2000`; console.log(baseURL); balanceCoef = 100000000; - return request(`${baseURL}`, { method: "GET", timeout: 6000 }) + await request(`${baseURL}`, { method: "GET", timeout: 6000 }) .then((resp) => { if (resp.txrefs) { let transactions: TXRef[] = resp.txrefs; @@ -90,14 +89,14 @@ export function getPoolContributors(cycle: number) { }) .catch((err) => { console.log(err); - return {}; + return { transactions: null }; }); break; } case "Mainnet": { baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}`; balanceCoef = 100000000; - return request(`${baseURL}`, { method: "GET", timeout: 6000 }) + await request(`${baseURL}`, { method: "GET", timeout: 6000 }) .then((resp) => { let transactions: TXRef[] = resp.txrefs; console.log(transactions); @@ -105,14 +104,12 @@ export function getPoolContributors(cycle: number) { }) .catch((err) => { console.log(err); - return {}; + return { transactions: null }; }); break; } default: break; } - return new Promise((resolve, reject) => { - resolve({ transactions: null }); - }); + return { transactions: null }; } From 7ba755078d3ee2d8730e362e35460c4419e70a68 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Sun, 13 Jun 2021 00:35:40 -0400 Subject: [PATCH 05/32] working on api call --- .../component/PoolContributerTable.tsx | 1 + .../managePool/models/poolContributerInfo.ts | 24 ++++-- src/services/constants.ts | 4 +- src/services/managePool/data.d.ts | 73 ++++++++++++++++++- src/services/managePool/managePool.ts | 52 +++---------- src/utils/utils.ts | 5 ++ 6 files changed, 112 insertions(+), 47 deletions(-) diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index a95d9b7..cf16013 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -34,6 +34,7 @@ const PoolContributerTable: React.FC<{}> = () => { columns={poolContributerColumns} //TODO: finish rest of this table like request and rowkey request={() => queryPoolContributerInfo()} + rowKey={"address"} /> ); }; diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index fbc86b5..085e487 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -8,14 +8,28 @@ export interface PoolContributerInfoState { poolContributerInfoList: PoolContributerInfo[]; } export default () => { - let [poolContributerInfoState, setPoolcontributerInfoState] = + let [poolContributerInfoState, setPoolContributerInfoState] = useState(); const queryPoolContributerInfo = async () => { const { cycle } = await getCurrentCycle(); - const poolContributers = await getPoolContributors(cycle); - if (poolContributers.transactions) { - console.log(poolContributers); - } + // console.log(cycle); + const transactions = await getPoolContributors(cycle); + // console.log(JSON.stringify(transactions)); + // const inputs = transactions.filter((txref) => !txref.spent); + // console.log(JSON.stringify(inputs)); + + // const res: PoolContributerInfo[] = [ + // { address: "wow", contribution: 1 }, + // { address: "wee", contribution: 2 }, + // ]; + + const res = transactions.data.map((transaction) => { + const sender = ""; + const contribution = "" + // return { address: transaction.address, contribution: transaction.value }; + }); + // setPoolContributerInfoState({ poolContributerInfoList: res }); + return { data: res }; }; return { diff --git a/src/services/constants.ts b/src/services/constants.ts index 4cb6f34..3623112 100644 --- a/src/services/constants.ts +++ b/src/services/constants.ts @@ -48,5 +48,7 @@ module.exports = { stxType: 2, // pooling - firstStackingBlock: 668050 + firstStackingBlock: 668050, + + balanceCoef : 100000000 } diff --git a/src/services/managePool/data.d.ts b/src/services/managePool/data.d.ts index 6c7927b..c418ae7 100644 --- a/src/services/managePool/data.d.ts +++ b/src/services/managePool/data.d.ts @@ -20,9 +20,80 @@ export interface TXRef { double_of?: string; } +export interface TxInput { + prev_hash: string; + output_index: number; + output_value: number; + script_type: string; + script: string; + addresses: string[]; + sequence: number; + age?: number; + wallet_name?: string; + wallet_token?: string; +} + +export interface TxOutput {} + +export interface Tx { + block_height: number; + hash: string; + addresses: string[]; + total: number; + fees: number; + size: number; + vsize: number; + preference: string; + relayed_by: string; + received: string; + ver: number; + lock_time: number; + double_spend: boolean; + vin_sz: number; + vout_sz: number; + confirmations: number; + inputs: TxInput[]; + outputs: TxOutput[]; + opt_in_rbf?: boolean; + confidence?: number; + confirmed?: string; + receive_count?: number; + change_address?: string; + block_hash?: string; + block_index?: number; + double_of?: string; + data_protocol?: string; + hex?: string; + next_inputs?: string; + next_outputs?: string; +} + +export interface Wallet { + token: string; + name: string; + addresses: string[]; +} + +export interface Address { + address?: string; + wallet?: Wallet; + total_received: number; + total_sent: number; + balance: number; + unconfirmed_balance: number; + final_balance: number; + n_tx: number; + unconfirmed_n_tx: number; + final_n_tx: number; + tx_url?: string; + txrefs?: TxRef[]; + txs: Tx[]; + unconfirmed_txrefs?: Txref[]; + hasMore?: boolean; +} export interface PoolContributerInfo { address: string; contribution: number; lastCycleContribution?: number; lastBlockContribution?: number; -} \ No newline at end of file +} diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 4da259c..eb59a8b 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -1,6 +1,6 @@ import { getNetworkFromStorage } from "@/utils/utils"; import request from "umi-request"; -import { TXRef } from "./data"; +import { Address, Tx } from "./data"; const { sidecarURLXenon, @@ -55,18 +55,10 @@ export function getCycleBlocks(cycle: number) { }; } -export async function getPoolContributors(cycle: number) { - if ( - localStorage.getItem("isPooling") !== "true" || - !localStorage.getItem("pooledBtcAddress") || - cycle < 0 - ) { - return {}; - } - +export async function getPoolContributors( + cycle: number +): Promise<{ data: Tx[] }> { let baseURL = sidecarURLXenon; - let balanceCoef = 1; - let pooledBtcAddress = localStorage.getItem("pooledBtcAddress"); const { startBlock, endBlock } = getCycleBlocks(cycle); @@ -75,41 +67,21 @@ export async function getPoolContributors(cycle: number) { case "Xenon": { //TODO: remember to add before and after // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}&limit=2000`; - baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?limit=2000`; - console.log(baseURL); - balanceCoef = 100000000; - await request(`${baseURL}`, { method: "GET", timeout: 6000 }) - .then((resp) => { - if (resp.txrefs) { - let transactions: TXRef[] = resp.txrefs; - console.log(transactions); - return { transactions: transactions }; - } - return { transactions: null }; - }) - .catch((err) => { - console.log(err); - return { transactions: null }; - }); + baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=2000`; break; } case "Mainnet": { baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}`; - balanceCoef = 100000000; - await request(`${baseURL}`, { method: "GET", timeout: 6000 }) - .then((resp) => { - let transactions: TXRef[] = resp.txrefs; - console.log(transactions); - return { transactions: transactions }; - }) - .catch((err) => { - console.log(err); - return { transactions: null }; - }); break; } default: break; } - return { transactions: null }; + + return request(`${baseURL}`, { method: "GET", timeout: 6000 }).then( + (resp: Address) => { + console.log(resp); + return { data: resp.txs }; + } + ); } diff --git a/src/utils/utils.ts b/src/utils/utils.ts index f4a028c..ed401d9 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -138,4 +138,9 @@ export function aes256Decrypt(data: string, key: Buffer, ivStr: string, authTagS export function getNetworkFromStorage() { let network = localStorage.getItem('network') return (network === null ? 'Xenon' : network) +} + +export function isPooling(): boolean { + return localStorage.getItem("isPooling") !== "true" || + !localStorage.getItem("pooledBtcAddress") } \ No newline at end of file From b829d926bed1096a0b6712fe26723172fbbbd16d Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Sun, 13 Jun 2021 02:22:50 -0400 Subject: [PATCH 06/32] gets contribution but needs to query more automatically --- .../managePool/models/poolContributerInfo.ts | 53 +++++++++++++++---- src/services/managePool/data.d.ts | 9 +++- src/services/managePool/managePool.ts | 5 +- 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index 085e487..1844da8 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -1,4 +1,4 @@ -import { PoolContributerInfo } from "@/services/managePool/data"; +import { PoolContributerInfo, Tx } from "@/services/managePool/data"; import { getCurrentCycle, getPoolContributors, @@ -7,6 +7,19 @@ import { useState } from "react"; export interface PoolContributerInfoState { poolContributerInfoList: PoolContributerInfo[]; } + +const { balanceCoef } = require("@/services/constants"); + +const isTransactionContribution = (transaction: Tx): boolean => { + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + for (const input of transaction.inputs) { + if (input.addresses && input.addresses.includes(pooledBtcAddress)) { + return false; + } + } + return true; +}; + export default () => { let [poolContributerInfoState, setPoolContributerInfoState] = useState(); @@ -14,18 +27,36 @@ export default () => { const { cycle } = await getCurrentCycle(); // console.log(cycle); const transactions = await getPoolContributors(cycle); - // console.log(JSON.stringify(transactions)); - // const inputs = transactions.filter((txref) => !txref.spent); - // console.log(JSON.stringify(inputs)); + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + + let res: PoolContributerInfo[] = []; + transactions.data.map((transaction) => { + let sender = ""; + let contribution = 0; - // const res: PoolContributerInfo[] = [ - // { address: "wow", contribution: 1 }, - // { address: "wee", contribution: 2 }, - // ]; + if (!isTransactionContribution(transaction)) { + return; + } + // if our pooled btc address is in a transaction output, we count this as a contribution + for (const output of transaction.outputs) { + if (output.addresses && output.addresses.includes(pooledBtcAddress)) { + contribution = output.value; + // sometimes there are two inputs in a transaction, we weigh contribution based on value of inputs + const totalInputvalue = transaction.inputs.reduce( + (prev, next) => prev + next.output_value, + 0 + ); - const res = transactions.data.map((transaction) => { - const sender = ""; - const contribution = "" + for (const input of transaction.inputs) { + let weightedContribution = + contribution * (input.output_value / totalInputvalue); + res.push({ + address: input.addresses[0], // TODO: deal with edge case where input has multiple addresses? + contribution: weightedContribution / balanceCoef, + }); + } + } + } // return { address: transaction.address, contribution: transaction.value }; }); // setPoolContributerInfoState({ poolContributerInfoList: res }); diff --git a/src/services/managePool/data.d.ts b/src/services/managePool/data.d.ts index c418ae7..52467ea 100644 --- a/src/services/managePool/data.d.ts +++ b/src/services/managePool/data.d.ts @@ -33,7 +33,14 @@ export interface TxInput { wallet_token?: string; } -export interface TxOutput {} +export interface TxOutput { + value: number; + script: string; + addresses: string[]; + script_type?: string; + data_hex?: string; + data_string?: string; +} export interface Tx { block_height: number; diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index eb59a8b..c5cb70d 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -59,7 +59,8 @@ export async function getPoolContributors( cycle: number ): Promise<{ data: Tx[] }> { let baseURL = sidecarURLXenon; - let pooledBtcAddress = localStorage.getItem("pooledBtcAddress"); + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + // let pooledBtcAddress = "tb1q46cjfj593k0dz44arfpfdlz3j24n5jqdad0xu9"; const { startBlock, endBlock } = getCycleBlocks(cycle); @@ -67,7 +68,7 @@ export async function getPoolContributors( case "Xenon": { //TODO: remember to add before and after // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}&limit=2000`; - baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=2000`; + baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50`; break; } case "Mainnet": { From 7636af57f4a534b4870e878750b2cb2203273b5c Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Mon, 14 Jun 2021 02:25:51 -0400 Subject: [PATCH 07/32] gets all transactions, need to work on has_more for input / output --- src/services/constants.ts | 1 + src/services/managePool/managePool.ts | 102 ++++++++++++++++---------- 2 files changed, 63 insertions(+), 40 deletions(-) diff --git a/src/services/constants.ts b/src/services/constants.ts index 3623112..a2e4e87 100644 --- a/src/services/constants.ts +++ b/src/services/constants.ts @@ -12,6 +12,7 @@ module.exports = { //Bitcoin endpoint bitcoinTestnet3: 'https://api.blockcypher.com/v1/btc/test3', bitcoinMainnet: 'https://blockchain.info', + bitcoinMainnet2: 'https://api.blockcypher.com/v1/btc/main', explorerURL: 'https://testnet-explorer.blockstack.org', binanceAPIURL: 'https://api.binance.com/api/v3', diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index c5cb70d..773c18b 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -6,73 +6,65 @@ const { sidecarURLXenon, sidecarURLMainnet, bitcoinTestnet3, - bitcoinMainnet, + bitcoinMainnet2, firstStackingBlock, } = require("@/services/constants"); -export async function getCurrentCycle() { +export async function getCurrentCycle(): Promise<{ cycle: number }> { let baseURL = sidecarURLXenon; switch (getNetworkFromStorage()) { - case "Xenon": { + case "Xenon": baseURL = bitcoinTestnet3; - return request(`${baseURL}`, { method: "GET", timeout: 6000 }) - .then((resp) => { - let height: number = resp.height; - return { cycle: Math.ceil((height - firstStackingBlock) / 2100) }; - }) - .catch((err) => { - console.log(err); - return { cycle: -1 }; - }); - } - case "Mainnet": { - baseURL = "https://api.blockcypher.com/v1/btc/main"; - return request(`${baseURL}`, { - method: "GET", - timeout: 6000, - }) - .then((resp) => { - console.log(resp); - let height: number = resp.height; - return { cycle: Math.ceil((height - firstStackingBlock) / 2100) }; - }) - .catch((err) => { - console.log(err); - return { cycle: -1 }; - }); - } + break; + case "Mainnet": + baseURL = bitcoinMainnet2; + break; default: break; } - return { cycle: -1 }; + + return request(`${baseURL}`, { method: "GET", timeout: 6000 }) + .then((resp) => { + let height: number = resp.height; + return { cycle: Math.ceil((height - firstStackingBlock) / 2100) }; + }) + .catch((err) => { + console.log(err); + return { cycle: -1 }; + }); } -export function getCycleBlocks(cycle: number) { +export function getCycleBlocks(cycle: number): { + startBlock: number; + endBlock: number; +} { return { startBlock: firstStackingBlock + (cycle - 1) * 2100, endBlock: firstStackingBlock + cycle * 2100, }; } -export async function getPoolContributors( - cycle: number -): Promise<{ data: Tx[] }> { +// gets pool contributors between blocks +export async function getPoolContributorsHelper( + startBlock: number, + endBlock: number +): Promise
{ let baseURL = sidecarURLXenon; let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; - // let pooledBtcAddress = "tb1q46cjfj593k0dz44arfpfdlz3j24n5jqdad0xu9"; - - const { startBlock, endBlock } = getCycleBlocks(cycle); + // stx mainnet miner switch (getNetworkFromStorage()) { case "Xenon": { //TODO: remember to add before and after // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}&limit=2000`; - baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50`; + baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50&before=${endBlock}&after=${startBlock}`; + // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50`; break; } case "Mainnet": { - baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}`; + let pooledBtcAddress = "1BFfc2e6Kk82ut7S3C5yaN3pWRxEFRLLu5"; + baseURL = `${bitcoinMainnet2}/addrs/${pooledBtcAddress}/full?limit=50&before=${endBlock}&after=${startBlock}`; break; } default: @@ -82,7 +74,37 @@ export async function getPoolContributors( return request(`${baseURL}`, { method: "GET", timeout: 6000 }).then( (resp: Address) => { console.log(resp); - return { data: resp.txs }; + return resp; } ); } + +export async function getPoolContributors( + cycle: number +): Promise<{ data: Tx[] }> { + let hasMore = true; + let transactions: Tx[] = []; + + let { startBlock, endBlock } = getCycleBlocks(cycle); + + while (hasMore) { + try { + const addressResult = await getPoolContributorsHelper( + startBlock, + endBlock + ); + if (addressResult.txs.length > 0) { + const [lastTx] = addressResult.txs.slice(-1); + endBlock = lastTx.block_height; + transactions = [...transactions, ...addressResult.txs]; + } + + hasMore = addressResult.hasMore!; + // hasMore = false; + } catch (error) { + hasMore = false; + } + } + + return { data: transactions }; +} From fe17110252ab461adbcbdc23b5f93b4920724955 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Wed, 16 Jun 2021 19:41:22 -0400 Subject: [PATCH 08/32] added pool start in config --- .../component/PoolContributerTable.tsx | 23 ++++++++------ src/pages/managePool/index.tsx | 31 ++++++++++++++++++- src/services/managePool/managePool.ts | 11 +++---- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index cf16013..206f1dd 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -27,15 +27,20 @@ const PoolContributerTable: React.FC<{}> = () => { ]; return ( - - headerTitle={ - - } - columns={poolContributerColumns} - //TODO: finish rest of this table like request and rowkey - request={() => queryPoolContributerInfo()} - rowKey={"address"} - /> + <> + + headerTitle={ + + } + columns={poolContributerColumns} + //TODO: finish rest of this table like request and rowkey + request={() => queryPoolContributerInfo()} + rowKey={"address"} + /> + ); }; diff --git a/src/pages/managePool/index.tsx b/src/pages/managePool/index.tsx index 5d1f7c0..ea32de5 100644 --- a/src/pages/managePool/index.tsx +++ b/src/pages/managePool/index.tsx @@ -7,8 +7,10 @@ import { Divider, Form, Input, + InputNumber, Select, Switch, + message, } from "antd"; import { queryAccount } from "@/services/wallet/account"; @@ -17,14 +19,17 @@ import { showMessage, switchConfigProviderLocale } from "@/services/locale"; import FormItem from "antd/lib/form/FormItem"; import { FormattedMessage } from "react-intl"; import PoolContributerTable from "./component/PoolContributerTable"; +import { getCurrentCycle } from "@/services/managePool/managePool"; export interface FormValueType { poolBtcAddress: string; + poolStartCycle: number; } const TableList: React.FC<{}> = () => { const { Option } = Select; const [formVals, setFormVals] = useState({ poolBtcAddress: localStorage.getItem("pooledBtcAddress") ?? "", + poolStartCycle: parseInt(localStorage.getItem("poolStartCycle") ?? ""), }); const [accounts, setAccounts] = useState([]); @@ -32,8 +37,14 @@ const TableList: React.FC<{}> = () => { const onSubmit = async () => { const fieldsValue: FormValueType = await form.validateFields(); + console.log(fieldsValue); setFormVals({ ...formVals, ...fieldsValue }); localStorage.setItem("pooledBtcAddress", fieldsValue.poolBtcAddress); + localStorage.setItem( + "poolStartCycle", + fieldsValue.poolStartCycle.toString() + ); + message.success("Successfully saved!"); }; const [isPooling, setIsPooling] = useState( @@ -55,7 +66,10 @@ const TableList: React.FC<{}> = () => {
= () => { })} + + + + ); + }, + }, ]; return ( <> - View Contributors for Cycle: + View Contributors for Cycle: = ({ columns={poolContributerColumns} request={() => queryPoolContributerInfo(selectedCycle)} rowKey={"address"} + manualRequest={true} + params={{ selectedCycle }} /> ); diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index f70ea56..412ac5e 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -53,6 +53,9 @@ export default () => { res.push({ address: input.addresses[0], // TODO: deal with edge case where input has multiple addresses? contribution: weightedContribution / balanceCoef, + transactionHash: transaction.hash, + cycleContribution: cycle, + blockContribution: transaction.block_height, }); } } diff --git a/src/pages/publicData/locales/en-US.ts b/src/pages/publicData/locales/en-US.ts index f1e2f5e..af2c8f4 100644 --- a/src/pages/publicData/locales/en-US.ts +++ b/src/pages/publicData/locales/en-US.ts @@ -20,5 +20,6 @@ export default { 'block.info.txType': 'TX Type', 'pool.address': "Address", 'pool.contribution': "Contribution", - 'pool.title': "Pool Contributors" + 'pool.title': "Pool Contributors", + 'pool.transaction': "Transaction" }; \ No newline at end of file diff --git a/src/services/managePool/data.d.ts b/src/services/managePool/data.d.ts index 52467ea..23c59a6 100644 --- a/src/services/managePool/data.d.ts +++ b/src/services/managePool/data.d.ts @@ -101,6 +101,7 @@ export interface Address { export interface PoolContributerInfo { address: string; contribution: number; + transactionHash: string; lastCycleContribution?: number; lastBlockContribution?: number; } diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 0324b30..5bab470 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -55,7 +55,7 @@ export async function getPoolContributorsHelper( case "Xenon": { //TODO: remember to add before and after // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}&limit=2000`; - baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50&before=${endBlock}&after=${startBlock}`; + baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50&before=${endBlock}&after=${startBlock}&confidence=99`; // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50`; break; } @@ -83,6 +83,7 @@ export async function getPoolContributors( let transactions: Tx[] = []; let { startBlock, endBlock } = getCycleBlocks(cycle); + console.log(`querying blocks ${startBlock} to ${endBlock}`); while (hasMore) { try { From cc64789340ea69cdebabad8f175486a4927ff435 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Tue, 22 Jun 2021 04:21:44 -0400 Subject: [PATCH 11/32] update locale --- src/pages/publicData/locales/en-US.ts | 4 +++- src/pages/publicData/locales/zh-CN.ts | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pages/publicData/locales/en-US.ts b/src/pages/publicData/locales/en-US.ts index af2c8f4..00b108f 100644 --- a/src/pages/publicData/locales/en-US.ts +++ b/src/pages/publicData/locales/en-US.ts @@ -21,5 +21,7 @@ export default { 'pool.address': "Address", 'pool.contribution': "Contribution", 'pool.title': "Pool Contributors", - 'pool.transaction': "Transaction" + 'pool.transaction': "Transaction", + 'pool.cycleContribution': "Cycle", + 'pool.blockContribution': "Block", }; \ No newline at end of file diff --git a/src/pages/publicData/locales/zh-CN.ts b/src/pages/publicData/locales/zh-CN.ts index 465f58a..148c161 100644 --- a/src/pages/publicData/locales/zh-CN.ts +++ b/src/pages/publicData/locales/zh-CN.ts @@ -21,7 +21,9 @@ export default { // TODO 'pool.address': "", 'pool.contribution': "", - 'pool.title': "" - + 'pool.title': "", + 'pool.transaction': "", + 'pool.cycleContribution': "", + 'pool.blockContribution': "", }; \ No newline at end of file From 63b6712997d5bddeade01254b44a87eb1047678f Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Wed, 23 Jun 2021 15:10:45 -0400 Subject: [PATCH 12/32] add transaction cache --- .gitignore | 4 ++ src/pages/joinPool/index.tsx | 5 +- .../managePool/models/poolContributerInfo.ts | 64 +++++++++++++++++-- src/pages/publicData/locales/zh-CN.ts | 1 - src/services/managePool/data.d.ts | 4 +- src/services/managePool/managePool.ts | 22 +++++-- 6 files changed, 86 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 7fd9f58..93a8509 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,7 @@ screenshot .eslintcache build + + +# pool +pool/ \ No newline at end of file diff --git a/src/pages/joinPool/index.tsx b/src/pages/joinPool/index.tsx index 51ff524..72715cf 100644 --- a/src/pages/joinPool/index.tsx +++ b/src/pages/joinPool/index.tsx @@ -20,7 +20,8 @@ const TableList: React.FC<{}> = () => { }, []); useEffect(() => { - getPoolContributors(currentCycle).then((transactions) => { + const { startBlock, endBlock } = getCycleBlocks(currentCycle); + getPoolContributors(startBlock, endBlock).then((transactions) => { if (transactions) { console.log(transactions); } @@ -32,7 +33,7 @@ const TableList: React.FC<{}> = () => {
joinPool
Cycle #{currentCycle}
- From block {getCycleBlocks(currentCycle).startBlock} to + From block {getCycleBlocks(currentCycle).startBlock} to {getCycleBlocks(currentCycle).endBlock}
diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index 412ac5e..73de04e 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -1,13 +1,20 @@ import { PoolContributerInfo, Tx } from "@/services/managePool/data"; import { getCurrentCycle, + getCycleBlocks, getPoolContributors, } from "@/services/managePool/managePool"; +import { pick } from "lodash"; import { useState } from "react"; export interface PoolContributerInfoState { poolContributerInfoList: PoolContributerInfo[]; } +// used for saving to local storage. btcAddress => PoolContributorInfo[] +export interface PoolContributors { + [key: string]: PoolContributerInfo[]; +} + const { balanceCoef } = require("@/services/constants"); const isTransactionContribution = (transaction: Tx): boolean => { @@ -20,23 +27,62 @@ const isTransactionContribution = (transaction: Tx): boolean => { return true; }; +const getLocalPoolContributorInfo = (): PoolContributerInfo[] => { + let poolContributors = localStorage.getItem("poolContributors"); + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + + if (poolContributors) { + let poolContributorsMap: PoolContributors = JSON.parse(poolContributors); + if (pooledBtcAddress in poolContributorsMap) { + return poolContributorsMap[pooledBtcAddress]; + } + } + return []; +}; + +const setLocalPoolContributorInfo = (contributions: PoolContributerInfo[]) => { + let poolContributors = localStorage.getItem("poolContributors"); + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + let poolContributorsMap = {}; + if (poolContributors && pooledBtcAddress) { + poolContributorsMap = JSON.parse(poolContributors); + } + if (pooledBtcAddress) { + poolContributorsMap[pooledBtcAddress] = contributions; + localStorage.setItem( + "poolContributors", + JSON.stringify(poolContributorsMap) + ); + } +}; + export default () => { let [poolContributerInfoState, setPoolContributerInfoState] = useState(); const queryPoolContributerInfo = async (cycle: number) => { - // const { cycle } = await getCurrentCycle(); - // console.log(cycle); - const transactions = await getPoolContributors(cycle); let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + let res: PoolContributerInfo[] = getLocalPoolContributorInfo(); + let { startBlock, endBlock } = getCycleBlocks(cycle); + + // get highest height from local info + const highestHeight = Math.max(...res.map((o) => o.blockContribution)); - let res: PoolContributerInfo[] = []; + const transactions = await getPoolContributors(highestHeight, endBlock); + + let txHashes = new Set(res.map((o) => o.transactionHash)); + console.log(txHashes); transactions.data.map((transaction) => { let sender = ""; let contribution = 0; + console.log(transaction.hash); - if (!isTransactionContribution(transaction)) { + if ( + !isTransactionContribution(transaction) || + txHashes.has(transaction.hash) + ) { return; } + // if our pooled btc address is in a transaction output, we count this as a contribution for (const output of transaction.outputs) { if (output.addresses && output.addresses.includes(pooledBtcAddress)) { @@ -63,6 +109,14 @@ export default () => { // return { address: transaction.address, contribution: transaction.value }; }); // setPoolContributerInfoState({ poolContributerInfoList: res }); + + setLocalPoolContributorInfo(res); + res = res.filter( + (contribution) => + contribution.blockContribution >= startBlock && + contribution.blockContribution <= endBlock + ); + return { data: res, success: true }; }; diff --git a/src/pages/publicData/locales/zh-CN.ts b/src/pages/publicData/locales/zh-CN.ts index 148c161..ccb4e8b 100644 --- a/src/pages/publicData/locales/zh-CN.ts +++ b/src/pages/publicData/locales/zh-CN.ts @@ -25,5 +25,4 @@ export default { 'pool.transaction': "", 'pool.cycleContribution': "", 'pool.blockContribution': "", - }; \ No newline at end of file diff --git a/src/services/managePool/data.d.ts b/src/services/managePool/data.d.ts index 23c59a6..8c25c49 100644 --- a/src/services/managePool/data.d.ts +++ b/src/services/managePool/data.d.ts @@ -102,6 +102,6 @@ export interface PoolContributerInfo { address: string; contribution: number; transactionHash: string; - lastCycleContribution?: number; - lastBlockContribution?: number; + cycleContribution: number; + blockContribution: number; } diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 5bab470..bb72052 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -42,6 +42,21 @@ export function getCycleBlocks(cycle: number): { }; } +export function getPoolStartCycleBlocks(): { + startBlock: number; + endBlock: number; +} { + let poolStartCycle = localStorage.getItem("poolStartCycle"); + if (poolStartCycle) { + return getCycleBlocks(parseInt(poolStartCycle)); + } else { + return { + startBlock: firstStackingBlock, + endBlock: firstStackingBlock + 2100, + }; + } +} + // gets pool contributors between blocks export async function getPoolContributorsHelper( startBlock: number, @@ -68,6 +83,7 @@ export async function getPoolContributorsHelper( break; } + console.log(baseURL); return request(`${baseURL}`, { method: "GET", timeout: 6000 }).then( (resp: Address) => { console.log(resp); @@ -77,14 +93,12 @@ export async function getPoolContributorsHelper( } export async function getPoolContributors( - cycle: number + startBlock: number, + endBlock: number ): Promise<{ data: Tx[] }> { let hasMore = true; let transactions: Tx[] = []; - let { startBlock, endBlock } = getCycleBlocks(cycle); - console.log(`querying blocks ${startBlock} to ${endBlock}`); - while (hasMore) { try { const addressResult = await getPoolContributorsHelper( From a6c3fc5560f62bbe95da1961408c6bae4c360f31 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Thu, 24 Jun 2021 09:15:28 -0400 Subject: [PATCH 13/32] remove unnecessary query --- .../managePool/models/poolContributerInfo.ts | 79 ++++++++++--------- src/services/managePool/managePool.ts | 4 + 2 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index 73de04e..b70b0a9 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -2,6 +2,7 @@ import { PoolContributerInfo, Tx } from "@/services/managePool/data"; import { getCurrentCycle, getCycleBlocks, + getCycleForBlock, getPoolContributors, } from "@/services/managePool/managePool"; import { pick } from "lodash"; @@ -67,47 +68,47 @@ export default () => { // get highest height from local info const highestHeight = Math.max(...res.map((o) => o.blockContribution)); - const transactions = await getPoolContributors(highestHeight, endBlock); - - let txHashes = new Set(res.map((o) => o.transactionHash)); - console.log(txHashes); - transactions.data.map((transaction) => { - let sender = ""; - let contribution = 0; - console.log(transaction.hash); - - if ( - !isTransactionContribution(transaction) || - txHashes.has(transaction.hash) - ) { - return; - } - - // if our pooled btc address is in a transaction output, we count this as a contribution - for (const output of transaction.outputs) { - if (output.addresses && output.addresses.includes(pooledBtcAddress)) { - contribution = output.value; - // sometimes there are two inputs in a transaction, we weigh contribution based on value of inputs - const totalInputvalue = transaction.inputs.reduce( - (prev, next) => prev + next.output_value, - 0 - ); - - for (const input of transaction.inputs) { - let weightedContribution = - contribution * (input.output_value / totalInputvalue); - res.push({ - address: input.addresses[0], // TODO: deal with edge case where input has multiple addresses? - contribution: weightedContribution / balanceCoef, - transactionHash: transaction.hash, - cycleContribution: cycle, - blockContribution: transaction.block_height, - }); + if (endBlock > highestHeight) { + const transactions = await getPoolContributors(highestHeight, endBlock); + + let txHashes = new Set(res.map((o) => o.transactionHash)); + transactions.data.map((transaction) => { + let contribution = 0; + + if ( + !isTransactionContribution(transaction) || + txHashes.has(transaction.hash) || + transaction.block_height == -1 + ) { + return; + } + + // if our pooled btc address is in a transaction output, we count this as a contribution + for (const output of transaction.outputs) { + if (output.addresses && output.addresses.includes(pooledBtcAddress)) { + contribution = output.value; + // sometimes there are two inputs in a transaction, we weigh contribution based on value of inputs + const totalInputvalue = transaction.inputs.reduce( + (prev, next) => prev + next.output_value, + 0 + ); + + for (const input of transaction.inputs) { + let weightedContribution = + contribution * (input.output_value / totalInputvalue); + res.push({ + address: input.addresses[0], // TODO: deal with edge case where input has multiple addresses? + contribution: weightedContribution / balanceCoef, + transactionHash: transaction.hash, + cycleContribution: getCycleForBlock(transaction.block_height), + blockContribution: transaction.block_height, + }); + } } } - } - // return { address: transaction.address, contribution: transaction.value }; - }); + // return { address: transaction.address, contribution: transaction.value }; + }); + } // setPoolContributerInfoState({ poolContributerInfoList: res }); setLocalPoolContributorInfo(res); diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index bb72052..06f3af1 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -57,6 +57,10 @@ export function getPoolStartCycleBlocks(): { } } +export function getCycleForBlock(blockHeight: number): number { + return Math.floor((blockHeight - firstStackingBlock) / 2100) + 1; +} + // gets pool contributors between blocks export async function getPoolContributorsHelper( startBlock: number, From 7893b0e96311980a0d51797f33ce4b7e221e8dfe Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Thu, 24 Jun 2021 11:31:48 -0400 Subject: [PATCH 14/32] store outputs too --- .../managePool/models/poolContributerInfo.ts | 96 ++++++++++++------- src/services/managePool/data.d.ts | 1 + src/services/managePool/managePool.ts | 6 +- 3 files changed, 68 insertions(+), 35 deletions(-) diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index b70b0a9..80cbe6c 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -5,19 +5,19 @@ import { getCycleForBlock, getPoolContributors, } from "@/services/managePool/managePool"; -import { pick } from "lodash"; import { useState } from "react"; export interface PoolContributerInfoState { poolContributerInfoList: PoolContributerInfo[]; } // used for saving to local storage. btcAddress => PoolContributorInfo[] -export interface PoolContributors { +export interface LocalPoolContributors { [key: string]: PoolContributerInfo[]; } const { balanceCoef } = require("@/services/constants"); +// used to check if transaction is an input to the address const isTransactionContribution = (transaction: Tx): boolean => { let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; for (const input of transaction.inputs) { @@ -28,12 +28,38 @@ const isTransactionContribution = (transaction: Tx): boolean => { return true; }; +// if transaction positive, this was an input / contribution, else output / spent on mining +const getTransactionValue = ( + pooledBtcAddress: string, + transaction: Tx +): number => { + let value = 0; + for (const input of transaction.inputs) { + if (input.addresses && input.addresses.includes(pooledBtcAddress)) { + value -= input.output_value; + } + } + for (const output of transaction.outputs) { + if (output.addresses && output.addresses.includes(pooledBtcAddress)) { + value += output.value; + } + } + // if this was an output, we also paid the fees + if (value < 0) { + value -= transaction.fees; + } + return value; +}; + +// used to get pool contributer info from local storage +// cached so you don't have to requery tx const getLocalPoolContributorInfo = (): PoolContributerInfo[] => { let poolContributors = localStorage.getItem("poolContributors"); let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; if (poolContributors) { - let poolContributorsMap: PoolContributors = JSON.parse(poolContributors); + let poolContributorsMap: LocalPoolContributors = + JSON.parse(poolContributors); if (pooledBtcAddress in poolContributorsMap) { return poolContributorsMap[pooledBtcAddress]; } @@ -41,6 +67,8 @@ const getLocalPoolContributorInfo = (): PoolContributerInfo[] => { return []; }; +// used to set pool contributor info from local storage +// cached so you don't have to requery tx const setLocalPoolContributorInfo = (contributions: PoolContributerInfo[]) => { let poolContributors = localStorage.getItem("poolContributors"); let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; @@ -73,49 +101,49 @@ export default () => { let txHashes = new Set(res.map((o) => o.transactionHash)); transactions.data.map((transaction) => { - let contribution = 0; - - if ( - !isTransactionContribution(transaction) || - txHashes.has(transaction.hash) || - transaction.block_height == -1 - ) { + // if we already stored this transaction or its not confirmed yet, skip + if (txHashes.has(transaction.hash) || transaction.block_height == -1) { return; } - // if our pooled btc address is in a transaction output, we count this as a contribution - for (const output of transaction.outputs) { - if (output.addresses && output.addresses.includes(pooledBtcAddress)) { - contribution = output.value; - // sometimes there are two inputs in a transaction, we weigh contribution based on value of inputs - const totalInputvalue = transaction.inputs.reduce( - (prev, next) => prev + next.output_value, - 0 - ); - - for (const input of transaction.inputs) { - let weightedContribution = - contribution * (input.output_value / totalInputvalue); - res.push({ - address: input.addresses[0], // TODO: deal with edge case where input has multiple addresses? - contribution: weightedContribution / balanceCoef, - transactionHash: transaction.hash, - cycleContribution: getCycleForBlock(transaction.block_height), - blockContribution: transaction.block_height, - }); - } + let contribution = getTransactionValue(pooledBtcAddress, transaction); + if (contribution > 0) { + // sometimes the inputs can have multiple addresses, so we weigh contributions based on each address input + const totalInputvalue = transaction.inputs.reduce( + (prev, next) => prev + next.output_value, + 0 + ); + for (const input of transaction.inputs) { + let weightedContribution = + contribution * (input.output_value / totalInputvalue); + res.push({ + address: input.addresses[0], // TODO: deal with edge case where input has multiple addresses? + contribution: weightedContribution / balanceCoef, + transactionHash: transaction.hash, + cycleContribution: getCycleForBlock(transaction.block_height), + blockContribution: transaction.block_height, + isContribution: true, + }); } + } else { + res.push({ + address: "output", + contribution: contribution / balanceCoef, + transactionHash: transaction.hash, + cycleContribution: getCycleForBlock(transaction.block_height), + blockContribution: transaction.block_height, + isContribution: false, + }); } - // return { address: transaction.address, contribution: transaction.value }; }); } - // setPoolContributerInfoState({ poolContributerInfoList: res }); setLocalPoolContributorInfo(res); res = res.filter( (contribution) => contribution.blockContribution >= startBlock && - contribution.blockContribution <= endBlock + contribution.blockContribution <= endBlock && + contribution.isContribution ); return { data: res, success: true }; diff --git a/src/services/managePool/data.d.ts b/src/services/managePool/data.d.ts index 8c25c49..e35bf9d 100644 --- a/src/services/managePool/data.d.ts +++ b/src/services/managePool/data.d.ts @@ -104,4 +104,5 @@ export interface PoolContributerInfo { transactionHash: string; cycleContribution: number; blockContribution: number; + isContribution: boolean; } diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 06f3af1..7e5df56 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -10,6 +10,10 @@ const { firstStackingBlock, } = require("@/services/constants"); +export interface LocalTxs { + [key: string]: Tx[]; +} + export async function getCurrentCycle(): Promise<{ cycle: number }> { let baseURL = sidecarURLXenon; @@ -116,8 +120,8 @@ export async function getPoolContributors( } hasMore = addressResult.hasMore!; - // hasMore = false; } catch (error) { + console.log(error); hasMore = false; } } From b0cbb81204b496a3c67024be9e5226331e40663c Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Thu, 24 Jun 2021 11:55:05 -0400 Subject: [PATCH 15/32] show error to user when failed to get newest pool contributors --- .../managePool/models/poolContributerInfo.ts | 57 ++----------------- src/services/managePool/managePool.ts | 56 ++++++++++++++++-- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index 80cbe6c..f74f76b 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -4,30 +4,15 @@ import { getCycleBlocks, getCycleForBlock, getPoolContributors, + PoolContributerInfoState, + LocalPoolContributors, + getLocalPoolContributorInfo, + setLocalPoolContributorInfo, } from "@/services/managePool/managePool"; import { useState } from "react"; -export interface PoolContributerInfoState { - poolContributerInfoList: PoolContributerInfo[]; -} - -// used for saving to local storage. btcAddress => PoolContributorInfo[] -export interface LocalPoolContributors { - [key: string]: PoolContributerInfo[]; -} const { balanceCoef } = require("@/services/constants"); -// used to check if transaction is an input to the address -const isTransactionContribution = (transaction: Tx): boolean => { - let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; - for (const input of transaction.inputs) { - if (input.addresses && input.addresses.includes(pooledBtcAddress)) { - return false; - } - } - return true; -}; - // if transaction positive, this was an input / contribution, else output / spent on mining const getTransactionValue = ( pooledBtcAddress: string, @@ -51,40 +36,6 @@ const getTransactionValue = ( return value; }; -// used to get pool contributer info from local storage -// cached so you don't have to requery tx -const getLocalPoolContributorInfo = (): PoolContributerInfo[] => { - let poolContributors = localStorage.getItem("poolContributors"); - let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; - - if (poolContributors) { - let poolContributorsMap: LocalPoolContributors = - JSON.parse(poolContributors); - if (pooledBtcAddress in poolContributorsMap) { - return poolContributorsMap[pooledBtcAddress]; - } - } - return []; -}; - -// used to set pool contributor info from local storage -// cached so you don't have to requery tx -const setLocalPoolContributorInfo = (contributions: PoolContributerInfo[]) => { - let poolContributors = localStorage.getItem("poolContributors"); - let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; - let poolContributorsMap = {}; - if (poolContributors && pooledBtcAddress) { - poolContributorsMap = JSON.parse(poolContributors); - } - if (pooledBtcAddress) { - poolContributorsMap[pooledBtcAddress] = contributions; - localStorage.setItem( - "poolContributors", - JSON.stringify(poolContributorsMap) - ); - } -}; - export default () => { let [poolContributerInfoState, setPoolContributerInfoState] = useState(); diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 7e5df56..9a06cd5 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -1,7 +1,7 @@ import { getNetworkFromStorage } from "@/utils/utils"; import request from "umi-request"; -import { Address, Tx } from "./data"; - +import { Address, Tx, PoolContributerInfo } from "./data"; +import { message } from "antd"; const { sidecarURLXenon, sidecarURLMainnet, @@ -10,8 +10,13 @@ const { firstStackingBlock, } = require("@/services/constants"); -export interface LocalTxs { - [key: string]: Tx[]; +export interface PoolContributerInfoState { + poolContributerInfoList: PoolContributerInfo[]; +} + +// used for saving to local storage. btcAddress => PoolContributorInfo[] +export interface LocalPoolContributors { + [key: string]: PoolContributerInfo[]; } export async function getCurrentCycle(): Promise<{ cycle: number }> { @@ -65,6 +70,42 @@ export function getCycleForBlock(blockHeight: number): number { return Math.floor((blockHeight - firstStackingBlock) / 2100) + 1; } +// used to get pool contributer info from local storage +// cached so you don't have to requery tx +export const getLocalPoolContributorInfo = (): PoolContributerInfo[] => { + let poolContributors = localStorage.getItem("poolContributors"); + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + + if (poolContributors) { + let poolContributorsMap: LocalPoolContributors = + JSON.parse(poolContributors); + if (pooledBtcAddress in poolContributorsMap) { + return poolContributorsMap[pooledBtcAddress]; + } + } + return []; +}; + +// used to set pool contributor info from local storage +// cached so you don't have to requery tx +export const setLocalPoolContributorInfo = ( + contributions: PoolContributerInfo[] +) => { + let poolContributors = localStorage.getItem("poolContributors"); + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + let poolContributorsMap = {}; + if (poolContributors && pooledBtcAddress) { + poolContributorsMap = JSON.parse(poolContributors); + } + if (pooledBtcAddress) { + poolContributorsMap[pooledBtcAddress] = contributions; + localStorage.setItem( + "poolContributors", + JSON.stringify(poolContributorsMap) + ); + } +}; + // gets pool contributors between blocks export async function getPoolContributorsHelper( startBlock: number, @@ -107,6 +148,12 @@ export async function getPoolContributors( let hasMore = true; let transactions: Tx[] = []; + // TODO: if you get rate limited halfway through, you'll have the most recent + // transactions cached but you'll be missing the transactions starting + // from startBlock. Then when you try again later, it'll only query from + // the highest cached transaction to end block, so you'll still be missing the + // middle transactions. either find a way to fix this, or return an empty array + // if any error occurs while (hasMore) { try { const addressResult = await getPoolContributorsHelper( @@ -122,6 +169,7 @@ export async function getPoolContributors( hasMore = addressResult.hasMore!; } catch (error) { console.log(error); + message.error("Failed to get newest pool contributors"); hasMore = false; } } From 6447b5fcc6110d6d2cfa40c79ad6de5262683aa2 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Thu, 24 Jun 2021 12:00:37 -0400 Subject: [PATCH 16/32] change initial cycle on form --- src/pages/managePool/index.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/managePool/index.tsx b/src/pages/managePool/index.tsx index 1c7243a..78d0548 100644 --- a/src/pages/managePool/index.tsx +++ b/src/pages/managePool/index.tsx @@ -29,7 +29,7 @@ const TableList: React.FC<{}> = () => { const { Option } = Select; const [formVals, setFormVals] = useState({ poolBtcAddress: localStorage.getItem("pooledBtcAddress") ?? "", - poolStartCycle: parseInt(localStorage.getItem("poolStartCycle") ?? ""), + poolStartCycle: parseInt(localStorage.getItem("poolStartCycle") ?? "-1"), }); const [accounts, setAccounts] = useState([]); @@ -61,6 +61,9 @@ const TableList: React.FC<{}> = () => { getCurrentCycle().then(({ cycle }) => { setCurrentCycle(cycle); + if (formVals.poolStartCycle == -1) { + setFormVals({ ...formVals, ...{ poolCycleStart: cycle } }); + } }); }, []); From 991e1d60ff2c6fa98585676ae30c6353753a6fd3 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Fri, 25 Jun 2021 19:06:51 -0400 Subject: [PATCH 17/32] get balance --- README.md | 33 +++++++++++ .../component/PoolContributerTable.tsx | 17 +++++- .../managePool/models/poolContributerInfo.ts | 17 +++++- src/services/managePool/managePool.ts | 59 ++++++++++++++++++- 4 files changed, 120 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4b35644..bd4609b 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,39 @@ Please Visit [Mining-Bot Documentation](https://daemon-technologies.github.io/do ## Pooling +Example: +Pool begins mining in cycle #10. Any BTC sent to the specified address before cycle #10 begins is counted as a contribution. + +### Before Cycle #10 + +For example: +- You contribute 0.1 BTC +- Other people contribute 0.9 BTC total +- Pool has a total of 1 BTC right before cycle #10 begins, so you will earn 0.1/1 = 10% of all mining rewards in cycle #10. + +### Cycle #10 + +- You earn 10% of all mining rewards this cycle. +- This address begins to mine STX. +- BTC sent to this address during this cycle will count as contributions for cycle #11 +- By the end of cycle #10, 0.1 BTC has been spent on mining, and another 0.9 BTC was contributed, so pool now has 1.8 BTC before cycle #11. +- The BTC received before cycle #10 is now 0.9 and receives a weight of 0.9/1.8 = 50%, and you receive 10% of this, so you get a total of 5% of all mining rewards in cycle #11. + +### Cycle #11 +- You receive 10% of all mining rewards this cycle. +- This address continues mining STX. +- BTC sent to this address during this cycle will count as contributions for cycle #12 +- By the end of cycle #11, another 0.1 BTC has been spent on mining, and no other BTC was contributed, so pool now has 1.7 BTC before cycle #12. +- Since no other BTC was received, you still get a total of 5% of all mining rewards in cycle #12. + +### Cycle #12 +- You receive 10% of all mining rewards this cycle. +- This address continues mining STX. +- BTC sent to this address during this cycle will count as contributions for cycle #13 +- You contribute another 0.4 BTC to the pool +- By the end of cycle #12, another 0.1 BTC has been spent on mining, so there is now 2 BTC before cycle #13. +- The BTC received before cycle #10 is now 1.6 and receives a weight of 1.6 / 2.0 = 80%, and you receive 5% of this, and you just contributed 0.4 / 2.0 = 20%, so you will receive 20% + 5% * 80% = 24% of all mining rewards in cycle #13. + ### Manage Pool On this page, you can manage a stacks mining pool. You should be able to: diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index 538c413..56a1e1b 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react"; import ProTable, { ProColumns } from "@ant-design/pro-table"; import { FormattedMessage, useModel } from "umi"; import { BlockInfo, TxInfo } from "@/services/publicdata/data"; -import { Tag, Card, InputNumber, Button } from "antd"; +import { Tag, Card, InputNumber, Button, Table } from "antd"; import { getBlockInfo, getTxsInfo } from "@/services/publicdata/chainInfo"; import { PoolContributerInfo } from "@/services/managePool/data"; import { showMessage } from "@/services/locale"; @@ -30,6 +30,7 @@ const PoolContributerTable: React.FC = ({ useEffect(() => { setSelectedCycle(cycle); }, [cycle]); + const poolContributerColumns: ProColumns[] = [ { title: , @@ -110,6 +111,20 @@ const PoolContributerTable: React.FC = ({ rowKey={"address"} manualRequest={true} params={{ selectedCycle }} + summary={(contributions) => { + let total = 0; + for (const contribution of contributions) { + total += contribution.contribution; + } + return ( + + + Total contributed + + {total} + + ); + }} /> ); diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index f74f76b..103748b 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -8,6 +8,8 @@ import { LocalPoolContributors, getLocalPoolContributorInfo, setLocalPoolContributorInfo, + getBalanceAtBlock, + getBalance, } from "@/services/managePool/managePool"; import { useState } from "react"; @@ -42,16 +44,20 @@ export default () => { const queryPoolContributerInfo = async (cycle: number) => { let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; let res: PoolContributerInfo[] = getLocalPoolContributorInfo(); - let { startBlock, endBlock } = getCycleBlocks(cycle); + let { startBlock, endBlock } = getCycleBlocks(cycle - 1); // get highest height from local info const highestHeight = Math.max(...res.map((o) => o.blockContribution)); + let currentBalance = 0; if (endBlock > highestHeight) { - const transactions = await getPoolContributors(highestHeight, endBlock); + let { transactions, balance } = await getPoolContributors( + highestHeight, + endBlock + ); let txHashes = new Set(res.map((o) => o.transactionHash)); - transactions.data.map((transaction) => { + transactions.map((transaction) => { // if we already stored this transaction or its not confirmed yet, skip if (txHashes.has(transaction.hash) || transaction.block_height == -1) { return; @@ -87,6 +93,9 @@ export default () => { }); } }); + currentBalance = balance / balanceCoef; + } else { + currentBalance = await getBalance(); } setLocalPoolContributorInfo(res); @@ -97,6 +106,8 @@ export default () => { contribution.isContribution ); + let balanceAtEndOfCycle = getBalanceAtBlock(endBlock, currentBalance); + console.log("at the end of block", endBlock, "had", balanceAtEndOfCycle); return { data: res, success: true }; }; diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 9a06cd5..e081842 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -8,6 +8,7 @@ const { bitcoinTestnet3, bitcoinMainnet2, firstStackingBlock, + balanceCoef, } = require("@/services/constants"); export interface PoolContributerInfoState { @@ -106,6 +107,54 @@ export const setLocalPoolContributorInfo = ( } }; +export async function getBalance(): Promise { + let baseURL = sidecarURLXenon; + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + + switch (getNetworkFromStorage()) { + case "Xenon": { + //TODO: remember to add before and after + // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}&limit=2000`; + baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/balance`; + // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50`; + break; + } + case "Mainnet": { + let pooledBtcAddress = "1BFfc2e6Kk82ut7S3C5yaN3pWRxEFRLLu5"; + baseURL = `${bitcoinMainnet2}/addrs/${pooledBtcAddress}/balance`; + break; + } + default: + break; + } + return request(`${baseURL}`, { method: "GET", timeout: 6000 }).then( + (resp: Address) => { + console.log(resp); + return resp.balance / balanceCoef; + } + ); +} + +// async function to get the balance? or change result of queryPoolContributerInfo +export function getBalanceAtBlock( + blockHeight: number, + currentBalance: number +): number { + let balance = currentBalance; + let transactions = getLocalPoolContributorInfo(); + let index = 0; + let transaction = transactions[index]; + while ( + index < transactions.length && + transaction.blockContribution >= blockHeight + ) { + balance -= transaction.contribution; + index += 1; + transaction = transactions[index]; + } + return balance; +} + // gets pool contributors between blocks export async function getPoolContributorsHelper( startBlock: number, @@ -144,9 +193,10 @@ export async function getPoolContributorsHelper( export async function getPoolContributors( startBlock: number, endBlock: number -): Promise<{ data: Tx[] }> { +): Promise<{ transactions: Tx[]; balance: number }> { let hasMore = true; let transactions: Tx[] = []; + let balance = -1; // TODO: if you get rate limited halfway through, you'll have the most recent // transactions cached but you'll be missing the transactions starting @@ -160,6 +210,11 @@ export async function getPoolContributors( startBlock, endBlock ); + + if (balance == -1) { + balance = addressResult.balance; + } + if (addressResult.txs.length > 0) { const [lastTx] = addressResult.txs.slice(-1); endBlock = lastTx.block_height; @@ -174,5 +229,5 @@ export async function getPoolContributors( } } - return { data: transactions }; + return { transactions, balance }; } From b91f0446c68b8a772dca04cdab09383a4cac3872 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Fri, 25 Jun 2021 19:55:37 -0400 Subject: [PATCH 18/32] add stx address --- src/pages/managePool/component/PoolContributerTable.tsx | 4 ++++ src/pages/managePool/models/poolContributerInfo.ts | 4 ++++ src/pages/publicData/locales/en-US.ts | 1 + src/pages/publicData/locales/zh-CN.ts | 1 + src/services/managePool/data.d.ts | 1 + 5 files changed, 11 insertions(+) diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index 56a1e1b..4ff204b 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -36,6 +36,10 @@ const PoolContributerTable: React.FC = ({ title: , dataIndex: "address", }, + { + title: , + dataIndex: "stxAddress", + }, { title: ( { for (const input of transaction.inputs) { let weightedContribution = contribution * (input.output_value / totalInputvalue); + // https://github.com/blockstack/cli-blockstack/blob/master/src/cli.ts res.push({ address: input.addresses[0], // TODO: deal with edge case where input has multiple addresses? + stxAddress: input.addresses[0], // b58ToC32(input.addresses[0]), contribution: weightedContribution / balanceCoef, transactionHash: transaction.hash, cycleContribution: getCycleForBlock(transaction.block_height), @@ -85,6 +88,7 @@ export default () => { } else { res.push({ address: "output", + stxAddress: "output", contribution: contribution / balanceCoef, transactionHash: transaction.hash, cycleContribution: getCycleForBlock(transaction.block_height), diff --git a/src/pages/publicData/locales/en-US.ts b/src/pages/publicData/locales/en-US.ts index 00b108f..b36daaa 100644 --- a/src/pages/publicData/locales/en-US.ts +++ b/src/pages/publicData/locales/en-US.ts @@ -19,6 +19,7 @@ export default { 'block.info.feeRate': 'Fee Rate', 'block.info.txType': 'TX Type', 'pool.address': "Address", + 'pool.stxAddress': "STX Address", 'pool.contribution': "Contribution", 'pool.title': "Pool Contributors", 'pool.transaction': "Transaction", diff --git a/src/pages/publicData/locales/zh-CN.ts b/src/pages/publicData/locales/zh-CN.ts index ccb4e8b..8279052 100644 --- a/src/pages/publicData/locales/zh-CN.ts +++ b/src/pages/publicData/locales/zh-CN.ts @@ -20,6 +20,7 @@ export default { 'block.info.txType': '交易类型', // TODO 'pool.address': "", + 'pool.stxAddress': "", 'pool.contribution': "", 'pool.title': "", 'pool.transaction': "", diff --git a/src/services/managePool/data.d.ts b/src/services/managePool/data.d.ts index e35bf9d..307345e 100644 --- a/src/services/managePool/data.d.ts +++ b/src/services/managePool/data.d.ts @@ -100,6 +100,7 @@ export interface Address { } export interface PoolContributerInfo { address: string; + stxAddress: string; contribution: number; transactionHash: string; cycleContribution: number; From 5dc7297d62fa592b5d8d4fe13efd31b13a47f40a Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Sun, 27 Jun 2021 15:42:44 -0400 Subject: [PATCH 19/32] fixed stx address --- .../component/PoolContributerTable.tsx | 8 ++- .../managePool/models/poolContributerInfo.ts | 50 +++++++++++++++++-- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index 4ff204b..7cb1865 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -35,10 +35,14 @@ const PoolContributerTable: React.FC = ({ { title: , dataIndex: "address", + copyable: true, }, { - title: , + title: ( + + ), dataIndex: "stxAddress", + copyable: true, }, { title: ( @@ -122,7 +126,7 @@ const PoolContributerTable: React.FC = ({ } return ( - + Total contributed {total} diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index cf25f8a..5767c80 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -13,8 +13,9 @@ import { } from "@/services/managePool/managePool"; import { b58ToC32 } from "c32check"; import { useState } from "react"; - +import { getNetworkFromStorage } from "@/utils/utils"; const { balanceCoef } = require("@/services/constants"); +const bitcoinjs_lib_1 = require("bitcoinjs-lib"); // if transaction positive, this was an input / contribution, else output / spent on mining const getTransactionValue = ( @@ -39,6 +40,30 @@ const getTransactionValue = ( return value; }; +// taken from BlockstackNetwork +const coerceAddress = (address: string) => { + const { hash, version } = bitcoinjs_lib_1.address.fromBase58Check(address); + const scriptHashes = [ + bitcoinjs_lib_1.networks.bitcoin.scriptHash, + bitcoinjs_lib_1.networks.testnet.scriptHash, + ]; + const pubKeyHashes = [ + bitcoinjs_lib_1.networks.bitcoin.pubKeyHash, + bitcoinjs_lib_1.networks.testnet.pubKeyHash, + ]; + let coercedVersion; + if (scriptHashes.indexOf(version) >= 0) { + coercedVersion = bitcoinjs_lib_1.networks.bitcoin.scriptHash; + } else if (pubKeyHashes.indexOf(version) >= 0) { + coercedVersion = bitcoinjs_lib_1.networks.bitcoin.pubKeyHash; + } else { + throw new Error( + `Unrecognized address version number ${version} in ${address}` + ); + } + return bitcoinjs_lib_1.address.toBase58Check(hash, coercedVersion); +}; + export default () => { let [poolContributerInfoState, setPoolContributerInfoState] = useState(); @@ -74,10 +99,27 @@ export default () => { for (const input of transaction.inputs) { let weightedContribution = contribution * (input.output_value / totalInputvalue); - // https://github.com/blockstack/cli-blockstack/blob/master/src/cli.ts + let address = input.addresses[0]; + let stxAddress = input.addresses[0]; + // BECH32 not supported + try { + switch (getNetworkFromStorage()) { + case "Xenon": { + address = coerceAddress(address); + break; + } + case "Mainnet": + break; + default: + break; + } + stxAddress = b58ToC32(address); + } catch (err) { + stxAddress = "UNSUPPORTED"; + } res.push({ - address: input.addresses[0], // TODO: deal with edge case where input has multiple addresses? - stxAddress: input.addresses[0], // b58ToC32(input.addresses[0]), + address: address, // TODO: deal with edge case where input has multiple addresses? + stxAddress: stxAddress, // b58ToC32(input.addresses[0]), contribution: weightedContribution / balanceCoef, transactionHash: transaction.hash, cycleContribution: getCycleForBlock(transaction.block_height), From c1c55e402de20d101b5511ff3da8ecfdbf8d306f Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Mon, 28 Jun 2021 00:12:51 -0400 Subject: [PATCH 20/32] added total remaining at end of last cycle --- .../component/PoolContributerTable.tsx | 28 ++++++++-- .../managePool/models/poolContributerInfo.ts | 10 +++- src/services/managePool/managePool.ts | 56 ++++++++++++++++--- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index 7cb1865..b2a07de 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -7,6 +7,11 @@ import { getBlockInfo, getTxsInfo } from "@/services/publicdata/chainInfo"; import { PoolContributerInfo } from "@/services/managePool/data"; import { showMessage } from "@/services/locale"; import { getNetworkFromStorage } from "@/utils/utils"; +import { + getBalanceAtBlock, + getCycleBlocks, + getLocalPoolBalance, +} from "@/services/managePool/managePool"; const { sidecarURLXenon, sidecarURLMainnet, @@ -124,13 +129,24 @@ const PoolContributerTable: React.FC = ({ for (const contribution of contributions) { total += contribution.contribution; } + + const { endBlock } = getCycleBlocks(selectedCycle-1); + const balance = getBalanceAtBlock(endBlock); return ( - - - Total contributed - - {total} - + <> + + + Total Contributed In Last Cycle + + {total} + + + + Total Remaining At End of Last Cycle + + {balance} + + ); }} /> diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index 5767c80..272ac5f 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -10,6 +10,8 @@ import { setLocalPoolContributorInfo, getBalanceAtBlock, getBalance, + setLocalPoolBalances, + getLocalPoolBalance, } from "@/services/managePool/managePool"; import { b58ToC32 } from "c32check"; import { useState } from "react"; @@ -152,7 +154,13 @@ export default () => { contribution.isContribution ); - let balanceAtEndOfCycle = getBalanceAtBlock(endBlock, currentBalance); + // sometimes API will return 0 tx for address, so only change local pool balance if we have a valid response + if (currentBalance > 0) { + setLocalPoolBalances(currentBalance); + } else { + currentBalance = getLocalPoolBalance(); + } + let balanceAtEndOfCycle = getBalanceAtBlock(endBlock); console.log("at the end of block", endBlock, "had", balanceAtEndOfCycle); return { data: res, success: true }; }; diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index e081842..fa4f1b8 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -20,6 +20,10 @@ export interface LocalPoolContributors { [key: string]: PoolContributerInfo[]; } +export interface LocalPoolBalances { + [key: string]: number; +} + export async function getCurrentCycle(): Promise<{ cycle: number }> { let baseURL = sidecarURLXenon; @@ -71,6 +75,37 @@ export function getCycleForBlock(blockHeight: number): number { return Math.floor((blockHeight - firstStackingBlock) / 2100) + 1; } +// used to get pool balance from local storage +// cached so you don't have to requery +export const getLocalPoolBalance = (): number => { + let poolBalances = localStorage.getItem("poolBalances"); + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + + if (poolBalances) { + let poolBalancesMap: LocalPoolBalances = JSON.parse(poolBalances); + if (pooledBtcAddress in poolBalancesMap) { + return poolBalancesMap[pooledBtcAddress]; + } + } + return 0; +}; + +// used to set pool balance from in local storage +// cached so you don't have to requery + +export const setLocalPoolBalances = (balance: number) => { + let poolBalances = localStorage.getItem("poolBalances"); + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; + let poolBalancesMap = {}; + if (poolBalances && pooledBtcAddress) { + poolBalancesMap = JSON.parse(poolBalances); + } + if (pooledBtcAddress) { + poolBalancesMap[pooledBtcAddress] = balance; + localStorage.setItem("poolBalances", JSON.stringify(poolBalancesMap)); + } +}; + // used to get pool contributer info from local storage // cached so you don't have to requery tx export const getLocalPoolContributorInfo = (): PoolContributerInfo[] => { @@ -87,7 +122,7 @@ export const getLocalPoolContributorInfo = (): PoolContributerInfo[] => { return []; }; -// used to set pool contributor info from local storage +// used to set pool contributor info in local storage // cached so you don't have to requery tx export const setLocalPoolContributorInfo = ( contributions: PoolContributerInfo[] @@ -99,7 +134,9 @@ export const setLocalPoolContributorInfo = ( poolContributorsMap = JSON.parse(poolContributors); } if (pooledBtcAddress) { - poolContributorsMap[pooledBtcAddress] = contributions; + poolContributorsMap[pooledBtcAddress] = contributions.sort((a, b) => + a.blockContribution < b.blockContribution ? 1 : -1 + ); localStorage.setItem( "poolContributors", JSON.stringify(poolContributorsMap) @@ -107,6 +144,7 @@ export const setLocalPoolContributorInfo = ( } }; +// sometimes the api will return 0 balance and 0 tx, so just return -1 if that happens export async function getBalance(): Promise { let baseURL = sidecarURLXenon; let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; @@ -130,24 +168,27 @@ export async function getBalance(): Promise { return request(`${baseURL}`, { method: "GET", timeout: 6000 }).then( (resp: Address) => { console.log(resp); + if (resp.n_tx == 0 && getLocalPoolBalance() > 0) { + return -1; + } return resp.balance / balanceCoef; } ); } // async function to get the balance? or change result of queryPoolContributerInfo -export function getBalanceAtBlock( - blockHeight: number, - currentBalance: number -): number { - let balance = currentBalance; +export function getBalanceAtBlock(blockHeight: number): number { + let balance = getLocalPoolBalance(); let transactions = getLocalPoolContributorInfo(); let index = 0; let transaction = transactions[index]; + console.log("blockHeight", blockHeight); + console.log("transaction height", transaction.blockContribution); while ( index < transactions.length && transaction.blockContribution >= blockHeight ) { + console.log("transaction height", transaction.blockContribution); balance -= transaction.contribution; index += 1; transaction = transactions[index]; @@ -181,7 +222,6 @@ export async function getPoolContributorsHelper( break; } - console.log(baseURL); return request(`${baseURL}`, { method: "GET", timeout: 6000 }).then( (resp: Address) => { console.log(resp); From 7a676015fd975a98518096fefba22098e95c1cf9 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Mon, 28 Jun 2021 16:07:58 -0400 Subject: [PATCH 21/32] updated readme --- README.md | 57 +++++++++++++++++++-------- src/services/managePool/managePool.ts | 2 - 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index bd4609b..5eaacf3 100644 --- a/README.md +++ b/README.md @@ -1,57 +1,82 @@ # Mining-Bot - Please Visit [Mining-Bot Documentation](https://daemon-technologies.github.io/docs/) - [WSL Tutorial Video](https://www.youtube.com/watch?v=FXifFx0Akzc) - [MacOS](https://www.youtube.com/watch?v=TCtCTttsSeI) - ## Pooling -Example: +This pooling infrastructure assumes the following: + +- All inputs to your specified pooling address will be new contributors. +- All outputs to your specified pooling address will be btc spent on mining. + +### Formulation + +For cycle ![](https://latex.codecogs.com/png.latex?n): + +- Let ![](https://latex.codecogs.com/png.latex?X_{n-1}) be the total BTC contributed to the pool during cycle ![](https://latex.codecogs.com/png.latex?n). + +- Let ![](https://latex.codecogs.com/png.latex?Y_{n-1}) be the total BTC in the pool at the end of cycle ![](https://latex.codecogs.com/png.latex?n). + +- Let ![](https://latex.codecogs.com/png.latex?Z_{n-1}=Y_{n-1}-X_{n-1}), or the amount of BTC left in the pool after mining during cycle ![](https://latex.codecogs.com/png.latex?n-1) and not including the newest contributions in cycle ![](https://latex.codecogs.com/png.latex?n-1). + +If you contributed ![](https://latex.codecogs.com/png.latex?c_{n-1}) BTC during cycle ![](https://latex.codecogs.com/png.latex?n-1), your reward percentage for cycle ![](https://latex.codecogs.com/png.latex?n) will be ![](https://latex.codecogs.com/png.latex?P_n=\frac{s_{n-1}}{X_{n-1}}\cdot\frac{X_{n-1}}{Y_{n-1}}=\frac{s_{n-1}}{Y_{n-1}}). + +If you contributed ![](https://latex.codecogs.com/png.latex?c_{n-k}) BTC during cycle ![](https://latex.codecogs.com/png.latex?n-k) where ![](https://latex.codecogs.com/png.latex?k>1), your reward percentage for cycle N will be ![](https://latex.codecogs.com/png.latex?\frac{P_k}{Z_{n-1}}). + +Essentially, your reward for any given cycle will be weighted based on how much you contributed divided by the total amount remaining at the end of each cycle. As time goes on, more contributors will join the pool and bitcoin will be spent on mining, so your reward percentage will go down. + +### Example: + Pool begins mining in cycle #10. Any BTC sent to the specified address before cycle #10 begins is counted as a contribution. ### Before Cycle #10 For example: + - You contribute 0.1 BTC -- Other people contribute 0.9 BTC total +- Other people contribute 0.9 BTC total - Pool has a total of 1 BTC right before cycle #10 begins, so you will earn 0.1/1 = 10% of all mining rewards in cycle #10. -### Cycle #10 +### Cycle #10 - You earn 10% of all mining rewards this cycle. - This address begins to mine STX. - BTC sent to this address during this cycle will count as contributions for cycle #11 -- By the end of cycle #10, 0.1 BTC has been spent on mining, and another 0.9 BTC was contributed, so pool now has 1.8 BTC before cycle #11. -- The BTC received before cycle #10 is now 0.9 and receives a weight of 0.9/1.8 = 50%, and you receive 10% of this, so you get a total of 5% of all mining rewards in cycle #11. +- By the end of cycle #10, 0.1 BTC has been spent on mining, and another 0.9 BTC was contributed, so pool now has 1.8 BTC before cycle #11. +- The BTC received before cycle #10 is now 0.9 and receives a weight of 0.9/1.8 = 50%, and you receive 10% of this, so you get a total of 5% of all mining rewards in cycle #11. ### Cycle #11 -- You receive 10% of all mining rewards this cycle. + +- You receive 10% of all mining rewards this cycle. - This address continues mining STX. - BTC sent to this address during this cycle will count as contributions for cycle #12 - By the end of cycle #11, another 0.1 BTC has been spent on mining, and no other BTC was contributed, so pool now has 1.7 BTC before cycle #12. - Since no other BTC was received, you still get a total of 5% of all mining rewards in cycle #12. ### Cycle #12 + - You receive 10% of all mining rewards this cycle. - This address continues mining STX. - BTC sent to this address during this cycle will count as contributions for cycle #13 - You contribute another 0.4 BTC to the pool -- By the end of cycle #12, another 0.1 BTC has been spent on mining, so there is now 2 BTC before cycle #13. -- The BTC received before cycle #10 is now 1.6 and receives a weight of 1.6 / 2.0 = 80%, and you receive 5% of this, and you just contributed 0.4 / 2.0 = 20%, so you will receive 20% + 5% * 80% = 24% of all mining rewards in cycle #13. +- By the end of cycle #12, another 0.1 BTC has been spent on mining, so there is now 2 BTC before cycle #13. +- The BTC received before cycle #10 is now 1.6 and receives a weight of 1.6 / 2.0 = 80%, and you receive 5% of this, and you just contributed 0.4 / 2.0 = 20%, so you will receive 20% + 5% \* 80% = 24% of all mining rewards in cycle #13. ### Manage Pool -On this page, you can manage a stacks mining pool. You should be able to: -- Define the btc address you want to pool on. Other people will send their btc to this address. -- See who has contributed to your pool. -- See how much time left in the "cycle". +On this page, you can manage a stacks mining pool. You should be able to: + +- Define the btc address you want to pool on. Other people will send their btc to this address. +- See who has contributed to your pool. +- See how much time left in the "cycle". ### Join Pool -On this page, you can see the mining pool you joined. You should be able to: +On this page, you can see the mining pool you joined. You should be able to: + - enter a bitcoin address to join their pool - you can also specify how many bitcoin you want to send every "cycle" -- see how much remaining time for this "cycle" \ No newline at end of file +- see how much remaining time for this "cycle" diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index fa4f1b8..0dcf308 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -182,8 +182,6 @@ export function getBalanceAtBlock(blockHeight: number): number { let transactions = getLocalPoolContributorInfo(); let index = 0; let transaction = transactions[index]; - console.log("blockHeight", blockHeight); - console.log("transaction height", transaction.blockContribution); while ( index < transactions.length && transaction.blockContribution >= blockHeight From b6be17b0567deb2db75b1baeb966ddc54e4a8f8b Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Tue, 29 Jun 2021 15:51:52 -0400 Subject: [PATCH 22/32] update readme --- README.md | 54 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 5eaacf3..f66464e 100644 --- a/README.md +++ b/README.md @@ -16,17 +16,19 @@ This pooling infrastructure assumes the following: For cycle ![](https://latex.codecogs.com/png.latex?n): -- Let ![](https://latex.codecogs.com/png.latex?X_{n-1}) be the total BTC contributed to the pool during cycle ![](https://latex.codecogs.com/png.latex?n). +- Let ![](https://latex.codecogs.com/png.latex?X_{n-1}) be the total BTC contributed to the pool during cycle ![](https://latex.codecogs.com/png.latex?n-1). -- Let ![](https://latex.codecogs.com/png.latex?Y_{n-1}) be the total BTC in the pool at the end of cycle ![](https://latex.codecogs.com/png.latex?n). +- Let ![](https://latex.codecogs.com/png.latex?Y_{n-1}) be the total BTC in the pool at the end of cycle ![](https://latex.codecogs.com/png.latex?n-1). - Let ![](https://latex.codecogs.com/png.latex?Z_{n-1}=Y_{n-1}-X_{n-1}), or the amount of BTC left in the pool after mining during cycle ![](https://latex.codecogs.com/png.latex?n-1) and not including the newest contributions in cycle ![](https://latex.codecogs.com/png.latex?n-1). -If you contributed ![](https://latex.codecogs.com/png.latex?c_{n-1}) BTC during cycle ![](https://latex.codecogs.com/png.latex?n-1), your reward percentage for cycle ![](https://latex.codecogs.com/png.latex?n) will be ![](https://latex.codecogs.com/png.latex?P_n=\frac{s_{n-1}}{X_{n-1}}\cdot\frac{X_{n-1}}{Y_{n-1}}=\frac{s_{n-1}}{Y_{n-1}}). +- If you contributed ![](https://latex.codecogs.com/png.latex?c_{n-1}) BTC during cycle ![](https://latex.codecogs.com/png.latex?n-1), your reward percentage for cycle ![](https://latex.codecogs.com/png.latex?n) will be ![](https://latex.codecogs.com/png.latex?P_n=\frac{c_{n-1}}{X_{n-1}}\cdot\frac{X_{n-1}}{Y_{n-1}}=\frac{c_{n-1}}{Y_{n-1}}). -If you contributed ![](https://latex.codecogs.com/png.latex?c_{n-k}) BTC during cycle ![](https://latex.codecogs.com/png.latex?n-k) where ![](https://latex.codecogs.com/png.latex?k>1), your reward percentage for cycle N will be ![](https://latex.codecogs.com/png.latex?\frac{P_k}{Z_{n-1}}). +- If you contributed ![](https://latex.codecogs.com/png.latex?c_{k}) BTC during cycle ![](https://latex.codecogs.com/png.latex?k) where ![](https://latex.codecogs.com/png.latex?k Date: Tue, 29 Jun 2021 15:58:57 -0400 Subject: [PATCH 23/32] update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f66464e..18aa4f9 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ For cycle ![](https://latex.codecogs.com/png.latex?n): - Let ![](https://latex.codecogs.com/png.latex?Z_{n-1}=Y_{n-1}-X_{n-1}), or the amount of BTC left in the pool after mining during cycle ![](https://latex.codecogs.com/png.latex?n-1) and not including the newest contributions in cycle ![](https://latex.codecogs.com/png.latex?n-1). -- If you contributed ![](https://latex.codecogs.com/png.latex?c_{n-1}) BTC during cycle ![](https://latex.codecogs.com/png.latex?n-1), your reward percentage for cycle ![](https://latex.codecogs.com/png.latex?n) will be ![](https://latex.codecogs.com/png.latex?P_n=\frac{c_{n-1}}{X_{n-1}}\cdot\frac{X_{n-1}}{Y_{n-1}}=\frac{c_{n-1}}{Y_{n-1}}). +- If you contributed ![](https://latex.codecogs.com/png.latex?c_{n-1}) BTC during cycle ![](https://latex.codecogs.com/png.latex?n-1), your reward percentage for cycle ![](https://latex.codecogs.com/png.latex?n) will be ![](https://latex.codecogs.com/png.latex?P_n=\frac{c_{n-1}}{X_{n-1}}*\frac{X_{n-1}}{Y_{n-1}}=\frac{c_{n-1}}{Y_{n-1}}). In other words, your reward percentage is based on how much you contributed in last cycle compared all the BTC in the pool. -- If you contributed ![](https://latex.codecogs.com/png.latex?c_{k}) BTC during cycle ![](https://latex.codecogs.com/png.latex?k) where ![](https://latex.codecogs.com/png.latex?k Date: Tue, 29 Jun 2021 16:03:25 -0400 Subject: [PATCH 24/32] update readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 18aa4f9..ff5b065 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,10 @@ For cycle ![](https://latex.codecogs.com/png.latex?n): - If you contribute during multiple cycles, your total reward percentage is the sum of your reward percentages per contribution. -Essentially, your reward for any given cycle will be weighted based on how much you contributed divided by the total amount remaining at the end of each cycle. As time goes on, bitcoin will be spent on mining and more contributors will join the pool, so your reward percentage will go down unless you contribute more. ### Example: -Pool begins mining in cycle #10. Any BTC sent to the specified address before cycle #10 begins is counted as a contribution. +Pool begins mining in cycle #10. Any BTC sent to the specified address during cycle #9 is counted as a contribution. ### Before Cycle #10 From 9516a47d18010a41d6beca3159fd0fe40f8aa0b1 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Wed, 30 Jun 2021 13:18:53 -0400 Subject: [PATCH 25/32] reward % --- .../component/PoolContributerTable.tsx | 23 ++++-- src/pages/managePool/index.tsx | 1 - .../managePool/models/poolContributerInfo.ts | 77 ++++++++++++++++--- src/services/managePool/data.d.ts | 1 + src/services/managePool/managePool.ts | 23 +++++- tests/testdata.json | 34 ++++++++ 6 files changed, 139 insertions(+), 20 deletions(-) create mode 100644 tests/testdata.json diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index b2a07de..0451bdc 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -10,6 +10,7 @@ import { getNetworkFromStorage } from "@/utils/utils"; import { getBalanceAtBlock, getCycleBlocks, + getCycleContributions, getLocalPoolBalance, } from "@/services/managePool/managePool"; const { @@ -41,6 +42,7 @@ const PoolContributerTable: React.FC = ({ title: , dataIndex: "address", copyable: true, + ellipsis: true, }, { title: ( @@ -48,6 +50,7 @@ const PoolContributerTable: React.FC = ({ ), dataIndex: "stxAddress", copyable: true, + ellipsis: true, }, { title: ( @@ -100,6 +103,15 @@ const PoolContributerTable: React.FC = ({ ); }, }, + { + title: ( + + ), + dataIndex: "rewardPercentage", + }, ]; return ( @@ -125,12 +137,13 @@ const PoolContributerTable: React.FC = ({ manualRequest={true} params={{ selectedCycle }} summary={(contributions) => { - let total = 0; - for (const contribution of contributions) { - total += contribution.contribution; - } + // let total = 0; + // for (const contribution of contributions) { + // total += contribution.contribution; + // } + let total = getCycleContributions(selectedCycle - 1); - const { endBlock } = getCycleBlocks(selectedCycle-1); + const { endBlock } = getCycleBlocks(selectedCycle - 1); const balance = getBalanceAtBlock(endBlock); return ( <> diff --git a/src/pages/managePool/index.tsx b/src/pages/managePool/index.tsx index 78d0548..b823538 100644 --- a/src/pages/managePool/index.tsx +++ b/src/pages/managePool/index.tsx @@ -39,7 +39,6 @@ const TableList: React.FC<{}> = () => { const onSubmit = async () => { const fieldsValue: FormValueType = await form.validateFields(); - console.log(fieldsValue); setFormVals({ ...formVals, ...fieldsValue }); localStorage.setItem("pooledBtcAddress", fieldsValue.poolBtcAddress); localStorage.setItem( diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index 272ac5f..74765d2 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -12,10 +12,13 @@ import { getBalance, setLocalPoolBalances, getLocalPoolBalance, + getPoolStartCycleBlocks, + getCycleContributions, } from "@/services/managePool/managePool"; import { b58ToC32 } from "c32check"; import { useState } from "react"; import { getNetworkFromStorage } from "@/utils/utils"; +import { message } from "antd"; const { balanceCoef } = require("@/services/constants"); const bitcoinjs_lib_1 = require("bitcoinjs-lib"); @@ -72,10 +75,14 @@ export default () => { const queryPoolContributerInfo = async (cycle: number) => { let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; let res: PoolContributerInfo[] = getLocalPoolContributorInfo(); - let { startBlock, endBlock } = getCycleBlocks(cycle - 1); + let { endBlock } = getCycleBlocks(cycle - 1); // get highest height from local info - const highestHeight = Math.max(...res.map((o) => o.blockContribution)); + let highestHeight = Math.max(...res.map((o) => o.blockContribution)); + // if no saved transactions yet, set start block as the pool cycle start block + if (highestHeight < 0) { + highestHeight = getPoolStartCycleBlocks().startBlock; + } let currentBalance = 0; if (endBlock > highestHeight) { @@ -84,7 +91,7 @@ export default () => { endBlock ); - let txHashes = new Set(res.map((o) => o.transactionHash)); + let txHashes = new Set(res.map((t) => t.transactionHash)); transactions.map((transaction) => { // if we already stored this transaction or its not confirmed yet, skip if (txHashes.has(transaction.hash) || transaction.block_height == -1) { @@ -127,6 +134,7 @@ export default () => { cycleContribution: getCycleForBlock(transaction.block_height), blockContribution: transaction.block_height, isContribution: true, + rewardPercentage: 0, }); } } else { @@ -138,15 +146,68 @@ export default () => { cycleContribution: getCycleForBlock(transaction.block_height), blockContribution: transaction.block_height, isContribution: false, + rewardPercentage: 0, }); } }); currentBalance = balance / balanceCoef; } else { - currentBalance = await getBalance(); + // currentBalance = await getBalance(); + } + + // sometimes API will return 0 tx for address, so only change local pool balance if we have a valid response + if (currentBalance > 0) { + setLocalPoolBalances(currentBalance); + } else { + currentBalance = getLocalPoolBalance(); + } + + let poolStartCycle = parseInt( + localStorage.getItem("poolStartCycle") ?? "-1" + ); + if (poolStartCycle == -1) { + message.error("poolStartCycle cannot be -1"); } + // cache of reward percentages per contribution + let cache = {}; + // sort from earlier contribution to later contribution + res = res + .filter( + (contribution) => contribution.cycleContribution >= poolStartCycle - 1 + ) + .sort((a, b) => (a.blockContribution > b.blockContribution ? 1 : -1)); + let currentCycle = poolStartCycle; + for (let contribution of res) { + if (!contribution.isContribution) { + continue; + } + currentCycle = contribution.cycleContribution + 1; + const totalBtcContributedLastCycle = getCycleContributions( + currentCycle - 1 + ); //X + const { endBlock } = getCycleBlocks(currentCycle - 1); + const totalBtcAtEndOfLastCycle = getBalanceAtBlock(endBlock); // Y + const totalBtcRemainingInPool = + totalBtcAtEndOfLastCycle - totalBtcContributedLastCycle; // Z + if (contribution.transactionHash in cache) { + cache[contribution.transactionHash] = + (cache[contribution.transactionHash] * totalBtcRemainingInPool) / + totalBtcAtEndOfLastCycle; + } else { + cache[contribution.transactionHash] = + contribution.contribution / totalBtcAtEndOfLastCycle; + } + contribution.rewardPercentage = cache[contribution.transactionHash]; + } + + res = res.sort((a, b) => + a.blockContribution > b.blockContribution ? 1 : -1 + ); setLocalPoolContributorInfo(res); + + const { startBlock } = getCycleBlocks(poolStartCycle - 1); + res = res.filter( (contribution) => contribution.blockContribution >= startBlock && @@ -154,14 +215,6 @@ export default () => { contribution.isContribution ); - // sometimes API will return 0 tx for address, so only change local pool balance if we have a valid response - if (currentBalance > 0) { - setLocalPoolBalances(currentBalance); - } else { - currentBalance = getLocalPoolBalance(); - } - let balanceAtEndOfCycle = getBalanceAtBlock(endBlock); - console.log("at the end of block", endBlock, "had", balanceAtEndOfCycle); return { data: res, success: true }; }; diff --git a/src/services/managePool/data.d.ts b/src/services/managePool/data.d.ts index 307345e..13629d3 100644 --- a/src/services/managePool/data.d.ts +++ b/src/services/managePool/data.d.ts @@ -106,4 +106,5 @@ export interface PoolContributerInfo { cycleContribution: number; blockContribution: number; isContribution: boolean; + rewardPercentage: number; } diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 0dcf308..2064bde 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -176,24 +176,42 @@ export async function getBalance(): Promise { ); } -// async function to get the balance? or change result of queryPoolContributerInfo +// gets total BTC in the pool at a block export function getBalanceAtBlock(blockHeight: number): number { let balance = getLocalPoolBalance(); let transactions = getLocalPoolContributorInfo(); let index = 0; let transaction = transactions[index]; + console.log(balance); while ( index < transactions.length && transaction.blockContribution >= blockHeight ) { - console.log("transaction height", transaction.blockContribution); + console.log(transaction); balance -= transaction.contribution; index += 1; transaction = transactions[index]; + console.log(balance); } return balance; } +export function getCycleContributions(cycle: number): number { + let transactions = getLocalPoolContributorInfo(); + const { startBlock, endBlock } = getCycleBlocks(cycle); + let totalContributions = 0; + for (const transaction of transactions) { + if ( + startBlock <= transaction.blockContribution && + transaction.blockContribution <= endBlock && + transaction.isContribution + ) { + totalContributions += transaction.contribution; + } + } + return totalContributions; +} + // gets pool contributors between blocks export async function getPoolContributorsHelper( startBlock: number, @@ -220,6 +238,7 @@ export async function getPoolContributorsHelper( break; } + console.log(baseURL); return request(`${baseURL}`, { method: "GET", timeout: 6000 }).then( (resp: Address) => { console.log(resp); diff --git a/tests/testdata.json b/tests/testdata.json new file mode 100644 index 0000000..a6077e3 --- /dev/null +++ b/tests/testdata.json @@ -0,0 +1,34 @@ +{ + "n3eCbsVBBHL6Ew9BvLDLm5MhXMJqBEvWkF": [ + { + "address": "output", + "stxAddress": "output", + "contribution": -0.1, + "transactionHash": "2222222222222222222222222222222222222222222222222222222222222222", + "cycleContribution": 10, + "blockContribution": 689049, + "isContribution": false, + "rewardPercentage": 0 + }, + { + "address": "38noJXruF8E5mNFL4q6FHrEVbnHwGu6sQn", + "stxAddress": "SM16Y1NT3WFQK1KB1VNJKB2MF2C1AYTSRH6PTMA5A", + "contribution": 0.9, + "transactionHash": "1111111111111111111111111111111111111111111111111111111111111111", + "cycleContribution": 9, + "blockContribution": 686910, + "isContribution": true, + "rewardPercentage": 0 + }, + { + "address": "39jfi6BLYyTvBCFBKGF1bpEgixJgV7mVaM", + "stxAddress": "SM1C42R9QVG4B9VW5F1WGCF7QDQ8ZXBKS53ZZ0T0N", + "contribution": 0.1, + "transactionHash": "0000000000000000000000000000000000000000000000000000000000000000", + "cycleContribution": 9, + "blockContribution": 686900, + "isContribution": true, + "rewardPercentage": 0 + } + ] +} From 6cabdacbed7d8c1ff707fa7b81654a2ca9d088ec Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Thu, 1 Jul 2021 04:38:04 -0400 Subject: [PATCH 26/32] fixed reward % --- .../component/PoolContributerTable.tsx | 10 ++-- .../managePool/models/poolContributerInfo.ts | 46 +++++++++++-------- src/services/managePool/managePool.ts | 3 -- tests/testdata.json | 42 ++++++++++++++++- 4 files changed, 75 insertions(+), 26 deletions(-) diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index 0451bdc..6da0da1 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -133,7 +133,7 @@ const PoolContributerTable: React.FC = ({ } columns={poolContributerColumns} request={() => queryPoolContributerInfo(selectedCycle)} - rowKey={"address"} + rowKey={"transactionHash"} manualRequest={true} params={{ selectedCycle }} summary={(contributions) => { @@ -151,13 +151,17 @@ const PoolContributerTable: React.FC = ({ Total Contributed In Last Cycle - {total} + + {total.toFixed(4)} + Total Remaining At End of Last Cycle - {balance} + + {balance.toFixed(4)} + ); diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index 74765d2..641440e 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -179,31 +179,38 @@ export default () => { .sort((a, b) => (a.blockContribution > b.blockContribution ? 1 : -1)); let currentCycle = poolStartCycle; for (let contribution of res) { - if (!contribution.isContribution) { + if ( + !contribution.isContribution || + contribution.cycleContribution >= cycle + ) { continue; } currentCycle = contribution.cycleContribution + 1; - const totalBtcContributedLastCycle = getCycleContributions( - currentCycle - 1 - ); //X - const { endBlock } = getCycleBlocks(currentCycle - 1); - const totalBtcAtEndOfLastCycle = getBalanceAtBlock(endBlock); // Y - const totalBtcRemainingInPool = - totalBtcAtEndOfLastCycle - totalBtcContributedLastCycle; // Z - if (contribution.transactionHash in cache) { - cache[contribution.transactionHash] = - (cache[contribution.transactionHash] * totalBtcRemainingInPool) / - totalBtcAtEndOfLastCycle; - } else { - cache[contribution.transactionHash] = - contribution.contribution / totalBtcAtEndOfLastCycle; + for (currentCycle; currentCycle <= cycle; currentCycle += 1) { + const totalBtcContributedLastCycle = getCycleContributions( + currentCycle - 1 + ); //X + const { endBlock } = getCycleBlocks(currentCycle - 1); + const totalBtcAtEndOfLastCycle = getBalanceAtBlock(endBlock); // Y + const totalBtcRemainingInPool = + totalBtcAtEndOfLastCycle - totalBtcContributedLastCycle; // Z + if (contribution.transactionHash in cache) { + cache[contribution.transactionHash] = + (cache[contribution.transactionHash] * totalBtcRemainingInPool) / + totalBtcAtEndOfLastCycle; + } else { + cache[contribution.transactionHash] = + contribution.contribution / totalBtcAtEndOfLastCycle; + } } - contribution.rewardPercentage = cache[contribution.transactionHash]; + contribution.rewardPercentage = + cache[contribution.transactionHash].toFixed(4); } - res = res.sort((a, b) => - a.blockContribution > b.blockContribution ? 1 : -1 - ); + res = res + .slice() + .sort((a, b) => (a.blockContribution > b.blockContribution ? 1 : -1)); + console.log(res); setLocalPoolContributorInfo(res); const { startBlock } = getCycleBlocks(poolStartCycle - 1); @@ -214,6 +221,7 @@ export default () => { contribution.blockContribution <= endBlock && contribution.isContribution ); + console.log(res.slice()); return { data: res, success: true }; }; diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 2064bde..320d766 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -182,16 +182,13 @@ export function getBalanceAtBlock(blockHeight: number): number { let transactions = getLocalPoolContributorInfo(); let index = 0; let transaction = transactions[index]; - console.log(balance); while ( index < transactions.length && transaction.blockContribution >= blockHeight ) { - console.log(transaction); balance -= transaction.contribution; index += 1; transaction = transactions[index]; - console.log(balance); } return balance; } diff --git a/tests/testdata.json b/tests/testdata.json index a6077e3..9e1f9e2 100644 --- a/tests/testdata.json +++ b/tests/testdata.json @@ -1,12 +1,52 @@ { "n3eCbsVBBHL6Ew9BvLDLm5MhXMJqBEvWkF": [ + { + "address": "output", + "stxAddress": "output", + "contribution": -0.1, + "transactionHash": "6666666666666666666666666666666666666666666666666666666666666666", + "cycleContribution": 12, + "blockContribution": 691162, + "isContribution": false, + "rewardPercentage": 0 + }, + { + "address": "39jfi6BLYyTvBCFBKGF1bpEgixJgV7mVaM", + "stxAddress": "SM1C42R9QVG4B9VW5F1WGCF7QDQ8ZXBKS53ZZ0T0N", + "contribution": 0.4, + "transactionHash": "5555555555555555555555555555555555555555555555555555555555555555", + "cycleContribution": 12, + "blockContribution": 691155, + "isContribution": true, + "rewardPercentage": 0 + }, + { + "address": "output", + "stxAddress": "output", + "contribution": -0.1, + "transactionHash": "4444444444444444444444444444444444444444444444444444444444444444", + "cycleContribution": 11, + "blockContribution": 689051, + "isContribution": false, + "rewardPercentage": 0 + }, + { + "address": "38noJXruF8E5mNFL4q6FHrEVbnHwGu6sQn", + "stxAddress": "SM16Y1NT3WFQK1KB1VNJKB2MF2C1AYTSRH6PTMA5A", + "contribution": 0.9, + "transactionHash": "3333333333333333333333333333333333333333333333333333333333333333", + "cycleContribution": 10, + "blockContribution": 689048, + "isContribution": true, + "rewardPercentage": 0 + }, { "address": "output", "stxAddress": "output", "contribution": -0.1, "transactionHash": "2222222222222222222222222222222222222222222222222222222222222222", "cycleContribution": 10, - "blockContribution": 689049, + "blockContribution": 689040, "isContribution": false, "rewardPercentage": 0 }, From bdc05b55596f0496986f78ead6744aafab3e3eae Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Sun, 11 Jul 2021 19:05:26 -0400 Subject: [PATCH 27/32] add send reward button --- src/components/RightContent/SwitchNetwork.tsx | 2 ++ .../component/PoolContributerTable.tsx | 28 +++++++++++-------- src/services/managePool/managePool.ts | 3 +- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/components/RightContent/SwitchNetwork.tsx b/src/components/RightContent/SwitchNetwork.tsx index 3995e32..5e5e429 100644 --- a/src/components/RightContent/SwitchNetwork.tsx +++ b/src/components/RightContent/SwitchNetwork.tsx @@ -41,6 +41,7 @@ const SwitchNetwork: React.FC = () => { setNetworkName("Xenon"); message.info(`Switch to Xenon network`); changeNetworkDAO("Xenon"); + localStorage.removeItem("pooledBtcAddress") window.location.reload(); // switchPage('Xenon'); break; @@ -48,6 +49,7 @@ const SwitchNetwork: React.FC = () => { case "Mainnet": { setNetworkName("Mainnet"); message.info(`Switch to Mainnet network`); + localStorage.removeItem("pooledBtcAddress") changeNetworkDAO("Mainnet"); window.location.reload(); // switchPage('Xenon'); diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index 6da0da1..fbeabd6 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react"; import ProTable, { ProColumns } from "@ant-design/pro-table"; import { FormattedMessage, useModel } from "umi"; import { BlockInfo, TxInfo } from "@/services/publicdata/data"; -import { Tag, Card, InputNumber, Button, Table } from "antd"; +import { Tag, Card, InputNumber, Button, Table, Tooltip } from "antd"; import { getBlockInfo, getTxsInfo } from "@/services/publicdata/chainInfo"; import { PoolContributerInfo } from "@/services/managePool/data"; import { showMessage } from "@/services/locale"; @@ -117,12 +117,22 @@ const PoolContributerTable: React.FC = ({ return ( <> - View Contributors for Cycle: - +
+
+ {showMessage("TODO", "View Contributors for Cycle:")} + +
+
+ {showMessage("TODO", "Send Rewards")} + + + +
+
headerTitle={ @@ -137,10 +147,6 @@ const PoolContributerTable: React.FC = ({ manualRequest={true} params={{ selectedCycle }} summary={(contributions) => { - // let total = 0; - // for (const contribution of contributions) { - // total += contribution.contribution; - // } let total = getCycleContributions(selectedCycle - 1); const { endBlock } = getCycleBlocks(selectedCycle - 1); diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 320d766..4371e9e 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -158,7 +158,7 @@ export async function getBalance(): Promise { break; } case "Mainnet": { - let pooledBtcAddress = "1BFfc2e6Kk82ut7S3C5yaN3pWRxEFRLLu5"; +// let pooledBtcAddress = "1BFfc2e6Kk82ut7S3C5yaN3pWRxEFRLLu5"; baseURL = `${bitcoinMainnet2}/addrs/${pooledBtcAddress}/balance`; break; } @@ -227,7 +227,6 @@ export async function getPoolContributorsHelper( break; } case "Mainnet": { - let pooledBtcAddress = "1BFfc2e6Kk82ut7S3C5yaN3pWRxEFRLLu5"; baseURL = `${bitcoinMainnet2}/addrs/${pooledBtcAddress}/full?limit=50&before=${endBlock}&after=${startBlock}`; break; } From 45d8c22023f3ced2e8e82f6e40f9c202555346b9 Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Mon, 12 Jul 2021 18:03:22 -0400 Subject: [PATCH 28/32] preparing for send stx button --- .../component/PoolContributerTable.tsx | 112 ++++++++++++------ src/pages/managePool/index.tsx | 10 +- .../managePool/models/poolContributerInfo.ts | 48 ++------ src/services/constants.ts | 4 +- src/services/managePool/data.d.ts | 34 ++++++ src/services/managePool/managePool.ts | 62 ++++------ src/services/wallet/account.ts | 11 +- 7 files changed, 152 insertions(+), 129 deletions(-) diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index fbeabd6..c10e892 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -1,41 +1,67 @@ import React, { useEffect, useState } from "react"; import ProTable, { ProColumns } from "@ant-design/pro-table"; import { FormattedMessage, useModel } from "umi"; -import { BlockInfo, TxInfo } from "@/services/publicdata/data"; -import { Tag, Card, InputNumber, Button, Table, Tooltip } from "antd"; -import { getBlockInfo, getTxsInfo } from "@/services/publicdata/chainInfo"; -import { PoolContributerInfo } from "@/services/managePool/data"; +import { Card, InputNumber, Button, Table, Tooltip } from "antd"; +import { PoolContributerInfo, StxBalances } from "@/services/managePool/data"; import { showMessage } from "@/services/locale"; import { getNetworkFromStorage } from "@/utils/utils"; import { getBalanceAtBlock, getCycleBlocks, getCycleContributions, - getLocalPoolBalance, + getBtcHeight, } from "@/services/managePool/managePool"; -const { - sidecarURLXenon, - sidecarURLMainnet, - bitcoinTestnet3, - bitcoinMainnet2, - firstStackingBlock, -} = require("@/services/constants"); +import { getStxBalance } from "@/services/wallet/account"; +import { getCurrentCycle } from "@/services/managePool/managePool"; +const { bitcoinTestnet3, stxBalanceCoef } = require("@/services/constants"); +import { b58ToC32 } from "c32check"; -interface PoolContributerTableProps { - cycle: number; -} -const PoolContributerTable: React.FC = ({ - cycle, -}) => { +const PoolContributerTable: React.FC<{}> = () => { const { queryPoolContributerInfo } = useModel( "managePool.poolContributerInfo" ); - const [selectedCycle, setSelectedCycle] = useState(cycle); + const [currentCycle, setCurrentCycle] = useState(-1); + const [selectedCycle, setSelectedCycle] = useState(currentCycle); + const [stxBalance, setStxBalance] = useState(0); + const [currentBtcHeight, setBtcHeight] = useState(0); useEffect(() => { - setSelectedCycle(cycle); - }, [cycle]); + let pooledBtcAddress = localStorage.getItem("pooledBtcAddress"); + if (pooledBtcAddress) { + getStxBalance(b58ToC32(pooledBtcAddress)).then((resp: StxBalances) => + setStxBalance(parseFloat(resp.stx.balance) / stxBalanceCoef) + ); + } + + getCurrentCycle().then(({ cycle }) => { + setCurrentCycle(cycle); + setSelectedCycle(cycle); + }); + + getBtcHeight().then((height) => setBtcHeight(height)); + }, []); + + const getDisabledReason = (): string => { + // TODO: if rewards were already sent out, disable button + const { endBlock } = getCycleBlocks(currentCycle - 1); + if (currentBtcHeight < endBlock + 100) { + return showMessage( + "TODO", + "Can only send rewards after 100 blocks after end of last cycle" + ); + } + return ""; + }; + + const disabledReason = getDisabledReason(); + + const canSendRewards = (): boolean => { + if (selectedCycle != currentCycle - 1) { + return false; + } + return true; + }; const poolContributerColumns: ProColumns[] = [ { @@ -117,22 +143,36 @@ const PoolContributerTable: React.FC = ({ return ( <> -
-
- {showMessage("TODO", "View Contributors for Cycle:")} - -
-
- {showMessage("TODO", "Send Rewards")} - - - -
+
+ {showMessage("TODO", "View Contributors for Cycle:")} +
+ + {canSendRewards() && ( +
+
+ {showMessage("TODO", "STX to send: ")} +
+
+ +
+
+ + + +
+
+ )} headerTitle={ diff --git a/src/pages/managePool/index.tsx b/src/pages/managePool/index.tsx index b823538..4d91076 100644 --- a/src/pages/managePool/index.tsx +++ b/src/pages/managePool/index.tsx @@ -19,7 +19,6 @@ import { showMessage, switchConfigProviderLocale } from "@/services/locale"; import FormItem from "antd/lib/form/FormItem"; import { FormattedMessage } from "react-intl"; import PoolContributerTable from "./component/PoolContributerTable"; -import { getCurrentCycle } from "@/services/managePool/managePool"; export interface FormValueType { poolBtcAddress: string; poolStartCycle: number; @@ -35,7 +34,6 @@ const TableList: React.FC<{}> = () => { const [accounts, setAccounts] = useState([]); const [loadingAccounts, setLoadingAccounts] = useState(true); - const [currentCycle, setCurrentCycle] = useState(1); const onSubmit = async () => { const fieldsValue: FormValueType = await form.validateFields(); @@ -58,12 +56,6 @@ const TableList: React.FC<{}> = () => { setLoadingAccounts(false); }); - getCurrentCycle().then(({ cycle }) => { - setCurrentCycle(cycle); - if (formVals.poolStartCycle == -1) { - setFormVals({ ...formVals, ...{ poolCycleStart: cycle } }); - } - }); }, []); const renderForm = () => { @@ -149,7 +141,7 @@ const TableList: React.FC<{}> = () => { {isPooling && renderForm()} {isPooling && } - {isPooling && } + {isPooling && } ); diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index 641440e..b59fd7c 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -9,18 +9,18 @@ import { getLocalPoolContributorInfo, setLocalPoolContributorInfo, getBalanceAtBlock, - getBalance, setLocalPoolBalances, getLocalPoolBalance, getPoolStartCycleBlocks, getCycleContributions, } from "@/services/managePool/managePool"; -import { b58ToC32 } from "c32check"; import { useState } from "react"; -import { getNetworkFromStorage } from "@/utils/utils"; import { message } from "antd"; -const { balanceCoef } = require("@/services/constants"); +import { getStxAddressFromPublicKey } from "@/services/wallet/key"; +import { getNetworkFromStorage } from "@/utils/utils"; +const { btcBalanceCoef } = require("@/services/constants"); const bitcoinjs_lib_1 = require("bitcoinjs-lib"); +import { b58ToC32 } from "c32check"; // if transaction positive, this was an input / contribution, else output / spent on mining const getTransactionValue = ( @@ -45,30 +45,6 @@ const getTransactionValue = ( return value; }; -// taken from BlockstackNetwork -const coerceAddress = (address: string) => { - const { hash, version } = bitcoinjs_lib_1.address.fromBase58Check(address); - const scriptHashes = [ - bitcoinjs_lib_1.networks.bitcoin.scriptHash, - bitcoinjs_lib_1.networks.testnet.scriptHash, - ]; - const pubKeyHashes = [ - bitcoinjs_lib_1.networks.bitcoin.pubKeyHash, - bitcoinjs_lib_1.networks.testnet.pubKeyHash, - ]; - let coercedVersion; - if (scriptHashes.indexOf(version) >= 0) { - coercedVersion = bitcoinjs_lib_1.networks.bitcoin.scriptHash; - } else if (pubKeyHashes.indexOf(version) >= 0) { - coercedVersion = bitcoinjs_lib_1.networks.bitcoin.pubKeyHash; - } else { - throw new Error( - `Unrecognized address version number ${version} in ${address}` - ); - } - return bitcoinjs_lib_1.address.toBase58Check(hash, coercedVersion); -}; - export default () => { let [poolContributerInfoState, setPoolContributerInfoState] = useState(); @@ -112,16 +88,6 @@ export default () => { let stxAddress = input.addresses[0]; // BECH32 not supported try { - switch (getNetworkFromStorage()) { - case "Xenon": { - address = coerceAddress(address); - break; - } - case "Mainnet": - break; - default: - break; - } stxAddress = b58ToC32(address); } catch (err) { stxAddress = "UNSUPPORTED"; @@ -129,7 +95,7 @@ export default () => { res.push({ address: address, // TODO: deal with edge case where input has multiple addresses? stxAddress: stxAddress, // b58ToC32(input.addresses[0]), - contribution: weightedContribution / balanceCoef, + contribution: weightedContribution / btcBalanceCoef, transactionHash: transaction.hash, cycleContribution: getCycleForBlock(transaction.block_height), blockContribution: transaction.block_height, @@ -141,7 +107,7 @@ export default () => { res.push({ address: "output", stxAddress: "output", - contribution: contribution / balanceCoef, + contribution: contribution / btcBalanceCoef, transactionHash: transaction.hash, cycleContribution: getCycleForBlock(transaction.block_height), blockContribution: transaction.block_height, @@ -150,7 +116,7 @@ export default () => { }); } }); - currentBalance = balance / balanceCoef; + currentBalance = balance / btcBalanceCoef; } else { // currentBalance = await getBalance(); } diff --git a/src/services/constants.ts b/src/services/constants.ts index a2e4e87..8036d59 100644 --- a/src/services/constants.ts +++ b/src/services/constants.ts @@ -51,5 +51,7 @@ module.exports = { // pooling firstStackingBlock: 668050, - balanceCoef : 100000000 + btcBalanceCoef: 100000000, + stxBalanceCoef: 1000000 + } diff --git a/src/services/managePool/data.d.ts b/src/services/managePool/data.d.ts index 13629d3..e3fbdc0 100644 --- a/src/services/managePool/data.d.ts +++ b/src/services/managePool/data.d.ts @@ -108,3 +108,37 @@ export interface PoolContributerInfo { isContribution: boolean; rewardPercentage: number; } + +export interface StxBalance { + balance: string; + total_sent: string; + total_received: string; + total_fees_sent: string; + total_miner_rewards_received: string; + lock_tx_id: string; + locked: string; + lock_height: integer; + burnchain_lock_height: integer; + burnchain_unlock_height: integer; +} + +export interface StxBalances { + stx: StxBalance; +} + +export interface BtcInfo { + name: string; + height: number; + hash: string; + time: string; + latest_url: string; + previous_hash: string; + previous_url: string; + peer_count: number; + high_fee_per_kb: number; + medium_fee_per_kb: number; + low_fee_per_kb: number; + unconfirmed_count: number; + last_fork_height?: number; + last_fork_hash?: string; +} diff --git a/src/services/managePool/managePool.ts b/src/services/managePool/managePool.ts index 4371e9e..ea86a00 100644 --- a/src/services/managePool/managePool.ts +++ b/src/services/managePool/managePool.ts @@ -1,6 +1,6 @@ import { getNetworkFromStorage } from "@/utils/utils"; import request from "umi-request"; -import { Address, Tx, PoolContributerInfo } from "./data"; +import { Address, Tx, PoolContributerInfo, BtcInfo } from "./data"; import { message } from "antd"; const { sidecarURLXenon, @@ -8,7 +8,7 @@ const { bitcoinTestnet3, bitcoinMainnet2, firstStackingBlock, - balanceCoef, + btcBalanceCoef, } = require("@/services/constants"); export interface PoolContributerInfoState { @@ -144,38 +144,6 @@ export const setLocalPoolContributorInfo = ( } }; -// sometimes the api will return 0 balance and 0 tx, so just return -1 if that happens -export async function getBalance(): Promise { - let baseURL = sidecarURLXenon; - let pooledBtcAddress = localStorage.getItem("pooledBtcAddress")!; - - switch (getNetworkFromStorage()) { - case "Xenon": { - //TODO: remember to add before and after - // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}&limit=2000`; - baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/balance`; - // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50`; - break; - } - case "Mainnet": { -// let pooledBtcAddress = "1BFfc2e6Kk82ut7S3C5yaN3pWRxEFRLLu5"; - baseURL = `${bitcoinMainnet2}/addrs/${pooledBtcAddress}/balance`; - break; - } - default: - break; - } - return request(`${baseURL}`, { method: "GET", timeout: 6000 }).then( - (resp: Address) => { - console.log(resp); - if (resp.n_tx == 0 && getLocalPoolBalance() > 0) { - return -1; - } - return resp.balance / balanceCoef; - } - ); -} - // gets total BTC in the pool at a block export function getBalanceAtBlock(blockHeight: number): number { let balance = getLocalPoolBalance(); @@ -209,6 +177,29 @@ export function getCycleContributions(cycle: number): number { return totalContributions; } +export async function getBtcHeight(): Promise { + let baseURL = sidecarURLXenon; + + switch (getNetworkFromStorage()) { + case "Xenon": { + baseURL = `${bitcoinTestnet3}`; + break; + } + case "Mainnet": { + baseURL = `${bitcoinMainnet2}`; + break; + } + default: + break; + } + return request(`${baseURL}`, { method: "GET", timeout: 6000 }).then( + (resp: BtcInfo) => { + console.log(resp); + return resp.height; + } + ); +} + // gets pool contributors between blocks export async function getPoolContributorsHelper( startBlock: number, @@ -222,7 +213,7 @@ export async function getPoolContributorsHelper( case "Xenon": { //TODO: remember to add before and after // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}?before=${endBlock}&after=${startBlock}&limit=2000`; - baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50&before=${endBlock}&after=${startBlock}&confidence=99`; + baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50&before=${endBlock}&after=${startBlock}&confidence=99&token=18b85235d6544c67932698c98ed17317`; // baseURL = `${bitcoinTestnet3}/addrs/${pooledBtcAddress}/full?limit=50`; break; } @@ -233,7 +224,6 @@ export async function getPoolContributorsHelper( default: break; } - console.log(baseURL); return request(`${baseURL}`, { method: "GET", timeout: 6000 }).then( (resp: Address) => { diff --git a/src/services/wallet/account.ts b/src/services/wallet/account.ts index 7ca3119..1153df9 100644 --- a/src/services/wallet/account.ts +++ b/src/services/wallet/account.ts @@ -6,7 +6,7 @@ import { message } from 'antd'; import { aes256Encrypt, keyGen } from '@/utils/utils'; import { showMessage } from "@/services/locale"; -const { btcType, stxType } = require('@/services/constants'); +const { btcType, stxType, btcBalanceCoef } = require('@/services/constants'); const { sidecarURLXenon, sidecarURLMainnet, bitcoinTestnet3, bitcoinMainnet } = require('@/services/constants') @@ -53,36 +53,35 @@ export async function getStxBalance(stxAddress: string) { export async function getBtcBalance(btcAddress: string) { let baseURL = sidecarURLXenon; - let balanceCoef = 1; // https://api.blockcypher.com/v1/btc/test3/addrs/mzYBtAjNzuEvEMAp2ahx8oT9kWWvb5L2Rj/balance switch (getNetworkFromStorage()) { //{"balance":0} case "Xenon": { baseURL = `${bitcoinTestnet3}/addrs/${btcAddress}/balance` //`${sidecarURLXenon}/v1/faucets/btc/${btcAddress}`; - balanceCoef = 100000000 return request(`${baseURL}`, { method: "GET", timeout: 6000, }).then((resp) => { - return { 'balance': (resp.final_balance / balanceCoef).toString() }; + return { 'balance': (resp.final_balance / btcBalanceCoef).toString() }; }).catch(err => { console.log(err) + message.error("Failed to get Btc balance"); return { 'balance': 'NaN' }; }); } case "Mainnet": { baseURL = `${bitcoinMainnet}/balance?active=${btcAddress}&cors=true`; //`${sidecarURLXenon}/v1/faucets/btc/${btcAddress}`; - balanceCoef = 100000000 return request(`${baseURL}`, { method: "GET", timeout: 10000, }).then((resp) => { - return { 'balance': (resp[`${btcAddress}`].final_balance / balanceCoef).toString() }; + return { 'balance': (resp[`${btcAddress}`].final_balance / btcBalanceCoef).toString() }; }).catch(err => { console.log(err) + message.error("Failed to get Btc balance"); return { 'balance': 'NaN' }; }); } From 9cb113be7186c69ec27cf4525413427af0b179aa Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Mon, 12 Jul 2021 19:13:29 -0400 Subject: [PATCH 29/32] remove send button for now --- src/pages/managePool/component/PoolContributerTable.tsx | 6 ++++-- tests/testPoolBalances.json | 1 + tests/{testdata.json => testPoolContributors.json} | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 tests/testPoolBalances.json rename tests/{testdata.json => testPoolContributors.json} (98%) diff --git a/src/pages/managePool/component/PoolContributerTable.tsx b/src/pages/managePool/component/PoolContributerTable.tsx index c10e892..888598e 100644 --- a/src/pages/managePool/component/PoolContributerTable.tsx +++ b/src/pages/managePool/component/PoolContributerTable.tsx @@ -51,7 +51,7 @@ const PoolContributerTable: React.FC<{}> = () => { "Can only send rewards after 100 blocks after end of last cycle" ); } - return ""; + return "Not implemented yet"; }; const disabledReason = getDisabledReason(); @@ -152,7 +152,8 @@ const PoolContributerTable: React.FC<{}> = () => { />
- {canSendRewards() && ( + {/* {canSendRewards() && ( */} + {false && (
{showMessage("TODO", "STX to send: ")} @@ -166,6 +167,7 @@ const PoolContributerTable: React.FC<{}> = () => {
+ {/*TODO: add functionality for send many */} diff --git a/tests/testPoolBalances.json b/tests/testPoolBalances.json new file mode 100644 index 0000000..57527b2 --- /dev/null +++ b/tests/testPoolBalances.json @@ -0,0 +1 @@ +{ "1NG4ZgJaGrvDLuyxgdjVWaeaZbvnS8EhQn": 2 } diff --git a/tests/testdata.json b/tests/testPoolContributors.json similarity index 98% rename from tests/testdata.json rename to tests/testPoolContributors.json index 9e1f9e2..1b82f61 100644 --- a/tests/testdata.json +++ b/tests/testPoolContributors.json @@ -1,5 +1,5 @@ { - "n3eCbsVBBHL6Ew9BvLDLm5MhXMJqBEvWkF": [ + "1NG4ZgJaGrvDLuyxgdjVWaeaZbvnS8EhQn": [ { "address": "output", "stxAddress": "output", From e58d54e7b0d0deaf3e9a4652fdbe91818aa3d33c Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Mon, 12 Jul 2021 20:35:25 -0400 Subject: [PATCH 30/32] update reward % --- src/pages/managePool/models/poolContributerInfo.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/managePool/models/poolContributerInfo.ts b/src/pages/managePool/models/poolContributerInfo.ts index b59fd7c..9bd6d1d 100644 --- a/src/pages/managePool/models/poolContributerInfo.ts +++ b/src/pages/managePool/models/poolContributerInfo.ts @@ -170,7 +170,7 @@ export default () => { } } contribution.rewardPercentage = - cache[contribution.transactionHash].toFixed(4); + cache[contribution.transactionHash].toFixed(4) * 100; } res = res From 0a9daa67beb5c9b0a8ac9fc6aa0a002bd061bc0f Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Mon, 12 Jul 2021 20:44:34 -0400 Subject: [PATCH 31/32] update readme --- README.md | 21 ++------------------- config/config.ts | 12 ++++++------ 2 files changed, 8 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index ff5b065..1fcc3f9 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ For cycle ![](https://latex.codecogs.com/png.latex?n): - If you contribute during multiple cycles, your total reward percentage is the sum of your reward percentages per contribution. - ### Example: Pool begins mining in cycle #10. Any BTC sent to the specified address during cycle #9 is counted as a contribution. @@ -80,22 +79,6 @@ For example: - ![](https://latex.codecogs.com/png.latex?n=13) - You contribute another 0.4 BTC to the pool - For example, let's say by the end of cycle #12, another 0.1 BTC has been spent on mining, so there is now 2 BTC before cycle #13 (![](https://latex.codecogs.com/png.latex?X_{12}=0.4,Y_{12}=2,Z_{12}=2.0-0.4=1.6)). -- Your contribution during cycle 12 gives you a cycle 13 reward percentage of ![](https://latex.codecogs.com/png.latex?P_{13}=P_{12}\frac{Z_{12}}{Y_{12}}=0.05*\frac{1.6}{2.0}=0.04) -- Your contribution during cycle 9 gives you a cycle 13 reward percentage of ![](https://latex.codecogs.com/png.latex?P_{13}=\frac{c_{12}}{Y_{12}}=\frac{0.4}{2.0}=0.2) +- Your contribution during cycle 12 gives you a cycle 13 reward percentage of ![](https://latex.codecogs.com/png.latex?P_{13}=P_{12}\frac{Z_{12}}{Y_{12}}=0.05*\frac{1.6}{2.0}=0.04) +- Your contribution during cycle 9 gives you a cycle 13 reward percentage of ![](https://latex.codecogs.com/png.latex?P_{13}=\frac{c_{12}}{Y_{12}}=\frac{0.4}{2.0}=0.2) - Your total reward percentage will be 0.04 + 0.2 = 0.24 of all mining rewards in cycle 13. - -### Manage Pool - -On this page, you can manage a stacks mining pool. You should be able to: - -- Define the btc address you want to pool on. Other people will send their btc to this address. -- See who has contributed to your pool. -- See how much time left in the "cycle". - -### Join Pool - -On this page, you can see the mining pool you joined. You should be able to: - -- enter a bitcoin address to join their pool -- you can also specify how many bitcoin you want to send every "cycle" -- see how much remaining time for this "cycle" diff --git a/config/config.ts b/config/config.ts index 78ae47f..a6198fc 100644 --- a/config/config.ts +++ b/config/config.ts @@ -74,12 +74,12 @@ export default defineConfig({ icon: 'TeamOutlined', component: './managePool' }, - { - path: '/joinPool', - name: 'joinPool', - icon: 'UserAddOutlined', - component: './joinPool' - }, +// { +// path: '/joinPool', +// name: 'joinPool', +// icon: 'UserAddOutlined', +// component: './joinPool' +// }, { path: '/', redirect: `/publicData`, From 1a775f95e3557be8df1838da69b0ab98099511bd Mon Sep 17 00:00:00 2001 From: Daniel Zhou Date: Mon, 12 Jul 2021 21:20:01 -0400 Subject: [PATCH 32/32] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1fcc3f9..b247337 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ For cycle ![](https://latex.codecogs.com/png.latex?n): - Let ![](https://latex.codecogs.com/png.latex?Z_{n-1}=Y_{n-1}-X_{n-1}), or the amount of BTC left in the pool after mining during cycle ![](https://latex.codecogs.com/png.latex?n-1) and not including the newest contributions in cycle ![](https://latex.codecogs.com/png.latex?n-1). -- If you contributed ![](https://latex.codecogs.com/png.latex?c_{n-1}) BTC during cycle ![](https://latex.codecogs.com/png.latex?n-1), your reward percentage for cycle ![](https://latex.codecogs.com/png.latex?n) will be ![](https://latex.codecogs.com/png.latex?P_n=\frac{c_{n-1}}{X_{n-1}}*\frac{X_{n-1}}{Y_{n-1}}=\frac{c_{n-1}}{Y_{n-1}}). In other words, your reward percentage is based on how much you contributed in last cycle compared all the BTC in the pool. +- If you contributed ![](https://latex.codecogs.com/png.latex?c_{n-1}) BTC during cycle ![](https://latex.codecogs.com/png.latex?n-1), your reward percentage for cycle ![](https://latex.codecogs.com/png.latex?n) will be ![](https://latex.codecogs.com/png.latex?P_n=\frac{c_{n-1}}{X_{n-1}}*\frac{X_{n-1}}{Y_{n-1}}=\frac{c_{n-1}}{Y_{n-1}}). In other words, your reward percentage is based on how much you contributed in last cycle compared to all the BTC in the pool. - If you contributed ![](https://latex.codecogs.com/png.latex?c_{k}) BTC during cycle ![](https://latex.codecogs.com/png.latex?k) where ![](https://latex.codecogs.com/png.latex?k