@unicitylabs/sphere-sdk 0.1.2 → 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.
package/dist/index.cjs CHANGED
@@ -1665,6 +1665,7 @@ var L1PaymentsModule = class {
1665
1665
  _chainCode;
1666
1666
  _addresses = [];
1667
1667
  _wallet;
1668
+ _transport;
1668
1669
  constructor(config) {
1669
1670
  this._config = {
1670
1671
  electrumUrl: config?.electrumUrl ?? "wss://fulcrum.alpha.unicity.network:50004",
@@ -1677,13 +1678,14 @@ var L1PaymentsModule = class {
1677
1678
  this._identity = deps.identity;
1678
1679
  this._chainCode = deps.chainCode;
1679
1680
  this._addresses = deps.addresses ?? [];
1681
+ this._transport = deps.transport;
1680
1682
  this._wallet = {
1681
1683
  masterPrivateKey: deps.identity.privateKey,
1682
1684
  chainCode: deps.chainCode,
1683
1685
  addresses: [
1684
1686
  {
1685
- address: deps.identity.address,
1686
- publicKey: deps.identity.publicKey,
1687
+ address: deps.identity.l1Address,
1688
+ publicKey: deps.identity.chainPubkey,
1687
1689
  privateKey: deps.identity.privateKey,
1688
1690
  path: "m/0",
1689
1691
  index: 0
@@ -1691,7 +1693,7 @@ var L1PaymentsModule = class {
1691
1693
  ]
1692
1694
  };
1693
1695
  for (const addr of this._addresses) {
1694
- if (addr !== deps.identity.address) {
1696
+ if (addr !== deps.identity.l1Address) {
1695
1697
  this._wallet.addresses.push({
1696
1698
  address: addr,
1697
1699
  path: null,
@@ -1714,18 +1716,64 @@ var L1PaymentsModule = class {
1714
1716
  this._addresses = [];
1715
1717
  this._wallet = void 0;
1716
1718
  }
1719
+ /**
1720
+ * Check if a string looks like an L1 address (alpha1... or alphat1...)
1721
+ */
1722
+ isL1Address(value) {
1723
+ return value.startsWith("alpha1") || value.startsWith("alphat1");
1724
+ }
1725
+ /**
1726
+ * Resolve recipient to L1 address
1727
+ * Supports: L1 address (alpha1...), nametag (with or without @)
1728
+ */
1729
+ async resolveL1Address(recipient) {
1730
+ if (recipient.startsWith("@")) {
1731
+ const nametag = recipient.slice(1);
1732
+ return this.resolveNametagToL1Address(nametag);
1733
+ }
1734
+ if (this.isL1Address(recipient)) {
1735
+ return recipient;
1736
+ }
1737
+ try {
1738
+ const l1Address = await this.resolveNametagToL1Address(recipient);
1739
+ return l1Address;
1740
+ } catch {
1741
+ throw new Error(
1742
+ `Recipient "${recipient}" is not a valid nametag or L1 address. Use @nametag for explicit nametag or a valid alpha1... address.`
1743
+ );
1744
+ }
1745
+ }
1746
+ /**
1747
+ * Resolve nametag to L1 address using transport provider
1748
+ */
1749
+ async resolveNametagToL1Address(nametag) {
1750
+ if (!this._transport?.resolveNametagInfo) {
1751
+ throw new Error("Transport provider does not support nametag resolution");
1752
+ }
1753
+ const info = await this._transport.resolveNametagInfo(nametag);
1754
+ if (!info) {
1755
+ throw new Error(`Nametag not found: ${nametag}`);
1756
+ }
1757
+ if (!info.l1Address) {
1758
+ throw new Error(
1759
+ `Nametag @${nametag} does not have L1 address information. The owner needs to update their nametag registration.`
1760
+ );
1761
+ }
1762
+ return info.l1Address;
1763
+ }
1717
1764
  async send(request) {
1718
1765
  this.ensureInitialized();
1719
1766
  if (!this._wallet || !this._identity) {
1720
1767
  return { success: false, error: "No wallet available" };
1721
1768
  }
1722
1769
  try {
1770
+ const recipientAddress = await this.resolveL1Address(request.to);
1723
1771
  const amountAlpha = parseInt(request.amount, 10) / 1e8;
1724
1772
  const results = await sendAlpha(
1725
1773
  this._wallet,
1726
- request.to,
1774
+ recipientAddress,
1727
1775
  amountAlpha,
1728
- this._identity.address
1776
+ this._identity.l1Address
1729
1777
  );
1730
1778
  if (results && results.length > 0) {
1731
1779
  const txids = results.map((r) => r.txid);
@@ -1947,8 +1995,8 @@ var L1PaymentsModule = class {
1947
1995
  }
1948
1996
  _getWatchedAddresses() {
1949
1997
  const addresses = [...this._addresses];
1950
- if (this._identity?.address && !addresses.includes(this._identity.address)) {
1951
- addresses.unshift(this._identity.address);
1998
+ if (this._identity?.l1Address && !addresses.includes(this._identity.l1Address)) {
1999
+ addresses.unshift(this._identity.l1Address);
1952
2000
  }
1953
2001
  return addresses;
1954
2002
  }
@@ -2938,12 +2986,10 @@ function countCommittedTransactions(token) {
2938
2986
 
2939
2987
  // modules/payments/PaymentsModule.ts
2940
2988
  var import_Token4 = require("@unicitylabs/state-transition-sdk/lib/token/Token");
2941
- var import_TokenId3 = require("@unicitylabs/state-transition-sdk/lib/token/TokenId");
2942
2989
  var import_CoinId3 = require("@unicitylabs/state-transition-sdk/lib/token/fungible/CoinId");
2943
2990
  var import_TransferCommitment2 = require("@unicitylabs/state-transition-sdk/lib/transaction/TransferCommitment");
2944
2991
  var import_TransferTransaction = require("@unicitylabs/state-transition-sdk/lib/transaction/TransferTransaction");
2945
2992
  var import_SigningService = require("@unicitylabs/state-transition-sdk/lib/sign/SigningService");
2946
- var import_ProxyAddress = require("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
2947
2993
  var import_AddressScheme = require("@unicitylabs/state-transition-sdk/lib/address/AddressScheme");
2948
2994
  var import_UnmaskedPredicate3 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate");
2949
2995
  var import_TokenState3 = require("@unicitylabs/state-transition-sdk/lib/token/TokenState");
@@ -3234,7 +3280,8 @@ var PaymentsModule = class {
3234
3280
  this.l1.initialize({
3235
3281
  identity: deps.identity,
3236
3282
  chainCode: deps.chainCode,
3237
- addresses: deps.l1Addresses
3283
+ addresses: deps.l1Addresses,
3284
+ transport: deps.transport
3238
3285
  });
3239
3286
  }
3240
3287
  this.unsubscribeTransfers = deps.transport.onTokenTransfer((transfer) => {
@@ -3631,7 +3678,7 @@ var PaymentsModule = class {
3631
3678
  }
3632
3679
  const request = {
3633
3680
  id: transportRequest.id,
3634
- senderPubkey: transportRequest.senderPubkey,
3681
+ senderPubkey: transportRequest.senderTransportPubkey,
3635
3682
  amount: transportRequest.request.amount,
3636
3683
  coinId: transportRequest.request.coinId,
3637
3684
  symbol: transportRequest.request.coinId,
@@ -3743,7 +3790,7 @@ var PaymentsModule = class {
3743
3790
  }
3744
3791
  const response = {
3745
3792
  id: transportResponse.id,
3746
- responderPubkey: transportResponse.responderPubkey,
3793
+ responderPubkey: transportResponse.responderTransportPubkey,
3747
3794
  requestId: transportResponse.response.requestId,
3748
3795
  responseType: transportResponse.response.responseType,
3749
3796
  message: transportResponse.response.message,
@@ -4497,6 +4544,23 @@ var PaymentsModule = class {
4497
4544
  // ===========================================================================
4498
4545
  // Private: Transfer Operations
4499
4546
  // ===========================================================================
4547
+ /**
4548
+ * Detect if a string is an L3 address (not a nametag)
4549
+ * Returns true for: hex pubkeys (64+ chars), PROXY:, DIRECT: prefixed addresses
4550
+ */
4551
+ isL3Address(value) {
4552
+ if (value.startsWith("PROXY:") || value.startsWith("DIRECT:")) {
4553
+ return true;
4554
+ }
4555
+ if (value.length >= 64 && /^[0-9a-fA-F]+$/.test(value)) {
4556
+ return true;
4557
+ }
4558
+ return false;
4559
+ }
4560
+ /**
4561
+ * Resolve recipient to Nostr pubkey for messaging
4562
+ * Supports: nametag (with or without @), hex pubkey
4563
+ */
4500
4564
  async resolveRecipient(recipient) {
4501
4565
  if (recipient.startsWith("@")) {
4502
4566
  const nametag = recipient.slice(1);
@@ -4506,7 +4570,19 @@ var PaymentsModule = class {
4506
4570
  }
4507
4571
  return pubkey;
4508
4572
  }
4509
- return recipient;
4573
+ if (this.isL3Address(recipient)) {
4574
+ return recipient;
4575
+ }
4576
+ if (this.deps?.transport.resolveNametag) {
4577
+ const pubkey = await this.deps.transport.resolveNametag(recipient);
4578
+ if (pubkey) {
4579
+ this.log(`Resolved "${recipient}" as nametag to pubkey`);
4580
+ return pubkey;
4581
+ }
4582
+ }
4583
+ throw new Error(
4584
+ `Recipient "${recipient}" is not a valid nametag or address. Use @nametag for explicit nametag or a valid hex pubkey/PROXY:/DIRECT: address.`
4585
+ );
4510
4586
  }
4511
4587
  /**
4512
4588
  * Create SDK TransferCommitment for a token transfer
@@ -4538,19 +4614,74 @@ var PaymentsModule = class {
4538
4614
  return import_SigningService.SigningService.createFromSecret(privateKeyBytes);
4539
4615
  }
4540
4616
  /**
4541
- * Resolve recipient to IAddress
4617
+ * Create DirectAddress from a public key using UnmaskedPredicateReference
4618
+ */
4619
+ async createDirectAddressFromPubkey(pubkeyHex) {
4620
+ const { UnmaskedPredicateReference: UnmaskedPredicateReference3 } = await import("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference");
4621
+ const { TokenType: TokenType3 } = await import("@unicitylabs/state-transition-sdk/lib/token/TokenType");
4622
+ const UNICITY_TOKEN_TYPE_HEX3 = "f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509";
4623
+ const tokenType = new TokenType3(Buffer.from(UNICITY_TOKEN_TYPE_HEX3, "hex"));
4624
+ const pubkeyBytes = new Uint8Array(
4625
+ pubkeyHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
4626
+ );
4627
+ const addressRef = await UnmaskedPredicateReference3.create(
4628
+ tokenType,
4629
+ "secp256k1",
4630
+ pubkeyBytes,
4631
+ import_HashAlgorithm3.HashAlgorithm.SHA256
4632
+ );
4633
+ return addressRef.toAddress();
4634
+ }
4635
+ /**
4636
+ * Resolve nametag to 33-byte compressed public key using resolveNametagInfo
4637
+ * Returns null if nametag not found or publicKey not available
4638
+ */
4639
+ async resolveNametagToPublicKey(nametag) {
4640
+ if (!this.deps?.transport.resolveNametagInfo) {
4641
+ this.log("resolveNametagInfo not available on transport");
4642
+ return null;
4643
+ }
4644
+ const info = await this.deps.transport.resolveNametagInfo(nametag);
4645
+ if (!info) {
4646
+ this.log(`Nametag "${nametag}" not found`);
4647
+ return null;
4648
+ }
4649
+ if (!info.chainPubkey) {
4650
+ this.log(`Nametag "${nametag}" has no 33-byte chainPubkey (legacy event)`);
4651
+ return null;
4652
+ }
4653
+ return info.chainPubkey;
4654
+ }
4655
+ /**
4656
+ * Resolve recipient to IAddress for L3 transfers
4657
+ * Supports: nametag (with or without @), PROXY:, DIRECT:, hex pubkey
4542
4658
  */
4543
4659
  async resolveRecipientAddress(recipient) {
4660
+ const { AddressFactory } = await import("@unicitylabs/state-transition-sdk/lib/address/AddressFactory");
4544
4661
  if (recipient.startsWith("@")) {
4545
4662
  const nametag = recipient.slice(1);
4546
- const tokenId2 = await import_TokenId3.TokenId.fromNameTag(nametag);
4547
- return import_ProxyAddress.ProxyAddress.fromTokenId(tokenId2);
4663
+ const publicKey2 = await this.resolveNametagToPublicKey(nametag);
4664
+ if (publicKey2) {
4665
+ this.log(`Resolved @${nametag} to 33-byte publicKey for DirectAddress`);
4666
+ return this.createDirectAddressFromPubkey(publicKey2);
4667
+ }
4668
+ throw new Error(`Nametag "${nametag}" not found or missing publicKey`);
4548
4669
  }
4549
- const pubkeyBytes = new Uint8Array(
4550
- recipient.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
4670
+ if (recipient.startsWith("PROXY:") || recipient.startsWith("DIRECT:")) {
4671
+ return AddressFactory.createAddress(recipient);
4672
+ }
4673
+ if (recipient.length === 66 && /^[0-9a-fA-F]+$/.test(recipient)) {
4674
+ this.log(`Creating DirectAddress from 33-byte compressed pubkey`);
4675
+ return this.createDirectAddressFromPubkey(recipient);
4676
+ }
4677
+ const publicKey = await this.resolveNametagToPublicKey(recipient);
4678
+ if (publicKey) {
4679
+ this.log(`Resolved "${recipient}" as nametag to 33-byte publicKey for DirectAddress`);
4680
+ return this.createDirectAddressFromPubkey(publicKey);
4681
+ }
4682
+ throw new Error(
4683
+ `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.`
4551
4684
  );
4552
- const tokenId = new import_TokenId3.TokenId(pubkeyBytes.slice(0, 32));
4553
- return import_ProxyAddress.ProxyAddress.fromTokenId(tokenId);
4554
4685
  }
4555
4686
  async handleIncomingTransfer(transfer) {
4556
4687
  try {
@@ -4608,7 +4739,39 @@ var PaymentsModule = class {
4608
4739
  }
4609
4740
  }
4610
4741
  } else {
4611
- tokenData = sourceTokenInput;
4742
+ this.log("Finalizing DIRECT address transfer for state tracking...");
4743
+ try {
4744
+ const signingService = await this.createSigningService();
4745
+ const transferSalt = transferTx.data.salt;
4746
+ const recipientPredicate = await import_UnmaskedPredicate3.UnmaskedPredicate.create(
4747
+ sourceToken.id,
4748
+ sourceToken.type,
4749
+ signingService,
4750
+ import_HashAlgorithm3.HashAlgorithm.SHA256,
4751
+ transferSalt
4752
+ );
4753
+ const recipientState = new import_TokenState3.TokenState(recipientPredicate, null);
4754
+ const stClient = this.deps.oracle.getStateTransitionClient?.();
4755
+ const trustBase = this.deps.oracle.getTrustBase?.();
4756
+ if (!stClient || !trustBase) {
4757
+ this.log("Cannot finalize DIRECT transfer - missing client, using source token");
4758
+ tokenData = sourceTokenInput;
4759
+ } else {
4760
+ finalizedSdkToken = await stClient.finalizeTransaction(
4761
+ trustBase,
4762
+ sourceToken,
4763
+ recipientState,
4764
+ transferTx,
4765
+ []
4766
+ // No nametag tokens needed for DIRECT
4767
+ );
4768
+ tokenData = finalizedSdkToken.toJSON();
4769
+ this.log("DIRECT transfer finalized successfully");
4770
+ }
4771
+ } catch (finalizeError) {
4772
+ this.log("DIRECT finalization failed, using source token:", finalizeError);
4773
+ tokenData = sourceTokenInput;
4774
+ }
4612
4775
  }
4613
4776
  } else if (payload.token) {
4614
4777
  tokenData = payload.token;
@@ -4642,7 +4805,7 @@ var PaymentsModule = class {
4642
4805
  await this.addToken(token);
4643
4806
  const incomingTransfer = {
4644
4807
  id: transfer.id,
4645
- senderPubkey: transfer.senderPubkey,
4808
+ senderPubkey: transfer.senderTransportPubkey,
4646
4809
  tokens: [token],
4647
4810
  memo: payload.memo,
4648
4811
  receivedAt: transfer.timestamp
@@ -4710,7 +4873,7 @@ var PaymentsModule = class {
4710
4873
  tokens,
4711
4874
  {
4712
4875
  version: 1,
4713
- address: this.deps.identity.address,
4876
+ address: this.deps.identity.l1Address,
4714
4877
  ipnsName: this.deps.identity.ipnsName ?? ""
4715
4878
  },
4716
4879
  {
@@ -4814,7 +4977,7 @@ var CommunicationsModule = class {
4814
4977
  const eventId = await this.deps.transport.sendMessage(recipientPubkey, content);
4815
4978
  const message = {
4816
4979
  id: eventId,
4817
- senderPubkey: this.deps.identity.publicKey,
4980
+ senderPubkey: this.deps.identity.chainPubkey,
4818
4981
  senderNametag: this.deps.identity.nametag,
4819
4982
  recipientPubkey,
4820
4983
  content,
@@ -4841,7 +5004,7 @@ var CommunicationsModule = class {
4841
5004
  getConversations() {
4842
5005
  const conversations = /* @__PURE__ */ new Map();
4843
5006
  for (const message of this.messages.values()) {
4844
- const peer = message.senderPubkey === this.deps?.identity.publicKey ? message.recipientPubkey : message.senderPubkey;
5007
+ const peer = message.senderPubkey === this.deps?.identity.chainPubkey ? message.recipientPubkey : message.senderPubkey;
4845
5008
  if (!conversations.has(peer)) {
4846
5009
  conversations.set(peer, []);
4847
5010
  }
@@ -4871,7 +5034,7 @@ var CommunicationsModule = class {
4871
5034
  */
4872
5035
  getUnreadCount(peerPubkey) {
4873
5036
  let messages = Array.from(this.messages.values()).filter(
4874
- (m) => !m.isRead && m.senderPubkey !== this.deps?.identity.publicKey
5037
+ (m) => !m.isRead && m.senderPubkey !== this.deps?.identity.chainPubkey
4875
5038
  );
4876
5039
  if (peerPubkey) {
4877
5040
  messages = messages.filter((m) => m.senderPubkey === peerPubkey);
@@ -4896,7 +5059,7 @@ var CommunicationsModule = class {
4896
5059
  const eventId = await this.deps.transport.publishBroadcast?.(content, tags);
4897
5060
  const message = {
4898
5061
  id: eventId ?? crypto.randomUUID(),
4899
- authorPubkey: this.deps.identity.publicKey,
5062
+ authorPubkey: this.deps.identity.chainPubkey,
4900
5063
  authorNametag: this.deps.identity.nametag,
4901
5064
  content,
4902
5065
  timestamp: Date.now(),
@@ -4947,11 +5110,12 @@ var CommunicationsModule = class {
4947
5110
  // Private: Message Handling
4948
5111
  // ===========================================================================
4949
5112
  handleIncomingMessage(msg) {
4950
- if (msg.senderPubkey === this.deps?.identity.publicKey) return;
5113
+ if (msg.senderTransportPubkey === this.deps?.identity.chainPubkey) return;
4951
5114
  const message = {
4952
5115
  id: msg.id,
4953
- senderPubkey: msg.senderPubkey,
4954
- recipientPubkey: this.deps.identity.publicKey,
5116
+ senderPubkey: msg.senderTransportPubkey,
5117
+ senderNametag: msg.senderNametag,
5118
+ recipientPubkey: this.deps.identity.chainPubkey,
4955
5119
  content: msg.content,
4956
5120
  timestamp: msg.timestamp,
4957
5121
  isRead: false
@@ -4973,7 +5137,7 @@ var CommunicationsModule = class {
4973
5137
  handleIncomingBroadcast(incoming) {
4974
5138
  const message = {
4975
5139
  id: incoming.id,
4976
- authorPubkey: incoming.authorPubkey,
5140
+ authorPubkey: incoming.authorTransportPubkey,
4977
5141
  content: incoming.content,
4978
5142
  timestamp: incoming.timestamp,
4979
5143
  tags: incoming.tags
@@ -5715,6 +5879,7 @@ var import_SigningService2 = require("@unicitylabs/state-transition-sdk/lib/sign
5715
5879
  var import_TokenType2 = require("@unicitylabs/state-transition-sdk/lib/token/TokenType");
5716
5880
  var import_HashAlgorithm4 = require("@unicitylabs/state-transition-sdk/lib/hash/HashAlgorithm");
5717
5881
  var import_UnmaskedPredicateReference2 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicateReference");
5882
+ var import_nostr_js_sdk = require("@unicitylabs/nostr-js-sdk");
5718
5883
  var UNICITY_TOKEN_TYPE_HEX2 = "f8aa13834268d29355ff12183066f0cb902003629bbc5eb9ef0efbe397867509";
5719
5884
  async function deriveL3PredicateAddress(privateKey) {
5720
5885
  const secret = Buffer.from(privateKey, "hex");
@@ -5773,12 +5938,13 @@ var Sphere = class _Sphere {
5773
5938
  */
5774
5939
  static async exists(storage) {
5775
5940
  try {
5776
- const exists = await storage.get(STORAGE_KEYS.WALLET_EXISTS);
5777
- if (exists === "true") {
5778
- const mnemonic = await storage.get(STORAGE_KEYS.MNEMONIC);
5779
- const masterKey = await storage.get(STORAGE_KEYS.MASTER_KEY);
5780
- return !!(mnemonic || masterKey);
5941
+ if (!storage.isConnected()) {
5942
+ await storage.connect();
5781
5943
  }
5944
+ const mnemonic = await storage.get(STORAGE_KEYS.MNEMONIC);
5945
+ if (mnemonic) return true;
5946
+ const masterKey = await storage.get(STORAGE_KEYS.MASTER_KEY);
5947
+ if (masterKey) return true;
5782
5948
  return false;
5783
5949
  } catch {
5784
5950
  return false;
@@ -5871,6 +6037,8 @@ var Sphere = class _Sphere {
5871
6037
  _Sphere.instance = sphere;
5872
6038
  if (options.nametag) {
5873
6039
  await sphere.registerNametag(options.nametag);
6040
+ } else {
6041
+ await sphere.recoverNametagFromNostr();
5874
6042
  }
5875
6043
  return sphere;
5876
6044
  }
@@ -5892,15 +6060,6 @@ var Sphere = class _Sphere {
5892
6060
  await sphere.initializeProviders();
5893
6061
  await sphere.initializeModules();
5894
6062
  await sphere.syncNametagWithNostr();
5895
- if (sphere._identity?.nametag && !sphere._payments.hasNametag()) {
5896
- console.log(`[Sphere] Minting missing nametag token for @${sphere._identity.nametag}...`);
5897
- const result = await sphere.mintNametag(sphere._identity.nametag);
5898
- if (!result.success) {
5899
- console.warn(`[Sphere] Failed to mint nametag token: ${result.error}`);
5900
- } else {
5901
- console.log(`[Sphere] Nametag token minted successfully`);
5902
- }
5903
- }
5904
6063
  sphere._initialized = true;
5905
6064
  _Sphere.instance = sphere;
5906
6065
  return sphere;
@@ -5942,6 +6101,9 @@ var Sphere = class _Sphere {
5942
6101
  }
5943
6102
  await sphere.initializeProviders();
5944
6103
  await sphere.initializeModules();
6104
+ if (!options.nametag) {
6105
+ await sphere.recoverNametagFromNostr();
6106
+ }
5945
6107
  await sphere.finalizeWalletCreation();
5946
6108
  sphere._initialized = true;
5947
6109
  _Sphere.instance = sphere;
@@ -6015,9 +6177,9 @@ var Sphere = class _Sphere {
6015
6177
  get identity() {
6016
6178
  if (!this._identity) return null;
6017
6179
  return {
6018
- publicKey: this._identity.publicKey,
6019
- address: this._identity.address,
6020
- predicateAddress: this._identity.predicateAddress,
6180
+ chainPubkey: this._identity.chainPubkey,
6181
+ l1Address: this._identity.l1Address,
6182
+ directAddress: this._identity.directAddress,
6021
6183
  ipnsName: this._identity.ipnsName,
6022
6184
  nametag: this._identity.nametag
6023
6185
  };
@@ -6134,7 +6296,7 @@ var Sphere = class _Sphere {
6134
6296
  if (this._masterKey) {
6135
6297
  address0 = this.deriveAddress(0).address;
6136
6298
  } else if (this._identity) {
6137
- address0 = this._identity.address;
6299
+ address0 = this._identity.l1Address;
6138
6300
  }
6139
6301
  } catch {
6140
6302
  }
@@ -6181,8 +6343,8 @@ var Sphere = class _Sphere {
6181
6343
  } catch {
6182
6344
  if (i === 0 && this._identity) {
6183
6345
  addresses.push({
6184
- address: this._identity.address,
6185
- publicKey: this._identity.publicKey,
6346
+ address: this._identity.l1Address,
6347
+ publicKey: this._identity.chainPubkey,
6186
6348
  path: this.getDefaultAddressPath(),
6187
6349
  index: 0
6188
6350
  });
@@ -6261,7 +6423,7 @@ var Sphere = class _Sphere {
6261
6423
  } catch {
6262
6424
  if (i === 0 && this._identity) {
6263
6425
  addresses.push({
6264
- address: this._identity.address,
6426
+ address: this._identity.l1Address,
6265
6427
  path: this.getDefaultAddressPath(),
6266
6428
  index: 0,
6267
6429
  isChange: false
@@ -6615,9 +6777,9 @@ var Sphere = class _Sphere {
6615
6777
  const nametag = this._addressNametags.get(index);
6616
6778
  this._identity = {
6617
6779
  privateKey: addressInfo.privateKey,
6618
- publicKey: addressInfo.publicKey,
6619
- address: addressInfo.address,
6620
- predicateAddress,
6780
+ chainPubkey: addressInfo.publicKey,
6781
+ l1Address: addressInfo.address,
6782
+ directAddress: predicateAddress,
6621
6783
  ipnsName: "12D3KooW" + ipnsHash,
6622
6784
  nametag
6623
6785
  };
@@ -6630,13 +6792,13 @@ var Sphere = class _Sphere {
6630
6792
  }
6631
6793
  await this.reinitializeModulesForNewAddress();
6632
6794
  this.emitEvent("identity:changed", {
6633
- address: this._identity.address,
6634
- predicateAddress: this._identity.predicateAddress,
6635
- publicKey: this._identity.publicKey,
6795
+ l1Address: this._identity.l1Address,
6796
+ directAddress: this._identity.directAddress,
6797
+ chainPubkey: this._identity.chainPubkey,
6636
6798
  nametag: this._identity.nametag,
6637
6799
  addressIndex: index
6638
6800
  });
6639
- console.log(`[Sphere] Switched to address ${index}:`, this._identity.address);
6801
+ console.log(`[Sphere] Switched to address ${index}:`, this._identity.l1Address);
6640
6802
  }
6641
6803
  /**
6642
6804
  * Re-initialize modules after address switch
@@ -6694,7 +6856,7 @@ var Sphere = class _Sphere {
6694
6856
  );
6695
6857
  return {
6696
6858
  ...info,
6697
- address: "alpha1" + info.address.slice(0, 38)
6859
+ address: publicKeyToAddress(info.publicKey, "alpha")
6698
6860
  };
6699
6861
  }
6700
6862
  /**
@@ -6721,11 +6883,10 @@ var Sphere = class _Sphere {
6721
6883
  path
6722
6884
  );
6723
6885
  const publicKey = getPublicKey(derived.privateKey);
6724
- const addressHash = hash160(publicKey);
6725
6886
  return {
6726
6887
  privateKey: derived.privateKey,
6727
6888
  publicKey,
6728
- address: "alpha1" + addressHash.slice(0, 38),
6889
+ address: publicKeyToAddress(publicKey, "alpha"),
6729
6890
  path,
6730
6891
  index
6731
6892
  };
@@ -6813,6 +6974,17 @@ var Sphere = class _Sphere {
6813
6974
  hasNametag() {
6814
6975
  return !!this._identity?.nametag;
6815
6976
  }
6977
+ /**
6978
+ * Get the PROXY address for the current nametag
6979
+ * PROXY addresses are derived from the nametag hash and require
6980
+ * the nametag token to claim funds sent to them
6981
+ * @returns PROXY address string or undefined if no nametag
6982
+ */
6983
+ getProxyAddress() {
6984
+ const nametag = this._identity?.nametag;
6985
+ if (!nametag) return void 0;
6986
+ return `PROXY:${(0, import_nostr_js_sdk.hashNametag)(nametag)}`;
6987
+ }
6816
6988
  /**
6817
6989
  * Register a nametag for the current active address
6818
6990
  * Each address can have its own independent nametag
@@ -6841,7 +7013,11 @@ var Sphere = class _Sphere {
6841
7013
  throw new Error(`Nametag already registered for address ${this._currentAddressIndex}: @${this._identity.nametag}`);
6842
7014
  }
6843
7015
  if (this._transport.registerNametag) {
6844
- const success = await this._transport.registerNametag(cleanNametag, this._identity.publicKey);
7016
+ const success = await this._transport.registerNametag(
7017
+ cleanNametag,
7018
+ this._identity.chainPubkey,
7019
+ this._identity.directAddress || ""
7020
+ );
6845
7021
  if (!success) {
6846
7022
  throw new Error("Failed to register nametag. It may already be taken.");
6847
7023
  }
@@ -6935,7 +7111,11 @@ var Sphere = class _Sphere {
6935
7111
  return;
6936
7112
  }
6937
7113
  try {
6938
- const success = await this._transport.registerNametag(nametag, this._identity.publicKey);
7114
+ const success = await this._transport.registerNametag(
7115
+ nametag,
7116
+ this._identity.chainPubkey,
7117
+ this._identity.directAddress || ""
7118
+ );
6939
7119
  if (success) {
6940
7120
  console.log(`[Sphere] Nametag @${nametag} synced with Nostr`);
6941
7121
  } else {
@@ -6945,6 +7125,38 @@ var Sphere = class _Sphere {
6945
7125
  console.warn(`[Sphere] Nametag sync failed:`, error);
6946
7126
  }
6947
7127
  }
7128
+ /**
7129
+ * Recover nametag from Nostr after wallet import
7130
+ * Searches for encrypted nametag events authored by this wallet's pubkey
7131
+ * and decrypts them to restore the nametag association
7132
+ */
7133
+ async recoverNametagFromNostr() {
7134
+ if (this._identity?.nametag) {
7135
+ return;
7136
+ }
7137
+ if (!this._transport.recoverNametag) {
7138
+ return;
7139
+ }
7140
+ try {
7141
+ const recoveredNametag = await this._transport.recoverNametag();
7142
+ if (recoveredNametag) {
7143
+ if (this._identity) {
7144
+ this._identity.nametag = recoveredNametag;
7145
+ }
7146
+ this._addressNametags.set(this._currentAddressIndex, recoveredNametag);
7147
+ await this._storage.set(STORAGE_KEYS.NAMETAG, recoveredNametag);
7148
+ if (this._transport.registerNametag) {
7149
+ await this._transport.registerNametag(
7150
+ recoveredNametag,
7151
+ this._identity.chainPubkey,
7152
+ this._identity.directAddress || ""
7153
+ );
7154
+ }
7155
+ this.emitEvent("nametag:recovered", { nametag: recoveredNametag });
7156
+ }
7157
+ } catch {
7158
+ }
7159
+ }
6948
7160
  /**
6949
7161
  * Validate nametag format
6950
7162
  */
@@ -7026,7 +7238,6 @@ var Sphere = class _Sphere {
7026
7238
  const encryptedMasterKey = await this._storage.get(STORAGE_KEYS.MASTER_KEY);
7027
7239
  const chainCode = await this._storage.get(STORAGE_KEYS.CHAIN_CODE);
7028
7240
  const derivationPath = await this._storage.get(STORAGE_KEYS.DERIVATION_PATH);
7029
- const savedNametag = await this._storage.get(STORAGE_KEYS.NAMETAG);
7030
7241
  const savedBasePath = await this._storage.get(STORAGE_KEYS.BASE_PATH);
7031
7242
  const savedDerivationMode = await this._storage.get(STORAGE_KEYS.DERIVATION_MODE);
7032
7243
  const savedSource = await this._storage.get(STORAGE_KEYS.WALLET_SOURCE);
@@ -7035,7 +7246,6 @@ var Sphere = class _Sphere {
7035
7246
  this._derivationMode = savedDerivationMode ?? "bip32";
7036
7247
  this._source = savedSource ?? "unknown";
7037
7248
  this._currentAddressIndex = savedAddressIndex ? parseInt(savedAddressIndex, 10) : 0;
7038
- await this.loadAddressNametags();
7039
7249
  if (encryptedMnemonic) {
7040
7250
  const mnemonic = this.decrypt(encryptedMnemonic);
7041
7251
  if (!mnemonic) {
@@ -7061,6 +7271,11 @@ var Sphere = class _Sphere {
7061
7271
  } else {
7062
7272
  throw new Error("No wallet data found in storage");
7063
7273
  }
7274
+ if (this._identity) {
7275
+ this._storage.setIdentity(this._identity);
7276
+ }
7277
+ await this.loadAddressNametags();
7278
+ const savedNametag = await this._storage.get(STORAGE_KEYS.NAMETAG);
7064
7279
  if (this._currentAddressIndex > 0 && this._masterKey) {
7065
7280
  const addressInfo = this.deriveAddress(this._currentAddressIndex, false);
7066
7281
  const ipnsHash = sha256(addressInfo.publicKey, "hex").slice(0, 40);
@@ -7068,56 +7283,64 @@ var Sphere = class _Sphere {
7068
7283
  const nametag = this._addressNametags.get(this._currentAddressIndex);
7069
7284
  this._identity = {
7070
7285
  privateKey: addressInfo.privateKey,
7071
- publicKey: addressInfo.publicKey,
7072
- address: addressInfo.address,
7073
- predicateAddress,
7286
+ chainPubkey: addressInfo.publicKey,
7287
+ l1Address: addressInfo.address,
7288
+ directAddress: predicateAddress,
7074
7289
  ipnsName: "12D3KooW" + ipnsHash,
7075
7290
  nametag
7076
7291
  };
7077
- console.log(`[Sphere] Restored to address ${this._currentAddressIndex}:`, this._identity.address);
7292
+ this._storage.setIdentity(this._identity);
7293
+ console.log(`[Sphere] Restored to address ${this._currentAddressIndex}:`, this._identity.l1Address);
7078
7294
  } else {
7079
7295
  if (savedNametag && this._identity) {
7080
- this._identity.nametag = savedNametag;
7296
+ let nametag = savedNametag;
7297
+ if (savedNametag.startsWith("{")) {
7298
+ try {
7299
+ const parsed = JSON.parse(savedNametag);
7300
+ nametag = parsed["0"] || parsed[0] || Object.values(parsed)[0];
7301
+ } catch {
7302
+ }
7303
+ }
7304
+ this._identity.nametag = nametag;
7081
7305
  if (!this._addressNametags.has(0)) {
7082
- this._addressNametags.set(0, savedNametag);
7306
+ this._addressNametags.set(0, nametag);
7083
7307
  }
7084
- console.log("[Sphere] Restored nametag:", savedNametag);
7085
7308
  } else if (this._identity) {
7086
7309
  const nametag = this._addressNametags.get(0);
7087
7310
  if (nametag) {
7088
7311
  this._identity.nametag = nametag;
7089
- console.log("[Sphere] Restored nametag from map:", nametag);
7090
7312
  }
7091
7313
  }
7092
7314
  }
7093
7315
  }
7094
7316
  async initializeIdentityFromMnemonic(mnemonic, derivationPath) {
7095
- const path = derivationPath ?? DEFAULT_DERIVATION_PATH;
7317
+ const basePath = derivationPath ?? DEFAULT_BASE_PATH;
7318
+ const fullPath = `${basePath}/0/0`;
7096
7319
  const masterKey = identityFromMnemonicSync(mnemonic);
7097
7320
  const derivedKey = deriveKeyAtPath(
7098
7321
  masterKey.privateKey,
7099
7322
  masterKey.chainCode,
7100
- `${path}/0/0`
7323
+ fullPath
7101
7324
  );
7102
7325
  const publicKey = getPublicKey(derivedKey.privateKey);
7103
- const addressHash = hash160(publicKey);
7326
+ const address = publicKeyToAddress(publicKey, "alpha");
7104
7327
  const ipnsHash = sha256(publicKey, "hex").slice(0, 40);
7105
7328
  const predicateAddress = await deriveL3PredicateAddress(derivedKey.privateKey);
7106
7329
  this._identity = {
7107
7330
  privateKey: derivedKey.privateKey,
7108
- publicKey,
7109
- address: "alpha1" + addressHash.slice(0, 38),
7110
- predicateAddress,
7331
+ chainPubkey: publicKey,
7332
+ l1Address: address,
7333
+ directAddress: predicateAddress,
7111
7334
  ipnsName: "12D3KooW" + ipnsHash
7112
7335
  };
7113
7336
  this._masterKey = masterKey;
7114
- console.log("[Sphere] Identity initialized from mnemonic, path:", path);
7115
7337
  }
7116
7338
  async initializeIdentityFromMasterKey(masterKey, chainCode, derivationPath) {
7117
- const path = derivationPath ?? DEFAULT_DERIVATION_PATH;
7339
+ const basePath = derivationPath ?? DEFAULT_BASE_PATH;
7340
+ const fullPath = `${basePath}/0/0`;
7118
7341
  let privateKey;
7119
7342
  if (chainCode) {
7120
- const derivedKey = deriveKeyAtPath(masterKey, chainCode, `${path}/0/0`);
7343
+ const derivedKey = deriveKeyAtPath(masterKey, chainCode, fullPath);
7121
7344
  privateKey = derivedKey.privateKey;
7122
7345
  this._masterKey = {
7123
7346
  privateKey: masterKey,
@@ -7128,17 +7351,16 @@ var Sphere = class _Sphere {
7128
7351
  this._masterKey = null;
7129
7352
  }
7130
7353
  const publicKey = getPublicKey(privateKey);
7131
- const addressHash = hash160(publicKey);
7354
+ const address = publicKeyToAddress(publicKey, "alpha");
7132
7355
  const ipnsHash = sha256(publicKey, "hex").slice(0, 40);
7133
7356
  const predicateAddress = await deriveL3PredicateAddress(privateKey);
7134
7357
  this._identity = {
7135
7358
  privateKey,
7136
- publicKey,
7137
- address: "alpha1" + addressHash.slice(0, 38),
7138
- predicateAddress,
7359
+ chainPubkey: publicKey,
7360
+ l1Address: address,
7361
+ directAddress: predicateAddress,
7139
7362
  ipnsName: "12D3KooW" + ipnsHash
7140
7363
  };
7141
- console.log("[Sphere] Identity initialized from master key, path:", path, "chainCode:", !!chainCode);
7142
7364
  }
7143
7365
  // ===========================================================================
7144
7366
  // Private: Provider & Module Initialization