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.
- package/dist/adapters/CosmostationWallet.d.ts +40 -0
- package/dist/adapters/CosmostationWallet.js +68 -0
- package/dist/adapters/GalaxyStationWallet.d.ts +34 -0
- package/dist/adapters/GalaxyStationWallet.js +64 -0
- package/dist/adapters/KeplrWallet.d.ts +36 -0
- package/dist/adapters/KeplrWallet.js +85 -0
- package/dist/adapters/LUNCDashWallet.d.ts +6 -0
- package/dist/adapters/LUNCDashWallet.js +19 -0
- package/dist/adapters/LeapWallet.d.ts +33 -0
- package/dist/adapters/LeapWallet.js +64 -0
- package/dist/adapters/StationWallet.d.ts +34 -0
- package/dist/adapters/StationWallet.js +67 -0
- package/dist/adapters/WalletConnectWallet.d.ts +27 -0
- package/dist/adapters/WalletConnectWallet.js +89 -0
- package/dist/adapters/utils/QRCodeModal.d.ts +20 -0
- package/dist/adapters/utils/QRCodeModal.js +50 -0
- package/dist/adapters/utils/WalletConnectV2.d.ts +52 -0
- package/dist/adapters/utils/WalletConnectV2.js +284 -0
- package/dist/adapters/utils/os.d.ts +1 -0
- package/dist/adapters/utils/os.js +1 -0
- package/dist/core/account.d.ts +1 -0
- package/dist/core/account.js +7 -0
- package/dist/core/chain.d.ts +4 -0
- package/dist/core/chain.js +11 -0
- package/dist/core/createClient.d.ts +2 -0
- package/dist/core/createClient.js +157 -0
- package/dist/core/storage.d.ts +2 -0
- package/dist/core/storage.js +18 -0
- package/dist/core/types.d.ts +55 -0
- package/dist/core/types.js +1 -0
- package/dist/core/wallet.d.ts +2 -0
- package/dist/core/wallet.js +3 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +11 -0
- package/package.json +18 -0
- package/src/adapters/CosmostationWallet.ts +113 -0
- package/src/adapters/GalaxyStationWallet.ts +100 -0
- package/src/adapters/KeplrWallet.ts +126 -0
- package/src/adapters/LUNCDashWallet.ts +20 -0
- package/src/adapters/LeapWallet.ts +95 -0
- package/src/adapters/StationWallet.ts +100 -0
- package/src/adapters/WalletConnectWallet.ts +125 -0
- package/src/adapters/utils/QRCodeModal.ts +73 -0
- package/src/adapters/utils/WalletConnectV2.ts +388 -0
- package/src/adapters/utils/os.ts +1 -0
- package/src/core/account.ts +7 -0
- package/src/core/chain.ts +15 -0
- package/src/core/createClient.ts +194 -0
- package/src/core/storage.ts +20 -0
- package/src/core/types.ts +72 -0
- package/src/core/wallet.ts +5 -0
- package/src/index.ts +11 -0
- package/src/types/modules.d.ts +6 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Chain,
|
|
3
|
+
Client,
|
|
4
|
+
ClientConfig,
|
|
5
|
+
ClientState,
|
|
6
|
+
StorageAdapter,
|
|
7
|
+
WalletAdapter,
|
|
8
|
+
Listener,
|
|
9
|
+
} from "./types.js";
|
|
10
|
+
import { defaultStorage } from "./storage.js";
|
|
11
|
+
|
|
12
|
+
const STORAGE_KEY_CHAIN = "cosmos-connect.chain";
|
|
13
|
+
const STORAGE_KEY_WALLET = "cosmos-connect.wallet";
|
|
14
|
+
|
|
15
|
+
export function createClient(config: ClientConfig): Client {
|
|
16
|
+
const { chains, wallets } = config;
|
|
17
|
+
const storage: StorageAdapter = config.storage || defaultStorage;
|
|
18
|
+
|
|
19
|
+
let state: ClientState = {
|
|
20
|
+
currentChain: null,
|
|
21
|
+
currentWallet: null,
|
|
22
|
+
account: null,
|
|
23
|
+
status: "disconnected",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const listeners = new Set<Listener<ClientState>>();
|
|
27
|
+
|
|
28
|
+
function setState(partial: Partial<ClientState>) {
|
|
29
|
+
state = { ...state, ...partial };
|
|
30
|
+
listeners.forEach((listener) => listener(state));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getChain(chainId: string): Chain | undefined {
|
|
34
|
+
return chains.find((c) => c.chainId === chainId);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getWallet(walletId: string): WalletAdapter | undefined {
|
|
38
|
+
return wallets.find((w) => w.id === walletId);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function connect(walletId: string, chainId: string) {
|
|
42
|
+
try {
|
|
43
|
+
const chain = getChain(chainId);
|
|
44
|
+
if (!chain) throw new Error(`Chain ${chainId} not found`);
|
|
45
|
+
|
|
46
|
+
const wallet = getWallet(walletId);
|
|
47
|
+
if (!wallet) throw new Error(`Wallet ${walletId} not found`);
|
|
48
|
+
|
|
49
|
+
setState({ status: "connecting" });
|
|
50
|
+
|
|
51
|
+
if (!wallet.installed() && !wallet.getUri) {
|
|
52
|
+
throw new Error(`Wallet ${wallet.name} is not installed`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const account = await wallet.connect(chain);
|
|
56
|
+
|
|
57
|
+
setState({
|
|
58
|
+
currentChain: chain,
|
|
59
|
+
currentWallet: wallet,
|
|
60
|
+
account,
|
|
61
|
+
status: "connected",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
storage.setItem(STORAGE_KEY_CHAIN, chainId);
|
|
65
|
+
storage.setItem(STORAGE_KEY_WALLET, walletId);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
setState({ status: "disconnected", account: null });
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function disconnect() {
|
|
73
|
+
if (state.currentWallet) {
|
|
74
|
+
try {
|
|
75
|
+
await state.currentWallet.disconnect();
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.error("Wallet disconnect failed", e);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setState({
|
|
82
|
+
currentChain: null,
|
|
83
|
+
currentWallet: null,
|
|
84
|
+
account: null,
|
|
85
|
+
status: "disconnected",
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
storage.removeItem(STORAGE_KEY_CHAIN);
|
|
89
|
+
storage.removeItem(STORAGE_KEY_WALLET);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function signAndBroadcast(txBytes: Uint8Array): Promise<string> {
|
|
93
|
+
if (!state.currentChain || !state.currentWallet || !state.account) {
|
|
94
|
+
throw new Error("Client not connected");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 1. Sign
|
|
98
|
+
const signedTxBytes = await state.currentWallet.signTx(txBytes);
|
|
99
|
+
|
|
100
|
+
// 2. Broadcast
|
|
101
|
+
const rpc = state.currentChain.rpc;
|
|
102
|
+
return await broadcastTx(rpc, signedTxBytes);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function subscribe(listener: Listener<ClientState>) {
|
|
106
|
+
listeners.add(listener);
|
|
107
|
+
listener(state);
|
|
108
|
+
return () => {
|
|
109
|
+
listeners.delete(listener);
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (storage) {
|
|
114
|
+
const savedChainId = storage.getItem(STORAGE_KEY_CHAIN);
|
|
115
|
+
const savedWalletId = storage.getItem(STORAGE_KEY_WALLET);
|
|
116
|
+
|
|
117
|
+
if (savedChainId && savedWalletId) {
|
|
118
|
+
connect(savedWalletId, savedChainId).catch(console.error);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const client: Client = {
|
|
123
|
+
get state() {
|
|
124
|
+
return state;
|
|
125
|
+
},
|
|
126
|
+
connect,
|
|
127
|
+
disconnect,
|
|
128
|
+
signAndBroadcast,
|
|
129
|
+
subscribe,
|
|
130
|
+
getChain,
|
|
131
|
+
getWallet,
|
|
132
|
+
getWallets: () => wallets,
|
|
133
|
+
getChains: () => chains,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
let updateQueued = false;
|
|
137
|
+
// Subscribe to updates from wallets (e.g. for QR code URIs)
|
|
138
|
+
wallets.forEach((w) => {
|
|
139
|
+
if (w.onUpdate) {
|
|
140
|
+
w.onUpdate(() => {
|
|
141
|
+
if (!updateQueued) {
|
|
142
|
+
updateQueued = true;
|
|
143
|
+
queueMicrotask(() => {
|
|
144
|
+
listeners.forEach((l) => l({ ...state }));
|
|
145
|
+
updateQueued = false;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
return client;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Browser-compatible base64 encoding
|
|
156
|
+
function toBase64(bytes: Uint8Array): string {
|
|
157
|
+
let binary = "";
|
|
158
|
+
const len = bytes.byteLength;
|
|
159
|
+
for (let i = 0; i < len; i++) {
|
|
160
|
+
binary += String.fromCharCode(bytes[i]);
|
|
161
|
+
}
|
|
162
|
+
return btoa(binary);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function broadcastTx(rpc: string, signedTx: Uint8Array): Promise<string> {
|
|
166
|
+
const txBytesBase64 = toBase64(signedTx);
|
|
167
|
+
const body = {
|
|
168
|
+
jsonrpc: "2.0",
|
|
169
|
+
id: "1",
|
|
170
|
+
method: "broadcast_tx_sync",
|
|
171
|
+
params: {
|
|
172
|
+
tx: txBytesBase64,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
if (typeof fetch === "undefined") {
|
|
177
|
+
throw new Error("Fetch is not defined in this environment");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const res = await fetch(rpc, {
|
|
181
|
+
method: "POST",
|
|
182
|
+
body: JSON.stringify(body),
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
if (!res.ok) {
|
|
186
|
+
throw new Error(`RPC request failed with status ${res.status}`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const json = await res.json();
|
|
190
|
+
if (json.error) {
|
|
191
|
+
throw new Error(json.error.message);
|
|
192
|
+
}
|
|
193
|
+
return json.result.hash;
|
|
194
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { StorageAdapter } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export const defaultStorage: StorageAdapter = {
|
|
4
|
+
getItem: (key: string) => {
|
|
5
|
+
if (typeof localStorage !== "undefined") {
|
|
6
|
+
return localStorage.getItem(key);
|
|
7
|
+
}
|
|
8
|
+
return null;
|
|
9
|
+
},
|
|
10
|
+
setItem: (key: string, value: string) => {
|
|
11
|
+
if (typeof localStorage !== "undefined") {
|
|
12
|
+
localStorage.setItem(key, value);
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
removeItem: (key: string) => {
|
|
16
|
+
if (typeof localStorage !== "undefined") {
|
|
17
|
+
localStorage.removeItem(key);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface Chain {
|
|
2
|
+
chainId: string;
|
|
3
|
+
rpc: string;
|
|
4
|
+
rest?: string;
|
|
5
|
+
bech32Prefix: string;
|
|
6
|
+
gasPrice?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Account {
|
|
10
|
+
address: string;
|
|
11
|
+
pubKey: Uint8Array;
|
|
12
|
+
algo?: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
isNanoLedger?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface WalletAdapter {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
icon?: string;
|
|
21
|
+
|
|
22
|
+
installed(): boolean;
|
|
23
|
+
connect(chain: Chain): Promise<Account>;
|
|
24
|
+
disconnect(): Promise<void>;
|
|
25
|
+
|
|
26
|
+
signTx(bytes: Uint8Array): Promise<Uint8Array>;
|
|
27
|
+
signMsg?(msg: string): Promise<Uint8Array>;
|
|
28
|
+
getUri?(): string;
|
|
29
|
+
onUpdate?(callback: () => void): void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type ClientStatus = "disconnected" | "connecting" | "connected";
|
|
33
|
+
|
|
34
|
+
export interface ClientState {
|
|
35
|
+
currentChain: Chain | null;
|
|
36
|
+
currentWallet: WalletAdapter | null;
|
|
37
|
+
account: Account | null;
|
|
38
|
+
status: ClientStatus;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ClientConfig {
|
|
42
|
+
chains: Chain[];
|
|
43
|
+
wallets: WalletAdapter[];
|
|
44
|
+
storage?: StorageAdapter;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface StorageAdapter {
|
|
48
|
+
getItem(key: string): string | null;
|
|
49
|
+
setItem(key: string, value: string): void;
|
|
50
|
+
removeItem(key: string): void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type Listener<T> = (state: T) => void;
|
|
54
|
+
|
|
55
|
+
export interface Client {
|
|
56
|
+
// State
|
|
57
|
+
readonly state: ClientState;
|
|
58
|
+
|
|
59
|
+
// Actions
|
|
60
|
+
connect(walletId: string, chainId: string): Promise<void>;
|
|
61
|
+
disconnect(): Promise<void>;
|
|
62
|
+
signAndBroadcast(txBytes: Uint8Array): Promise<string>;
|
|
63
|
+
|
|
64
|
+
// Events
|
|
65
|
+
subscribe(listener: Listener<ClientState>): () => void;
|
|
66
|
+
|
|
67
|
+
// Getters
|
|
68
|
+
getChain(chainId: string): Chain | undefined;
|
|
69
|
+
getWallet(walletId: string): WalletAdapter | undefined;
|
|
70
|
+
getWallets(): WalletAdapter[];
|
|
71
|
+
getChains(): Chain[];
|
|
72
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from "./core/types.js";
|
|
2
|
+
export * from "./core/createClient.js";
|
|
3
|
+
export * from "./core/chain.js";
|
|
4
|
+
export * from "./core/storage.js";
|
|
5
|
+
export * from "./adapters/KeplrWallet.js";
|
|
6
|
+
export * from "./adapters/GalaxyStationWallet.js";
|
|
7
|
+
export * from "./adapters/LeapWallet.js";
|
|
8
|
+
export * from "./adapters/StationWallet.js";
|
|
9
|
+
export * from "./adapters/CosmostationWallet.js";
|
|
10
|
+
export * from "./adapters/LUNCDashWallet.js";
|
|
11
|
+
export * from "./adapters/WalletConnectWallet.js";
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"lib": ["esnext", "dom"]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"]
|
|
15
|
+
}
|