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

Hotfix/383 balance inside header #387

Open
wants to merge 10 commits into
base: dev
Choose a base branch
from
38 changes: 36 additions & 2 deletions docs/WalletIntegration.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,17 @@ export interface UTXO {
scriptPubKey: string;
}

export interface Inscription {
// output of the inscription in the format of `txid:vout`
output: string;
}

// supported networks
export type Network = "mainnet" | "testnet" | "regtest" | "signet";

// Default number of inscriptions to fetch in a single method call
export const DEFAULT_INSCRIPTION_LIMIT = 100;

/**
* Abstract class representing a wallet provider.
* Provides methods for connecting to a wallet, retrieving wallet information, signing transactions, and more.
Expand Down Expand Up @@ -162,6 +170,12 @@ export abstract class WalletProvider {
* @returns A promise that resolves to the block height.
*/
abstract getBTCTipHeight(): Promise<number>;

/**
* Retrieves the inscriptions for the connected wallet.
* @returns A promise that resolves to an array of inscriptions.
*/
abstract getInscriptions(): Promise<Inscription[]>;
}
```

Expand Down Expand Up @@ -307,7 +321,6 @@ export class OKXWallet extends WalletProvider {
};

// Mempool calls

getBalance = async (): Promise<number> => {
return await getAddressBalance(await this.getAddress());
};
Expand All @@ -328,6 +341,27 @@ export class OKXWallet extends WalletProvider {
getBTCTipHeight = async (): Promise<number> => {
return await getTipHeight();
};

// Inscriptions(Ordinal/Runes/BRC-20 etc)
getInscriptions = async (): Promise<Inscription[]> => {
if (!this.okxWalletInfo) {
throw new Error("OKX Wallet not connected");
}
const inscriptions: Inscription[] = [];
let cursor = 0;
while (true) {
const { list } = await this.bitcoinNetworkProvider.getInscriptions(
cursor,
DEFAULT_INSCRIPTION_LIMIT,
);
inscriptions.push(...list);
if (list.length < DEFAULT_INSCRIPTION_LIMIT) {
break;
}
cursor += DEFAULT_INSCRIPTION_LIMIT;
}
return inscriptions;
};
}
```

