diff --git a/.github/workflows/solidity.yaml b/.github/workflows/solidity.yaml
index 14e72aa31..a2af4fc9b 100644
--- a/.github/workflows/solidity.yaml
+++ b/.github/workflows/solidity.yaml
@@ -172,7 +172,7 @@ jobs:
path: solidity/
- name: Deploy
- run: pnpm run deployment --no-compile
+ run: pnpm run deploy --no-compile
solidity-deploy-testnet:
needs: [solidity-deploy-dry-run]
@@ -204,8 +204,8 @@ jobs:
- name: Deploy contracts
env:
- ACCOUNTS_PRIVATE_KEYS: ${{ secrets.TESTNET_ETH_CONTRACT_OWNER_PRIVATE_KEY }}
- CHAIN_API_URL: ${{ secrets.SEPOLIA_CHAIN_API_URL }}
+ SEPOLIA_PRIVATE_KEY: ${{ secrets.TESTNET_ETH_CONTRACT_OWNER_PRIVATE_KEY }}
+ SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_CHAIN_API_URL }}
ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }}
run: |
pnpm run deploy --network ${{ github.event.inputs.environment }}
diff --git a/.gitignore b/.gitignore
index 629d01034..022d1e746 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,5 +13,7 @@ tmp/
# Environment configuration files
.envrc
+.env
.env.*
!.env.example
+!.env.ci.example
diff --git a/dapp/src/assets/icons/AlertInfo.tsx b/dapp/src/assets/icons/AlertInfo.tsx
deleted file mode 100644
index a1c8cf1ad..000000000
--- a/dapp/src/assets/icons/AlertInfo.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from "react"
-import { createIcon } from "@chakra-ui/react"
-
-export const AlertInfo = createIcon({
- displayName: "AlertInfo",
- viewBox: "0 0 16 16",
- path: [
-
-
- ,
-
-
-
-
- ,
- ],
-})
diff --git a/dapp/src/assets/icons/index.ts b/dapp/src/assets/icons/index.ts
index 855a92790..d786957f5 100644
--- a/dapp/src/assets/icons/index.ts
+++ b/dapp/src/assets/icons/index.ts
@@ -3,7 +3,6 @@ export * from "./ArrowUpRight"
export * from "./ArrowLeft"
export * from "./ArrowRight"
export * from "./AcreLogo"
-export * from "./AlertInfo"
export * from "./stBTC"
export * from "./BTC"
export * from "./ShieldPlus"
diff --git a/dapp/src/components/Header/ConnectWallet.tsx b/dapp/src/components/Header/ConnectWallet.tsx
index 9aee57748..0398874df 100644
--- a/dapp/src/components/Header/ConnectWallet.tsx
+++ b/dapp/src/components/Header/ConnectWallet.tsx
@@ -1,10 +1,6 @@
import React from "react"
import { Button, HStack, Icon, Tooltip } from "@chakra-ui/react"
-import {
- useRequestBitcoinAccount,
- useRequestEthereumAccount,
- useWalletContext,
-} from "#/hooks"
+import { useWallet } from "#/hooks"
import { CurrencyBalance } from "#/components/shared/CurrencyBalance"
import { TextMd } from "#/components/shared/Typography"
import { BitcoinIcon, EthereumIcon } from "#/assets/icons"
@@ -30,9 +26,10 @@ const getCustomDataByAccount = (
}
export default function ConnectWallet() {
- const { requestAccount: requestBitcoinAccount } = useRequestBitcoinAccount()
- const { requestAccount: requestEthereumAccount } = useRequestEthereumAccount()
- const { btcAccount, ethAccount } = useWalletContext()
+ const {
+ bitcoin: { account: btcAccount, requestAccount: requestBitcoinAccount },
+ ethereum: { account: ethAccount, requestAccount: requestEthereumAccount },
+ } = useWallet()
const customDataBtcAccount = getCustomDataByAccount(btcAccount)
const customDataEthAccount = getCustomDataByAccount(ethAccount)
diff --git a/dapp/src/components/LiquidStakingTokenPopover.tsx b/dapp/src/components/LiquidStakingTokenPopover.tsx
index 229a37ffa..b16da54c0 100644
--- a/dapp/src/components/LiquidStakingTokenPopover.tsx
+++ b/dapp/src/components/LiquidStakingTokenPopover.tsx
@@ -12,8 +12,8 @@ import {
import { SizeType } from "#/types"
import { useDocsDrawer, useSharesBalance, useWalletContext } from "#/hooks"
import { TextMd, TextSm } from "./shared/Typography"
-import Alert from "./shared/Alert"
import { CurrencyBalance } from "./shared/CurrencyBalance"
+import { CardAlert } from "./shared/alerts"
type LiquidStakingTokenPopoverProps = PopoverProps & { popoverSize: SizeType }
@@ -55,18 +55,18 @@ export function LiquidStakingTokenPopover({
variant="greater-balance-xl"
currency="stbtc"
/>
-
Your tokens are this Ethereum address once the staking transaction
is finalized.
-
+
diff --git a/dapp/src/components/TransactionHistory/Table/utils/columns.tsx b/dapp/src/components/TransactionHistory/Table/utils/columns.tsx
index 7523e56f8..d656a50ea 100644
--- a/dapp/src/components/TransactionHistory/Table/utils/columns.tsx
+++ b/dapp/src/components/TransactionHistory/Table/utils/columns.tsx
@@ -1,7 +1,7 @@
import React from "react"
import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
import { StakeHistory } from "#/types"
-import { capitalize, truncateAddress } from "#/utils"
+import { capitalizeFirstLetter, truncateAddress } from "#/utils"
import CustomCell from "../Cell/Custom"
import Cell from "../Cell"
import SimpleText from "../Cell/components/SimpleText"
@@ -32,10 +32,14 @@ export const COLUMNS: ColumnDef[] = [
cell: ({ row: { original } }) => (
{capitalize(original.callTx.action)}
+
+ {capitalizeFirstLetter(original.callTx.action)}
+
}
secondField={
- {capitalize(original.receiptTx.action)}
+
+ {capitalizeFirstLetter(original.receiptTx.action)}
+
}
/>
),
diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx
index f5d21eb54..4b68afa54 100644
--- a/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx
+++ b/dapp/src/components/TransactionModal/ActiveStakingStep/DepositBTCModal.tsx
@@ -1,29 +1,39 @@
-import React, { useCallback } from "react"
+import React, { useCallback, useState } from "react"
import {
useDepositBTCTransaction,
useDepositTelemetry,
useExecuteFunction,
useModalFlowContext,
useStakeFlowContext,
+ useToast,
useTransactionContext,
useWalletContext,
} from "#/hooks"
-import Alert from "#/components/shared/Alert"
import { TextMd } from "#/components/shared/Typography"
import { logPromiseFailure } from "#/utils"
import { PROCESS_STATUSES } from "#/types"
+import { CardAlert } from "#/components/shared/alerts"
+import { TOASTS, TOAST_IDS } from "#/types/toast"
import StakingStepsModalContent from "./StakingStepsModalContent"
+const TOAST_ID = TOAST_IDS.DEPOSIT_TRANSACTION_ERROR
+const TOAST = TOASTS[TOAST_ID]
+
export default function DepositBTCModal() {
const { ethAccount } = useWalletContext()
const { tokenAmount } = useTransactionContext()
const { setStatus } = useModalFlowContext()
const { btcAddress, depositReceipt, stake } = useStakeFlowContext()
const depositTelemetry = useDepositTelemetry()
+ const { closeToast, openToast } = useToast()
- const onStakeBTCSuccess = useCallback(() => {
- setStatus(PROCESS_STATUSES.SUCCEEDED)
- }, [setStatus])
+ const [isLoading, setIsLoading] = useState(false)
+ const [buttonText, setButtonText] = useState("Deposit BTC")
+
+ const onStakeBTCSuccess = useCallback(
+ () => setStatus(PROCESS_STATUSES.SUCCEEDED),
+ [setStatus],
+ )
const onStakeBTCError = useCallback(() => {
setStatus(PROCESS_STATUSES.FAILED)
@@ -36,34 +46,51 @@ export default function DepositBTCModal() {
)
const onDepositBTCSuccess = useCallback(() => {
+ closeToast(TOAST_ID)
setStatus(PROCESS_STATUSES.LOADING)
logPromiseFailure(handleStake())
- }, [setStatus, handleStake])
+ }, [closeToast, setStatus, handleStake])
- const { sendBitcoinTransaction } =
- useDepositBTCTransaction(onDepositBTCSuccess)
+ const showError = useCallback(() => {
+ openToast({
+ id: TOAST_ID,
+ render: TOAST,
+ })
+ setButtonText("Try again")
+ }, [openToast])
+
+ const onDepositBTCError = useCallback(() => showError(), [showError])
+
+ const { sendBitcoinTransaction } = useDepositBTCTransaction(
+ onDepositBTCSuccess,
+ onDepositBTCError,
+ )
const handledDepositBTC = useCallback(async () => {
if (!tokenAmount?.amount || !btcAddress || !depositReceipt || !ethAccount)
return
+ setIsLoading(true)
const response = await depositTelemetry(
depositReceipt,
btcAddress,
ethAccount.address,
)
+ setIsLoading(false)
- // TODO: Display the correct message for the user
- if (response.verificationStatus !== "valid") return
-
- logPromiseFailure(sendBitcoinTransaction(tokenAmount?.amount, btcAddress))
+ if (response.verificationStatus === "valid") {
+ logPromiseFailure(sendBitcoinTransaction(tokenAmount?.amount, btcAddress))
+ } else {
+ showError()
+ }
}, [
btcAddress,
depositReceipt,
depositTelemetry,
ethAccount,
sendBitcoinTransaction,
+ showError,
tokenAmount?.amount,
])
@@ -73,15 +100,16 @@ export default function DepositBTCModal() {
return (
-
+
Make a Bitcoin transaction to deposit and stake your BTC.
-
+
)
}
diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/SignMessageModal.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/SignMessageModal.tsx
index 84803da08..37bba6883 100644
--- a/dapp/src/components/TransactionModal/ActiveStakingStep/SignMessageModal.tsx
+++ b/dapp/src/components/TransactionModal/ActiveStakingStep/SignMessageModal.tsx
@@ -1,34 +1,58 @@
-import React, { useCallback, useEffect } from "react"
+import React, { useCallback, useEffect, useState } from "react"
import {
useExecuteFunction,
useModalFlowContext,
useStakeFlowContext,
+ useToast,
} from "#/hooks"
import { logPromiseFailure } from "#/utils"
-import AlertReceiveSTBTC from "#/components/shared/AlertReceiveSTBTC"
-import { PROCESS_STATUSES } from "#/types"
+import { PROCESS_STATUSES, TOASTS, TOAST_IDS } from "#/types"
+import { ReceiveSTBTCAlert } from "#/components/shared/alerts"
import StakingStepsModalContent from "./StakingStepsModalContent"
+const TOAST_ID = TOAST_IDS.SIGNING_ERROR
+const TOAST = TOASTS[TOAST_ID]
+
export default function SignMessageModal() {
const { goNext, setStatus } = useModalFlowContext()
const { signMessage } = useStakeFlowContext()
- const handleSignMessage = useExecuteFunction(signMessage, goNext)
-
- const handleSignMessageWrapper = useCallback(() => {
- logPromiseFailure(handleSignMessage())
- }, [handleSignMessage])
+ const [buttonText, setButtonText] = useState("Sign now")
+ const { closeToast, openToast } = useToast()
useEffect(() => {
setStatus(PROCESS_STATUSES.PENDING)
}, [setStatus])
+ const onSignMessageSuccess = useCallback(() => {
+ closeToast(TOAST_ID)
+ goNext()
+ }, [closeToast, goNext])
+
+ const onSignMessageError = useCallback(() => {
+ openToast({
+ id: TOAST_ID,
+ render: TOAST,
+ })
+ setButtonText("Try again")
+ }, [openToast])
+
+ const handleSignMessage = useExecuteFunction(
+ signMessage,
+ onSignMessageSuccess,
+ onSignMessageError,
+ )
+
+ const handleSignMessageWrapper = useCallback(() => {
+ logPromiseFailure(handleSignMessage())
+ }, [handleSignMessage])
+
return (
-
+
)
}
diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/StakeFormModal/StakeDetails.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/StakeFormModal/StakeDetails.tsx
index bba5a7c28..9f6d8ebf3 100644
--- a/dapp/src/components/TransactionModal/ActiveStakingStep/StakeFormModal/StakeDetails.tsx
+++ b/dapp/src/components/TransactionModal/ActiveStakingStep/StakeFormModal/StakeDetails.tsx
@@ -11,12 +11,12 @@ function StakeDetails({
maxTokenAmount,
}: {
currency: CurrencyType
- minTokenAmount: string
- maxTokenAmount: string
+ minTokenAmount: bigint
+ maxTokenAmount: bigint
}) {
const value = useTokenAmountFormValue() ?? 0n
- const isMaximumValueExceeded = value > BigInt(maxTokenAmount)
- const isMinimumValueFulfilled = value >= BigInt(minTokenAmount)
+ const isMaximumValueExceeded = value > maxTokenAmount
+ const isMinimumValueFulfilled = value >= minTokenAmount
// Let's not calculate the details of the transaction when the value is not valid.
const amount = !isMaximumValueExceeded && isMinimumValueFulfilled ? value : 0n
const details = useTransactionDetails(amount)
diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/StakeFormModal/index.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/StakeFormModal/index.tsx
index 5f80d9576..7e627e73d 100644
--- a/dapp/src/components/TransactionModal/ActiveStakingStep/StakeFormModal/index.tsx
+++ b/dapp/src/components/TransactionModal/ActiveStakingStep/StakeFormModal/index.tsx
@@ -1,8 +1,7 @@
import React from "react"
-import { BITCOIN_MIN_AMOUNT } from "#/constants"
import TokenAmountForm from "#/components/shared/TokenAmountForm"
import { TokenAmountFormValues } from "#/components/shared/TokenAmountForm/TokenAmountFormBase"
-import { useWalletContext } from "#/hooks"
+import { useMinDepositAmount, useWalletContext } from "#/hooks"
import { FormSubmitButton } from "#/components/shared/Form"
import StakeDetails from "./StakeDetails"
@@ -11,20 +10,21 @@ function StakeFormModal({
}: {
onSubmitForm: (values: TokenAmountFormValues) => void
}) {
+ const minDepositAmount = useMinDepositAmount()
const { btcAccount } = useWalletContext()
- const tokenBalance = btcAccount?.balance.toString() ?? "0"
+ const tokenBalance = BigInt(btcAccount?.balance.toString() ?? "0")
return (
Stake
diff --git a/dapp/src/components/TransactionModal/ActiveStakingStep/StakingStepsModalContent.tsx b/dapp/src/components/TransactionModal/ActiveStakingStep/StakingStepsModalContent.tsx
index bca9915d2..24f13b273 100644
--- a/dapp/src/components/TransactionModal/ActiveStakingStep/StakingStepsModalContent.tsx
+++ b/dapp/src/components/TransactionModal/ActiveStakingStep/StakingStepsModalContent.tsx
@@ -1,14 +1,9 @@
import React from "react"
-import {
- Button,
- HStack,
- ModalBody,
- ModalFooter,
- ModalHeader,
-} from "@chakra-ui/react"
+import { HStack, ModalBody, ModalFooter, ModalHeader } from "@chakra-ui/react"
import { TextLg, TextMd } from "#/components/shared/Typography"
import StepperBase, { StepBase } from "#/components/shared/StepperBase"
import Spinner from "#/components/shared/Spinner"
+import { LoadingButton } from "#/components/shared/LoadingButton"
export function Title({ children }: { children: React.ReactNode }) {
return {children}
@@ -43,12 +38,14 @@ const STEPS: StepBase[] = [
export default function StakingStepsModalContent({
buttonText,
+ isLoading,
activeStep,
onClick,
children,
}: {
buttonText: string
activeStep: number
+ isLoading?: boolean
onClick: () => void
children: React.ReactNode
}) {
@@ -68,9 +65,14 @@ export default function StakingStepsModalContent({
{children}
-
+
>
)
diff --git a/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx b/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx
index 0f9bd1003..d462cab94 100644
--- a/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx
+++ b/dapp/src/components/TransactionModal/ActiveUnstakingStep/SignMessageModal.tsx
@@ -3,8 +3,8 @@ import { useExecuteFunction, useModalFlowContext } from "#/hooks"
import { PROCESS_STATUSES } from "#/types"
import { Button, ModalBody, ModalFooter, ModalHeader } from "@chakra-ui/react"
import { TextMd } from "#/components/shared/Typography"
-import AlertReceiveSTBTC from "#/components/shared/AlertReceiveSTBTC"
import { logPromiseFailure } from "#/utils"
+import { ReceiveSTBTCAlert } from "#/components/shared/alerts"
export default function SignMessageModal() {
const { setStatus } = useModalFlowContext()
@@ -46,7 +46,7 @@ export default function SignMessageModal() {
You will sign a gas-free Ethereum message to indicate the address
where you'd like to get your stBTC liquid staking token.
-
+
|