Skip to content

Commit

Permalink
feat: add connectors
Browse files Browse the repository at this point in the history
  • Loading branch information
fracek authored and tarrencev committed Mar 13, 2022
1 parent dbaf7b2 commit c76bce6
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 39 deletions.
6 changes: 3 additions & 3 deletions examples/starknet-react-next/src/components/ConnectWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useStarknet } from '@starknet-react/core'
import { useStarknet, InjectedConnector } from '@starknet-react/core'

export function ConnectWallet() {
const { account, connectBrowserWallet } = useStarknet()
const { account, connect } = useStarknet()

if (account) {
return <p>Account: {account}</p>
}

return <button onClick={connectBrowserWallet}>Connect</button>
return <button onClick={() => connect(new InjectedConnector())}>Connect</button>
}
21 changes: 21 additions & 0 deletions packages/core/src/connectors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { AccountInterface } from 'starknet'

export abstract class Connector<Options = any> {
/** Unique connector id */
abstract readonly id: string
/** Connector name */
abstract readonly name: string
/** Whether connector is usable */
abstract readonly ready: boolean
/** Options to use with connector */
readonly options: Options

constructor({ options }: { options: Options }) {
this.options = options
}

abstract connect(): Promise<AccountInterface>
abstract account(): Promise<AccountInterface>
}

export { InjectedConnector } from './injected'
80 changes: 80 additions & 0 deletions packages/core/src/connectors/injected.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { AccountInterface, Provider } from 'starknet'
import { getStarknet } from '@argent/get-starknet'

import { Connector } from './index'
import {
ConnectorNotConnectedError,
ConnectorNotFoundError,
UserRejectedRequestError,
} from '../errors'

type InjectedConnectorOptions = {
showModal?: boolean
}

export class InjectedConnector extends Connector<InjectedConnectorOptions> {
readonly id = 'injected'
readonly name = 'argent'
readonly ready = typeof window != 'undefined' && !!window.starknet

private starknet = getStarknet()

constructor(options?: InjectedConnectorOptions) {
super({ options })
}

async connect() {
if (!this.ready) {
throw new ConnectorNotFoundError()
}

try {
await this.starknet.enable(this.options)
} catch {
// NOTE: Argent v3.0.0 swallows the `.enable` call on reject, so this won't get hit.
throw new UserRejectedRequestError()
}

if (!this.starknet.isConnected) {
// NOTE: Argent v3.0.0 swallows the `.enable` call on reject, so this won't get hit.
throw new UserRejectedRequestError()
}

return this.starknet.account
}

account() {
if (!this.ready) {
throw new ConnectorNotFoundError()
}

return this.starknet.account
? Promise.resolve(this.starknet.account)
: Promise.reject(new ConnectorNotConnectedError())
}
}

export type EventHandler = (accounts: string[]) => void

interface IStarknetWindowObject {
enable: (options?: { showModal?: boolean }) => Promise<string[]>
isPreauthorized: () => Promise<boolean>
on: (event: 'accountsChanged', handleEvent: EventHandler) => void
off: (event: 'accountsChanged', handleEvent: EventHandler) => void
account?: AccountInterface
provider: Provider
selectedAddress?: string
version: string
}

interface ConnectedStarknetWindowObject extends IStarknetWindowObject {
isConnected: true
account: AccountInterface
selectedAddress: string
}

interface DisconnectedStarknetWindowObject extends IStarknetWindowObject {
isConnected: false
}

export type StarknetWindowObject = ConnectedStarknetWindowObject | DisconnectedStarknetWindowObject
19 changes: 19 additions & 0 deletions packages/core/src/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export class ConnectorAlreadyConnectedError extends Error {
name = 'ConnectorAlreadyConnectedError'
message = 'Connector already connected'
}

export class ConnectorNotConnectedError extends Error {
name = 'ConnectorNotConnectedError'
message = 'Connector not connected'
}

