Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NuCypher tvl #86

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 73 additions & 11 deletions src/hooks/__tests__/useFetchTvl.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
useMulticall,
useMulticallContract,
useTStakingContract,
useNuStakingEscrowContract,
useNuWorkLockContract,
} from "../../web3/hooks"
import { useETHData } from "../useETHData"
import { useFetchTvl } from "../useFetchTvl"
Expand All @@ -23,6 +25,8 @@ jest.mock("../../web3/hooks", () => ({
useMulticall: jest.fn(),
useMulticallContract: jest.fn(),
useTStakingContract: jest.fn(),
useNuStakingEscrowContract: jest.fn(),
useNuWorkLockContract: jest.fn(),
}))

jest.mock("../useETHData", () => ({
Expand Down Expand Up @@ -55,6 +59,8 @@ describe("Test `useFetchTvl` hook", () => {
const mockedTStakingContract = { address: "0x2" }
const mockedMultiCallContract = {}
const mockedKeepAssetPoolContract = {}
const mockedNuWorkLockContrarct = { address: "0x3" }
const mockedNuStakingEscrowContract = { address: "0x4" }

const wrapper = ({ children }) => (
<TokenContext.Provider
Expand Down Expand Up @@ -88,6 +94,12 @@ describe("Test `useFetchTvl` hook", () => {
;(useKeepTokenStakingContract as jest.Mock).mockReturnValue(
mockedKeepTokenStakingContract
)
;(useNuStakingEscrowContract as jest.Mock).mockReturnValue(
mockedNuStakingEscrowContract
)
;(useNuWorkLockContract as jest.Mock).mockReturnValue(
mockedNuWorkLockContrarct
)
})

test("should fetch tvl data correctly.", async () => {
Expand All @@ -97,13 +109,27 @@ describe("Test `useFetchTvl` hook", () => {
const coveragePoolTvl = { raw: "300000000000000000000", format: "300.0" }
const keepStaking = { raw: "500000000000000000000", format: "500.0" }
const tStaking = { raw: "600000000000000000000", format: "600.0" }
const nuTotalSupply = { raw: "7000000000000000000000", format: "7000.0" }
const nuCurrentPeriodSupply = {
raw: "800000000000000000000",
format: "800.0",
}
const nuInStakingEscrow = {
raw: "6500000000000000000000",
format: "6500.0",
}
const ethInWorkLock = { raw: "1000000000000000000000", format: "1000.0" }

const multicallRequestResult = [
ethInKeepBonding.raw,
tbtcTokenTotalSupply.raw,
coveragePoolTvl.raw,
keepStaking.raw,
tStaking.raw,
nuTotalSupply.raw,
nuCurrentPeriodSupply.raw,
nuInStakingEscrow.raw,
ethInWorkLock.raw,
]

multicallRequest.mockResolvedValue(multicallRequestResult)
Expand All @@ -112,12 +138,19 @@ describe("Test `useFetchTvl` hook", () => {
const spyOnToUsdBalance = jest.spyOn(usdUtils, "toUsdBalance")
const spyOnUseToken = jest.spyOn(useTokenModule, "useToken")

const haltedRewards =
Number(nuTotalSupply.format) - Number(nuCurrentPeriodSupply.format)
const stakedNU = Number(nuInStakingEscrow.format) - haltedRewards

const _expectedResult = {
ecdsa: ethInKeepBonding.format * mockedETHData.usdPrice,
tbtc: tbtcTokenTotalSupply.format * tbtcContext.usdConversion,
keepCoveragePool: coveragePoolTvl.format * keepContext.usdConversion,
keepStaking: keepStaking.format * keepContext.usdConversion,
tStaking: tStaking.format * tContext.usdConversion,
nu:
stakedNU * nuContext.usdConversion +
Number(ethInWorkLock.format) * mockedETHData.usdPrice,
}

// `FixedNumber` from `@ethersproject/bignumber` adds trailing zero so we
Expand All @@ -128,12 +161,14 @@ describe("Test `useFetchTvl` hook", () => {
keepCoveragePool: `${_expectedResult.keepCoveragePool.toString()}.0`,
keepStaking: `${_expectedResult.keepStaking.toString()}.0`,
tStaking: `${_expectedResult.tStaking.toString()}.0`,
nu: `${_expectedResult.nu.toString()}.0`,
total: `${
_expectedResult.ecdsa +
_expectedResult.tbtc +
_expectedResult.keepCoveragePool +
_expectedResult.keepStaking +
_expectedResult.tStaking
_expectedResult.tStaking +
_expectedResult.nu
}.0`,
}

Expand All @@ -147,6 +182,9 @@ describe("Test `useFetchTvl` hook", () => {
expect(spyOnUseToken).toHaveBeenCalledWith(Token.Keep)
expect(spyOnUseToken).toHaveBeenCalledWith(Token.TBTC)
expect(spyOnUseToken).toHaveBeenCalledWith(Token.T)
expect(spyOnUseToken).toHaveBeenCalledWith(Token.Nu)
expect(useNuStakingEscrowContract).toHaveBeenCalled()
expect(useNuWorkLockContract).toHaveBeenCalled()
expect(useKeepBondingContract).toHaveBeenCalled()
expect(useMulticallContract).toHaveBeenCalled()
expect(useKeepAssetPoolContract).toHaveBeenCalled()
Expand All @@ -173,6 +211,24 @@ describe("Test `useFetchTvl` hook", () => {
method: "balanceOf",
args: [mockedTStakingContract.address],
},
{
contract: nuContext.contract,
method: "totalSupply",
},
{
contract: mockedNuStakingEscrowContract,
method: "currentPeriodSupply",
},
{
contract: nuContext.contract,
method: "balanceOf",
args: [mockedNuStakingEscrowContract.address],
},
{
contract: mockedMultiCallContract,
method: "getEthBalance",
args: [mockedNuWorkLockContrarct.address],
},
])

result.current[1]()
Expand All @@ -183,36 +239,42 @@ describe("Test `useFetchTvl` hook", () => {
expect(spyOnFormatUnits).toHaveBeenCalledTimes(
multicallRequestResult.length
)
// The `toUsdBalance` function was called 2x times because it was called
// first on mount for every value and then after fetching on-chain data.
expect(spyOnToUsdBalance).toHaveBeenCalledTimes(
multicallRequestResult.length * 2
)

expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
6,
8,
ethInKeepBonding.format,
mockedETHData.usdPrice
)
expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
7,
9,
tbtcTokenTotalSupply.format,
tbtcContext.usdConversion
)
expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
8,
10,
coveragePoolTvl.format,
keepContext.usdConversion
)
expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
9,
11,
keepStaking.format,
keepContext.usdConversion
)
expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
10,
12,
tStaking.format,
tContext.usdConversion
)
expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
13,
`${stakedNU.toString()}.0`,
nuContext.usdConversion
)
expect(spyOnToUsdBalance).toHaveBeenNthCalledWith(
14,
ethInWorkLock.format,
mockedETHData.usdPrice
)

expect(result.current[0]).toEqual(expectedResult)
})
Expand Down
51 changes: 51 additions & 0 deletions src/hooks/useFetchTvl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
useKeepAssetPoolContract,
useTStakingContract,
useKeepTokenStakingContract,
useNuStakingEscrowContract,
useNuWorkLockContract,
} from "../web3/hooks"
import { useETHData } from "./useETHData"
import { useToken } from "./useToken"
Expand All @@ -20,6 +22,8 @@ interface TVLRawData {
keepCoveragePoolTVL: string
keepStakingTVL: string
tStakingTVL: string
stakedNU: string
ethInNuNetwork: string
// TODO: add PRE and NU TVL
}

Expand All @@ -38,6 +42,8 @@ const initialState = {
keepCoveragePoolTVL: "0",
keepStakingTVL: "0",
tStakingTVL: "0",
stakedNU: "0",
ethInNuNetwork: "0",
}

export const useFetchTvl = (): [TVLData, () => Promise<TVLRawData>] => {
Expand All @@ -48,12 +54,17 @@ export const useFetchTvl = (): [TVLData, () => Promise<TVLRawData>] => {
keepCoveragePoolTVL,
keepStakingTVL,
tStakingTVL,
stakedNU,
ethInNuNetwork,
} = rawData

const eth = useETHData()
const keep = useToken(Token.Keep)
const tbtc = useToken(Token.TBTC)
const t = useToken(Token.T)
const nu = useToken(Token.Nu)
const nuStakingEscrow = useNuStakingEscrowContract()
const nuWorkLock = useNuWorkLockContract()
const keepBonding = useKeepBondingContract()
const multicall = useMulticallContract()
const keepAssetPool = useKeepAssetPoolContract()
Expand Down Expand Up @@ -81,6 +92,24 @@ export const useFetchTvl = (): [TVLData, () => Promise<TVLRawData>] => {
method: "balanceOf",
args: [tTokenStaking?.address],
},
{
contract: nu.contract!,
method: "totalSupply",
},
{
contract: nuStakingEscrow!,
method: "currentPeriodSupply",
},
{
contract: nu.contract!,
method: "balanceOf",
args: [nuStakingEscrow?.address],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify why we're tracking here the NU balance of staking escrow?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH I implemented based on the https://github.com/nucypher/nucypher-monitor/blob/main/monitor/dashboard.py#L146-L163. Any tips on how to calculate NU TVL correctly would be appreciated 🙂

},
{
contract: multicall!,
method: "getEthBalance",
args: [nuWorkLock?.address],
},
])

const fetchTVLData = useCallback(async () => {
Expand All @@ -93,14 +122,27 @@ export const useFetchTvl = (): [TVLData, () => Promise<TVLRawData>] => {
coveragePoolTvl,
keepStaking,
tStaking,
nuTotalSupply,
nuCurrentPeriodSupply,
nuInEscrow,
ethInNuNetwork,
] = chainData.map((amount: string) => formatUnits(amount.toString()))

const haltedRewards = FixedNumber.fromString(nuTotalSupply).subUnsafe(
FixedNumber.fromString(nuCurrentPeriodSupply)
)
const stakedNU = FixedNumber.fromString(nuInEscrow)
.subUnsafe(haltedRewards)
.toString()

const data: TVLRawData = {
ecdsaTVL: ethInKeepBonding,
tbtcTVL: tbtcTokenTotalSupply,
keepCoveragePoolTVL: coveragePoolTvl,
keepStakingTVL: keepStaking,
tStakingTVL: tStaking,
stakedNU,
ethInNuNetwork,
}
setRawData(data)

Expand All @@ -121,17 +163,23 @@ export const useFetchTvl = (): [TVLData, () => Promise<TVLRawData>] => {

const tStaking = toUsdBalance(tStakingTVL, t.usdConversion)

const stakedNuInUSD = toUsdBalance(stakedNU, nu.usdConversion)
const ethInNu = toUsdBalance(ethInNuNetwork, eth.usdPrice)
const totalNu = stakedNuInUSD.addUnsafe(ethInNu)

return {
ecdsa: ecdsa.toString(),
tbtc: tbtcUSD.toString(),
keepCoveragePool: keepCoveragePool.toString(),
keepStaking: keepStaking.toString(),
tStaking: tStaking.toString(),
nu: totalNu.toString(),
total: ecdsa
.addUnsafe(tbtcUSD)
.addUnsafe(keepCoveragePool)
.addUnsafe(keepStaking)
.addUnsafe(tStaking)
.addUnsafe(totalNu)
.toString(),
} as TVLData
}, [
Expand All @@ -144,6 +192,9 @@ export const useFetchTvl = (): [TVLData, () => Promise<TVLRawData>] => {
keep.usdConversion,
tbtc.usdConversion,
t.usdConversion,
stakedNU,
ethInNuNetwork,
nu.usdConversion,
])

return [data, fetchTVLData]
Expand Down
2 changes: 2 additions & 0 deletions src/web3/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ export * from "./useAssetPoolContract"
export * from "./useTBTCTokenContract"
export * from "./useTStakingContract"
export * from "./useKeepTokenStakingContract"
export * from "./useNuStakingEscrowContract"
export * from "./useNuWorkLockContract"
18 changes: 18 additions & 0 deletions src/web3/hooks/useNuStakingEscrowContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useContract } from "./useContract"

// TODO: Get contract abi from the package and figure out how to use these
// contracts on ropsten and local network. This only works on mainnet.
const ESCROW_ABI = [
{
inputs: [],
name: "currentPeriodSupply",
outputs: [{ internalType: "uint128", name: "", type: "uint128" }],
stateMutability: "view",
type: "function",
},
]
const ESCROW_ADDRESS = "0xbbD3C0C794F40c4f993B03F65343aCC6fcfCb2e2"
Copy link
Contributor

@georgeweiler georgeweiler Feb 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about placing this in our .env? might be better so that we can just add ropsten & local address when they become available? Our env has the supported chainId, so we can be sure to use the correct one based on the env.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a nice idea 👍 , but hopefully, we can get artifacts for mainnet/ropsten/local network from the package like we do for other contracts. So let's hold for a while and we will see if we can get a separate package for ropsten network.


export const useNuStakingEscrowContract = () => {
return useContract(ESCROW_ADDRESS, ESCROW_ABI)
}
24 changes: 24 additions & 0 deletions src/web3/hooks/useNuWorkLockContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useContract } from "./useContract"

// TODO: Get contract abi from the package and figure out how to use these
// contracts on ropsten and local network. This only works on mainnet.
const WORK_LOCK_ADDRESS = "0xe9778E69a961e64d3cdBB34CF6778281d34667c2"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

const ABI = [
{
inputs: [],
name: "escrow",
outputs: [
{
internalType: "contract StakingEscrow",
name: "",
type: "address",
},
],
stateMutability: "view",
type: "function",
},
]

export const useNuWorkLockContract = () => {
return useContract(WORK_LOCK_ADDRESS, ABI)
}