Skip to content

Commit

Permalink
Merge pull request #2443 from OlympusDAO/develop
Browse files Browse the repository at this point in the history
Fix: Range Improvements
  • Loading branch information
appleseed-iii authored Nov 22, 2022
2 parents f5531de + df2447b commit a0b24a7
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 88 deletions.
10 changes: 8 additions & 2 deletions src/views/Bond/hooks/useBondV3.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useQuery } from "@tanstack/react-query";
import { BigNumber } from "ethers";
import { NetworkId } from "src/constants";
import { BOND_AGGREGATOR_CONTRACT, BOND_FIXED_EXPIRY_TELLER } from "src/constants/contracts";
import { RANGE_OPERATOR_ADDRESSES } from "src/constants/addresses";
import { BOND_AGGREGATOR_CONTRACT, BOND_FIXED_EXPIRY_TELLER, RANGE_PRICE_CONTRACT } from "src/constants/contracts";
import { OHM_TOKEN } from "src/constants/tokens";
import { getTokenByAddress } from "src/helpers/contracts/getTokenByAddress";
import { DecimalBigNumber } from "src/helpers/DecimalBigNumber/DecimalBigNumber";
Expand Down Expand Up @@ -73,7 +74,12 @@ export const fetchBondV3 = async ({ id, isInverseBond, networkId }: UseBondOptio
const quoteTokenPerBaseToken = new DecimalBigNumber(bondMarketPrice.mul(shift), 36);
const bondTeller = BOND_FIXED_EXPIRY_TELLER.getEthersContract(networkId);
const bondToken = await bondTeller.getBondTokenForMarket(id);
const priceInUsd = quoteTokenPerUsd.mul(quoteTokenPerBaseToken);
const rbsBond = market.owner === RANGE_OPERATOR_ADDRESSES[networkId];
const rangePriceContract = RANGE_PRICE_CONTRACT.getEthersContract(networkId);
const priceInUsd = rbsBond
? new DecimalBigNumber(await rangePriceContract.getCurrentPrice(), 18).mul(quoteTokenPerBaseToken)
: quoteTokenPerUsd.mul(quoteTokenPerBaseToken);

const discount = baseTokenPerUsd.sub(priceInUsd).div(baseTokenPerUsd);

/**
Expand Down
2 changes: 1 addition & 1 deletion src/views/Range/__mocks__/mockRangeCalls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const RangeData: OlympusRange.RangeStruct = {
threshold: BigNumber.from("100000000000000000000000"),
},
wall: {
low: { price: BigNumber.from("16117147092410245645") },
low: { price: BigNumber.from("13117147092410245645") },
high: { price: BigNumber.from("24175720638615368468") },
spread: BigNumber.from(2000),
},
Expand Down
20 changes: 10 additions & 10 deletions src/views/Range/__tests__/Range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,32 +162,32 @@ describe("Sell Tab Main Range View", () => {
expect(await screen.findByTestId("max-row")).toHaveTextContent("Max You Can Sell");
});

it("Should Display Premium instead of Discount", async () => {
it("Should Display Discount instead of Premium", async () => {
const { container } = render(<Range />);
fireEvent.click(container.getElementsByClassName("arrow-wrapper")[0]);
expect(await screen.findByTestId("premium-discount")).toHaveTextContent("Premium");
expect(await screen.findByTestId("premium-discount")).toHaveTextContent("Discount");
});

it("Should populate DAI Value automatically with 100 when 6.204572026713784 DAI amount is entered", async () => {
it("Should populate DAI Value automatically with 81.38628391985866 when 6.204572026713784 DAI amount is entered", async () => {
const { container } = render(<Range />);
fireEvent.click(container.getElementsByClassName("arrow-wrapper")[0]);
fireEvent.input(await screen.findByTestId("ohm-amount"), { target: { value: "6.204572026713784" } });
expect(await screen.findByTestId("reserve-amount")).toHaveValue("100");
expect(await screen.findByTestId("reserve-amount")).toHaveValue("81.38628391985866");
});
it("Should populate OHM Value automatically with 6.204572026713784 OHM when 100 DAI is entered", async () => {
it("Should populate OHM Value automatically with 7.623608952122014 OHM when 100 DAI is entered", async () => {
const { container } = render(<Range />);
fireEvent.click(container.getElementsByClassName("arrow-wrapper")[0]);
fireEvent.input(await screen.findByTestId("reserve-amount"), { target: { value: "100" } });
expect(await screen.findByTestId("ohm-amount")).toHaveValue("6.204572026713784");
expect(await screen.findByTestId("ohm-amount")).toHaveValue("7.623608952122014");
});

it("Should change the OHM Value when switching back to the Buy Tab", async () => {
const { container } = render(<Range />);
fireEvent.click(container.getElementsByClassName("arrow-wrapper")[0]);
fireEvent.input(await screen.findByTestId("ohm-amount"), { target: { value: "6.204572026713784" } });
expect(await screen.findByTestId("reserve-amount")).toHaveValue("100");
expect(await screen.findByTestId("reserve-amount")).toHaveValue("81.38628391985866");
fireEvent.click(container.getElementsByClassName("arrow-wrapper")[0]);
expect(await screen.findByTestId("ohm-amount")).toHaveValue("4.136381351142522");
expect(await screen.findByTestId("ohm-amount")).toHaveValue("3.366447070448939");
});

it("Should display Amount exceeds balance when OHM amount entered exceeds balance", async () => {
Expand All @@ -209,10 +209,10 @@ describe("Sell Tab Main Range View", () => {
expect(await screen.findByTestId("ohm-amount")).toHaveValue("10");
});

it("Should render with Bid price of $16.12 on chart", async () => {
it("Should render with Bid price of $13.12 on chart", async () => {
const { container } = render(<Range />);
fireEvent.click(container.getElementsByClassName("arrow-wrapper")[0]);
expect(await screen.findByText("Bid: $16.12"));
expect(await screen.findByText("Bid: $13.12"));
});
});

Expand Down
16 changes: 7 additions & 9 deletions src/views/Range/__tests__/RangeBondsUpper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe("Upper Wall Active Bond Market", () => {
Balance.useBalance = jest.fn().mockReturnValue({ 1: { data: new DecimalBigNumber("10", 9) } });
//@ts-expect-error
rangeData.mockReturnValueOnce({
range: jest.fn().mockReturnValueOnce({ ...RangeData, high: { ...RangeData.high, market: BigNumber.from("1") } }),
range: jest.fn().mockReturnValueOnce({ ...RangeData, high: { ...RangeData.high } }),
reserve: jest.fn().mockReturnValue("address"),
});
//@ts-expect-error
Expand Down Expand Up @@ -108,8 +108,9 @@ describe("Upper Wall Active Bond Market", () => {

it("Should have a disclaimer notifying a buy above current market price ($13.20)", async () => {
//@ts-ignore
RangeHooks.DetermineRangePrice = jest.fn().mockReturnValue({ data: { price: "14.12" } });
render(<Range />);
RangeHooks.DetermineRangePrice = jest.fn().mockReturnValue({ data: { price: "14.20" } });
const { container } = render(<Range />);
fireEvent.click(container.getElementsByClassName("arrow-wrapper")[0]);
fireEvent.input(await screen.findByTestId("reserve-amount"), { target: { value: "6" } });
fireEvent.click(screen.getByTestId("range-submit"));
expect(screen.getByTestId("disclaimer")).toHaveTextContent(
Expand All @@ -119,12 +120,9 @@ describe("Upper Wall Active Bond Market", () => {

it("Should successfully complete buy regular bond transaction", async () => {
//@ts-ignore
RangeHooks.DetermineRangePrice = jest.fn().mockReturnValue({ data: { price: "14.12" } });
render(
<>
<Range />
</>,
);
RangeHooks.DetermineRangePrice = jest.fn().mockReturnValue({ data: { price: "14.20" } });
const { container } = render(<Range />);
fireEvent.click(container.getElementsByClassName("arrow-wrapper")[0]);
fireEvent.input(await screen.findByTestId("reserve-amount"), { target: { value: "6" } });
fireEvent.click(screen.getByTestId("range-submit"));
fireEvent.click(screen.getByTestId("disclaimer-checkbox"));
Expand Down
58 changes: 29 additions & 29 deletions src/views/Range/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { assert } from "src/helpers/types/assert";
import { useTestableNetworks } from "src/hooks/useTestableNetworks";
import { BondFixedTermSDA__factory, BondTeller__factory, IERC20__factory } from "src/typechain";
import { RANGEv1 as OlympusRange } from "src/typechain/Range";
import { useNetwork, useSigner } from "wagmi";
import { useSigner } from "wagmi";

/**Chainlink Price Feed. Retrieves OHMETH and ETH/{RESERVE} feed **/
export const OHMPriceHistory = (assetPair = "OHMv2/ETH") => {
Expand Down Expand Up @@ -105,10 +105,10 @@ export const PriceHistory = (reserveToken: string) => {
* Returns the current price of the Operator at the given address
*/
export const OperatorPrice = () => {
const { chain = { id: 1 } } = useNetwork();
const networks = useTestableNetworks();

const contract = RANGE_PRICE_CONTRACT.getEthersContract(chain.id);
const { data, isFetched, isLoading } = useQuery(["getOperatorPrice", chain], async () => {
const contract = RANGE_PRICE_CONTRACT.getEthersContract(networks.MAINNET);
const { data, isFetched, isLoading } = useQuery(["getOperatorPrice", networks.MAINNET], async () => {
return parseBigNumber(await contract.getCurrentPrice(), 18);
});
return { data, isFetched, isLoading };
Expand All @@ -118,14 +118,14 @@ export const OperatorPrice = () => {
* Returns the current price of the Operator at the given address
*/
export const OperatorMovingAverage = () => {
const { chain = { id: 1 } } = useNetwork();
const networks = useTestableNetworks();

const contract = RANGE_PRICE_CONTRACT.getEthersContract(chain.id);
const contract = RANGE_PRICE_CONTRACT.getEthersContract(networks.MAINNET);
const {
data = { movingAverage: 0, days: 30 },
isFetched,
isLoading,
} = useQuery(["getOperatorMovingAverage", chain], async () => {
} = useQuery(["getOperatorMovingAverage", networks.MAINNET], async () => {
const movingAverage = parseBigNumber(await contract.getMovingAverage(), 18);
const movingAverageSeconds = await contract.movingAverageDuration();
const days = movingAverageSeconds / 60 / 60 / 24; //seconds to days;
Expand All @@ -138,14 +138,14 @@ export const OperatorMovingAverage = () => {
* Returns the reserve contract address on the Operator
*/
export const OperatorReserveSymbol = () => {
const { chain = { id: 1 } } = useNetwork();
const contract = RANGE_CONTRACT.getEthersContract(chain.id);
const networks = useTestableNetworks();
const contract = RANGE_CONTRACT.getEthersContract(networks.MAINNET);
const {
data = { symbol: "", reserveAddress: "" },
isFetched,
isLoading,
} = useQuery(["getOperatorReserveSymbol", chain], async () => {
const provider = Providers.getStaticProvider(chain.id);
} = useQuery(["getOperatorReserveSymbol", networks.MAINNET], async () => {
const provider = Providers.getStaticProvider(networks.MAINNET);
const reserveAddress = await contract.reserve();
const TokenContract = IERC20__factory.connect(reserveAddress, provider);
const symbol = await TokenContract.symbol();
Expand All @@ -159,8 +159,8 @@ export const OperatorReserveSymbol = () => {
*/

export const RangeData = () => {
const { chain = { id: 1 } } = useNetwork();
const contract = RANGE_CONTRACT.getEthersContract(chain.id);
const networks = useTestableNetworks();
const contract = RANGE_CONTRACT.getEthersContract(networks.MAINNET);

const {
data = {
Expand All @@ -171,7 +171,7 @@ export const RangeData = () => {
} as OlympusRange.RangeStructOutput,
isFetched,
isLoading,
} = useQuery(["getRangeData", chain.id], async () => {
} = useQuery(["getRangeData", networks.MAINNET], async () => {
const range = await contract.range();
return range;
});
Expand Down Expand Up @@ -200,24 +200,25 @@ const band: OlympusRange.BandStruct = {
* @param id Bond Market ID
*/
export const RangeBondPrice = (id: BigNumber, side: "low" | "high") => {
const { chain = { id: 1 } } = useNetwork();
const contract = BOND_AGGREGATOR_CONTRACT.getEthersContract(chain.id);
const networks = useTestableNetworks();
const contract = BOND_AGGREGATOR_CONTRACT.getEthersContract(networks.MAINNET);
const { data, isFetched, isLoading } = useQuery(
["getRangeBondPrice", id, chain, side],
["getRangeBondPrice", id, networks.MAINNET, side],
async () => {
const bondPrice = await contract.marketPrice(id);
const auctioneerAddress = await contract.getAuctioneer(id);
const auctioneerContract = BondFixedTermSDA__factory.connect(auctioneerAddress, contract.provider);
const market = await auctioneerContract.markets(id);
const inverse =
market.payoutToken.toLowerCase() !== OHM_ADDRESSES[chain.id as keyof typeof OHM_ADDRESSES].toLowerCase();
market.payoutToken.toLowerCase() !==
OHM_ADDRESSES[networks.MAINNET as keyof typeof OHM_ADDRESSES].toLowerCase();
const baseToken = inverse
? await getTokenByAddress({ address: market.payoutToken, networkId: chain.id })
? await getTokenByAddress({ address: market.payoutToken, networkId: networks.MAINNET })
: OHM_TOKEN;
assert(baseToken, `Unknown base token address: ${market.payoutToken}`);
const quoteToken = inverse
? OHM_TOKEN
: await getTokenByAddress({ address: market.quoteToken, networkId: chain.id });
: await getTokenByAddress({ address: market.quoteToken, networkId: networks.MAINNET });
assert(quoteToken, `Unknown quote token address: ${market.quoteToken}`);

const scale = await contract.marketScale(id);
Expand All @@ -237,11 +238,11 @@ export const RangeBondPrice = (id: BigNumber, side: "low" | "high") => {
};

export const RangeBondMaxPayout = (id: BigNumber) => {
const { chain = { id: 1 } } = useNetwork();
const aggregatorContract = BOND_AGGREGATOR_CONTRACT.getEthersContract(chain.id);
const networks = useTestableNetworks();
const aggregatorContract = BOND_AGGREGATOR_CONTRACT.getEthersContract(networks.MAINNET);

const { data, isFetched, isLoading } = useQuery(
["getRangeBondMaxPayout", id, chain],
["getRangeBondMaxPayout", id, networks.MAINNET],
async () => {
const auctioneerAddress = await aggregatorContract.getAuctioneer(id);
const contract = BondFixedTermSDA__factory.connect(auctioneerAddress, aggregatorContract.provider);
Expand All @@ -256,10 +257,10 @@ export const RangeBondMaxPayout = (id: BigNumber) => {
};

export const BondTellerAddress = (id: BigNumber) => {
const { chain = { id: 1 } } = useNetwork();
const contract = BOND_AGGREGATOR_CONTRACT.getEthersContract(chain.id);
const networks = useTestableNetworks();
const contract = BOND_AGGREGATOR_CONTRACT.getEthersContract(networks.MAINNET);
const { data, isFetched, isLoading } = useQuery(
["getRangeBondTeller", id, chain],
["getRangeBondTeller", id, networks.MAINNET],
async () => {
const tellerAddress = await contract.getTeller(id);
return tellerAddress;
Expand Down Expand Up @@ -351,7 +352,6 @@ type RangeContracts = "swap" | "bond";
export const RangeSwap = () => {
const networks = useTestableNetworks();
const { data: signer } = useSigner();
const { chain = { id: 1 } } = useNetwork();
const referrer = DAO_TREASURY_ADDRESSES[networks.MAINNET];

return useMutation<
Expand All @@ -369,8 +369,8 @@ export const RangeSwap = () => {
}
>(
async ({ market, tokenAddress, swapType, amount, receiveAmount, sellActive, slippage, recipientAddress }) => {
const decimals = tokenAddress === OHM_ADDRESSES[chain.id as keyof typeof OHM_ADDRESSES] ? 9 : 18;
const receiveDecimals = tokenAddress === OHM_ADDRESSES[chain.id as keyof typeof OHM_ADDRESSES] ? 18 : 9; //opposite of send
const decimals = tokenAddress === OHM_ADDRESSES[networks.MAINNET as keyof typeof OHM_ADDRESSES] ? 9 : 18;
const receiveDecimals = tokenAddress === OHM_ADDRESSES[networks.MAINNET as keyof typeof OHM_ADDRESSES] ? 18 : 9; //opposite of send
if (!signer) throw new Error(t`Please connect a wallet to Range Swap`);

if (!isValidAddress(recipientAddress) || recipientAddress === "") throw new Error(t`Invalid address`);
Expand Down
81 changes: 44 additions & 37 deletions src/views/Range/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,21 @@ export const Range = () => {
const buyAsset = sellActive ? reserveSymbol : "OHM";
const sellAsset = sellActive ? "OHM" : reserveSymbol;

const { data: bidPrice } = DetermineRangePrice("bid");
const { data: askPrice } = DetermineRangePrice("ask");

useEffect(() => {
if (reserveAmount && ohmAmount) {
handleChangeReserveAmount(reserveAmount);
}
}, [sellActive]);

const { data: bidPrice } = DetermineRangePrice("bid");
const { data: askPrice } = DetermineRangePrice("ask");
useEffect(() => {
const sellDiscount = (currentPrice - bidPrice.price) / -currentPrice;
if (sellDiscount > 0) {
setSellActive(true);
}
}, [bidPrice, currentPrice]);

const maxBalanceString = `${maxCapacity.toFixed(2)} ${buyAsset} (${(sellActive
? maxCapacity / bidPrice.price
Expand Down Expand Up @@ -149,22 +156,20 @@ export const Range = () => {
)}
</Box>
<form onSubmit={handleSubmit}>
<WalletConnectedGuard message="Connect your wallet to use Range Swap">
<RangeInputForm
reserveSymbol={reserveSymbol as OHMTokenProps["name"]}
onSetSellActive={() => setSellActive(!sellActive)}
sellActive={sellActive}
reserveBalance={reserveBalance}
ohmBalance={ohmBalance}
onFormSubmit={handleSubmit}
onChangeReserveAmount={handleChangeReserveAmount}
onChangeOhmAmount={handleChangeOhmAmount}
ohmAmount={ohmAmount}
reserveAmount={reserveAmount}
capacity={maxCapacity}
hasPrice={hasPrice}
/>
</WalletConnectedGuard>
<RangeInputForm
reserveSymbol={reserveSymbol as OHMTokenProps["name"]}
onSetSellActive={() => setSellActive(!sellActive)}
sellActive={sellActive}
reserveBalance={reserveBalance}
ohmBalance={ohmBalance}
onFormSubmit={handleSubmit}
onChangeReserveAmount={handleChangeReserveAmount}
onChangeOhmAmount={handleChangeOhmAmount}
ohmAmount={ohmAmount}
reserveAmount={reserveAmount}
capacity={maxCapacity}
hasPrice={hasPrice}
/>
{hasPrice && (
<Box display="flex" flexDirection="row" width="100%" justifyContent="center">
<Box display="flex" flexDirection="column" width="100%" maxWidth="476px">
Expand Down Expand Up @@ -212,25 +217,27 @@ export const Range = () => {
<DataRow title={t`Swap Price per OHM`} balance={swapPrice} />
</div>
<Box mt="8px">
<PrimaryButton
data-testid="range-submit"
fullWidth
type="submit"
disabled={
!ohmAmount ||
!reserveAmount ||
amountAboveCapacity ||
amountAboveBalance ||
(sellActive && !rangeData.low.active) ||
(!sellActive && !rangeData.high.active)
}
>
{amountAboveCapacity
? `Amount exceeds capacity`
: amountAboveBalance
? `Amount exceeds balance`
: swapButtonText}
</PrimaryButton>
<WalletConnectedGuard fullWidth>
<PrimaryButton
data-testid="range-submit"
fullWidth
type="submit"
disabled={
!ohmAmount ||
!reserveAmount ||
amountAboveCapacity ||
amountAboveBalance ||
(sellActive && !rangeData.low.active) ||
(!sellActive && !rangeData.high.active)
}
>
{amountAboveCapacity
? `Amount exceeds capacity`
: amountAboveBalance
? `Amount exceeds balance`
: swapButtonText}
</PrimaryButton>
</WalletConnectedGuard>
</Box>
</Box>
</Box>
Expand Down

0 comments on commit a0b24a7

Please sign in to comment.