Skip to content

Commit

Permalink
feat: attempt to use WBIP standard as connector to bitcoin
Browse files Browse the repository at this point in the history
  • Loading branch information
zoruka committed Nov 12, 2024
1 parent 5ab7dd4 commit c9b8ba5
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 6 deletions.
3 changes: 2 additions & 1 deletion apps/laboratory/src/pages/library/bitcoin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ const modal = createAppKit({
features: {
analytics: true
},
metadata: ConstantsUtil.Metadata
metadata: ConstantsUtil.Metadata,
debug: true
})

ThemeStore.setModal(modal)
Expand Down
20 changes: 15 additions & 5 deletions packages/adapters/bitcoin/src/adapter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { AppKit, AppKitOptions } from '@reown/appkit'
import { AdapterBlueprint } from '@reown/appkit/adapters'
import type { BitcoinConnector } from './utils/BitcoinConnector.js'
import { WalletStandardConnector } from './connectors/WalletStandardConnector.js'
import { WBIPConnector } from './connectors/WBIPConnector.js'

export class BitcoinAdapter extends AdapterBlueprint<BitcoinConnector> {
constructor(params: BitcoinAdapter.ConstructorParams) {
Expand Down Expand Up @@ -29,6 +29,8 @@ export class BitcoinAdapter extends AdapterBlueprint<BitcoinConnector> {

const address = await connector.connect()

this.connector = connector

return {
id: connector.id,
type: connector.type,
Expand Down Expand Up @@ -63,10 +65,18 @@ export class BitcoinAdapter extends AdapterBlueprint<BitcoinConnector> {
}

override syncConnectors(_options?: AppKitOptions, _appKit?: AppKit): void {
WalletStandardConnector.watchWallets({
callback: this.addConnector.bind(this),
requestedChains: this.networks
})
/*
* WalletStandardConnector.watchWallets({
* callback: this.addConnector.bind(this),
* requestedChains: this.networks
* })
*/

this.addConnector(
...WBIPConnector.getWallets({
requestedChains: this.networks
})
)
}

override syncConnection(
Expand Down
122 changes: 122 additions & 0 deletions packages/adapters/bitcoin/src/connectors/WBIPConnector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import type { CaipNetwork } from '@reown/appkit-common'
import type { BitcoinConnector } from '../utils/BitcoinConnector.js'

export class WBIPConnector implements BitcoinConnector {
public readonly chain = 'bip122'
public readonly type = 'ANNOUNCED'

readonly wallet: WBIPConnector.Provider
private requestedChains: CaipNetwork[] = []

constructor({ provider, requestedChains }: WBIPConnector.ConstructorParams) {
this.wallet = provider
this.requestedChains = requestedChains
}

public get id(): string {
return this.wallet.id
}

public get name(): string {
return this.wallet.name
}

public get imageUrl(): string {
return this.wallet.icon
}

public get chains() {
return this.requestedChains
}

async connect() {
const addresses = await this.getAccountAddresses()
const address = addresses[0]?.address
if (!address) {
throw new Error('No address available')
}

return address
}

async getAccountAddresses(): Promise<BitcoinConnector.AccountAddress[]> {
return (await this.request('getAddresses', {})).addresses
}

private async request<Method extends WBIPConnector.Methods>(
method: Method,
params: WBIPConnector.Requests[Method]['params']
): Promise<WBIPConnector.Requests[Method]['response']> {
if (!this.wallet.methods?.includes(method)) {
throw new Error(`Method ${method} is not available for wallet ${this.wallet.id}`)
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const walletRequest = (window as any)[this.wallet.id]?.request
if (typeof walletRequest !== 'function') {
throw new Error(`Wallet ${this.wallet.id} is not available`)
}

const response = await walletRequest(method, params)

return response.result
}

public static getWallets({ requestedChains }: WBIPConnector.GetWalletsParams) {
const providers: WBIPConnector.Provider[] =
(window as Window & { btc_providers?: WBIPConnector.Provider[] }).btc_providers || []

return providers.map(provider => new WBIPConnector({ provider, requestedChains }))
}
}

export namespace WBIPConnector {
export interface ConstructorParams {
provider: WBIPConnector.Provider
requestedChains: CaipNetwork[]
}

export interface Provider {
id: string
name: string
icon: string

webUrl?: string

chromeWebStoreUrl?: string
mozillaAddOnsUrl?: string
googlePlayStoreUrl?: string
iOSAppStoreUrl?: string

methods?: string[]
}

export interface GetWalletsParams {
requestedChains: CaipNetwork[]
}

export type Request<Params, Response> = {
params: Params
response: Response
}

export type Requests = {
getAddresses: Request<
{
types?: string[]
intentions?: string[]
count?: number
},
{
addresses: {
address: string
path?: string
publicKey?: string
intention?: 'payment' | 'ordinal'
}[]
}
>
}

export type Methods = keyof Requests
}

0 comments on commit c9b8ba5

Please sign in to comment.