@sign-global/tokentable-wallets 1.0.1 → 1.2.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @sign-global/tokentable-wallets
2
2
 
3
+ ## 1.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @sign-global/tokentable-core@1.2.0
9
+
10
+ ## 1.1.0
11
+
12
+ ### Minor Changes
13
+
14
+ - feat: add Ledger wallet support and enhance signing functionality
15
+
3
16
  ## 1.0.1
4
17
 
5
18
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -11,11 +11,13 @@ import { Cluster } from '@solana/web3.js';
11
11
  declare enum ChainType {
12
12
  Evm = "evm",
13
13
  Ton = "ton",
14
- Solana = "solana"
14
+ Solana = "solana",
15
+ Sui = "sui"
15
16
  }
16
17
  type ISignResult = {
17
18
  message: string;
18
19
  signature: string;
20
+ signedMessage?: string;
19
21
  [key: string]: any;
20
22
  } | undefined;
21
23
 
package/dist/index.d.ts CHANGED
@@ -11,11 +11,13 @@ import { Cluster } from '@solana/web3.js';
11
11
  declare enum ChainType {
12
12
  Evm = "evm",
13
13
  Ton = "ton",
14
- Solana = "solana"
14
+ Solana = "solana",
15
+ Sui = "sui"
15
16
  }
16
17
  type ISignResult = {
17
18
  message: string;
18
19
  signature: string;
20
+ signedMessage?: string;
19
21
  [key: string]: any;
20
22
  } | undefined;
21
23
 
package/dist/index.js CHANGED
@@ -419,6 +419,343 @@ var import_wallet_adapter_wallets = require("@solana/wallet-adapter-wallets");
419
419
  var import_bs58 = __toESM(require("bs58"));
420
420
  var import_events3 = __toESM(require("events"));
421
421
  var import_tokentable_core3 = require("@sign-global/tokentable-core");
