Skip to content

Commit

Permalink
Merge branch 'landing-page' into landing-cards
Browse files Browse the repository at this point in the history
  • Loading branch information
kpyszkowski committed Apr 18, 2024
2 parents 32b5b79 + a165f04 commit 8df74db
Show file tree
Hide file tree
Showing 13 changed files with 567 additions and 18 deletions.
3 changes: 2 additions & 1 deletion dapp/src/pages/ActivityPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Flex, Link as ChakraLink, Icon } from "@chakra-ui/react"

import { Link as ReactRouterLink } from "react-router-dom"
import { useSidebar } from "#/hooks"
import { routerPath } from "#/router/path"
import { ArrowLeft } from "#/assets/icons"
import ActivityDetails from "./ActivityDetails"
import { ActivityBar } from "./ActivityBar"
Expand All @@ -17,7 +18,7 @@ export default function ActivityPage() {

return (
<Flex direction="column" gap={4} p={6}>
<ChakraLink as={ReactRouterLink} to="/">
<ChakraLink as={ReactRouterLink} to={routerPath.overview}>
<Icon
as={ArrowLeft}
boxSize={8}
Expand Down
6 changes: 2 additions & 4 deletions dapp/src/pages/LandingPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useMemo } from "react"
import { Box, Flex, VStack, HStack } from "@chakra-ui/react"
import { Flex, VStack, HStack } from "@chakra-ui/react"
import boostCardIcon from "#/assets/images/card-icon-boost-arrow.png"
import misteryCardIcon from "#/assets/images/card-icon-question-mark.png"
import { useCountdown } from "#/hooks"
Expand All @@ -23,9 +23,7 @@ export default function LandingPage() {
)

return (
// TODO: To be removed, changes for testing purposes only
<Flex w="full" flexFlow="column" px={10} h="400vh">
<Box h="336px" />
<Flex w="full" flexFlow="column" px={10}>
<VStack spacing={4} mx={32}>
<HStack spacing={5} align="stretch" mb={1} w="full">
<IconCard
Expand Down
6 changes: 6 additions & 0 deletions dapp/src/router/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import React from "react"
import { createBrowserRouter } from "react-router-dom"
import LandingPage from "#/pages/LandingPage"
import OverviewPage from "#/pages/OverviewPage"
import ActivityPage from "#/pages/ActivityPage"
import { routerPath } from "./path"

export const router = createBrowserRouter([
{
path: routerPath.home,
element: <LandingPage />,
index: true,
},
{
path: routerPath.overview,
element: <OverviewPage />,
},
{
path: `${routerPath.activity}/:activityId`,
Expand Down
1 change: 1 addition & 0 deletions dapp/src/router/path.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const routerPath = {
home: "/",
overview: "/overview",
activity: "/activity-details",
}
46 changes: 46 additions & 0 deletions sdk/src/lib/contracts/bitcoin-depositor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,44 @@ export type DecodedExtraData = {
referral: number
}

/**
* Represents the tBTC network minting fees.
*/
type TBTCMintingFees = {
/**
* The tBTC treasury fee taken from each deposit and transferred to the
* treasury upon sweep proof submission. Is calculated based on the initial
* funding transaction amount.
*/
treasuryFee: bigint
/**
* The tBTC optimistic minting fee, Is calculated AFTER the treasury fee is
* cut.
*/
optimisticMintingFee: bigint
/**
* Maximum amount of BTC transaction fee that can be incurred by each swept
* deposit being part of the given sweep transaction.
*/
depositTxMaxFee: bigint
}

/**
* Represents the Acre protocol deposit fees.
*/
type AcreDepositFees = {
/**
* The Acre protocol depositor fee taken from each Bitcoin deposit and
* transferred to the treasury upon deposit request finalization.
*/
bitcoinDepositorFee: bigint
}

export type DepositFees = {
tbtc: TBTCMintingFees
acre: AcreDepositFees
}

/**
* Interface for communication with the BitcoinDepositor on-chain contract.
*/
Expand Down Expand Up @@ -36,6 +74,14 @@ export interface BitcoinDepositor extends DepositorProxy {
*/
decodeExtraData(extraData: string): DecodedExtraData

/**
* Calculates the deposit fee based on the provided amount.
* @param amountToDeposit Amount to deposit in 1e18 token precision.
* @returns Deposit fees grouped by tBTC and Acre networks in 1e18 tBTC token
* precision.
*/
calculateDepositFee(amountToDeposit: bigint): Promise<DepositFees>

/**
* @returns Minimum deposit amount.
*/
Expand Down
8 changes: 8 additions & 0 deletions sdk/src/lib/contracts/stbtc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@ export interface StBTC {
* @returns Maximum withdraw value.
*/
assetsBalanceOf(identifier: ChainIdentifier): Promise<bigint>

/**
* Calculates the deposit fee taken from each tBTC deposit to the stBTC pool
* which is then transferred to the treasury.
* @param amount Amount to deposit in 1e18 precision.
* @returns Deposit fee.
*/
calculateDepositFee(amount: bigint): Promise<bigint>
}
101 changes: 100 additions & 1 deletion sdk/src/lib/ethereum/bitcoin-depositor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import {
isAddress,
solidityPacked,
zeroPadBytes,
Contract,
} from "ethers"
import {
ChainIdentifier,
DecodedExtraData,
BitcoinDepositor,
DepositReceipt,
DepositFees,
} from "../contracts"
import { BitcoinRawTxVectors } from "../bitcoin"
import { EthereumAddress } from "./address"
Expand All @@ -23,9 +25,23 @@ import {
EthersContractDeployment,
EthersContractWrapper,
} from "./contract"
import { Hex } from "../utils"
import { Hex, fromSatoshi } from "../utils"
import { EthereumNetwork } from "./network"

type TbtcDepositParameters = {
depositTreasuryFeeDivisor: bigint
depositTxMaxFee: bigint
}

type TbtcBridgeMintingParameters = TbtcDepositParameters & {
optimisticMintingFeeDivisor: bigint
}

type BitcoinDepositorCache = {
tbtcBridgeMintingParameters: TbtcBridgeMintingParameters | undefined
depositorFeeDivisor: bigint | undefined
}

/**
* Ethereum implementation of the BitcoinDepositor.
*/
Expand All @@ -36,6 +52,8 @@ class EthereumBitcoinDepositor
extends EthersContractWrapper<BitcoinDepositorTypechain>
implements BitcoinDepositor
{
#cache: BitcoinDepositorCache

constructor(config: EthersContractConfig, network: EthereumNetwork) {
let artifact: EthersContractDeployment

Expand All @@ -49,6 +67,10 @@ class EthereumBitcoinDepositor
}

super(config, artifact)
this.#cache = {
tbtcBridgeMintingParameters: undefined,
depositorFeeDivisor: undefined,
}
}

/**
Expand Down Expand Up @@ -138,6 +160,83 @@ class EthereumBitcoinDepositor
async minDepositAmount(): Promise<bigint> {
return this.instance.minDepositAmount()
}

/**
* @see {BitcoinDepositor#calculateDepositFee}
*/
async calculateDepositFee(amountToDeposit: bigint): Promise<DepositFees> {
const {
depositTreasuryFeeDivisor,
depositTxMaxFee,
optimisticMintingFeeDivisor,
} = await this.#getTbtcBridgeMintingParameters()

const treasuryFee =
depositTreasuryFeeDivisor > 0
? amountToDeposit / depositTreasuryFeeDivisor
: 0n

const amountSubTreasury = amountToDeposit - treasuryFee

const optimisticMintingFee =
optimisticMintingFeeDivisor > 0
? amountSubTreasury / optimisticMintingFeeDivisor
: 0n

const depositorFeeDivisor = await this.#depositorFeeDivisor()
// Compute depositor fee. The fee is calculated based on the initial funding
// transaction amount, before the tBTC protocol network fees were taken.
const depositorFee =
depositorFeeDivisor > 0n ? amountToDeposit / depositorFeeDivisor : 0n

return {
tbtc: {
treasuryFee,
optimisticMintingFee,
depositTxMaxFee: fromSatoshi(depositTxMaxFee),
},
acre: {
bitcoinDepositorFee: depositorFee,
},
}
}

// TODO: Consider exposing it from tBTC SDK.
async #getTbtcBridgeMintingParameters(): Promise<TbtcBridgeMintingParameters> {
if (this.#cache.tbtcBridgeMintingParameters) {
return this.#cache.tbtcBridgeMintingParameters
}

const bridgeAddress = await this.instance.bridge()
const bridge = new Contract(bridgeAddress, [
"function depositsParameters()",
])
const depositsParameters =
(await bridge.depositsParameters()) as TbtcDepositParameters

const vaultAddress = await this.getTbtcVaultChainIdentifier()
const vault = new Contract(`0x${vaultAddress.identifierHex}`, [
"function optimisticMintingFeeDivisor()",
])
const optimisticMintingFeeDivisor =
(await vault.optimisticMintingFeeDivisor()) as bigint

this.#cache.tbtcBridgeMintingParameters = {
...depositsParameters,
optimisticMintingFeeDivisor,
}
return this.#cache.tbtcBridgeMintingParameters
}

async #depositorFeeDivisor(): Promise<bigint> {
if (this.#cache.depositorFeeDivisor) {
return this.#cache.depositorFeeDivisor
}

this.#cache.depositorFeeDivisor = await this.instance.depositorFeeDivisor()

return this.#cache.depositorFeeDivisor
}
}

export { EthereumBitcoinDepositor, packRevealDepositParameters }
28 changes: 28 additions & 0 deletions sdk/src/lib/ethereum/stbtc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ class EthereumStBTC
extends EthersContractWrapper<StBTCTypechain>
implements StBTC
{
readonly #BASIS_POINT_SCALE = BigInt(1e4)

#cache: {
entryFeeBasisPoints?: bigint
} = { entryFeeBasisPoints: undefined }

constructor(config: EthersContractConfig, network: EthereumNetwork) {
let artifact: EthersContractDeployment

Expand Down Expand Up @@ -44,6 +50,28 @@ class EthereumStBTC
assetsBalanceOf(identifier: ChainIdentifier): Promise<bigint> {
return this.instance.assetsBalanceOf(`0x${identifier.identifierHex}`)
}

/**
* @see {StBTC#calculateDepositFee}
*/
async calculateDepositFee(amount: bigint): Promise<bigint> {
const entryFeeBasisPoints = await this.#getEntryFeeBasisPoints()

return (
(amount * entryFeeBasisPoints) /
(entryFeeBasisPoints + this.#BASIS_POINT_SCALE)
)
}

async #getEntryFeeBasisPoints(): Promise<bigint> {
if (this.#cache.entryFeeBasisPoints) {
return this.#cache.entryFeeBasisPoints
}

this.#cache.entryFeeBasisPoints = await this.instance.entryFeeBasisPoints()

return this.#cache.entryFeeBasisPoints
}
}

// eslint-disable-next-line import/prefer-default-export
Expand Down
47 changes: 45 additions & 2 deletions sdk/src/modules/staking/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { ChainIdentifier, TBTC } from "@keep-network/tbtc-v2.ts"
import { AcreContracts, DepositorProxy } from "../../lib/contracts"
import { AcreContracts, DepositorProxy, DepositFees } from "../../lib/contracts"
import { ChainEIP712Signer } from "../../lib/eip712-signer"
import { StakeInitialization } from "./stake-initialization"
import { toSatoshi } from "../../lib/utils"
import { fromSatoshi, toSatoshi } from "../../lib/utils"

/**
* Represents all total deposit fees grouped by network.
*/
export type DepositFee = {
tbtc: bigint
acre: bigint
total: bigint
}

/**
* Module exposing features related to the staking.
Expand Down Expand Up @@ -80,6 +89,40 @@ class StakingModule {
return this.#contracts.stBTC.assetsBalanceOf(identifier)
}

/**
* Estimates the deposit fee based on the provided amount.
* @param amount Amount to deposit in satoshi.
* @returns Deposit fee grouped by tBTC and Acre networks in 1e8 satoshi
* precision and total deposit fee value.
*/
async estimateDepositFee(amount: bigint): Promise<DepositFee> {
const amountInTokenPrecision = fromSatoshi(amount)

const { acre: acreFees, tbtc: tbtcFees } =
await this.#contracts.bitcoinDepositor.calculateDepositFee(
amountInTokenPrecision,
)
const depositFee = await this.#contracts.stBTC.calculateDepositFee(
amountInTokenPrecision,
)

const sumFeesByProtocol = <
T extends DepositFees["tbtc"] | DepositFees["acre"],
>(
fees: T,
) => Object.values(fees).reduce((reducer, fee) => reducer + fee, 0n)

const tbtc = toSatoshi(sumFeesByProtocol(tbtcFees))

const acre = toSatoshi(sumFeesByProtocol(acreFees)) + toSatoshi(depositFee)

return {
tbtc,
acre,
total: tbtc + acre,
}
}

/**
* @returns Minimum deposit amount in 1e8 satoshi precision.
*/
Expand Down
Loading

0 comments on commit 8df74db

Please sign in to comment.