@shadow-corp/nearconnect 1.0.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 (179) hide show
  1. package/README.md +546 -0
  2. package/build/InjectedWallet.d.ts +22 -0
  3. package/build/InjectedWallet.js +58 -0
  4. package/build/InjectedWallet.js.map +1 -0
  5. package/build/NearConnector.d.ts +151 -0
  6. package/build/NearConnector.js +536 -0
  7. package/build/NearConnector.js.map +1 -0
  8. package/build/ParentFrameWallet.d.ts +22 -0
  9. package/build/ParentFrameWallet.js +66 -0
  10. package/build/ParentFrameWallet.js.map +1 -0
  11. package/build/SandboxedWallet/code.d.ts +7 -0
  12. package/build/SandboxedWallet/code.js +324 -0
  13. package/build/SandboxedWallet/code.js.map +1 -0
  14. package/build/SandboxedWallet/executor.d.ts +23 -0
  15. package/build/SandboxedWallet/executor.js +338 -0
  16. package/build/SandboxedWallet/executor.js.map +1 -0
  17. package/build/SandboxedWallet/iframe.d.ts +18 -0
  18. package/build/SandboxedWallet/iframe.js +78 -0
  19. package/build/SandboxedWallet/iframe.js.map +1 -0
  20. package/build/SandboxedWallet/index.d.ts +24 -0
  21. package/build/SandboxedWallet/index.js +54 -0
  22. package/build/SandboxedWallet/index.js.map +1 -0
  23. package/build/actions/index.d.ts +3 -0
  24. package/build/actions/index.js +105 -0
  25. package/build/actions/index.js.map +1 -0
  26. package/build/actions/types.d.ts +76 -0
  27. package/build/actions/types.js +3 -0
  28. package/build/actions/types.js.map +1 -0
  29. package/build/connection/health.d.ts +213 -0
  30. package/build/connection/health.js +391 -0
  31. package/build/connection/health.js.map +1 -0
  32. package/build/connection/index.d.ts +4 -0
  33. package/build/connection/index.js +48 -0
  34. package/build/connection/index.js.map +1 -0
  35. package/build/connection/reconnect.d.ts +261 -0
  36. package/build/connection/reconnect.js +454 -0
  37. package/build/connection/reconnect.js.map +1 -0
  38. package/build/connection/retry.d.ts +187 -0
  39. package/build/connection/retry.js +427 -0
  40. package/build/connection/retry.js.map +1 -0
  41. package/build/connection/state.d.ts +222 -0
  42. package/build/connection/state.js +431 -0
  43. package/build/connection/state.js.map +1 -0
  44. package/build/errors.d.ts +177 -0
  45. package/build/errors.js +546 -0
  46. package/build/errors.js.map +1 -0
  47. package/build/hardware/errors.d.ts +36 -0
  48. package/build/hardware/errors.js +127 -0
  49. package/build/hardware/errors.js.map +1 -0
  50. package/build/hardware/index.d.ts +7 -0
  51. package/build/hardware/index.js +39 -0
  52. package/build/hardware/index.js.map +1 -0
  53. package/build/hardware/near-app.d.ts +95 -0
  54. package/build/hardware/near-app.js +291 -0
  55. package/build/hardware/near-app.js.map +1 -0
  56. package/build/hardware/transport.d.ts +94 -0
  57. package/build/hardware/transport.js +267 -0
  58. package/build/hardware/transport.js.map +1 -0
  59. package/build/hardware/types.d.ts +98 -0
  60. package/build/hardware/types.js +72 -0
  61. package/build/hardware/types.js.map +1 -0
  62. package/build/helpers/analytics.d.ts +191 -0
  63. package/build/helpers/analytics.js +304 -0
  64. package/build/helpers/analytics.js.map +1 -0
  65. package/build/helpers/base58.d.ts +6 -0
  66. package/build/helpers/base58.js +47 -0
  67. package/build/helpers/base58.js.map +1 -0
  68. package/build/helpers/events.d.ts +42 -0
  69. package/build/helpers/events.js +68 -0
  70. package/build/helpers/events.js.map +1 -0
  71. package/build/helpers/html.d.ts +8 -0
  72. package/build/helpers/html.js +30 -0
  73. package/build/helpers/html.js.map +1 -0
  74. package/build/helpers/indexdb.d.ts +14 -0
  75. package/build/helpers/indexdb.js +166 -0
  76. package/build/helpers/indexdb.js.map +1 -0
  77. package/build/helpers/manifest.d.ts +147 -0
  78. package/build/helpers/manifest.js +329 -0
  79. package/build/helpers/manifest.js.map +1 -0
  80. package/build/helpers/queue.d.ts +11 -0
  81. package/build/helpers/queue.js +48 -0
  82. package/build/helpers/queue.js.map +1 -0
  83. package/build/helpers/session.d.ts +119 -0
  84. package/build/helpers/session.js +289 -0
  85. package/build/helpers/session.js.map +1 -0
  86. package/build/helpers/simulation.d.ts +128 -0
  87. package/build/helpers/simulation.js +441 -0
  88. package/build/helpers/simulation.js.map +1 -0
  89. package/build/helpers/storage.d.ts +58 -0
  90. package/build/helpers/storage.js +190 -0
  91. package/build/helpers/storage.js.map +1 -0
  92. package/build/helpers/trust.d.ts +157 -0
  93. package/build/helpers/trust.js +340 -0
  94. package/build/helpers/trust.js.map +1 -0
  95. package/build/helpers/url.d.ts +1 -0
  96. package/build/helpers/url.js +13 -0
  97. package/build/helpers/url.js.map +1 -0
  98. package/build/helpers/uuid.d.ts +1 -0
  99. package/build/helpers/uuid.js +14 -0
  100. package/build/helpers/uuid.js.map +1 -0
  101. package/build/index.d.ts +21 -0
  102. package/build/index.js +167 -0
  103. package/build/index.js.map +1 -0
  104. package/build/popups/IframeWalletPopup.d.ts +16 -0
  105. package/build/popups/IframeWalletPopup.js +38 -0
  106. package/build/popups/IframeWalletPopup.js.map +1 -0
  107. package/build/popups/NearWalletsPopup.d.ts +25 -0
  108. package/build/popups/NearWalletsPopup.js +153 -0
  109. package/build/popups/NearWalletsPopup.js.map +1 -0
  110. package/build/popups/Popup.d.ts +22 -0
  111. package/build/popups/Popup.js +94 -0
  112. package/build/popups/Popup.js.map +1 -0
  113. package/build/popups/styles.d.ts +1 -0
  114. package/build/popups/styles.js +257 -0
  115. package/build/popups/styles.js.map +1 -0
  116. package/build/security/audit-log.d.ts +123 -0
  117. package/build/security/audit-log.js +268 -0
  118. package/build/security/audit-log.js.map +1 -0
  119. package/build/security/csp.d.ts +68 -0
  120. package/build/security/csp.js +328 -0
  121. package/build/security/csp.js.map +1 -0
  122. package/build/security/index.d.ts +10 -0
  123. package/build/security/index.js +42 -0
  124. package/build/security/index.js.map +1 -0
  125. package/build/security/origin-guard.d.ts +90 -0
  126. package/build/security/origin-guard.js +244 -0
  127. package/build/security/origin-guard.js.map +1 -0
  128. package/build/security/rate-limiter.d.ts +84 -0
  129. package/build/security/rate-limiter.js +212 -0
  130. package/build/security/rate-limiter.js.map +1 -0
  131. package/build/security/secure-storage.d.ts +77 -0
  132. package/build/security/secure-storage.js +242 -0
  133. package/build/security/secure-storage.js.map +1 -0
  134. package/build/security/transaction-guard.d.ts +71 -0
  135. package/build/security/transaction-guard.js +239 -0
  136. package/build/security/transaction-guard.js.map +1 -0
  137. package/build/types.d.ts +508 -0
  138. package/build/types.js +3 -0
  139. package/build/types.js.map +1 -0
  140. package/build/ui/AccountSwitcherModal.d.ts +53 -0
  141. package/build/ui/AccountSwitcherModal.js +239 -0
  142. package/build/ui/AccountSwitcherModal.js.map +1 -0
  143. package/build/ui/Modal.d.ts +84 -0
  144. package/build/ui/Modal.js +278 -0
  145. package/build/ui/Modal.js.map +1 -0
  146. package/build/ui/TransactionModal.d.ts +84 -0
  147. package/build/ui/TransactionModal.js +406 -0
  148. package/build/ui/TransactionModal.js.map +1 -0
  149. package/build/ui/WalletSelectorModal.d.ts +97 -0
  150. package/build/ui/WalletSelectorModal.js +481 -0
  151. package/build/ui/WalletSelectorModal.js.map +1 -0
  152. package/build/ui/icons.d.ts +19 -0
  153. package/build/ui/icons.js +65 -0
  154. package/build/ui/icons.js.map +1 -0
  155. package/build/ui/index.d.ts +10 -0
  156. package/build/ui/index.js +31 -0
  157. package/build/ui/index.js.map +1 -0
  158. package/build/ui/styles.d.ts +5 -0
  159. package/build/ui/styles.js +973 -0
  160. package/build/ui/styles.js.map +1 -0
  161. package/build/ui/theme.d.ts +133 -0
  162. package/build/ui/theme.js +204 -0
  163. package/build/ui/theme.js.map +1 -0
  164. package/build/wallets/external/index.d.ts +4 -0
  165. package/build/wallets/external/index.js +9 -0
  166. package/build/wallets/external/index.js.map +1 -0
  167. package/build/wallets/external/manager.d.ts +152 -0
  168. package/build/wallets/external/manager.js +586 -0
  169. package/build/wallets/external/manager.js.map +1 -0
  170. package/build/wallets/privileged/index.d.ts +5 -0
  171. package/build/wallets/privileged/index.js +12 -0
  172. package/build/wallets/privileged/index.js.map +1 -0
  173. package/build/wallets/privileged/ledger.d.ts +132 -0
  174. package/build/wallets/privileged/ledger.js +563 -0
  175. package/build/wallets/privileged/ledger.js.map +1 -0
  176. package/build/wallets/privileged/manager.d.ts +54 -0
  177. package/build/wallets/privileged/manager.js +174 -0
  178. package/build/wallets/privileged/manager.js.map +1 -0
  179. package/package.json +33 -0
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Ledger Wallet Implementation
3
+ *
4
+ * Privileged wallet that runs in main thread with WebHID access
5
+ */
6
+ import { type LedgerConfig, type LedgerDeviceInfo, type HardwareWaitingEvent, type HardwareConfirmEvent, type HardwareRejectedEvent } from '../../hardware/types';
7
+ import type { Network, Transaction } from '../../types';
8
+ export interface LedgerWalletAccount {
9
+ accountId: string;
10
+ publicKey?: string;
11
+ }
12
+ export interface LedgerTransactionResult {
13
+ transaction: {
14
+ hash: string;
15
+ signerId: string;
16
+ receiverId: string;
17
+ };
18
+ transaction_outcome: {
19
+ id: string;
20
+ outcome: {
21
+ status: unknown;
22
+ logs: string[];
23
+ gas_burnt: number;
24
+ };
25
+ };
26
+ receipts_outcome: Array<{
27
+ id: string;
28
+ outcome: {
29
+ status: unknown;
30
+ logs: string[];
31
+ };
32
+ }>;
33
+ status: {
34
+ SuccessValue?: string;
35
+ Failure?: unknown;
36
+ };
37
+ }
38
+ export interface LedgerSignedTransaction {
39
+ hash: string;
40
+ signedTransaction: Uint8Array;
41
+ }
42
+ export interface LedgerSignMessageParams {
43
+ message: string;
44
+ recipient: string;
45
+ nonce: Uint8Array;
46
+ callbackUrl?: string;
47
+ }
48
+ export interface LedgerSignedMessage {
49
+ accountId: string;
50
+ publicKey: string;
51
+ signature: string;
52
+ message: string;
53
+ }
54
+ type EventCallback<T> = (data: T) => void;
55
+ type EventUnsubscribe = () => void;
56
+ export declare class LedgerWallet {
57
+ readonly id = "ledger";
58
+ readonly type: "privileged";
59
+ private app;
60
+ private accounts;
61
+ private derivationPath;
62
+ private networkId;
63
+ private rpcUrl;
64
+ private listeners;
65
+ constructor(config: {
66
+ network: Network;
67
+ ledger?: LedgerConfig | boolean;
68
+ rpcUrl?: string;
69
+ });
70
+ static isSupported(): boolean;
71
+ static getManifest(): {
72
+ id: string;
73
+ version: string;
74
+ name: string;
75
+ description: string;
76
+ iconUrl: string;
77
+ website: string;
78
+ type: "privileged";
79
+ hardwareType: "ledger";
80
+ features: {
81
+ signMessage: boolean;
82
+ signTransaction: boolean;
83
+ signAndSendTransaction: boolean;
84
+ signAndSendTransactions: boolean;
85
+ };
86
+ };
87
+ onWaiting(callback: EventCallback<HardwareWaitingEvent>): EventUnsubscribe;
88
+ onConfirm(callback: EventCallback<HardwareConfirmEvent>): EventUnsubscribe;
89
+ onRejected(callback: EventCallback<HardwareRejectedEvent>): EventUnsubscribe;
90
+ onConnected(callback: EventCallback<{
91
+ device: LedgerDeviceInfo;
92
+ }>): EventUnsubscribe;
93
+ onDisconnected(callback: EventCallback<void>): EventUnsubscribe;
94
+ private emitWaiting;
95
+ private emitConfirm;
96
+ private emitRejected;
97
+ private emitConnected;
98
+ private emitDisconnected;
99
+ isConnected(): boolean;
100
+ getAccounts(): Promise<LedgerWalletAccount[]>;
101
+ signIn(): Promise<LedgerWalletAccount[]>;
102
+ signOut(): Promise<void>;
103
+ private disconnect;
104
+ signTransaction(tx: Transaction): Promise<LedgerSignedTransaction>;
105
+ signAndSendTransaction(tx: Transaction): Promise<LedgerTransactionResult>;
106
+ signAndSendTransactions(txs: Transaction[]): Promise<LedgerTransactionResult[]>;
107
+ signMessage(params: LedgerSignMessageParams): Promise<LedgerSignedMessage>;
108
+ private getDefaultRpcUrl;
109
+ private publicKeyToImplicitAccountId;
110
+ private serializeTransaction;
111
+ private borshSerializeTransaction;
112
+ private borshString;
113
+ private uint64LE;
114
+ private borshActions;
115
+ private borshAction;
116
+ private createSignedTransaction;
117
+ private computeTransactionHash;
118
+ private broadcastTransaction;
119
+ private getAccessKey;
120
+ private getRecentBlockHash;
121
+ private writeUint32LE;
122
+ private bytesToHex;
123
+ private bytesToBase64;
124
+ private bytesToBase58;
125
+ private base58ToBytes;
126
+ }
127
+ export declare function createLedgerWallet(config: {
128
+ network: Network;
129
+ ledger?: LedgerConfig | boolean;
130
+ rpcUrl?: string;
131
+ }): LedgerWallet;
132
+ export {};
@@ -0,0 +1,563 @@
1
+ "use strict";
2
+ /**
3
+ * Ledger Wallet Implementation
4
+ *
5
+ * Privileged wallet that runs in main thread with WebHID access
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.LedgerWallet = void 0;
9
+ exports.createLedgerWallet = createLedgerWallet;
10
+ const near_app_1 = require("../../hardware/near-app");
11
+ const types_1 = require("../../hardware/types");
12
+ const errors_1 = require("../../hardware/errors");
13
+ // =============================================================================
14
+ // Ledger Wallet
15
+ // =============================================================================
16
+ class LedgerWallet {
17
+ id = 'ledger';
18
+ type = 'privileged';
19
+ app = null;
20
+ accounts = [];
21
+ derivationPath;
22
+ networkId;
23
+ rpcUrl;
24
+ // Event listeners
25
+ listeners = {
26
+ waiting: new Set(),
27
+ confirm: new Set(),
28
+ rejected: new Set(),
29
+ connected: new Set(),
30
+ disconnected: new Set(),
31
+ };
32
+ constructor(config) {
33
+ this.networkId = config.network;
34
+ this.rpcUrl = config.rpcUrl || this.getDefaultRpcUrl(config.network);
35
+ // Parse config
36
+ const ledgerConfig = typeof config.ledger === 'boolean'
37
+ ? { enabled: config.ledger }
38
+ : config.ledger;
39
+ this.derivationPath = ledgerConfig?.derivationPath || types_1.DEFAULT_DERIVATION_PATH;
40
+ }
41
+ // ===========================================================================
42
+ // Static Methods
43
+ // ===========================================================================
44
+ static isSupported() {
45
+ return near_app_1.LedgerNearApp.isSupported();
46
+ }
47
+ static getManifest() {
48
+ return {
49
+ id: 'ledger',
50
+ version: '1.0.0',
51
+ name: 'Ledger',
52
+ description: 'Connect your Ledger hardware wallet',
53
+ iconUrl: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMjgiIGhlaWdodD0iMTI4IiByeD0iMjQiIGZpbGw9ImJsYWNrIi8+CjxwYXRoIGQ9Ik0zOC40IDc5LjJWODkuNkg3OS4yVjc5LjJIMzguNFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0zOC40IDM4LjRWNjguOEg0OC44VjQ4LjhINjguOFYzOC40SDM4LjRaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNNzkuMiAzOC40Vjc5LjJIODkuNlYzOC40SDc5LjJaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K',
54
+ website: 'https://ledger.com',
55
+ type: 'privileged',
56
+ hardwareType: 'ledger',
57
+ features: {
58
+ signMessage: true,
59
+ signTransaction: true,
60
+ signAndSendTransaction: true,
61
+ signAndSendTransactions: true,
62
+ },
63
+ };
64
+ }
65
+ // ===========================================================================
66
+ // Event Methods
67
+ // ===========================================================================
68
+ onWaiting(callback) {
69
+ this.listeners.waiting.add(callback);
70
+ return () => this.listeners.waiting.delete(callback);
71
+ }
72
+ onConfirm(callback) {
73
+ this.listeners.confirm.add(callback);
74
+ return () => this.listeners.confirm.delete(callback);
75
+ }
76
+ onRejected(callback) {
77
+ this.listeners.rejected.add(callback);
78
+ return () => this.listeners.rejected.delete(callback);
79
+ }
80
+ onConnected(callback) {
81
+ this.listeners.connected.add(callback);
82
+ return () => this.listeners.connected.delete(callback);
83
+ }
84
+ onDisconnected(callback) {
85
+ this.listeners.disconnected.add(callback);
86
+ return () => this.listeners.disconnected.delete(callback);
87
+ }
88
+ emitWaiting(data) {
89
+ this.listeners.waiting.forEach((cb) => { try {
90
+ cb(data);
91
+ }
92
+ catch (e) {
93
+ console.error('Error in waiting listener:', e);
94
+ } });
95
+ }
96
+ emitConfirm(data) {
97
+ this.listeners.confirm.forEach((cb) => { try {
98
+ cb(data);
99
+ }
100
+ catch (e) {
101
+ console.error('Error in confirm listener:', e);
102
+ } });
103
+ }
104
+ emitRejected(data) {
105
+ this.listeners.rejected.forEach((cb) => { try {
106
+ cb(data);
107
+ }
108
+ catch (e) {
109
+ console.error('Error in rejected listener:', e);
110
+ } });
111
+ }
112
+ emitConnected(data) {
113
+ this.listeners.connected.forEach((cb) => { try {
114
+ cb(data);
115
+ }
116
+ catch (e) {
117
+ console.error('Error in connected listener:', e);
118
+ } });
119
+ }
120
+ emitDisconnected() {
121
+ this.listeners.disconnected.forEach((cb) => { try {
122
+ cb();
123
+ }
124
+ catch (e) {
125
+ console.error('Error in disconnected listener:', e);
126
+ } });
127
+ }
128
+ // ===========================================================================
129
+ // Connection Methods
130
+ // ===========================================================================
131
+ isConnected() {
132
+ return this.app !== null && this.app.isConnected() && this.accounts.length > 0;
133
+ }
134
+ async getAccounts() {
135
+ return this.accounts;
136
+ }
137
+ async signIn() {
138
+ this.emitWaiting({
139
+ walletId: this.id,
140
+ action: 'connect',
141
+ message: 'Please connect and unlock your Ledger device, then open the NEAR app',
142
+ });
143
+ try {
144
+ this.app = await near_app_1.LedgerNearApp.connect();
145
+ const deviceInfo = await this.app.getDeviceInfo();
146
+ this.emitConfirm({ walletId: this.id, action: 'connect' });
147
+ this.emitConnected({ device: deviceInfo });
148
+ this.emitWaiting({
149
+ walletId: this.id,
150
+ action: 'get_public_key',
151
+ message: 'Please verify your address on the Ledger device',
152
+ });
153
+ const { address } = await this.app.getPublicKey(this.derivationPath, true);
154
+ this.emitConfirm({ walletId: this.id, action: 'get_public_key' });
155
+ // Derive account ID from public key (implicit account)
156
+ const accountId = this.publicKeyToImplicitAccountId(address);
157
+ this.accounts = [{
158
+ accountId,
159
+ publicKey: address,
160
+ }];
161
+ return this.accounts;
162
+ }
163
+ catch (error) {
164
+ this.emitRejected({
165
+ walletId: this.id,
166
+ action: 'connect',
167
+ reason: error instanceof Error ? error.message : 'Connection failed',
168
+ });
169
+ await this.disconnect();
170
+ throw error;
171
+ }
172
+ }
173
+ async signOut() {
174
+ await this.disconnect();
175
+ }
176
+ async disconnect() {
177
+ if (this.app) {
178
+ await this.app.disconnect();
179
+ this.app = null;
180
+ }
181
+ this.accounts = [];
182
+ this.emitDisconnected();
183
+ }
184
+ // ===========================================================================
185
+ // Transaction Methods
186
+ // ===========================================================================
187
+ async signTransaction(tx) {
188
+ if (!this.app || !this.isConnected()) {
189
+ throw (0, errors_1.createHardwareError)(types_1.HardwareErrorCode.DEVICE_NOT_FOUND, 'Ledger not connected');
190
+ }
191
+ const account = this.accounts[0];
192
+ if (!account) {
193
+ throw (0, errors_1.createHardwareError)(types_1.HardwareErrorCode.DEVICE_NOT_FOUND, 'No account connected');
194
+ }
195
+ this.emitWaiting({
196
+ walletId: this.id,
197
+ action: 'sign',
198
+ message: 'Please review and approve the transaction on your Ledger',
199
+ });
200
+ try {
201
+ const signerId = tx.signerId || account.accountId;
202
+ const txBytes = await this.serializeTransaction({
203
+ ...tx,
204
+ signerId,
205
+ });
206
+ const { signature } = await this.app.signTransaction(this.derivationPath, txBytes);
207
+ this.emitConfirm({ walletId: this.id, action: 'sign' });
208
+ const signedTx = this.createSignedTransaction(txBytes, signature);
209
+ return {
210
+ hash: await this.computeTransactionHash(txBytes),
211
+ signedTransaction: signedTx,
212
+ };
213
+ }
214
+ catch (error) {
215
+ const isRejection = (0, errors_1.isHardwareError)(error) && error.code === types_1.HardwareErrorCode.USER_REJECTED;
216
+ this.emitRejected({
217
+ walletId: this.id,
218
+ action: 'sign',
219
+ reason: isRejection ? 'User rejected on device' :
220
+ (error instanceof Error ? error.message : 'Signing failed'),
221
+ });
222
+ throw error;
223
+ }
224
+ }
225
+ async signAndSendTransaction(tx) {
226
+ const signed = await this.signTransaction(tx);
227
+ return this.broadcastTransaction(signed.signedTransaction);
228
+ }
229
+ async signAndSendTransactions(txs) {
230
+ const results = [];
231
+ for (const tx of txs) {
232
+ const result = await this.signAndSendTransaction(tx);
233
+ results.push(result);
234
+ }
235
+ return results;
236
+ }
237
+ // ===========================================================================
238
+ // Message Signing (NEP-413)
239
+ // ===========================================================================
240
+ async signMessage(params) {
241
+ if (!this.app || !this.isConnected()) {
242
+ throw (0, errors_1.createHardwareError)(types_1.HardwareErrorCode.DEVICE_NOT_FOUND, 'Ledger not connected');
243
+ }
244
+ const account = this.accounts[0];
245
+ if (!account) {
246
+ throw (0, errors_1.createHardwareError)(types_1.HardwareErrorCode.DEVICE_NOT_FOUND, 'No account connected');
247
+ }
248
+ this.emitWaiting({
249
+ walletId: this.id,
250
+ action: 'sign_message',
251
+ message: 'Please review and approve the message on your Ledger',
252
+ });
253
+ try {
254
+ const { signature } = await this.app.signMessage(this.derivationPath, params.message, params.nonce, params.recipient, params.callbackUrl);
255
+ this.emitConfirm({ walletId: this.id, action: 'sign_message' });
256
+ return {
257
+ accountId: account.accountId,
258
+ publicKey: account.publicKey,
259
+ signature: this.bytesToBase64(signature),
260
+ message: params.message,
261
+ };
262
+ }
263
+ catch (error) {
264
+ const isRejection = (0, errors_1.isHardwareError)(error) && error.code === types_1.HardwareErrorCode.USER_REJECTED;
265
+ this.emitRejected({
266
+ walletId: this.id,
267
+ action: 'sign_message',
268
+ reason: isRejection ? 'User rejected on device' :
269
+ (error instanceof Error ? error.message : 'Signing failed'),
270
+ });
271
+ throw error;
272
+ }
273
+ }
274
+ // ===========================================================================
275
+ // Helper Methods
276
+ // ===========================================================================
277
+ getDefaultRpcUrl(network) {
278
+ return network === 'mainnet'
279
+ ? 'https://rpc.mainnet.near.org'
280
+ : 'https://rpc.testnet.near.org';
281
+ }
282
+ publicKeyToImplicitAccountId(publicKey) {
283
+ const key = publicKey.replace('ed25519:', '');
284
+ const bytes = this.base58ToBytes(key);
285
+ return this.bytesToHex(bytes);
286
+ }
287
+ async serializeTransaction(tx) {
288
+ const accessKey = await this.getAccessKey(tx.signerId, this.accounts[0].publicKey);
289
+ const nonce = accessKey.nonce + 1;
290
+ const blockHash = await this.getRecentBlockHash();
291
+ const txData = {
292
+ signerId: tx.signerId,
293
+ publicKey: this.accounts[0].publicKey,
294
+ nonce,
295
+ receiverId: tx.receiverId,
296
+ blockHash,
297
+ actions: tx.actions,
298
+ };
299
+ return this.borshSerializeTransaction(txData);
300
+ }
301
+ borshSerializeTransaction(tx) {
302
+ const chunks = [];
303
+ // Signer ID
304
+ chunks.push(this.borshString(tx.signerId));
305
+ // Public key (enum + 32 bytes)
306
+ const pubKeyBytes = this.base58ToBytes(tx.publicKey.replace('ed25519:', ''));
307
+ const pubKey = new Uint8Array(33);
308
+ pubKey[0] = 0; // ED25519 = 0
309
+ pubKey.set(pubKeyBytes, 1);
310
+ chunks.push(pubKey);
311
+ // Nonce (u64 LE)
312
+ chunks.push(this.uint64LE(tx.nonce));
313
+ // Receiver ID
314
+ chunks.push(this.borshString(tx.receiverId));
315
+ // Block hash (32 bytes)
316
+ chunks.push(tx.blockHash);
317
+ // Actions
318
+ chunks.push(this.borshActions(tx.actions));
319
+ // Concatenate
320
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
321
+ const result = new Uint8Array(totalLength);
322
+ let offset = 0;
323
+ for (const chunk of chunks) {
324
+ result.set(chunk, offset);
325
+ offset += chunk.length;
326
+ }
327
+ return result;
328
+ }
329
+ borshString(str) {
330
+ const bytes = new TextEncoder().encode(str);
331
+ const result = new Uint8Array(4 + bytes.length);
332
+ this.writeUint32LE(result, 0, bytes.length);
333
+ result.set(bytes, 4);
334
+ return result;
335
+ }
336
+ uint64LE(value) {
337
+ const result = new Uint8Array(8);
338
+ let v = BigInt(value);
339
+ for (let i = 0; i < 8; i++) {
340
+ result[i] = Number(v & BigInt(0xff));
341
+ v >>= BigInt(8);
342
+ }
343
+ return result;
344
+ }
345
+ borshActions(actions) {
346
+ const chunks = [];
347
+ const length = new Uint8Array(4);
348
+ this.writeUint32LE(length, 0, actions.length);
349
+ chunks.push(length);
350
+ for (const action of actions) {
351
+ chunks.push(this.borshAction(action));
352
+ }
353
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
354
+ const result = new Uint8Array(totalLength);
355
+ let offset = 0;
356
+ for (const chunk of chunks) {
357
+ result.set(chunk, offset);
358
+ offset += chunk.length;
359
+ }
360
+ return result;
361
+ }
362
+ borshAction(action) {
363
+ const actionObj = action;
364
+ const actionType = Object.keys(actionObj)[0];
365
+ const actionData = actionObj[actionType];
366
+ const actionTypes = {
367
+ CreateAccount: 0,
368
+ DeployContract: 1,
369
+ FunctionCall: 2,
370
+ Transfer: 3,
371
+ Stake: 4,
372
+ AddKey: 5,
373
+ DeleteKey: 6,
374
+ DeleteAccount: 7,
375
+ };
376
+ const typeIndex = actionTypes[actionType];
377
+ if (typeIndex === undefined) {
378
+ throw new Error(`Unknown action type: ${actionType}`);
379
+ }
380
+ const chunks = [];
381
+ chunks.push(new Uint8Array([typeIndex]));
382
+ switch (actionType) {
383
+ case 'Transfer': {
384
+ const data = actionData;
385
+ const deposit = BigInt(data.deposit || '0');
386
+ const depositBytes = new Uint8Array(16);
387
+ let d = deposit;
388
+ for (let i = 0; i < 16; i++) {
389
+ depositBytes[i] = Number(d & BigInt(0xff));
390
+ d >>= BigInt(8);
391
+ }
392
+ chunks.push(depositBytes);
393
+ break;
394
+ }
395
+ case 'FunctionCall': {
396
+ const data = actionData;
397
+ chunks.push(this.borshString(data.methodName));
398
+ const argsJson = JSON.stringify(data.args);
399
+ const argsBytes = new TextEncoder().encode(argsJson);
400
+ const argsLength = new Uint8Array(4);
401
+ this.writeUint32LE(argsLength, 0, argsBytes.length);
402
+ chunks.push(argsLength);
403
+ chunks.push(argsBytes);
404
+ chunks.push(this.uint64LE(Number(data.gas)));
405
+ const deposit = BigInt(data.deposit || '0');
406
+ const depositBytes = new Uint8Array(16);
407
+ let d = deposit;
408
+ for (let i = 0; i < 16; i++) {
409
+ depositBytes[i] = Number(d & BigInt(0xff));
410
+ d >>= BigInt(8);
411
+ }
412
+ chunks.push(depositBytes);
413
+ break;
414
+ }
415
+ }
416
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
417
+ const result = new Uint8Array(totalLength);
418
+ let offset = 0;
419
+ for (const chunk of chunks) {
420
+ result.set(chunk, offset);
421
+ offset += chunk.length;
422
+ }
423
+ return result;
424
+ }
425
+ createSignedTransaction(txBytes, signature) {
426
+ const sigStruct = new Uint8Array(65);
427
+ sigStruct[0] = 0; // ED25519 = 0
428
+ sigStruct.set(signature, 1);
429
+ const result = new Uint8Array(txBytes.length + sigStruct.length);
430
+ result.set(txBytes, 0);
431
+ result.set(sigStruct, txBytes.length);
432
+ return result;
433
+ }
434
+ async computeTransactionHash(txBytes) {
435
+ const hashBuffer = await crypto.subtle.digest('SHA-256', txBytes);
436
+ return this.bytesToBase58(new Uint8Array(hashBuffer));
437
+ }
438
+ async broadcastTransaction(signedTx) {
439
+ const response = await fetch(this.rpcUrl, {
440
+ method: 'POST',
441
+ headers: { 'Content-Type': 'application/json' },
442
+ body: JSON.stringify({
443
+ jsonrpc: '2.0',
444
+ id: 'dontcare',
445
+ method: 'broadcast_tx_commit',
446
+ params: [this.bytesToBase64(signedTx)],
447
+ }),
448
+ });
449
+ const result = await response.json();
450
+ if (result.error) {
451
+ throw new Error(result.error.message || 'Transaction broadcast failed');
452
+ }
453
+ return result.result;
454
+ }
455
+ async getAccessKey(accountId, publicKey) {
456
+ const response = await fetch(this.rpcUrl, {
457
+ method: 'POST',
458
+ headers: { 'Content-Type': 'application/json' },
459
+ body: JSON.stringify({
460
+ jsonrpc: '2.0',
461
+ id: 'dontcare',
462
+ method: 'query',
463
+ params: {
464
+ request_type: 'view_access_key',
465
+ finality: 'final',
466
+ account_id: accountId,
467
+ public_key: publicKey,
468
+ },
469
+ }),
470
+ });
471
+ const result = await response.json();
472
+ if (result.error) {
473
+ throw new Error(result.error.message || 'Failed to get access key');
474
+ }
475
+ return result.result;
476
+ }
477
+ async getRecentBlockHash() {
478
+ const response = await fetch(this.rpcUrl, {
479
+ method: 'POST',
480
+ headers: { 'Content-Type': 'application/json' },
481
+ body: JSON.stringify({
482
+ jsonrpc: '2.0',
483
+ id: 'dontcare',
484
+ method: 'block',
485
+ params: { finality: 'final' },
486
+ }),
487
+ });
488
+ const result = await response.json();
489
+ if (result.error) {
490
+ throw new Error(result.error.message || 'Failed to get block');
491
+ }
492
+ const hashBase58 = result.result.header.hash;
493
+ return this.base58ToBytes(hashBase58);
494
+ }
495
+ // ===========================================================================
496
+ // Encoding Utilities
497
+ // ===========================================================================
498
+ writeUint32LE(buffer, offset, value) {
499
+ buffer[offset] = value & 0xff;
500
+ buffer[offset + 1] = (value >> 8) & 0xff;
501
+ buffer[offset + 2] = (value >> 16) & 0xff;
502
+ buffer[offset + 3] = (value >> 24) & 0xff;
503
+ }
504
+ bytesToHex(bytes) {
505
+ return Array.from(bytes)
506
+ .map(b => b.toString(16).padStart(2, '0'))
507
+ .join('');
508
+ }
509
+ bytesToBase64(bytes) {
510
+ return btoa(String.fromCharCode(...bytes));
511
+ }
512
+ bytesToBase58(bytes) {
513
+ const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
514
+ let num = BigInt(0);
515
+ for (const byte of bytes) {
516
+ num = num * BigInt(256) + BigInt(byte);
517
+ }
518
+ let result = '';
519
+ while (num > 0) {
520
+ const remainder = Number(num % BigInt(58));
521
+ num = num / BigInt(58);
522
+ result = ALPHABET[remainder] + result;
523
+ }
524
+ for (const byte of bytes) {
525
+ if (byte === 0) {
526
+ result = '1' + result;
527
+ }
528
+ else {
529
+ break;
530
+ }
531
+ }
532
+ return result;
533
+ }
534
+ base58ToBytes(str) {
535
+ const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
536
+ let num = BigInt(0);
537
+ for (const char of str) {
538
+ const index = ALPHABET.indexOf(char);
539
+ if (index === -1)
540
+ throw new Error(`Invalid base58 character: ${char}`);
541
+ num = num * BigInt(58) + BigInt(index);
542
+ }
543
+ const bytes = [];
544
+ while (num > 0) {
545
+ bytes.unshift(Number(num % BigInt(256)));
546
+ num = num / BigInt(256);
547
+ }
548
+ for (const char of str) {
549
+ if (char === '1') {
550
+ bytes.unshift(0);
551
+ }
552
+ else {
553
+ break;
554
+ }
555
+ }
556
+ return new Uint8Array(bytes);
557
+ }
558
+ }
559
+ exports.LedgerWallet = LedgerWallet;
560
+ function createLedgerWallet(config) {
561
+ return new LedgerWallet(config);
562
+ }
563
+ //# sourceMappingURL=ledger.js.map