cosmos-connect-core 0.1.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.
Files changed (54) hide show
  1. package/dist/adapters/CosmostationWallet.d.ts +40 -0
  2. package/dist/adapters/CosmostationWallet.js +68 -0
  3. package/dist/adapters/GalaxyStationWallet.d.ts +34 -0
  4. package/dist/adapters/GalaxyStationWallet.js +64 -0
  5. package/dist/adapters/KeplrWallet.d.ts +36 -0
  6. package/dist/adapters/KeplrWallet.js +85 -0
  7. package/dist/adapters/LUNCDashWallet.d.ts +6 -0
  8. package/dist/adapters/LUNCDashWallet.js +19 -0
  9. package/dist/adapters/LeapWallet.d.ts +33 -0
  10. package/dist/adapters/LeapWallet.js +64 -0
  11. package/dist/adapters/StationWallet.d.ts +34 -0
  12. package/dist/adapters/StationWallet.js +67 -0
  13. package/dist/adapters/WalletConnectWallet.d.ts +27 -0
  14. package/dist/adapters/WalletConnectWallet.js +89 -0
  15. package/dist/adapters/utils/QRCodeModal.d.ts +20 -0
  16. package/dist/adapters/utils/QRCodeModal.js +50 -0
  17. package/dist/adapters/utils/WalletConnectV2.d.ts +52 -0
  18. package/dist/adapters/utils/WalletConnectV2.js +284 -0
  19. package/dist/adapters/utils/os.d.ts +1 -0
  20. package/dist/adapters/utils/os.js +1 -0
  21. package/dist/core/account.d.ts +1 -0
  22. package/dist/core/account.js +7 -0
  23. package/dist/core/chain.d.ts +4 -0
  24. package/dist/core/chain.js +11 -0
  25. package/dist/core/createClient.d.ts +2 -0
  26. package/dist/core/createClient.js +157 -0
  27. package/dist/core/storage.d.ts +2 -0
  28. package/dist/core/storage.js +18 -0
  29. package/dist/core/types.d.ts +55 -0
  30. package/dist/core/types.js +1 -0
  31. package/dist/core/wallet.d.ts +2 -0
  32. package/dist/core/wallet.js +3 -0
  33. package/dist/index.d.ts +11 -0
  34. package/dist/index.js +11 -0
  35. package/package.json +18 -0
  36. package/src/adapters/CosmostationWallet.ts +113 -0
  37. package/src/adapters/GalaxyStationWallet.ts +100 -0
  38. package/src/adapters/KeplrWallet.ts +126 -0
  39. package/src/adapters/LUNCDashWallet.ts +20 -0
  40. package/src/adapters/LeapWallet.ts +95 -0
  41. package/src/adapters/StationWallet.ts +100 -0
  42. package/src/adapters/WalletConnectWallet.ts +125 -0
  43. package/src/adapters/utils/QRCodeModal.ts +73 -0
  44. package/src/adapters/utils/WalletConnectV2.ts +388 -0
  45. package/src/adapters/utils/os.ts +1 -0
  46. package/src/core/account.ts +7 -0
  47. package/src/core/chain.ts +15 -0
  48. package/src/core/createClient.ts +194 -0
  49. package/src/core/storage.ts +20 -0
  50. package/src/core/types.ts +72 -0
  51. package/src/core/wallet.ts +5 -0
  52. package/src/index.ts +11 -0
  53. package/src/types/modules.d.ts +6 -0
  54. package/tsconfig.json +15 -0
