-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
276 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { useWidgetState } from "@/hooks/useWidgetState"; | ||
|
||
import { Error } from "./index"; | ||
|
||
interface ErrorContainer { | ||
className?: string; | ||
} | ||
|
||
export function ErrorContainer({ className }: ErrorContainer) { | ||
const { screen } = useWidgetState(); | ||
const { icon, title, description, cancelButton, submitButton, onCancel, onSubmit } = screen.params ?? {}; | ||
|
||
return ( | ||
<Error | ||
className={className} | ||
icon={icon} | ||
title={title} | ||
description={description} | ||
cancelButton={cancelButton} | ||
submitButton={submitButton} | ||
onCancel={onCancel} | ||
onSubmit={onSubmit} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import type { Meta, StoryObj } from "@storybook/react"; | ||
|
||
import { Error } from "./index"; | ||
|
||
const meta: Meta<typeof Error> = { | ||
component: Error, | ||
tags: ["autodocs"], | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
className: "", | ||
icon: ( | ||
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="52" viewBox="0 0 52 52" fill="none"> | ||
<path | ||
d="M2.16675 46.5837H49.8334L26.0001 5.41699L2.16675 46.5837ZM28.1667 40.0837H23.8334V35.7503H28.1667V40.0837ZM28.1667 31.417H23.8334V22.7503H28.1667V31.417Z" | ||
fill="#387085" | ||
/> | ||
</svg> | ||
), | ||
title: "Public Key Mismatch", | ||
description: | ||
"The Bitcoin address and Public Key for this wallet do not match. Please contact your wallet provider for support.", | ||
cancelButton: "Cancel", | ||
submitButton: "Continue Anyway", | ||
onCancel: () => console.log("cancel"), | ||
onSubmit: () => console.log("submit"), | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { Button, DialogBody, DialogFooter, Heading, Text } from "@babylonlabs-io/bbn-core-ui"; | ||
import {} from "react"; | ||
|
||
interface ErrorProps { | ||
className?: string; | ||
icon: JSX.Element; | ||
title: string | JSX.Element; | ||
description: string | JSX.Element; | ||
cancelButton?: string | JSX.Element; | ||
submitButton?: string | JSX.Element; | ||
onCancel?: () => void; | ||
onSubmit?: () => void; | ||
} | ||
|
||
export function Error({ | ||
className, | ||
icon, | ||
title, | ||
description, | ||
cancelButton = "Cancel", | ||
submitButton = "Submit", | ||
onCancel, | ||
onSubmit, | ||
}: ErrorProps) { | ||
return ( | ||
<div className={className}> | ||
<DialogBody className="py-16 text-center"> | ||
<div className="mb-6 inline-flex h-20 w-20 items-center justify-center bg-primary-contrast text-primary-light"> | ||
{icon} | ||
</div> | ||
|
||
<Heading variant="h4" className="mb-4 text-accent-primary"> | ||
{title} | ||
</Heading> | ||
|
||
<Text as="div" className="text-accent-secondary"> | ||
{description} | ||
</Text> | ||
</DialogBody> | ||
|
||
<DialogFooter className="flex gap-4"> | ||
<Button variant="outlined" fluid onClick={onCancel}> | ||
{cancelButton} | ||
</Button> | ||
|
||
<Button fluid onClick={onSubmit}> | ||
{submitButton} | ||
</Button> | ||
</DialogFooter> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,109 @@ | ||
import { networks } from "bitcoinjs-lib"; | ||
import * as ecc from "@bitcoin-js/tiny-secp256k1-asmjs"; | ||
import { initEccLib, networks, payments } from "bitcoinjs-lib"; | ||
import { toXOnly } from "bitcoinjs-lib/src/psbt/bip371"; | ||
|
||
import { Network } from "@/core/types"; | ||
export const COMPRESSED_PUBLIC_KEY_HEX_LENGTH = 66; | ||
|
||
export function validateAddress(network: Network, address: string): void { | ||
if (network === Network.MAINNET && !address.startsWith("bc1")) { | ||
throw new Error("Incorrect address prefix for Mainnet. Expected address to start with 'bc1'."); | ||
initEccLib(ecc); | ||
|
||
const NETWORKS = { | ||
[Network.MAINNET]: { | ||
name: "Mainnet", | ||
config: networks.bitcoin, | ||
prefix: { | ||
common: "bc1", | ||
nativeSegWit: "bc1q", | ||
taproot: "bc1p", | ||
}, | ||
}, | ||
[Network.CANARY]: { | ||
name: "Canary", | ||
config: networks.bitcoin, | ||
prefix: { | ||
common: "bc1", | ||
nativeSegWit: "bc1q", | ||
taproot: "bc1p", | ||
}, | ||
}, | ||
[Network.TESTNET]: { | ||
name: "Testnet", | ||
config: networks.testnet, | ||
prefix: { | ||
common: "tb1", | ||
nativeSegWit: "tb1q", | ||
taproot: "tb1p", | ||
}, | ||
}, | ||
[Network.SIGNET]: { | ||
name: "Signet", | ||
config: networks.testnet, | ||
prefix: { | ||
common: "tb1", | ||
nativeSegWit: "tb1q", | ||
taproot: "tb1p", | ||
}, | ||
}, | ||
}; | ||
|
||
export const getTaprootAddress = (publicKey: string, network: Network) => { | ||
if (publicKey.length == COMPRESSED_PUBLIC_KEY_HEX_LENGTH) { | ||
publicKey = publicKey.slice(2); | ||
} | ||
if (network === Network.CANARY && !address.startsWith("bc1")) { | ||
throw new Error("Incorrect address prefix for Canary. Expected address to start with 'bc1'."); | ||
|
||
const internalPubkey = Buffer.from(publicKey, "hex"); | ||
const { address, output: scriptPubKey } = payments.p2tr({ | ||
internalPubkey: toXOnly(internalPubkey), | ||
network: NETWORKS[network].config, | ||
}); | ||
|
||
if (!address || !scriptPubKey) { | ||
throw new Error("Failed to generate taproot address or script from public key"); | ||
} | ||
if ((network === Network.TESTNET || network === Network.SIGNET) && !address.startsWith("tb1")) { | ||
throw new Error("Incorrect address prefix for Testnet/Signet. Expected address to start with 'tb1'."); | ||
|
||
return address; | ||
}; | ||
|
||
export const getNativeSegwitAddress = (publicKey: string, network: Network) => { | ||
if (publicKey.length !== COMPRESSED_PUBLIC_KEY_HEX_LENGTH) { | ||
throw new Error("Invalid public key length for generating native segwit address"); | ||
} | ||
|
||
if (![Network.MAINNET, Network.SIGNET, Network.TESTNET, Network.CANARY].includes(network)) { | ||
throw new Error(`Unsupported network: ${network}. Please provide a valid network.`); | ||
const internalPubkey = Buffer.from(publicKey, "hex"); | ||
const { address, output: scriptPubKey } = payments.p2wpkh({ | ||
pubkey: internalPubkey, | ||
network: NETWORKS[network].config, | ||
}); | ||
|
||
if (!address || !scriptPubKey) { | ||
throw new Error("Failed to generate native segwit address or script from public key"); | ||
} | ||
|
||
return address; | ||
}; | ||
|
||
export function validateAddressWithPK(address: string, publicKey: string, network: Network) { | ||
if (address.startsWith(NETWORKS[network].prefix.taproot)) { | ||
return address === getTaprootAddress(publicKey, network); | ||
} | ||
|
||
if (address.startsWith(NETWORKS[network].prefix.nativeSegWit)) { | ||
return address === getNativeSegwitAddress(publicKey, network); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
export const toNetwork = (network: Network): networks.Network => { | ||
switch (network) { | ||
case Network.MAINNET: | ||
case Network.CANARY: | ||
return networks.bitcoin; | ||
case Network.TESTNET: | ||
case Network.SIGNET: | ||
return networks.testnet; | ||
default: | ||
throw new Error("Unsupported network"); | ||
export function validateAddress(network: Network, address: string): void { | ||
const { prefix, name } = NETWORKS[network]; | ||
|
||
if (!(network in NETWORKS)) { | ||
throw new Error(`Unsupported network: ${network}. Please provide a valid network.`); | ||
} | ||
}; | ||
|
||
if (!address.startsWith(prefix.common)) { | ||
throw new Error(`Incorrect address prefix for ${name}. Expected address to start with '${prefix}'.`); | ||
} | ||
} | ||
|
||
export const toNetwork = (network: Network): networks.Network => NETWORKS[network].config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters