From 0421577273a583a4b7a828e75ffff1645caf200b Mon Sep 17 00:00:00 2001 From: Nishant Ghodke Date: Fri, 29 Sep 2023 14:59:14 +0530 Subject: [PATCH 1/3] feat: add Coin98 type interface also, move `Window` to `global` scope --- .../sdk/src/browser-wallets/coin98/types.ts | 25 +++++++++++++++++++ packages/sdk/src/types.d.ts | 15 ++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 packages/sdk/src/browser-wallets/coin98/types.ts diff --git a/packages/sdk/src/browser-wallets/coin98/types.ts b/packages/sdk/src/browser-wallets/coin98/types.ts new file mode 100644 index 00000000..d3a23d0d --- /dev/null +++ b/packages/sdk/src/browser-wallets/coin98/types.ts @@ -0,0 +1,25 @@ +import { RequireAtLeastOne } from "../../utils/types" +import { UnisatNetwork } from "../unisat" + +interface Coin98SignPSBTOptions { + autoFinalized?: boolean + toSignInputs?: Array< + RequireAtLeastOne<{ + address?: string + publicKey?: string + }> & { + index: number + sigHashTypes?: number[] + } + > +} + +export interface Coin98 { + requestAccounts: () => Promise + getAccounts: () => Promise + getNetwork: () => Promise + getPublicKey: () => Promise + signMessage: (message: string) => Promise + signPsbt: (hex: string, { autoFinalized = true, toSignInputs }: Coin98SignPSBTOptions) => Promise + switchNetwork: (network: UnisatNetwork) => Promise +} diff --git a/packages/sdk/src/types.d.ts b/packages/sdk/src/types.d.ts index 000f412a..a3255915 100644 --- a/packages/sdk/src/types.d.ts +++ b/packages/sdk/src/types.d.ts @@ -1,7 +1,14 @@ -declare interface Window { - unisat: Unisat - satsConnect: any - ethereum: MetaMask +import { BitcoinProvider } from "sats-connect" + +import { Coin98 } from "./browser-wallets/coin98/types" + +declare global { + interface Window { + unisat: Unisat + coin98: { bitcoin: Coin98 } + BitcoinProvider: BitcoinProvider + ethereum: MetaMask + } } type Unisat = { From 6410c87d6ac178b80043f7cd3565c0f238259e8c Mon Sep 17 00:00:00 2001 From: Nishant Ghodke Date: Fri, 29 Sep 2023 15:02:19 +0530 Subject: [PATCH 2/3] feat: integrate Coin98 --- .../src/browser-wallets/coin98/addresses.ts | 41 ++++++++++++++++ .../sdk/src/browser-wallets/coin98/index.ts | 3 ++ .../src/browser-wallets/coin98/signatures.ts | 48 +++++++++++++++++++ .../sdk/src/browser-wallets/coin98/utils.ts | 9 ++++ 4 files changed, 101 insertions(+) create mode 100644 packages/sdk/src/browser-wallets/coin98/addresses.ts create mode 100644 packages/sdk/src/browser-wallets/coin98/index.ts create mode 100644 packages/sdk/src/browser-wallets/coin98/signatures.ts create mode 100644 packages/sdk/src/browser-wallets/coin98/utils.ts diff --git a/packages/sdk/src/browser-wallets/coin98/addresses.ts b/packages/sdk/src/browser-wallets/coin98/addresses.ts new file mode 100644 index 00000000..cb0b2e0d --- /dev/null +++ b/packages/sdk/src/browser-wallets/coin98/addresses.ts @@ -0,0 +1,41 @@ +import { getAddressFormat } from "../.." +import { Network } from "../../config/types" +import { isCoin98Installed, UnisatNetwork } from "./utils" + +export async function getAddresses(network: Network) { + if (!isCoin98Installed()) { + throw new Error("Coin98 not installed") + } + + if (!network) { + throw new Error("Invalid options provided") + } + + let targetNetwork: UnisatNetwork = "livenet" + const connectedNetwork = await window.coin98.getNetwork() + + if (network === "testnet") { + targetNetwork = network + } + + if (connectedNetwork !== targetNetwork) { + await window.coin98.switchNetwork(targetNetwork) + } + + const accounts = await window.coin98.requestAccounts() + const publicKey = await window.coin98.getPublicKey() + + if (!accounts[0]) { + return [] + } + + const formatObj = getAddressFormat(accounts[0], network) + + return [ + { + pub: publicKey, + address: formatObj.address, + format: formatObj.format + } + ] +} diff --git a/packages/sdk/src/browser-wallets/coin98/index.ts b/packages/sdk/src/browser-wallets/coin98/index.ts new file mode 100644 index 00000000..ebbce1e6 --- /dev/null +++ b/packages/sdk/src/browser-wallets/coin98/index.ts @@ -0,0 +1,3 @@ +export * from "./addresses" +export * from "./signatures" +export * from "./utils" diff --git a/packages/sdk/src/browser-wallets/coin98/signatures.ts b/packages/sdk/src/browser-wallets/coin98/signatures.ts new file mode 100644 index 00000000..1efb9df3 --- /dev/null +++ b/packages/sdk/src/browser-wallets/coin98/signatures.ts @@ -0,0 +1,48 @@ +import { Psbt } from "bitcoinjs-lib" + +import { BrowserWalletSignPSBTResponse } from "../types" +import { UnisatSignPSBTOptions } from "../unisat/types" +import { isCoin98Installed } from "./utils" + +export async function signPsbt( + psbt: Psbt, + { finalize = true, extractTx = true }: UnisatSignPSBTOptions = {} +): Promise { + if (!isCoin98Installed()) { + throw new Error("Coin98 not installed") + } + + const psbtHex = psbt.toHex() + const signedPsbtHex = await window.coin98.signPsbt(psbtHex, { autoFinalized: finalize }) + if (!signedPsbtHex) { + throw new Error("Failed to sign psbt hex using Coin98") + } + + if (psbtHex === signedPsbtHex) { + throw new Error("Psbt has already been signed.") + } + + const signedPsbt = Psbt.fromHex(signedPsbtHex) + + return { + hex: extractTx ? signedPsbt.extractTransaction().toHex() : signedPsbt.toHex(), + base64: !extractTx ? signedPsbt.toBase64() : null + } +} + +export async function signMessage(message: string) { + if (!isCoin98Installed()) { + throw new Error("Coin98 not installed.") + } + + const signature = await window.coin98.signMessage(message) + + if (!signature) { + throw new Error("Failed to sign message using Coin98") + } + + return { + base64: signature, + hex: Buffer.from(signature, "base64").toString("hex") + } +} diff --git a/packages/sdk/src/browser-wallets/coin98/utils.ts b/packages/sdk/src/browser-wallets/coin98/utils.ts new file mode 100644 index 00000000..6b5bd018 --- /dev/null +++ b/packages/sdk/src/browser-wallets/coin98/utils.ts @@ -0,0 +1,9 @@ +export function isCoin98Installed() { + if (typeof window.coin98?.bitcoin !== "undefined") { + return false + } + + return false +} + +export type UnisatNetwork = "livenet" | "testnet" From 0cffdfd55a11e85794512bbc5172bcfd21862708 Mon Sep 17 00:00:00 2001 From: Nishant Ghodke Date: Tue, 10 Oct 2023 10:44:34 +0530 Subject: [PATCH 3/3] fix: use correct window path to access Coin98 APIs --- packages/sdk/src/browser-wallets/coin98/addresses.ts | 8 ++++---- packages/sdk/src/browser-wallets/coin98/signatures.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/sdk/src/browser-wallets/coin98/addresses.ts b/packages/sdk/src/browser-wallets/coin98/addresses.ts index cb0b2e0d..97076423 100644 --- a/packages/sdk/src/browser-wallets/coin98/addresses.ts +++ b/packages/sdk/src/browser-wallets/coin98/addresses.ts @@ -12,18 +12,18 @@ export async function getAddresses(network: Network) { } let targetNetwork: UnisatNetwork = "livenet" - const connectedNetwork = await window.coin98.getNetwork() + const connectedNetwork = await window.coin98.bitcoin.getNetwork() if (network === "testnet") { targetNetwork = network } if (connectedNetwork !== targetNetwork) { - await window.coin98.switchNetwork(targetNetwork) + await window.coin98.bitcoin.switchNetwork(targetNetwork) } - const accounts = await window.coin98.requestAccounts() - const publicKey = await window.coin98.getPublicKey() + const accounts = await window.coin98.bitcoin.requestAccounts() + const publicKey = await window.coin98.bitcoin.getPublicKey() if (!accounts[0]) { return [] diff --git a/packages/sdk/src/browser-wallets/coin98/signatures.ts b/packages/sdk/src/browser-wallets/coin98/signatures.ts index 1efb9df3..39d2dac8 100644 --- a/packages/sdk/src/browser-wallets/coin98/signatures.ts +++ b/packages/sdk/src/browser-wallets/coin98/signatures.ts @@ -13,7 +13,7 @@ export async function signPsbt( } const psbtHex = psbt.toHex() - const signedPsbtHex = await window.coin98.signPsbt(psbtHex, { autoFinalized: finalize }) + const signedPsbtHex = await window.coin98.bitcoin.signPsbt(psbtHex, { autoFinalized: finalize }) if (!signedPsbtHex) { throw new Error("Failed to sign psbt hex using Coin98") } @@ -35,7 +35,7 @@ export async function signMessage(message: string) { throw new Error("Coin98 not installed.") } - const signature = await window.coin98.signMessage(message) + const signature = await window.coin98.bitcoin.signMessage(message) if (!signature) { throw new Error("Failed to sign message using Coin98")