UNPKG

@bsv/sdk

Version:

BSV Blockchain Software Development Kit

476 lines (444 loc) 14 kB
import { AcquireCertificateArgs, AcquireCertificateResult, Base64String, BasketStringUnder300Bytes, BooleanDefaultFalse, Byte, CertificateFieldNameUnder50Bytes, CreateActionArgs, CreateActionResult, DescriptionString5to50Bytes, DiscoverCertificatesResult, HexString, InternalizeActionArgs, ISOTimestampString, KeyIDStringUnder800Bytes, ListActionsArgs, ListActionsResult, ListCertificatesResult, ListOutputsArgs, ListOutputsResult, OriginatorDomainNameStringUnder250Bytes, OutpointString, PositiveInteger, PositiveIntegerDefault10Max10000, PositiveIntegerOrZero, ProtocolString5To400Bytes, ProveCertificateArgs, ProveCertificateResult, PubKeyHex, SecurityLevel, SignActionArgs, SignActionResult, VersionString7To30Bytes, WalletInterface, AuthenticatedResult } from './Wallet.interfaces.js' import WindowCWISubstrate from './substrates/window.CWI.js' import XDMSubstrate from './substrates/XDM.js' import WalletWireTransceiver from './substrates/WalletWireTransceiver.js' import HTTPWalletWire from './substrates/HTTPWalletWire.js' import HTTPWalletJSON from './substrates/HTTPWalletJSON.js' import ReactNativeWebView from './substrates/ReactNativeWebView.js' const MAX_XDM_RESPONSE_WAIT = 200 /** * The SDK is how applications communicate with wallets over a communications substrate. */ export default class WalletClient implements WalletInterface { public substrate: 'auto' | WalletInterface originator?: OriginatorDomainNameStringUnder250Bytes constructor ( substrate: | 'auto' | 'Cicada' | 'XDM' | 'window.CWI' | 'json-api' | 'react-native' | WalletInterface = 'auto', originator?: OriginatorDomainNameStringUnder250Bytes ) { if (substrate === 'Cicada') { substrate = new WalletWireTransceiver(new HTTPWalletWire(originator)) } if (substrate === 'window.CWI') substrate = new WindowCWISubstrate() if (substrate === 'XDM') substrate = new XDMSubstrate() if (substrate === 'json-api') substrate = new HTTPWalletJSON(originator) if (substrate === 'react-native') substrate = new ReactNativeWebView(originator) this.substrate = substrate this.originator = originator } async connectToSubstrate (): Promise<void> { if (typeof this.substrate === 'object') { return // substrate is already connected } let sub: WalletInterface const checkSub = async (timeout?: number): Promise<void> => { let result if (typeof timeout === 'number') { result = await Promise.race([ sub.getVersion({}), new Promise<never>((_resolve, reject) => setTimeout(() => reject(new Error('Timed out.')), timeout) ) ]) } else { result = await sub.getVersion({}) } if (typeof result !== 'object' || typeof result.version !== 'string') { throw new Error('Failed to use substrate.') } } try { sub = new WindowCWISubstrate() await checkSub() this.substrate = sub } catch (e) { // XDM failed, try the next one... try { sub = new XDMSubstrate() await checkSub(MAX_XDM_RESPONSE_WAIT) this.substrate = sub } catch (e) { // HTTP wire failed, move on... try { sub = new WalletWireTransceiver(new HTTPWalletWire(this.originator)) await checkSub() this.substrate = sub } catch (e) { // HTTP Wire failed, attempt the next... try { sub = new HTTPWalletJSON(this.originator) await checkSub() this.substrate = sub } catch (e) { // HTTP JSON failed, attempt the next... try { sub = new ReactNativeWebView(this.originator) await checkSub() this.substrate = sub } catch (e) { // No comms. Tell the user to install a BSV wallet. throw new Error( 'No wallet available over any communication substrate. Install a BSV wallet today!' ) } } } } } } async createAction (args: CreateActionArgs): Promise<CreateActionResult> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).createAction( args, this.originator ) } async signAction (args: SignActionArgs): Promise<SignActionResult> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).signAction( args, this.originator ) } async abortAction (args: { reference: Base64String }): Promise<{ aborted: true }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).abortAction( args, this.originator ) } async listActions (args: ListActionsArgs): Promise<ListActionsResult> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).listActions( args, this.originator ) } async internalizeAction ( args: InternalizeActionArgs ): Promise<{ accepted: true }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).internalizeAction( args, this.originator ) } async listOutputs (args: ListOutputsArgs): Promise<ListOutputsResult> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).listOutputs( args, this.originator ) } async relinquishOutput (args: { basket: BasketStringUnder300Bytes output: OutpointString }): Promise<{ relinquished: true }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).relinquishOutput( args, this.originator ) } async getPublicKey (args: { identityKey?: true protocolID?: [SecurityLevel, ProtocolString5To400Bytes] keyID?: KeyIDStringUnder800Bytes privileged?: BooleanDefaultFalse privilegedReason?: DescriptionString5to50Bytes counterparty?: PubKeyHex | 'self' | 'anyone' forSelf?: BooleanDefaultFalse }): Promise<{ publicKey: PubKeyHex }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).getPublicKey( args, this.originator ) } async revealCounterpartyKeyLinkage (args: { counterparty: PubKeyHex verifier: PubKeyHex privilegedReason?: DescriptionString5to50Bytes privileged?: BooleanDefaultFalse }): Promise<{ prover: PubKeyHex verifier: PubKeyHex counterparty: PubKeyHex revelationTime: ISOTimestampString encryptedLinkage: Byte[] encryptedLinkageProof: Byte[] }> { await this.connectToSubstrate() return await ( this.substrate as WalletInterface ).revealCounterpartyKeyLinkage(args, this.originator) } async revealSpecificKeyLinkage (args: { counterparty: PubKeyHex verifier: PubKeyHex protocolID: [SecurityLevel, ProtocolString5To400Bytes] keyID: KeyIDStringUnder800Bytes privilegedReason?: DescriptionString5to50Bytes privileged?: BooleanDefaultFalse }): Promise<{ prover: PubKeyHex verifier: PubKeyHex counterparty: PubKeyHex protocolID: [SecurityLevel, ProtocolString5To400Bytes] keyID: KeyIDStringUnder800Bytes encryptedLinkage: Byte[] encryptedLinkageProof: Byte[] proofType: Byte }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).revealSpecificKeyLinkage( args, this.originator ) } async encrypt (args: { plaintext: Byte[] protocolID: [SecurityLevel, ProtocolString5To400Bytes] keyID: KeyIDStringUnder800Bytes privilegedReason?: DescriptionString5to50Bytes counterparty?: PubKeyHex | 'self' | 'anyone' privileged?: BooleanDefaultFalse }): Promise<{ ciphertext: Byte[] }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).encrypt( args, this.originator ) } async decrypt (args: { ciphertext: Byte[] protocolID: [SecurityLevel, ProtocolString5To400Bytes] keyID: KeyIDStringUnder800Bytes privilegedReason?: DescriptionString5to50Bytes counterparty?: PubKeyHex | 'self' | 'anyone' privileged?: BooleanDefaultFalse }): Promise<{ plaintext: Byte[] }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).decrypt( args, this.originator ) } async createHmac (args: { data: Byte[] protocolID: [SecurityLevel, ProtocolString5To400Bytes] keyID: KeyIDStringUnder800Bytes privilegedReason?: DescriptionString5to50Bytes counterparty?: PubKeyHex | 'self' | 'anyone' privileged?: BooleanDefaultFalse }): Promise<{ hmac: Byte[] }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).createHmac( args, this.originator ) } async verifyHmac (args: { data: Byte[] hmac: Byte[] protocolID: [SecurityLevel, ProtocolString5To400Bytes] keyID: KeyIDStringUnder800Bytes privilegedReason?: DescriptionString5to50Bytes counterparty?: PubKeyHex | 'self' | 'anyone' privileged?: BooleanDefaultFalse }): Promise<{ valid: true }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).verifyHmac( args, this.originator ) } async createSignature (args: { data?: Byte[] hashToDirectlySign?: Byte[] protocolID: [SecurityLevel, ProtocolString5To400Bytes] keyID: KeyIDStringUnder800Bytes privilegedReason?: DescriptionString5to50Bytes counterparty?: PubKeyHex | 'self' | 'anyone' privileged?: BooleanDefaultFalse }): Promise<{ signature: Byte[] }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).createSignature( args, this.originator ) } async verifySignature (args: { data?: Byte[] hashToDirectlyVerify?: Byte[] signature: Byte[] protocolID: [SecurityLevel, ProtocolString5To400Bytes] keyID: KeyIDStringUnder800Bytes privilegedReason?: DescriptionString5to50Bytes counterparty?: PubKeyHex | 'self' | 'anyone' forSelf?: BooleanDefaultFalse privileged?: BooleanDefaultFalse }): Promise<{ valid: true }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).verifySignature( args, this.originator ) } async acquireCertificate ( args: AcquireCertificateArgs ): Promise<AcquireCertificateResult> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).acquireCertificate( args, this.originator ) } async listCertificates (args: { certifiers: PubKeyHex[] types: Base64String[] limit?: PositiveIntegerDefault10Max10000 offset?: PositiveIntegerOrZero privileged?: BooleanDefaultFalse privilegedReason?: DescriptionString5to50Bytes }): Promise<ListCertificatesResult> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).listCertificates( args, this.originator ) } async proveCertificate ( args: ProveCertificateArgs ): Promise<ProveCertificateResult> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).proveCertificate( args, this.originator ) } async relinquishCertificate (args: { type: Base64String serialNumber: Base64String certifier: PubKeyHex }): Promise<{ relinquished: true }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).relinquishCertificate( args, this.originator ) } async discoverByIdentityKey (args: { identityKey: PubKeyHex limit?: PositiveIntegerDefault10Max10000 offset?: PositiveIntegerOrZero }): Promise<DiscoverCertificatesResult> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).discoverByIdentityKey( args, this.originator ) } async discoverByAttributes (args: { attributes: Record<CertificateFieldNameUnder50Bytes, string> limit?: PositiveIntegerDefault10Max10000 offset?: PositiveIntegerOrZero }): Promise<DiscoverCertificatesResult> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).discoverByAttributes( args, this.originator ) } async isAuthenticated (args: object = {}): Promise<AuthenticatedResult> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).isAuthenticated( args, this.originator ) } async waitForAuthentication (args: object = {}): Promise<{ authenticated: true }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).waitForAuthentication( args, this.originator ) } async getHeight (args: object = {}): Promise<{ height: PositiveInteger }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).getHeight( args, this.originator ) } async getHeaderForHeight (args: { height: PositiveInteger }): Promise<{ header: HexString }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).getHeaderForHeight( args, this.originator ) } async getNetwork (args: object = {}): Promise<{ network: 'mainnet' | 'testnet' }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).getNetwork( args, this.originator ) } async getVersion ( args: object = {} ): Promise<{ version: VersionString7To30Bytes }> { await this.connectToSubstrate() return await (this.substrate as WalletInterface).getVersion( args, this.originator ) } }