Fixes and Orchestrator info added

This commit is contained in:
Marco van Dijk 2022-03-03 22:25:54 +01:00
parent c317eef732
commit 019f8ddb3b
8 changed files with 114 additions and 71 deletions

View File

@ -240,6 +240,7 @@ apiRouter.get("/getEvents", async (req, res) => {
}); });
const parseOrchestrator = async function (reqAddr) { const parseOrchestrator = async function (reqAddr) {
reqAddr = reqAddr.toLowerCase();
const now = new Date().getTime(); const now = new Date().getTime();
// Default assume it's the first time we request this Orchestrator // Default assume it's the first time we request this Orchestrator
let wasCached = false; let wasCached = false;
@ -248,6 +249,8 @@ const parseOrchestrator = async function (reqAddr) {
// First get cached object // First get cached object
for (var orch of orchestratorCache) { for (var orch of orchestratorCache) {
if (orch.addr == reqAddr) { if (orch.addr == reqAddr) {
console.log("found cached obj");
console.log(orch);
wasCached = true; wasCached = true;
orchestratorObj = orch; orchestratorObj = orch;
break; break;
@ -256,6 +259,9 @@ const parseOrchestrator = async function (reqAddr) {
if (wasCached) { if (wasCached) {
if (now - orch.lastGet < timeoutTheGraph) { if (now - orch.lastGet < timeoutTheGraph) {
needsUpdate = false; needsUpdate = false;
console.log("cached obj is up to date");
}else{
console.log("cached obj needs update");
} }
} }
if (!wasCached || needsUpdate) { if (!wasCached || needsUpdate) {
@ -300,17 +306,23 @@ const parseOrchestrator = async function (reqAddr) {
} }
`; `;
orchestratorObj = JSON.stringify(await request("https://api.thegraph.com/subgraphs/name/livepeer/arbitrum-one", orchQuery)); orchestratorObj = JSON.stringify(await request("https://api.thegraph.com/subgraphs/name/livepeer/arbitrum-one", orchQuery));
console.log("downloaded new obj");
console.log(orchestratorObj);
if (wasCached) { if (wasCached) {
for (var orch of orchestratorCache) { for (var orch of orchestratorCache) {
if (orch.addr == requestedOrchestrator) { if (orch.addr == requestedOrchestrator) {
console.log("modifying existing obj in cache");
orch = orchestratorObj; orch = orchestratorObj;
break; break;
} }
} }
} else { } else {
console.log("pushing this obj to cache");
orchestratorCache.push(orchestratorObj); orchestratorCache.push(orchestratorObj);
} }
} }
console.log("returning obj");
console.log(orchestratorObj);
return orchestratorObj; return orchestratorObj;
} }

View File

@ -62,6 +62,7 @@ export const getCurrentOrchestratorInfo = () => async dispatch => {
export const getOrchestratorInfo = (orchAddr) => async dispatch => { export const getOrchestratorInfo = (orchAddr) => async dispatch => {
const response = await apiUtil.getOrchestratorInfo(orchAddr); const response = await apiUtil.getOrchestratorInfo(orchAddr);
const data = await response.json(); const data = await response.json();
console.log(data);
if (response.ok) { if (response.ok) {
return dispatch(setOrchestratorInfo(data)); return dispatch(setOrchestratorInfo(data));
} }

View File

@ -29,9 +29,9 @@ const EventButton = (obj) => {
thisData.map(eventObj => { thisData.map(eventObj => {
// Bond: contains amount the transaction is about and who is participating // Bond: contains amount the transaction is about and who is participating
if (eventObj.name == "Bond") { if (eventObj.name == "Bond") {
transactionCaller = eventObj.data.delegator; transactionCaller = eventObj.data.delegator.toLowerCase();
transactionFrom = eventObj.data.oldDelegate; transactionFrom = eventObj.data.oldDelegate.toLowerCase();
transactionTo = eventObj.data.newDelegate; transactionTo = eventObj.data.newDelegate.toLowerCase();
transactionAmount = parseFloat(eventObj.data.bondedAmount); transactionAmount = parseFloat(eventObj.data.bondedAmount);
transactionAdditionalAmount = parseFloat(eventObj.data.additionalAmount); transactionAdditionalAmount = parseFloat(eventObj.data.additionalAmount);
hasBondTransaction = true; hasBondTransaction = true;
@ -41,7 +41,7 @@ const EventButton = (obj) => {
transactionName = "Activated"; transactionName = "Activated";
transactionWhen = eventObj.data.activationRound; transactionWhen = eventObj.data.activationRound;
if (!hasBondTransaction) { if (!hasBondTransaction) {
transactionCaller = eventObj.data.transcoder; transactionCaller = eventObj.data.transcoder.toLowerCase();
} }
thisColour = activationColour; thisColour = activationColour;
isOnlyBond = false; isOnlyBond = false;
@ -49,7 +49,7 @@ const EventButton = (obj) => {
// TranscoderActivated: defines transactionName. Defines transactionAmount as X / 1000000000000000000 LPT // TranscoderActivated: defines transactionName. Defines transactionAmount as X / 1000000000000000000 LPT
if (eventObj.name == "Reward") { if (eventObj.name == "Reward") {
transactionName = "Reward"; transactionName = "Reward";
transactionCaller = eventObj.data.transcoder; transactionCaller = eventObj.data.transcoder.toLowerCase();
transactionAmount = eventObj.data.amount / 1000000000000000000; transactionAmount = eventObj.data.amount / 1000000000000000000;
thisColour = rewardColour; thisColour = rewardColour;
isOnlyBond = false; isOnlyBond = false;
@ -57,7 +57,7 @@ const EventButton = (obj) => {
// TranscoderUpdate: defines transactionName. Defines transactionAmount as rewardCut and transactionAdditionalAmount as feeCut // TranscoderUpdate: defines transactionName. Defines transactionAmount as rewardCut and transactionAdditionalAmount as feeCut
if (eventObj.name == "TranscoderUpdate") { if (eventObj.name == "TranscoderUpdate") {
transactionName = "Update"; transactionName = "Update";
transactionCaller = eventObj.data.transcoder; transactionCaller = eventObj.data.transcoder.toLowerCase();
transactionAmount = eventObj.data.rewardCut / 10000; transactionAmount = eventObj.data.rewardCut / 10000;
transactionAdditionalAmount = 100 - (eventObj.data.feeShare / 10000); transactionAdditionalAmount = 100 - (eventObj.data.feeShare / 10000);
thisColour = updateColour; thisColour = updateColour;
@ -66,7 +66,7 @@ const EventButton = (obj) => {
// WithdrawStake: defines transactionName. Defines transactionAmount as rewardCut and transactionAdditionalAmount as feeCut // WithdrawStake: defines transactionName. Defines transactionAmount as rewardCut and transactionAdditionalAmount as feeCut
if (eventObj.name == "WithdrawStake") { if (eventObj.name == "WithdrawStake") {
transactionName = "Withdraw"; transactionName = "Withdraw";
transactionCaller = eventObj.data.delegator; transactionCaller = eventObj.data.delegator.toLowerCase();
transactionAmount = eventObj.data.amount / 1000000000000000000; transactionAmount = eventObj.data.amount / 1000000000000000000;
transactionWhen = eventObj.data.withdrawRound; transactionWhen = eventObj.data.withdrawRound;
thisColour = withdrawStakeColour; thisColour = withdrawStakeColour;
@ -84,47 +84,51 @@ const EventButton = (obj) => {
if (transactionName == "Reward") { if (transactionName == "Reward") {
if (transactionAmount - 69 < 1 && transactionAmount - 69 > 0) { if (transactionAmount - 69 < 1 && transactionAmount - 69 > 0) {
eventSpecificInfo = eventSpecificInfo =
<div className="row"> <div className="rowAlignLeft">
<p>called reward worth {transactionAmount.toFixed(2)} LPT. nice</p> <p>called reward worth {transactionAmount.toFixed(2)} LPT. nice</p>
</div> </div>
} else { } else {
eventSpecificInfo = eventSpecificInfo =
<div className="row"> <div className="rowAlignLeft">
<p>called reward worth {transactionAmount.toFixed(2)} LPT</p> <p>called reward worth {transactionAmount.toFixed(2)} LPT</p>
</div> </div>
} }
} else if (transactionName == "Update") { } else if (transactionName == "Update") {
eventSpecificInfo = eventSpecificInfo =
<div className="row"> <div className="rowAlignLeft">
<p>changed their reward commission to {transactionAmount.toFixed(2)}% and their fee commission to {transactionAdditionalAmount.toFixed(2)}%</p> <p>changed their reward commission to {transactionAmount.toFixed(2)}% and their fee commission to {transactionAdditionalAmount.toFixed(2)}%</p>
</div> </div>
} else if (transactionName == "Stake") { } else if (transactionName == "Stake") {
if (transactionFrom == "0x0000000000000000000000000000000000000000") { if (transactionFrom == "0x0000000000000000000000000000000000000000") {
eventSpecificInfo = eventSpecificInfo =
<div className="row"> <div className="rowAlignLeft">
<p> staked {(transactionAmount / 1000000000000000000).toFixed(2)} LPT to {transactionTo} </p> <p> staked {(transactionAmount / 1000000000000000000).toFixed(2)} LPT to </p>
<button className="selectOrch" onClick={() => {obj.setOrchFunction(transactionTo)}} >{transactionTo}</button>
</div> </div>
} else { } else {
eventSpecificInfo = eventSpecificInfo =
<div className="row"> <div className="rowAlignLeft">
<p> changed stake from {transactionFrom} to {transactionTo} of {(transactionAmount / 1000000000000000000).toFixed(2)} LPT</p> <p> moved {(transactionAmount / 1000000000000000000).toFixed(2)} LPT stake: </p>
<button className="selectOrch" onClick={() => {obj.setOrchFunction(transactionFrom)}} >{transactionFrom}</button>
<p> to </p>
<button className="selectOrch" onClick={() => {obj.setOrchFunction(transactionTo)}} >{transactionTo}</button>
</div> </div>
} }
} else if (transactionName == "Withdraw") { } else if (transactionName == "Withdraw") {
eventSpecificInfo = eventSpecificInfo =
<div className="row"> <div className="rowAlignLeft">
<p> withdrew {(transactionAmount / 1000000000000000000).toFixed(2)} LPT in round {transactionWhen}</p> <p> withdrew {(transactionAmount / 1000000000000000000).toFixed(2)} LPT in round {transactionWhen}</p>
</div> </div>
} else if (transactionName == "Activated") { } else if (transactionName == "Activated") {
if (hasBondTransaction) { if (hasBondTransaction) {
eventSpecificInfo = eventSpecificInfo =
<div className="row"> <div className="rowAlignLeft">
<p>{transactionCaller} activated with a self stake of {(transactionAmount / 1000000000000000000).toFixed(2)} LPT and will become active in round {transactionWhen}</p> <p>activated with a self stake of {(transactionAmount / 1000000000000000000).toFixed(2)} LPT and will become active in round {transactionWhen}</p>
</div> </div>
} else { } else {
// If there was no bond transaction, display fewer information // If there was no bond transaction, display fewer information
eventSpecificInfo = eventSpecificInfo =
<div className="row"> <div className="rowAlignLeft">
<p>reactivated and will become active in round {transactionWhen}</p> <p>reactivated and will become active in round {transactionWhen}</p>
</div> </div>
} }
@ -140,10 +144,12 @@ const EventButton = (obj) => {
return ( return (
<div className="row" style={{ backgroundColor: thisColour, borderRadius: "1.2em" }}> <div className="row" style={{ backgroundColor: thisColour, borderRadius: "1.2em" }}>
<a href={"https://explorer.livepeer.org/accounts/" + transactionCaller} style={{ flexDirection: 'row', display: "flex" }}> <div style={{ flexDirection: 'row', display: "flex" }}>
<img alt="" src="livepeer.png" width="30" height="30" /> <img alt="" src="livepeer.png" width="30" height="30" />
<p>{transactionCaller}</p> <div className="row">
</a> <button className="selectOrch" onClick={() => {obj.setOrchFunction(transactionCaller)}} >{transactionCaller}</button>
</div>
</div>
{eventSpecificInfo} {eventSpecificInfo}
<a href={thisURL}> <a href={thisURL}>
<img alt="" src="arb.svg" width="30" height="30" /> <img alt="" src="arb.svg" width="30" height="30" />

View File

@ -14,7 +14,7 @@ const EventViewer = (obj) => {
let finalHash = ""; let finalHash = "";
let finalIdx = 0; let finalIdx = 0;
return ( return (
<div className="stroke roundedOpaque" style={{ padding: 0, margin: 0, marginTop: '2em', position: 'absolute', bottom: 0, top: '200px', left: '0px', right: '0px', overflowY: 'auto', overflowX: 'hidden', width: '100%' }}> <div className="stroke roundedOpaque" style={{ padding: 0, margin: 0, marginTop: '2em', position: 'absolute', bottom: 0, top: '300px', left: '0px', right: '0px', overflowY: 'auto', overflowX: 'hidden', width: '100%' }}>
<div className="content-wrapper"> <div className="content-wrapper">
<ScrollContainer className="overflow-container" hideScrollbars={false}> <ScrollContainer className="overflow-container" hideScrollbars={false}>
<div className="overflow-content" style={{ cursor: 'grab' }}> <div className="overflow-content" style={{ cursor: 'grab' }}>
@ -50,6 +50,7 @@ const EventViewer = (obj) => {
transactionHash={finalHash} transactionHash={finalHash}
events={eventBundle} events={eventBundle}
idx={finalIdx} idx={finalIdx}
setOrchFunction={obj.setOrchFunction}
/> />
} }
})} })}

View File

@ -5,9 +5,10 @@ import {
} from "react-router-dom"; } from "react-router-dom";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { import {
getQuotes, getBlockchainData, getEvents, getCurrentOrchestratorInfo getQuotes, getBlockchainData, getEvents, getCurrentOrchestratorInfo, getOrchestratorInfo
} from "./actions/livepeer"; } from "./actions/livepeer";
import EventViewer from "./eventViewer"; import EventViewer from "./eventViewer";
import Orchestrator from "./orchestratorViewer";
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
@ -22,7 +23,8 @@ const mapDispatchToProps = dispatch => ({
getQuotes: () => dispatch(getQuotes()), getQuotes: () => dispatch(getQuotes()),
getBlockchainData: () => dispatch(getBlockchainData()), getBlockchainData: () => dispatch(getBlockchainData()),
getEvents: () => dispatch(getEvents()), getEvents: () => dispatch(getEvents()),
getCurrentOrchestratorInfo: () => dispatch(getCurrentOrchestratorInfo()) getCurrentOrchestratorInfo: () => dispatch(getCurrentOrchestratorInfo()),
getOrchestratorInfo: (addr) => dispatch(getOrchestratorInfo(addr))
}); });
class Livepeer extends React.Component { class Livepeer extends React.Component {
@ -120,9 +122,14 @@ class Livepeer extends React.Component {
eventsList = this.props.livepeer.events; eventsList = this.props.livepeer.events;
} }
let thisOrchObj = this.props.livepeer.thisOrchestrator;
if (this.props.livepeer.selectedOrchestrator){
thisOrchObj = this.props.livepeer.selectedOrchestrator;
}
return ( return (
<div style={{ width: '100%', height: '100%' }}> <div style={{ width: '100%', height: '100%' }}>
<div className="row" style={{ margin: 0, padding: 0, backgroundColor: "rgba(180, 175, 252, 0.80)", boxSizing: "border-box", backdropDilter: "blur(6px)", boxSshadow: "9px 13px 18px 8px rgba(8, 7, 56, 0.692)", position: 'absolute', top: '0px', left: '0px', height: '200px', right: '0px', overflow: 'hidden' }}> <div className="row" style={{ margin: 0, padding: 0, backgroundColor: "rgba(180, 175, 252, 0.80)", boxSizing: "border-box", backdropDilter: "blur(6px)", boxSshadow: "9px 13px 18px 8px rgba(8, 7, 56, 0.692)", position: 'absolute', top: '0px', left: '0px', height: '300px', right: '0px', overflow: 'hidden' }}>
<div className="row" style={{ margin: 0, padding: 0 }}> <div className="row" style={{ margin: 0, padding: 0 }}>
<button className="homeButton" onClick={() => { <button className="homeButton" onClick={() => {
this.setState({ redirectToHome: true }); this.setState({ redirectToHome: true });
@ -130,22 +137,8 @@ class Livepeer extends React.Component {
<img alt="" src="livepeer.png" width="100em" height="100em" /> <img alt="" src="livepeer.png" width="100em" height="100em" />
</button> </button>
</div> </div>
<Orchestrator thisOrchestrator={thisOrchObj} />
<div className="row metaSidebar" style={{ padding: 0 }}> <div className="row metaSidebar" style={{ padding: 0 }}>
<div className="stroke" style={{ margin: 0, padding: 0 }}>
<div className="row">
<h3>Price Info</h3>
</div>
<div className="row">
<img alt="" src="livepeer.png" width="30" height="30" />
<p>${lptPrice}</p>
<p>({lptPriceChange24h}%)</p>
</div>
<div className="row">
<img alt="" src="eth.png" width="30" height="30" />
<p>${ethPrice}</p>
<p>({ethPriceChange24h}%)</p>
</div>
</div>
<div className="stroke" style={{ margin: 0, padding: 0 }}> <div className="stroke" style={{ margin: 0, padding: 0 }}>
<h3>Smart contract prices</h3> <h3>Smart contract prices</h3>
<div className="row"> <div className="row">
@ -163,7 +156,7 @@ class Livepeer extends React.Component {
</div> </div>
</div> </div>
</div > </div >
<EventViewer events={eventsList} /> <EventViewer events={eventsList} setOrchFunction={this.props.getOrchestratorInfo}/>
</div > </div >
); );
} }

View File

@ -1,4 +1,5 @@
import React from "react"; import React from "react";
import ScrollContainer from "react-indiana-drag-scroll";
const Orchestrator = (obj) => { const Orchestrator = (obj) => {
let rewardCut = 0; let rewardCut = 0;
@ -9,6 +10,8 @@ const Orchestrator = (obj) => {
let delegators = []; let delegators = [];
let selfStake = 0; let selfStake = 0;
let selfStakeRatio = 0; let selfStakeRatio = 0;
let thisUrl = "";
let thisID = "";
if (obj.thisOrchestrator) { if (obj.thisOrchestrator) {
if (obj.thisOrchestrator.rewardCut) { if (obj.thisOrchestrator.rewardCut) {
rewardCut = (obj.thisOrchestrator.rewardCut / 10000).toFixed(2); rewardCut = (obj.thisOrchestrator.rewardCut / 10000).toFixed(2);
@ -30,14 +33,23 @@ const Orchestrator = (obj) => {
selfStake = parseFloat(obj.thisOrchestrator.delegator.bondedAmount); selfStake = parseFloat(obj.thisOrchestrator.delegator.bondedAmount);
selfStakeRatio = ((selfStake / totalStake) * 100).toFixed(2); selfStakeRatio = ((selfStake / totalStake) * 100).toFixed(2);
selfStake = selfStake.toFixed(2); selfStake = selfStake.toFixed(2);
thisID = obj.thisOrchestrator.delegator.id;
thisUrl = "https://explorer.livepeer.org/accounts/" + thisID;
} }
} }
return ( return (
<div className="hostInfo" style={{ margin: 0, padding: 0 }}> <div className="hostInfo">
<div className="stroke" style={{ margin: 0, padding: 0 }}> <div className="strokeSmollLeft">
<div style={{ flexDirection: 'row', display: "flex" }}>
<a href={thisUrl}>
<img alt="" src="livepeer.png" width="30" height="30" />
<h3>Orchestrator Info</h3>
{thisID}
</a>
</div>
<div className="rowAlignLeft"> <div className="rowAlignLeft">
<h3>Orchestrator Info</h3> <p>Earned fees {totalVolumeETH} Eth (${totalVolumeUSD})</p>
</div> </div>
<div className="rowAlignLeft"> <div className="rowAlignLeft">
<p>Reward Cut {rewardCut}%</p> <p>Reward Cut {rewardCut}%</p>
@ -45,27 +57,32 @@ const Orchestrator = (obj) => {
</div> </div>
<div className="rowAlignLeft"> <div className="rowAlignLeft">
<p>Total Stake {totalStake} LPT</p> <p>Total Stake {totalStake} LPT</p>
</div>
<div className="rowAlignLeft">
<p>Self stake {selfStake} LPT ({selfStakeRatio}%)</p> <p>Self stake {selfStake} LPT ({selfStakeRatio}%)</p>
</div> </div>
<div className="rowAlignLeft"> </div>
<p>Earned fees {totalVolumeETH} Eth (${totalVolumeUSD})</p> <div className="rowAlignLeft">
<div className="content-wrapper">
<ScrollContainer className="overflow-container" hideScrollbars={false}>
<div className="overflow-content" style={{ cursor: 'grab', height: '300px' }}>
{
delegators.map((delObj, idx) => {
return (
<div className="rowAlignLeft">
<a href={"https://explorer.livepeer.org/accounts/" + delObj.id}>
<img alt="" src="livepeer.png" width="30" height="30" />{delObj.id.substr(0, 6) + ".."}</a>
<div className="strokeSmollLeft">
<p>{parseFloat(delObj.bondedAmount).toFixed(2)} LPT since round {delObj.startRound}</p>
</div>
</div>
)
})
}
</div>
</ScrollContainer>
</div> </div>
{
delegators.map((delObj, idx) => {
return (
<div className="rowAlignLeft">
<a href={"https://explorer.livepeer.org/accounts/" + delObj.id}>
<img alt="" src="livepeer.png" width="30" height="30" />
</a>
<p>{parseFloat(delObj.bondedAmount).toFixed(2)} LPT since round {delObj.startRound}</p>
</div>
)
})
}
</div> </div>
</div> </div>
) )
} }

View File

@ -1,9 +1,10 @@
a:hover, a:visited, a:link, a:active{ .selectOrch:hover, a:hover, a:visited, a:link, a:active{
text-decoration: none; text-decoration: none;
color: rgba(0, 0, 0, 0.875); color: rgba(0, 0, 0, 0.875);
text-align: center; text-align: center;
justify-content: center; justify-content: center;
align-items: center; align-items: copy;
cursor: pointer;
} }
img { img {
@ -41,9 +42,11 @@ h2, h3, h1, h4, h5, h6 {
justify-content: space-evenly; justify-content: space-evenly;
} }
a { .selectOrch, a {
text-shadow: 0.5px 0.5px 0.8px #948dff; text-shadow: 0.5px 0.5px 0.8px #948dff;
color: #1a1b26; color: #1a1b26;
background-color: transparent;
border: none;
} }
p { p {
@ -195,14 +198,14 @@ svg {
padding: 10px; padding: 10px;
margin: 10px; margin: 10px;
user-select: text; user-select: text;
margin-top: 0;
margin-bottom: 0;
font-size: small; font-size: small;
color: rgba(15, 15, 15, 0.8750); color: rgba(15, 15, 15, 0.8750);
background-color: rgba(169, 177, 214, 0.8); background-color: rgba(169, 177, 214, 0.8);
-webkit-box-shadow: inset 3px 3px 12px 2px rgba(28, 28, 170, 0.2); -webkit-box-shadow: inset 3px 3px 12px 2px rgba(28, 28, 170, 0.2);
-moz-box-shadow: inset 3px 3px 12px 2px rgba(28, 28, 170, 0.2); -moz-box-shadow: inset 3px 3px 12px 2px rgba(28, 28, 170, 0.2);
box-shadow: inset 3px 3px 12px 2px rgba(28, 28, 170, 0.2); box-shadow: inset 3px 3px 12px 2px rgba(28, 28, 170, 0.2);
display: flex;
flex-direction: row;
} }
.flexContainer { .flexContainer {
@ -232,10 +235,8 @@ svg {
.strokeSmoll { .strokeSmoll {
box-sizing: border-box; box-sizing: border-box;
height: 100%; padding: 0;
paddin: 0;
margin: 0; margin: 0;
width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -243,6 +244,19 @@ svg {
z-index: 2; z-index: 2;
} }
.strokeSmollLeft {
padding: 0;
margin: 0;
display: flex;
text-align: center;
justify-content: center;
align-items: center;
justify-content: middle;
vertical-align: middle;
flex-direction: column;
z-index: 2;
}
.row { .row {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;

View File

@ -37,9 +37,8 @@ export const getCurrentOrchestratorInfo = () => (
); );
export const getOrchestratorInfo = (orchAddr) => ( export const getOrchestratorInfo = (orchAddr) => (
fetch("api/livepeer/getOrchestrator", { fetch("api/livepeer/getOrchestrator/" + orchAddr, {
method: "POST", method: "GET",
body: JSON.stringify(orchAddr),
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json"
} }