@unicitylabs/sphere-sdk 0.1.3 → 0.1.4

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.
@@ -1350,6 +1350,7 @@ var L1PaymentsModule = class {
1350
1350
  _chainCode;
1351
1351
  _addresses = [];
1352
1352
  _wallet;
1353
+ _transport;
1353
1354
  constructor(config) {
1354
1355
  this._config = {
1355
1356
  electrumUrl: config?.electrumUrl ?? "wss://fulcrum.alpha.unicity.network:50004",
@@ -1362,13 +1363,14 @@ var L1PaymentsModule = class {
1362
1363
  this._identity = deps.identity;
1363
1364
  this._chainCode = deps.chainCode;
1364
1365
  this._addresses = deps.addresses ?? [];
1366
+ this._transport = deps.transport;
1365
1367
  this._wallet = {
1366
1368
  masterPrivateKey: deps.identity.privateKey,
1367
1369
  chainCode: deps.chainCode,
1368
1370
  addresses: [
1369
1371
  {
1370
- address: deps.identity.address,
1371
- publicKey: deps.identity.publicKey,
1372
+ address: deps.identity.l1Address,
1373
+ publicKey: deps.identity.chainPubkey,
1372
1374
  privateKey: deps.identity.privateKey,
1373
1375
  path: "m/0",
1374
1376
  index: 0
@@ -1376,7 +1378,7 @@ var L1PaymentsModule = class {
1376
1378
  ]
1377
1379
  };
1378
1380
  for (const addr of this._addresses) {
1379
- if (addr !== deps.identity.address) {
1381
+ if (addr !== deps.identity.l1Address) {
1380
1382
  this._wallet.addresses.push({
1381
1383
  address: addr,
1382
1384
  path: null,
@@ -1399,18 +1401,64 @@ var L1PaymentsModule = class {
1399
1401
  this._addresses = [];
1400
1402
  this._wallet = void 0;
1401
1403
  }
1404
+ /**
1405
+ * Check if a string looks like an L1 address (alpha1... or alphat1...)
1406
+ */
1407
+ isL1Address(value) {
1408
+ return value.startsWith("alpha1") || value.startsWith("alphat1");
1409
+ }
1410
+ /**
1411
+ * Resolve recipient to L1 address
1412
+ * Supports: L1 address (alpha1...), nametag (with or without @)
1413
+ */
1414
+ async resolveL1Address(recipient) {
1415
+ if (recipient.startsWith("@")) {
1416
+ const nametag = recipient.slice(1);
1417
+ return this.resolveNametagToL1Address(nametag);
1418
+ }
1419
+ if (this.isL1Address(recipient)) {
1420
+ return recipient;
1421
+ }
1422
+ try {
1423
+ const l1Address = await this.resolveNametagToL1Address(recipient);
1424
+ return l1Address;
1425
+ } catch {
1426
+ throw new Error(
1427
+ `Recipient "${recipient}" is not a valid nametag or L1 address. Use @nametag for explicit nametag or a valid alpha1... address.`
1428
+ );
1429
+ }
1430
+ }
1431
+ /**
1432
+ * Resolve nametag to L1 address using transport provider
1433
+ */
1434
+ async resolveNametagToL1Address(nametag) {
1435
+ if (!this._transport?.resolveNametagInfo) {
1436
+ throw new Error("Transport provider does not support nametag resolution");
1437
+ }
1438
+ const info = await this._transport.resolveNametagInfo(nametag);
1439
+ if (!info) {
1440
+ throw new Error(`Nametag not found: ${nametag}`);
1441
+ }
1442
+ if (!info.l1Address) {
1443
+ throw new Error(
1444
+ `Nametag @${nametag} does not have L1 address information. The owner needs to update their nametag registration.`
1445
+ );
1446
+ }
1447
+ return info.l1Address;
1448
+ }
1402
1449
  async send(request) {
1403
1450
  this.ensureInitialized();
1404
1451
  if (!this._wallet || !this._identity) {
1405
1452
  return { success: false, error: "No wallet available" };
1406
1453
  }
1407
1454
  try {
1455
+ const recipientAddress = await this.resolveL1Address(request.to);
1408
1456
  const amountAlpha = parseInt(request.amount, 10) / 1e8;
1409
1457
  const results = await sendAlpha(
1410
1458
  this._wallet,
1411
- request.to,
1459
+ recipientAddress,
1412
1460
  amountAlpha,
1413
- this._identity.address
1461
+ this._identity.l1Address
1414
1462
  );
1415
1463
  if (results && results.length > 0) {
1416
1464
  const txids = results.map((r) => r.txid);
@@ -1632,8 +1680,8 @@ var L1PaymentsModule = class {
1632
1680
  }
1633
1681
  _getWatchedAddresses() {
1634
1682
  const addresses = [...this._addresses];
1635
- if (this._identity?.address && !addresses.includes(this._identity.address)) {
1636
- addresses.unshift(this._identity.address);
1683
+ if (this._identity?.l1Address && !addresses.includes(this._identity.l1Address)) {
1684
+ addresses.unshift(this._identity.l1Address);
1637
1685
  }
1638
1686
  return addresses;
1639
1687
  }
@@ -2475,12 +2523,10 @@ function getCurrentStateHash(txf) {
2475
2523
 
2476
2524
  // modules/payments/PaymentsModule.ts
2477
2525
  import { Token as SdkToken2 } from "@unicitylabs/state-transition-sdk/lib/token/Token";
2478
- import { TokenId as TokenId3 } from "@unicitylabs/state-transition-sdk/lib/token/TokenId";
2479
2526
  import { CoinId as CoinId3 } from "@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId";
2480
2527
  import { TransferCommitment as TransferCommitment2 } from "@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment";
2481
2528
  import { TransferTransaction } from "@unicitylabs/state-transition-sdk/lib/transaction/TransferTransaction";
2482
2529
  import { SigningService } from "@unicitylabs/state-transition-sdk/lib/sign/SigningService";
2483
- import { ProxyAddress } from "@unicitylabs/state-transition-sdk/lib/address/ProxyAddress";
2484
2530
  import { AddressScheme } from "@unicitylabs/state-transition-sdk/lib/address/AddressScheme";
2485
2531
  import { UnmaskedPredicate as UnmaskedPredicate3 } from "@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate";
2486
2532
  import { TokenState as TokenState3 } from "@unicitylabs/state-transition-sdk/lib/token/TokenState";
@@ -2771,7 +2817,8 @@ var PaymentsModule = class {
2771
2817
  this.l1.initialize({
2772
2818
  identity: deps.identity,
2773
2819
  chainCode: deps.chainCode,
2774
- addresses: deps.l1Addresses
2820
+ addresses: deps.l1Addresses,
2821
+ transport: deps.transport
2775
2822
  });
2776
2823
  }
2777
2824
  this.unsubscribeTransfers = deps.transport.onTokenTransfer((transfer) => {
@@ -3168,7 +3215,7 @@ var PaymentsModule = class {
3168
3215
  }
3169
3216
  const request = {
3170
3217
  id: transportRequest.id,
3171
- senderPubkey: transportRequest.senderPubkey,
3218
+ senderPubkey: transportRequest.senderTransportPubkey,
3172
3219
  amount: transportRequest.request.amount,
3173
3220
  coinId: transportRequest.request.coinId,
3174
3221
  symbol: transportRequest.request.coinId,
@@ -3280,7 +3327,7 @@ var PaymentsModule = class {
3280
3327
  }
3281
3328
  const response = {
3282
3329
  id: transportResponse.id,
3283
- responderPubkey: transportResponse.responderPubkey,
3330
+ responderPubkey: transportResponse.responderTransportPubkey,
3284
3331
  requestId: transportResponse.response.requestId,
3285
3332
  responseType: transportResponse.response.responseType,
3286
3333
  message: transportResponse.response.message,
@@ -4034,6 +4081,23 @@ var PaymentsModule = class {
4034
4081
  // ===========================================================================
4035
4082
  // Private: Transfer Operations
4036
4083
  // ===========================================================================
4084
+ /**
4085
+ * Detect if a string is an L3 address (not a nametag)
4086
+ * Returns true for: hex pubkeys (64+ chars), PROXY:, DIRECT: prefixed addresses
4087
+ */
4088
+ isL3Address(value) {
4089
+ if (value.startsWith("PROXY:") || value.startsWith("DIRECT:")) {
4090
+ return true;
4091
+ }
4092
+ if (value.length >= 64 && /^[0-9a-fA-F]+$/.test(value)) {
4093
+ return true;
4094
+ }
4095
+ return false;
4096
+ }
4097
+ /**
4098
+ * Resolve recipient to Nostr pubkey for messaging
4099
+ * Supports: nametag (with or without @), hex pubkey
4100
+ */
4037
4101
  async resolveRecipient(recipient) {
4038
4102
  if (recipient.startsWith("@")) {
4039
4103
  const nametag = recipient.slice(1);
@@ -4043,7 +4107,19 @@ var PaymentsModule = class {
4043
4107
  }
4044
4108
  return pubkey;
4045
4109
  }
4046
- return recipient;
4110
+ if (this.isL3Address(recipient)) {
4111
+ return recipient;
4112
+ }
4113
+ if (this.deps?.transport.resolveNametag) {
4114
+ const pubkey = await this.deps.transport.resolveNametag(recipient);
4115
+ if (pubkey) {
4116
+ this.log(`Resolved "${recipient}" as nametag to pubkey`);
4117
+ return pubkey;
4118
+ }
4119
+ }
4120
+ throw new Error(
4121
+ `Recipient "${recipient}" is not a valid nametag or address. Use @nametag for explicit nametag or a valid hex pubkey/PROXY:/DIRECT: address.`
4122
+ );
4047
4123
  }
4048
4124
  /**
4049
4125
  * Create SDK TransferCommitment for a token transfer
@@ -4075,19 +4151,74 @@ var PaymentsModule = class {
4075
4151
  return SigningService.createFromSecret(privateKeyBytes);
4076
4152
  }
4077
4153
  /**
4078
- * Resolve recipient to IAddress
4154
+ * Create DirectAddress from a public key using UnmaskedPredicateReference
4155
+ */
4156
+ async createDirectAddressFromPubkey(pubkeyHex) {
4157
+ const { UnmaskedPredicateReference: UnmaskedPredicateReference3 } = await import("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference");
4158
+ const { TokenType: TokenType3 } = await import("@unicitylabs/state-transition-sdk/lib/token/TokenType");
4159
+ const UNICITY_TOKEN_TYPE_HEX3 = "f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509";
4160
+ const tokenType = new TokenType3(Buffer.from(UNICITY_TOKEN_TYPE_HEX3, "hex"));
4161
+ const pubkeyBytes = new Uint8Array(
4162
+ pubkeyHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
4163
+ );
4164
+ const addressRef = await UnmaskedPredicateReference3.create(
4165
+ tokenType,
4166
+ "secp256k1",
4167
+ pubkeyBytes,
4168
+ HashAlgorithm3.SHA256
4169
+ );
4170
+ return addressRef.toAddress();
4171
+ }
4172
+ /**
4173
+ * Resolve nametag to 33-byte compressed public key using resolveNametagInfo
4174
+ * Returns null if nametag not found or publicKey not available
4175
+ */
4176
+ async resolveNametagToPublicKey(nametag) {
4177
+ if (!this.deps?.transport.resolveNametagInfo) {
4178
+ this.log("resolveNametagInfo not available on transport");
4179
+ return null;
4180
+ }
4181
+ const info = await this.deps.transport.resolveNametagInfo(nametag);
4182
+ if (!info) {
4183
+ this.log(`Nametag "${nametag}" not found`);
4184
+ return null;
4185
+ }
4186
+ if (!info.chainPubkey) {
4187
+ this.log(`Nametag "${nametag}" has no 33-byte chainPubkey (legacy event)`);
4188
+ return null;
4189
+ }
4190
+ return info.chainPubkey;
4191
+ }
4192
+ /**
4193
+ * Resolve recipient to IAddress for L3 transfers
4194
+ * Supports: nametag (with or without @), PROXY:, DIRECT:, hex pubkey
4079
4195
  */
4080
4196
  async resolveRecipientAddress(recipient) {
4197
+ const { AddressFactory } = await import("@unicitylabs/state-transition-sdk/lib/address/AddressFactory");
4081
4198
  if (recipient.startsWith("@")) {
4082
4199
  const nametag = recipient.slice(1);
4083
- const tokenId2 = await TokenId3.fromNameTag(nametag);
4084
- return ProxyAddress.fromTokenId(tokenId2);
4200
+ const publicKey2 = await this.resolveNametagToPublicKey(nametag);
4201
+ if (publicKey2) {
4202
+ this.log(`Resolved @${nametag} to 33-byte publicKey for DirectAddress`);
4203
+ return this.createDirectAddressFromPubkey(publicKey2);
4204
+ }
4205
+ throw new Error(`Nametag "${nametag}" not found or missing publicKey`);
4085
4206
  }
4086
- const pubkeyBytes = new Uint8Array(
4087
- recipient.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
4207
+ if (recipient.startsWith("PROXY:") || recipient.startsWith("DIRECT:")) {
4208
+ return AddressFactory.createAddress(recipient);
4209
+ }
4210
+ if (recipient.length === 66 && /^[0-9a-fA-F]+$/.test(recipient)) {
4211
+ this.log(`Creating DirectAddress from 33-byte compressed pubkey`);
4212
+ return this.createDirectAddressFromPubkey(recipient);
4213
+ }
4214
+ const publicKey = await this.resolveNametagToPublicKey(recipient);
4215
+ if (publicKey) {
4216
+ this.log(`Resolved "${recipient}" as nametag to 33-byte publicKey for DirectAddress`);
4217
+ return this.createDirectAddressFromPubkey(publicKey);
4218
+ }
4219
+ throw new Error(
4220
+ `Recipient "${recipient}" is not a valid nametag or L3 address. Use @nametag for explicit nametag or a valid 33-byte hex pubkey/PROXY:/DIRECT: address.`
4088
4221
  );
4089
- const tokenId = new TokenId3(pubkeyBytes.slice(0, 32));
4090
- return ProxyAddress.fromTokenId(tokenId);
4091
4222
  }
4092
4223
  async handleIncomingTransfer(transfer) {
4093
4224
  try {
@@ -4145,7 +4276,39 @@ var PaymentsModule = class {
4145
4276
  }
4146
4277
  }
4147
4278
  } else {
4148
- tokenData = sourceTokenInput;
4279
+ this.log("Finalizing DIRECT address transfer for state tracking...");
4280
+ try {
4281
+ const signingService = await this.createSigningService();
4282
+ const transferSalt = transferTx.data.salt;
4283
+ const recipientPredicate = await UnmaskedPredicate3.create(
4284
+ sourceToken.id,
4285
+ sourceToken.type,
4286
+ signingService,
4287
+ HashAlgorithm3.SHA256,
4288
+ transferSalt
4289
+ );
4290
+ const recipientState = new TokenState3(recipientPredicate, null);
4291
+ const stClient = this.deps.oracle.getStateTransitionClient?.();
4292
+ const trustBase = this.deps.oracle.getTrustBase?.();
4293
+ if (!stClient || !trustBase) {
4294
+ this.log("Cannot finalize DIRECT transfer - missing client, using source token");
4295
+ tokenData = sourceTokenInput;
4296
+ } else {
4297
+ finalizedSdkToken = await stClient.finalizeTransaction(
4298
+ trustBase,
4299
+ sourceToken,
4300
+ recipientState,
4301
+ transferTx,
4302
+ []
4303
+ // No nametag tokens needed for DIRECT
4304
+ );
4305
+ tokenData = finalizedSdkToken.toJSON();
4306
+ this.log("DIRECT transfer finalized successfully");
4307
+ }
4308
+ } catch (finalizeError) {
4309
+ this.log("DIRECT finalization failed, using source token:", finalizeError);
4310
+ tokenData = sourceTokenInput;
4311
+ }
4149
4312
  }
4150
4313
  } else if (payload.token) {
4151
4314
  tokenData = payload.token;
@@ -4179,7 +4342,7 @@ var PaymentsModule = class {
4179
4342
  await this.addToken(token);
4180
4343
  const incomingTransfer = {
4181
4344
  id: transfer.id,
4182
- senderPubkey: transfer.senderPubkey,
4345
+ senderPubkey: transfer.senderTransportPubkey,
4183
4346
  tokens: [token],
4184
4347
  memo: payload.memo,
4185
4348
  receivedAt: transfer.timestamp
@@ -4247,7 +4410,7 @@ var PaymentsModule = class {
4247
4410
  tokens,
4248
4411
  {
4249
4412
  version: 1,
4250
- address: this.deps.identity.address,
4413
+ address: this.deps.identity.l1Address,
4251
4414
  ipnsName: this.deps.identity.ipnsName ?? ""
4252
4415
  },
4253
4416
  {
@@ -4351,7 +4514,7 @@ var CommunicationsModule = class {
4351
4514
  const eventId = await this.deps.transport.sendMessage(recipientPubkey, content);
4352
4515
  const message = {
4353
4516
  id: eventId,
4354
- senderPubkey: this.deps.identity.publicKey,
4517
+ senderPubkey: this.deps.identity.chainPubkey,
4355
4518
  senderNametag: this.deps.identity.nametag,
4356
4519
  recipientPubkey,
4357
4520
  content,
@@ -4378,7 +4541,7 @@ var CommunicationsModule = class {
4378
4541
  getConversations() {
4379
4542
  const conversations = /* @__PURE__ */ new Map();
4380
4543
  for (const message of this.messages.values()) {
4381
- const peer = message.senderPubkey === this.deps?.identity.publicKey ? message.recipientPubkey : message.senderPubkey;
4544
+ const peer = message.senderPubkey === this.deps?.identity.chainPubkey ? message.recipientPubkey : message.senderPubkey;
4382
4545
  if (!conversations.has(peer)) {
4383
4546
  conversations.set(peer, []);
4384
4547
  }
@@ -4408,7 +4571,7 @@ var CommunicationsModule = class {
4408
4571
  */
4409
4572
  getUnreadCount(peerPubkey) {
4410
4573
  let messages = Array.from(this.messages.values()).filter(
4411
- (m) => !m.isRead && m.senderPubkey !== this.deps?.identity.publicKey
4574
+ (m) => !m.isRead && m.senderPubkey !== this.deps?.identity.chainPubkey
4412
4575
  );
4413
4576
  if (peerPubkey) {
4414
4577
  messages = messages.filter((m) => m.senderPubkey === peerPubkey);
@@ -4433,7 +4596,7 @@ var CommunicationsModule = class {
4433
4596
  const eventId = await this.deps.transport.publishBroadcast?.(content, tags);
4434
4597
  const message = {
4435
4598
  id: eventId ?? crypto.randomUUID(),
4436
- authorPubkey: this.deps.identity.publicKey,
4599
+ authorPubkey: this.deps.identity.chainPubkey,
4437
4600
  authorNametag: this.deps.identity.nametag,
4438
4601
  content,
4439
4602
  timestamp: Date.now(),
@@ -4484,11 +4647,12 @@ var CommunicationsModule = class {
4484
4647
  // Private: Message Handling
4485
4648
  // ===========================================================================
4486
4649
  handleIncomingMessage(msg) {
4487
- if (msg.senderPubkey === this.deps?.identity.publicKey) return;
4650
+ if (msg.senderTransportPubkey === this.deps?.identity.chainPubkey) return;
4488
4651
  const message = {
4489
4652
  id: msg.id,
4490
- senderPubkey: msg.senderPubkey,
4491
- recipientPubkey: this.deps.identity.publicKey,
4653
+ senderPubkey: msg.senderTransportPubkey,
4654
+ senderNametag: msg.senderNametag,
4655
+ recipientPubkey: this.deps.identity.chainPubkey,
4492
4656
  content: msg.content,
4493
4657
  timestamp: msg.timestamp,
4494
4658
  isRead: false
@@ -4510,7 +4674,7 @@ var CommunicationsModule = class {
4510
4674
  handleIncomingBroadcast(incoming) {
4511
4675
  const message = {
4512
4676
  id: incoming.id,
4513
- authorPubkey: incoming.authorPubkey,
4677
+ authorPubkey: incoming.authorTransportPubkey,
4514
4678
  content: incoming.content,
4515
4679
  timestamp: incoming.timestamp,
4516
4680
  tags: incoming.tags
@@ -5337,6 +5501,7 @@ import { SigningService as SigningService2 } from "@unicitylabs/state-transition
5337
5501
  import { TokenType as TokenType2 } from "@unicitylabs/state-transition-sdk/lib/token/TokenType";
5338
5502
  import { HashAlgorithm as HashAlgorithm4 } from "@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm";
5339
5503
  import { UnmaskedPredicateReference as UnmaskedPredicateReference2 } from "@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference";
5504
+ import { hashNametag } from "@unicitylabs/nostr-js-sdk";
5340
5505
  var UNICITY_TOKEN_TYPE_HEX2 = "f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509";
5341
5506
  async function deriveL3PredicateAddress(privateKey) {
5342
5507
  const secret = Buffer.from(privateKey, "hex");
@@ -5494,6 +5659,8 @@ var Sphere = class _Sphere {
5494
5659
  _Sphere.instance = sphere;
5495
5660
  if (options.nametag) {
5496
5661
  await sphere.registerNametag(options.nametag);
5662
+ } else {
5663
+ await sphere.recoverNametagFromNostr();
5497
5664
  }
5498
5665
  return sphere;
5499
5666
  }
@@ -5556,6 +5723,9 @@ var Sphere = class _Sphere {
5556
5723
  }
5557
5724
  await sphere.initializeProviders();
5558
5725
  await sphere.initializeModules();
5726
+ if (!options.nametag) {
5727
+ await sphere.recoverNametagFromNostr();
5728
+ }
5559
5729
  await sphere.finalizeWalletCreation();
5560
5730
  sphere._initialized = true;
5561
5731
  _Sphere.instance = sphere;
@@ -5629,9 +5799,9 @@ var Sphere = class _Sphere {
5629
5799
  get identity() {
5630
5800
  if (!this._identity) return null;
5631
5801
  return {
5632
- publicKey: this._identity.publicKey,
5633
- address: this._identity.address,
5634
- predicateAddress: this._identity.predicateAddress,
5802
+ chainPubkey: this._identity.chainPubkey,
5803
+ l1Address: this._identity.l1Address,
5804
+ directAddress: this._identity.directAddress,
5635
5805
  ipnsName: this._identity.ipnsName,
5636
5806
  nametag: this._identity.nametag
5637
5807
  };
@@ -5748,7 +5918,7 @@ var Sphere = class _Sphere {
5748
5918
  if (this._masterKey) {
5749
5919
  address0 = this.deriveAddress(0).address;
5750
5920
  } else if (this._identity) {
5751
- address0 = this._identity.address;
5921
+ address0 = this._identity.l1Address;
5752
5922
  }
5753
5923
  } catch {
5754
5924
  }
@@ -5795,8 +5965,8 @@ var Sphere = class _Sphere {
5795
5965
  } catch {
5796
5966
  if (i === 0 && this._identity) {
5797
5967
  addresses.push({
5798
- address: this._identity.address,
5799
- publicKey: this._identity.publicKey,
5968
+ address: this._identity.l1Address,
5969
+ publicKey: this._identity.chainPubkey,
5800
5970
  path: this.getDefaultAddressPath(),
5801
5971
  index: 0
5802
5972
  });
@@ -5875,7 +6045,7 @@ var Sphere = class _Sphere {
5875
6045
  } catch {
5876
6046
  if (i === 0 && this._identity) {
5877
6047
  addresses.push({
5878
- address: this._identity.address,
6048
+ address: this._identity.l1Address,
5879
6049
  path: this.getDefaultAddressPath(),
5880
6050
  index: 0,
5881
6051
  isChange: false
@@ -6229,9 +6399,9 @@ var Sphere = class _Sphere {
6229
6399
  const nametag = this._addressNametags.get(index);
6230
6400
  this._identity = {
6231
6401
  privateKey: addressInfo.privateKey,
6232
- publicKey: addressInfo.publicKey,
6233
- address: addressInfo.address,
6234
- predicateAddress,
6402
+ chainPubkey: addressInfo.publicKey,
6403
+ l1Address: addressInfo.address,
6404
+ directAddress: predicateAddress,
6235
6405
  ipnsName: "12D3KooW" + ipnsHash,
6236
6406
  nametag
6237
6407
  };
@@ -6244,13 +6414,13 @@ var Sphere = class _Sphere {
6244
6414
  }
6245
6415
  await this.reinitializeModulesForNewAddress();
6246
6416
  this.emitEvent("identity:changed", {
6247
- address: this._identity.address,
6248
- predicateAddress: this._identity.predicateAddress,
6249
- publicKey: this._identity.publicKey,
6417
+ l1Address: this._identity.l1Address,
6418
+ directAddress: this._identity.directAddress,
6419
+ chainPubkey: this._identity.chainPubkey,
6250
6420
  nametag: this._identity.nametag,
6251
6421
  addressIndex: index
6252
6422
  });
6253
- console.log(`[Sphere] Switched to address ${index}:`, this._identity.address);
6423
+ console.log(`[Sphere] Switched to address ${index}:`, this._identity.l1Address);
6254
6424
  }
6255
6425
  /**
6256
6426
  * Re-initialize modules after address switch
@@ -6308,7 +6478,7 @@ var Sphere = class _Sphere {
6308
6478
  );
6309
6479
  return {
6310
6480
  ...info,
6311
- address: "alpha1" + info.address.slice(0, 38)
6481
+ address: publicKeyToAddress(info.publicKey, "alpha")
6312
6482
  };
6313
6483
  }
6314
6484
  /**
@@ -6335,11 +6505,10 @@ var Sphere = class _Sphere {
6335
6505
  path
6336
6506
  );
6337
6507
  const publicKey = getPublicKey(derived.privateKey);
6338
- const addressHash = hash160(publicKey);
6339
6508
  return {
6340
6509
  privateKey: derived.privateKey,
6341
6510
  publicKey,
6342
- address: "alpha1" + addressHash.slice(0, 38),
6511
+ address: publicKeyToAddress(publicKey, "alpha"),
6343
6512
  path,
6344
6513
  index
6345
6514
  };
@@ -6427,6 +6596,17 @@ var Sphere = class _Sphere {
6427
6596
  hasNametag() {
6428
6597
  return !!this._identity?.nametag;
6429
6598
  }
6599
+ /**
6600
+ * Get the PROXY address for the current nametag
6601
+ * PROXY addresses are derived from the nametag hash and require
6602
+ * the nametag token to claim funds sent to them
6603
+ * @returns PROXY address string or undefined if no nametag
6604
+ */
6605
+ getProxyAddress() {
6606
+ const nametag = this._identity?.nametag;
6607
+ if (!nametag) return void 0;
6608
+ return `PROXY:${hashNametag(nametag)}`;
6609
+ }
6430
6610
  /**
6431
6611
  * Register a nametag for the current active address
6432
6612
  * Each address can have its own independent nametag
@@ -6455,7 +6635,11 @@ var Sphere = class _Sphere {
6455
6635
  throw new Error(`Nametag already registered for address ${this._currentAddressIndex}: @${this._identity.nametag}`);
6456
6636
  }
6457
6637
  if (this._transport.registerNametag) {
6458
- const success = await this._transport.registerNametag(cleanNametag, this._identity.publicKey);
6638
+ const success = await this._transport.registerNametag(
6639
+ cleanNametag,
6640
+ this._identity.chainPubkey,
6641
+ this._identity.directAddress || ""
6642
+ );
6459
6643
  if (!success) {
6460
6644
  throw new Error("Failed to register nametag. It may already be taken.");
6461
6645
  }
@@ -6549,7 +6733,11 @@ var Sphere = class _Sphere {
6549
6733
  return;
6550
6734
  }
6551
6735
  try {
6552
- const success = await this._transport.registerNametag(nametag, this._identity.publicKey);
6736
+ const success = await this._transport.registerNametag(
6737
+ nametag,
6738
+ this._identity.chainPubkey,
6739
+ this._identity.directAddress || ""
6740
+ );
6553
6741
  if (success) {
6554
6742
  console.log(`[Sphere] Nametag @${nametag} synced with Nostr`);
6555
6743
  } else {
@@ -6559,6 +6747,38 @@ var Sphere = class _Sphere {
6559
6747
  console.warn(`[Sphere] Nametag sync failed:`, error);
6560
6748
  }
6561
6749
  }
6750
+ /**
6751
+ * Recover nametag from Nostr after wallet import
6752
+ * Searches for encrypted nametag events authored by this wallet's pubkey
6753
+ * and decrypts them to restore the nametag association
6754
+ */
6755
+ async recoverNametagFromNostr() {
6756
+ if (this._identity?.nametag) {
6757
+ return;
6758
+ }
6759
+ if (!this._transport.recoverNametag) {
6760
+ return;
6761
+ }
6762
+ try {
6763
+ const recoveredNametag = await this._transport.recoverNametag();
6764
+ if (recoveredNametag) {
6765
+ if (this._identity) {
6766
+ this._identity.nametag = recoveredNametag;
6767
+ }
6768
+ this._addressNametags.set(this._currentAddressIndex, recoveredNametag);
6769
+ await this._storage.set(STORAGE_KEYS.NAMETAG, recoveredNametag);
6770
+ if (this._transport.registerNametag) {
6771
+ await this._transport.registerNametag(
6772
+ recoveredNametag,
6773
+ this._identity.chainPubkey,
6774
+ this._identity.directAddress || ""
6775
+ );
6776
+ }
6777
+ this.emitEvent("nametag:recovered", { nametag: recoveredNametag });
6778
+ }
6779
+ } catch {
6780
+ }
6781
+ }
6562
6782
  /**
6563
6783
  * Validate nametag format
6564
6784
  */
@@ -6685,57 +6905,64 @@ var Sphere = class _Sphere {
6685
6905
  const nametag = this._addressNametags.get(this._currentAddressIndex);
6686
6906
  this._identity = {
6687
6907
  privateKey: addressInfo.privateKey,
6688
- publicKey: addressInfo.publicKey,
6689
- address: addressInfo.address,
6690
- predicateAddress,
6908
+ chainPubkey: addressInfo.publicKey,
6909
+ l1Address: addressInfo.address,
6910
+ directAddress: predicateAddress,
6691
6911
  ipnsName: "12D3KooW" + ipnsHash,
6692
6912
  nametag
6693
6913
  };
6694
6914
  this._storage.setIdentity(this._identity);
6695
- console.log(`[Sphere] Restored to address ${this._currentAddressIndex}:`, this._identity.address);
6915
+ console.log(`[Sphere] Restored to address ${this._currentAddressIndex}:`, this._identity.l1Address);
6696
6916
  } else {
6697
6917
  if (savedNametag && this._identity) {
6698
- this._identity.nametag = savedNametag;
6918
+ let nametag = savedNametag;
6919
+ if (savedNametag.startsWith("{")) {
6920
+ try {
6921
+ const parsed = JSON.parse(savedNametag);
6922
+ nametag = parsed["0"] || parsed[0] || Object.values(parsed)[0];
6923
+ } catch {
6924
+ }
6925
+ }
6926
+ this._identity.nametag = nametag;
6699
6927
  if (!this._addressNametags.has(0)) {
6700
- this._addressNametags.set(0, savedNametag);
6928
+ this._addressNametags.set(0, nametag);
6701
6929
  }
6702
- console.log("[Sphere] Restored nametag:", savedNametag);
6703
6930
  } else if (this._identity) {
6704
6931
  const nametag = this._addressNametags.get(0);
6705
6932
  if (nametag) {
6706
6933
  this._identity.nametag = nametag;
6707
- console.log("[Sphere] Restored nametag from map:", nametag);
6708
6934
  }
6709
6935
  }
6710
6936
  }
6711
6937
  }
6712
6938
  async initializeIdentityFromMnemonic(mnemonic, derivationPath) {
6713
- const path = derivationPath ?? DEFAULT_DERIVATION_PATH2;
6939
+ const basePath = derivationPath ?? DEFAULT_BASE_PATH;
6940
+ const fullPath = `${basePath}/0/0`;
6714
6941
  const masterKey = identityFromMnemonicSync(mnemonic);
6715
6942
  const derivedKey = deriveKeyAtPath(
6716
6943
  masterKey.privateKey,
6717
6944
  masterKey.chainCode,
6718
- `${path}/0/0`
6945
+ fullPath
6719
6946
  );
6720
6947
  const publicKey = getPublicKey(derivedKey.privateKey);
6721
- const addressHash = hash160(publicKey);
6948
+ const address = publicKeyToAddress(publicKey, "alpha");
6722
6949
  const ipnsHash = sha256(publicKey, "hex").slice(0, 40);
6723
6950
  const predicateAddress = await deriveL3PredicateAddress(derivedKey.privateKey);
6724
6951
  this._identity = {
6725
6952
  privateKey: derivedKey.privateKey,
6726
- publicKey,
6727
- address: "alpha1" + addressHash.slice(0, 38),
6728
- predicateAddress,
6953
+ chainPubkey: publicKey,
6954
+ l1Address: address,
6955
+ directAddress: predicateAddress,
6729
6956
  ipnsName: "12D3KooW" + ipnsHash
6730
6957
  };
6731
6958
  this._masterKey = masterKey;
6732
- console.log("[Sphere] Identity initialized from mnemonic, path:", path);
6733
6959
  }
6734
6960
  async initializeIdentityFromMasterKey(masterKey, chainCode, derivationPath) {
6735
- const path = derivationPath ?? DEFAULT_DERIVATION_PATH2;
6961
+ const basePath = derivationPath ?? DEFAULT_BASE_PATH;
6962
+ const fullPath = `${basePath}/0/0`;
6736
6963
  let privateKey;
6737
6964
  if (chainCode) {
6738
- const derivedKey = deriveKeyAtPath(masterKey, chainCode, `${path}/0/0`);
6965
+ const derivedKey = deriveKeyAtPath(masterKey, chainCode, fullPath);
6739
6966
  privateKey = derivedKey.privateKey;
6740
6967
  this._masterKey = {
6741
6968
  privateKey: masterKey,
@@ -6746,17 +6973,16 @@ var Sphere = class _Sphere {
6746
6973
  this._masterKey = null;
6747
6974
  }
6748
6975
  const publicKey = getPublicKey(privateKey);
6749
- const addressHash = hash160(publicKey);
6976
+ const address = publicKeyToAddress(publicKey, "alpha");
6750
6977
  const ipnsHash = sha256(publicKey, "hex").slice(0, 40);
6751
6978
  const predicateAddress = await deriveL3PredicateAddress(privateKey);
6752
6979
  this._identity = {
6753
6980
  privateKey,
6754
- publicKey,
6755
- address: "alpha1" + addressHash.slice(0, 38),
6756
- predicateAddress,
6981
+ chainPubkey: publicKey,
6982
+ l1Address: address,
6983
+ directAddress: predicateAddress,
6757
6984
  ipnsName: "12D3KooW" + ipnsHash
6758
6985
  };
6759
- console.log("[Sphere] Identity initialized from master key, path:", path, "chainCode:", !!chainCode);
6760
6986
  }
6761
6987
  // ===========================================================================
6762
6988
  // Private: Provider & Module Initialization