@meshconnect/uwc-bitcoin 0.2.4-snapshot.ec6b95b → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/okx.d.ts +60 -0
- package/dist/adapters/okx.d.ts.map +1 -0
- package/dist/adapters/okx.js +93 -0
- package/dist/adapters/okx.js.map +1 -0
- package/dist/adapters/wallet-standard.d.ts +10 -1
- package/dist/adapters/wallet-standard.d.ts.map +1 -1
- package/dist/adapters/wallet-standard.js +19 -2
- package/dist/adapters/wallet-standard.js.map +1 -1
- package/dist/bitcoin-namespace.d.ts +7 -2
- package/dist/bitcoin-namespace.d.ts.map +1 -1
- package/dist/bitcoin-namespace.js +14 -2
- package/dist/bitcoin-namespace.js.map +1 -1
- package/dist/encoding.d.ts +1 -0
- package/dist/encoding.d.ts.map +1 -1
- package/dist/encoding.js +17 -0
- package/dist/encoding.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/adapters/okx.test.ts +176 -0
- package/src/adapters/okx.ts +155 -0
- package/src/adapters/wallet-standard.ts +24 -2
- package/src/bitcoin-namespace.test.ts +59 -0
- package/src/bitcoin-namespace.ts +14 -2
- package/src/encoding.ts +18 -0
- package/src/index.ts +3 -2
- package/dist/adapters/walletconnect.d.ts +0 -36
- package/dist/adapters/walletconnect.d.ts.map +0 -1
- package/dist/adapters/walletconnect.js +0 -90
- package/dist/adapters/walletconnect.js.map +0 -1
- package/src/adapters/walletconnect.test.ts +0 -97
- package/src/adapters/walletconnect.ts +0 -126
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { BitcoinAccount, BitcoinPsbtSignRequest, BitcoinSignMessageParams, SignatureType } from '@meshconnect/uwc-types';
|
|
2
|
+
import type { BitcoinTransportAdapter } from '../adapter';
|
|
3
|
+
/**
|
|
4
|
+
* The subset of OKX's injected Bitcoin provider this adapter drives
|
|
5
|
+
* (`window.okxwallet.bitcoin`). OKX does NOT expose Bitcoin through Wallet
|
|
6
|
+
* Standard — only this legacy injected provider — so it needs a dedicated
|
|
7
|
+
* adapter, not `WalletStandardBitcoinAdapter`.
|
|
8
|
+
*
|
|
9
|
+
* Wire conventions the provider follows:
|
|
10
|
+
* - `requestAccounts()` prompts + returns the authorized addresses; the caller
|
|
11
|
+
* pairs `getPublicKey()` for the active account's compressed key (hex).
|
|
12
|
+
* - `signMessage(msg, type)` returns a base64 signature.
|
|
13
|
+
* - `signPsbt(psbtHex, options)` takes AND returns PSBT as HEX — so this adapter
|
|
14
|
+
* converts base64 ↔ hex at the boundary (our domain is base64/BIP-174).
|
|
15
|
+
*/
|
|
16
|
+
export interface OkxBitcoinProvider {
|
|
17
|
+
/** Prompt for connection; returns the authorized addresses. */
|
|
18
|
+
requestAccounts(): Promise<string[]>;
|
|
19
|
+
/** Non-prompting: the already-authorized addresses ([] if not connected). */
|
|
20
|
+
getAccounts(): Promise<string[]>;
|
|
21
|
+
/** The active account's compressed public key, hex-encoded. */
|
|
22
|
+
getPublicKey(): Promise<string>;
|
|
23
|
+
/** Sign a message; returns a base64 signature. */
|
|
24
|
+
signMessage(message: string, type?: 'ecdsa' | 'bip322-simple'): Promise<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Sign a PSBT (hex in, signed PSBT hex out). `toSignInputs` scopes which
|
|
27
|
+
* inputs to sign (index + expected address, optional sighash), mirroring the
|
|
28
|
+
* Wallet Standard adapter's `inputsToSign`; omitted → the wallet signs all it
|
|
29
|
+
* can.
|
|
30
|
+
*/
|
|
31
|
+
signPsbt(psbtHex: string, options?: {
|
|
32
|
+
autoFinalized?: boolean;
|
|
33
|
+
toSignInputs?: {
|
|
34
|
+
index: number;
|
|
35
|
+
address: string;
|
|
36
|
+
sighashTypes?: number[];
|
|
37
|
+
}[];
|
|
38
|
+
}): Promise<string>;
|
|
39
|
+
on(event: string, handler: (accounts: string[]) => void): void;
|
|
40
|
+
removeListener(event: string, handler: (accounts: string[]) => void): void;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* OKX (legacy injected) Bitcoin transport adapter — the non-Wallet-Standard
|
|
44
|
+
* injected path. The injected transport resolves `window.okxwallet.bitcoin` by
|
|
45
|
+
* its `injectedId` and hands it here; this adapter maps our domain shapes onto
|
|
46
|
+
* the provider's methods.
|
|
47
|
+
*
|
|
48
|
+
* `sendTransfer` is intentionally not implemented — that is the WalletConnect
|
|
49
|
+
* high-level path. (OKX has `sendBitcoin`, but broadcast is out of scope here:
|
|
50
|
+
* this stays sign-only, matching `WalletStandardBitcoinAdapter`.)
|
|
51
|
+
*/
|
|
52
|
+
export declare class OkxBitcoinAdapter implements BitcoinTransportAdapter {
|
|
53
|
+
private readonly provider;
|
|
54
|
+
constructor(provider: OkxBitcoinProvider);
|
|
55
|
+
getAccounts(): Promise<BitcoinAccount[]>;
|
|
56
|
+
signMessage(params: BitcoinSignMessageParams): Promise<SignatureType>;
|
|
57
|
+
signPsbt(request: BitcoinPsbtSignRequest): Promise<string>;
|
|
58
|
+
disconnect(): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=okx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"okx.d.ts","sourceRoot":"","sources":["../../src/adapters/okx.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EAEtB,wBAAwB,EACxB,aAAa,EACd,MAAM,wBAAwB,CAAA;AAE/B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAQzD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,kBAAkB;IACjC,+DAA+D;IAC/D,eAAe,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACpC,6EAA6E;IAC7E,WAAW,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAChC,+DAA+D;IAC/D,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;IAC/B,kDAAkD;IAClD,WAAW,CACT,OAAO,EAAE,MAAM,EACf,IAAI,CAAC,EAAE,OAAO,GAAG,eAAe,GAC/B,OAAO,CAAC,MAAM,CAAC,CAAA;IAClB;;;;;OAKG;IACH,QAAQ,CACN,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACR,aAAa,CAAC,EAAE,OAAO,CAAA;QACvB,YAAY,CAAC,EAAE;YACb,KAAK,EAAE,MAAM,CAAA;YACb,OAAO,EAAE,MAAM,CAAA;YACf,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;SACxB,EAAE,CAAA;KACJ,GACA,OAAO,CAAC,MAAM,CAAC,CAAA;IAClB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;IAC9D,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;CAC3E;AAaD;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,YAAW,uBAAuB;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,kBAAkB;IAEnD,WAAW,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAgBxC,WAAW,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC;IAgBrE,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC;IA+BhE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAK5B"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { WalletConnectorError } from '@meshconnect/uwc-types';
|
|
2
|
+
import { base64ToBytes, bytesToBase64, bytesToHex, hexToBytes } from '../encoding';
|
|
3
|
+
/** Bitcoin SIGHASH flag → numeric value (Bitcoin Core encoding) for the
|
|
4
|
+
* provider's `toSignInputs.sighashTypes`. */
|
|
5
|
+
const SIGHASH_VALUES = {
|
|
6
|
+
ALL: 0x01,
|
|
7
|
+
NONE: 0x02,
|
|
8
|
+
SINGLE: 0x03,
|
|
9
|
+
'ALL|ANYONECANPAY': 0x81,
|
|
10
|
+
'NONE|ANYONECANPAY': 0x82,
|
|
11
|
+
'SINGLE|ANYONECANPAY': 0x83
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* OKX (legacy injected) Bitcoin transport adapter — the non-Wallet-Standard
|
|
15
|
+
* injected path. The injected transport resolves `window.okxwallet.bitcoin` by
|
|
16
|
+
* its `injectedId` and hands it here; this adapter maps our domain shapes onto
|
|
17
|
+
* the provider's methods.
|
|
18
|
+
*
|
|
19
|
+
* `sendTransfer` is intentionally not implemented — that is the WalletConnect
|
|
20
|
+
* high-level path. (OKX has `sendBitcoin`, but broadcast is out of scope here:
|
|
21
|
+
* this stays sign-only, matching `WalletStandardBitcoinAdapter`.)
|
|
22
|
+
*/
|
|
23
|
+
export class OkxBitcoinAdapter {
|
|
24
|
+
provider;
|
|
25
|
+
constructor(provider) {
|
|
26
|
+
this.provider = provider;
|
|
27
|
+
}
|
|
28
|
+
async getAccounts() {
|
|
29
|
+
const addresses = await this.provider.requestAccounts();
|
|
30
|
+
// The provider exposes one active public key; pair it with the first
|
|
31
|
+
// (active) address. Tolerate a missing key rather than failing the connect.
|
|
32
|
+
let publicKey = '';
|
|
33
|
+
try {
|
|
34
|
+
publicKey = await this.provider.getPublicKey();
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
publicKey = '';
|
|
38
|
+
}
|
|
39
|
+
return addresses.map((address, index) => ({
|
|
40
|
+
address,
|
|
41
|
+
publicKey: index === 0 ? publicKey : ''
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
async signMessage(params) {
|
|
45
|
+
// OKX signs with its OWN active account (no address param), so the caller's
|
|
46
|
+
// `params.account` is advisory here. Map our protocol name to the
|
|
47
|
+
// provider's ('bip322' → 'bip322-simple').
|
|
48
|
+
const type = params.protocol === 'bip322' ? 'bip322-simple' : 'ecdsa';
|
|
49
|
+
const signature = await this.provider.signMessage(params.message, type);
|
|
50
|
+
if (!signature) {
|
|
51
|
+
throw new WalletConnectorError({
|
|
52
|
+
type: 'unknown',
|
|
53
|
+
message: 'okx bitcoin: signMessage returned no signature'
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
// OKX returns a base64 signature — matches our contract.
|
|
57
|
+
return { type: 'standard', signature };
|
|
58
|
+
}
|
|
59
|
+
async signPsbt(request) {
|
|
60
|
+
// Our domain is base64 (BIP-174); OKX speaks hex. autoFinalized:false keeps
|
|
61
|
+
// this sign-only (the wallet returns the signed-but-unfinalized PSBT).
|
|
62
|
+
const psbtHex = bytesToHex(base64ToBytes(request.psbt));
|
|
63
|
+
// Forward which inputs to sign (index + address, optional sighash) so the
|
|
64
|
+
// wallet signs exactly the requested set — matching the Wallet Standard
|
|
65
|
+
// adapter's `inputsToSign`. `request.from` isn't forwarded: OKX signs with
|
|
66
|
+
// its single active account, so there's no per-`from` routing. Omitted →
|
|
67
|
+
// OKX signs all inputs it can.
|
|
68
|
+
const toSignInputs = request.inputsToSign?.flatMap(input => input.signingIndexes.map(index => ({
|
|
69
|
+
index,
|
|
70
|
+
address: input.address,
|
|
71
|
+
...(input.sigHash
|
|
72
|
+
? { sighashTypes: [SIGHASH_VALUES[input.sigHash]] }
|
|
73
|
+
: {})
|
|
74
|
+
})));
|
|
75
|
+
const signedHex = await this.provider.signPsbt(psbtHex, {
|
|
76
|
+
autoFinalized: false,
|
|
77
|
+
...(toSignInputs ? { toSignInputs } : {})
|
|
78
|
+
});
|
|
79
|
+
if (!signedHex) {
|
|
80
|
+
throw new WalletConnectorError({
|
|
81
|
+
type: 'unknown',
|
|
82
|
+
message: 'okx bitcoin: signPsbt returned no PSBT'
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return bytesToBase64(hexToBytes(signedHex));
|
|
86
|
+
}
|
|
87
|
+
disconnect() {
|
|
88
|
+
// OKX's injected provider has no disconnect RPC; clearing session state is
|
|
89
|
+
// the caller's job.
|
|
90
|
+
return Promise.resolve();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=okx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"okx.js","sourceRoot":"","sources":["../../src/adapters/okx.ts"],"names":[],"mappings":"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"}
|
|
@@ -66,7 +66,16 @@ export interface WalletStandardBitcoinWallet {
|
|
|
66
66
|
export declare class WalletStandardBitcoinAdapter implements BitcoinTransportAdapter {
|
|
67
67
|
private readonly wallet;
|
|
68
68
|
private accounts;
|
|
69
|
-
|
|
69
|
+
/**
|
|
70
|
+
* @param wallet The discovered `bitcoin:*` wallet.
|
|
71
|
+
* @param initialAccounts Optional already-authorized accounts to seed the
|
|
72
|
+
* cache with. Passed on the SILENT restore path so the first
|
|
73
|
+
* `signMessage`/`signPsbt` doesn't re-invoke `bitcoin:connect` (which some
|
|
74
|
+
* wallets surface as UI) via `requireAccount`→`getAccounts`. Omit on a
|
|
75
|
+
* fresh connect, where `getAccounts()` should call `bitcoin:connect` to
|
|
76
|
+
* authorize.
|
|
77
|
+
*/
|
|
78
|
+
constructor(wallet: WalletStandardBitcoinWallet, initialAccounts?: readonly WalletStandardBitcoinAccount[]);
|
|
70
79
|
getAccounts(): Promise<BitcoinAccount[]>;
|
|
71
80
|
signMessage(params: BitcoinSignMessageParams): Promise<SignatureType>;
|
|
72
81
|
signPsbt(request: BitcoinPsbtSignRequest): Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet-standard.d.ts","sourceRoot":"","sources":["../../src/adapters/wallet-standard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,wBAAwB,EACxB,aAAa,EACd,MAAM,wBAAwB,CAAA;AAE/B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAQzD;;;;;;;GAOG;AACH,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,UAAU,CAAA;IACrB,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,CAAA;CACjC;AAED,UAAU,qBAAqB;IAC7B,OAAO,CAAC,KAAK,EAAE;QACb,QAAQ,EAAE,CAAC,SAAS,GAAG,UAAU,CAAC,EAAE,CAAA;KACrC,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,4BAA4B,EAAE,CAAA;KAAE,CAAC,CAAA;CAC1D;AAED,UAAU,yBAAyB;IACjC,WAAW,CAAC,KAAK,EAAE;QACjB,OAAO,EAAE,4BAA4B,CAAA;QACrC,OAAO,EAAE,UAAU,CAAA;QACnB,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;KAC9B,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,UAAU,CAAC;QAAC,aAAa,EAAE,UAAU,CAAA;KAAE,EAAE,CAAC,CAAA;CACpE;AAED,UAAU,6BAA6B;IACrC,eAAe,CAAC,KAAK,EAAE;QACrB,OAAO,EAAE,4BAA4B,CAAA;QACrC,IAAI,EAAE,UAAU,CAAA;QAChB,YAAY,CAAC,EAAE;YACb,OAAO,EAAE,4BAA4B,CAAA;YACrC,cAAc,EAAE,MAAM,EAAE,CAAA;YACxB,OAAO,CAAC,EAAE,MAAM,CAAA;SACjB,EAAE,CAAA;KACJ,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,EAAE,CAAC,CAAA;CACpC;AAED,qFAAqF;AACrF,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,SAAS,4BAA4B,EAAE,CAAA;IACjD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAClC,iBAAiB,CAAC,EAAE,qBAAqB,CAAA;QACzC,qBAAqB,CAAC,EAAE,yBAAyB,CAAA;QACjD,yBAAyB,CAAC,EAAE,6BAA6B,CAAA;KAC1D,CAAA;CACF;AAED;;;;;;;;;GASG;AACH,qBAAa,4BAA6B,YAAW,uBAAuB;
|
|
1
|
+
{"version":3,"file":"wallet-standard.d.ts","sourceRoot":"","sources":["../../src/adapters/wallet-standard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,wBAAwB,EACxB,aAAa,EACd,MAAM,wBAAwB,CAAA;AAE/B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAQzD;;;;;;;GAOG;AACH,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,UAAU,CAAA;IACrB,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,CAAA;CACjC;AAED,UAAU,qBAAqB;IAC7B,OAAO,CAAC,KAAK,EAAE;QACb,QAAQ,EAAE,CAAC,SAAS,GAAG,UAAU,CAAC,EAAE,CAAA;KACrC,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,4BAA4B,EAAE,CAAA;KAAE,CAAC,CAAA;CAC1D;AAED,UAAU,yBAAyB;IACjC,WAAW,CAAC,KAAK,EAAE;QACjB,OAAO,EAAE,4BAA4B,CAAA;QACrC,OAAO,EAAE,UAAU,CAAA;QACnB,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;KAC9B,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,UAAU,CAAC;QAAC,aAAa,EAAE,UAAU,CAAA;KAAE,EAAE,CAAC,CAAA;CACpE;AAED,UAAU,6BAA6B;IACrC,eAAe,CAAC,KAAK,EAAE;QACrB,OAAO,EAAE,4BAA4B,CAAA;QACrC,IAAI,EAAE,UAAU,CAAA;QAChB,YAAY,CAAC,EAAE;YACb,OAAO,EAAE,4BAA4B,CAAA;YACrC,cAAc,EAAE,MAAM,EAAE,CAAA;YACxB,OAAO,CAAC,EAAE,MAAM,CAAA;SACjB,EAAE,CAAA;KACJ,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,EAAE,CAAC,CAAA;CACpC;AAED,qFAAqF;AACrF,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,SAAS,4BAA4B,EAAE,CAAA;IACjD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAClC,iBAAiB,CAAC,EAAE,qBAAqB,CAAA;QACzC,qBAAqB,CAAC,EAAE,yBAAyB,CAAA;QACjD,yBAAyB,CAAC,EAAE,6BAA6B,CAAA;KAC1D,CAAA;CACF;AAED;;;;;;;;;GASG;AACH,qBAAa,4BAA6B,YAAW,uBAAuB;IAaxE,OAAO,CAAC,QAAQ,CAAC,MAAM;IAZzB,OAAO,CAAC,QAAQ,CAAuD;IAEvE;;;;;;;;OAQG;gBAEgB,MAAM,EAAE,2BAA2B,EACpD,eAAe,CAAC,EAAE,SAAS,4BAA4B,EAAE;IAOrD,WAAW,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAexC,WAAW,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC;IAoBrE,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC;IA6BhE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,oFAAoF;YACtE,cAAc;IAoB5B,OAAO,CAAC,WAAW;CAMpB"}
|
|
@@ -13,8 +13,20 @@ import { base64ToBytes, bytesToBase64, bytesToHex, utf8ToBytes } from '../encodi
|
|
|
13
13
|
export class WalletStandardBitcoinAdapter {
|
|
14
14
|
wallet;
|
|
15
15
|
accounts = null;
|
|
16
|
-
|
|
16
|
+
/**
|
|
17
|
+
* @param wallet The discovered `bitcoin:*` wallet.
|
|
18
|
+
* @param initialAccounts Optional already-authorized accounts to seed the
|
|
19
|
+
* cache with. Passed on the SILENT restore path so the first
|
|
20
|
+
* `signMessage`/`signPsbt` doesn't re-invoke `bitcoin:connect` (which some
|
|
21
|
+
* wallets surface as UI) via `requireAccount`→`getAccounts`. Omit on a
|
|
22
|
+
* fresh connect, where `getAccounts()` should call `bitcoin:connect` to
|
|
23
|
+
* authorize.
|
|
24
|
+
*/
|
|
25
|
+
constructor(wallet, initialAccounts) {
|
|
17
26
|
this.wallet = wallet;
|
|
27
|
+
if (initialAccounts && initialAccounts.length > 0) {
|
|
28
|
+
this.accounts = initialAccounts;
|
|
29
|
+
}
|
|
18
30
|
}
|
|
19
31
|
async getAccounts() {
|
|
20
32
|
const connect = this.wallet.features['bitcoin:connect'];
|
|
@@ -82,7 +94,12 @@ export class WalletStandardBitcoinAdapter {
|
|
|
82
94
|
async requireAccount(address) {
|
|
83
95
|
if (!this.accounts)
|
|
84
96
|
await this.getAccounts();
|
|
85
|
-
const account = this.accounts?.find(a => a.address === address)
|
|
97
|
+
const account = this.accounts?.find(a => a.address === address) ??
|
|
98
|
+
// The cached set is from an earlier authorize; the wallet may have since
|
|
99
|
+
// switched accounts (its `accounts` update in place). Re-check the
|
|
100
|
+
// wallet's CURRENT accounts before failing — so signing the live account
|
|
101
|
+
// after a switch resolves without re-invoking `bitcoin:connect`.
|
|
102
|
+
this.wallet.accounts?.find(a => a.address === address);
|
|
86
103
|
if (!account) {
|
|
87
104
|
throw new WalletConnectorError({
|
|
88
105
|
type: 'unknown',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet-standard.js","sourceRoot":"","sources":["../../src/adapters/wallet-standard.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAE7D,OAAO,EACL,aAAa,EACb,aAAa,EACb,UAAU,EACV,WAAW,EACZ,MAAM,aAAa,CAAA;AAqDpB;;;;;;;;;GASG;AACH,MAAM,OAAO,4BAA4B;
|
|
1
|
+
{"version":3,"file":"wallet-standard.js","sourceRoot":"","sources":["../../src/adapters/wallet-standard.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAE7D,OAAO,EACL,aAAa,EACb,aAAa,EACb,UAAU,EACV,WAAW,EACZ,MAAM,aAAa,CAAA;AAqDpB;;;;;;;;;GASG;AACH,MAAM,OAAO,4BAA4B;IAapB;IAZX,QAAQ,GAAmD,IAAI,CAAA;IAEvE;;;;;;;;OAQG;IACH,YACmB,MAAmC,EACpD,eAAyD;QADxC,WAAM,GAAN,MAAM,CAA6B;QAGpD,IAAI,eAAe,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,QAAQ,GAAG,eAAe,CAAA;QACjC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAA;QACvD,6EAA6E;QAC7E,2DAA2D;QAC3D,IAAI,CAAC,QAAQ,GAAG,OAAO;YACrB,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ;YAC7D,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAA;QAExB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACnC,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC;YACxC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,CAAC,CAAC,CAAA;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,MAAgC;QAChD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAA;QAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAA;QACvC,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QACjE,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC;YACzC,OAAO;YACP,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC;YACpC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1D,CAAC,CAAA;QACF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,oBAAoB,CAAC;gBAC7B,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,4DAA4D;aACtE,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAA;IACzE,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAA+B;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAA;QAC/D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAA;QACpC,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACvD,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY;YACvC,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,CACf,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAC,KAAK,EAAC,EAAE,CAAC,CAAC;gBACvC,OAAO,EAAE,MAAM,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC;gBACjD,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACrD,CAAC,CAAC,CACJ;YACH,CAAC,CAAC,SAAS,CAAA;QACb,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC;YAC7C,OAAO;YACP,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;YACjC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1C,CAAC,CAAA;QACF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,oBAAoB,CAAC;gBAC7B,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,2DAA2D;aACrE,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC;IAED,UAAU;QACR,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QACpB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;IAC1B,CAAC;IAED,oFAAoF;IAC5E,KAAK,CAAC,cAAc,CAC1B,OAAe;QAEf,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,CAAC,WAAW,EAAE,CAAA;QAC5C,MAAM,OAAO,GACX,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC;YAC/C,yEAAyE;YACzE,mEAAmE;YACnE,yEAAyE;YACzE,iEAAiE;YACjE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAA;QACxD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,oBAAoB,CAAC;gBAC7B,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,sDAAsD,OAAO,GAAG;aAC1E,CAAC,CAAA;QACJ,CAAC;QACD,OAAO,OAAO,CAAA;IAChB,CAAC;IAEO,WAAW,CAAC,MAAc;QAChC,OAAO,IAAI,oBAAoB,CAAC;YAC9B,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,yDAAyD,MAAM,EAAE;SAC3E,CAAC,CAAA;IACJ,CAAC;CACF"}
|
|
@@ -3,8 +3,13 @@ import type { BitcoinTransportAdapter } from './adapter';
|
|
|
3
3
|
/** CAIP-2 namespace this module serves. */
|
|
4
4
|
export declare const BITCOIN_NAMESPACE: Namespace;
|
|
5
5
|
/**
|
|
6
|
-
* Assert `network` is
|
|
7
|
-
*
|
|
6
|
+
* Assert `network` is the bip122 network this module actually supports
|
|
7
|
+
* (Bitcoin mainnet), else throw. Other bip122 chains (Dogecoin, Litecoin,
|
|
8
|
+
* etc.) share the namespace but differ in chain id — accepting them here
|
|
9
|
+
* would let a Bitcoin-only wallet silently return a Bitcoin address stamped
|
|
10
|
+
* with the wrong network id, so they must be rejected explicitly rather than
|
|
11
|
+
* only checking the namespace. Shared by the namespace module and its
|
|
12
|
+
* transport adapters so the boundary check lives in one place.
|
|
8
13
|
*/
|
|
9
14
|
export declare function assertBitcoinNetwork(network: Network, method: string): void;
|
|
10
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bitcoin-namespace.d.ts","sourceRoot":"","sources":["../src/bitcoin-namespace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,SAAS,EACT,OAAO,EACP,aAAa,EACb,iBAAiB,EAClB,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"bitcoin-namespace.d.ts","sourceRoot":"","sources":["../src/bitcoin-namespace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,SAAS,EACT,OAAO,EACP,aAAa,EACb,iBAAiB,EAClB,MAAM,wBAAwB,CAAA;AAG/B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AAExD,2CAA2C;AAC3C,eAAO,MAAM,iBAAiB,EAAE,SAAoB,CAAA;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAa3E;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,gBAAgB;IAIf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAHpC,2CAA2C;IAC3C,QAAQ,CAAC,SAAS,YAAoB;gBAET,OAAO,EAAE,uBAAuB;IAE7D,mDAAmD;IACnD,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI9C,8DAA8D;IAC9D,WAAW,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAIxC,6CAA6C;IAC7C,WAAW,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC;IAIrE;;;;OAIG;IACG,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC;IAKhE;;;OAGG;IACG,YAAY,CAChB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,iBAAiB,CAAC;IAK7B,uDAAuD;IACjD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC,OAAO,CAAC,WAAW;CAMpB"}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import { bitcoinNetwork } from '@meshconnect/uwc-constants';
|
|
1
2
|
import { WalletConnectorError } from '@meshconnect/uwc-types';
|
|
2
3
|
/** CAIP-2 namespace this module serves. */
|
|
3
4
|
export const BITCOIN_NAMESPACE = 'bip122';
|
|
4
5
|
/**
|
|
5
|
-
* Assert `network` is
|
|
6
|
-
*
|
|
6
|
+
* Assert `network` is the bip122 network this module actually supports
|
|
7
|
+
* (Bitcoin mainnet), else throw. Other bip122 chains (Dogecoin, Litecoin,
|
|
8
|
+
* etc.) share the namespace but differ in chain id — accepting them here
|
|
9
|
+
* would let a Bitcoin-only wallet silently return a Bitcoin address stamped
|
|
10
|
+
* with the wrong network id, so they must be rejected explicitly rather than
|
|
11
|
+
* only checking the namespace. Shared by the namespace module and its
|
|
12
|
+
* transport adapters so the boundary check lives in one place.
|
|
7
13
|
*/
|
|
8
14
|
export function assertBitcoinNetwork(network, method) {
|
|
9
15
|
if (network.namespace !== BITCOIN_NAMESPACE) {
|
|
@@ -12,6 +18,12 @@ export function assertBitcoinNetwork(network, method) {
|
|
|
12
18
|
message: `${method}: expected a bip122 network but got "${network.id}"`
|
|
13
19
|
});
|
|
14
20
|
}
|
|
21
|
+
if (network.id !== bitcoinNetwork.id) {
|
|
22
|
+
throw new WalletConnectorError({
|
|
23
|
+
type: 'unknown',
|
|
24
|
+
message: `${method}: unsupported bip122 chain "${network.id}" — only Bitcoin mainnet ("${bitcoinNetwork.id}") is supported`
|
|
25
|
+
});
|
|
26
|
+
}
|
|
15
27
|
}
|
|
16
28
|
/**
|
|
17
29
|
* Bitcoin (bip122) namespace module.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bitcoin-namespace.js","sourceRoot":"","sources":["../src/bitcoin-namespace.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAG7D,2CAA2C;AAC3C,MAAM,CAAC,MAAM,iBAAiB,GAAc,QAAQ,CAAA;AAEpD
|
|
1
|
+
{"version":3,"file":"bitcoin-namespace.js","sourceRoot":"","sources":["../src/bitcoin-namespace.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAG7D,2CAA2C;AAC3C,MAAM,CAAC,MAAM,iBAAiB,GAAc,QAAQ,CAAA;AAEpD;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAgB,EAAE,MAAc;IACnE,IAAI,OAAO,CAAC,SAAS,KAAK,iBAAiB,EAAE,CAAC;QAC5C,MAAM,IAAI,oBAAoB,CAAC;YAC7B,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,GAAG,MAAM,wCAAwC,OAAO,CAAC,EAAE,GAAG;SACxE,CAAC,CAAA;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,EAAE,KAAK,cAAc,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,IAAI,oBAAoB,CAAC;YAC7B,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,GAAG,MAAM,+BAA+B,OAAO,CAAC,EAAE,8BAA8B,cAAc,CAAC,EAAE,iBAAiB;SAC5H,CAAC,CAAA;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,gBAAgB;IAIE;IAH7B,2CAA2C;IAClC,SAAS,GAAG,iBAAiB,CAAA;IAEtC,YAA6B,OAAgC;QAAhC,YAAO,GAAP,OAAO,CAAyB;IAAG,CAAC;IAEjE,mDAAmD;IACnD,sBAAsB,CAAC,OAAgB;QACrC,oBAAoB,CAAC,OAAO,EAAE,yCAAyC,CAAC,CAAA;IAC1E,CAAC;IAED,8DAA8D;IAC9D,WAAW;QACT,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAA;IACnC,CAAC;IAED,6CAA6C;IAC7C,WAAW,CAAC,MAAgC;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;IACzC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CAAC,OAA+B;QAC5C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,CAAA;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IACvC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,YAAY,CAChB,OAAmC;QAEnC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY;YAAE,MAAM,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,CAAA;QACtE,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAA;IAC3C,CAAC;IAED,uDAAuD;IACvD,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAA;IACnC,CAAC;IAEO,WAAW,CAAC,MAAc;QAChC,OAAO,IAAI,oBAAoB,CAAC;YAC9B,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,oBAAoB,MAAM,0CAA0C;SAC9E,CAAC,CAAA;IACJ,CAAC;CACF"}
|
package/dist/encoding.d.ts
CHANGED
|
@@ -8,4 +8,5 @@ export declare function utf8ToBytes(text: string): Uint8Array;
|
|
|
8
8
|
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
9
9
|
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
10
10
|
export declare function base64ToBytes(base64: string): Uint8Array;
|
|
11
|
+
export declare function hexToBytes(hex: string): Uint8Array;
|
|
11
12
|
//# sourceMappingURL=encoding.d.ts.map
|
package/dist/encoding.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEpD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIpD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIvD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAKxD"}
|
|
1
|
+
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEpD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIpD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIvD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAKxD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAgBlD"}
|
package/dist/encoding.js
CHANGED
|
@@ -26,4 +26,21 @@ export function base64ToBytes(base64) {
|
|
|
26
26
|
bytes[i] = binary.charCodeAt(i);
|
|
27
27
|
return bytes;
|
|
28
28
|
}
|
|
29
|
+
export function hexToBytes(hex) {
|
|
30
|
+
const clean = /^0x/i.test(hex) ? hex.slice(2) : hex;
|
|
31
|
+
if (clean.length % 2 !== 0) {
|
|
32
|
+
throw new Error('hexToBytes: odd-length hex string');
|
|
33
|
+
}
|
|
34
|
+
// Validate before parsing: `parseInt` on a non-hex pair yields NaN, which a
|
|
35
|
+
// Uint8Array silently coerces to 0 — so bad input would corrupt data (a PSBT
|
|
36
|
+
// or public key) instead of failing fast. Reject it.
|
|
37
|
+
if (!/^[0-9a-fA-F]*$/.test(clean)) {
|
|
38
|
+
throw new Error('hexToBytes: non-hex characters');
|
|
39
|
+
}
|
|
40
|
+
const bytes = new Uint8Array(clean.length / 2);
|
|
41
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
42
|
+
bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);
|
|
43
|
+
}
|
|
44
|
+
return bytes;
|
|
45
|
+
}
|
|
29
46
|
//# sourceMappingURL=encoding.js.map
|
package/dist/encoding.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encoding.js","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,IAAI,GAAG,GAAG,EAAE,CAAA;IACZ,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IACnE,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IAC7D,OAAO,IAAI,CAAC,MAAM,CAAC,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;IAC3B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;IACvE,OAAO,KAAK,CAAA;AACd,CAAC"}
|
|
1
|
+
{"version":3,"file":"encoding.js","sourceRoot":"","sources":["../src/encoding.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,IAAI,GAAG,GAAG,EAAE,CAAA;IACZ,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IACnE,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IAC7D,OAAO,IAAI,CAAC,MAAM,CAAC,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;IAC3B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;IACvE,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;IACnD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;IACtD,CAAC;IACD,4EAA4E;IAC5E,6EAA6E;IAC7E,qDAAqD;IACrD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;IACnD,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACxD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { BitcoinNamespace, assertBitcoinNetwork, BITCOIN_NAMESPACE } from './bit
|
|
|
2
2
|
export type { BitcoinTransportAdapter } from './adapter';
|
|
3
3
|
export { WalletStandardBitcoinAdapter } from './adapters/wallet-standard';
|
|
4
4
|
export type { WalletStandardBitcoinWallet, WalletStandardBitcoinAccount } from './adapters/wallet-standard';
|
|
5
|
-
export {
|
|
6
|
-
export type {
|
|
5
|
+
export { OkxBitcoinAdapter } from './adapters/okx';
|
|
6
|
+
export type { OkxBitcoinProvider } from './adapters/okx';
|
|
7
|
+
export { bytesToHex, hexToBytes } from './encoding';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AACxD,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAA;AACzE,YAAY,EACV,2BAA2B,EAC3B,4BAA4B,EAC7B,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,qBAAqB,CAAA;AAC5B,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AACxD,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAA;AACzE,YAAY,EACV,2BAA2B,EAC3B,4BAA4B,EAC7B,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,YAAY,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { BitcoinNamespace, assertBitcoinNetwork, BITCOIN_NAMESPACE } from './bitcoin-namespace';
|
|
2
2
|
export { WalletStandardBitcoinAdapter } from './adapters/wallet-standard';
|
|
3
|
-
export {
|
|
3
|
+
export { OkxBitcoinAdapter } from './adapters/okx';
|
|
4
|
+
export { bytesToHex, hexToBytes } from './encoding';
|
|
4
5
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAA;AAKzE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EAClB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAA;AAKzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshconnect/uwc-bitcoin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Mesh-owned Bitcoin (bip122) namespace module for Universal Wallet Connector — network-specific logic (PSBT, address/network handling, mempool broadcast) with pluggable transport adapters (Wallet Standard bitcoin:* and WalletConnect bip122), consumed by the injected and walletConnect transport connectors",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"src"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@meshconnect/uwc-
|
|
19
|
+
"@meshconnect/uwc-constants": "0.7.5",
|
|
20
|
+
"@meshconnect/uwc-types": "0.27.0"
|
|
20
21
|
},
|
|
21
22
|
"devDependencies": {
|
|
22
23
|
"typescript": "^5.9.3"
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest'
|
|
2
|
+
import { WalletConnectorError } from '@meshconnect/uwc-types'
|
|
3
|
+
import { OkxBitcoinAdapter, type OkxBitcoinProvider } from './okx'
|
|
4
|
+
import {
|
|
5
|
+
base64ToBytes,
|
|
6
|
+
bytesToBase64,
|
|
7
|
+
bytesToHex,
|
|
8
|
+
hexToBytes
|
|
9
|
+
} from '../encoding'
|
|
10
|
+
|
|
11
|
+
const account = { address: 'bc1qokx', publicKey: '02aabbcc' }
|
|
12
|
+
|
|
13
|
+
/** A fake OKX injected bitcoin provider wired via vi mocks. */
|
|
14
|
+
const fakeProvider = (
|
|
15
|
+
overrides: Partial<OkxBitcoinProvider> = {}
|
|
16
|
+
): OkxBitcoinProvider => ({
|
|
17
|
+
requestAccounts: vi.fn().mockResolvedValue([account.address]),
|
|
18
|
+
getAccounts: vi.fn().mockResolvedValue([account.address]),
|
|
19
|
+
getPublicKey: vi.fn().mockResolvedValue(account.publicKey),
|
|
20
|
+
signMessage: vi.fn().mockResolvedValue('c2lnbmF0dXJl'),
|
|
21
|
+
signPsbt: vi.fn().mockResolvedValue('abcdef01'),
|
|
22
|
+
on: vi.fn(),
|
|
23
|
+
removeListener: vi.fn(),
|
|
24
|
+
...overrides
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('OkxBitcoinAdapter', () => {
|
|
28
|
+
it('getAccounts prompts via requestAccounts and pairs the active public key', async () => {
|
|
29
|
+
const provider = fakeProvider()
|
|
30
|
+
const accounts = await new OkxBitcoinAdapter(provider).getAccounts()
|
|
31
|
+
|
|
32
|
+
expect(provider.requestAccounts).toHaveBeenCalledOnce()
|
|
33
|
+
expect(accounts).toEqual([{ address: 'bc1qokx', publicKey: '02aabbcc' }])
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('getAccounts tolerates a getPublicKey failure (empty key, not a throw)', async () => {
|
|
37
|
+
const provider = fakeProvider({
|
|
38
|
+
getPublicKey: vi.fn().mockRejectedValue(new Error('locked'))
|
|
39
|
+
})
|
|
40
|
+
const accounts = await new OkxBitcoinAdapter(provider).getAccounts()
|
|
41
|
+
expect(accounts).toEqual([{ address: 'bc1qokx', publicKey: '' }])
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('signMessage maps bip322 → bip322-simple and passes the base64 signature through', async () => {
|
|
45
|
+
const provider = fakeProvider()
|
|
46
|
+
const adapter = new OkxBitcoinAdapter(provider)
|
|
47
|
+
|
|
48
|
+
const result = await adapter.signMessage({
|
|
49
|
+
account: { address: account.address, publicKey: account.publicKey },
|
|
50
|
+
message: 'verify me',
|
|
51
|
+
protocol: 'bip322'
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
expect(provider.signMessage).toHaveBeenCalledWith(
|
|
55
|
+
'verify me',
|
|
56
|
+
'bip322-simple'
|
|
57
|
+
)
|
|
58
|
+
expect(result).toEqual({ type: 'standard', signature: 'c2lnbmF0dXJl' })
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('signMessage defaults to ecdsa when no protocol is given', async () => {
|
|
62
|
+
const provider = fakeProvider()
|
|
63
|
+
await new OkxBitcoinAdapter(provider).signMessage({
|
|
64
|
+
account: { address: account.address, publicKey: account.publicKey },
|
|
65
|
+
message: 'hi'
|
|
66
|
+
})
|
|
67
|
+
expect(provider.signMessage).toHaveBeenCalledWith('hi', 'ecdsa')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('signMessage throws when the provider returns no signature', async () => {
|
|
71
|
+
const provider = fakeProvider({
|
|
72
|
+
signMessage: vi.fn().mockResolvedValue('')
|
|
73
|
+
})
|
|
74
|
+
await expect(
|
|
75
|
+
new OkxBitcoinAdapter(provider).signMessage({
|
|
76
|
+
account: { address: account.address, publicKey: account.publicKey },
|
|
77
|
+
message: 'hi'
|
|
78
|
+
})
|
|
79
|
+
).rejects.toBeInstanceOf(WalletConnectorError)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('signPsbt converts base64 → hex for OKX and hex → base64 on the way back', async () => {
|
|
83
|
+
// Round-trip fixture: a base64 PSBT whose hex the mock echoes back signed.
|
|
84
|
+
const psbtBytes = new Uint8Array([0x70, 0x73, 0x62, 0x74, 0xff])
|
|
85
|
+
const psbtB64 = bytesToBase64(psbtBytes)
|
|
86
|
+
const signedBytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef])
|
|
87
|
+
const provider = fakeProvider({
|
|
88
|
+
signPsbt: vi.fn().mockResolvedValue(bytesToHex(signedBytes))
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
const result = await new OkxBitcoinAdapter(provider).signPsbt({
|
|
92
|
+
from: account.address,
|
|
93
|
+
psbt: psbtB64
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// OKX received the PSBT as HEX (autoFinalized:false = sign-only).
|
|
97
|
+
expect(provider.signPsbt).toHaveBeenCalledWith(bytesToHex(psbtBytes), {
|
|
98
|
+
autoFinalized: false
|
|
99
|
+
})
|
|
100
|
+
// ...and we returned it as base64.
|
|
101
|
+
expect(result).toBe(bytesToBase64(signedBytes))
|
|
102
|
+
expect(base64ToBytes(result)).toEqual(signedBytes)
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
it('maps inputsToSign → toSignInputs (index/address + numeric sighash)', async () => {
|
|
106
|
+
const provider = fakeProvider()
|
|
107
|
+
await new OkxBitcoinAdapter(provider).signPsbt({
|
|
108
|
+
from: 'bc1qokx',
|
|
109
|
+
psbt: bytesToBase64(new Uint8Array([1, 2])),
|
|
110
|
+
inputsToSign: [
|
|
111
|
+
{ address: 'bc1qa', signingIndexes: [0, 2] },
|
|
112
|
+
{
|
|
113
|
+
address: 'bc1qb',
|
|
114
|
+
signingIndexes: [1],
|
|
115
|
+
sigHash: 'SINGLE|ANYONECANPAY'
|
|
116
|
+
}
|
|
117
|
+
]
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
expect(provider.signPsbt).toHaveBeenCalledWith(expect.any(String), {
|
|
121
|
+
autoFinalized: false,
|
|
122
|
+
toSignInputs: [
|
|
123
|
+
{ index: 0, address: 'bc1qa' },
|
|
124
|
+
{ index: 2, address: 'bc1qa' },
|
|
125
|
+
{ index: 1, address: 'bc1qb', sighashTypes: [0x83] }
|
|
126
|
+
]
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('omits toSignInputs entirely when no inputsToSign is given', async () => {
|
|
131
|
+
const provider = fakeProvider()
|
|
132
|
+
await new OkxBitcoinAdapter(provider).signPsbt({
|
|
133
|
+
from: 'bc1qokx',
|
|
134
|
+
psbt: bytesToBase64(new Uint8Array([1, 2]))
|
|
135
|
+
})
|
|
136
|
+
expect(provider.signPsbt).toHaveBeenCalledWith(expect.any(String), {
|
|
137
|
+
autoFinalized: false
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('signPsbt throws when the provider returns no PSBT', async () => {
|
|
142
|
+
const provider = fakeProvider({
|
|
143
|
+
signPsbt: vi.fn().mockResolvedValue('')
|
|
144
|
+
})
|
|
145
|
+
await expect(
|
|
146
|
+
new OkxBitcoinAdapter(provider).signPsbt({
|
|
147
|
+
from: account.address,
|
|
148
|
+
psbt: bytesToBase64(new Uint8Array([1, 2]))
|
|
149
|
+
})
|
|
150
|
+
).rejects.toBeInstanceOf(WalletConnectorError)
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
it('disconnect resolves (OKX has no disconnect RPC)', async () => {
|
|
154
|
+
await expect(
|
|
155
|
+
new OkxBitcoinAdapter(fakeProvider()).disconnect()
|
|
156
|
+
).resolves.toBeUndefined()
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
describe('hexToBytes', () => {
|
|
161
|
+
it('round-trips with bytesToHex, tolerating a 0x / 0X prefix', () => {
|
|
162
|
+
const bytes = new Uint8Array([0x00, 0x0f, 0xa0, 0xff])
|
|
163
|
+
expect(hexToBytes(bytesToHex(bytes))).toEqual(bytes)
|
|
164
|
+
expect(hexToBytes('0x' + bytesToHex(bytes))).toEqual(bytes)
|
|
165
|
+
expect(hexToBytes('0X' + bytesToHex(bytes))).toEqual(bytes)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('throws on odd-length hex', () => {
|
|
169
|
+
expect(() => hexToBytes('abc')).toThrow(/odd-length/)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('throws on non-hex characters (no silent 0-coercion)', () => {
|
|
173
|
+
expect(() => hexToBytes('zz')).toThrow(/non-hex/)
|
|
174
|
+
expect(() => hexToBytes('12g4')).toThrow(/non-hex/)
|
|
175
|
+
})
|
|
176
|
+
})
|