@unicitylabs/sphere-sdk 0.1.3 → 0.1.5
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/README.md +110 -15
- package/dist/core/index.cjs +829 -236
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +332 -210
- package/dist/core/index.d.ts +332 -210
- package/dist/core/index.js +829 -236
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +1224 -339
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +1221 -342
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/browser/ipfs.cjs +471 -37
- package/dist/impl/browser/ipfs.cjs.map +1 -1
- package/dist/impl/browser/ipfs.js +470 -36
- package/dist/impl/browser/ipfs.js.map +1 -1
- package/dist/impl/nodejs/index.cjs +1238 -345
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +142 -57
- package/dist/impl/nodejs/index.d.ts +142 -57
- package/dist/impl/nodejs/index.js +1245 -348
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +871 -235
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1395 -503
- package/dist/index.d.ts +1395 -503
- package/dist/index.js +862 -235
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
|
@@ -1,3 +1,126 @@
|
|
|
1
|
+
// constants.ts
|
|
2
|
+
var STORAGE_KEYS_GLOBAL = {
|
|
3
|
+
/** Encrypted BIP39 mnemonic */
|
|
4
|
+
MNEMONIC: "mnemonic",
|
|
5
|
+
/** Encrypted master private key */
|
|
6
|
+
MASTER_KEY: "master_key",
|
|
7
|
+
/** BIP32 chain code */
|
|
8
|
+
CHAIN_CODE: "chain_code",
|
|
9
|
+
/** HD derivation path (full path like m/44'/0'/0'/0/0) */
|
|
10
|
+
DERIVATION_PATH: "derivation_path",
|
|
11
|
+
/** Base derivation path (like m/44'/0'/0' without chain/index) */
|
|
12
|
+
BASE_PATH: "base_path",
|
|
13
|
+
/** Derivation mode: bip32, wif_hmac, legacy_hmac */
|
|
14
|
+
DERIVATION_MODE: "derivation_mode",
|
|
15
|
+
/** Wallet source: mnemonic, file, unknown */
|
|
16
|
+
WALLET_SOURCE: "wallet_source",
|
|
17
|
+
/** Wallet existence flag */
|
|
18
|
+
WALLET_EXISTS: "wallet_exists",
|
|
19
|
+
/** Current active address index */
|
|
20
|
+
CURRENT_ADDRESS_INDEX: "current_address_index",
|
|
21
|
+
/** Index of address nametags (JSON: { "0": "alice", "1": "bob" }) - for discovery */
|
|
22
|
+
ADDRESS_NAMETAGS: "address_nametags"
|
|
23
|
+
};
|
|
24
|
+
var STORAGE_KEYS_ADDRESS = {
|
|
25
|
+
/** Pending transfers for this address */
|
|
26
|
+
PENDING_TRANSFERS: "pending_transfers",
|
|
27
|
+
/** Transfer outbox for this address */
|
|
28
|
+
OUTBOX: "outbox",
|
|
29
|
+
/** Conversations for this address */
|
|
30
|
+
CONVERSATIONS: "conversations",
|
|
31
|
+
/** Messages for this address */
|
|
32
|
+
MESSAGES: "messages",
|
|
33
|
+
/** Transaction history for this address */
|
|
34
|
+
TRANSACTION_HISTORY: "transaction_history"
|
|
35
|
+
};
|
|
36
|
+
var STORAGE_KEYS = {
|
|
37
|
+
...STORAGE_KEYS_GLOBAL,
|
|
38
|
+
...STORAGE_KEYS_ADDRESS
|
|
39
|
+
};
|
|
40
|
+
function getAddressId(directAddress) {
|
|
41
|
+
let hash = directAddress;
|
|
42
|
+
if (hash.startsWith("DIRECT://")) {
|
|
43
|
+
hash = hash.slice(9);
|
|
44
|
+
} else if (hash.startsWith("DIRECT:")) {
|
|
45
|
+
hash = hash.slice(7);
|
|
46
|
+
}
|
|
47
|
+
const first = hash.slice(0, 6).toLowerCase();
|
|
48
|
+
const last = hash.slice(-6).toLowerCase();
|
|
49
|
+
return `DIRECT_${first}_${last}`;
|
|
50
|
+
}
|
|
51
|
+
var DEFAULT_NOSTR_RELAYS = [
|
|
52
|
+
"wss://relay.unicity.network",
|
|
53
|
+
"wss://relay.damus.io",
|
|
54
|
+
"wss://nos.lol",
|
|
55
|
+
"wss://relay.nostr.band"
|
|
56
|
+
];
|
|
57
|
+
var NOSTR_EVENT_KINDS = {
|
|
58
|
+
/** NIP-04 encrypted direct message */
|
|
59
|
+
DIRECT_MESSAGE: 4,
|
|
60
|
+
/** Token transfer (Unicity custom - 31113) */
|
|
61
|
+
TOKEN_TRANSFER: 31113,
|
|
62
|
+
/** Payment request (Unicity custom - 31115) */
|
|
63
|
+
PAYMENT_REQUEST: 31115,
|
|
64
|
+
/** Payment request response (Unicity custom - 31116) */
|
|
65
|
+
PAYMENT_REQUEST_RESPONSE: 31116,
|
|
66
|
+
/** Nametag binding (NIP-78 app-specific data) */
|
|
67
|
+
NAMETAG_BINDING: 30078,
|
|
68
|
+
/** Public broadcast */
|
|
69
|
+
BROADCAST: 1
|
|
70
|
+
};
|
|
71
|
+
var DEFAULT_AGGREGATOR_URL = "https://aggregator.unicity.network/rpc";
|
|
72
|
+
var DEV_AGGREGATOR_URL = "https://dev-aggregator.dyndns.org/rpc";
|
|
73
|
+
var TEST_AGGREGATOR_URL = "https://goggregator-test.unicity.network";
|
|
74
|
+
var DEFAULT_AGGREGATOR_TIMEOUT = 3e4;
|
|
75
|
+
var DEFAULT_AGGREGATOR_API_KEY = "sk_06365a9c44654841a366068bcfc68986";
|
|
76
|
+
var DEFAULT_IPFS_GATEWAYS = [
|
|
77
|
+
"https://ipfs.unicity.network",
|
|
78
|
+
"https://dweb.link",
|
|
79
|
+
"https://ipfs.io"
|
|
80
|
+
];
|
|
81
|
+
var DEFAULT_BASE_PATH = "m/44'/0'/0'";
|
|
82
|
+
var DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0`;
|
|
83
|
+
var DEFAULT_ELECTRUM_URL = "wss://fulcrum.alpha.unicity.network:50004";
|
|
84
|
+
var TEST_ELECTRUM_URL = "wss://fulcrum.alpha.testnet.unicity.network:50004";
|
|
85
|
+
var TEST_NOSTR_RELAYS = [
|
|
86
|
+
"wss://nostr-relay.testnet.unicity.network"
|
|
87
|
+
];
|
|
88
|
+
var NETWORKS = {
|
|
89
|
+
mainnet: {
|
|
90
|
+
name: "Mainnet",
|
|
91
|
+
aggregatorUrl: DEFAULT_AGGREGATOR_URL,
|
|
92
|
+
nostrRelays: DEFAULT_NOSTR_RELAYS,
|
|
93
|
+
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
94
|
+
electrumUrl: DEFAULT_ELECTRUM_URL
|
|
95
|
+
},
|
|
96
|
+
testnet: {
|
|
97
|
+
name: "Testnet",
|
|
98
|
+
aggregatorUrl: TEST_AGGREGATOR_URL,
|
|
99
|
+
nostrRelays: TEST_NOSTR_RELAYS,
|
|
100
|
+
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
101
|
+
electrumUrl: TEST_ELECTRUM_URL
|
|
102
|
+
},
|
|
103
|
+
dev: {
|
|
104
|
+
name: "Development",
|
|
105
|
+
aggregatorUrl: DEV_AGGREGATOR_URL,
|
|
106
|
+
nostrRelays: TEST_NOSTR_RELAYS,
|
|
107
|
+
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
108
|
+
electrumUrl: TEST_ELECTRUM_URL
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
var TIMEOUTS = {
|
|
112
|
+
/** WebSocket connection timeout */
|
|
113
|
+
WEBSOCKET_CONNECT: 1e4,
|
|
114
|
+
/** Nostr relay reconnect delay */
|
|
115
|
+
NOSTR_RECONNECT_DELAY: 3e3,
|
|
116
|
+
/** Max reconnect attempts */
|
|
117
|
+
MAX_RECONNECT_ATTEMPTS: 5,
|
|
118
|
+
/** Proof polling interval */
|
|
119
|
+
PROOF_POLL_INTERVAL: 1e3,
|
|
120
|
+
/** Sync interval */
|
|
121
|
+
SYNC_INTERVAL: 6e4
|
|
122
|
+
};
|
|
123
|
+
|
|
1
124
|
// impl/browser/storage/LocalStorageProvider.ts
|
|
2
125
|
var LocalStorageProvider = class {
|
|
3
126
|
id = "localStorage";
|
|
@@ -47,7 +170,7 @@ var LocalStorageProvider = class {
|
|
|
47
170
|
// ===========================================================================
|
|
48
171
|
setIdentity(identity) {
|
|
49
172
|
this.identity = identity;
|
|
50
|
-
this.log("Identity set:", identity.
|
|
173
|
+
this.log("Identity set:", identity.l1Address);
|
|
51
174
|
}
|
|
52
175
|
async get(key) {
|
|
53
176
|
this.ensureConnected();
|
|
@@ -114,8 +237,12 @@ var LocalStorageProvider = class {
|
|
|
114
237
|
// Private Methods
|
|
115
238
|
// ===========================================================================
|
|
116
239
|
getFullKey(key) {
|
|
117
|
-
const
|
|
118
|
-
|
|
240
|
+
const isPerAddressKey = Object.values(STORAGE_KEYS_ADDRESS).includes(key);
|
|
241
|
+
if (isPerAddressKey && this.identity?.directAddress) {
|
|
242
|
+
const addressId = getAddressId(this.identity.directAddress);
|
|
243
|
+
return `${this.config.prefix}${addressId}_${key}`;
|
|
244
|
+
}
|
|
245
|
+
return `${this.config.prefix}${key}`;
|
|
119
246
|
}
|
|
120
247
|
ensureConnected() {
|
|
121
248
|
if (this.status !== "connected") {
|
|
@@ -170,17 +297,21 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
170
297
|
id = "indexeddb-token-storage";
|
|
171
298
|
name = "IndexedDB Token Storage";
|
|
172
299
|
type = "local";
|
|
300
|
+
dbNamePrefix;
|
|
173
301
|
dbName;
|
|
174
302
|
db = null;
|
|
175
303
|
status = "disconnected";
|
|
176
304
|
identity = null;
|
|
177
305
|
constructor(config) {
|
|
178
|
-
|
|
179
|
-
this.dbName =
|
|
306
|
+
this.dbNamePrefix = config?.dbNamePrefix ?? DB_NAME;
|
|
307
|
+
this.dbName = this.dbNamePrefix;
|
|
180
308
|
}
|
|
181
309
|
setIdentity(identity) {
|
|
182
310
|
this.identity = identity;
|
|
183
|
-
|
|
311
|
+
if (identity.directAddress) {
|
|
312
|
+
const addressId = getAddressId(identity.directAddress);
|
|
313
|
+
this.dbName = `${this.dbNamePrefix}-${addressId}`;
|
|
314
|
+
}
|
|
184
315
|
}
|
|
185
316
|
async initialize() {
|
|
186
317
|
try {
|
|
@@ -225,7 +356,7 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
225
356
|
const data = {
|
|
226
357
|
_meta: {
|
|
227
358
|
version: 1,
|
|
228
|
-
address: this.identity?.
|
|
359
|
+
address: this.identity?.l1Address ?? "",
|
|
229
360
|
formatVersion: "2.0",
|
|
230
361
|
updatedAt: Date.now()
|
|
231
362
|
}
|
|
@@ -458,14 +589,565 @@ function createIndexedDBTokenStorageProvider(config) {
|
|
|
458
589
|
}
|
|
459
590
|
|
|
460
591
|
// transport/NostrTransportProvider.ts
|
|
461
|
-
import { Buffer } from "buffer";
|
|
592
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
593
|
+
|
|
594
|
+
// node_modules/@noble/hashes/utils.js
|
|
595
|
+
function isBytes(a) {
|
|
596
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
|
|
597
|
+
}
|
|
598
|
+
function anumber(n, title = "") {
|
|
599
|
+
if (!Number.isSafeInteger(n) || n < 0) {
|
|
600
|
+
const prefix = title && `"${title}" `;
|
|
601
|
+
throw new Error(`${prefix}expected integer >= 0, got ${n}`);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
function abytes(value, length, title = "") {
|
|
605
|
+
const bytes = isBytes(value);
|
|
606
|
+
const len = value?.length;
|
|
607
|
+
const needsLen = length !== void 0;
|
|
608
|
+
if (!bytes || needsLen && len !== length) {
|
|
609
|
+
const prefix = title && `"${title}" `;
|
|
610
|
+
const ofLen = needsLen ? ` of length ${length}` : "";
|
|
611
|
+
const got = bytes ? `length=${len}` : `type=${typeof value}`;
|
|
612
|
+
throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
|
|
613
|
+
}
|
|
614
|
+
return value;
|
|
615
|
+
}
|
|
616
|
+
function ahash(h) {
|
|
617
|
+
if (typeof h !== "function" || typeof h.create !== "function")
|
|
618
|
+
throw new Error("Hash must wrapped by utils.createHasher");
|
|
619
|
+
anumber(h.outputLen);
|
|
620
|
+
anumber(h.blockLen);
|
|
621
|
+
}
|
|
622
|
+
function aexists(instance, checkFinished = true) {
|
|
623
|
+
if (instance.destroyed)
|
|
624
|
+
throw new Error("Hash instance has been destroyed");
|
|
625
|
+
if (checkFinished && instance.finished)
|
|
626
|
+
throw new Error("Hash#digest() has already been called");
|
|
627
|
+
}
|
|
628
|
+
function aoutput(out, instance) {
|
|
629
|
+
abytes(out, void 0, "digestInto() output");
|
|
630
|
+
const min = instance.outputLen;
|
|
631
|
+
if (out.length < min) {
|
|
632
|
+
throw new Error('"digestInto() output" expected to be of length >=' + min);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
function clean(...arrays) {
|
|
636
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
637
|
+
arrays[i].fill(0);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
function createView(arr) {
|
|
641
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
642
|
+
}
|
|
643
|
+
function rotr(word, shift) {
|
|
644
|
+
return word << 32 - shift | word >>> shift;
|
|
645
|
+
}
|
|
646
|
+
function createHasher(hashCons, info = {}) {
|
|
647
|
+
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
648
|
+
const tmp = hashCons(void 0);
|
|
649
|
+
hashC.outputLen = tmp.outputLen;
|
|
650
|
+
hashC.blockLen = tmp.blockLen;
|
|
651
|
+
hashC.create = (opts) => hashCons(opts);
|
|
652
|
+
Object.assign(hashC, info);
|
|
653
|
+
return Object.freeze(hashC);
|
|
654
|
+
}
|
|
655
|
+
var oidNist = (suffix) => ({
|
|
656
|
+
oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
// node_modules/@noble/hashes/hmac.js
|
|
660
|
+
var _HMAC = class {
|
|
661
|
+
oHash;
|
|
662
|
+
iHash;
|
|
663
|
+
blockLen;
|
|
664
|
+
outputLen;
|
|
665
|
+
finished = false;
|
|
666
|
+
destroyed = false;
|
|
667
|
+
constructor(hash, key) {
|
|
668
|
+
ahash(hash);
|
|
669
|
+
abytes(key, void 0, "key");
|
|
670
|
+
this.iHash = hash.create();
|
|
671
|
+
if (typeof this.iHash.update !== "function")
|
|
672
|
+
throw new Error("Expected instance of class which extends utils.Hash");
|
|
673
|
+
this.blockLen = this.iHash.blockLen;
|
|
674
|
+
this.outputLen = this.iHash.outputLen;
|
|
675
|
+
const blockLen = this.blockLen;
|
|
676
|
+
const pad = new Uint8Array(blockLen);
|
|
677
|
+
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
678
|
+
for (let i = 0; i < pad.length; i++)
|
|
679
|
+
pad[i] ^= 54;
|
|
680
|
+
this.iHash.update(pad);
|
|
681
|
+
this.oHash = hash.create();
|
|
682
|
+
for (let i = 0; i < pad.length; i++)
|
|
683
|
+
pad[i] ^= 54 ^ 92;
|
|
684
|
+
this.oHash.update(pad);
|
|
685
|
+
clean(pad);
|
|
686
|
+
}
|
|
687
|
+
update(buf) {
|
|
688
|
+
aexists(this);
|
|
689
|
+
this.iHash.update(buf);
|
|
690
|
+
return this;
|
|
691
|
+
}
|
|
692
|
+
digestInto(out) {
|
|
693
|
+
aexists(this);
|
|
694
|
+
abytes(out, this.outputLen, "output");
|
|
695
|
+
this.finished = true;
|
|
696
|
+
this.iHash.digestInto(out);
|
|
697
|
+
this.oHash.update(out);
|
|
698
|
+
this.oHash.digestInto(out);
|
|
699
|
+
this.destroy();
|
|
700
|
+
}
|
|
701
|
+
digest() {
|
|
702
|
+
const out = new Uint8Array(this.oHash.outputLen);
|
|
703
|
+
this.digestInto(out);
|
|
704
|
+
return out;
|
|
705
|
+
}
|
|
706
|
+
_cloneInto(to) {
|
|
707
|
+
to ||= Object.create(Object.getPrototypeOf(this), {});
|
|
708
|
+
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
|
709
|
+
to = to;
|
|
710
|
+
to.finished = finished;
|
|
711
|
+
to.destroyed = destroyed;
|
|
712
|
+
to.blockLen = blockLen;
|
|
713
|
+
to.outputLen = outputLen;
|
|
714
|
+
to.oHash = oHash._cloneInto(to.oHash);
|
|
715
|
+
to.iHash = iHash._cloneInto(to.iHash);
|
|
716
|
+
return to;
|
|
717
|
+
}
|
|
718
|
+
clone() {
|
|
719
|
+
return this._cloneInto();
|
|
720
|
+
}
|
|
721
|
+
destroy() {
|
|
722
|
+
this.destroyed = true;
|
|
723
|
+
this.oHash.destroy();
|
|
724
|
+
this.iHash.destroy();
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
var hmac = (hash, key, message) => new _HMAC(hash, key).update(message).digest();
|
|
728
|
+
hmac.create = (hash, key) => new _HMAC(hash, key);
|
|
729
|
+
|
|
730
|
+
// node_modules/@noble/hashes/hkdf.js
|
|
731
|
+
function extract(hash, ikm, salt) {
|
|
732
|
+
ahash(hash);
|
|
733
|
+
if (salt === void 0)
|
|
734
|
+
salt = new Uint8Array(hash.outputLen);
|
|
735
|
+
return hmac(hash, salt, ikm);
|
|
736
|
+
}
|
|
737
|
+
var HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0);
|
|
738
|
+
var EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of();
|
|
739
|
+
function expand(hash, prk, info, length = 32) {
|
|
740
|
+
ahash(hash);
|
|
741
|
+
anumber(length, "length");
|
|
742
|
+
const olen = hash.outputLen;
|
|
743
|
+
if (length > 255 * olen)
|
|
744
|
+
throw new Error("Length must be <= 255*HashLen");
|
|
745
|
+
const blocks = Math.ceil(length / olen);
|
|
746
|
+
if (info === void 0)
|
|
747
|
+
info = EMPTY_BUFFER;
|
|
748
|
+
else
|
|
749
|
+
abytes(info, void 0, "info");
|
|
750
|
+
const okm = new Uint8Array(blocks * olen);
|
|
751
|
+
const HMAC = hmac.create(hash, prk);
|
|
752
|
+
const HMACTmp = HMAC._cloneInto();
|
|
753
|
+
const T = new Uint8Array(HMAC.outputLen);
|
|
754
|
+
for (let counter = 0; counter < blocks; counter++) {
|
|
755
|
+
HKDF_COUNTER[0] = counter + 1;
|
|
756
|
+
HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T).update(info).update(HKDF_COUNTER).digestInto(T);
|
|
757
|
+
okm.set(T, olen * counter);
|
|
758
|
+
HMAC._cloneInto(HMACTmp);
|
|
759
|
+
}
|
|
760
|
+
HMAC.destroy();
|
|
761
|
+
HMACTmp.destroy();
|
|
762
|
+
clean(T, HKDF_COUNTER);
|
|
763
|
+
return okm.slice(0, length);
|
|
764
|
+
}
|
|
765
|
+
var hkdf = (hash, ikm, salt, info, length) => expand(hash, extract(hash, ikm, salt), info, length);
|
|
766
|
+
|
|
767
|
+
// node_modules/@noble/hashes/_md.js
|
|
768
|
+
function Chi(a, b, c) {
|
|
769
|
+
return a & b ^ ~a & c;
|
|
770
|
+
}
|
|
771
|
+
function Maj(a, b, c) {
|
|
772
|
+
return a & b ^ a & c ^ b & c;
|
|
773
|
+
}
|
|
774
|
+
var HashMD = class {
|
|
775
|
+
blockLen;
|
|
776
|
+
outputLen;
|
|
777
|
+
padOffset;
|
|
778
|
+
isLE;
|
|
779
|
+
// For partial updates less than block size
|
|
780
|
+
buffer;
|
|
781
|
+
view;
|
|
782
|
+
finished = false;
|
|
783
|
+
length = 0;
|
|
784
|
+
pos = 0;
|
|
785
|
+
destroyed = false;
|
|
786
|
+
constructor(blockLen, outputLen, padOffset, isLE) {
|
|
787
|
+
this.blockLen = blockLen;
|
|
788
|
+
this.outputLen = outputLen;
|
|
789
|
+
this.padOffset = padOffset;
|
|
790
|
+
this.isLE = isLE;
|
|
791
|
+
this.buffer = new Uint8Array(blockLen);
|
|
792
|
+
this.view = createView(this.buffer);
|
|
793
|
+
}
|
|
794
|
+
update(data) {
|
|
795
|
+
aexists(this);
|
|
796
|
+
abytes(data);
|
|
797
|
+
const { view, buffer, blockLen } = this;
|
|
798
|
+
const len = data.length;
|
|
799
|
+
for (let pos = 0; pos < len; ) {
|
|
800
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
801
|
+
if (take === blockLen) {
|
|
802
|
+
const dataView = createView(data);
|
|
803
|
+
for (; blockLen <= len - pos; pos += blockLen)
|
|
804
|
+
this.process(dataView, pos);
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
buffer.set(data.subarray(pos, pos + take), this.pos);
|
|
808
|
+
this.pos += take;
|
|
809
|
+
pos += take;
|
|
810
|
+
if (this.pos === blockLen) {
|
|
811
|
+
this.process(view, 0);
|
|
812
|
+
this.pos = 0;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
this.length += data.length;
|
|
816
|
+
this.roundClean();
|
|
817
|
+
return this;
|
|
818
|
+
}
|
|
819
|
+
digestInto(out) {
|
|
820
|
+
aexists(this);
|
|
821
|
+
aoutput(out, this);
|
|
822
|
+
this.finished = true;
|
|
823
|
+
const { buffer, view, blockLen, isLE } = this;
|
|
824
|
+
let { pos } = this;
|
|
825
|
+
buffer[pos++] = 128;
|
|
826
|
+
clean(this.buffer.subarray(pos));
|
|
827
|
+
if (this.padOffset > blockLen - pos) {
|
|
828
|
+
this.process(view, 0);
|
|
829
|
+
pos = 0;
|
|
830
|
+
}
|
|
831
|
+
for (let i = pos; i < blockLen; i++)
|
|
832
|
+
buffer[i] = 0;
|
|
833
|
+
view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
|
|
834
|
+
this.process(view, 0);
|
|
835
|
+
const oview = createView(out);
|
|
836
|
+
const len = this.outputLen;
|
|
837
|
+
if (len % 4)
|
|
838
|
+
throw new Error("_sha2: outputLen must be aligned to 32bit");
|
|
839
|
+
const outLen = len / 4;
|
|
840
|
+
const state = this.get();
|
|
841
|
+
if (outLen > state.length)
|
|
842
|
+
throw new Error("_sha2: outputLen bigger than state");
|
|
843
|
+
for (let i = 0; i < outLen; i++)
|
|
844
|
+
oview.setUint32(4 * i, state[i], isLE);
|
|
845
|
+
}
|
|
846
|
+
digest() {
|
|
847
|
+
const { buffer, outputLen } = this;
|
|
848
|
+
this.digestInto(buffer);
|
|
849
|
+
const res = buffer.slice(0, outputLen);
|
|
850
|
+
this.destroy();
|
|
851
|
+
return res;
|
|
852
|
+
}
|
|
853
|
+
_cloneInto(to) {
|
|
854
|
+
to ||= new this.constructor();
|
|
855
|
+
to.set(...this.get());
|
|
856
|
+
const { blockLen, buffer, length, finished, destroyed, pos } = this;
|
|
857
|
+
to.destroyed = destroyed;
|
|
858
|
+
to.finished = finished;
|
|
859
|
+
to.length = length;
|
|
860
|
+
to.pos = pos;
|
|
861
|
+
if (length % blockLen)
|
|
862
|
+
to.buffer.set(buffer);
|
|
863
|
+
return to;
|
|
864
|
+
}
|
|
865
|
+
clone() {
|
|
866
|
+
return this._cloneInto();
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
|
|
870
|
+
1779033703,
|
|
871
|
+
3144134277,
|
|
872
|
+
1013904242,
|
|
873
|
+
2773480762,
|
|
874
|
+
1359893119,
|
|
875
|
+
2600822924,
|
|
876
|
+
528734635,
|
|
877
|
+
1541459225
|
|
878
|
+
]);
|
|
879
|
+
|
|
880
|
+
// node_modules/@noble/hashes/sha2.js
|
|
881
|
+
var SHA256_K = /* @__PURE__ */ Uint32Array.from([
|
|
882
|
+
1116352408,
|
|
883
|
+
1899447441,
|
|
884
|
+
3049323471,
|
|
885
|
+
3921009573,
|
|
886
|
+
961987163,
|
|
887
|
+
1508970993,
|
|
888
|
+
2453635748,
|
|
889
|
+
2870763221,
|
|
890
|
+
3624381080,
|
|
891
|
+
310598401,
|
|
892
|
+
607225278,
|
|
893
|
+
1426881987,
|
|
894
|
+
1925078388,
|
|
895
|
+
2162078206,
|
|
896
|
+
2614888103,
|
|
897
|
+
3248222580,
|
|
898
|
+
3835390401,
|
|
899
|
+
4022224774,
|
|
900
|
+
264347078,
|
|
901
|
+
604807628,
|
|
902
|
+
770255983,
|
|
903
|
+
1249150122,
|
|
904
|
+
1555081692,
|
|
905
|
+
1996064986,
|
|
906
|
+
2554220882,
|
|
907
|
+
2821834349,
|
|
908
|
+
2952996808,
|
|
909
|
+
3210313671,
|
|
910
|
+
3336571891,
|
|
911
|
+
3584528711,
|
|
912
|
+
113926993,
|
|
913
|
+
338241895,
|
|
914
|
+
666307205,
|
|
915
|
+
773529912,
|
|
916
|
+
1294757372,
|
|
917
|
+
1396182291,
|
|
918
|
+
1695183700,
|
|
919
|
+
1986661051,
|
|
920
|
+
2177026350,
|
|
921
|
+
2456956037,
|
|
922
|
+
2730485921,
|
|
923
|
+
2820302411,
|
|
924
|
+
3259730800,
|
|
925
|
+
3345764771,
|
|
926
|
+
3516065817,
|
|
927
|
+
3600352804,
|
|
928
|
+
4094571909,
|
|
929
|
+
275423344,
|
|
930
|
+
430227734,
|
|
931
|
+
506948616,
|
|
932
|
+
659060556,
|
|
933
|
+
883997877,
|
|
934
|
+
958139571,
|
|
935
|
+
1322822218,
|
|
936
|
+
1537002063,
|
|
937
|
+
1747873779,
|
|
938
|
+
1955562222,
|
|
939
|
+
2024104815,
|
|
940
|
+
2227730452,
|
|
941
|
+
2361852424,
|
|
942
|
+
2428436474,
|
|
943
|
+
2756734187,
|
|
944
|
+
3204031479,
|
|
945
|
+
3329325298
|
|
946
|
+
]);
|
|
947
|
+
var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
|
|
948
|
+
var SHA2_32B = class extends HashMD {
|
|
949
|
+
constructor(outputLen) {
|
|
950
|
+
super(64, outputLen, 8, false);
|
|
951
|
+
}
|
|
952
|
+
get() {
|
|
953
|
+
const { A, B, C, D, E, F, G, H } = this;
|
|
954
|
+
return [A, B, C, D, E, F, G, H];
|
|
955
|
+
}
|
|
956
|
+
// prettier-ignore
|
|
957
|
+
set(A, B, C, D, E, F, G, H) {
|
|
958
|
+
this.A = A | 0;
|
|
959
|
+
this.B = B | 0;
|
|
960
|
+
this.C = C | 0;
|
|
961
|
+
this.D = D | 0;
|
|
962
|
+
this.E = E | 0;
|
|
963
|
+
this.F = F | 0;
|
|
964
|
+
this.G = G | 0;
|
|
965
|
+
this.H = H | 0;
|
|
966
|
+
}
|
|
967
|
+
process(view, offset) {
|
|
968
|
+
for (let i = 0; i < 16; i++, offset += 4)
|
|
969
|
+
SHA256_W[i] = view.getUint32(offset, false);
|
|
970
|
+
for (let i = 16; i < 64; i++) {
|
|
971
|
+
const W15 = SHA256_W[i - 15];
|
|
972
|
+
const W2 = SHA256_W[i - 2];
|
|
973
|
+
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
|
|
974
|
+
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
|
|
975
|
+
SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
|
|
976
|
+
}
|
|
977
|
+
let { A, B, C, D, E, F, G, H } = this;
|
|
978
|
+
for (let i = 0; i < 64; i++) {
|
|
979
|
+
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
|
|
980
|
+
const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
|
|
981
|
+
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
|
|
982
|
+
const T2 = sigma0 + Maj(A, B, C) | 0;
|
|
983
|
+
H = G;
|
|
984
|
+
G = F;
|
|
985
|
+
F = E;
|
|
986
|
+
E = D + T1 | 0;
|
|
987
|
+
D = C;
|
|
988
|
+
C = B;
|
|
989
|
+
B = A;
|
|
990
|
+
A = T1 + T2 | 0;
|
|
991
|
+
}
|
|
992
|
+
A = A + this.A | 0;
|
|
993
|
+
B = B + this.B | 0;
|
|
994
|
+
C = C + this.C | 0;
|
|
995
|
+
D = D + this.D | 0;
|
|
996
|
+
E = E + this.E | 0;
|
|
997
|
+
F = F + this.F | 0;
|
|
998
|
+
G = G + this.G | 0;
|
|
999
|
+
H = H + this.H | 0;
|
|
1000
|
+
this.set(A, B, C, D, E, F, G, H);
|
|
1001
|
+
}
|
|
1002
|
+
roundClean() {
|
|
1003
|
+
clean(SHA256_W);
|
|
1004
|
+
}
|
|
1005
|
+
destroy() {
|
|
1006
|
+
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
|
1007
|
+
clean(this.buffer);
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
var _SHA256 = class extends SHA2_32B {
|
|
1011
|
+
// We cannot use array here since array allows indexing by variable
|
|
1012
|
+
// which means optimizer/compiler cannot use registers.
|
|
1013
|
+
A = SHA256_IV[0] | 0;
|
|
1014
|
+
B = SHA256_IV[1] | 0;
|
|
1015
|
+
C = SHA256_IV[2] | 0;
|
|
1016
|
+
D = SHA256_IV[3] | 0;
|
|
1017
|
+
E = SHA256_IV[4] | 0;
|
|
1018
|
+
F = SHA256_IV[5] | 0;
|
|
1019
|
+
G = SHA256_IV[6] | 0;
|
|
1020
|
+
H = SHA256_IV[7] | 0;
|
|
1021
|
+
constructor() {
|
|
1022
|
+
super(32);
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
var sha256 = /* @__PURE__ */ createHasher(
|
|
1026
|
+
() => new _SHA256(),
|
|
1027
|
+
/* @__PURE__ */ oidNist(1)
|
|
1028
|
+
);
|
|
1029
|
+
|
|
1030
|
+
// transport/NostrTransportProvider.ts
|
|
462
1031
|
import {
|
|
463
1032
|
NostrKeyManager,
|
|
464
1033
|
NIP04,
|
|
1034
|
+
NIP17,
|
|
465
1035
|
Event as NostrEventClass,
|
|
466
|
-
|
|
1036
|
+
EventKinds,
|
|
1037
|
+
hashNametag,
|
|
1038
|
+
NostrClient,
|
|
1039
|
+
Filter
|
|
467
1040
|
} from "@unicitylabs/nostr-js-sdk";
|
|
468
1041
|
|
|
1042
|
+
// core/crypto.ts
|
|
1043
|
+
import * as bip39 from "bip39";
|
|
1044
|
+
import CryptoJS from "crypto-js";
|
|
1045
|
+
import elliptic from "elliptic";
|
|
1046
|
+
|
|
1047
|
+
// core/bech32.ts
|
|
1048
|
+
var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
1049
|
+
var GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
1050
|
+
function convertBits(data, fromBits, toBits, pad) {
|
|
1051
|
+
let acc = 0;
|
|
1052
|
+
let bits = 0;
|
|
1053
|
+
const ret = [];
|
|
1054
|
+
const maxv = (1 << toBits) - 1;
|
|
1055
|
+
for (let i = 0; i < data.length; i++) {
|
|
1056
|
+
const value = data[i];
|
|
1057
|
+
if (value < 0 || value >> fromBits !== 0) return null;
|
|
1058
|
+
acc = acc << fromBits | value;
|
|
1059
|
+
bits += fromBits;
|
|
1060
|
+
while (bits >= toBits) {
|
|
1061
|
+
bits -= toBits;
|
|
1062
|
+
ret.push(acc >> bits & maxv);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
if (pad) {
|
|
1066
|
+
if (bits > 0) {
|
|
1067
|
+
ret.push(acc << toBits - bits & maxv);
|
|
1068
|
+
}
|
|
1069
|
+
} else if (bits >= fromBits || acc << toBits - bits & maxv) {
|
|
1070
|
+
return null;
|
|
1071
|
+
}
|
|
1072
|
+
return ret;
|
|
1073
|
+
}
|
|
1074
|
+
function hrpExpand(hrp) {
|
|
1075
|
+
const ret = [];
|
|
1076
|
+
for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) >> 5);
|
|
1077
|
+
ret.push(0);
|
|
1078
|
+
for (let i = 0; i < hrp.length; i++) ret.push(hrp.charCodeAt(i) & 31);
|
|
1079
|
+
return ret;
|
|
1080
|
+
}
|
|
1081
|
+
function bech32Polymod(values) {
|
|
1082
|
+
let chk = 1;
|
|
1083
|
+
for (let p = 0; p < values.length; p++) {
|
|
1084
|
+
const top = chk >> 25;
|
|
1085
|
+
chk = (chk & 33554431) << 5 ^ values[p];
|
|
1086
|
+
for (let i = 0; i < 5; i++) {
|
|
1087
|
+
if (top >> i & 1) chk ^= GENERATOR[i];
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
return chk;
|
|
1091
|
+
}
|
|
1092
|
+
function bech32Checksum(hrp, data) {
|
|
1093
|
+
const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
|
|
1094
|
+
const mod = bech32Polymod(values) ^ 1;
|
|
1095
|
+
const ret = [];
|
|
1096
|
+
for (let p = 0; p < 6; p++) {
|
|
1097
|
+
ret.push(mod >> 5 * (5 - p) & 31);
|
|
1098
|
+
}
|
|
1099
|
+
return ret;
|
|
1100
|
+
}
|
|
1101
|
+
function encodeBech32(hrp, version, program) {
|
|
1102
|
+
if (version < 0 || version > 16) {
|
|
1103
|
+
throw new Error("Invalid witness version");
|
|
1104
|
+
}
|
|
1105
|
+
const converted = convertBits(Array.from(program), 8, 5, true);
|
|
1106
|
+
if (!converted) {
|
|
1107
|
+
throw new Error("Failed to convert bits");
|
|
1108
|
+
}
|
|
1109
|
+
const data = [version].concat(converted);
|
|
1110
|
+
const checksum = bech32Checksum(hrp, data);
|
|
1111
|
+
const combined = data.concat(checksum);
|
|
1112
|
+
let out = hrp + "1";
|
|
1113
|
+
for (let i = 0; i < combined.length; i++) {
|
|
1114
|
+
out += CHARSET[combined[i]];
|
|
1115
|
+
}
|
|
1116
|
+
return out;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// core/crypto.ts
|
|
1120
|
+
var ec = new elliptic.ec("secp256k1");
|
|
1121
|
+
var CURVE_ORDER = BigInt(
|
|
1122
|
+
"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
|
|
1123
|
+
);
|
|
1124
|
+
function getPublicKey(privateKey, compressed = true) {
|
|
1125
|
+
const keyPair = ec.keyFromPrivate(privateKey, "hex");
|
|
1126
|
+
return keyPair.getPublic(compressed, "hex");
|
|
1127
|
+
}
|
|
1128
|
+
function sha2562(data, inputEncoding = "hex") {
|
|
1129
|
+
const parsed = inputEncoding === "hex" ? CryptoJS.enc.Hex.parse(data) : CryptoJS.enc.Utf8.parse(data);
|
|
1130
|
+
return CryptoJS.SHA256(parsed).toString();
|
|
1131
|
+
}
|
|
1132
|
+
function ripemd160(data, inputEncoding = "hex") {
|
|
1133
|
+
const parsed = inputEncoding === "hex" ? CryptoJS.enc.Hex.parse(data) : CryptoJS.enc.Utf8.parse(data);
|
|
1134
|
+
return CryptoJS.RIPEMD160(parsed).toString();
|
|
1135
|
+
}
|
|
1136
|
+
function hash160(data) {
|
|
1137
|
+
const sha = sha2562(data, "hex");
|
|
1138
|
+
return ripemd160(sha, "hex");
|
|
1139
|
+
}
|
|
1140
|
+
function hash160ToBytes(hash160Hex) {
|
|
1141
|
+
const matches = hash160Hex.match(/../g);
|
|
1142
|
+
if (!matches) return new Uint8Array(0);
|
|
1143
|
+
return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
|
|
1144
|
+
}
|
|
1145
|
+
function publicKeyToAddress(publicKey, prefix = "alpha", witnessVersion = 0) {
|
|
1146
|
+
const pubKeyHash = hash160(publicKey);
|
|
1147
|
+
const programBytes = hash160ToBytes(pubKeyHash);
|
|
1148
|
+
return encodeBech32(prefix, witnessVersion, programBytes);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
469
1151
|
// transport/websocket.ts
|
|
470
1152
|
var WebSocketReadyState = {
|
|
471
1153
|
CONNECTING: 0,
|
|
@@ -484,124 +1166,61 @@ function defaultUUIDGenerator() {
|
|
|
484
1166
|
});
|
|
485
1167
|
}
|
|
486
1168
|
|
|
487
|
-
// constants.ts
|
|
488
|
-
var STORAGE_PREFIX = "sphere_";
|
|
489
|
-
var STORAGE_KEYS = {
|
|
490
|
-
/** Encrypted BIP39 mnemonic */
|
|
491
|
-
MNEMONIC: `${STORAGE_PREFIX}mnemonic`,
|
|
492
|
-
/** Encrypted master private key */
|
|
493
|
-
MASTER_KEY: `${STORAGE_PREFIX}master_key`,
|
|
494
|
-
/** BIP32 chain code */
|
|
495
|
-
CHAIN_CODE: `${STORAGE_PREFIX}chain_code`,
|
|
496
|
-
/** HD derivation path (full path like m/44'/0'/0'/0/0) */
|
|
497
|
-
DERIVATION_PATH: `${STORAGE_PREFIX}derivation_path`,
|
|
498
|
-
/** Base derivation path (like m/44'/0'/0' without chain/index) */
|
|
499
|
-
BASE_PATH: `${STORAGE_PREFIX}base_path`,
|
|
500
|
-
/** Derivation mode: bip32, wif_hmac, legacy_hmac */
|
|
501
|
-
DERIVATION_MODE: `${STORAGE_PREFIX}derivation_mode`,
|
|
502
|
-
/** Wallet source: mnemonic, file, unknown */
|
|
503
|
-
WALLET_SOURCE: `${STORAGE_PREFIX}wallet_source`,
|
|
504
|
-
/** Wallet existence flag */
|
|
505
|
-
WALLET_EXISTS: `${STORAGE_PREFIX}wallet_exists`,
|
|
506
|
-
/** Registered nametag (legacy - single address) */
|
|
507
|
-
NAMETAG: `${STORAGE_PREFIX}nametag`,
|
|
508
|
-
/** Current active address index */
|
|
509
|
-
CURRENT_ADDRESS_INDEX: `${STORAGE_PREFIX}current_address_index`,
|
|
510
|
-
/** Address nametags map (JSON: { "0": "alice", "1": "bob" }) */
|
|
511
|
-
ADDRESS_NAMETAGS: `${STORAGE_PREFIX}address_nametags`,
|
|
512
|
-
/** Token data */
|
|
513
|
-
TOKENS: `${STORAGE_PREFIX}tokens`,
|
|
514
|
-
/** Pending transfers */
|
|
515
|
-
PENDING_TRANSFERS: `${STORAGE_PREFIX}pending_transfers`,
|
|
516
|
-
/** Transfer outbox */
|
|
517
|
-
OUTBOX: `${STORAGE_PREFIX}outbox`,
|
|
518
|
-
/** Conversations */
|
|
519
|
-
CONVERSATIONS: `${STORAGE_PREFIX}conversations`,
|
|
520
|
-
/** Messages */
|
|
521
|
-
MESSAGES: `${STORAGE_PREFIX}messages`,
|
|
522
|
-
/** Transaction history */
|
|
523
|
-
TRANSACTION_HISTORY: `${STORAGE_PREFIX}transaction_history`,
|
|
524
|
-
/** Archived tokens (spent token history) */
|
|
525
|
-
ARCHIVED_TOKENS: `${STORAGE_PREFIX}archived_tokens`,
|
|
526
|
-
/** Tombstones (records of deleted/spent tokens) */
|
|
527
|
-
TOMBSTONES: `${STORAGE_PREFIX}tombstones`,
|
|
528
|
-
/** Forked tokens (alternative histories) */
|
|
529
|
-
FORKED_TOKENS: `${STORAGE_PREFIX}forked_tokens`
|
|
530
|
-
};
|
|
531
|
-
var DEFAULT_NOSTR_RELAYS = [
|
|
532
|
-
"wss://relay.unicity.network",
|
|
533
|
-
"wss://relay.damus.io",
|
|
534
|
-
"wss://nos.lol",
|
|
535
|
-
"wss://relay.nostr.band"
|
|
536
|
-
];
|
|
537
|
-
var NOSTR_EVENT_KINDS = {
|
|
538
|
-
/** NIP-04 encrypted direct message */
|
|
539
|
-
DIRECT_MESSAGE: 4,
|
|
540
|
-
/** Token transfer (Unicity custom - 31113) */
|
|
541
|
-
TOKEN_TRANSFER: 31113,
|
|
542
|
-
/** Payment request (Unicity custom - 31115) */
|
|
543
|
-
PAYMENT_REQUEST: 31115,
|
|
544
|
-
/** Payment request response (Unicity custom - 31116) */
|
|
545
|
-
PAYMENT_REQUEST_RESPONSE: 31116,
|
|
546
|
-
/** Nametag binding (NIP-78 app-specific data) */
|
|
547
|
-
NAMETAG_BINDING: 30078,
|
|
548
|
-
/** Public broadcast */
|
|
549
|
-
BROADCAST: 1
|
|
550
|
-
};
|
|
551
|
-
var DEFAULT_AGGREGATOR_URL = "https://aggregator.unicity.network/rpc";
|
|
552
|
-
var DEV_AGGREGATOR_URL = "https://dev-aggregator.dyndns.org/rpc";
|
|
553
|
-
var TEST_AGGREGATOR_URL = "https://goggregator-test.unicity.network";
|
|
554
|
-
var DEFAULT_AGGREGATOR_TIMEOUT = 3e4;
|
|
555
|
-
var DEFAULT_IPFS_GATEWAYS = [
|
|
556
|
-
"https://ipfs.unicity.network",
|
|
557
|
-
"https://dweb.link",
|
|
558
|
-
"https://ipfs.io"
|
|
559
|
-
];
|
|
560
|
-
var DEFAULT_BASE_PATH = "m/44'/0'/0'";
|
|
561
|
-
var DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0`;
|
|
562
|
-
var DEFAULT_ELECTRUM_URL = "wss://fulcrum.alpha.unicity.network:50004";
|
|
563
|
-
var TEST_ELECTRUM_URL = "wss://fulcrum.alpha.testnet.unicity.network:50004";
|
|
564
|
-
var TEST_NOSTR_RELAYS = [
|
|
565
|
-
"wss://nostr-relay.testnet.unicity.network"
|
|
566
|
-
];
|
|
567
|
-
var NETWORKS = {
|
|
568
|
-
mainnet: {
|
|
569
|
-
name: "Mainnet",
|
|
570
|
-
aggregatorUrl: DEFAULT_AGGREGATOR_URL,
|
|
571
|
-
nostrRelays: DEFAULT_NOSTR_RELAYS,
|
|
572
|
-
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
573
|
-
electrumUrl: DEFAULT_ELECTRUM_URL
|
|
574
|
-
},
|
|
575
|
-
testnet: {
|
|
576
|
-
name: "Testnet",
|
|
577
|
-
aggregatorUrl: TEST_AGGREGATOR_URL,
|
|
578
|
-
nostrRelays: TEST_NOSTR_RELAYS,
|
|
579
|
-
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
580
|
-
electrumUrl: TEST_ELECTRUM_URL
|
|
581
|
-
},
|
|
582
|
-
dev: {
|
|
583
|
-
name: "Development",
|
|
584
|
-
aggregatorUrl: DEV_AGGREGATOR_URL,
|
|
585
|
-
nostrRelays: TEST_NOSTR_RELAYS,
|
|
586
|
-
ipfsGateways: DEFAULT_IPFS_GATEWAYS,
|
|
587
|
-
electrumUrl: TEST_ELECTRUM_URL
|
|
588
|
-
}
|
|
589
|
-
};
|
|
590
|
-
var TIMEOUTS = {
|
|
591
|
-
/** WebSocket connection timeout */
|
|
592
|
-
WEBSOCKET_CONNECT: 1e4,
|
|
593
|
-
/** Nostr relay reconnect delay */
|
|
594
|
-
NOSTR_RECONNECT_DELAY: 3e3,
|
|
595
|
-
/** Max reconnect attempts */
|
|
596
|
-
MAX_RECONNECT_ATTEMPTS: 5,
|
|
597
|
-
/** Proof polling interval */
|
|
598
|
-
PROOF_POLL_INTERVAL: 1e3,
|
|
599
|
-
/** Sync interval */
|
|
600
|
-
SYNC_INTERVAL: 6e4
|
|
601
|
-
};
|
|
602
|
-
|
|
603
1169
|
// transport/NostrTransportProvider.ts
|
|
604
1170
|
var EVENT_KINDS = NOSTR_EVENT_KINDS;
|
|
1171
|
+
function deriveNametagEncryptionKey(privateKeyHex) {
|
|
1172
|
+
const privateKeyBytes = Buffer2.from(privateKeyHex, "hex");
|
|
1173
|
+
const saltInput = new TextEncoder().encode("sphere-nametag-salt");
|
|
1174
|
+
const salt = sha256(saltInput);
|
|
1175
|
+
const info = new TextEncoder().encode("nametag-encryption");
|
|
1176
|
+
return hkdf(sha256, privateKeyBytes, salt, info, 32);
|
|
1177
|
+
}
|
|
1178
|
+
async function encryptNametag(nametag, privateKeyHex) {
|
|
1179
|
+
const key = deriveNametagEncryptionKey(privateKeyHex);
|
|
1180
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
1181
|
+
const encoder = new TextEncoder();
|
|
1182
|
+
const data = encoder.encode(nametag);
|
|
1183
|
+
const cryptoKey = await crypto.subtle.importKey(
|
|
1184
|
+
"raw",
|
|
1185
|
+
new Uint8Array(key).buffer,
|
|
1186
|
+
{ name: "AES-GCM" },
|
|
1187
|
+
false,
|
|
1188
|
+
["encrypt"]
|
|
1189
|
+
);
|
|
1190
|
+
const encrypted = await crypto.subtle.encrypt(
|
|
1191
|
+
{ name: "AES-GCM", iv: new Uint8Array(iv).buffer },
|
|
1192
|
+
cryptoKey,
|
|
1193
|
+
new Uint8Array(data).buffer
|
|
1194
|
+
);
|
|
1195
|
+
const combined = new Uint8Array(iv.length + encrypted.byteLength);
|
|
1196
|
+
combined.set(iv, 0);
|
|
1197
|
+
combined.set(new Uint8Array(encrypted), iv.length);
|
|
1198
|
+
return Buffer2.from(combined).toString("base64");
|
|
1199
|
+
}
|
|
1200
|
+
async function decryptNametag(encryptedBase64, privateKeyHex) {
|
|
1201
|
+
try {
|
|
1202
|
+
const key = deriveNametagEncryptionKey(privateKeyHex);
|
|
1203
|
+
const combined = Buffer2.from(encryptedBase64, "base64");
|
|
1204
|
+
const iv = combined.slice(0, 12);
|
|
1205
|
+
const ciphertext = combined.slice(12);
|
|
1206
|
+
const cryptoKey = await crypto.subtle.importKey(
|
|
1207
|
+
"raw",
|
|
1208
|
+
new Uint8Array(key).buffer,
|
|
1209
|
+
{ name: "AES-GCM" },
|
|
1210
|
+
false,
|
|
1211
|
+
["decrypt"]
|
|
1212
|
+
);
|
|
1213
|
+
const decrypted = await crypto.subtle.decrypt(
|
|
1214
|
+
{ name: "AES-GCM", iv: new Uint8Array(iv).buffer },
|
|
1215
|
+
cryptoKey,
|
|
1216
|
+
new Uint8Array(ciphertext).buffer
|
|
1217
|
+
);
|
|
1218
|
+
const decoder = new TextDecoder();
|
|
1219
|
+
return decoder.decode(decrypted);
|
|
1220
|
+
} catch {
|
|
1221
|
+
return null;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
605
1224
|
var NostrTransportProvider = class {
|
|
606
1225
|
id = "nostr";
|
|
607
1226
|
name = "Nostr Transport";
|
|
@@ -611,9 +1230,10 @@ var NostrTransportProvider = class {
|
|
|
611
1230
|
identity = null;
|
|
612
1231
|
keyManager = null;
|
|
613
1232
|
status = "disconnected";
|
|
614
|
-
//
|
|
615
|
-
|
|
616
|
-
|
|
1233
|
+
// NostrClient from nostr-js-sdk handles all WebSocket management,
|
|
1234
|
+
// keepalive pings, reconnection, and NIP-42 authentication
|
|
1235
|
+
nostrClient = null;
|
|
1236
|
+
mainSubscriptionId = null;
|
|
617
1237
|
// Event handlers
|
|
618
1238
|
messageHandlers = /* @__PURE__ */ new Set();
|
|
619
1239
|
transferHandlers = /* @__PURE__ */ new Set();
|
|
@@ -621,9 +1241,6 @@ var NostrTransportProvider = class {
|
|
|
621
1241
|
paymentRequestResponseHandlers = /* @__PURE__ */ new Set();
|
|
622
1242
|
broadcastHandlers = /* @__PURE__ */ new Map();
|
|
623
1243
|
eventCallbacks = /* @__PURE__ */ new Set();
|
|
624
|
-
// Subscriptions
|
|
625
|
-
subscriptions = /* @__PURE__ */ new Map();
|
|
626
|
-
// subId -> relays
|
|
627
1244
|
constructor(config) {
|
|
628
1245
|
this.config = {
|
|
629
1246
|
relays: config.relays ?? [...DEFAULT_NOSTR_RELAYS],
|
|
@@ -643,16 +1260,43 @@ var NostrTransportProvider = class {
|
|
|
643
1260
|
if (this.status === "connected") return;
|
|
644
1261
|
this.status = "connecting";
|
|
645
1262
|
try {
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
1263
|
+
if (!this.keyManager) {
|
|
1264
|
+
const tempKey = Buffer2.alloc(32);
|
|
1265
|
+
crypto.getRandomValues(tempKey);
|
|
1266
|
+
this.keyManager = NostrKeyManager.fromPrivateKey(tempKey);
|
|
1267
|
+
}
|
|
1268
|
+
this.nostrClient = new NostrClient(this.keyManager, {
|
|
1269
|
+
autoReconnect: this.config.autoReconnect,
|
|
1270
|
+
reconnectIntervalMs: this.config.reconnectDelay,
|
|
1271
|
+
maxReconnectIntervalMs: this.config.reconnectDelay * 16,
|
|
1272
|
+
// exponential backoff cap
|
|
1273
|
+
pingIntervalMs: 15e3
|
|
1274
|
+
// 15 second keepalive pings (more aggressive to prevent drops)
|
|
1275
|
+
});
|
|
1276
|
+
this.nostrClient.addConnectionListener({
|
|
1277
|
+
onConnect: (url) => {
|
|
1278
|
+
this.log("NostrClient connected to relay:", url);
|
|
1279
|
+
this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
|
|
1280
|
+
},
|
|
1281
|
+
onDisconnect: (url, reason) => {
|
|
1282
|
+
this.log("NostrClient disconnected from relay:", url, "reason:", reason);
|
|
1283
|
+
},
|
|
1284
|
+
onReconnecting: (url, attempt) => {
|
|
1285
|
+
this.log("NostrClient reconnecting to relay:", url, "attempt:", attempt);
|
|
1286
|
+
this.emitEvent({ type: "transport:reconnecting", timestamp: Date.now() });
|
|
1287
|
+
},
|
|
1288
|
+
onReconnected: (url) => {
|
|
1289
|
+
this.log("NostrClient reconnected to relay:", url);
|
|
1290
|
+
this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
|
|
1291
|
+
}
|
|
1292
|
+
});
|
|
1293
|
+
await this.nostrClient.connect(...this.config.relays);
|
|
1294
|
+
if (!this.nostrClient.isConnected()) {
|
|
651
1295
|
throw new Error("Failed to connect to any relay");
|
|
652
1296
|
}
|
|
653
1297
|
this.status = "connected";
|
|
654
1298
|
this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
|
|
655
|
-
this.log("Connected to", this.
|
|
1299
|
+
this.log("Connected to", this.nostrClient.getConnectedRelays().size, "relays");
|
|
656
1300
|
if (this.identity) {
|
|
657
1301
|
this.subscribeToEvents();
|
|
658
1302
|
}
|
|
@@ -662,17 +1306,19 @@ var NostrTransportProvider = class {
|
|
|
662
1306
|
}
|
|
663
1307
|
}
|
|
664
1308
|
async disconnect() {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
this.
|
|
1309
|
+
if (this.nostrClient) {
|
|
1310
|
+
this.nostrClient.disconnect();
|
|
1311
|
+
this.nostrClient = null;
|
|
668
1312
|
}
|
|
669
|
-
this.
|
|
1313
|
+
this.mainSubscriptionId = null;
|
|
1314
|
+
this.walletSubscriptionId = null;
|
|
1315
|
+
this.chatSubscriptionId = null;
|
|
670
1316
|
this.status = "disconnected";
|
|
671
1317
|
this.emitEvent({ type: "transport:disconnected", timestamp: Date.now() });
|
|
672
1318
|
this.log("Disconnected from all relays");
|
|
673
1319
|
}
|
|
674
1320
|
isConnected() {
|
|
675
|
-
return this.status === "connected" && this.
|
|
1321
|
+
return this.status === "connected" && this.nostrClient?.isConnected() === true;
|
|
676
1322
|
}
|
|
677
1323
|
getStatus() {
|
|
678
1324
|
return this.status;
|
|
@@ -690,7 +1336,8 @@ var NostrTransportProvider = class {
|
|
|
690
1336
|
* Get list of currently connected relay URLs
|
|
691
1337
|
*/
|
|
692
1338
|
getConnectedRelays() {
|
|
693
|
-
|
|
1339
|
+
if (!this.nostrClient) return [];
|
|
1340
|
+
return Array.from(this.nostrClient.getConnectedRelays());
|
|
694
1341
|
}
|
|
695
1342
|
/**
|
|
696
1343
|
* Add a new relay dynamically
|
|
@@ -702,9 +1349,9 @@ var NostrTransportProvider = class {
|
|
|
702
1349
|
return false;
|
|
703
1350
|
}
|
|
704
1351
|
this.config.relays.push(relayUrl);
|
|
705
|
-
if (this.status === "connected") {
|
|
1352
|
+
if (this.status === "connected" && this.nostrClient) {
|
|
706
1353
|
try {
|
|
707
|
-
await this.
|
|
1354
|
+
await this.nostrClient.connect(relayUrl);
|
|
708
1355
|
this.log("Added and connected to relay:", relayUrl);
|
|
709
1356
|
this.emitEvent({
|
|
710
1357
|
type: "transport:relay_added",
|
|
@@ -732,6 +1379,8 @@ var NostrTransportProvider = class {
|
|
|
732
1379
|
/**
|
|
733
1380
|
* Remove a relay dynamically
|
|
734
1381
|
* Will disconnect from the relay if connected
|
|
1382
|
+
* NOTE: NostrClient doesn't support removing individual relays at runtime.
|
|
1383
|
+
* We remove from config so it won't be used on next connect().
|
|
735
1384
|
*/
|
|
736
1385
|
async removeRelay(relayUrl) {
|
|
737
1386
|
const index = this.config.relays.indexOf(relayUrl);
|
|
@@ -740,19 +1389,13 @@ var NostrTransportProvider = class {
|
|
|
740
1389
|
return false;
|
|
741
1390
|
}
|
|
742
1391
|
this.config.relays.splice(index, 1);
|
|
743
|
-
|
|
744
|
-
if (ws) {
|
|
745
|
-
ws.close();
|
|
746
|
-
this.connections.delete(relayUrl);
|
|
747
|
-
this.reconnectAttempts.delete(relayUrl);
|
|
748
|
-
this.log("Removed and disconnected from relay:", relayUrl);
|
|
749
|
-
}
|
|
1392
|
+
this.log("Removed relay from config:", relayUrl);
|
|
750
1393
|
this.emitEvent({
|
|
751
1394
|
type: "transport:relay_removed",
|
|
752
1395
|
timestamp: Date.now(),
|
|
753
1396
|
data: { relay: relayUrl }
|
|
754
1397
|
});
|
|
755
|
-
if (this.
|
|
1398
|
+
if (this.nostrClient && !this.nostrClient.isConnected() && this.status === "connected") {
|
|
756
1399
|
this.status = "error";
|
|
757
1400
|
this.emitEvent({
|
|
758
1401
|
type: "transport:error",
|
|
@@ -772,19 +1415,49 @@ var NostrTransportProvider = class {
|
|
|
772
1415
|
* Check if a relay is currently connected
|
|
773
1416
|
*/
|
|
774
1417
|
isRelayConnected(relayUrl) {
|
|
775
|
-
|
|
776
|
-
return
|
|
1418
|
+
if (!this.nostrClient) return false;
|
|
1419
|
+
return this.nostrClient.getConnectedRelays().has(relayUrl);
|
|
777
1420
|
}
|
|
778
1421
|
// ===========================================================================
|
|
779
1422
|
// TransportProvider Implementation
|
|
780
1423
|
// ===========================================================================
|
|
781
1424
|
setIdentity(identity) {
|
|
782
1425
|
this.identity = identity;
|
|
783
|
-
const secretKey =
|
|
1426
|
+
const secretKey = Buffer2.from(identity.privateKey, "hex");
|
|
784
1427
|
this.keyManager = NostrKeyManager.fromPrivateKey(secretKey);
|
|
785
1428
|
const nostrPubkey = this.keyManager.getPublicKeyHex();
|
|
786
1429
|
this.log("Identity set, Nostr pubkey:", nostrPubkey.slice(0, 16) + "...");
|
|
787
|
-
if (this.
|
|
1430
|
+
if (this.nostrClient && this.status === "connected") {
|
|
1431
|
+
this.log("Identity changed while connected - recreating NostrClient");
|
|
1432
|
+
const oldClient = this.nostrClient;
|
|
1433
|
+
this.nostrClient = new NostrClient(this.keyManager, {
|
|
1434
|
+
autoReconnect: this.config.autoReconnect,
|
|
1435
|
+
reconnectIntervalMs: this.config.reconnectDelay,
|
|
1436
|
+
maxReconnectIntervalMs: this.config.reconnectDelay * 16,
|
|
1437
|
+
pingIntervalMs: 15e3
|
|
1438
|
+
// 15 second keepalive pings
|
|
1439
|
+
});
|
|
1440
|
+
this.nostrClient.addConnectionListener({
|
|
1441
|
+
onConnect: (url) => {
|
|
1442
|
+
this.log("NostrClient connected to relay:", url);
|
|
1443
|
+
},
|
|
1444
|
+
onDisconnect: (url, reason) => {
|
|
1445
|
+
this.log("NostrClient disconnected from relay:", url, "reason:", reason);
|
|
1446
|
+
},
|
|
1447
|
+
onReconnecting: (url, attempt) => {
|
|
1448
|
+
this.log("NostrClient reconnecting to relay:", url, "attempt:", attempt);
|
|
1449
|
+
},
|
|
1450
|
+
onReconnected: (url) => {
|
|
1451
|
+
this.log("NostrClient reconnected to relay:", url);
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
this.nostrClient.connect(...this.config.relays).then(() => {
|
|
1455
|
+
this.subscribeToEvents();
|
|
1456
|
+
oldClient.disconnect();
|
|
1457
|
+
}).catch((err) => {
|
|
1458
|
+
this.log("Failed to reconnect with new identity:", err);
|
|
1459
|
+
});
|
|
1460
|
+
} else if (this.isConnected()) {
|
|
788
1461
|
this.subscribeToEvents();
|
|
789
1462
|
}
|
|
790
1463
|
}
|
|
@@ -800,18 +1473,17 @@ var NostrTransportProvider = class {
|
|
|
800
1473
|
}
|
|
801
1474
|
async sendMessage(recipientPubkey, content) {
|
|
802
1475
|
this.ensureReady();
|
|
803
|
-
const
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
);
|
|
808
|
-
await this.publishEvent(event);
|
|
1476
|
+
const nostrRecipient = recipientPubkey.length === 66 && (recipientPubkey.startsWith("02") || recipientPubkey.startsWith("03")) ? recipientPubkey.slice(2) : recipientPubkey;
|
|
1477
|
+
const senderNametag = this.identity?.nametag;
|
|
1478
|
+
const wrappedContent = senderNametag ? JSON.stringify({ senderNametag, text: content }) : content;
|
|
1479
|
+
const giftWrap = NIP17.createGiftWrap(this.keyManager, nostrRecipient, wrappedContent);
|
|
1480
|
+
await this.publishEvent(giftWrap);
|
|
809
1481
|
this.emitEvent({
|
|
810
1482
|
type: "message:sent",
|
|
811
1483
|
timestamp: Date.now(),
|
|
812
1484
|
data: { recipient: recipientPubkey }
|
|
813
1485
|
});
|
|
814
|
-
return
|
|
1486
|
+
return giftWrap.id;
|
|
815
1487
|
}
|
|
816
1488
|
onMessage(handler) {
|
|
817
1489
|
this.messageHandlers.add(handler);
|
|
@@ -928,6 +1600,118 @@ var NostrTransportProvider = class {
|
|
|
928
1600
|
if (pubkeyTag?.[1]) return pubkeyTag[1];
|
|
929
1601
|
return null;
|
|
930
1602
|
}
|
|
1603
|
+
async resolveNametagInfo(nametag) {
|
|
1604
|
+
this.ensureReady();
|
|
1605
|
+
const hashedNametag = hashNametag(nametag);
|
|
1606
|
+
let events = await this.queryEvents({
|
|
1607
|
+
kinds: [EVENT_KINDS.NAMETAG_BINDING],
|
|
1608
|
+
"#t": [hashedNametag],
|
|
1609
|
+
limit: 1
|
|
1610
|
+
});
|
|
1611
|
+
if (events.length === 0) {
|
|
1612
|
+
events = await this.queryEvents({
|
|
1613
|
+
kinds: [EVENT_KINDS.NAMETAG_BINDING],
|
|
1614
|
+
"#d": [hashedNametag],
|
|
1615
|
+
limit: 1
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
if (events.length === 0) return null;
|
|
1619
|
+
const bindingEvent = events[0];
|
|
1620
|
+
try {
|
|
1621
|
+
const content = JSON.parse(bindingEvent.content);
|
|
1622
|
+
if (content.public_key && content.l1_address) {
|
|
1623
|
+
const l3Address = `PROXY:${hashedNametag}`;
|
|
1624
|
+
return {
|
|
1625
|
+
nametag,
|
|
1626
|
+
transportPubkey: bindingEvent.pubkey,
|
|
1627
|
+
chainPubkey: content.public_key,
|
|
1628
|
+
l1Address: content.l1_address,
|
|
1629
|
+
directAddress: content.direct_address || "",
|
|
1630
|
+
proxyAddress: l3Address,
|
|
1631
|
+
timestamp: bindingEvent.created_at * 1e3
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
this.log("Legacy nametag event without extended fields:", nametag);
|
|
1635
|
+
const pubkeyTag = bindingEvent.tags.find((t) => t[0] === "pubkey");
|
|
1636
|
+
const l1Tag = bindingEvent.tags.find((t) => t[0] === "l1");
|
|
1637
|
+
if (pubkeyTag?.[1] && l1Tag?.[1]) {
|
|
1638
|
+
const l3Address = `PROXY:${hashedNametag}`;
|
|
1639
|
+
return {
|
|
1640
|
+
nametag,
|
|
1641
|
+
transportPubkey: bindingEvent.pubkey,
|
|
1642
|
+
chainPubkey: pubkeyTag[1],
|
|
1643
|
+
l1Address: l1Tag[1],
|
|
1644
|
+
directAddress: "",
|
|
1645
|
+
proxyAddress: l3Address,
|
|
1646
|
+
timestamp: bindingEvent.created_at * 1e3
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
return {
|
|
1650
|
+
nametag,
|
|
1651
|
+
transportPubkey: bindingEvent.pubkey,
|
|
1652
|
+
chainPubkey: "",
|
|
1653
|
+
// Cannot derive from 32-byte Nostr pubkey
|
|
1654
|
+
l1Address: "",
|
|
1655
|
+
// Cannot derive without 33-byte pubkey
|
|
1656
|
+
directAddress: "",
|
|
1657
|
+
proxyAddress: `PROXY:${hashedNametag}`,
|
|
1658
|
+
timestamp: bindingEvent.created_at * 1e3
|
|
1659
|
+
};
|
|
1660
|
+
} catch {
|
|
1661
|
+
return {
|
|
1662
|
+
nametag,
|
|
1663
|
+
transportPubkey: bindingEvent.pubkey,
|
|
1664
|
+
chainPubkey: "",
|
|
1665
|
+
l1Address: "",
|
|
1666
|
+
directAddress: "",
|
|
1667
|
+
proxyAddress: `PROXY:${hashedNametag}`,
|
|
1668
|
+
timestamp: bindingEvent.created_at * 1e3
|
|
1669
|
+
};
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
/**
|
|
1673
|
+
* Recover nametag for the current identity by searching for encrypted nametag events
|
|
1674
|
+
* Used after wallet import to recover associated nametag
|
|
1675
|
+
* @returns Decrypted nametag or null if none found
|
|
1676
|
+
*/
|
|
1677
|
+
async recoverNametag() {
|
|
1678
|
+
this.ensureReady();
|
|
1679
|
+
if (!this.identity || !this.keyManager) {
|
|
1680
|
+
throw new Error("Identity not set");
|
|
1681
|
+
}
|
|
1682
|
+
const nostrPubkey = this.getNostrPubkey();
|
|
1683
|
+
this.log("Searching for nametag events for pubkey:", nostrPubkey.slice(0, 16) + "...");
|
|
1684
|
+
const events = await this.queryEvents({
|
|
1685
|
+
kinds: [EVENT_KINDS.NAMETAG_BINDING],
|
|
1686
|
+
authors: [nostrPubkey],
|
|
1687
|
+
limit: 10
|
|
1688
|
+
// Get recent events in case of updates
|
|
1689
|
+
});
|
|
1690
|
+
if (events.length === 0) {
|
|
1691
|
+
this.log("No nametag events found for this pubkey");
|
|
1692
|
+
return null;
|
|
1693
|
+
}
|
|
1694
|
+
events.sort((a, b) => b.created_at - a.created_at);
|
|
1695
|
+
for (const event of events) {
|
|
1696
|
+
try {
|
|
1697
|
+
const content = JSON.parse(event.content);
|
|
1698
|
+
if (content.encrypted_nametag) {
|
|
1699
|
+
const decrypted = await decryptNametag(
|
|
1700
|
+
content.encrypted_nametag,
|
|
1701
|
+
this.identity.privateKey
|
|
1702
|
+
);
|
|
1703
|
+
if (decrypted) {
|
|
1704
|
+
this.log("Recovered nametag:", decrypted);
|
|
1705
|
+
return decrypted;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
} catch {
|
|
1709
|
+
continue;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
this.log("Could not decrypt nametag from any event");
|
|
1713
|
+
return null;
|
|
1714
|
+
}
|
|
931
1715
|
async publishNametag(nametag, address) {
|
|
932
1716
|
this.ensureReady();
|
|
933
1717
|
const hashedNametag = hashNametag(nametag);
|
|
@@ -938,8 +1722,11 @@ var NostrTransportProvider = class {
|
|
|
938
1722
|
await this.publishEvent(event);
|
|
939
1723
|
this.log("Published nametag binding:", nametag);
|
|
940
1724
|
}
|
|
941
|
-
async registerNametag(nametag, _publicKey) {
|
|
1725
|
+
async registerNametag(nametag, _publicKey, directAddress = "") {
|
|
942
1726
|
this.ensureReady();
|
|
1727
|
+
if (!this.identity) {
|
|
1728
|
+
throw new Error("Identity not set");
|
|
1729
|
+
}
|
|
943
1730
|
const nostrPubkey = this.getNostrPubkey();
|
|
944
1731
|
const existing = await this.resolveNametag(nametag);
|
|
945
1732
|
this.log("registerNametag:", nametag, "existing:", existing, "myPubkey:", nostrPubkey);
|
|
@@ -947,27 +1734,42 @@ var NostrTransportProvider = class {
|
|
|
947
1734
|
this.log("Nametag already taken:", nametag, "- owner:", existing);
|
|
948
1735
|
return false;
|
|
949
1736
|
}
|
|
1737
|
+
const privateKeyHex = this.identity.privateKey;
|
|
1738
|
+
const compressedPubkey = getPublicKey(privateKeyHex, true);
|
|
1739
|
+
const l1Address = publicKeyToAddress(compressedPubkey, "alpha");
|
|
1740
|
+
const encryptedNametag = await encryptNametag(nametag, privateKeyHex);
|
|
950
1741
|
const hashedNametag = hashNametag(nametag);
|
|
951
1742
|
const content = JSON.stringify({
|
|
952
1743
|
nametag_hash: hashedNametag,
|
|
953
1744
|
address: nostrPubkey,
|
|
954
|
-
verified: Date.now()
|
|
1745
|
+
verified: Date.now(),
|
|
1746
|
+
// Extended fields for nametag recovery and address lookup
|
|
1747
|
+
encrypted_nametag: encryptedNametag,
|
|
1748
|
+
public_key: compressedPubkey,
|
|
1749
|
+
l1_address: l1Address,
|
|
1750
|
+
direct_address: directAddress
|
|
955
1751
|
});
|
|
956
1752
|
const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, [
|
|
957
1753
|
["d", hashedNametag],
|
|
958
1754
|
["nametag", hashedNametag],
|
|
959
1755
|
["t", hashedNametag],
|
|
960
|
-
["address", nostrPubkey]
|
|
1756
|
+
["address", nostrPubkey],
|
|
1757
|
+
// Extended tags for indexing
|
|
1758
|
+
["pubkey", compressedPubkey],
|
|
1759
|
+
["l1", l1Address]
|
|
961
1760
|
]);
|
|
962
1761
|
await this.publishEvent(event);
|
|
963
|
-
this.log("Registered nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...");
|
|
1762
|
+
this.log("Registered nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...", "l1:", l1Address.slice(0, 12) + "...");
|
|
964
1763
|
return true;
|
|
965
1764
|
}
|
|
1765
|
+
// Track broadcast subscriptions
|
|
1766
|
+
broadcastSubscriptions = /* @__PURE__ */ new Map();
|
|
1767
|
+
// key -> subId
|
|
966
1768
|
subscribeToBroadcast(tags, handler) {
|
|
967
1769
|
const key = tags.sort().join(":");
|
|
968
1770
|
if (!this.broadcastHandlers.has(key)) {
|
|
969
1771
|
this.broadcastHandlers.set(key, /* @__PURE__ */ new Set());
|
|
970
|
-
if (this.isConnected()) {
|
|
1772
|
+
if (this.isConnected() && this.nostrClient) {
|
|
971
1773
|
this.subscribeToTags(tags);
|
|
972
1774
|
}
|
|
973
1775
|
}
|
|
@@ -976,6 +1778,11 @@ var NostrTransportProvider = class {
|
|
|
976
1778
|
this.broadcastHandlers.get(key)?.delete(handler);
|
|
977
1779
|
if (this.broadcastHandlers.get(key)?.size === 0) {
|
|
978
1780
|
this.broadcastHandlers.delete(key);
|
|
1781
|
+
const subId = this.broadcastSubscriptions.get(key);
|
|
1782
|
+
if (subId && this.nostrClient) {
|
|
1783
|
+
this.nostrClient.unsubscribe(subId);
|
|
1784
|
+
this.broadcastSubscriptions.delete(key);
|
|
1785
|
+
}
|
|
979
1786
|
}
|
|
980
1787
|
};
|
|
981
1788
|
}
|
|
@@ -994,81 +1801,19 @@ var NostrTransportProvider = class {
|
|
|
994
1801
|
return () => this.eventCallbacks.delete(callback);
|
|
995
1802
|
}
|
|
996
1803
|
// ===========================================================================
|
|
997
|
-
// Private: Connection Management
|
|
998
|
-
// ===========================================================================
|
|
999
|
-
async connectToRelay(url) {
|
|
1000
|
-
return new Promise((resolve, reject) => {
|
|
1001
|
-
const ws = this.config.createWebSocket(url);
|
|
1002
|
-
const timeout = setTimeout(() => {
|
|
1003
|
-
ws.close();
|
|
1004
|
-
reject(new Error(`Connection timeout: ${url}`));
|
|
1005
|
-
}, this.config.timeout);
|
|
1006
|
-
ws.onopen = () => {
|
|
1007
|
-
clearTimeout(timeout);
|
|
1008
|
-
this.connections.set(url, ws);
|
|
1009
|
-
this.reconnectAttempts.set(url, 0);
|
|
1010
|
-
this.log("Connected to relay:", url);
|
|
1011
|
-
resolve();
|
|
1012
|
-
};
|
|
1013
|
-
ws.onerror = (error) => {
|
|
1014
|
-
clearTimeout(timeout);
|
|
1015
|
-
this.log("Relay error:", url, error);
|
|
1016
|
-
reject(error);
|
|
1017
|
-
};
|
|
1018
|
-
ws.onclose = () => {
|
|
1019
|
-
this.connections.delete(url);
|
|
1020
|
-
if (this.config.autoReconnect && this.status === "connected") {
|
|
1021
|
-
this.scheduleReconnect(url);
|
|
1022
|
-
}
|
|
1023
|
-
};
|
|
1024
|
-
ws.onmessage = (event) => {
|
|
1025
|
-
this.handleRelayMessage(url, event.data);
|
|
1026
|
-
};
|
|
1027
|
-
});
|
|
1028
|
-
}
|
|
1029
|
-
scheduleReconnect(url) {
|
|
1030
|
-
const attempts = this.reconnectAttempts.get(url) ?? 0;
|
|
1031
|
-
if (attempts >= this.config.maxReconnectAttempts) {
|
|
1032
|
-
this.log("Max reconnect attempts reached for:", url);
|
|
1033
|
-
return;
|
|
1034
|
-
}
|
|
1035
|
-
this.reconnectAttempts.set(url, attempts + 1);
|
|
1036
|
-
const delay = this.config.reconnectDelay * Math.pow(2, attempts);
|
|
1037
|
-
this.emitEvent({ type: "transport:reconnecting", timestamp: Date.now() });
|
|
1038
|
-
setTimeout(() => {
|
|
1039
|
-
this.connectToRelay(url).catch(() => {
|
|
1040
|
-
});
|
|
1041
|
-
}, delay);
|
|
1042
|
-
}
|
|
1043
|
-
// ===========================================================================
|
|
1044
1804
|
// Private: Message Handling
|
|
1045
1805
|
// ===========================================================================
|
|
1046
|
-
handleRelayMessage(relay, data) {
|
|
1047
|
-
try {
|
|
1048
|
-
const message = JSON.parse(data);
|
|
1049
|
-
const [type, ...args] = message;
|
|
1050
|
-
switch (type) {
|
|
1051
|
-
case "EVENT":
|
|
1052
|
-
this.handleEvent(args[1]);
|
|
1053
|
-
break;
|
|
1054
|
-
case "EOSE":
|
|
1055
|
-
break;
|
|
1056
|
-
case "OK":
|
|
1057
|
-
break;
|
|
1058
|
-
case "NOTICE":
|
|
1059
|
-
this.log("Relay notice:", relay, args[0]);
|
|
1060
|
-
break;
|
|
1061
|
-
}
|
|
1062
|
-
} catch (error) {
|
|
1063
|
-
this.log("Failed to parse relay message:", error);
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
1806
|
async handleEvent(event) {
|
|
1807
|
+
this.log("Processing event kind:", event.kind, "id:", event.id?.slice(0, 12));
|
|
1067
1808
|
try {
|
|
1068
1809
|
switch (event.kind) {
|
|
1069
1810
|
case EVENT_KINDS.DIRECT_MESSAGE:
|
|
1070
1811
|
await this.handleDirectMessage(event);
|
|
1071
1812
|
break;
|
|
1813
|
+
case EventKinds.GIFT_WRAP:
|
|
1814
|
+
this.log("Handling gift wrap (NIP-17 DM)");
|
|
1815
|
+
await this.handleGiftWrap(event);
|
|
1816
|
+
break;
|
|
1072
1817
|
case EVENT_KINDS.TOKEN_TRANSFER:
|
|
1073
1818
|
await this.handleTokenTransfer(event);
|
|
1074
1819
|
break;
|
|
@@ -1087,23 +1832,54 @@ var NostrTransportProvider = class {
|
|
|
1087
1832
|
}
|
|
1088
1833
|
}
|
|
1089
1834
|
async handleDirectMessage(event) {
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1835
|
+
this.log("Ignoring NIP-04 kind 4 event (DMs use NIP-17):", event.id?.slice(0, 12));
|
|
1836
|
+
}
|
|
1837
|
+
async handleGiftWrap(event) {
|
|
1838
|
+
if (!this.identity || !this.keyManager) {
|
|
1839
|
+
this.log("handleGiftWrap: no identity/keyManager");
|
|
1840
|
+
return;
|
|
1841
|
+
}
|
|
1842
|
+
try {
|
|
1843
|
+
const pm = NIP17.unwrap(event, this.keyManager);
|
|
1844
|
+
this.log("Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
|
|
1845
|
+
if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
|
|
1846
|
+
this.log("Skipping own message");
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1849
|
+
if (pm.kind !== EventKinds.CHAT_MESSAGE) {
|
|
1850
|
+
this.log("Skipping non-chat message, kind:", pm.kind);
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
let content = pm.content;
|
|
1854
|
+
let senderNametag;
|
|
1102
1855
|
try {
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1856
|
+
const parsed = JSON.parse(content);
|
|
1857
|
+
if (typeof parsed === "object" && parsed.text !== void 0) {
|
|
1858
|
+
content = parsed.text;
|
|
1859
|
+
senderNametag = parsed.senderNametag || void 0;
|
|
1860
|
+
}
|
|
1861
|
+
} catch {
|
|
1862
|
+
}
|
|
1863
|
+
this.log("DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
|
|
1864
|
+
const message = {
|
|
1865
|
+
id: pm.eventId,
|
|
1866
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
1867
|
+
senderNametag,
|
|
1868
|
+
content,
|
|
1869
|
+
timestamp: pm.timestamp * 1e3,
|
|
1870
|
+
encrypted: true
|
|
1871
|
+
};
|
|
1872
|
+
this.emitEvent({ type: "message:received", timestamp: Date.now() });
|
|
1873
|
+
this.log("Dispatching to", this.messageHandlers.size, "handlers");
|
|
1874
|
+
for (const handler of this.messageHandlers) {
|
|
1875
|
+
try {
|
|
1876
|
+
handler(message);
|
|
1877
|
+
} catch (error) {
|
|
1878
|
+
this.log("Message handler error:", error);
|
|
1879
|
+
}
|
|
1106
1880
|
}
|
|
1881
|
+
} catch (err) {
|
|
1882
|
+
this.log("Gift wrap decrypt failed (expected if not for us):", err?.message?.slice(0, 50));
|
|
1107
1883
|
}
|
|
1108
1884
|
}
|
|
1109
1885
|
async handleTokenTransfer(event) {
|
|
@@ -1112,7 +1888,7 @@ var NostrTransportProvider = class {
|
|
|
1112
1888
|
const payload = JSON.parse(content);
|
|
1113
1889
|
const transfer = {
|
|
1114
1890
|
id: event.id,
|
|
1115
|
-
|
|
1891
|
+
senderTransportPubkey: event.pubkey,
|
|
1116
1892
|
payload,
|
|
1117
1893
|
timestamp: event.created_at * 1e3
|
|
1118
1894
|
};
|
|
@@ -1132,7 +1908,7 @@ var NostrTransportProvider = class {
|
|
|
1132
1908
|
const requestData = JSON.parse(content);
|
|
1133
1909
|
const request = {
|
|
1134
1910
|
id: event.id,
|
|
1135
|
-
|
|
1911
|
+
senderTransportPubkey: event.pubkey,
|
|
1136
1912
|
request: {
|
|
1137
1913
|
requestId: requestData.requestId,
|
|
1138
1914
|
amount: requestData.amount,
|
|
@@ -1162,7 +1938,7 @@ var NostrTransportProvider = class {
|
|
|
1162
1938
|
const responseData = JSON.parse(content);
|
|
1163
1939
|
const response = {
|
|
1164
1940
|
id: event.id,
|
|
1165
|
-
|
|
1941
|
+
responderTransportPubkey: event.pubkey,
|
|
1166
1942
|
response: {
|
|
1167
1943
|
requestId: responseData.requestId,
|
|
1168
1944
|
responseType: responseData.responseType,
|
|
@@ -1187,7 +1963,7 @@ var NostrTransportProvider = class {
|
|
|
1187
1963
|
const tags = event.tags.filter((t) => t[0] === "t").map((t) => t[1]);
|
|
1188
1964
|
const broadcast = {
|
|
1189
1965
|
id: event.id,
|
|
1190
|
-
|
|
1966
|
+
authorTransportPubkey: event.pubkey,
|
|
1191
1967
|
content: event.content,
|
|
1192
1968
|
tags,
|
|
1193
1969
|
timestamp: event.created_at * 1e3
|
|
@@ -1242,109 +2018,149 @@ var NostrTransportProvider = class {
|
|
|
1242
2018
|
return this.createEvent(kind, encrypted, tags);
|
|
1243
2019
|
}
|
|
1244
2020
|
async publishEvent(event) {
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
return;
|
|
1251
|
-
}
|
|
1252
|
-
ws.send(message);
|
|
1253
|
-
resolve();
|
|
1254
|
-
});
|
|
1255
|
-
});
|
|
1256
|
-
await Promise.any(publishPromises);
|
|
2021
|
+
if (!this.nostrClient) {
|
|
2022
|
+
throw new Error("NostrClient not initialized");
|
|
2023
|
+
}
|
|
2024
|
+
const sdkEvent = NostrEventClass.fromJSON(event);
|
|
2025
|
+
await this.nostrClient.publishEvent(sdkEvent);
|
|
1257
2026
|
}
|
|
1258
|
-
async queryEvents(
|
|
1259
|
-
if (this.
|
|
2027
|
+
async queryEvents(filterObj) {
|
|
2028
|
+
if (!this.nostrClient || !this.nostrClient.isConnected()) {
|
|
1260
2029
|
throw new Error("No connected relays");
|
|
1261
2030
|
}
|
|
1262
|
-
const queryPromises = Array.from(this.connections.values()).map(
|
|
1263
|
-
(ws) => this.queryEventsFromRelay(ws, filter)
|
|
1264
|
-
);
|
|
1265
|
-
const results = await Promise.allSettled(queryPromises);
|
|
1266
|
-
for (const result of results) {
|
|
1267
|
-
if (result.status === "fulfilled" && result.value.length > 0) {
|
|
1268
|
-
return result.value;
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
return [];
|
|
1272
|
-
}
|
|
1273
|
-
async queryEventsFromRelay(ws, filter) {
|
|
1274
|
-
const subId = this.config.generateUUID().slice(0, 8);
|
|
1275
2031
|
const events = [];
|
|
2032
|
+
const filter = new Filter(filterObj);
|
|
1276
2033
|
return new Promise((resolve) => {
|
|
1277
2034
|
const timeout = setTimeout(() => {
|
|
1278
|
-
|
|
2035
|
+
if (subId) {
|
|
2036
|
+
this.nostrClient?.unsubscribe(subId);
|
|
2037
|
+
}
|
|
1279
2038
|
resolve(events);
|
|
1280
2039
|
}, 5e3);
|
|
1281
|
-
const
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
2040
|
+
const subId = this.nostrClient.subscribe(filter, {
|
|
2041
|
+
onEvent: (event) => {
|
|
2042
|
+
events.push({
|
|
2043
|
+
id: event.id,
|
|
2044
|
+
kind: event.kind,
|
|
2045
|
+
content: event.content,
|
|
2046
|
+
tags: event.tags,
|
|
2047
|
+
pubkey: event.pubkey,
|
|
2048
|
+
created_at: event.created_at,
|
|
2049
|
+
sig: event.sig
|
|
2050
|
+
});
|
|
2051
|
+
},
|
|
2052
|
+
onEndOfStoredEvents: () => {
|
|
1292
2053
|
clearTimeout(timeout);
|
|
1293
|
-
|
|
1294
|
-
this.unsubscribeFromRelay(ws, subId);
|
|
2054
|
+
this.nostrClient?.unsubscribe(subId);
|
|
1295
2055
|
resolve(events);
|
|
1296
2056
|
}
|
|
1297
|
-
};
|
|
1298
|
-
ws.send(JSON.stringify(["REQ", subId, filter]));
|
|
2057
|
+
});
|
|
1299
2058
|
});
|
|
1300
2059
|
}
|
|
1301
|
-
unsubscribeFromRelay(ws, subId) {
|
|
1302
|
-
if (ws.readyState === WebSocketReadyState.OPEN) {
|
|
1303
|
-
ws.send(JSON.stringify(["CLOSE", subId]));
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
2060
|
// ===========================================================================
|
|
1307
2061
|
// Private: Subscriptions
|
|
1308
2062
|
// ===========================================================================
|
|
2063
|
+
// Track subscription IDs for cleanup
|
|
2064
|
+
walletSubscriptionId = null;
|
|
2065
|
+
chatSubscriptionId = null;
|
|
1309
2066
|
subscribeToEvents() {
|
|
1310
|
-
|
|
1311
|
-
|
|
2067
|
+
this.log("subscribeToEvents called, identity:", !!this.identity, "keyManager:", !!this.keyManager, "nostrClient:", !!this.nostrClient);
|
|
2068
|
+
if (!this.identity || !this.keyManager || !this.nostrClient) {
|
|
2069
|
+
this.log("subscribeToEvents: skipped - no identity, keyManager, or nostrClient");
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
if (this.walletSubscriptionId) {
|
|
2073
|
+
this.nostrClient.unsubscribe(this.walletSubscriptionId);
|
|
2074
|
+
this.walletSubscriptionId = null;
|
|
2075
|
+
}
|
|
2076
|
+
if (this.chatSubscriptionId) {
|
|
2077
|
+
this.nostrClient.unsubscribe(this.chatSubscriptionId);
|
|
2078
|
+
this.chatSubscriptionId = null;
|
|
2079
|
+
}
|
|
2080
|
+
if (this.mainSubscriptionId) {
|
|
2081
|
+
this.nostrClient.unsubscribe(this.mainSubscriptionId);
|
|
2082
|
+
this.mainSubscriptionId = null;
|
|
2083
|
+
}
|
|
1312
2084
|
const nostrPubkey = this.keyManager.getPublicKeyHex();
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
2085
|
+
this.log("Subscribing with Nostr pubkey:", nostrPubkey);
|
|
2086
|
+
const walletFilter = new Filter();
|
|
2087
|
+
walletFilter.kinds = [
|
|
2088
|
+
EVENT_KINDS.DIRECT_MESSAGE,
|
|
2089
|
+
EVENT_KINDS.TOKEN_TRANSFER,
|
|
2090
|
+
EVENT_KINDS.PAYMENT_REQUEST,
|
|
2091
|
+
EVENT_KINDS.PAYMENT_REQUEST_RESPONSE
|
|
2092
|
+
];
|
|
2093
|
+
walletFilter["#p"] = [nostrPubkey];
|
|
2094
|
+
walletFilter.since = Math.floor(Date.now() / 1e3) - 86400;
|
|
2095
|
+
this.walletSubscriptionId = this.nostrClient.subscribe(walletFilter, {
|
|
2096
|
+
onEvent: (event) => {
|
|
2097
|
+
this.log("Received wallet event kind:", event.kind, "id:", event.id?.slice(0, 12));
|
|
2098
|
+
this.handleEvent({
|
|
2099
|
+
id: event.id,
|
|
2100
|
+
kind: event.kind,
|
|
2101
|
+
content: event.content,
|
|
2102
|
+
tags: event.tags,
|
|
2103
|
+
pubkey: event.pubkey,
|
|
2104
|
+
created_at: event.created_at,
|
|
2105
|
+
sig: event.sig
|
|
2106
|
+
});
|
|
2107
|
+
},
|
|
2108
|
+
onEndOfStoredEvents: () => {
|
|
2109
|
+
this.log("Wallet subscription ready (EOSE)");
|
|
2110
|
+
},
|
|
2111
|
+
onError: (_subId, error) => {
|
|
2112
|
+
this.log("Wallet subscription error:", error);
|
|
1328
2113
|
}
|
|
1329
|
-
}
|
|
1330
|
-
this.
|
|
1331
|
-
|
|
2114
|
+
});
|
|
2115
|
+
this.log("Wallet subscription created, subId:", this.walletSubscriptionId);
|
|
2116
|
+
const chatFilter = new Filter();
|
|
2117
|
+
chatFilter.kinds = [EventKinds.GIFT_WRAP];
|
|
2118
|
+
chatFilter["#p"] = [nostrPubkey];
|
|
2119
|
+
this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {
|
|
2120
|
+
onEvent: (event) => {
|
|
2121
|
+
this.log("Received chat event kind:", event.kind, "id:", event.id?.slice(0, 12));
|
|
2122
|
+
this.handleEvent({
|
|
2123
|
+
id: event.id,
|
|
2124
|
+
kind: event.kind,
|
|
2125
|
+
content: event.content,
|
|
2126
|
+
tags: event.tags,
|
|
2127
|
+
pubkey: event.pubkey,
|
|
2128
|
+
created_at: event.created_at,
|
|
2129
|
+
sig: event.sig
|
|
2130
|
+
});
|
|
2131
|
+
},
|
|
2132
|
+
onEndOfStoredEvents: () => {
|
|
2133
|
+
this.log("Chat subscription ready (EOSE)");
|
|
2134
|
+
},
|
|
2135
|
+
onError: (_subId, error) => {
|
|
2136
|
+
this.log("Chat subscription error:", error);
|
|
2137
|
+
}
|
|
2138
|
+
});
|
|
2139
|
+
this.log("Chat subscription created, subId:", this.chatSubscriptionId);
|
|
1332
2140
|
}
|
|
1333
2141
|
subscribeToTags(tags) {
|
|
1334
|
-
|
|
1335
|
-
const
|
|
2142
|
+
if (!this.nostrClient) return;
|
|
2143
|
+
const key = tags.sort().join(":");
|
|
2144
|
+
const filter = new Filter({
|
|
1336
2145
|
kinds: [EVENT_KINDS.BROADCAST],
|
|
1337
2146
|
"#t": tags,
|
|
1338
2147
|
since: Math.floor(Date.now() / 1e3) - 3600
|
|
1339
2148
|
// Last hour
|
|
1340
|
-
};
|
|
1341
|
-
const
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
2149
|
+
});
|
|
2150
|
+
const subId = this.nostrClient.subscribe(filter, {
|
|
2151
|
+
onEvent: (event) => {
|
|
2152
|
+
this.handleBroadcast({
|
|
2153
|
+
id: event.id,
|
|
2154
|
+
kind: event.kind,
|
|
2155
|
+
content: event.content,
|
|
2156
|
+
tags: event.tags,
|
|
2157
|
+
pubkey: event.pubkey,
|
|
2158
|
+
created_at: event.created_at,
|
|
2159
|
+
sig: event.sig
|
|
2160
|
+
});
|
|
1345
2161
|
}
|
|
1346
|
-
}
|
|
1347
|
-
this.
|
|
2162
|
+
});
|
|
2163
|
+
this.broadcastSubscriptions.set(key, subId);
|
|
1348
2164
|
}
|
|
1349
2165
|
// ===========================================================================
|
|
1350
2166
|
// Private: Encryption
|
|
@@ -1800,13 +2616,70 @@ var UnicityAggregatorProvider = class {
|
|
|
1800
2616
|
};
|
|
1801
2617
|
var UnicityOracleProvider = UnicityAggregatorProvider;
|
|
1802
2618
|
|
|
2619
|
+
// assets/trustbase.ts
|
|
2620
|
+
var TRUSTBASE_TESTNET = {
|
|
2621
|
+
version: 1,
|
|
2622
|
+
networkId: 3,
|
|
2623
|
+
epoch: 1,
|
|
2624
|
+
epochStartRound: 1,
|
|
2625
|
+
rootNodes: [
|
|
2626
|
+
{
|
|
2627
|
+
nodeId: "16Uiu2HAkyQRiA7pMgzgLj9GgaBJEJa8zmx9dzqUDa6WxQPJ82ghU",
|
|
2628
|
+
sigKey: "0x039afb2acb65f5fbc272d8907f763d0a5d189aadc9b97afdcc5897ea4dd112e68b",
|
|
2629
|
+
stake: 1
|
|
2630
|
+
}
|
|
2631
|
+
],
|
|
2632
|
+
quorumThreshold: 1,
|
|
2633
|
+
stateHash: "",
|
|
2634
|
+
changeRecordHash: "",
|
|
2635
|
+
previousEntryHash: "",
|
|
2636
|
+
signatures: {
|
|
2637
|
+
"16Uiu2HAkyQRiA7pMgzgLj9GgaBJEJa8zmx9dzqUDa6WxQPJ82ghU": "0xf157c9fdd8a378e3ca70d354ccc4475ab2cd8de360127bc46b0aeab4b453a80f07fd9136a5843b60a8babaff23e20acc8879861f7651440a5e2829f7541b31f100"
|
|
2638
|
+
}
|
|
2639
|
+
};
|
|
2640
|
+
var TRUSTBASE_MAINNET = null;
|
|
2641
|
+
var TRUSTBASE_DEV = TRUSTBASE_TESTNET;
|
|
2642
|
+
|
|
2643
|
+
// impl/shared/trustbase-loader.ts
|
|
2644
|
+
function getEmbeddedTrustBase(network) {
|
|
2645
|
+
switch (network) {
|
|
2646
|
+
case "mainnet":
|
|
2647
|
+
return TRUSTBASE_MAINNET;
|
|
2648
|
+
case "testnet":
|
|
2649
|
+
return TRUSTBASE_TESTNET;
|
|
2650
|
+
case "dev":
|
|
2651
|
+
return TRUSTBASE_DEV;
|
|
2652
|
+
default:
|
|
2653
|
+
return TRUSTBASE_TESTNET;
|
|
2654
|
+
}
|
|
2655
|
+
}
|
|
2656
|
+
var BaseTrustBaseLoader = class {
|
|
2657
|
+
network;
|
|
2658
|
+
constructor(network = "testnet") {
|
|
2659
|
+
this.network = network;
|
|
2660
|
+
}
|
|
2661
|
+
async load() {
|
|
2662
|
+
const external = await this.loadFromExternal();
|
|
2663
|
+
if (external) {
|
|
2664
|
+
return external;
|
|
2665
|
+
}
|
|
2666
|
+
return getEmbeddedTrustBase(this.network);
|
|
2667
|
+
}
|
|
2668
|
+
};
|
|
2669
|
+
|
|
1803
2670
|
// impl/browser/oracle/index.ts
|
|
1804
|
-
var BrowserTrustBaseLoader = class {
|
|
2671
|
+
var BrowserTrustBaseLoader = class extends BaseTrustBaseLoader {
|
|
1805
2672
|
url;
|
|
1806
|
-
constructor(
|
|
1807
|
-
|
|
2673
|
+
constructor(networkOrUrl = "testnet") {
|
|
2674
|
+
if (networkOrUrl.startsWith("/") || networkOrUrl.startsWith("http")) {
|
|
2675
|
+
super("testnet");
|
|
2676
|
+
this.url = networkOrUrl;
|
|
2677
|
+
} else {
|
|
2678
|
+
super(networkOrUrl);
|
|
2679
|
+
}
|
|
1808
2680
|
}
|
|
1809
|
-
async
|
|
2681
|
+
async loadFromExternal() {
|
|
2682
|
+
if (!this.url) return null;
|
|
1810
2683
|
try {
|
|
1811
2684
|
const response = await fetch(this.url);
|
|
1812
2685
|
if (response.ok) {
|
|
@@ -1817,14 +2690,14 @@ var BrowserTrustBaseLoader = class {
|
|
|
1817
2690
|
return null;
|
|
1818
2691
|
}
|
|
1819
2692
|
};
|
|
1820
|
-
function createBrowserTrustBaseLoader(
|
|
1821
|
-
return new BrowserTrustBaseLoader(
|
|
2693
|
+
function createBrowserTrustBaseLoader(networkOrUrl) {
|
|
2694
|
+
return new BrowserTrustBaseLoader(networkOrUrl);
|
|
1822
2695
|
}
|
|
1823
2696
|
function createUnicityAggregatorProvider(config) {
|
|
1824
|
-
const { trustBaseUrl, ...restConfig } = config;
|
|
2697
|
+
const { trustBaseUrl, network, ...restConfig } = config;
|
|
1825
2698
|
return new UnicityAggregatorProvider({
|
|
1826
2699
|
...restConfig,
|
|
1827
|
-
trustBaseLoader: createBrowserTrustBaseLoader(trustBaseUrl)
|
|
2700
|
+
trustBaseLoader: createBrowserTrustBaseLoader(trustBaseUrl ?? network ?? "testnet")
|
|
1828
2701
|
});
|
|
1829
2702
|
}
|
|
1830
2703
|
var createUnicityOracleProvider = createUnicityAggregatorProvider;
|
|
@@ -1918,7 +2791,7 @@ function resolveOracleConfig(network, config) {
|
|
|
1918
2791
|
const networkConfig = getNetworkConfig(network);
|
|
1919
2792
|
return {
|
|
1920
2793
|
url: config?.url ?? networkConfig.aggregatorUrl,
|
|
1921
|
-
apiKey: config?.apiKey,
|
|
2794
|
+
apiKey: config?.apiKey ?? DEFAULT_AGGREGATOR_API_KEY,
|
|
1922
2795
|
timeout: config?.timeout,
|
|
1923
2796
|
skipVerification: config?.skipVerification,
|
|
1924
2797
|
debug: config?.debug,
|
|
@@ -2016,7 +2889,8 @@ function createBrowserProviders(config) {
|
|
|
2016
2889
|
apiKey: oracleConfig.apiKey,
|
|
2017
2890
|
timeout: oracleConfig.timeout,
|
|
2018
2891
|
skipVerification: oracleConfig.skipVerification,
|
|
2019
|
-
debug: oracleConfig.debug
|
|
2892
|
+
debug: oracleConfig.debug,
|
|
2893
|
+
network
|
|
2020
2894
|
}),
|
|
2021
2895
|
tokenStorage: createIndexedDBTokenStorageProvider(),
|
|
2022
2896
|
l1: l1Config,
|
|
@@ -2050,4 +2924,9 @@ export {
|
|
|
2050
2924
|
readFileAsText,
|
|
2051
2925
|
readFileAsUint8Array
|
|
2052
2926
|
};
|
|
2927
|
+
/*! Bundled license information:
|
|
2928
|
+
|
|
2929
|
+
@noble/hashes/utils.js:
|
|
2930
|
+
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
2931
|
+
*/
|
|
2053
2932
|
//# sourceMappingURL=index.js.map
|