@getpara/graz-connector 0.1.0-alpha.6 → 2.0.0-dev.11

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/package.json CHANGED
@@ -1,25 +1,36 @@
1
1
  {
2
2
  "name": "@getpara/graz-connector",
3
- "version": "0.1.0-alpha.6",
3
+ "version": "2.0.0-dev.11",
4
+ "sideEffects": false,
4
5
  "type": "module",
5
6
  "main": "dist/index.js",
6
7
  "types": "dist/index.d.ts",
7
- "sideEffects": false,
8
- "dependencies": {
9
- "@getpara/react-sdk": "1.11.0",
10
- "@getpara/cosmjs-v0-integration": "1.11.0"
11
- },
12
8
  "scripts": {
13
9
  "build": "rm -rf dist && yarn typegen && node ./scripts/build.mjs",
10
+ "test": "vitest run --coverage",
14
11
  "typegen": "tsc --emitDeclarationOnly"
15
12
  },
13
+ "dependencies": {
14
+ "@getpara/cosmjs-v0-integration": "~2.0.0-alpha.44",
15
+ "@getpara/web-sdk": "~2.0.0-alpha.44"
16
+ },
16
17
  "devDependencies": {
17
- "@cosmjs/amino": "^0.32.3",
18
- "@cosmjs/encoding": "^0.32.3",
19
- "@cosmjs/proto-signing": "^0.32.3",
20
- "cosmjs-types": "0.9.0",
21
- "typescript": "5.1.6",
22
- "graz": "0.2.1",
23
- "@keplr-wallet/types": "0.12.221"
18
+ "@cosmjs/amino": "^0.32.4",
19
+ "@cosmjs/encoding": "^0.32.4",
20
+ "@cosmjs/proto-signing": "^0.32.4",
21
+ "@keplr-wallet/types": "^0.12.156",
22
+ "cosmjs-types": "^0.9.0",
23
+ "graz": "^0.3.3",
24
+ "typescript": "5.1.6"
25
+ },
26
+ "peerDependencies": {
27
+ "@cosmjs/amino": ">=0.32.4",
28
+ "@cosmjs/encoding": ">=0.32.4",
29
+ "@cosmjs/proto-signing": ">=0.32.4",
30
+ "@cosmjs/stargate": ">=0.32.4",
31
+ "@cosmjs/tendermint-rpc": ">=0.32.4",
32
+ "@keplr-wallet/types": ">=0.12.156",
33
+ "cosmjs-types": ">=0.8.0",
34
+ "graz": ">=0.3.3"
24
35
  }
25
36
  }
package/src/connector.ts CHANGED
@@ -1,153 +1,211 @@
1
- import ParaWeb from '@getpara/react-sdk';
2
- import type { Environment, ParaModalProps } from '@getpara/react-sdk';
3
- import type { Wallet, Key as GrazKey } from 'graz';
4
- import { getChainInfo } from 'graz';
5
- import type {
6
- OfflineAminoSigner,
7
- OfflineDirectSigner,
8
- AminoSignResponse,
9
- StdSignDoc,
10
- StdSignature,
11
- DirectSignResponse,
12
- AccountData,
13
- Algo,
14
- SignDoc as KeplrSignDoc,
15
- SignDoc,
16
- } from '@keplr-wallet/types';
17
- import { ParaAminoSigner, ParaProtoSigner } from '@getpara/cosmjs-v0-integration';
18
1
  import { fromBech32 } from '@cosmjs/encoding';
19
- import { renderModal } from './connectorModal.js';
20
- import Long from 'long';
2
+ import { SignDoc } from 'cosmjs-types/cosmos/tx/v1beta1/tx.js';
3
+ import { Wallet, SignDoc as GrazSignDoc } from 'graz';
4
+ import { ParaAminoSigner, ParaProtoSigner } from '@getpara/cosmjs-v0-integration';
5
+ import { ParaWeb, Wallet as ParaWallet } from '@getpara/web-sdk';
6
+ import { Algo, DirectSignResponse, OfflineDirectSigner } from '@cosmjs/proto-signing';
7
+ import { AccountData, AminoSignResponse, OfflineAminoSigner, StdSignature, StdSignDoc } from '@cosmjs/amino';
8
+ import { ChainInfo, KeplrSignOptions } from '@keplr-wallet/types';
21
9
 
