Skip to content

Commit

Permalink
Merge develop (which merged master) into master (#70)
Browse files Browse the repository at this point in the history
* Add dynamic links to exchanges to buy collateral or synthetic tokens (#50)

Signed-off-by: Nick Pai <[email protected]>

* Distinguish between Staging and Prod sites (#59)

* Refine dapp styling and spacing (#53)

* Updated styling

* nits

Signed-off-by: Christopher Maree <[email protected]>

* Updated favicon

* Fixed nits

Signed-off-by: Christopher Maree <[email protected]>

* Fix EMP Management features (#55)

Signed-off-by: Nick Pai <[email protected]>

Co-authored-by: Chris Maree <[email protected]>
  • Loading branch information
nicholaspai and chrismaree authored Jul 25, 2020
1 parent d92d41d commit 9f3a4b8
Show file tree
Hide file tree
Showing 24 changed files with 1,801 additions and 1,308 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

_Expiring Multi Party is UMA's most current financial smart contract template. This UI is a community-made tool to make interfacing with the protocol easier, please use at your own risk._

Live frontend: https://emp-tools.vercel.app/
Live frontend:

- Staging: https://emp-tools.vercel.app/
- Production: https://tools.umaproject.org/

## Manual testing

Expand Down
24 changes: 13 additions & 11 deletions containers/EmpSponsors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,19 @@ const useEmpSponsors = () => {
utils.getAddress(contract.id) === emp.address
);

empData.positions.forEach((position: PositionQuery) => {
const sponsor = utils.getAddress(position.sponsor.id);

newPositions[sponsor] = {
tokensOutstanding: position.tokensOutstanding,
collateral: position.collateral,
sponsor,
};
});

setActivePositions(newPositions);
if (empData) {
empData.positions.forEach((position: PositionQuery) => {
const sponsor = utils.getAddress(position.sponsor.id);

newPositions[sponsor] = {
tokensOutstanding: position.tokensOutstanding,
collateral: position.collateral,
sponsor,
};
});

setActivePositions(newPositions);
}
}
}
};
Expand Down
4 changes: 4 additions & 0 deletions containers/EmpState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface ContractState {
totalTokensOutstanding: BigNumber | null;
liquidationLiveness: BigNumber | null;
withdrawalLiveness: BigNumber | null;
currentTime: BigNumber | null;
}

const initState = {
Expand All @@ -39,6 +40,7 @@ const initState = {
totalTokensOutstanding: null,
liquidationLiveness: null,
withdrawalLiveness: null,
currentTime: null,
};

const useContractState = () => {
Expand Down Expand Up @@ -70,6 +72,7 @@ const useContractState = () => {
emp.totalTokensOutstanding(),
emp.liquidationLiveness(),
emp.withdrawalLiveness(),
emp.getCurrentTime(),
]);

const newState: ContractState = {
Expand All @@ -88,6 +91,7 @@ const useContractState = () => {
totalTokensOutstanding: res[12] as BigNumber,
liquidationLiveness: res[13] as BigNumber,
withdrawalLiveness: res[14] as BigNumber,
currentTime: res[15] as BigNumber,
};

setState(newState);
Expand Down
10 changes: 10 additions & 0 deletions containers/Position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function usePosition() {

const [collateral, setCollateral] = useState<number | null>(null);
const [tokens, setTokens] = useState<number | null>(null);
const [cRatio, setCRatio] = useState<number | null>(null);
const [withdrawAmt, setWithdrawAmt] = useState<number | null>(null);
const [withdrawPassTime, setWithdrawPassTime] = useState<number | null>(null);
const [pendingWithdraw, setPendingWithdraw] = useState<string | null>(null);
Expand All @@ -37,6 +38,12 @@ function usePosition() {
// format data for storage
const collateral: number = weiToNum(collRaw, collDec);
const tokens: number = weiToNum(tokensOutstanding, tokenDec);
const cRatio =
collateral !== null && tokens !== null
? tokens > 0
? collateral / tokens
: 0
: null;
const withdrawAmt: number = weiToNum(withdrawReqAmt, collDec);
const withdrawPassTime: number = withdrawReqPassTime.toNumber();
const pendingWithdraw: string =
Expand All @@ -47,6 +54,7 @@ function usePosition() {
// set states
setCollateral(collateral);
setTokens(tokens);
setCRatio(cRatio);
setWithdrawAmt(withdrawAmt);
setWithdrawPassTime(withdrawPassTime);
setPendingWithdraw(pendingWithdraw);
Expand All @@ -67,6 +75,7 @@ function usePosition() {
if (contract === null) {
setCollateral(null);
setTokens(null);
setCRatio(null);
setWithdrawAmt(null);
setWithdrawPassTime(null);
setPendingWithdraw(null);
Expand All @@ -78,6 +87,7 @@ function usePosition() {
return {
collateral,
tokens,
cRatio,
withdrawAmt,
withdrawPassTime,
pendingWithdraw,
Expand Down
2 changes: 1 addition & 1 deletion containers/Totals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function useTotals() {
// use multiplier to find real total collateral in EMP
const totalColl = weiToNum(multiplier) * weiToNum(rawColl, collDec);
const totalTokens = weiToNum(totalTokensWei, tokenDec);
const gcr = totalColl / totalTokens;
const gcr = totalTokens > 0 ? totalColl / totalTokens : 0;

// set states
setTotalCollateral(totalColl);
Expand Down
214 changes: 123 additions & 91 deletions features/all-positions/AllPositions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import {
TableHead,
TableRow,
Paper,
Container,
Typography,
Tooltip,
} from "@material-ui/core";
import styled from "styled-components";
import { utils, BigNumberish } from "ethers";
import { utils } from "ethers";

import EmpState from "../../containers/EmpState";
import Collateral from "../../containers/Collateral";
Expand All @@ -21,6 +21,10 @@ import EmpContract from "../../containers/EmpContract";
import PriceFeed from "../../containers/PriceFeed";
import Etherscan from "../../containers/Etherscan";

import { getLiquidationPrice } from "../../utils/getLiquidationPrice";

const fromWei = utils.formatUnits;

const Link = styled.a`
color: white;
font-size: 18px;
Expand All @@ -30,109 +34,137 @@ const AllPositions = () => {
const { empState } = EmpState.useContainer();
const { priceIdentifier: priceId } = empState;
const { symbol: tokenSymbol } = Token.useContainer();
const { symbol: collSymbol } = Collateral.useContainer();
const {
symbol: collSymbol,
decimals: collDecimals,
} = Collateral.useContainer();
const { activeSponsors } = EmpSponsors.useContainer();
const { contract: emp } = EmpContract.useContainer();
const { latestPrice, sourceUrl } = PriceFeed.useContainer();
const { getEtherscanUrl } = Etherscan.useContainer();
const { collateralRequirement } = empState;

if (tokenSymbol === null || emp === null) {
return (
<Container>
<Box py={2}>
<Typography>
<i>Please first select an EMP from the dropdown above.</i>
</Typography>
</Box>
</Container>
if (
collateralRequirement !== null &&
collDecimals !== null &&
tokenSymbol !== null &&
collSymbol !== null &&
emp !== null &&
latestPrice !== null &&
priceId !== null &&
sourceUrl !== undefined
) {
const collReqFromWei = parseFloat(
fromWei(collateralRequirement, collDecimals)
);
}
const priceIdUtf8 = utils.parseBytes32String(priceId);

const prettyBalance = (x: BigNumberish | null) => {
if (!x) return "N/A";
x = Number(x).toFixed(4);
return utils.commify(x as string);
};
const getCollateralRatio = (collateral: number, tokens: number) => {
if (tokens <= 0 || latestPrice <= 0) return 0;
const tokensScaled = tokens * latestPrice;
return collateral / tokensScaled;
};

const prettyAddress = (x: String | null) => {
if (!x) return "N/A";
return x.substr(0, 6) + "..." + x.substr(x.length - 6, x.length);
};
const prettyBalance = (x: number) => {
const x_string = x.toFixed(4);
return utils.commify(x_string);
};

const getCollateralRatio = (
collateral: BigNumberish,
tokens: BigNumberish
) => {
if (!latestPrice) return null;
const tokensScaled = Number(tokens) * Number(latestPrice);
return (Number(collateral) / tokensScaled).toFixed(4);
};
const prettyAddress = (x: string) => {
return x.substr(0, 6) + "..." + x.substr(x.length - 6, x.length);
};

return (
<Container>
return (
<Box>
<Box>
<Typography>
{`Estimated price of ${latestPrice} for ${priceIdUtf8} sourced from: `}
<Link href={sourceUrl} target="_blank" rel="noopener noreferrer">
Coinbase Pro.
</Link>
</Typography>
</Box>
<Box pt={4}>
{activeSponsors && (
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>Sponsor</TableCell>
<TableCell align="right">
Collateral
<br />({collSymbol})
</TableCell>
<TableCell align="right">
Synthetics
<br />({tokenSymbol})
</TableCell>
<TableCell align="right">Collateral Ratio</TableCell>
<Tooltip
title={`This is the price that the identifier (${priceIdUtf8}) must increase to in order for the position be liquidatable`}
placement="top"
>
<TableCell align="right">Liquidation Price</TableCell>
</Tooltip>
</TableRow>
</TableHead>
<TableBody>
{Object.keys(activeSponsors).map((sponsor: string) => {
const activeSponsor = activeSponsors[sponsor];
return (
activeSponsor?.collateral &&
activeSponsor?.tokensOutstanding && (
<TableRow key={sponsor}>
<TableCell component="th" scope="row">
<a href={getEtherscanUrl(sponsor)} target="_blank">
{prettyAddress(sponsor)}
</a>
</TableCell>
<TableCell align="right">
{prettyBalance(Number(activeSponsor.collateral))}
</TableCell>
<TableCell align="right">
{prettyBalance(
Number(activeSponsor.tokensOutstanding)
)}
</TableCell>
<TableCell align="right">
{prettyBalance(
getCollateralRatio(
Number(activeSponsor.collateral),
Number(activeSponsor.tokensOutstanding)
)
)}
</TableCell>
<TableCell align="right">
{prettyBalance(
getLiquidationPrice(
Number(activeSponsor.collateral),
Number(activeSponsor.tokensOutstanding),
collReqFromWei
)
)}
</TableCell>
</TableRow>
)
);
})}
</TableBody>
</Table>
</TableContainer>
)}
</Box>
</Box>
);
} else {
return (
<Box>
<Typography>
<i>
Estimated price of{" "}
{latestPrice ? Number(latestPrice).toFixed(4) : "N/A"} for{" "}
{priceId ? utils.parseBytes32String(priceId) : "N/A"} sourced from{" "}
</i>
<Link href={sourceUrl} target="_blank" rel="noopener noreferrer">
Coinbase Pro.
</Link>
<i>Please first connect and select an EMP from the dropdown above.</i>
</Typography>
</Box>
<Box py={4}>
{activeSponsors && (
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>Sponsor</TableCell>
<TableCell align="right">Collateral ({collSymbol})</TableCell>
<TableCell align="right">
Synthetics ({tokenSymbol})
</TableCell>
<TableCell align="right">Collateral Ratio</TableCell>
</TableRow>
</TableHead>
<TableBody>
{Object.keys(activeSponsors).map((sponsor: string) => {
const activeSponsor = activeSponsors[sponsor];
return (
activeSponsor?.collateral &&
activeSponsor?.tokensOutstanding && (
<TableRow key={sponsor}>
<TableCell component="th" scope="row">
<a href={getEtherscanUrl(sponsor)} target="_blank">
{prettyAddress(sponsor)}
</a>
</TableCell>
<TableCell align="right">
{prettyBalance(activeSponsor.collateral)}
</TableCell>
<TableCell align="right">
{prettyBalance(activeSponsor.tokensOutstanding)}
</TableCell>
<TableCell align="right">
{prettyBalance(
getCollateralRatio(
activeSponsor.collateral,
activeSponsor.tokensOutstanding
)
)}
</TableCell>
</TableRow>
)
);
})}
</TableBody>
</Table>
</TableContainer>
)}
</Box>
</Container>
);
);
}
};

export default AllPositions;
Loading

0 comments on commit 9f3a4b8

Please sign in to comment.