export class ConnectorNotFoundError extends Error {
name = 'ConnectorNotFoundError'
message = 'Connector not found'
}

export class UserRejectedRequestError extends Error {
name = 'UserRejectedRequestError'
message = 'User rejected request'
}
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export { useStarknetTransactionManager } from './providers/transaction'
export type { Transaction } from './providers/transaction'
export { StarknetProvider } from './providers'
export * from './hooks'
export * from './connectors'
42 changes: 15 additions & 27 deletions packages/core/src/providers/starknet/manager.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { getStarknet } from '@argent/get-starknet'
import { useCallback, useEffect, useReducer, useState } from 'react'
import { useCallback, useReducer } from 'react'
import { defaultProvider, ProviderInterface } from 'starknet'

import { StarknetState } from './model'
import { Connector } from '../../connectors'

interface StarknetManagerState {
account?: string
Expand Down Expand Up @@ -45,38 +45,26 @@ function reducer(state: StarknetManagerState, action: Action): StarknetManagerSt
}

export function useStarknetManager(): StarknetState {
const [hasStarknet, setHasStarknet] = useState(false)
const [state, dispatch] = useReducer(reducer, {
library: defaultProvider,
})

const { account, library, error } = state

useEffect(() => {
if (typeof window !== undefined) {
// calling getStarknet here makes the detection more reliable
const starknet = getStarknet()
if (starknet.version !== 'uninstalled') {
setHasStarknet(true)
}
const connect = useCallback(async (connector: Connector) => {
if (connector.ready) {
connector.connect().then(
(account) => {
dispatch({ type: 'set_account', account: account.address })
dispatch({ type: 'set_provider', provider: account })
},
(err) => {
console.error(err)
dispatch({ type: 'set_error', error: 'could not activate StarkNet' })
}
)
}
}, [])

const connectBrowserWallet = useCallback(async () => {
try {
if (typeof window === undefined) return
if (window.starknet === undefined) return
const [account] = await window.starknet.enable()
dispatch({ type: 'set_account', account })
const starknet = getStarknet()
if (starknet.account) {
dispatch({ type: 'set_provider', provider: starknet.account })
}
} catch (err) {
console.error(err)
dispatch({ type: 'set_error', error: 'could not activate StarkNet' })
}
}, [])

return { account, hasStarknet, connectBrowserWallet, library, error }
return { account, connect, library, error }
}
7 changes: 3 additions & 4 deletions packages/core/src/providers/starknet/model.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { defaultProvider, ProviderInterface } from 'starknet'
import { Connector } from '../../connectors'

export interface StarknetState {
account?: string
hasStarknet: boolean
connectBrowserWallet: () => void
connect: (connector: Connector) => void
library: ProviderInterface
error?: string
}

export const STARKNET_INITIAL_STATE: StarknetState = {
account: undefined,
hasStarknet: false,
connectBrowserWallet: () => undefined,
connect: () => undefined,
library: defaultProvider,
}
5 changes: 0 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,6 @@
"@jridgewell/trace-mapping" "^0.2.2"
sourcemap-codec "1.4.8"

"@argent/get-starknet@^2.1.1":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@argent/get-starknet/-/get-starknet-2.1.1.tgz#cc44b02ad11d427d0c6300c3c8e6d8eb9f2366cc"
integrity sha512-CqW/bXrvcTnLlhCpxc51uhRjVb7UUbUgkckhvIWBG3Ma9wKFWaJyJyZizRjh+I47NL5VL3PpJwzJC1tEKeaZBQ==

"@argent/get-starknet@^3.0":
version "3.0.0"
resolved "https://registry.yarnpkg.com/@argent/get-starknet/-/get-starknet-3.0.0.tgz#a1c581b8b3777e7dfb4d8da1a1cbab84dfbf28b1"
Expand Down

0 comments on commit c76bce6

Please sign in to comment.