22
- const TEN_MINUTES_MS = 600000;
10
+ export type ParaGrazConnectorEvents = {
11
+ onEnabled?: (chainIds: string[], connector: ParaGrazConnector) => void;
12
+ };
23
13
 
24
14
  export interface ParaGrazConfig {
25
- apiKey: string;
26
- env: Environment;
27
- modalProps?: ParaModalProps;
15
+ paraWeb: ParaWeb;
16
+ events?: ParaGrazConnectorEvents;
17
+ noModal?: boolean;
18
+ }
19
+
20
+ export function toArray<T>(v: T | T[]): T[] {
21
+ return Array.isArray(v) ? v : [v];
28
22
  }
29
23
 
30
- export class ParaOfflineSigner implements OfflineDirectSigner {
31
- private chainId: string;
32
- private paraWebClient: ParaWeb;
24
+ class ParaOfflineSigner implements OfflineDirectSigner {
25
+ constructor(
26
+ protected readonly chainId: string,
27
+ protected readonly connector: ParaGrazConnector,
28
+ ) {}
29
+
30
+ protected get para() {
31
+ return this.connector.getParaWebClient();
32
+ }
33
+
34
+ protected get prefix() {
35
+ return this.connector.getBech32Prefix(this.chainId);
36
+ }
33
37
 
34
- constructor(chainId: string, paraWebClient: ParaWeb) {
35
- this.chainId = chainId;
36
- this.paraWebClient = paraWebClient;
38
+ protected async wallet() {
39
+ return this.connector.getFirstWallet();
37
40
  }
38
41
 
39
42
  async getAccounts(): Promise<readonly AccountData[]> {
40
- const key = await getKey(this.paraWebClient, this.chainId);
43
+ const key = await this.connector.getKey(this.chainId);
41
44
  return [
42
45
  {
43
- address: key.address,
46
+ address: key.bech32Address,
44
47
  algo: key.algo as Algo,
45
- pubkey: key.pubkey,
48
+ pubkey: key.pubKey,
46
49
  },
47
50
  ];
48
51
  }
49
52
 
50
- async signDirect(signerAddress: string, signDoc: KeplrSignDoc): Promise<DirectSignResponse> {
53
+ async signDirect(signerAddress: string, signDoc: SignDoc): Promise<DirectSignResponse> {
51
54
  if (this.chainId !== signDoc.chainId) {
52
- throw new Error('Chain ID does not match signer chain ID');
55
+ throw new Error(`Chain ID mismatch: expected ${this.chainId}, got ${signDoc.chainId}`);
53
56
  }
54
57
 
55
58
  const accounts = await this.getAccounts();
56
- if (accounts.find(account => account.address !== signerAddress)) {
57
- throw new Error('Signer address does not match wallet address');
59
+ if (accounts.every(a => a.address !== signerAddress)) {
60
+ throw new Error(`Signer address ${signerAddress} not found in wallet`);
58
61
  }
59
62
 
60
- const convertedSignDoc = {
61
- bodyBytes: signDoc.bodyBytes,
62
- authInfoBytes: signDoc.authInfoBytes,
63
- chainId: signDoc.chainId,
64
- accountNumber: typeof signDoc.accountNumber === 'string' ? signDoc.accountNumber : signDoc.accountNumber.toString(),
65
- };
66
-
67
- const result = await requestSignature(this.paraWebClient, this.chainId, signerAddress, convertedSignDoc);
63
+ const signer = new ParaProtoSigner(this.para, this.prefix, (await this.wallet()).id);
68
64
 
69
- return {
70
- signed: {
71
- bodyBytes: result.signed.bodyBytes,
72
- authInfoBytes: result.signed.authInfoBytes,
73
- chainId: result.signed.chainId,
74
- accountNumber: Long.fromString(result.signed.accountNumber.toString()),
75
- },
76
- signature: result.signature,
77
- };
65
+ try {
66
+ const result = await signer.signDirect(signerAddress, signDoc);
67
+ return {
68
+ signed: {
69
+ bodyBytes: result.signed.bodyBytes,
70
+ authInfoBytes: result.signed.authInfoBytes,
71
+ chainId: result.signed.chainId,
72
+ accountNumber: result.signed.accountNumber,
73
+ },
74
+ signature: result.signature,
75
+ };
76
+ } catch (err) {
77
+ throw new Error(`Direct signing failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
78
+ }
78
79
  }
79
80
  }
80
81
 
81
82
  export class ParaGrazConnector implements Omit<Wallet, 'experimentalSuggestChain'> {
82
- private paraWebClient: ParaWeb;
83
- private config: ParaGrazConfig;
84
- private isModalClosed: boolean;
83
+ protected paraWebClient: ParaWeb;
84
+ protected enabledChainIds = new Set<string>();
85
+ protected readonly events?: ParaGrazConnectorEvents;
86
+ protected noModal?: boolean;
87
+
88
+ constructor(
89
+ protected readonly config: ParaGrazConfig,
90
+ protected readonly chains: ChainInfo[] | null = null,
91
+ ) {
92
+ if (!config?.paraWeb) {
93
+ throw new Error('ParaWeb instance required in config');
94
+ }
95
+ this.events = config.events;
96
+ this.paraWebClient = config.paraWeb;
97
+ this.noModal = config.noModal;
98
+ }
85
99
 
86
- constructor(config: ParaGrazConfig) {
87
- if (!config || !config.apiKey || !config.env) {
88
- throw new Error('Para Connector: Missing API Key or Environment in config.');
100
+ protected async ensureChainEnabled(chainId: string): Promise<void> {
101
+ if (!this.enabledChainIds.has(chainId)) {
102
+ throw new Error(`Chain ${chainId} not enabled. Call enable() first`);
103
+ }
104
+
105
+ if (!(await this.paraWebClient.isFullyLoggedIn())) {
106
+ throw new Error('Para wallet not authenticated');
89
107
  }
90
- this.config = config;
91
- this.paraWebClient = new ParaWeb(config.env, config.apiKey);
92
- this.isModalClosed = true;
93
108
  }
94
109
 
95
- closeModal = () => {
96
- this.isModalClosed = true;
97
- };
110
+ protected async waitForLogin(timeoutMs = 60_000): Promise<void> {
111
+ const deadline = Date.now() + timeoutMs;
112
+ let delay = 500;
113
+ const MAX_DELAY = 5_000;
98
114
 
99
- private async waitForLogin(timeoutMs = TEN_MINUTES_MS): Promise<boolean> {
100
- const startTime = Date.now();
101
- while (Date.now() - startTime < timeoutMs) {
115
+ while (true) {
102
116
  if (await this.paraWebClient.isFullyLoggedIn()) {
103
- return true;
117
+ return;
104
118
  }
105
119
 
106
- if (this.isModalClosed) {
107
- throw new Error('user closed modal');
120
+ if (Date.now() >= deadline) {
121
+ throw new Error(`Login timeout after ${timeoutMs / 1000}s`);
108
122
  }
109
123
 
110
- await new Promise(resolve => setTimeout(resolve, 2000));
124
+ await new Promise(r => setTimeout(r, delay));
125
+ delay = Math.min(delay * 1.5, MAX_DELAY);
111
126
  }
112
-
113
- throw new Error('timed out waiting for user to log in');
114
127
  }
115
128
 
116
- private async waitForAccounts(chainIds: string | string[], timeoutMs = 5000): Promise<boolean> {
117
- const startTime = Date.now();
118
- while (Date.now() - startTime < timeoutMs) {
119
- const wallets = Object.values(this.paraWebClient.getWalletsByType('COSMOS'));
120
- if (wallets && wallets.length > 0) {
121
- return true;
129
+ protected async waitForAccounts(timeoutMs = 5_000): Promise<ParaWallet[]> {
130
+ const deadline = Date.now() + timeoutMs;
131
+ let delay = 250;
132
+ const MAX_DELAY = 1_000;
133
+
134
+ while (true) {
135
+ const wallets = this.paraWebClient.getWalletsByType('COSMOS');
136
+ if (wallets.length) {
137
+ return wallets;
138
+ }
139
+
140
+ if (Date.now() >= deadline) {
141
+ throw new Error('No Cosmos wallets found');
122
142
  }
123
- await new Promise(resolve => setTimeout(resolve, 500));
143
+
144
+ await new Promise(r => setTimeout(r, delay));
145
+ delay = Math.min(delay * 1.5, MAX_DELAY);
124
146
  }
147
+ }
125
148
 
126
- throw new Error('timed out waiting for accounts to load');
149
+ protected async hasCosmosWallet(): Promise<boolean> {
150
+ const isLoggedIn = await this.paraWebClient.isFullyLoggedIn();
151
+ const wallets = this.paraWebClient.getWalletsByType('COSMOS');
152
+ return isLoggedIn && wallets.length > 0;
127
153
  }
128
154
 
129
- async enable(chainIds: string | string[]): Promise<void> {
130
- if (await this.paraWebClient.isFullyLoggedIn()) {
131
- const wallets = Object.values(this.paraWebClient.getWalletsByType('COSMOS'));
132
- if (wallets && wallets.length > 0) {
155
+ async enable(chainIdsInput: string | string[]): Promise<void> {
156
+ const chainIds = toArray(chainIdsInput);
157
+ const previousEnabled = new Set(this.enabledChainIds);
158
+
159
+ try {
160
+ chainIds.forEach(id => this.enabledChainIds.add(id));
161
+
162
+ if (await this.hasCosmosWallet()) {
163
+ this.events?.onEnabled?.(chainIds, this);
133
164
  return;
134
165
  }
135
- }
136
166
 
137
- this.isModalClosed = false;
138
- renderModal(this.paraWebClient, this.config.modalProps, () => {
139
- this.isModalClosed = true;
140
- });
167
+ if (!this.noModal) {
168
+ throw new Error('Modal not supported. Use @getpara/graz-integration or set noModal: true');
169
+ }
170
+
171
+ await this.waitForLogin();
172
+ await this.waitForAccounts();
173
+ this.events?.onEnabled?.(chainIds, this);
174
+ } catch (err) {
175
+ this.enabledChainIds = previousEnabled;
176
+
177
+ if (err instanceof Error) {
178
+ throw err;
179
+ }
180
+
181
+ throw new Error('Failed to enable Para wallet');
182
+ }
183
+ }
141
184
 
142
- await this.waitForLogin();
185
+ async disconnect(): Promise<void> {
186
+ try {
187
+ await this.paraWebClient.logout();
188
+ } catch (err) {
189
+ throw new Error('Disconnect failed');
190
+ } finally {
191
+ this.enabledChainIds.clear();
192
+ }
193
+ }
143
194
 
195
+ async getFirstWallet(): Promise<ParaWallet> {
144
196
  try {
145
- await this.waitForAccounts(chainIds);
146
- } catch (error) {
147
- throw new Error('accounts not available after login');
197
+ const [wallet] = await this.waitForAccounts();
198
+ return wallet;
199
+ } catch (err) {
200
+ throw new Error('No Para wallet available');
148
201
  }
149
202
  }
150
203
 
204
+ getBech32Prefix(chainId: string): string {
205
+ const prefix = this.chains?.find(c => c.chainId === chainId)?.bech32Config?.bech32PrefixAccAddr || 'cosmos';
206
+ return prefix;
207
+ }
208
+
151
209
  getParaWebClient(): ParaWeb {
152
210
  return this.paraWebClient;
153
211
  }
@@ -156,215 +214,142 @@ export class ParaGrazConnector implements Omit<Wallet, 'experimentalSuggestChain
156
214
  return this.config;
157
215
  }
158
216
 
159
- async getKey(chainId: string): Promise<GrazKey> {
160
- const wallets = Object.values(this.paraWebClient.getWalletsByType('COSMOS'));
161
-
162
- if (wallets.length === 0) {
163
- throw new Error(`Para Connector: No wallets found for chainId ${chainId}`);
164
- }
165
-
166
- // Get the bech32 prefix from chain info
167
- const bech32Prefix = this.getBech32Prefix(chainId);
168
-
169
- const walletSigner = new ParaProtoSigner(this.paraWebClient, bech32Prefix, wallets[0].id);
170
- const accountData = await walletSigner.getAccounts();
171
- if (accountData.length === 0) {
172
- throw new Error(`Para Connector: No accounts found for wallet ${wallets[0].id}`);
173
- }
174
-
175
- const account = accountData[0];
217
+ protected buildHybridSigner(chainId: string): OfflineAminoSigner & OfflineDirectSigner {
218
+ const aminoSigner = this.getOfflineSignerOnlyAmino(chainId);
219
+ const directSigner = new ParaOfflineSigner(chainId, this);
176
220
  return {
177
- address: fromBech32(account.address).data,
178
- bech32Address: account.address,
179
- algo: account.algo,
180
- name: account.address,
181
- pubKey: account.pubkey,
182
- isKeystone: false,
183
- isNanoLedger: false,
184
- };
221
+ getAccounts: () => directSigner.getAccounts(),
222
+ signAmino: (signer: string, signDoc: StdSignDoc) => aminoSigner.signAmino(signer, signDoc),
223
+ signDirect: (signer: string, signDoc: SignDoc) => directSigner.signDirect(signer, signDoc),
224
+ } as unknown as OfflineAminoSigner & OfflineDirectSigner;
185
225
  }
186
226
 
187
- getOfflineSigner(chainId: string): OfflineAminoSigner & OfflineDirectSigner {
188
- const aminoSigner = this.getOfflineSignerOnlyAmino(chainId);
189
- const directSigner = new ParaOfflineSigner(chainId, this.paraWebClient);
227
+ async getKey(chainId: string) {
228
+ try {
229
+ await this.ensureChainEnabled(chainId);
230
+ const wallet = await this.getFirstWallet();
231
+ const signer = new ParaProtoSigner(this.paraWebClient, this.getBech32Prefix(chainId), wallet.id);
232
+ const [account] = await signer.getAccounts();
190
233
 
191
- const combinedSigner = {
192
- getAccounts: () => directSigner.getAccounts(),
193
- signAmino: (signerAddress: string, signDoc: StdSignDoc) => aminoSigner.signAmino(signerAddress, signDoc),
194
- signDirect: (signerAddress: string, signDoc: SignDoc) => directSigner.signDirect(signerAddress, signDoc),
195
- };
234
+ if (!account) {
235
+ throw new Error(`No Cosmos accounts for chain ${chainId}`);
236
+ }
237
+
238
+ return {
239
+ name: 'Para Wallet',
240
+ algo: account.algo,
241
+ pubKey: account.pubkey,
242
+ address: fromBech32(account.address).data,
243
+ bech32Address: account.address,
244
+ isKeystone: false,
245
+ isNanoLedger: false,
246
+ };
247
+ } catch (err) {
248
+ if (err instanceof Error) {
249
+ throw err;
250
+ }
196
251
 
197
- return combinedSigner as unknown as OfflineAminoSigner & OfflineDirectSigner;
252
+ throw new Error(`Failed to get key for chain ${chainId}`);
253
+ }
198
254
  }
199
255
 
200
256
  getOfflineSignerOnlyAmino(chainId: string): OfflineAminoSigner {
201
- const wallets = Object.values(this.paraWebClient.getWalletsByType('COSMOS'));
202
- if (wallets.length === 0) {
203
- throw new Error(`Para Connector: No wallets found for chainId ${chainId}`);
257
+ void this.ensureChainEnabled(chainId);
258
+ const wallet = this.paraWebClient.getWalletsByType('COSMOS')[0];
259
+
260
+ if (!wallet) {
261
+ throw new Error('No Cosmos wallet for Amino signing');
204
262
  }
205
263
 
206
- const bech32Prefix = this.getBech32Prefix(chainId);
264
+ return new ParaAminoSigner(this.paraWebClient, this.getBech32Prefix(chainId), wallet.id);
265
+ }
207
266
 
208
- return new ParaAminoSigner(this.paraWebClient, bech32Prefix, wallets[0].id);
267
+ getOfflineSigner(chainId: string): OfflineAminoSigner & OfflineDirectSigner {
268
+ void this.ensureChainEnabled(chainId);
269
+ return this.buildHybridSigner(chainId);
209
270
  }
210
271
 
211
- getOfflineSignerAuto(chainId: string): Promise<OfflineAminoSigner | OfflineDirectSigner> {
212
- return Promise.resolve(this.getOfflineSignerOnlyAmino(chainId));
272
+ async getOfflineSignerAuto(chainId: string): Promise<OfflineAminoSigner | OfflineDirectSigner> {
273
+ void this.ensureChainEnabled(chainId);
274
+ return this.buildHybridSigner(chainId);
213
275
  }
214
276
 
215
- async signAmino(chainId: string, signer: string, signDoc: StdSignDoc): Promise<AminoSignResponse> {
216
- await this.ensureConnected();
277
+ async signAmino(
278
+ chainId: string,
279
+ signer: string,
280
+ signDoc: StdSignDoc,
281
+ _signOptions?: KeplrSignOptions,
282
+ ): Promise<AminoSignResponse> {
283
+ await this.ensureChainEnabled(chainId);
217
284
 
218
- const wallets = Object.values(this.paraWebClient.getWalletsByType('COSMOS'));
219
- if (wallets.length === 0) {
220
- throw new Error(`Para Connector: No wallets found for chainId ${chainId}`);
285
+ try {
286
+ const wallet = await this.getFirstWallet();
287
+ const signerImpl = new ParaAminoSigner(this.paraWebClient, this.getBech32Prefix(chainId), wallet.id);
288
+ const response = await signerImpl.signAmino(signer, signDoc);
289
+ return response;
290
+ } catch (err) {
291
+ throw new Error(`Amino signing failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
221
292
  }
222
-
223
- const bech32Prefix = this.getBech32Prefix(chainId);
224
-
225
- const walletSigner = new ParaAminoSigner(this.paraWebClient, bech32Prefix, wallets[0].id);
226
-
227
- return walletSigner.signAmino(signer, signDoc);
228
293
  }
229
294
 
230
295
  async signDirect(
231
296
  chainId: string,
232
297
  signer: string,
233
- signDoc: {
234
- bodyBytes?: Uint8Array;
235
- authInfoBytes?: Uint8Array;
236
- chainId?: string;
237
- accountNumber?: Long;
238
- },
298
+ signDoc: GrazSignDoc,
299
+ _signOptions?: KeplrSignOptions,
239
300
  ): Promise<DirectSignResponse> {
240
- await this.ensureConnected();
301
+ await this.ensureChainEnabled(chainId);
241
302
 
242
- const wallets = Object.values(this.paraWebClient.getWalletsByType('COSMOS'));
243
- if (wallets.length === 0) {
244
- throw new Error(`Para Connector: No wallets found for chainId ${chainId}`);
303
+ try {
304
+ const wallet = await this.getFirstWallet();
305
+ const signerImpl = new ParaProtoSigner(this.paraWebClient, this.getBech32Prefix(chainId), wallet.id);
306
+ const convertedSignDoc: SignDoc = {
307
+ bodyBytes: signDoc.bodyBytes ?? new Uint8Array(),
308
+ authInfoBytes: signDoc.authInfoBytes ?? new Uint8Array(),
309
+ chainId: signDoc.chainId,
310
+ accountNumber: typeof signDoc.accountNumber === 'bigint' ? signDoc.accountNumber : BigInt(signDoc.accountNumber),
311
+ };
312
+
313
+ const result = await signerImpl.signDirect(signer, convertedSignDoc);
314
+ return {
315
+ signed: {
316
+ bodyBytes: result.signed.bodyBytes,
317
+ authInfoBytes: result.signed.authInfoBytes,
318
+ chainId: result.signed.chainId,
319
+ accountNumber: result.signed.accountNumber,
320
+ },
321
+ signature: result.signature,
322
+ };
323
+ } catch (err) {
324
+ throw new Error(`Direct signing failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
245
325
  }
246
-
247
- const convertedSignDoc = {
248
- bodyBytes: signDoc.bodyBytes || new Uint8Array(),
249
- authInfoBytes: signDoc.authInfoBytes || new Uint8Array(),
250
- chainId: signDoc.chainId || chainId,
251
- accountNumber: signDoc.accountNumber ? signDoc.accountNumber.toString() : '0',
252
- };
253
-
254
- const bech32Prefix = this.getBech32Prefix(chainId);
255
-
256
- const walletSigner = new ParaProtoSigner(this.paraWebClient, bech32Prefix, wallets[0].id);
257
-
258
- const result = await walletSigner.signDirect(signer, {
259
- ...convertedSignDoc,
260
- accountNumber: BigInt(convertedSignDoc.accountNumber),
261
- });
262
-
263
- return {
264
- signed: {
265
- bodyBytes: result.signed.bodyBytes,
266
- authInfoBytes: result.signed.authInfoBytes,
267
- chainId: result.signed.chainId,
268
- accountNumber: Long.fromString(result.signed.accountNumber.toString()),
269
- },
270
- signature: result.signature,
271
- };
272
326
  }
273
327
 
274
328
  async signArbitrary(chainId: string, signer: string, data: string | Uint8Array): Promise<StdSignature> {
275
- await this.ensureConnected();
329
+ await this.ensureChainEnabled(chainId);
276
330
 
277
- let encodedData: string;
278
- let isADR36WithString = false;
279
-
280
- if (typeof data === 'string') {
281
- encodedData = Buffer.from(data).toString('base64');
282
- isADR36WithString = true;
283
- } else {
284
- encodedData = Buffer.from(data).toString('base64');
285
- }
331
+ const encodedData =
332
+ typeof data === 'string' ? Buffer.from(data, 'utf-8').toString('base64') : Buffer.from(data).toString('base64');
286
333
 
287
334
  const signDoc = {
288
335
  chain_id: '',
289
336
  account_number: '0',
290
337
  sequence: '0',
291
- fee: {
292
- gas: '0',
293
- amount: [],
294
- },
338
+ fee: { gas: '0', amount: [] },
295
339
  msgs: [
296
340
  {
297
341
  type: 'sign/MsgSignData',
298
- value: {
299
- signer,
300
- data: encodedData,
301
- },
342
+ value: { signer, data: encodedData },
302
343
  },
303
344
  ],
304
345
  memo: '',
305
346
  };
306
347
 
307
- const response = await this.signAmino(chainId, signer, signDoc);
308
-
309
- return response.signature;
310
- }
311
-
312
- async disconnect(): Promise<void> {
313
- await this.paraWebClient.logout();
314
- }
315
-
316
- private async ensureConnected(): Promise<void> {
317
- const isConnected = await this.paraWebClient.isFullyLoggedIn();
318
- if (!isConnected) {
319
- throw new Error('Wallet is not connected, please connect first');
320
- }
321
- }
322
-
323
- private getBech32Prefix(chainId: string): string {
324
- const chainInfo = getChainInfo({ chainId });
325
- if (chainInfo?.bech32Config?.bech32PrefixAccAddr) {
326
- return chainInfo.bech32Config.bech32PrefixAccAddr;
348
+ try {
349
+ const response = await this.signAmino(chainId, signer, signDoc);
350
+ return response.signature;
351
+ } catch (err) {
352
+ throw new Error(`Arbitrary signing failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
327
353
  }
328
-
329
- return 'cosmos';
330
- }
331
- }
332
-
333
- async function getKey(paraWebClient: ParaWeb, chainId: string) {
334
- const wallets = Object.values(paraWebClient.getWalletsByType('COSMOS'));
335
-
336
- if (wallets.length < 1) {
337
- throw Error('No wallets available');
338
- }
339
-
340
- const chainInfo = getChainInfo({ chainId });
341
- const bech32Prefix = chainInfo?.bech32Config?.bech32PrefixAccAddr || 'cosmos';
342
-
343
- const walletSigner = new ParaProtoSigner(paraWebClient, bech32Prefix, wallets[0].id);
344
-
345
- const accountData = (await walletSigner.getAccounts())[0];
346
- if (!accountData) {
347
- throw new Error('No account data found');
348
- }
349
-
350
- return accountData;
351
- }
352
-
353
- async function requestSignature(paraWebClient: ParaWeb, chainId: string, signerAddress: string, signDoc: any) {
354
- const isConnected = await paraWebClient.isFullyLoggedIn();
355
- if (!isConnected) {
356
- throw new Error('Wallet is not connected, please connect first');
357
- }
358
-
359
- const wallets = Object.values(paraWebClient.getWalletsByType('COSMOS'));
360
- if (wallets.length === 0) {
361
- throw new Error('No wallets available');
362
354
  }
363
-
364
- const chainInfo = getChainInfo({ chainId });
365
- const bech32Prefix = chainInfo?.bech32Config?.bech32PrefixAccAddr || 'cosmos';
366
-
367
- const walletSigner = new ParaProtoSigner(paraWebClient, bech32Prefix, wallets[0].id);
368
-
369
- return walletSigner.signDirect(signerAddress, signDoc);
370
355
  }
package/src/index.ts CHANGED
@@ -1,3 +1,2 @@
1
- export { WalletType, AuthLayout, AuthMethod, OAuthMethod, Environment } from '@getpara/react-sdk';
2
- export { ParaGrazConnector } from './connector.js';
1
+ export { toArray, ParaGrazConnector } from './connector.js';
3
2
  export type { ParaGrazConfig } from './connector.js';