Expand Down Expand Up @@ -401,7 +435,7 @@ export async function pushTx(txHex: string): Promise<string> {
* Returns the balance of an address.
* @param address - The Bitcoin address in string format.
* @returns A promise that resolves to the amount of satoshis that the address
* holds.
* holds.
*/
export async function getAddressBalance(address: string): Promise<number> {
const response = await fetch(addressInfoUrl(address));
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "simple-staking",
"version": "0.2.17",
"version": "0.2.20",
"private": true,
"scripts": {
"dev": "next dev",
Expand Down
4 changes: 4 additions & 0 deletions src/app/api/apiWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const apiWrapper = async (
url: string,
generalErrorMessage: string,
params?: any,
timeout?: number,
) => {
let response;
let handler;
Expand All @@ -28,6 +29,9 @@ export const apiWrapper = async (
: {
params,
},
{
timeout: timeout || 0, // 0 is no timeout
},
);
} catch (error) {
if (axios.isAxiosError(error)) {
Expand Down
39 changes: 39 additions & 0 deletions src/app/api/postFilterOrdinals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { chunkArray } from "@/utils/chunkArray";
import { UTXO } from "@/utils/wallet/wallet_provider";

import { apiWrapper } from "./apiWrapper";

export interface UtxoInfo {
txid: string;
vout: number;
inscription: boolean;
}

const TIMEOUT_DURATION = 2000; // 2 seconds
const BATCH_SIZE = 30;

export const postVerifyUtxoOrdinals = async (
utxos: UTXO[],
address: string,
): Promise<UtxoInfo[]> => {
const utxoChunks = chunkArray(utxos, BATCH_SIZE);
const responses = await Promise.all(
utxoChunks.map((chunk) =>
apiWrapper(
"POST",
"/v1/ordinals/verify-utxos",
"Error verifying utxos ordinals",
{
address,
utxos: chunk.map((utxo) => ({
txid: utxo.txid,
vout: utxo.vout,
})),
},
TIMEOUT_DURATION,
),
),
);

return responses.flatMap((response) => response.data.data);
};
1 change: 1 addition & 0 deletions src/app/common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export const OVERFLOW_TVL_WARNING_THRESHOLD = 0.8;
export const OVERFLOW_HEIGHT_WARNING_THRESHOLD = 3;
export const UTXO_KEY = "UTXOs";
19 changes: 12 additions & 7 deletions src/app/components/Connect/ConnectSmall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@ import { maxDecimals } from "@/utils/maxDecimals";
import { trim } from "@/utils/trim";

import { Hash } from "../Hash/Hash";
import { LoadingSmall } from "../Loading/Loading";

interface ConnectSmallProps {
onConnect: () => void;
address: string;
balanceSat: number;
btcWalletBalanceSat?: number;
onDisconnect: () => void;
}

export const ConnectSmall: React.FC<ConnectSmallProps> = ({
onConnect,
address,
balanceSat,
btcWalletBalanceSat,
onDisconnect,
}) => {
const [showMenu, setShowMenu] = useState(false);
Expand All @@ -43,11 +44,15 @@ export const ConnectSmall: React.FC<ConnectSmallProps> = ({
<div className="flex items-center rounded-lg border border-base-200/75 p-2 pr-4">
<div className="flex items-center gap-1">
<FaBitcoin className="text-primary" />
<p>
<strong>
{maxDecimals(satoshiToBtc(balanceSat), 8) || 0} {coinName}
</strong>
</p>
{typeof btcWalletBalanceSat === "number" ? (
<p>
<strong>
{maxDecimals(satoshiToBtc(btcWalletBalanceSat), 8)} {coinName}
</strong>
</p>
) : (
<LoadingSmall text="Loading..." />
)}
</div>
</div>
<div className="relative right-[10px] flex items-center rounded-lg border border-primary bg-[#fdf2ec] p-2 dark:border-white dark:bg-base-200">
Expand Down
20 changes: 13 additions & 7 deletions src/app/components/Connect/ConnectedSmall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ import { maxDecimals } from "@/utils/maxDecimals";
import { trim } from "@/utils/trim";

import { Hash } from "../Hash/Hash";
import { LoadingSmall } from "../Loading/Loading";

interface ConnectedSmallProps {
address: string;
balanceSat: number;
onDisconnect: () => void;
btcWalletBalanceSat?: number;
}

export const ConnectedSmall: React.FC<ConnectedSmallProps> = ({
address,
balanceSat,
btcWalletBalanceSat,
onDisconnect,
}) => {
const [showMenu, setShowMenu] = useState(false);
Expand All @@ -41,11 +42,16 @@ export const ConnectedSmall: React.FC<ConnectedSmallProps> = ({
<div className="flex items-center rounded-lg border border-base-200/75 p-2 pr-4 w-full">
<div className="flex items-center gap-1 w-full justify-center">
<FaBitcoin className="text-primary" />
<p>
<strong>
{maxDecimals(satoshiToBtc(balanceSat), 8) || 0} {coinName}
</strong>
</p>
{typeof btcWalletBalanceSat === "number" ? (
<p>
<strong>
{maxDecimals(satoshiToBtc(btcWalletBalanceSat), 8)}{" "}
{coinName}
</strong>
</p>
) : (
<LoadingSmall text="Loading..." />
)}
</div>
</div>
<div className="relative flex items-center rounded-lg border border-primary bg-[#fdf2ec] p-2 dark:border-white dark:bg-base-200">
Expand Down
5 changes: 5 additions & 0 deletions src/app/components/FAQ/data/questions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ export const questions = (coinName: string): Question[] => {
</ol><br />
<p>In summary, to stake S, you need S + Fs, and upon completion, you get S - Fw or S - Fu - Fw back, depending on whether you wait for expiration or unbond early.</p>`,
},
{
title:
"Is it ok to use a wallet holding fungible tokens built on Bitcoin (e.g. BRC-20/ARC-20/Runes)?",
content: `<p>No, this should be avoided. The fungible tokens built on Bitcoin ecosystem is still in its infancy and in an experimental phase. Software built for the detection of such tokens to avoid their misspending comes without a warranty and guarantees, making it risky to connect wallets owning such tokens to dApps.</p>`,
},
];
if (shouldDisplayTestingMsg()) {
questionList.push({
Expand Down
48 changes: 25 additions & 23 deletions src/app/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,42 +8,44 @@ import { Logo } from "./Logo";
interface HeaderProps {
onConnect: () => void;
address: string;
balanceSat: number;
btcWalletBalanceSat?: number;
onDisconnect: () => void;
}

export const Header: React.FC<HeaderProps> = ({
onConnect,
address,
balanceSat,
btcWalletBalanceSat,
onDisconnect,
}) => {
return (
<nav>
<div className="bg-base-300 shadow-sm">
<div className="container mx-auto flex w-full items-center justify-between gap-4 p-6 pb-4 md:pb-6">
<Logo />
<div className="flex flex-1">
<div className="hidden flex-1 xl:flex">
<TestingInfo />
<div className="container mx-auto flex-col">
<div className="w-full flex items-center justify-between gap-4 p-6 pb-4 md:pb-6">
<Logo />
<div className="flex flex-1">
<div className="hidden flex-1 xl:flex">
<TestingInfo />
</div>
</div>
<ConnectSmall
onConnect={onConnect}
address={address}
btcWalletBalanceSat={btcWalletBalanceSat}
onDisconnect={onDisconnect}
/>
<ThemeToggle />
</div>
<div
className={`container mx-auto flex w-full items-center gap-4 md:hidden md:p-0 ${address ? "justify-end p-6 pt-0" : ""}`}
>
<ConnectedSmall
address={address}
btcWalletBalanceSat={btcWalletBalanceSat}
onDisconnect={onDisconnect}
/>
</div>
<ConnectSmall
onConnect={onConnect}
address={address}
balanceSat={balanceSat}
onDisconnect={onDisconnect}
/>
<ThemeToggle />
</div>
<div
className={`container mx-auto flex w-full items-center gap-4 ${address ? "justify-end p-6 pt-0" : ""} md:hidden md:p-0`}
>
<ConnectedSmall
address={address}
balanceSat={balanceSat}
onDisconnect={onDisconnect}
/>
</div>
</div>
<div className="container mx-auto flex w-full items-center p-6 pb-0 xl:hidden">
Expand Down
28 changes: 24 additions & 4 deletions src/app/components/Modals/ConnectModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export const ConnectModal: React.FC<ConnectModalProps> = ({
onConnect,
connectDisabled,
}) => {
const [accepted, setAccepted] = useState(false);
const [termsAccepted, setTermsAccepted] = useState(false);
const [noInscription, setNoInscription] = useState(false);
const [selectedWallet, setSelectedWallet] = useState<string>("");
const [mounted, setMounted] = useState(false);

Expand Down Expand Up @@ -139,8 +140,8 @@ export const ConnectModal: React.FC<ConnectModalProps> = ({
<input
type="checkbox"
className="checkbox-primary checkbox"
onChange={(e) => setAccepted(e.target.checked)}
checked={accepted}
onChange={(e) => setTermsAccepted(e.target.checked)}
checked={termsAccepted}
/>
<span className="label-text">
I certify that I have read and accept the updated{" "}
Expand All @@ -154,6 +155,20 @@ export const ConnectModal: React.FC<ConnectModalProps> = ({
</span>
</label>
</div>
<div className="form-control">
<label className="label cursor-pointer justify-start gap-2 rounded-xl bg-base-100 p-4">
<input
type="checkbox"
className="checkbox-primary checkbox"
onChange={(e) => setNoInscription(e.target.checked)}
checked={noInscription}
/>
<span className="label-text">
I certify that there are no Bitcoin inscriptions tokens in my
wallet.
</span>
</label>
</div>
<div className="my-4 flex flex-col gap-4">
<h3 className="text-center font-semibold">Choose wallet</h3>
<div className="grid max-h-[20rem] grid-cols-1 gap-4 overflow-y-auto">
Expand Down Expand Up @@ -216,7 +231,12 @@ export const ConnectModal: React.FC<ConnectModalProps> = ({
<button
className="btn-primary btn h-[2.5rem] min-h-[2.5rem] rounded-lg px-2 text-white"
onClick={handleConnect}
disabled={connectDisabled || !accepted || !selectedWallet}
disabled={
connectDisabled ||
!termsAccepted ||
!selectedWallet ||
!noInscription
}
>
<PiWalletBold size={20} />
Connect to {networkName} network
Expand Down
Loading