Skip to content

Commit

Permalink
feat(wallet): leather wallet integration (#219)
Browse files Browse the repository at this point in the history
* feat(wallet): leather wallet

* fix(wallet): unisat connect should be use unisat wallet

* comment(wallet-modal): remove & update leather comment

* fix(leather): use address format on signMessage function

* fix(signMessage): validate address & format

* fix(selectModal): variable naming & separate error

* Update packages/ord-connect/src/components/SelectWalletModal/index.tsx

Co-authored-by: Benedict Pak <10258208+Nanosync@users.noreply.github.com>

* Update packages/ord-connect/src/components/SelectWalletModal/index.tsx

Co-authored-by: Benedict Pak <10258208+Nanosync@users.noreply.github.com>

* docs(preview): update preview image

* docs(preview): update preview image

---------

Co-authored-by: Benedict Pak <10258208+Nanosync@users.noreply.github.com>
  • Loading branch information
joundy and Nanosync authored Feb 26, 2024
1 parent b60593b commit 90a04c9
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
| Unisat |||
| Xverse |||
| Magic Eden |||
| Leather |||

## Quick Start

Expand Down
3 changes: 1 addition & 2 deletions packages/ord-connect/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
},
"dependencies": {
"@headlessui/react": "^1.7.18",
"@ordzaar/ordit-sdk": "1.3.1",
"bitcoinjs-lib": "6.1.5",
"boring-avatars": "^1.10.1"
},
Expand All @@ -60,7 +59,7 @@
]
},
"peerDependencies": {
"@ordzaar/ordit-sdk": "1.3.1",
"@ordzaar/ordit-sdk": "1.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
Expand Down
9 changes: 9 additions & 0 deletions packages/ord-connect/src/assets/leather-wallet.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Avatar from "boring-avatars";
import { Menu, Transition } from "@headlessui/react";

import ChevronDownIcon from "../../assets/chevron-down.svg";
import LeatherWalletIcon from "../../assets/leather-wallet.svg";
import LogoutIcon from "../../assets/logout.svg";
import MagicEdenIcon from "../../assets/magiceden-wallet.svg";
import UnisatWalletIcon from "../../assets/unisat-wallet.svg";
Expand All @@ -14,6 +15,7 @@ const WALLET_TO_ICON: Record<Wallet, string> = {
[Wallet.MAGICEDEN]: MagicEdenIcon,
[Wallet.UNISAT]: UnisatWalletIcon,
[Wallet.XVERSE]: XverseWalletIcon,
[Wallet.LEATHER]: LeatherWalletIcon,
} as const;

interface PostConnectButtonProp {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const WALLET_TO_NAME: Record<Wallet, string> = {
[Wallet.MAGICEDEN]: "Magic Eden",
[Wallet.UNISAT]: "UniSat",
[Wallet.XVERSE]: "Xverse",
[Wallet.LEATHER]: "Leather",
} as const;

interface WalletButtonProp {
Expand Down
68 changes: 68 additions & 0 deletions packages/ord-connect/src/components/SelectWalletModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import {
BrowserWalletNotInstalledError,
BrowserWalletRequestCancelledByUserError,
} from "@ordzaar/ordit-sdk";
import { getAddresses as getLeatherAddresses } from "@ordzaar/ordit-sdk/leather";
import { getAddresses as getMagicEdenAddress } from "@ordzaar/ordit-sdk/magiceden";
import { getAddresses as getUnisatAddresses } from "@ordzaar/ordit-sdk/unisat";
import { getAddresses as getXverseAddresses } from "@ordzaar/ordit-sdk/xverse";

import CloseModalIcon from "../../assets/close-modal.svg";
import LeatherWalletIcon from "../../assets/leather-wallet.svg";
import MagicEdenWalletIcon from "../../assets/magiceden-wallet.svg";
import UnisatWalletIcon from "../../assets/unisat-wallet.svg";
import XverseWalletIcon from "../../assets/xverse-wallet.svg";
Expand All @@ -29,6 +31,7 @@ const WALLET_CHROME_EXTENSION_URL: Record<Wallet, string> = {
[Wallet.MAGICEDEN]: "https://wallet.magiceden.io/",
[Wallet.UNISAT]: "https://unisat.io/download", // their www subdomain doesn't work
[Wallet.XVERSE]: "https://www.xverse.app/download",
[Wallet.LEATHER]: "https://leather.io/install-extension",
};

export function SelectWalletModal({
Expand Down Expand Up @@ -245,6 +248,58 @@ export function SelectWalletModal({
updatePublicKey,
updateWallet,
]);
const onConnectLeatherWallet = useCallback(async () => {
try {
setErrorMessage("");
const leather = await getLeatherAddresses(network);
if (!leather || leather.length < 1) {
disconnectWallet();
throw new Error("Leather via Ordit returned no addresses.");
}

const paymentAddress = leather.find(
(walletAddress) => walletAddress.format === "segwit",
);
if (!paymentAddress) {
throw new Error("Leather via Ordit did not return a Segwit address.");
}

const ordinalAddress = leather.find(
(walletAddress) => walletAddress.format === "taproot",
);
if (!ordinalAddress) {
throw new Error("Leather via Ordit did not return a Taproot address.");
}

updateAddress({
ordinals: ordinalAddress.address,
payments: paymentAddress.address,
});
updatePublicKey({
ordinals: ordinalAddress.publicKey,
payments: paymentAddress.publicKey,
});
updateWallet(Wallet.LEATHER);
updateFormat({
ordinals: ordinalAddress.format,
payments: paymentAddress.format,
});
closeModal();
return true;
} catch (err) {
onError(Wallet.LEATHER, err as Error);
return false;
}
}, [
closeModal,
disconnectWallet,
network,
onError,
updateAddress,
updateFormat,
updatePublicKey,
updateWallet,
]);

// Reconnect address change listener if there there is already a connected wallet
useEffect(() => {
Expand Down Expand Up @@ -372,6 +427,19 @@ export function SelectWalletModal({
renderAvatar={renderAvatar}
/>
)}
<hr className="horizontal-separator" />
{!isMobile && (
<WalletButton
wallet={Wallet.LEATHER}
subtitle="Coming soon on mobile browsing"
onConnect={onConnectLeatherWallet}
icon={LeatherWalletIcon}
setErrorMessage={setErrorMessage}
isDisabled={isMobile}
isMobileDevice={isMobile}
renderAvatar={renderAvatar}
/>
)}
</section>
) : (
<Dialog.Description className="unsupported-browser-message">
Expand Down
22 changes: 20 additions & 2 deletions packages/ord-connect/src/hooks/useSignMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,42 @@ export function useSignMessage(): {
signMsg: (address: string, message: string) => Promise<string | null>;
error: string | null;
} {
const { network, wallet, publicKey, format } = useOrdConnect();
const {
network,
wallet,
publicKey,
format,
address: walletAddresses,
} = useOrdConnect();
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);

const signMsg = useCallback(
async (address: string, message: string) => {
setIsLoading(true);

try {
setError(null);
if (!format || !publicKey || !wallet) {
throw new Error("No wallet is connected");
}

if (
walletAddresses.ordinals !== address &&
walletAddresses.payments !== address
) {
throw new Error("Address supplied is not connected address");
}

const signedMessage = await signMessage({
address,
wallet,
message,
network,
format:
walletAddresses.ordinals === address
? format.ordinals!
: format.payments!,
});

setIsLoading(false);
Expand All @@ -36,7 +54,7 @@ export function useSignMessage(): {
throw err;
}
},
[format, network, publicKey, wallet],
[format, network, publicKey, wallet, walletAddresses],
);

return { signMsg, error, isLoading };
Expand Down
28 changes: 28 additions & 0 deletions packages/ord-connect/src/lib/signMessage.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import { AddressFormat } from "@ordzaar/ordit-sdk";
import {
LeatherAddressType,
signMessage as signLeatherMessage,
} from "@ordzaar/ordit-sdk/leather";
import { signMessage as signMagicEdenMessage } from "@ordzaar/ordit-sdk/magiceden";
import { signMessage as signUnisatMessage } from "@ordzaar/ordit-sdk/unisat";
import { signMessage as signXverseMessage } from "@ordzaar/ordit-sdk/xverse";
Expand All @@ -9,6 +14,19 @@ interface SignMessageParams {
wallet: Wallet;
address: string;
network: Network;
format: AddressFormat;
}

function leatherPaymentTypeFromFormat(
format: AddressFormat,
): LeatherAddressType {
if (format === "segwit") {
return LeatherAddressType.P2WPKH;
}
if (format === "taproot") {
return LeatherAddressType.P2TR;
}
throw new Error("Leather payment address format is not supported");
}

/**
Expand All @@ -22,6 +40,7 @@ export default async function signMessage({
wallet,
address,
network,
format,
}: SignMessageParams): Promise<string | null> {
if (wallet === Wallet.MAGICEDEN) {
const { base64 } = await signMagicEdenMessage(message, address, network);
Expand All @@ -38,5 +57,14 @@ export default async function signMessage({
return base64;
}

if (wallet === Wallet.LEATHER) {
const paymentType = leatherPaymentTypeFromFormat(format);
const { base64 } = await signLeatherMessage(message, {
paymentType,
network,
});
return base64;
}

throw new Error("Invalid wallet selected");
}
12 changes: 12 additions & 0 deletions packages/ord-connect/src/lib/signPsbt.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { signPsbt as signLeatherPsbt } from "@ordzaar/ordit-sdk/leather";
import { signPsbt as signMagicEdenPsbt } from "@ordzaar/ordit-sdk/magiceden";
import { signPsbt as signUnisatPsbt } from "@ordzaar/ordit-sdk/unisat";
import { signPsbt as signXversePsbt } from "@ordzaar/ordit-sdk/xverse";
Expand Down Expand Up @@ -83,6 +84,17 @@ export default async function signPsbt({
});
return signedXversePsbt;
}

if (wallet === Wallet.LEATHER) {
const signedLeatherPsbt = await signLeatherPsbt(psbt, {
network,
finalize,
extractTx,
allowedSighash: options?.sigHash ? [options?.sigHash] : [],
signAtIndexes: options?.signingIndexes ?? getAllInputIndices(), // If signingIndexes is not provided, just sign everything
});
return signedLeatherPsbt;
}
// else throw error
throw new Error("Invalid wallet selected");
}
5 changes: 3 additions & 2 deletions packages/ord-connect/src/providers/OrdConnectProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ export enum Wallet {
UNISAT = "unisat",
XVERSE = "xverse",
MAGICEDEN = "magiceden",
LEATHER = "leather",
}

export interface BiAddress<T> {
payments: T | null;
ordinals: T | null;
}

type BiAddressString = BiAddress<string>;
type BiAddressFormat = BiAddress<AddressFormat>;
export type BiAddressString = BiAddress<string>;
export type BiAddressFormat = BiAddress<AddressFormat>;

const EMPTY_BIADDRESS_OBJECT = {
payments: null,
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

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

Binary file modified preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 90a04c9

Please sign in to comment.