@@ -0,0 +1,125 @@
1
+ import { WalletConnectV2 } from "./utils/WalletConnectV2.js";
2
+ import { WalletAdapter, Chain, Account } from "../core/types.js";
3
+ import { base64 } from "@goblinhunt/cosmes/codec";
4
+ import { MobileAppDetails } from "./utils/QRCodeModal.js";
5
+
6
+ export class WalletConnectWallet implements WalletAdapter {
7
+ id = "walletConnect";
8
+ name = "Other Wallets";
9
+ icon =
10
+ "https://raw.githubusercontent.com/WalletConnect/walletconnect-assets/master/Logo/Blue%20(Default)/Logo.svg";
11
+
12
+ private wc: WalletConnectV2;
13
+ private _uri: string = "";
14
+ private _connecting: boolean = false;
15
+ private _updateCallback?: () => void;
16
+
17
+ constructor({
18
+ projectId,
19
+ id,
20
+ name,
21
+ icon,
22
+ mobileAppDetails,
23
+ }: {
24
+ projectId: string;
25
+ id?: string;
26
+ name?: string;
27
+ icon?: string;
28
+ mobileAppDetails?: MobileAppDetails;
29
+ }) {
30
+ if (id) this.id = id;
31
+ if (name) this.name = name;
32
+ if (icon) this.icon = icon;
33
+
34
+ const details = mobileAppDetails || {
35
+ name: "Cosmos Connect",
36
+ description: "Connect to Cosmos app",
37
+ url: typeof window !== "undefined" ? window.location.origin : "",
38
+ icons: [
39
+ "https://raw.githubusercontent.com/WalletConnect/walletconnect-assets/master/Logo/Blue%20(Default)/Logo.svg",
40
+ ],
41
+ android:
42
+ "intent://wcV2#Intent;package=com.chainapsis.keplr;scheme=keplrwallet;end;", // Default to Keplr for android
43
+ ios: "keplrwallet://wcV2", // Default to Keplr for ios
44
+ };
45
+
46
+ this.wc = new WalletConnectV2(projectId, details);
47
+
48
+ this.wc.onUri((uri: string) => {
49
+ this._uri = uri;
50
+ this._updateCallback?.();
51
+ });
52
+ }
53
+
54
+ installed(): boolean {
55
+ return false;
56
+ }
57
+
58
+ getUri(): string {
59
+ return this._uri;
60
+ }
61
+
62
+ private _connectPromise: Promise<Account> | null = null;
63
+
64
+ async connect(chain: Chain): Promise<Account> {
65
+ if (this._connectPromise) {
66
+ console.log(
67
+ "WalletConnectWallet: connect already in progress, returning existing promise...",
68
+ );
69
+ return this._connectPromise;
70
+ }
71
+
72
+ this._connectPromise = (async () => {
73
+ console.log(
74
+ "WalletConnectWallet: connect called for chain",
75
+ chain.chainId,
76
+ );
77
+ this._connecting = true;
78
+ try {
79
+ // This will trigger our onUri callback
80
+ console.log("WalletConnectWallet: triggering wc.connect...");
81
+ await this.wc.connect([chain.chainId]);
82
+ console.log("WalletConnectWallet: wc.connect settled");
83
+
84
+ // After approval, keys are set
85
+ const accountRes = await this.wc.getAccount(chain.chainId);
86
+
87
+ return {
88
+ address: accountRes.address,
89
+ pubKey: base64.decode(accountRes.pubkey),
90
+ algo: accountRes.algo,
91
+ name: accountRes.name,
92
+ };
93
+ } catch (e) {
94
+ console.error("WalletConnectWallet: Connection failed", e);
95
+ throw e;
96
+ } finally {
97
+ this._connecting = false;
98
+ this._connectPromise = null;
99
+ }
100
+ })();
101
+
102
+ return this._connectPromise;
103
+ }
104
+
105
+ async disconnect(): Promise<void> {
106
+ this.wc.disconnect();
107
+ this._uri = "";
108
+ this._connecting = false;
109
+ }
110
+
111
+ async signTx(_bytes: Uint8Array): Promise<Uint8Array> {
112
+ throw new Error(
113
+ "signTx not implemented directly on adapter. Use client.signAndBroadcast",
114
+ );
115
+ }
116
+
117
+ onUpdate(callback: () => void) {
118
+ this._updateCallback = callback;
119
+ }
120
+
121
+ // Helper for direct access if needed
122
+ get client() {
123
+ return this.wc;
124
+ }
125
+ }
@@ -0,0 +1,73 @@
1
+ import { isAndroid, isMobile } from "./os.js";
2
+
3
+ export type MobileAppDetails = {
4
+ name: string;
5
+ android: string;
6
+ ios: string;
7
+ isStation?: boolean;
8
+ isLuncDash?: boolean;
9
+ description?: string;
10
+ url?: string;
11
+ icons?: string[];
12
+ projectId?: string;
13
+ };
14
+
15
+ export class QRCodeModal {
16
+ private details: MobileAppDetails;
17
+
18
+ // Expose URI for external access (monkey-patch hook)
19
+ // Static or instance property? WalletConnectV2 creates a NEW instance each time.
20
+ // So we need a way to extract it.
21
+ // The official QRCodeModal renders to DOM.
22
+ // The WalletConnectWallet adapter will PATCH the prototype or instance.
23
+
24
+ constructor(details: MobileAppDetails) {
25
+ this.details = details;
26
+ }
27
+
28
+ open(uri: string) {
29
+ console.log("QRCodeModalStub open called with:", uri);
30
+ // Default behavior is to redirect on mobile
31
+ if (isMobile() && typeof window !== "undefined") {
32
+ const schemeUri = this.getSchemeUri(uri);
33
+ if (this.details.isStation) {
34
+ window.location.href = schemeUri;
35
+ } else if (isAndroid()) {
36
+ window.location.href = this.generateAndroidIntent(uri);
37
+ } else {
38
+ window.location.href = this.generateIosIntent(uri);
39
+ }
40
+ }
41
+ }
42
+
43
+ close() {
44
+ console.log("QRCodeModalStub close called");
45
+ }
46
+
47
+ private getSchemeUri(uri: string): string {
48
+ return this.details.isStation
49
+ ? this.details.isLuncDash
50
+ ? `luncdash://wallet_connect?${encodeURIComponent(
51
+ `payload=${encodeURIComponent(uri)}`,
52
+ )}`
53
+ : `https://terrastation.page.link/?link=https://terra.money?${encodeURIComponent(
54
+ `action=wallet_connect&payload=${encodeURIComponent(uri)}`,
55
+ )}&apn=money.terra.station&ibi=money.terra.station&isi=1548434735`
56
+ : uri;
57
+ }
58
+
59
+ private generateAndroidIntent(uri: string): string {
60
+ const hashIndex = this.details.android.indexOf("#");
61
+ if (hashIndex === -1) return this.details.android;
62
+ return (
63
+ this.details.android.slice(0, hashIndex) +
64
+ "?" +
65
+ encodeURIComponent(uri) +
66
+ this.details.android.slice(hashIndex)
67
+ );
68
+ }
69
+
70
+ private generateIosIntent(uri: string): string {
71
+ return this.details.ios + "?" + encodeURIComponent(uri);
72
+ }
73
+ }
@@ -0,0 +1,388 @@
1
+ // @ts-nocheck
2
+ import SignClient from "@walletconnect/sign-client";
3
+ import { isAndroid, isMobile } from "./os.js";
4
+ import { MobileAppDetails } from "./QRCodeModal.js";
5
+ import { debounce } from "lodash-es";
6
+
7
+ // Re-defining internal types as they are not exported
8
+ export type GetAccountResponse = {
9
+ name?: string | undefined;
10
+ address: string;
11
+ algo: string;
12
+ pubkey: string;
13
+ };
14
+
15
+ export type WcSignAminoResponse = {
16
+ signature: {
17
+ signature: string;
18
+ };
19
+ signed?: any | undefined;
20
+ };
21
+
22
+ export type SignAminoResponse = Required<WcSignAminoResponse>;
23
+
24
+ export type WcSignDirectResponse = {
25
+ signature: {
26
+ signature: string;
27
+ };
28
+ signed?: any | undefined;
29
+ };
30
+ export type SignDirectResponse = Required<WcSignDirectResponse>;
31
+
32
+ export type WalletConnectV2Config = {
33
+ disableConnectionCheck?: boolean;
34
+ };
35
+
36
+ const Method = {
37
+ GET_ACCOUNTS: "cosmos_getAccounts",
38
+ SIGN_AMINO: "cosmos_signAmino",
39
+ SIGN_DIRECT: "cosmos_signDirect",
40
+ SIGN_ARBITRARY: "keplr_signArbitrary",
41
+ ADD_CHAIN: "keplr_experimentalSuggestChain",
42
+ } as const;
43
+
44
+ const Event = {
45
+ CHAIN_CHANGED: "chainChanged",
46
+ ACCOUNTS_CHANGED: "accountsChanged",
47
+ } as const;
48
+
49
+ const DEFAULT_SIGN_OPTIONS = {
50
+ preferNoSetFee: true,
51
+ preferNoSetMemo: true,
52
+ };
53
+
54
+ export class WalletConnectV2 {
55
+ private readonly projectId: string;
56
+ private readonly mobileAppDetails: MobileAppDetails;
57
+ private readonly sessionStorageKey: string;
58
+ private readonly accountStorageKey: string;
59
+ private readonly onDisconnectCbs: Set<() => unknown>;
60
+ private readonly onAccountChangeCbs: Set<() => unknown>;
61
+ private readonly onUriCbs: Set<(uri: string) => unknown>;
62
+ private signClient: any | null;
63
+ private config?: WalletConnectV2Config;
64
+
65
+ constructor(
66
+ projectId: string,
67
+ mobileAppDetails: MobileAppDetails,
68
+ config?: WalletConnectV2Config,
69
+ ) {
70
+ this.projectId = projectId;
71
+ this.mobileAppDetails = mobileAppDetails;
72
+ this.sessionStorageKey = `cosmes.wallet.${mobileAppDetails.name.toLowerCase()}.wcSession`;
73
+ this.accountStorageKey = `cosmes.wallet.${mobileAppDetails.name.toLowerCase()}.lastAccount`;
74
+ this.onDisconnectCbs = new Set();
75
+ this.onAccountChangeCbs = new Set();
76
+ this.onUriCbs = new Set();
77
+ this.signClient = null;
78
+ this.config = config;
79
+ }
80
+
81
+ onUri(cb: (uri: string) => unknown): () => void {
82
+ this.onUriCbs.add(cb);
83
+ return () => {
84
+ this.onUriCbs.delete(cb);
85
+ };
86
+ }
87
+
88
+ async addChain(chainId: string, chainInfo: any): Promise<void> {
89
+ if (!this.signClient) {
90
+ throw new Error("SignClient is not initialized");
91
+ }
92
+ await this.request(chainId, Method.ADD_CHAIN, {
93
+ chainInfo,
94
+ });
95
+ }
96
+
97
+ async connect(chainIds: string[]): Promise<void> {
98
+ // Initialise the sign client and event listeners if they don't already exist
99
+ if (!this.signClient) {
100
+ console.log("WalletConnectV2: Initializing SignClient...");
101
+ try {
102
+ this.signClient = await (SignClient as any).init({
103
+ projectId: this.projectId,
104
+ relayUrl: "wss://relay.walletconnect.com",
105
+ metadata: {
106
+ name: this.mobileAppDetails.name,
107
+ description: this.mobileAppDetails.description || "Cosmos App",
108
+ url:
109
+ this.mobileAppDetails.url ||
110
+ (typeof window !== "undefined" ? window.location.origin : ""),
111
+ icons: this.mobileAppDetails.icons || [],
112
+ },
113
+ });
114
+ console.log("WalletConnectV2: SignClient initialized");
115
+ } catch (err) {
116
+ console.error("WalletConnectV2: Failed to initialize SignClient", err);
117
+ throw err;
118
+ }
119
+ // Disconnect if the session is disconnected or expired
120
+ this.signClient.on("session_delete", ({ topic }: { topic: string }) =>
121
+ this._disconnect(topic),
122
+ );
123
+ this.signClient.on("session_expire", ({ topic }: { topic: string }) =>
124
+ this._disconnect(topic),
125
+ );
126
+ // Handle the `accountsChanged` event
127
+ const handleAccountChange = debounce(
128
+ // Handler is debounced as the `accountsChanged` event is fired once for
129
+ // each connected chain, but we only want to trigger the callback once.
130
+ () => this.onAccountChangeCbs.forEach((cb) => cb()),
131
+ 300,
132
+ { leading: true, trailing: false },
133
+ );
134
+ this.signClient.on("session_event", ({ params }: { params: any }) => {
135
+ if (params.event.name === Event.ACCOUNTS_CHANGED) {
136
+ handleAccountChange();
137
+ }
138
+ });
139
+ }
140
+ // Check if a valid session already exists
141
+ const oldSession = localStorage.getItem(this.sessionStorageKey);
142
+ const chainIdsSet = new Set(chainIds);
143
+
144
+ if (oldSession) {
145
+ const { topic, chainIds: storedIds } = JSON.parse(oldSession);
146
+ const storedIdsSet = new Set<string>(storedIds);
147
+ if (chainIds.every((id) => storedIdsSet.has(id))) {
148
+ // Assume we want a fresh session for the UI to show the QR code
149
+ // unless explicitly disabled.
150
+ if (this.config?.disableConnectionCheck) {
151
+ return;
152
+ }
153
+ // Force disconnect old session to ensure a new URI is generated
154
+ this._disconnect(topic);
155
+ } else {
156
+ // Otherwise, we need to merge the stored IDs with the requested IDs
157
+ for (const id of storedIds) {
158
+ chainIdsSet.add(id);
159
+ }
160
+ }
161
+ }
162
+ // Initialise a new session
163
+ const { uri, approval } = await this.signClient!.connect({
164
+ optionalNamespaces: {
165
+ cosmos: {
166
+ chains: [...chainIdsSet].map((id) => this.toCosmosNamespace(id)),
167
+ methods: Object.values(Method),
168
+ events: Object.values(Event),
169
+ },
170
+ },
171
+ });
172
+ if (uri) {
173
+ console.log("WalletConnectV2: URI generated", uri);
174
+ this._uri = uri; // Store it locally too
175
+ this.onUriCbs.forEach((cb) => cb(uri));
176
+ console.log("WalletConnectV2: Waiting for approval...");
177
+ const approvalPromise = approval();
178
+ const timeoutPromise = new Promise((_, reject) =>
179
+ setTimeout(
180
+ () => reject(new Error("Connection approval timed out")),
181
+ 60000,
182
+ ),
183
+ );
184
+
185
+ const { topic } = await (Promise.race([
186
+ approvalPromise,
187
+ timeoutPromise,
188
+ ]) as Promise<{ topic: string }>);
189
+
190
+ console.log("WalletConnectV2: Approved session topic", topic);
191
+ // Save this new session to local storage
192
+ const newSession = {
193
+ topic,
194
+ chainIds: [...chainIdsSet],
195
+ };
196
+ localStorage.setItem(this.sessionStorageKey, JSON.stringify(newSession));
197
+ }
198
+ }
199
+
200
+ disconnect() {
201
+ const session = localStorage.getItem(this.sessionStorageKey);
202
+ if (session) {
203
+ const { topic } = JSON.parse(session);
204
+ this._disconnect(topic);
205
+ }
206
+ }
207
+
208
+ onDisconnect(cb: () => unknown): () => void {
209
+ this.onDisconnectCbs.add(cb);
210
+ return () => {
211
+ this.onDisconnectCbs.delete(cb);
212
+ };
213
+ }
214
+
215
+ onAccountChange(cb: () => unknown): () => void {
216
+ this.onAccountChangeCbs.add(cb);
217
+ return () => {
218
+ this.onAccountChangeCbs.delete(cb);
219
+ };
220
+ }
221
+
222
+ async getAccount(chainId: string): Promise<GetAccountResponse> {
223
+ if (!this.config?.disableConnectionCheck) {
224
+ const res = await this.request(chainId, Method.GET_ACCOUNTS, {});
225
+ // result might be array or single object depending on wallet impl, usually array
226
+ return Array.isArray(res) ? res[0] : res;
227
+ }
228
+ try {
229
+ const timeout = new Promise((_, reject) =>
230
+ setTimeout(() => reject(new Error("Request timed out")), 3000),
231
+ );
232
+ const resArray: any = await Promise.race([
233
+ this.request(chainId, Method.GET_ACCOUNTS, {}),
234
+ timeout,
235
+ ]);
236
+ const res = Array.isArray(resArray) ? resArray[0] : resArray;
237
+ // Store successful response
238
+ this.onDisconnect(() => {
239
+ localStorage.removeItem(this.accountStorageKey);
240
+ });
241
+ localStorage.setItem(this.accountStorageKey, JSON.stringify(res));
242
+ return res;
243
+ } catch (e) {
244
+ // Try to get stored account data
245
+ const stored = localStorage.getItem(this.accountStorageKey);
246
+ if (stored) {
247
+ const account = JSON.parse(stored);
248
+ // Try to refresh in background
249
+ this.request(chainId, Method.GET_ACCOUNTS, {})
250
+ .then((res: any) => {
251
+ const accountData = Array.isArray(res) ? res[0] : res;
252
+ localStorage.setItem(
253
+ this.accountStorageKey,
254
+ JSON.stringify(accountData),
255
+ );
256
+ })
257
+ .catch(() => {});
258
+ this.onDisconnect(() => {
259
+ localStorage.removeItem(this.accountStorageKey);
260
+ });
261
+ return account;
262
+ }
263
+ throw e;
264
+ }
265
+ }
266
+
267
+ async signArbitrary(
268
+ chainId: string,
269
+ signerAddress: string,
270
+ data: string,
271
+ ): Promise<{ signature: string }> {
272
+ return this.request(chainId, Method.SIGN_ARBITRARY, {
273
+ chainId,
274
+ signer: signerAddress,
275
+ type: "string",
276
+ data,
277
+ });
278
+ }
279
+
280
+ async signAmino(
281
+ chainId: string,
282
+ signerAddress: string,
283
+ stdSignDoc: any,
284
+ ): Promise<SignAminoResponse> {
285
+ const { signature, signed } = await this.request(
286
+ chainId,
287
+ Method.SIGN_AMINO,
288
+ {
289
+ signerAddress,
290
+ signDoc: stdSignDoc,
291
+ signOptions: DEFAULT_SIGN_OPTIONS,
292
+ },
293
+ );
294
+ return {
295
+ signature: signature,
296
+ signed: signed ?? stdSignDoc,
297
+ };
298
+ }
299
+
300
+ async signDirect(
301
+ chainId: string,
302
+ signerAddress: string,
303
+ signDoc: any,
304
+ ): Promise<SignDirectResponse> {
305
+ const { signature, signed } = await this.request(
306
+ chainId,
307
+ Method.SIGN_DIRECT,
308
+ {
309
+ signerAddress,
310
+ signDoc,
311
+ signOptions: DEFAULT_SIGN_OPTIONS,
312
+ },
313
+ );
314
+ return {
315
+ signature: signature,
316
+ signed: signed ?? signDoc,
317
+ };
318
+ }
319
+
320
+ private isConnected(
321
+ signClient: any,
322
+ topic: string,
323
+ timeoutSeconds: number,
324
+ ): Promise<boolean> {
325
+ const tryPing = async () =>
326
+ signClient
327
+ .ping({ topic })
328
+ .then(() => true)
329
+ .catch(() => false);
330
+ const waitDisconnect = async () =>
331
+ new Promise<boolean>((resolve) => {
332
+ // @ts-ignore
333
+ signClient.on("session_delete", (res) => {
334
+ if (topic === res.topic) {
335
+ resolve(false);
336
+ }
337
+ });
338
+ // @ts-ignore
339
+ signClient.on("session_expire", (res) => {
340
+ if (topic === res.topic) {
341
+ resolve(false);
342
+ }
343
+ });
344
+ });
345
+ const timeout = async () =>
346
+ new Promise<boolean>((resolve) =>
347
+ setTimeout(() => resolve(false), timeoutSeconds * 1000),
348
+ );
349
+ return Promise.race([tryPing(), waitDisconnect(), timeout()]);
350
+ }
351
+
352
+ private _disconnect(topic: string) {
353
+ const session = localStorage.getItem(this.sessionStorageKey);
354
+ if (!session || session.includes(topic)) {
355
+ localStorage.removeItem(this.sessionStorageKey);
356
+ this.onDisconnectCbs.forEach((cb) => cb());
357
+ }
358
+ }
359
+
360
+ private async request(
361
+ chainId: string,
362
+ method: string,
363
+ params: any,
364
+ ): Promise<any> {
365
+ const session = localStorage.getItem(this.sessionStorageKey);
366
+ if (!session || !this.signClient) {
367
+ throw new Error("Session not found for " + chainId);
368
+ }
369
+ const { topic } = JSON.parse(session);
370
+ if (isMobile() && method !== Method.GET_ACCOUNTS) {
371
+ window.location.href = isAndroid()
372
+ ? this.mobileAppDetails.android
373
+ : this.mobileAppDetails.ios;
374
+ }
375
+ return this.signClient!.request({
376
+ topic,
377
+ chainId: this.toCosmosNamespace(chainId),
378
+ request: {
379
+ method,
380
+ params,
381
+ },
382
+ });
383
+ }
384
+
385
+ private toCosmosNamespace(chainId: string): string {
386
+ return "cosmos:" + chainId;
387
+ }
388
+ }
@@ -0,0 +1 @@
1
+ export { isAndroid, isIOS, isMobile } from "@goblinhunt/cosmes/wallet";
@@ -0,0 +1,7 @@
1
+ // import { Account } from "./types.js";
2
+
3
+ // Currently just a placeholder for potential account-related utilities
4
+ export function formatShortAddress(address: string, prefixLen = 8, suffixLen = 4): string {
5
+ if (!address) return "";
6
+ return `${address.slice(0, prefixLen)}...${address.slice(-suffixLen)}`;
7
+ }
@@ -0,0 +1,15 @@
1
+ import { Chain } from "./types.js";
2
+
3
+ export const TERRA_CLASSIC: Chain = {
4
+ chainId: "columbus-5",
5
+ rpc: "https://rpc-columbus-5.garuda-defi.org/",
6
+ rest: "https://lcd-columbus-5.garuda-defi.org/",
7
+ bech32Prefix: "terra",
8
+ gasPrice: "28.325uluna", // Approximate gas price for LUNC
9
+ };
10
+
11
+ export const DEFAULT_CHAINS: Chain[] = [TERRA_CLASSIC];
12
+
13
+ export function findChain(chains: Chain[], chainId: string): Chain | undefined {
14
+ return chains.find((c) => c.chainId === chainId);
15
+ }