422
+
423
+ // src/utils/ledger/adapter.ts
424
+ var import_wallet_adapter_base2 = require("@solana/wallet-adapter-base");
425
+
426
+ // src/utils/ledger/polyfills/Buffer.ts
427
+ var import_buffer = require("buffer");
428
+ if (typeof window !== "undefined" && window.Buffer === void 0) {
429
+ window.Buffer = import_buffer.Buffer;
430
+ }
431
+
432
+ // src/utils/ledger/util.ts
433
+ var import_hw_transport = require("@ledgerhq/hw-transport");
434
+ var import_wallet_adapter_base = require("@solana/wallet-adapter-base");
435
+ var import_web3 = require("@solana/web3.js");
436
+ function getDerivationPath(account, change) {
437
+ const length = account !== void 0 ? change === void 0 ? 3 : 4 : 2;
438
+ const derivationPath = Buffer.alloc(1 + length * 4);
439
+ let offset = derivationPath.writeUInt8(length, 0);
440
+ offset = derivationPath.writeUInt32BE(harden(44), offset);
441
+ offset = derivationPath.writeUInt32BE(harden(501), offset);
442
+ if (account !== void 0) {
443
+ offset = derivationPath.writeUInt32BE(harden(account), offset);
444
+ if (change !== void 0) {
445
+ derivationPath.writeUInt32BE(harden(change), offset);
446
+ }
447
+ }
448
+ return derivationPath;
449
+ }
450
+ var BIP32_HARDENED_BIT = 1 << 31 >>> 0;
451
+ function harden(n) {
452
+ return (n | BIP32_HARDENED_BIT) >>> 0;
453
+ }
454
+ var INS_GET_VERSION = 4;
455
+ var INS_GET_PUBKEY = 5;
456
+ var INS_SIGN_MESSAGE = 6;
457
+ var INS_SIGN_MESSAGE_OFFCHAIN = 7;
458
+ var P1_NON_CONFIRM = 0;
459
+ var P1_CONFIRM = 1;
460
+ var P2_EXTEND = 1;
461
+ var P2_MORE = 2;
462
+ var MAX_PAYLOAD = 255;
463
+ var LEDGER_CLA = 224;
464
+ var OFFCM_MAX_LEDGER_LEN = 1212;
465
+ var OFFCM_MAX_V0_LEN = 65515;
466
+ var OffchainMessage = class _OffchainMessage {
467
+ version;
468
+ messageFormat;
469
+ message;
470
+ signerAddress;
471
+ /**
472
+ * Constructs a new OffchainMessage
473
+ * @param {version: number, messageFormat: number, message: string | Buffer} opts - Constructor parameters
474
+ */
475
+ constructor(opts) {
476
+ this.version = 0;
477
+ this.messageFormat = void 0;
478
+ this.message = void 0;
479
+ this.signerAddress = opts.signerAddress;
480
+ if (!opts) {
481
+ return;
482
+ }
483
+ if (opts.version) {
484
+ this.version = opts.version;
485
+ }
486
+ if (opts.messageFormat) {
487
+ this.messageFormat = opts.messageFormat;
488
+ }
489
+ if (opts.message) {
490
+ this.message = Buffer.from(opts.message);
491
+ if (this.version === 0) {
492
+ if (!this.messageFormat) {
493
+ this.messageFormat = _OffchainMessage.guessMessageFormat(this.message);
494
+ }
495
+ }
496
+ }
497
+ }
498
+ static guessMessageFormat(message) {
499
+ if (Object.prototype.toString.call(message) !== "[object Uint8Array]") {
500
+ return void 0;
501
+ }
502
+ if (message.length <= OFFCM_MAX_LEDGER_LEN) {
503
+ if (_OffchainMessage.isPrintableASCII(message)) {
504
+ return 0;
505
+ } else if (_OffchainMessage.isUTF8(message)) {
506
+ return 1;
507
+ }
508
+ } else if (message.length <= OFFCM_MAX_V0_LEN) {
509
+ if (_OffchainMessage.isUTF8(message)) {
510
+ return 2;
511
+ }
512
+ }
513
+ return void 0;
514
+ }
515
+ static isPrintableASCII(buffer) {
516
+ return buffer && buffer.every((element) => {
517
+ return element == 10 || element >= 32 && element <= 126;
518
+ });
519
+ }
520
+ static isUTF8(buffer) {
521
+ try {
522
+ new TextDecoder("utf8", { fatal: true }).decode(buffer);
523
+ return true;
524
+ } catch {
525
+ return false;
526
+ }
527
+ }
528
+ isValid() {
529
+ if (this.version !== 0) {
530
+ return false;
531
+ }
532
+ if (!this.message) {
533
+ return false;
534
+ }
535
+ const format = _OffchainMessage.guessMessageFormat(this.message);
536
+ return format != null && format === this.messageFormat;
537
+ }
538
+ isLedgerSupported(allowBlindSigning) {
539
+ return this.isValid() && (this.messageFormat === 0 || this.messageFormat === 1 && allowBlindSigning);
540
+ }
541
+ serialize() {
542
+ if (!this.isValid()) {
543
+ throw new Error(`Invalid OffchainMessage: ${JSON.stringify(this)}`);
544
+ }
545
+ const signingDomain = Buffer.concat([Buffer.from([255]), Buffer.from("solana offchain")]);
546
+ const headerVersion = Buffer.alloc(1);
547
+ const applicationDomain = Buffer.alloc(32);
548
+ const messageFormat = Buffer.alloc(1);
549
+ const signerCount = Buffer.alloc(1);
550
+ signerCount.writeUInt8(1);
551
+ const messageLength = Buffer.alloc(2);
552
+ const messageBuffer = Buffer.from(this.message);
553
+ messageFormat.writeUInt8(this.messageFormat);
554
+ const signers = this.signerAddress.toBuffer();
555
+ messageLength.writeUInt16LE(messageBuffer.length);
556
+ return Buffer.concat([
557
+ signingDomain,
558
+ headerVersion,
559
+ applicationDomain,
560
+ messageFormat,
561
+ signerCount,
562
+ signers,
563
+ messageLength,
564
+ messageBuffer
565
+ ]);
566
+ }
567
+ };
568
+ async function getPublicKey(transport, derivationPath) {
569
+ const bytes = await send(transport, INS_GET_PUBKEY, P1_NON_CONFIRM, derivationPath);
570
+ return new import_web3.PublicKey(bytes);
571
+ }
572
+ async function signTransaction(transport, transaction, derivationPath) {
573
+ const paths = Buffer.alloc(1);
574
+ paths.writeUInt8(1, 0);
575
+ const message = (0, import_wallet_adapter_base.isVersionedTransaction)(transaction) ? transaction.message.serialize() : transaction.serializeMessage();
576
+ const data = Buffer.concat([paths, derivationPath, message]);
577
+ return await send(transport, INS_SIGN_MESSAGE, P1_CONFIRM, data);
578
+ }
579
+ async function signMessage2(transport, message, derivationPath) {
580
+ const paths = Buffer.alloc(1);
581
+ paths.writeUInt8(1, 0);
582
+ const data = Buffer.concat([paths, derivationPath, message]);
583
+ return await send(transport, INS_SIGN_MESSAGE_OFFCHAIN, P1_CONFIRM, data);
584
+ }
585
+ async function getAppConfiguration(transport) {
586
+ const [blindSigningEnabled, pubKeyDisplayMode, major, minor, patch] = await send(
587
+ transport,
588
+ INS_GET_VERSION,
589
+ P1_NON_CONFIRM,
590
+ Buffer.alloc(0)
591
+ );
592
+ return {
593
+ blindSigningEnabled: Boolean(blindSigningEnabled),
594
+ pubKeyDisplayMode,
595
+ version: `${major}.${minor}.${patch}`
596
+ };
597
+ }
598
+ async function send(transport, instruction, p1, data) {
599
+ let p2 = 0;
600
+ let offset = 0;
601
+ if (data.length > MAX_PAYLOAD) {
602
+ while (data.length - offset > MAX_PAYLOAD) {
603
+ const buffer2 = data.slice(offset, offset + MAX_PAYLOAD);
604
+ const response2 = await transport.send(LEDGER_CLA, instruction, p1, p2 | P2_MORE, buffer2);
605
+ if (response2.length !== 2) throw new import_hw_transport.TransportStatusError(import_hw_transport.StatusCodes.INCORRECT_DATA);
606
+ p2 |= P2_EXTEND;
607
+ offset += MAX_PAYLOAD;
608
+ }
609
+ }
610
+ const buffer = data.slice(offset);
611
+ const response = await transport.send(LEDGER_CLA, instruction, p1, p2, buffer);
612
+ return response.slice(0, response.length - 2);
613
+ }
614
+
615
+ // src/utils/ledger/adapter.ts
616
+ var LedgerWalletName = "Ledger";
617
+ var LedgerWalletAdapter = class extends import_wallet_adapter_base2.BaseSignerWalletAdapter {
618
+ name = LedgerWalletName;
619
+ url = "https://ledger.com";
620
+ icon = "data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMzUgMzUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0ibTIzLjU4OCAwaC0xNnYyMS41ODNoMjEuNnYtMTZhNS41ODUgNS41ODUgMCAwIDAgLTUuNi01LjU4M3oiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUuNzM5KSIvPjxwYXRoIGQ9Im04LjM0MiAwaC0yLjc1N2E1LjU4NSA1LjU4NSAwIDAgMCAtNS41ODUgNS41ODV2Mi43NTdoOC4zNDJ6Ii8+PHBhdGggZD0ibTAgNy41OWg4LjM0MnY4LjM0MmgtOC4zNDJ6IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDUuNzM5KSIvPjxwYXRoIGQ9Im0xNS4xOCAyMy40NTFoMi43NTdhNS41ODUgNS41ODUgMCAwIDAgNS41ODUtNS42di0yLjY3MWgtOC4zNDJ6IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMS40NzggMTEuNDc4KSIvPjxwYXRoIGQ9Im03LjU5IDE1LjE4aDguMzQydjguMzQyaC04LjM0MnoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUuNzM5IDExLjQ3OCkiLz48cGF0aCBkPSJtMCAxNS4xOHYyLjc1N2E1LjU4NSA1LjU4NSAwIDAgMCA1LjU4NSA1LjU4NWgyLjc1N3YtOC4zNDJ6IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDExLjQ3OCkiLz48L2c+PC9zdmc+";
621
+ supportedTransactionVersions = /* @__PURE__ */ new Set(["legacy", 0]);
622
+ _derivationPath;
623
+ _connecting;
624
+ _transport;
625
+ _publicKey;
626
+ _readyState = typeof window === "undefined" || typeof document === "undefined" || typeof navigator === "undefined" || !navigator.hid ? import_wallet_adapter_base2.WalletReadyState.Unsupported : import_wallet_adapter_base2.WalletReadyState.Loadable;
627
+ constructor(config = {}) {
628
+ super();
629
+ this._derivationPath = config.derivationPath || getDerivationPath(0, 0);
630
+ this._connecting = false;
631
+ this._transport = null;
632
+ this._publicKey = null;
633
+ }
634
+ get publicKey() {
635
+ return this._publicKey;
636
+ }
637
+ get connecting() {
638
+ return this._connecting;
639
+ }
640
+ get readyState() {
641
+ return this._readyState;
642
+ }
643
+ async connect() {
644
+ try {
645
+ if (this.connected || this.connecting) return;
646
+ if (this._readyState !== import_wallet_adapter_base2.WalletReadyState.Loadable) throw new import_wallet_adapter_base2.WalletNotReadyError();
647
+ this._connecting = true;
648
+ let TransportWebHIDClass;
649
+ try {
650
+ TransportWebHIDClass = (await import("@ledgerhq/hw-transport-webhid")).default;
651
+ } catch (error) {
652
+ throw new import_wallet_adapter_base2.WalletLoadError(error?.message, error);
653
+ }
654
+ let transport;
655
+ try {
656
+ transport = await TransportWebHIDClass.create();
657
+ } catch (error) {
658
+ throw new import_wallet_adapter_base2.WalletConnectionError(error?.message, error);
659
+ }
660
+ let publicKey;
661
+ try {
662
+ publicKey = await getPublicKey(transport, this._derivationPath);
663
+ } catch (error) {
664
+ throw new import_wallet_adapter_base2.WalletPublicKeyError(error?.message, error);
665
+ }
666
+ transport.on("disconnect", this._disconnected);
667
+ this._transport = transport;
668
+ this._publicKey = publicKey;
669
+ this.emit("connect", publicKey);
670
+ } catch (error) {
671
+ this.emit("error", error);
672
+ throw error;
673
+ } finally {
674
+ this._connecting = false;
675
+ }
676
+ }
677
+ async disconnect() {
678
+ const transport = this._transport;
679
+ if (transport) {
680
+ transport.off("disconnect", this._disconnected);
681
+ this._transport = null;
682
+ this._publicKey = null;
683
+ try {
684
+ await transport.close();
685
+ } catch (error) {
686
+ this.emit("error", new import_wallet_adapter_base2.WalletDisconnectionError(error?.message, error));
687
+ }
688
+ }
689
+ this.emit("disconnect");
690
+ }
691
+ async signTransaction(transaction) {
692
+ try {
693
+ const transport = this._transport;
694
+ const publicKey = this._publicKey;
695
+ if (!transport || !publicKey) throw new import_wallet_adapter_base2.WalletNotConnectedError();
696
+ try {
697
+ const signature = await signTransaction(transport, transaction, this._derivationPath);
698
+ transaction.addSignature(publicKey, signature);
699
+ } catch (error) {
700
+ throw new import_wallet_adapter_base2.WalletSignTransactionError(error?.message, error);
701
+ }
702
+ return transaction;
703
+ } catch (error) {
704
+ this.emit("error", error);
705
+ throw error;
706
+ }
707
+ }
708
+ async signMessage(message) {
709
+ try {
710
+ try {
711
+ const transport = this._transport;
712
+ const publicKey = this._publicKey;
713
+ if (!transport || !publicKey) throw new import_wallet_adapter_base2.WalletNotConnectedError();
714
+ const appConfig = await getAppConfiguration(transport);
715
+ const [major, minor] = appConfig.version.split(".").map(Number);
716
+ if (major < 1 || major === 1 && minor < 8) {
717
+ throw new import_wallet_adapter_base2.WalletSignMessageError("Signing off-chain messages requires Solana Ledger App 1.8.0 or later");
718
+ }
719
+ const offchainMessage = new OffchainMessage({
720
+ message: Buffer.from(message.buffer),
721
+ signerAddress: publicKey
722
+ });
723
+ if (!offchainMessage.isLedgerSupported(appConfig.blindSigningEnabled)) {
724
+ if (!offchainMessage.isValid()) {
725
+ throw new import_wallet_adapter_base2.WalletSignMessageError("Message is not valid for signing.");
726
+ } else if (offchainMessage.messageFormat === 1 && !appConfig.blindSigningEnabled) {
727
+ throw new import_wallet_adapter_base2.WalletSignMessageError(
728
+ "Message contains non-ASCII characters and requires blind signing to be enabled on your Ledger device."
729
+ );
730
+ } else if (offchainMessage.messageFormat === 2) {
731
+ throw new import_wallet_adapter_base2.WalletSignMessageError("Message is too long to be signed on Ledger device.");
732
+ } else {
733
+ throw new import_wallet_adapter_base2.WalletSignMessageError("Message format is not supported by Ledger device.");
734
+ }
735
+ }
736
+ const signature = await signMessage2(transport, offchainMessage.serialize(), this._derivationPath);
737
+ return { signature: new Uint8Array(signature), signedMessage: offchainMessage.serialize() };
738
+ } catch (error) {
739
+ throw new import_wallet_adapter_base2.WalletSignMessageError(error?.message, error);
740
+ }
741
+ } catch (error) {
742
+ this.emit("error", error);
743
+ throw error;
744
+ }
745
+ }
746
+ _disconnected = () => {
747
+ const transport = this._transport;
748
+ if (transport) {
749
+ transport.off("disconnect", this._disconnected);
750
+ this._transport = null;
751
+ this._publicKey = null;
752
+ this.emit("error", new import_wallet_adapter_base2.WalletDisconnectedError());
753
+ this.emit("disconnect");
754
+ }
755
+ };
756
+ };
757
+
758
+ // src/providers/solana/index.tsx
422
759
  var import_jsx_runtime3 = require("react/jsx-runtime");
