From a7064052758ff65935452538e4af9cdaaf1325b6 Mon Sep 17 00:00:00 2001
From: brightiron <brightiron@protonmail.com>
Date: Sat, 30 Nov 2024 19:53:33 -0600
Subject: [PATCH 1/3] usds handling RBS

---
 src/constants/addresses.ts                 |  7 +++-
 src/views/Range/RangeConfirmationModal.tsx |  4 +-
 src/views/Range/RangeInputForm.tsx         | 47 +++++++++++++---------
 src/views/Range/hooks.tsx                  |  5 +--
 src/views/Range/index.tsx                  | 26 ++++++------
 5 files changed, 54 insertions(+), 35 deletions(-)

diff --git a/src/constants/addresses.ts b/src/constants/addresses.ts
index f84ea1a725..77d209dae2 100644
--- a/src/constants/addresses.ts
+++ b/src/constants/addresses.ts
@@ -52,6 +52,11 @@ export const DAI_ADDRESSES = {
   [NetworkId.MAINNET]: "0x6b175474e89094c44da98b954eedeac495271d0f",
 };
 
+export const USDS_ADDRESSES = {
+  [NetworkId.MAINNET]: "0xdC035D45d973E3EC169d2276DDab16f1e407384F",
+  [NetworkId.TESTNET_GOERLI]: "",
+};
+
 export const WETH_ADDRESSES = {
   [NetworkId.MAINNET]: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
 };
@@ -142,7 +147,7 @@ export const BALANCER_VAULT_ADDRESSSES = {
 };
 
 export const RANGE_OPERATOR_ADDRESSES = {
-  [NetworkId.MAINNET]: "0x0AE561226896dA978EaDA0Bec4a7d3CfAE04f506",
+  [NetworkId.MAINNET]: "0x6417F206a0a6628Da136C0Faa39026d0134D2b52",
   [NetworkId.TESTNET_GOERLI]: "0x6620592f9bdffAbadcea644a35946E7b93EaaF56",
 };
 
