diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 3388e0c69..e7442e766 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -21,23 +21,3 @@ - We rebranded "Bonding" to "Staking" to disambiguate our bonds (e.g. Chicken Bonds) branding. - We rebranded "Debts" to "Credits" because it has a positive connotation for the users. - We rebranded "Ubiquity Algorithmic Dollar" to "Ubiquity Dollar" because the term "algorithmic" is contentious in this context after Luna. -- Filenames should be in kebab-case for example (note as of writing this we still have to fix this): - - credit-nft-manager.sol - - credit-nft-redemption-calculator.sol - - credit-nft.sol - - credit-redemption-calculator.sol - - credit-token.sol - - dollar-manager.sol - - dollar-mint-calculator.sol - - dollar-mint-excess.sol - - dollar-token.sol - - dollar3pool-oracle.sol - - erc1155-ubiquity.sol - - erc20-ubiquity.sol - - formulas.sol - - governance-token.sol - - masterchef-ubiquity.sol - - staking-formulas.sol - - staking-token.sol - - staking.sol - - transfer-hooks/dollar3pool.sol diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 198e1643f..99f76ad6c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -26,7 +26,7 @@ jobs: - name: Setup Foundry uses: foundry-rs/foundry-toolchain@v1 with: - version: nightly-d369d2486f85576eec4ca41d277391dfdae21ba7 + version: nightly-5be158ba6dc7c798a6f032026fe60fc01686b33b - name: Yarn Install run: yarn install --mode=skip-build && yarn allow-scripts diff --git a/.github/workflows/coverage-check.yml b/.github/workflows/coverage-check.yml index 1230feb88..43efe2ba4 100644 --- a/.github/workflows/coverage-check.yml +++ b/.github/workflows/coverage-check.yml @@ -23,7 +23,7 @@ jobs: - name: Setup Foundry uses: onbjerg/foundry-toolchain@v1 with: - version: nightly-d369d2486f85576eec4ca41d277391dfdae21ba7 + version: nightly-5be158ba6dc7c798a6f032026fe60fc01686b33b - name: Install dependencies run: sudo apt-get install lcov diff --git a/.github/workflows/deep-fuzz.yml b/.github/workflows/deep-fuzz.yml index 9c3a1df9d..d0329cb12 100644 --- a/.github/workflows/deep-fuzz.yml +++ b/.github/workflows/deep-fuzz.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Foundry uses: foundry-rs/foundry-toolchain@v1 with: - version: nightly-d369d2486f85576eec4ca41d277391dfdae21ba7 + version: nightly-5be158ba6dc7c798a6f032026fe60fc01686b33b - name: Forge install working-directory: packages/contracts diff --git a/.github/workflows/generate-doc.yml b/.github/workflows/generate-doc.yml index 2f8b0d631..ebe265ad3 100644 --- a/.github/workflows/generate-doc.yml +++ b/.github/workflows/generate-doc.yml @@ -28,7 +28,7 @@ jobs: - name: Setup Foundry uses: foundry-rs/foundry-toolchain@v1 with: - version: nightly-d369d2486f85576eec4ca41d277391dfdae21ba7 + version: nightly-5be158ba6dc7c798a6f032026fe60fc01686b33b - name: Yarn Install run: yarn install --mode=skip-build && yarn allow-scripts diff --git a/global.d.ts b/global.d.ts deleted file mode 100644 index 62b1cc3c2..000000000 --- a/global.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { MetaMaskInpageProvider } from "@metamask/providers"; - -declare global { - interface Window { - ethereum?: MetaMaskInpageProvider; - } -} -declare module "*.svg" { - const value: React.StatelessComponent>; - export default value; -} diff --git a/package.json b/package.json index fd3c57179..dd18192f7 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "lint-staged": { "*.{js,jsx,ts,tsx,json}": [ "prettier --write", - "eslint --fix", + "eslint --fix --max-warnings=0", "cspell --no-must-find-files" ], "*.sol": [ diff --git a/packages/dapp/components/layout/anvil/anvil-rpcs.tsx b/packages/dapp/components/layout/anvil/anvil-rpcs.tsx index d7895a8c5..6dfb9cb3c 100644 --- a/packages/dapp/components/layout/anvil/anvil-rpcs.tsx +++ b/packages/dapp/components/layout/anvil/anvil-rpcs.tsx @@ -1,16 +1,17 @@ -import React from "react"; import Button from "../../ui/button"; import { methodConfigs } from "./method-configs"; import useWeb3 from "@/components/lib/hooks/use-web-3"; +import { LOCAL_NODE_ADDRESS } from "@/components/lib/hooks/use-web-3"; +import { useState } from "react"; export default function AnvilRpcs() { - const [isHidden, setIsHidden] = React.useState(true); - const [isVisible, setIsVisible] = React.useState(0); - const [methodArgs, setMethodArgs] = React.useState>({}); + const [isHidden, setIsHidden] = useState(true); + const [isVisible, setIsVisible] = useState(0); + const [methodArgs, setMethodArgs] = useState>({}); const { signer } = useWeb3(); const handleFetch = async (method: string, params: unknown[]) => { - const result = await fetch("http://localhost:8545", { + const result = await fetch(LOCAL_NODE_ADDRESS, { method: "POST", headers: { "Content-Type": "application/json", diff --git a/packages/dapp/components/layout/inventory.tsx b/packages/dapp/components/layout/inventory.tsx index 11efb7a15..964e0d2bf 100644 --- a/packages/dapp/components/layout/inventory.tsx +++ b/packages/dapp/components/layout/inventory.tsx @@ -7,8 +7,9 @@ import icons from "@/ui/icons"; import useManagerManaged from "../lib/hooks/contracts/use-manager-managed"; import useNamedContracts from "../lib/hooks/contracts/use-named-contracts"; -import useBalances, { Balances } from "../lib/hooks/use-balances"; +import useBalances from "../lib/hooks/use-balances"; import { ManagedContracts } from "../lib/hooks/contracts/use-manager-managed"; +import { Balances } from "../lib/types"; const Inventory = () => { const { walletAddress } = useWeb3(); diff --git a/packages/dapp/components/lib/app-context-provider.tsx b/packages/dapp/components/lib/app-context-provider.tsx index 3011770e4..015017391 100644 --- a/packages/dapp/components/lib/app-context-provider.tsx +++ b/packages/dapp/components/lib/app-context-provider.tsx @@ -1,4 +1,3 @@ -import { ManagedContractsContextProvider } from "./hooks/contracts/use-manager-managed"; import { BalancesContextProvider } from "./hooks/use-balances"; import { TransactionsContextProvider } from "./hooks/use-transaction-logger"; import { UseWeb3Provider } from "./hooks/use-web-3"; diff --git a/packages/dapp/components/lib/contracts-shortcuts.ts b/packages/dapp/components/lib/contracts-shortcuts.ts index c1078e25f..be4f208be 100644 --- a/packages/dapp/components/lib/contracts-shortcuts.ts +++ b/packages/dapp/components/lib/contracts-shortcuts.ts @@ -1,11 +1,10 @@ -import { BigNumber, ethers } from "ethers"; -import { ERC1155Ubiquity, ERC20 } from "types"; +import { BigNumber, ethers, Contract } from "ethers"; import { performTransaction } from "./utils"; export async function ensureERC20Allowance( logName: string, - contract: ERC20, + contract: Contract, amount: BigNumber, signer: ethers.providers.JsonRpcSigner, spender: string, @@ -25,7 +24,7 @@ export async function ensureERC20Allowance( return true; } -export async function ensureERC1155Allowance(logName: string, contract: ERC1155Ubiquity, signer: ethers.providers.JsonRpcSigner, spender: string): Promise { +export async function ensureERC1155Allowance(logName: string, contract: Contract, signer: ethers.providers.JsonRpcSigner, spender: string): Promise { const signerAddress = await signer.getAddress(); const isAllowed = await contract.isApprovedForAll(signerAddress, spender); console.log(`${logName} isAllowed: `, isAllowed); diff --git a/packages/dapp/components/lib/hooks/contracts/use-named-contracts.tsx b/packages/dapp/components/lib/hooks/contracts/use-named-contracts.tsx index 61723bd0f..d8ce7d7dd 100644 --- a/packages/dapp/components/lib/hooks/contracts/use-named-contracts.tsx +++ b/packages/dapp/components/lib/hooks/contracts/use-named-contracts.tsx @@ -1,16 +1,7 @@ import useWeb3, { PossibleProviders } from "../use-web-3"; -import Deployed_Contracts from "@ubiquity/contracts/deployments.json"; import NAMED_ACCOUNTS from "../../../config/named-accounts.json"; -import { getCurveFactoryContract, getDebtCouponManagerContract, getERC20Contract, getIJarContract, getYieldProxyContract } from "@/components/utils/contracts"; - -const getDebtCouponManagerAddress = () => { - const contractDeployments: Record = Deployed_Contracts; - const record = contractDeployments["1"] ?? {}; - const contract = record?.contracts ? record?.contracts["DebtCouponManager"] : undefined; - return contract ? contract.address : undefined; -}; -export const DEBT_COUPON_MANAGER_ADDRESS = getDebtCouponManagerAddress(); +import { getCurveFactoryContract, getERC20Contract, getIJarContract, getYieldProxyContract } from "@/components/utils/contracts"; export type NamedContracts = ReturnType | null; export function connectedContracts(provider: NonNullable) { @@ -20,7 +11,6 @@ export function connectedContracts(provider: NonNullable) { usdc: getERC20Contract(NAMED_ACCOUNTS.USDC, provider), dai: getERC20Contract(NAMED_ACCOUNTS.DAI, provider), usdt: getERC20Contract(NAMED_ACCOUNTS.USDT, provider), - debtCouponManager: getDebtCouponManagerContract(DEBT_COUPON_MANAGER_ADDRESS, provider), jarUsdc: getIJarContract(NAMED_ACCOUNTS.jarUSDCAddr, provider), }; } diff --git a/packages/dapp/components/lib/hooks/contracts/use-protocol-contracts.ts b/packages/dapp/components/lib/hooks/contracts/use-protocol-contracts.ts index a36d68409..c6ac8a942 100644 --- a/packages/dapp/components/lib/hooks/contracts/use-protocol-contracts.ts +++ b/packages/dapp/components/lib/hooks/contracts/use-protocol-contracts.ts @@ -3,6 +3,7 @@ import { Contract, ethers } from "ethers"; import latestDeployment from "@ubiquity/contracts/broadcast/05_StakingShare.s.sol/31337/run-latest.json"; import useWeb3 from "../use-web-3"; +import { sushiSwapPoolAddress, dollar3poolMarketAddress } from "@/lib/utils"; // contract build artifacts // separately deployed contracts @@ -27,17 +28,21 @@ import StakingFacetArtifact from "@ubiquity/contracts/out/StakingFacet.sol/Staki import StakingFormulasFacetArtifact from "@ubiquity/contracts/out/StakingFormulasFacet.sol/StakingFormulasFacet.json"; import TWAPOracleDollar3poolFacetArtifact from "@ubiquity/contracts/out/TWAPOracleDollar3poolFacet.sol/TWAPOracleDollar3poolFacet.json"; import UbiquityPoolFacetArtifact from "@ubiquity/contracts/out/UbiquityPoolFacet.sol/UbiquityPoolFacet.json"; +// other related contracts +// import SushiSwapPoolArtifact from "@ubiquity/contracts/out/SushiSwapPool.sol/SushiSwapPool.json"; +import IMetaPoolArtifact from "@ubiquity/contracts/out/IMetaPool.sol/IMetaPool.json"; +import UniswapV2PairABI from "@/components/config/abis/uniswap-v-2-pair.json"; /** - * Returns all of the available protocol contracts. - * + * Returns all of the available protocol contracts + * * Right now the Ubiquity org uses: * - separately deployed contracts (https://github.com/ubiquity/ubiquity-dollar/tree/development/packages/contracts/src/dollar/core) * - contracts deployed as diamond proxy facets (https://github.com/ubiquity/ubiquity-dollar/tree/development/packages/contracts/src/dollar/facets) - * + * * The following contracts are not exported for various reasons (but feel free * to export new contracts when you need them): - * + * * Contracts not used in the UI (as far as I understand): * - https://github.com/ubiquity/ubiquity-dollar/blob/development/packages/contracts/src/dollar/core/ERC1155Ubiquity.sol * - https://github.com/ubiquity/ubiquity-dollar/blob/development/packages/contracts/src/dollar/core/ERC20Ubiquity.sol @@ -45,41 +50,44 @@ import UbiquityPoolFacetArtifact from "@ubiquity/contracts/out/UbiquityPoolFacet * - https://github.com/ubiquity/ubiquity-dollar/blob/development/packages/contracts/src/dollar/facets/DiamondLoupeFacet.sol * - https://github.com/ubiquity/ubiquity-dollar/blob/development/packages/contracts/src/dollar/Diamond.sol * - https://github.com/ubiquity/ubiquity-dollar/blob/development/packages/contracts/src/dollar/DirectGovernanceFarmer.sol - * + * * Contracts not yet integrated (i.e. not used in other solidity contracts): * - https://github.com/ubiquity/ubiquity-dollar/blob/development/packages/contracts/src/dollar/core/CreditClock.sol - * + * * Contracts on hold (i.e. obsolete) until we find a better utility for them: * - https://github.com/ubiquity/ubiquity-dollar/tree/development/packages/contracts/src/ubiquistick */ -const useProtocolContracts = () => { +export type ProtocolContracts = ReturnType | null; +const useProtocolContracts = async () => { // get current web3 provider const { provider } = useWeb3(); // all protocol contracts const protocolContracts: { // separately deployed contracts (i.e. not part of the diamond) - creditNft: Contract | null, - creditToken: Contract | null, - dollarToken: Contract | null, - governanceToken: Contract | null, - stakingShare: Contract | null, + creditNft: Contract | null; + creditToken: Contract | null; + dollarToken: Contract | null; + governanceToken: Contract | null; + stakingShare: Contract | null; // diamond facets - accessControlFacet: Contract | null, - chefFacet: Contract | null, - collectableDustFacet: Contract | null, - creditNftManagerFacet: Contract | null, - creditNftRedemptionCalculatorFacet: Contract | null, - creditRedemptionCalculatorFacet: Contract | null, - curveDollarIncentiveFacet: Contract | null, - dollarMintCalculatorFacet: Contract | null, - dollarMintExcessFacet: Contract | null, - managerFacet: Contract | null, - ownershipFacet: Contract | null, - stakingFacet: Contract | null, - stakingFormulasFacet: Contract | null, - twapOracleDollar3poolFacet: Contract | null, - ubiquityPoolFacet: Contract | null, + accessControlFacet: Contract | null; + chefFacet: Contract | null; + collectableDustFacet: Contract | null; + creditNftManagerFacet: Contract | null; + creditNftRedemptionCalculatorFacet: Contract | null; + creditRedemptionCalculatorFacet: Contract | null; + curveDollarIncentiveFacet: Contract | null; + dollarMintCalculatorFacet: Contract | null; + dollarMintExcessFacet: Contract | null; + managerFacet: Contract | null; + ownershipFacet: Contract | null; + stakingFacet: Contract | null; + stakingFormulasFacet: Contract | null; + twapOracleDollar3poolFacet: Contract | null; + ubiquityPoolFacet: Contract | null; + sushiPoolGovernanceDollarLp: Contract | null; + curveMetaPoolDollarTriPoolLp: Contract | null; } = { // separately deployed contracts (i.e. not part of the diamond) creditNft: null, @@ -103,31 +111,33 @@ const useProtocolContracts = () => { stakingFormulasFacet: null, twapOracleDollar3poolFacet: null, ubiquityPoolFacet: null, + // related contracts + sushiPoolGovernanceDollarLp: null, + curveMetaPoolDollarTriPoolLp: null, }; - - let diamondAddress = ''; + let diamondAddress = ""; // for all of the deployment transactions - latestDeployment.transactions.map(tx => { - if (tx.transactionType === 'CREATE') { + latestDeployment.transactions.map((tx) => { + if (tx.transactionType === "CREATE") { // find contracts that deployed separately (i.e. not part of the diamond) - if (tx.contractName === 'CreditNft') { + if (tx.contractName === "CreditNft") { protocolContracts.creditNft = new ethers.Contract(tx.contractAddress, CreditNftArtifact.abi, provider); } - if (tx.contractName === 'UbiquityCreditToken') { + if (tx.contractName === "UbiquityCreditToken") { protocolContracts.creditToken = new ethers.Contract(tx.contractAddress, UbiquityCreditTokenArtifact.abi, provider); } - if (tx.contractName === 'UbiquityDollarToken') { + if (tx.contractName === "UbiquityDollarToken") { protocolContracts.dollarToken = new ethers.Contract(tx.contractAddress, UbiquityDollarTokenArtifact.abi, provider); } - if (tx.contractName === 'UbiquityGovernanceToken') { + if (tx.contractName === "UbiquityGovernanceToken") { protocolContracts.governanceToken = new ethers.Contract(tx.contractAddress, UbiquityGovernanceTokenArtifact.abi, provider); } - if (tx.contractName === 'StakingShare') { + if (tx.contractName === "StakingShare") { protocolContracts.stakingShare = new ethers.Contract(tx.contractAddress, StakingShareArtifact.abi, provider); } // find the diamond address - if (tx.contractName === 'Diamond') diamondAddress = tx.contractAddress; + if (tx.contractName === "Diamond") diamondAddress = tx.contractAddress; } }); @@ -148,6 +158,18 @@ const useProtocolContracts = () => { protocolContracts.twapOracleDollar3poolFacet = new ethers.Contract(diamondAddress, TWAPOracleDollar3poolFacetArtifact.abi, provider); protocolContracts.ubiquityPoolFacet = new ethers.Contract(diamondAddress, UbiquityPoolFacetArtifact.abi, provider); + // other related contracts + // const sushiSwapPool = await protocolContracts.managerFacet.sushiSwapPoolAddress(); + // const sushiSwapPoolContract = new ethers.Contract(sushiSwapPool, SushiSwapPoolArtifact.abi, provider); + // const UniswapV2PairContract = new ethers.Contract(await sushiSwapPoolContract.pair(), UniswapV2PairABI, provider); + const UniswapV2PairContract = new ethers.Contract(sushiSwapPoolAddress, UniswapV2PairABI, provider); + protocolContracts.sushiPoolGovernanceDollarLp = UniswapV2PairContract; + + // const dollar3poolMarket = await protocolContracts.managerFacet.stableSwapMetaPoolAddress(); + // const metaPoolContract = new ethers.Contract(dollar3poolMarket, IMetaPoolArtifact.abi, provider); + const metaPoolContract = new ethers.Contract(dollar3poolMarketAddress, IMetaPoolArtifact.abi, provider); + protocolContracts.curveMetaPoolDollarTriPoolLp = metaPoolContract; + return protocolContracts; }; diff --git a/packages/dapp/components/lib/hooks/use-balances.tsx b/packages/dapp/components/lib/hooks/use-balances.tsx index 6eaf6c53a..47a8262fb 100644 --- a/packages/dapp/components/lib/hooks/use-balances.tsx +++ b/packages/dapp/components/lib/hooks/use-balances.tsx @@ -1,23 +1,12 @@ -import { erc1155BalanceOf } from "@/lib/utils"; -import { BigNumber, Contract } from "ethers"; +import { erc1155BalanceOf, _3crvTokenAddress } from "@/lib/utils"; import { createContext, useContext, useEffect, useState } from "react"; -import useManagerManaged from "./contracts/use-manager-managed"; import useNamedContracts from "./contracts/use-named-contracts"; import useWalletAddress from "./use-wallet-address"; import { ChildrenShim } from "./children-shim-d"; - -export interface Balances { - uad: BigNumber; - _3crv: BigNumber; - uad3crv: BigNumber; - ucr: BigNumber; - ucrNft: BigNumber; - ubq: BigNumber; - stakingShares: BigNumber; - usdc: BigNumber; - dai: BigNumber; - usdt: BigNumber; -} +import useProtocolContracts from "@/components/lib/hooks/contracts/use-protocol-contracts"; +import { getERC20Contract } from "@/components/utils/contracts"; +import useWeb3 from "@/components/lib/hooks/use-web-3"; +import { Balances } from "../types"; type RefreshBalances = () => Promise; @@ -26,24 +15,32 @@ export const BalancesContext = createContext<[Balances | null, RefreshBalances]> export const BalancesContextProvider: React.FC = ({ children }) => { const [balances, setBalances] = useState(null); const [walletAddress] = useWalletAddress(); - const managedContracts = useManagerManaged(); const namedContracts = useNamedContracts(); + const protocolContracts = useProtocolContracts(); + const { provider } = useWeb3(); async function refreshBalances() { - if (walletAddress && managedContracts && namedContracts) { + if (!walletAddress || !namedContracts || !protocolContracts || !provider) { + return; + } + + const contracts = await protocolContracts; + + if (contracts.creditNft && contracts.stakingShare) { + // const _3crvTokenAddress = await contracts.managerFacet?.curve3PoolTokenAddress(); + const _3crvTokenContract = getERC20Contract(_3crvTokenAddress, provider); const [uad, _3crv, uad3crv, ucr, ubq, ucrNft, stakingShares, usdc, dai, usdt] = await Promise.all([ - managedContracts.dollarToken.balanceOf(walletAddress), - managedContracts._3crvToken.balanceOf(walletAddress), - managedContracts.dollarMetapool.balanceOf(walletAddress), - managedContracts.creditToken.balanceOf(walletAddress), - managedContracts.governanceToken.balanceOf(walletAddress), - erc1155BalanceOf(walletAddress, managedContracts.creditNft), - erc1155BalanceOf(walletAddress, managedContracts.stakingToken), + contracts.dollarToken?.balanceOf(walletAddress), + _3crvTokenContract.balanceOf(walletAddress), + contracts.curveMetaPoolDollarTriPoolLp?.balanceOf(walletAddress), + contracts.creditToken?.balanceOf(walletAddress), + contracts.governanceToken?.balanceOf(walletAddress), + erc1155BalanceOf(walletAddress, contracts.creditNft), + erc1155BalanceOf(walletAddress, contracts.stakingShare), namedContracts.usdc.balanceOf(walletAddress), namedContracts.dai.balanceOf(walletAddress), namedContracts.usdt.balanceOf(walletAddress), ]); - setBalances({ uad, _3crv, @@ -61,7 +58,7 @@ export const BalancesContextProvider: React.FC = ({ children }) => useEffect(() => { refreshBalances(); - }, [walletAddress, managedContracts]); + }, [walletAddress]); return {children}; }; diff --git a/packages/dapp/components/lib/hooks/use-web-3.tsx b/packages/dapp/components/lib/hooks/use-web-3.tsx index 08aafdeb4..088e6e355 100644 --- a/packages/dapp/components/lib/hooks/use-web-3.tsx +++ b/packages/dapp/components/lib/hooks/use-web-3.tsx @@ -1,7 +1,7 @@ import { JsonRpcProvider, JsonRpcSigner, Web3Provider } from "@ethersproject/providers"; import { useAccount, useProvider, useSigner } from "wagmi"; import { WagmiConfig, createClient } from "wagmi"; -import { mainnet, hardhat, localhost, foundry } from "wagmi/chains"; +import { mainnet, localhost, foundry } from "wagmi/chains"; import { WalletConnectConnector } from "wagmi/connectors/walletConnect"; import { InjectedConnector } from "wagmi/connectors/injected"; import { CoinbaseWalletConnector } from "wagmi/connectors/coinbaseWallet"; @@ -25,7 +25,7 @@ export type Web3State = { signer?: JsonRpcSigner; }; -const metamaskInstalled = typeof window !== "undefined" ? !!window?.ethereum?.request : false; +const metamaskInstalled = (typeof window !== "undefined" ? window.ethereum : undefined); const defaultChains = [mainnet, localhost, foundry /*, hardhat*/]; @@ -42,15 +42,15 @@ const client = createClient( chains: defaultChains, options: { shimDisconnect: true, - UNSTABLE_shimOnConnectSelectAccount: true - } + UNSTABLE_shimOnConnectSelectAccount: true, + }, }), new InjectedConnector({ chains: defaultChains, options: { name: "Injected Wallet", getProvider: () => typeof window !== 'undefined' ? window.ethereum : undefined, - shimDisconnect: true + shimDisconnect: true, }, }), new CoinbaseWalletConnector({ @@ -60,8 +60,8 @@ const client = createClient( appLogoUrl: "https://dao.ubq.fi/favicon.ico", darkMode: true, headlessMode: true, - jsonRpcUrl: process.env.NEXT_PUBLIC_JSON_RPC_URL || "" - } + jsonRpcUrl: process.env.NEXT_PUBLIC_JSON_RPC_URL || "", + }, }), new WalletConnectConnector({ chains: defaultChains, @@ -72,11 +72,11 @@ const client = createClient( name: "Ubiquity DAO", description: "World's first scalable digital dollar", url: "https://dao.ubq.fi/", - icons: ["https://dao.ubq.fi/favicon.ico"] + icons: ["https://dao.ubq.fi/favicon.ico"], }, - } - }) - ] + }, + }), + ], }) ); diff --git a/packages/dapp/components/lib/types.ts b/packages/dapp/components/lib/types.ts index e3d93ffd2..f27dcabbf 100644 --- a/packages/dapp/components/lib/types.ts +++ b/packages/dapp/components/lib/types.ts @@ -1,4 +1,4 @@ -import { ethers } from "ethers"; +import { BigNumber, ethers } from "ethers"; export interface EthAccount { balance: number; @@ -30,3 +30,16 @@ export interface PoolState { feeProtocol: number; unlocked: boolean; } + +export interface Balances { + uad: BigNumber; + _3crv: BigNumber; + uad3crv: BigNumber; + ucr: BigNumber; + ucrNft: BigNumber; + ubq: BigNumber; + stakingShares: BigNumber; + usdc: BigNumber; + dai: BigNumber; + usdt: BigNumber; +} diff --git a/packages/dapp/components/lib/utils.ts b/packages/dapp/components/lib/utils.ts index 2caf22cb1..022161a37 100644 --- a/packages/dapp/components/lib/utils.ts +++ b/packages/dapp/components/lib/utils.ts @@ -122,6 +122,10 @@ export const uCR_USDT_ADDRESS = "0x9d498aB38Aa889AE0f4A865d30da2116ee9716bC"; // Uniswap Router address export const V3_ROUTER_ADDRESS = "0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45"; +export const sushiSwapPoolAddress = "0x41e087485f47538752A1195D984109cB8Dc0E429"; +export const dollar3poolMarketAddress = "0x20955CB69Ae1515962177D164dfC9522feef567E"; +export const _3crvTokenAddress = "0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490"; + export const safeParseEther = (val: string) => { try { return ethers.utils.parseEther(val); @@ -138,7 +142,7 @@ export const USDC_TOKEN = new Token(1, "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB export const USDT_TOKEN = new Token(1, "0xdAC17F958D2ee523a2206206994597C13D831ec7", 6, "USDT", "Tether USD"); export const DAI_TOKEN = new Token(1, "0x6B175474E89094C44Da98b954EedeAC495271d0F", 18, "DAI", "Dai Stablecoin"); -export class CurrencyAmount extends CurrencyAmountRaw { } +export class CurrencyAmount extends CurrencyAmountRaw {} // Try to parse a user entered amount for a given token export function parseAmount(value: string, currency: Currency): CurrencyAmount { diff --git a/packages/dapp/components/lib/with-loaded-context.tsx b/packages/dapp/components/lib/with-loaded-context.tsx index 53ce24cd2..690575c4f 100644 --- a/packages/dapp/components/lib/with-loaded-context.tsx +++ b/packages/dapp/components/lib/with-loaded-context.tsx @@ -1,13 +1,10 @@ import { ethers } from "ethers"; -import useDeployedContracts, { DeployedContracts } from "./hooks/contracts/use-deployed-contracts"; -import { ManagedContracts } from "./hooks/contracts/use-manager-managed"; +import useProtocolContracts, { ProtocolContracts } from "./hooks/contracts/use-protocol-contracts"; import useNamedContracts, { NamedContracts } from "./hooks/contracts/use-named-contracts"; import useWeb3, { PossibleProviders } from "./hooks/use-web-3"; -import useManagerManaged from "@/components/lib/hooks/contracts/use-manager-managed"; export type LoadedContext = { - managedContracts: NonNullable; - deployedContracts: NonNullable; + protocolContracts: NonNullable; namedContracts: NonNullable; web3Provider: NonNullable; walletAddress: string; @@ -17,19 +14,17 @@ export type LoadedContext = { export default function withLoadedContext(El: (params: LoadedContext & T) => JSX.Element, ElNull?: () => JSX.Element) { return (otherParams: T) => { const { walletAddress, signer, provider } = useWeb3(); - const managedContracts = useManagerManaged(); - const deployedContracts = useDeployedContracts(); const namedContracts = useNamedContracts(); + const protocolContracts = useProtocolContracts(); - if (provider && walletAddress && signer && managedContracts && deployedContracts && namedContracts) { + if (provider && walletAddress && signer && protocolContracts && namedContracts) { return ( ); diff --git a/packages/dapp/components/monitor/price-monitor.tsx b/packages/dapp/components/monitor/price-monitor.tsx index d61169dc2..ccee25adc 100644 --- a/packages/dapp/components/monitor/price-monitor.tsx +++ b/packages/dapp/components/monitor/price-monitor.tsx @@ -5,7 +5,6 @@ import NAMED_ACCOUNTS from "../config/named-accounts.json"; import { formatEther, formatMwei } from "@/lib/format"; import useNamedContracts from "../lib/hooks/contracts/use-named-contracts"; import useManagerManaged from "../lib/hooks/contracts/use-manager-managed"; -// import Address from "./ui/Address"; import PriceExchange from "./ui/price-exchange"; type State = null | PriceMonitorProps; diff --git a/packages/dapp/components/redeem/debt-coupon-deposit.tsx b/packages/dapp/components/redeem/debt-coupon-deposit.tsx index df692e6a5..a95767a33 100644 --- a/packages/dapp/components/redeem/debt-coupon-deposit.tsx +++ b/packages/dapp/components/redeem/debt-coupon-deposit.tsx @@ -4,8 +4,7 @@ import { useState } from "react"; import { ensureERC20Allowance } from "@/lib/contracts-shortcuts"; import { formatEther } from "@/lib/format"; import { safeParseEther } from "@/lib/utils"; -import useDeployedContracts from "../lib/hooks/contracts/use-deployed-contracts"; -import useManagerManaged from "../lib/hooks/contracts/use-manager-managed"; +import useProtocolContracts from "@/components/lib/hooks/contracts/use-protocol-contracts"; import useBalances from "../lib/hooks/use-balances"; import useSigner from "../lib/hooks/use-signer"; import useTransactionLogger from "../lib/hooks/use-transaction-logger"; @@ -18,8 +17,7 @@ const UcrNftGenerator = () => { const signer = useSigner(); const [balances, refreshBalances] = useBalances(); const [, doTransaction, doingTransaction] = useTransactionLogger(); - const deployedContracts = useDeployedContracts(); - const managedContracts = useManagerManaged(); + const protocolContracts = useProtocolContracts(); const [inputVal, setInputVal] = useState(""); const [expectedDebtCoupon, setExpectedDebtCoupon] = useState(null); @@ -28,16 +26,18 @@ const UcrNftGenerator = () => { return Connect wallet; } - if (!balances || !managedContracts || !deployedContracts) { + if (!balances || !protocolContracts) { return · · ·; } const depositDollarForDebtCoupons = async (amount: BigNumber) => { - const { debtCouponManager } = deployedContracts; - // cspell: disable-next-line - await ensureERC20Allowance("uAD -> DebtCouponManager", managedContracts.dollarToken, amount, signer, debtCouponManager.address); - await (await debtCouponManager.connect(signer).exchangeDollarsForCreditNft(amount)).wait(); - refreshBalances(); + const contracts = await protocolContracts; + if (contracts.dollarToken && contracts.creditNftManagerFacet) { + // cspell: disable-next-line + await ensureERC20Allowance("uCR -> CreditNftManagerFacet", contracts.dollarToken, amount, signer, contracts.creditNftManagerFacet.address); + await (await contracts.creditNftManagerFacet.connect(signer).exchangeDollarsForCreditNft(amount)).wait(); + refreshBalances(); + } }; const handleBurn = async () => { @@ -52,11 +52,12 @@ const UcrNftGenerator = () => { }; const handleInput = async (val: string) => { + const contracts = await protocolContracts; setInputVal(val); const amount = extractValidAmount(val); - if (amount) { + if (amount && contracts.creditNftRedemptionCalculatorFacet) { setExpectedDebtCoupon(null); - setExpectedDebtCoupon(await managedContracts.creditNftCalculator.connect(signer).getCreditNftAmount(amount)); + setExpectedDebtCoupon(await contracts.creditNftRedemptionCalculatorFacet.connect(signer).getCreditNftAmount(amount)); } }; diff --git a/packages/dapp/components/redeem/debt-coupon.tsx b/packages/dapp/components/redeem/debt-coupon.tsx index 73682758b..2bc062d1d 100644 --- a/packages/dapp/components/redeem/debt-coupon.tsx +++ b/packages/dapp/components/redeem/debt-coupon.tsx @@ -2,9 +2,10 @@ import { constrainNumber, formatTimeDiff } from "@/lib/utils"; import withLoadedContext, { LoadedContext } from "@/lib/with-loaded-context"; import { BigNumber, ethers } from "ethers"; import { ChangeEvent, Dispatch, memo, SetStateAction, useEffect, useMemo, useState } from "react"; -import useBalances, { Balances } from "../lib/hooks/use-balances"; +import useBalances from "../lib/hooks/use-balances"; import useTransactionLogger from "../lib/hooks/use-transaction-logger"; import usePrices from "./lib/use-prices"; +import { Balances } from "../lib/types"; type Actions = { onRedeem: () => void; @@ -33,7 +34,7 @@ const uDEBT = "uDEBT"; const uAR = "uAR"; // eslint-disable-next-line @typescript-eslint/no-unused-vars -export const DebtCouponContainer = ({ managedContracts, deployedContracts, web3Provider, walletAddress, signer }: LoadedContext) => { +export const DebtCouponContainer = ({ protocolContracts, web3Provider, walletAddress, signer }: LoadedContext) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const [balances, refreshBalances] = useBalances(); const [, doTransaction] = useTransactionLogger(); diff --git a/packages/dapp/components/redeem/lib/use-prices.ts b/packages/dapp/components/redeem/lib/use-prices.ts index 9b22d050e..26e4d4b8b 100644 --- a/packages/dapp/components/redeem/lib/use-prices.ts +++ b/packages/dapp/components/redeem/lib/use-prices.ts @@ -1,4 +1,3 @@ -import { getIMetaPoolContract } from "@/components/utils/contracts"; import useProtocolContracts from "@/components/lib/hooks/contracts/use-protocol-contracts"; import useWeb3 from "@/components/lib/hooks/use-web-3"; import { BigNumber, utils } from "ethers"; @@ -13,28 +12,27 @@ const usePrices = (): [BigNumber | null, BigNumber | null, () => Promise] async function refreshPrices() { try { - if(!protocolContracts || !provider) { + if (!protocolContracts || !provider) { return; } - if(protocolContracts.managerFacet && protocolContracts.twapOracleDollar3poolFacet) { - const dollarTokenAddress = await protocolContracts.managerFacet.dollarTokenAddress(); - const newTwapPrice = await protocolContracts.twapOracleDollar3poolFacet.consult(dollarTokenAddress); - const dollar3poolMarket = await protocolContracts.managerFacet.stableSwapMetaPoolAddress(); - const dollarMetapool = getIMetaPoolContract(dollar3poolMarket, provider) - const newSpotPrice = await dollarMetapool["get_dy(int128,int128,uint256)"](0, 1, utils.parseEther("1")); + const contracts = await protocolContracts; + + if (contracts.curveMetaPoolDollarTriPoolLp) { + const dollarTokenAddress = await contracts.managerFacet?.dollarTokenAddress(); + const newTwapPrice = await contracts.twapOracleDollar3poolFacet?.consult(dollarTokenAddress); + const newSpotPrice = await contracts.curveMetaPoolDollarTriPoolLp["get_dy(int128,int128,uint256)"](0, 1, utils.parseEther("1")); setTwapPrice(newTwapPrice); setSpotPrice(newSpotPrice); } - } catch (error) { - console.log("Error in refreshPrices: ", error) + console.log("Error in refreshPrices: ", error); } } useEffect(() => { refreshPrices(); - }, [protocolContracts, provider]); + }, [provider]); return [twapPrice, spotPrice, refreshPrices]; }; diff --git a/packages/dapp/components/redeem/ucr-nft-redeem.tsx b/packages/dapp/components/redeem/ucr-nft-redeem.tsx index 44d7c87e8..699bc6773 100644 --- a/packages/dapp/components/redeem/ucr-nft-redeem.tsx +++ b/packages/dapp/components/redeem/ucr-nft-redeem.tsx @@ -1,25 +1,24 @@ import { BigNumber, ethers, Contract } from "ethers"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { ensureERC1155Allowance } from "@/lib/contracts-shortcuts"; import { formatEther } from "@/lib/format"; import { safeParseEther } from "@/lib/utils"; -import useDeployedContracts from "../lib/hooks/contracts/use-deployed-contracts"; -import useManagerManaged from "../lib/hooks/contracts/use-manager-managed"; +import useProtocolContracts from "@/components/lib/hooks/contracts/use-protocol-contracts"; import useBalances from "../lib/hooks/use-balances"; import useSigner from "../lib/hooks/use-signer"; import useTransactionLogger from "../lib/hooks/use-transaction-logger"; import useWalletAddress from "../lib/hooks/use-wallet-address"; import Button from "../ui/button"; import PositiveNumberInput from "../ui/positive-number-input"; +import useEffectAsync from "../lib/hooks/use-effect-async"; const UcrNftRedeem = () => { const [walletAddress] = useWalletAddress(); const signer = useSigner(); const [, refreshBalances] = useBalances(); const [, doTransaction, doingTransaction] = useTransactionLogger(); - const deployedContracts = useDeployedContracts(); - const managedContracts = useManagerManaged(); + const protocolContracts = useProtocolContracts(); const [inputVal, setInputVal] = useState(""); const [debtIds, setDebtIds] = useState(null); @@ -32,14 +31,15 @@ const UcrNftRedeem = () => { } }; - useEffect(() => { - if (managedContracts && walletAddress) { - fetchDebts(walletAddress, managedContracts.creditNft); + useEffectAsync(async () => { + const contracts = await protocolContracts; + if (contracts.creditNft && walletAddress) { + fetchDebts(walletAddress, contracts.creditNft); } - }, [managedContracts, walletAddress]); + }, [walletAddress]); if (!walletAddress || !signer) return Connect wallet; - if (!deployedContracts || !managedContracts || !debtIds) return · · ·; + if (!protocolContracts || !debtIds) return · · ·; if (debtIds.length === 0) return No uCR-NFT coupons; async function fetchDebts(address: string, contract: Contract) { @@ -67,12 +67,14 @@ const UcrNftRedeem = () => { }; const redeemUcrNftForUad = async (amount: BigNumber) => { - const { debtCouponManager } = deployedContracts; + const contracts = await protocolContracts; const debtId = debtIds[selectedDebtId]; - if (debtId && (await ensureERC1155Allowance("uCR-NFT -> DebtCouponManager", managedContracts.creditNft, signer, debtCouponManager.address))) { - await (await debtCouponManager.connect(signer).redeemCreditNft(debtId, amount)).wait(); - refreshBalances(); - fetchDebts(walletAddress, managedContracts.creditNft); + if (contracts.creditNft && contracts.creditNftManagerFacet) { + if (debtId && (await ensureERC1155Allowance("uCR-NFT -> CreditNftManagerFacet", contracts.creditNft, signer, contracts.creditNftManagerFacet.address))) { + await (await contracts.creditNftManagerFacet.connect(signer).redeemCreditNft(debtId, amount)).wait(); + refreshBalances(); + fetchDebts(walletAddress, contracts.creditNft); + } } }; diff --git a/packages/dapp/components/redeem/ucr-redeem.tsx b/packages/dapp/components/redeem/ucr-redeem.tsx index 5e3097a75..5e113c642 100644 --- a/packages/dapp/components/redeem/ucr-redeem.tsx +++ b/packages/dapp/components/redeem/ucr-redeem.tsx @@ -1,10 +1,9 @@ -import { BigNumber, Contract, ethers } from "ethers"; +import { BigNumber, ethers } from "ethers"; import { useState } from "react"; import { SwapWidget } from "@uniswap/widgets"; import { ensureERC20Allowance } from "@/lib/contracts-shortcuts"; import { safeParseEther } from "@/lib/utils"; -import useDeployedContracts from "../lib/hooks/contracts/use-deployed-contracts"; -import useManagerManaged from "../lib/hooks/contracts/use-manager-managed"; +import useProtocolContracts from "@/components/lib/hooks/contracts/use-protocol-contracts"; import useBalances from "../lib/hooks/use-balances"; import useSigner from "../lib/hooks/use-signer"; import useTransactionLogger from "../lib/hooks/use-transaction-logger"; @@ -12,7 +11,7 @@ import Button from "../ui/button"; import PositiveNumberInput from "../ui/positive-number-input"; import useRouter from "../lib/hooks/use-router"; import useTrade from "../lib/hooks/use-trade"; -import { USDC_ADDRESS, SWAP_WIDGET_TOKEN_LIST, V3_ROUTER_ADDRESS } from "@/lib/utils"; +import { SWAP_WIDGET_TOKEN_LIST, V3_ROUTER_ADDRESS } from "@/lib/utils"; import { getUniswapV3RouterContract } from "../utils/contracts"; import useWeb3 from "@/components/lib/hooks/use-web-3"; @@ -21,8 +20,7 @@ const UcrRedeem = ({ twapInteger }: { twapInteger: number }) => { const signer = useSigner(); const [balances, refreshBalances] = useBalances(); const [, doTransaction, doingTransaction] = useTransactionLogger(); - const deployedContracts = useDeployedContracts(); - const managedContracts = useManagerManaged(); + const protocolContracts = useProtocolContracts(); const [inputVal, setInputVal] = useState("0"); // cspell: disable-next-line @@ -34,22 +32,24 @@ const UcrRedeem = ({ twapInteger }: { twapInteger: number }) => { return Connect wallet; } - if (!managedContracts || !deployedContracts || !balances) { + if (!protocolContracts || !balances) { return · · ·; } const redeemUcr = async (amount: BigNumber) => { - const { debtCouponManager } = deployedContracts; - // cspell: disable-next-line - await ensureERC20Allowance("uCR -> DebtCouponManager", managedContracts.creditToken, amount, signer, debtCouponManager.address); - await (await debtCouponManager.connect(signer).burnCreditTokensForDollars(amount)).wait(); - refreshBalances(); - // cspell: disable-next-line - if (provider && quoteAmount && selectedRedeemToken !== "uAD") { - const routerContract = getUniswapV3RouterContract(V3_ROUTER_ADDRESS, provider); - await (await routerContract.connect(signer).approveMax(managedContracts.dollarToken.address)).wait(); - await useTrade(selectedRedeemToken, quoteAmount); + const contracts = await protocolContracts; + if (contracts.creditToken && contracts.creditNftManagerFacet && contracts.dollarToken) { + // cspell: disable-next-line + await ensureERC20Allowance("uCR -> CreditNftManagerFacet", contracts.creditToken, amount, signer, contracts.creditNftManagerFacet.address); + await (await contracts.creditNftManagerFacet.connect(signer).burnCreditTokensForDollars(amount)).wait(); refreshBalances(); + // cspell: disable-next-line + if (provider && quoteAmount && selectedRedeemToken !== "uAD") { + const routerContract = getUniswapV3RouterContract(V3_ROUTER_ADDRESS, provider); + await (await routerContract.connect(signer).approveMax(contracts.dollarToken.address)).wait(); + await useTrade(selectedRedeemToken, quoteAmount); + refreshBalances(); + } } }; diff --git a/packages/dapp/components/staking/deposit-share.tsx b/packages/dapp/components/staking/deposit-share.tsx index 7f8463280..7025bc992 100644 --- a/packages/dapp/components/staking/deposit-share.tsx +++ b/packages/dapp/components/staking/deposit-share.tsx @@ -1,7 +1,7 @@ import { BigNumber, ethers } from "ethers"; import { useEffect, useState } from "react"; -import { ManagedContracts } from "@/lib/hooks/contracts/use-manager-managed"; +import { ProtocolContracts } from "@/components/lib/hooks/contracts/use-protocol-contracts"; import { constrainNumber } from "@/lib/utils"; import withLoadedContext, { LoadedContext } from "@/lib/with-loaded-context"; import Button from "../ui/button"; @@ -15,24 +15,25 @@ const MAX_WEEKS = 208; // cspell: disable-next-line type PrefetchedConstants = { totalShares: number; usdPerWeek: number; bondingDiscountMultiplier: BigNumber }; -async function prefetchConstants(contracts: NonNullable): Promise { - const reserves = await contracts.governanceMarket.getReserves(); - +async function prefetchConstants(contracts: NonNullable): Promise { + const contract = await contracts; + const reserves = await contract.sushiPoolGovernanceDollarLp?.getReserves(); const ubqPrice = +reserves[0].toString() / +reserves[1].toString(); - const ubqPerBlock = await contracts.masterChef.governancePerBlock(); - const ubqMultiplier = await contracts.masterChef.governanceMultiplier(); + const ubqPerBlock = await contract.chefFacet?.governancePerBlock(); + const ubqMultiplier = await contract.chefFacet?.governanceMultiplier(); const actualUbqPerBlock = toEtherNum(ubqPerBlock.mul(ubqMultiplier).div(`${1e18}`)); - const blockCountInAWeek = toNum(await contracts.staking.blockCountInAWeek()); + const blockCountInAWeek = toNum(await contract.stakingFacet?.blockCountInAWeek()); const ubqPerWeek = actualUbqPerBlock * blockCountInAWeek; - const totalShares = toEtherNum(await contracts.masterChef.totalShares()); + const totalShares = toEtherNum(await contract.chefFacet?.totalShares()); const usdPerWeek = ubqPerWeek * ubqPrice; // cspell: disable-next-line - const bondingDiscountMultiplier = await contracts.staking.stakingDiscountMultiplier(); + const bondingDiscountMultiplier = await contract.stakingFacet?.stakingDiscountMultiplier(); // cspell: disable-next-line return { totalShares, usdPerWeek, bondingDiscountMultiplier }; } -async function calculateApyForWeeks(contracts: NonNullable, prefetch: PrefetchedConstants, weeksNum: number): Promise { +async function calculateApyForWeeks(contracts: NonNullable, prefetch: PrefetchedConstants, weeksNum: number): Promise { + const contract = await contracts; // cspell: disable-next-line const { totalShares, usdPerWeek, bondingDiscountMultiplier } = prefetch; const DAYS_IN_A_YEAR = 365.2422; @@ -40,7 +41,7 @@ async function calculateApyForWeeks(contracts: NonNullable, pr const bigNumberOneUsdAsLp = ethers.utils.parseEther(usdAsLp.toString()); const weeks = BigNumber.from(weeksNum.toString()); // cspell: disable-next-line - const shares = toEtherNum(await contracts.ubiquityFormulas.durationMultiply(bigNumberOneUsdAsLp, weeks, bondingDiscountMultiplier)); + const shares = toEtherNum(contract.stakingFormulasFacet?.durationMultiply(bigNumberOneUsdAsLp, weeks, bondingDiscountMultiplier)); const rewardsPerWeek = (shares / totalShares) * usdPerWeek; const yearlyYield = (rewardsPerWeek / 7) * DAYS_IN_A_YEAR * 100; return Math.round(yearlyYield * 100) / 100; @@ -52,7 +53,7 @@ type DepositShareProps = { maxLp: BigNumber; } & LoadedContext; -const DepositShare = ({ onStake, disabled, maxLp, managedContracts: contracts }: DepositShareProps) => { +const DepositShare = ({ onStake, disabled, maxLp, protocolContracts: contracts }: DepositShareProps) => { const [amount, setAmount] = useState(""); const [weeks, setWeeks] = useState(""); const [currentApy, setCurrentApy] = useState(null); diff --git a/packages/dapp/components/staking/bonding-shares-explorer.tsx b/packages/dapp/components/staking/staking-shares-explorer.tsx similarity index 60% rename from packages/dapp/components/staking/bonding-shares-explorer.tsx rename to packages/dapp/components/staking/staking-shares-explorer.tsx index 014420123..bc373a4bb 100644 --- a/packages/dapp/components/staking/bonding-shares-explorer.tsx +++ b/packages/dapp/components/staking/staking-shares-explorer.tsx @@ -15,8 +15,8 @@ import Loading from "../ui/loading"; type ShareData = { id: number; // cspell: disable-next-line - ugov: BigNumber; - bond: { + governanceToken: BigNumber; + stake: { minter: string; lpFirstDeposited: BigNumber; creationBlock: BigNumber; @@ -44,65 +44,68 @@ type Actions = { const USD_TO_LP = 0.7460387929; const LP_TO_USD = 1 / USD_TO_LP; -export const BondingSharesExplorerContainer = ({ managedContracts, web3Provider, walletAddress, signer }: LoadedContext) => { +export const StakingSharesExplorerContainer = ({ protocolContracts, web3Provider, walletAddress, signer }: LoadedContext) => { const [model, setModel] = useState(null); const [, doTransaction] = useTransactionLogger(); const [, refreshBalances] = useBalances(); - // cspell: disable-next-line - const { staking: bonding, masterChef, stakingToken: bondingToken, dollarMetapool: metaPool } = managedContracts; useAsyncInit(fetchSharesInformation); async function fetchSharesInformation(processedShareId?: ShareData["id"]) { - console.time("BondingShareExplorerContainer contract loading"); - const currentBlock = await web3Provider.getBlockNumber(); - // cspell: disable-next-line - const blockCountInAWeek = +(await bonding.blockCountInAWeek()).toString(); - const totalShares = await masterChef.totalShares(); // cspell: disable-next-line - const bondingShareIds = await bondingToken.holderTokens(walletAddress); - const walletLpBalance = await metaPool.balanceOf(walletAddress); - - const shares: ShareData[] = []; - await Promise.all( + const { stakingFacet, chefFacet, stakingShare: stakingToken, curveMetaPoolDollarTriPoolLp } = await protocolContracts; + if (stakingFacet) { + console.time("StakingShareExplorerContainer contract loading"); + const currentBlock = await web3Provider.getBlockNumber(); // cspell: disable-next-line - bondingShareIds.map(async (id: BigNumber) => { + const blockCountInAWeek = +(await stakingFacet.blockCountInAWeek()).toString(); + const totalShares = await chefFacet?.totalShares(); + // cspell: disable-next-line + const stakingShareIds = await stakingToken?.holderTokens(walletAddress); + + const walletLpBalance = await curveMetaPoolDollarTriPoolLp?.balanceOf(walletAddress); + + const shares: ShareData[] = []; + await Promise.all( // cspell: disable-next-line - const [ugov, bond, bondingShareInfo, tokenBalance] = await Promise.all([ - // cspell: disable-next-line - masterChef.pendingGovernance(id), + stakingShareIds.map(async (id: BigNumber) => { // cspell: disable-next-line - bondingToken.getStake(id), - masterChef.getStakingShareInfo(id), - // cspell: disable-next-line - bondingToken.balanceOf(walletAddress, id), - ]); + const [governanceToken, stake, stakingShareInfo, tokenBalance] = await Promise.all([ + // cspell: disable-next-line + chefFacet?.pendingGovernance(id), + // cspell: disable-next-line + stakingToken?.getStake(id), + chefFacet?.getStakingShareInfo(id), + // cspell: disable-next-line + stakingToken?.balanceOf(walletAddress, id), + ]); - const endBlock = +bond.endBlock.toString(); - const blocksLeft = endBlock - currentBlock; - const weeksLeft = Math.round((blocksLeft / blockCountInAWeek) * 100) / 100; + const endBlock = +stake.endBlock.toString(); + const blocksLeft = endBlock - currentBlock; + const weeksLeft = Math.round((blocksLeft / blockCountInAWeek) * 100) / 100; - // If this is 0 it means the share ERC1155 token was transferred to another account - if (+tokenBalance.toString() > 0) { - // cspell: disable-next-line - shares.push({ id: +id.toString(), ugov, bond, sharesBalance: bondingShareInfo[0], weeksLeft }); - } - }) - ); - - const sortedShares = shares.sort((a, b) => a.id - b.id); - - console.timeEnd("BondingShareExplorerContainer contract loading"); - setModel((model) => ({ - processing: model ? model.processing.filter((id) => id !== processedShareId) : [], - shares: sortedShares, - totalShares, - walletLpBalance, - })); + // If this is 0 it means the share ERC1155 token was transferred to another account + if (+tokenBalance.toString() > 0) { + // cspell: disable-next-line + shares.push({ id: +id.toString(), governanceToken, stake, sharesBalance: stakingShareInfo[0], weeksLeft }); + } + }) + ); + + const sortedShares = shares.sort((a, b) => a.id - b.id); + + console.timeEnd("StakingShareExplorerContainer contract loading"); + setModel((model) => ({ + processing: model ? model.processing.filter((id) => id !== processedShareId) : [], + shares: sortedShares, + totalShares, + walletLpBalance, + })); + } } function allLpAmount(id: number): BigNumber { if (!model) throw new Error("No model"); - const lpAmount = model.shares.find((s) => s.id === id)?.bond?.lpAmount; + const lpAmount = model.shares.find((s) => s.id === id)?.stake?.lpAmount; if (!lpAmount) throw new Error("Could not find share in model"); return lpAmount; } @@ -110,25 +113,26 @@ export const BondingSharesExplorerContainer = ({ managedContracts, web3Provider, const actions: Actions = { onWithdrawLp: useCallback( async ({ id, amount }) => { + const { stakingFacet: staking, stakingShare: stakingToken } = await protocolContracts; if (!model || model.processing.includes(id)) return; console.log(`Withdrawing ${amount ? amount : "ALL"} LP from ${id}`); setModel((prevModel) => (prevModel ? { ...prevModel, processing: [...prevModel.processing, id] } : null)); doTransaction("Withdrawing LP...", async () => { try { // cspell: disable-next-line - const isAllowed = await bondingToken.isApprovedForAll(walletAddress, bonding.address); + const isAllowed = await stakingToken?.isApprovedForAll(walletAddress, staking?.address); if (!isAllowed) { // cspell: disable-next-line - // Allow bonding contract to control account share + // Allow staking contract to control account share // cspell: disable-next-line - if (!(await performTransaction(bondingToken.connect(signer).setApprovalForAll(bonding.address, true)))) { + if (!(await performTransaction(stakingToken?.connect(signer).setApprovalForAll(staking?.address, true)))) { return; // TODO: Show transaction errors to user } } const bigNumberAmount = amount ? ethers.utils.parseEther(amount.toString()) : allLpAmount(id); // cspell: disable-next-line - await performTransaction(bonding.connect(signer).removeLiquidity(bigNumberAmount, BigNumber.from(id))); + await performTransaction(staking?.connect(signer).removeLiquidity(bigNumberAmount, BigNumber.from(id))); } catch (error) { console.log(`Withdrawing LP from ${id} failed:`, error); // throws exception to update the transaction log @@ -144,12 +148,13 @@ export const BondingSharesExplorerContainer = ({ managedContracts, web3Provider, onClaimUbq: useCallback( async (id) => { + const { chefFacet } = await protocolContracts; if (!model) return; console.log(`Claiming Ubiquity Governance token rewards from ${id}`); setModel((prevModel) => (prevModel ? { ...prevModel, processing: [...prevModel.processing, id] } : null)); doTransaction("Claiming Ubiquity Governance tokens...", async () => { try { - await performTransaction(masterChef.connect(signer).getRewards(BigNumber.from(id))); + await performTransaction(chefFacet?.connect(signer).getRewards(BigNumber.from(id))); } catch (error) { console.log(`Claiming Ubiquity Governance token rewards from ${id} failed:`, error); // throws exception to update the transaction log @@ -165,22 +170,24 @@ export const BondingSharesExplorerContainer = ({ managedContracts, web3Provider, onStake: useCallback( async ({ amount, weeks }) => { + const { stakingFacet: staking, curveMetaPoolDollarTriPoolLp } = await protocolContracts; if (!model || model.processing.length) return; console.log(`Staking ${amount} for ${weeks} weeks`); doTransaction("Staking...", async () => {}); + // cspell: disable-next-line - const allowance = await metaPool.allowance(walletAddress, bonding.address); + const allowance = await curveMetaPoolDollarTriPoolLp?.allowance(walletAddress, staking?.address); console.log("allowance", ethers.utils.formatEther(allowance)); console.log("lpsAmount", ethers.utils.formatEther(amount)); if (allowance.lt(amount)) { // cspell: disable-next-line - await performTransaction(metaPool.connect(signer).approve(bonding.address, amount)); + await performTransaction(curveMetaPoolDollarTriPoolLp?.connect(signer).approve(staking?.address, amount)); // cspell: disable-next-line - const allowance2 = await metaPool.allowance(walletAddress, bonding.address); + const allowance2 = await curveMetaPoolDollarTriPoolLp?.allowance(walletAddress, staking?.address); console.log("allowance2", ethers.utils.formatEther(allowance2)); } // cspell: disable-next-line - await performTransaction(bonding.connect(signer).deposit(amount, weeks)); + await performTransaction(staking?.connect(signer).deposit(amount, weeks)); fetchSharesInformation(); refreshBalances(); @@ -189,27 +196,27 @@ export const BondingSharesExplorerContainer = ({ managedContracts, web3Provider, ), }; - return ; + return ; }; -export const BondingSharesExplorer = memo(({ model, actions }: { model: Model | null; actions: Actions }) => { - return <>{model ? : }; +export const StakingSharesExplorer = memo(({ model, actions }: { model: Model | null; actions: Actions }) => { + return <>{model ? : }; }); -export const BondingSharesInformation = ({ shares, totalShares, onWithdrawLp, onClaimUbq, onStake, processing, walletLpBalance }: Model & Actions) => { +export const StakingSharesInformation = ({ shares, totalShares, onWithdrawLp, onClaimUbq, onStake, processing, walletLpBalance }: Model & Actions) => { const totalUserShares = shares.reduce((sum, val) => { return sum.add(val.sharesBalance); }, BigNumber.from(0)); const totalLpBalance = shares.reduce((sum, val) => { - return sum.add(val.bond.lpAmount); + return sum.add(val.stake.lpAmount); }, BigNumber.from(0)); // cspell: disable-next-line - const totalPendingUgov = shares.reduce((sum, val) => sum.add(val.ugov), BigNumber.from(0)); + const totalPendingGovernanceToken = shares.reduce((sum, val) => sum.add(val.governanceToken), BigNumber.from(0)); - const poolPercentage = formatEther(totalUserShares.mul(ethers.utils.parseEther("100")).div(totalShares)); + const poolPercentage = totalShares.isZero() ? 0 : formatEther(totalUserShares.mul(ethers.utils.parseEther("100")).div(totalShares)); // cspell: disable-next-line - const filteredShares = shares.filter(({ bond: { lpAmount }, ugov }) => lpAmount.gt(0) || ugov.gt(0)); + const filteredShares = shares.filter(({ stake: { lpAmount }, governanceToken }) => lpAmount.gt(0) || governanceToken.gt(0)); return (
@@ -226,7 +233,7 @@ export const BondingSharesInformation = ({ shares, totalShares, onWithdrawLp, on {filteredShares.length > 0 ? ( {filteredShares.map((share) => ( - + ))} ) : ( @@ -249,7 +256,7 @@ export const BondingSharesInformation = ({ shares, totalShares, onWithdrawLp, on {/* cspell: disable-next-line */} - {formatEther(totalPendingUgov)} + {formatEther(totalPendingGovernanceToken)} @@ -272,12 +279,12 @@ export const BondingSharesInformation = ({ shares, totalShares, onWithdrawLp, on ); }; -type BondingShareRowProps = ShareData & { disabled: boolean; onWithdrawLp: Actions["onWithdrawLp"]; onClaimUbq: Actions["onClaimUbq"] }; +type StakingShareRowProps = ShareData & { disabled: boolean; onWithdrawLp: Actions["onWithdrawLp"]; onClaimUbq: Actions["onClaimUbq"] }; // cspell: disable-next-line -const BondingShareRow = ({ id, ugov, sharesBalance, bond, weeksLeft, disabled, onWithdrawLp, onClaimUbq }: BondingShareRowProps) => { +const StakingShareRow = ({ id, governanceToken, stake, weeksLeft, disabled, onWithdrawLp, onClaimUbq }: StakingShareRowProps) => { const [withdrawAmount] = useState(""); - const numLpAmount = +formatEther(bond.lpAmount); + const numLpAmount = +formatEther(stake.lpAmount); const usdAmount = numLpAmount * LP_TO_USD; function onClickWithdraw() { @@ -290,14 +297,14 @@ const BondingShareRow = ({ id, ugov, sharesBalance, bond, weeksLeft, disabled, o } return ( - + - {weeksLeft <= 0 && bond.lpAmount.gt(0) ? ( + {weeksLeft <= 0 && stake.lpAmount.gt(0) ? ( ) : // cspell: disable-next-line - ugov.gt(0) ? ( + governanceToken.gt(0) ? ( @@ -306,7 +313,7 @@ const BondingShareRow = ({ id, ugov, sharesBalance, bond, weeksLeft, disabled, o
{/* cspell: disable-next-line */} - {formatEther(ugov)} + {formatEther(governanceToken)}
{weeksLeft <= 0 ? "Ready" : {weeksLeft}w} @@ -316,4 +323,4 @@ const BondingShareRow = ({ id, ugov, sharesBalance, bond, weeksLeft, disabled, o ); }; -export default withLoadedContext(BondingSharesExplorerContainer); +export default withLoadedContext(StakingSharesExplorerContainer); diff --git a/packages/dapp/pages/credits.tsx b/packages/dapp/pages/credits.tsx index 80320e0d2..c5cf19de5 100644 --- a/packages/dapp/pages/credits.tsx +++ b/packages/dapp/pages/credits.tsx @@ -3,7 +3,7 @@ import DollarPrice from "@/components/redeem/dollar-price"; import UcrRedeem from "@/components/redeem/ucr-redeem"; import UcrNftGenerator from "@/components/redeem/debt-coupon-deposit"; import UcrNftRedeem from "@/components/redeem/ucr-nft-redeem"; -import useManagerManaged from "@/components/lib/hooks/contracts/use-manager-managed"; +import useProtocolContracts from "@/components/lib/hooks/contracts/use-protocol-contracts"; import useEffectAsync from "@/components/lib/hooks/use-effect-async"; // import DisabledBlurredMessage from "@/components/ui/DisabledBlurredMessage"; import dynamic from "next/dynamic"; @@ -11,17 +11,19 @@ const WalletConnectionWall = dynamic(() => import("@/components/ui/wallet-connec const PriceStabilization: FC = (): JSX.Element => { const [twapInteger, setTwapInteger] = useState(0); - const managedContracts = useManagerManaged(); + const protocolContracts = useProtocolContracts(); useEffectAsync(async () => { - if (managedContracts) { - const twapPrice = await managedContracts.dollarTwapOracle.consult(managedContracts.dollarToken.address); + const contracts = await protocolContracts; + if (contracts) { + const dollarTokenAddress = await contracts.managerFacet?.dollarTokenAddress(); + const twapPrice = await contracts.twapOracleDollar3poolFacet?.consult(dollarTokenAddress); if (twapPrice) { const twapPriceInteger = (twapPrice as unknown as number) / 1e18; setTwapInteger(twapPriceInteger); } } - }, [managedContracts]); + }, []); return ( diff --git a/packages/dapp/pages/index.tsx b/packages/dapp/pages/index.tsx index 6003cdfbc..a0a0777e0 100644 --- a/packages/dapp/pages/index.tsx +++ b/packages/dapp/pages/index.tsx @@ -26,7 +26,7 @@ const index: FC = (): JSX.Element => { console.log("protocolContracts is null"); setTwapPrice(null); } - }, [protocolContracts]); + }, []); if (process.env.DEBUG === "true") { fetchData(); diff --git a/packages/dapp/pages/staking.tsx b/packages/dapp/pages/staking.tsx index e26d6cd9e..44d2c372b 100644 --- a/packages/dapp/pages/staking.tsx +++ b/packages/dapp/pages/staking.tsx @@ -1,12 +1,12 @@ import { FC } from "react"; -import BondingSharesExplorer from "@/components/staking/bonding-shares-explorer"; +import StakingSharesExplorer from "@/components/staking/staking-shares-explorer"; import dynamic from "next/dynamic"; const WalletConnectionWall = dynamic(() => import("@/components/ui/wallet-connection-wall"), { ssr: false }); //@note Fix: (Hydration Error) const Staking: FC = (): JSX.Element => { return ( - + ); };