423
760
  var solStore = {
424
761
  connectModal: null,
@@ -447,10 +784,12 @@ var SolWallet = class extends WalletBase {
447
784
  try {
448
785
  const provider = solStore.account;
449
786
  const encodedMessage = new TextEncoder().encode(message);
450
- const signedMessage = await provider.signMessage?.(encodedMessage);
787
+ const result = await provider.signMessage?.(encodedMessage);
788
+ const { signature, signedMessage } = result instanceof Uint8Array ? { signature: result, signedMessage: "" } : result;
451
789
  return {
452
790
  message,
453
- signature: import_bs58.default.encode(signedMessage)
791
+ signature: import_bs58.default.encode(signature),
792
+ signedMessage: signedMessage instanceof Uint8Array ? import_bs58.default.encode(signedMessage) : ""
454
793
  };
455
794
  } catch (error) {
456
795
  console.error(error);
@@ -458,30 +797,40 @@ var SolWallet = class extends WalletBase {
458
797
  }
459
798
  }
460
799
  signin(statement, prepare = true) {
461
- return new Promise((resolve) => {
462
- const signCallback = (data) => {
463
- this.publicKey = data.publicKey?.toString();
464
- this.address = this.publicKey;
465
- this.chainId = 1;
466
- let fullMessage = statement;
467
- if (prepare) {
468
- const msg = prepareSignMessage({ statement, chainId: "1", address: this.address });
469
- fullMessage = get4361Message(msg);
800
+ return new Promise((resolve, reject) => {
801
+ try {
802
+ const signCallback = async (data) => {
803
+ try {
804
+ this.publicKey = data.publicKey?.toString();
805
+ this.address = this.publicKey;
806
+ this.chainId = 1;
807
+ let fullMessage = statement;
808
+ if (prepare) {
809
+ const msg = prepareSignMessage({ statement, chainId: "1", address: this.address });
810
+ fullMessage = get4361Message(msg);
811
+ }
812
+ const res = await this.sign(fullMessage);
813
+ resolve(res);
814
+ } catch (error) {
815
+ console.error("Error in signCallback:", error);
816
+ reject(error);
817
+ }
818
+ };
819
+ if (this.isConnected) {
820
+ signCallback(solStore.account);
821
+ return;
470
822
  }
471
- const res = this.sign(fullMessage);
472
- resolve(res);
473
- };
474
- if (this.isConnected) {
475
- signCallback(solStore.account);
476
- return;
823
+ solStore.counter++;
824
+ this.connect();
825
+ const eventKey = getEventKey3();
826
+ eventBus3.once(eventKey, (data) => {
827
+ console.log("listen event key success, event key = %s, data = %j", eventKey, data);
828
+ signCallback(data);
829
+ });
830
+ } catch (error) {
831
+ console.error("Error in signin:", error);
832
+ reject(error);
477
833
  }
478
- solStore.counter++;
479
- this.connect();
480
- const eventKey = getEventKey3();
481
- eventBus3.once(eventKey, (data) => {
482
- console.log("listen event key success, event key = %s, data = %j", eventKey, data);
483
- signCallback(data);
484
- });
485
834
  });
486
835
  }
487
836
  };
@@ -507,7 +856,13 @@ var SolanaProvider = ({
507
856
  }) => {
508
857
  const endpoint = (0, import_tokentable_core3.clusterApiUrl)(cluster ? cluster : "mainnet-beta");
509
858
  const defaultWallets = (0, import_react3.useMemo)(
510
- () => [new import_wallet_adapter_wallets.PhantomWalletAdapter(), new import_wallet_adapter_wallets.TrustWalletAdapter(), new import_wallet_adapter_wallets.LedgerWalletAdapter()],
859
+ () => [
860
+ new import_wallet_adapter_wallets.PhantomWalletAdapter(),
861
+ new import_wallet_adapter_wallets.TrustWalletAdapter(),
862
+ new LedgerWalletAdapter({
863
+ derivationPath: getDerivationPath(0)
864
+ })
865
+ ],
511
866
  []
512
867
  );
513
868
  const onError = (0, import_react3.useCallback)((error) => {