diff --git a/src/views/Range/RangeConfirmationModal.tsx b/src/views/Range/RangeConfirmationModal.tsx
index 48e3db11ea..3d021858a4 100644
--- a/src/views/Range/RangeConfirmationModal.tsx
+++ b/src/views/Range/RangeConfirmationModal.tsx
@@ -84,7 +84,9 @@ const RangeConfirmationModal = (props: {
         <Box display="flex" flexDirection="row" justifyContent="space-between" alignItems="center" mb={"9px"}>
           <Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>Price of OHM</Typography>
           <Box display="flex" flexDirection="column" textAlign="right">
-            <Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>{props.swapPrice} DAI</Typography>
+            <Typography sx={{ fontSize: "15px", lineHeight: "21px" }}>
+              {props.swapPrice} {props.reserveSymbol}
+            </Typography>
           </Box>
         </Box>
         <Box display="flex" flexDirection="row" justifyContent="space-between" alignItems="center" mb={"9px"}>
diff --git a/src/views/Range/RangeInputForm.tsx b/src/views/Range/RangeInputForm.tsx
index 0341652269..afbe3026b5 100644
--- a/src/views/Range/RangeInputForm.tsx
+++ b/src/views/Range/RangeInputForm.tsx
@@ -1,9 +1,9 @@
-import { Box } from "@mui/material";
+import { Box, SvgIcon } from "@mui/material";
 import { SwapCollection } from "@olympusdao/component-library";
 import { OHMTokenProps, SwapCard } from "@olympusdao/component-library";
 import React from "react";
+import usdsIcon from "src/assets/tokens/usds.svg?react";
 import { DecimalBigNumber } from "src/helpers/DecimalBigNumber/DecimalBigNumber";
-
 /**
  * Component for Displaying RangeInputForm
  */
@@ -36,22 +36,33 @@ const RangeInputForm = (props: {
   const trimmedOhmBalance = ohmBalance.toString({ decimals: 2 });
   const trimmedReserveBalance = reserveBalance.toString({ decimals: 2 });
 
-  const ReserveInput = () => (
-    <SwapCard
-      key="reserveAmount"
-      id="reserve-amount"
-      inputProps={{ "data-testid": "reserve-amount" }}
-      name="reserveAmount"
-      value={reserveAmount}
-      onChange={event => onChangeReserveAmount(event.currentTarget.value)}
-      endString={`Max`}
-      endStringOnClick={() => hasPrice && onChangeReserveAmount(reserveBalance.toString())}
-      token={reserveSymbol}
-      type="string"
-      info={`Balance: ${trimmedReserveBalance} ${reserveSymbol}`}
-      disabled={!hasPrice}
-    />
-  );
+  const ReserveInput = () => {
+    const token =
+      reserveSymbol === ("USDS" as OHMTokenProps["name"]) ? (
+        <Box display="flex" gap="9px" alignItems="center">
+          <SvgIcon color="primary" sx={{ width: "20px", height: "20px" }} viewBox="0 0 50 50" component={usdsIcon} />
+          USDS
+        </Box>
+      ) : (
+        reserveSymbol
+      );
+    return (
+      <SwapCard
+        key="reserveAmount"
+        id="reserve-amount"
+        inputProps={{ "data-testid": "reserve-amount" }}
+        name="reserveAmount"
+        value={reserveAmount}
+        onChange={event => onChangeReserveAmount(event.currentTarget.value)}
+        endString={`Max`}
+        endStringOnClick={() => hasPrice && onChangeReserveAmount(reserveBalance.toString())}
+        token={token}
+        type="string"
+        info={`Balance: ${trimmedReserveBalance} ${reserveSymbol}`}
+        disabled={!hasPrice}
+      />
+    );
+  };
 
   const OhmInput = () => (
     <SwapCard
diff --git a/src/views/Range/hooks.tsx b/src/views/Range/hooks.tsx
index 3b9b51a006..bb30dd049a 100644
--- a/src/views/Range/hooks.tsx
+++ b/src/views/Range/hooks.tsx
@@ -2,7 +2,7 @@ import { useMutation, useQuery } from "@tanstack/react-query";
 import { BigNumber, ContractReceipt, ethers } from "ethers";
 import request, { gql } from "graphql-request";
 import toast from "react-hot-toast";
-import { DAO_TREASURY_ADDRESSES, OHM_ADDRESSES } from "src/constants/addresses";
+import { DAO_TREASURY_ADDRESSES, OHM_ADDRESSES, USDS_ADDRESSES } from "src/constants/addresses";
 import {
   BOND_AGGREGATOR_CONTRACT,
   RANGE_CONTRACT,
@@ -142,14 +142,13 @@ export const OperatorMovingAverage = () => {
  */
 export const OperatorReserveSymbol = () => {
   const networks = useTestableNetworks();
-  const contract = RANGE_CONTRACT.getEthersContract(networks.MAINNET);
   const {
     data = { symbol: "", reserveAddress: "" },
     isFetched,
     isLoading,
   } = useQuery(["getOperatorReserveSymbol", networks.MAINNET], async () => {
     const provider = Providers.getStaticProvider(networks.MAINNET);
-    const reserveAddress = await contract.reserve();
+    const reserveAddress = USDS_ADDRESSES[networks.MAINNET]; //Range contract was not updated to set USDS as reserve
     const TokenContract = IERC20__factory.connect(reserveAddress, provider);
     const symbol = await TokenContract.symbol();
     return { reserveAddress, symbol };
diff --git a/src/views/Range/index.tsx b/src/views/Range/index.tsx
index fbfc77fb4c..aaa726c67e 100644
--- a/src/views/Range/index.tsx
+++ b/src/views/Range/index.tsx
@@ -13,7 +13,7 @@ import { useNavigate } from "react-router-dom";
 import { Link as RouterLink } from "react-router-dom";
 import PageTitle from "src/components/PageTitle";
 import { WalletConnectedGuard } from "src/components/WalletConnectedGuard";
-import { DAI_ADDRESSES, OHM_ADDRESSES } from "src/constants/addresses";
+import { OHM_ADDRESSES, USDS_ADDRESSES } from "src/constants/addresses";
 import { formatNumber, parseBigNumber } from "src/helpers";
 import CountdownTimer from "src/helpers/CountdownTimer";
 import { DecimalBigNumber } from "src/helpers/DecimalBigNumber/DecimalBigNumber";
@@ -58,19 +58,19 @@ export const Range = () => {
   const [reserveAmount, setReserveAmount] = useState("");
   const [ohmAmount, setOhmAmount] = useState("");
 
-  const { data: reserveBalance = new DecimalBigNumber("0", 18) } = useBalance(DAI_ADDRESSES)[networks.MAINNET];
+  const { data: reserveBalance = new DecimalBigNumber("0", 18) } = useBalance(USDS_ADDRESSES)[networks.MAINNET];
   const { data: ohmBalance = new DecimalBigNumber("0", 9) } = useBalance(OHM_ADDRESSES)[networks.MAINNET];
 
   const { data: currentPrice } = OperatorPrice();
   const { data: lastPrice } = LastSnapshotPrice();
   const { data: currentMarketPrices } = useGetDefillamaPrice({
-    addresses: [DAI_ADDRESSES[1], OHM_ADDRESSES[1]],
+    addresses: [USDS_ADDRESSES[1], OHM_ADDRESSES[1]],
   });
   const { data: nextBeat } = RangeNextBeat();
 
-  const daiPriceUSD = currentMarketPrices?.[`ethereum:${DAI_ADDRESSES[1]}`].price;
+  const usdsPriceUSD = currentMarketPrices?.[`ethereum:${USDS_ADDRESSES[1]}`].price;
   const ohmPriceUSD = currentMarketPrices?.[`ethereum:${OHM_ADDRESSES[1]}`].price;
-  const marketOhmPriceDAI = daiPriceUSD && ohmPriceUSD ? ohmPriceUSD / daiPriceUSD : undefined;
+  const marketOhmPriceUSDS = usdsPriceUSD && ohmPriceUSD ? ohmPriceUSD / usdsPriceUSD : undefined;
 
   const maxString = sellActive ? `Max You Can Sell` : `Max You Can Buy`;
 
@@ -112,12 +112,12 @@ export const Range = () => {
   // Set sell active if market price is defined and is below lower cushion OR if there is a active lower bond market.
   useEffect(() => {
     if (
-      (marketOhmPriceDAI && marketOhmPriceDAI < parseBigNumber(rangeData.low.cushion.price, 18)) ||
+      (marketOhmPriceUSDS && marketOhmPriceUSDS < parseBigNumber(rangeData.low.cushion.price, 18)) ||
       bidPrice.activeBondMarket
     ) {
       setSellActive(true);
     }
-  }, [rangeData.low.cushion.price, marketOhmPriceDAI]);
+  }, [rangeData.low.cushion.price, marketOhmPriceUSDS]);
 
   const maxBalanceString = `${formatNumber(maxCapacity, 2)} ${buyAsset}  (${formatNumber(
     sellActive ? maxCapacity / bidPrice.price : maxCapacity * askPrice.price,
@@ -146,7 +146,9 @@ export const Range = () => {
   const swapPriceFormatted = formatNumber(swapPrice, 2);
 
   const discount =
-    (marketOhmPriceDAI && (marketOhmPriceDAI - swapPrice) / (sellActive ? -marketOhmPriceDAI : marketOhmPriceDAI)) || 0;
+    (marketOhmPriceUSDS &&
+      (marketOhmPriceUSDS - swapPrice) / (sellActive ? -marketOhmPriceUSDS : marketOhmPriceUSDS)) ||
+    0;
 
   const hasPrice = (sellActive && askPrice.price) || (!sellActive && bidPrice.price) ? true : false;
 
@@ -164,7 +166,7 @@ export const Range = () => {
         name="Range Bound Stability"
         subtitle={
           <Box display="flex" flexDirection="row" alignItems="center" gap="4px">
-            Swap DAI or OHM directly with the treasury.{" "}
+            Swap ${reserveSymbol} or OHM directly with the treasury.{" "}
             <Link
               component={RouterLink}
               to="https://docs.olympusdao.finance/main/overview/range-bound"
@@ -184,9 +186,9 @@ export const Range = () => {
           <>
             <Metric
               label="Market Price"
-              metric={`${formatNumber(marketOhmPriceDAI || 0, 2)} DAI`}
+              metric={`${formatNumber(marketOhmPriceUSDS || 0, 2)} ${reserveSymbol}`}
               tooltip="Market Price uses DefiLlama API, and is also used when calculating premium/discount on RBS"
-              isLoading={!marketOhmPriceDAI}
+              isLoading={!marketOhmPriceUSDS}
             />
             <Grid container>
               <Grid item xs={12} lg={6}>
@@ -263,7 +265,7 @@ export const Range = () => {
                                 ? "premium"
                                 : "discount"}{" "}
                             of {formatNumber(Math.abs(discount) * 100, 2)}% relative to market price of{" "}
-                            {formatNumber(marketOhmPriceDAI || 0, 2)} {reserveSymbol}
+                            {formatNumber(marketOhmPriceUSDS || 0, 2)} {reserveSymbol}
                           </InfoNotification>
                         </Box>
                         <div data-testid="max-row">

From 10678087035fe6018f7ea060c22bfd05534db25c Mon Sep 17 00:00:00 2001
From: brightiron <brightiron@protonmail.com>
Date: Sat, 7 Dec 2024 10:52:41 -0600
Subject: [PATCH 2/3] pull from operator contract

---
 src/views/Range/hooks.tsx | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/views/Range/hooks.tsx b/src/views/Range/hooks.tsx
index bb30dd049a..98847f9dd4 100644
--- a/src/views/Range/hooks.tsx
+++ b/src/views/Range/hooks.tsx
@@ -2,7 +2,7 @@ import { useMutation, useQuery } from "@tanstack/react-query";
 import { BigNumber, ContractReceipt, ethers } from "ethers";
 import request, { gql } from "graphql-request";
 import toast from "react-hot-toast";
-import { DAO_TREASURY_ADDRESSES, OHM_ADDRESSES, USDS_ADDRESSES } from "src/constants/addresses";
+import { DAO_TREASURY_ADDRESSES, OHM_ADDRESSES } from "src/constants/addresses";
 import {
   BOND_AGGREGATOR_CONTRACT,
   RANGE_CONTRACT,
@@ -142,13 +142,14 @@ export const OperatorMovingAverage = () => {
  */
 export const OperatorReserveSymbol = () => {
   const networks = useTestableNetworks();
+  const contract = RANGE_OPERATOR_CONTRACT.getEthersContract(networks.MAINNET);
   const {
     data = { symbol: "", reserveAddress: "" },
     isFetched,
     isLoading,
   } = useQuery(["getOperatorReserveSymbol", networks.MAINNET], async () => {
     const provider = Providers.getStaticProvider(networks.MAINNET);
-    const reserveAddress = USDS_ADDRESSES[networks.MAINNET]; //Range contract was not updated to set USDS as reserve
+    const reserveAddress = await contract.reserve();
     const TokenContract = IERC20__factory.connect(reserveAddress, provider);
     const symbol = await TokenContract.symbol();
     return { reserveAddress, symbol };

From 4ee62989e1e21310283b5f3fee885dbbee5b584e Mon Sep 17 00:00:00 2001
From: brightiron <brightiron@protonmail.com>
Date: Sun, 8 Dec 2024 21:06:20 -0600
Subject: [PATCH 3/3] active check

---
 src/views/Range/hooks.tsx | 10 ++++++++++
 src/views/Range/index.tsx | 12 +++++++++++-
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/views/Range/hooks.tsx b/src/views/Range/hooks.tsx
index 98847f9dd4..3e8a654e9f 100644
--- a/src/views/Range/hooks.tsx
+++ b/src/views/Range/hooks.tsx
@@ -445,3 +445,13 @@ export const RangeNextBeat = () => {
   });
   return { data, isFetched, isLoading };
 };
+
+export const useRangeCheckActive = () => {
+  const networks = useTestableNetworks();
+  const contract = RANGE_OPERATOR_CONTRACT.getEthersContract(networks.MAINNET);
+  const { data, isFetched, isLoading } = useQuery(["getRangeCheckActive", networks.MAINNET], async () => {
+    const active = await contract.active();
+    return active;
+  });
+  return { data, isFetched, isLoading };
+};
diff --git a/src/views/Range/index.tsx b/src/views/Range/index.tsx
index aaa726c67e..430a79939f 100644
--- a/src/views/Range/index.tsx
+++ b/src/views/Range/index.tsx
@@ -29,6 +29,7 @@ import {
   RangeBondMaxPayout,
   RangeData,
   RangeNextBeat,
+  useRangeCheckActive,
 } from "src/views/Range/hooks";
 import RangeChart from "src/views/Range/RangeChart";
 import RangeConfirmationModal from "src/views/Range/RangeConfirmationModal";
@@ -46,6 +47,7 @@ export const Range = () => {
   const networks = useTestableNetworks();
   const { chain = { id: 1 } } = useNetwork();
   const { data: rangeData, isLoading: rangeDataLoading } = RangeData();
+  const { data: isActive } = useRangeCheckActive();
   usePathForNetwork({ pathName: "range", networkID: chain.id, navigate });
 
   const {
@@ -234,6 +236,13 @@ export const Range = () => {
                       </Box>
                     </Box>
                   )}
+                  {!isActive && (
+                    <Box display="flex" flexDirection="row" width="100%" justifyContent="center" mt="24px">
+                      <Box display="flex" flexDirection="column" width="100%" maxWidth="476px">
+                        <InfoNotification>RBS Operator is currently inactive</InfoNotification>
+                      </Box>
+                    </Box>
+                  )}
                 </Box>
                 <form onSubmit={handleSubmit}>
                   <RangeInputForm
@@ -310,7 +319,8 @@ export const Range = () => {
                                 amountAboveCapacity ||
                                 amountAboveBalance ||
                                 (sellActive && !rangeData.low.active) ||
-                                (!sellActive && !rangeData.high.active)
+                                (!sellActive && !rangeData.high.active) ||
+                                !isActive
                               }
                             >
                               {amountAboveCapacity