# Tron Signer Kit

This module provides the implementation of the Ledger Tron signer of the Device Management Kit. It enables interaction with the Tron (TRX) application on a Ledger device including:

- Retrieving the Tron address using a given derivation path
- Signing a Tron transaction
- Signing a Tron transaction hash
- Signing a personal message
- Retrieving the app configuration
- Computing an ECDH shared secret with a peer public key

## 🔹 Index

1. [How it works](#-how-it-works)
2. [Installation](#-installation)
3. [Initialisation](#-initialisation)
4. [Use Cases](#-use-cases)
   - [Get App Configuration](#use-case-1-get-app-configuration)
   - [Get Address](#use-case-2-get-address)
   - [Sign Transaction](#use-case-3-sign-transaction)
   - [Sign Transaction Hash](#use-case-4-sign-transaction-hash)
   - [Sign Personal Message](#use-case-5-sign-personal-message)
   - [Get ECDH Secret](#use-case-6-get-ecdh-secret)
5. [Observable Behavior](#-observable-behavior)
6. [Example](#-example)

## 🔹 How it works

The Ledger Tron Signer utilizes the advanced capabilities of the Ledger device to provide secure operations for end users. It takes advantage of the interface provided by the Device Management Kit to establish communication with the Ledger device and execute various operations. The communication with the Ledger device is performed using [APDU](https://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit)s (Application Protocol Data Units), which are encapsulated within the `Command` object. These commands are then organized into tasks, allowing for the execution of complex operations with one or more APDUs. The tasks are further encapsulated within `DeviceAction` objects to handle different real-world scenarios. Finally, the Signer exposes dedicated and independent use cases that can be directly utilized by end users.

## 🔹 Installation

> **Note:** This module is not standalone; it depends on the [@ledgerhq/device-management-kit](https://github.com/LedgerHQ/device-sdk-ts/tree/develop/packages/device-management-kit) package, so you need to install it first.

To install the `device-signer-kit-tron` package, run the following command:

```sh
npm install @ledgerhq/device-signer-kit-tron
```

## 🔹 Initialisation

To initialise a Tron signer instance, you need a Ledger Device Management Kit instance and the ID of the session of the connected device. Use the `SignerTrxBuilder`:

```typescript
const signerTrx = new SignerTrxBuilder({ dmk, sessionId }).build();
```

## 🔹 Use Cases

The `SignerTrxBuilder.build()` method will return a `SignerTrx` instance that exposes 6 dedicated methods, each of which calls an independent use case. Each use case will return an object that contains an observable and a method called `cancel`.

> **Note:** Tron uses the BIP44 coin type `195`, so derivation paths look like `"44'/195'/0'/0/0"`.

---

### Use Case 1: Get App Configuration

This method allows users to retrieve the app configuration from the Ledger device.

```typescript
const { observable, cancel } = signerTrx.getAppConfiguration();
```

#### **Returns**

- `observable` Emits DeviceActionState updates, including the following details:

```typescript
type AppConfiguration = {
  version: string;
  versionN: number;
  allowData: boolean;
  allowContract: boolean;
  truncateAddress: boolean;
  signByHash: boolean;
};
```

- `cancel` A function to cancel the action on the Ledger device.

---

### Use Case 2: Get Address

This method allows users to retrieve the Tron address based on a given `derivationPath`.

```typescript
const { observable, cancel } = signerTrx.getAddress(derivationPath, options);
```

#### **Parameters**

- `derivationPath`

  - **Required**
  - **Type:** `string` (e.g., `"44'/195'/0'/0/0"`)
  - The derivation path used for the Tron address. See [here](https://www.ledger.com/blog/understanding-crypto-addresses-and-derivation-paths) for more information.

- `options`

  - Optional

  - Type: `AddressOptions`

    ```typescript
    type AddressOptions = {
      checkOnDevice?: boolean;
      skipOpenApp?: boolean;
    };
    ```

  - `checkOnDevice`: An optional boolean indicating whether user confirmation on the device is required (`true`) or not (`false`).

  - `skipOpenApp`: An optional boolean indicating whether to skip opening the Tron app automatically (`true`) or not (`false`).

#### **Returns**

- `observable` Emits DeviceActionState updates, including the following details:

```typescript
type GetAddressCommandResponse = {
  publicKey: string; // hex-encoded public key
  address: string; // Base58 Tron address (e.g. "TWdnWBzFdBP1b8sqZ5RcFDbkV3sBmnxsYu")
  chainCode?: string;
};
```

- `cancel` A function to cancel the action on the Ledger device.

---

### Use Case 3: Sign Transaction

This method allows users to sign a Tron transaction.

```typescript
const { observable, cancel } = signerTrx.signTransaction(
  derivationPath,
  transaction,
  options,
);
```

#### **Parameters**

- `derivationPath`

  - **Required**
  - **Type:** `string` (e.g., `"44'/195'/0'/0/0"`)
  - The derivation path used for the Tron transaction.

- `transaction`

  - **Required**
  - **Type:** `Uint8Array`
  - The serialized (protobuf) transaction to be signed.

- `options`

  - Optional

  - Type: `TransactionOptions`

    ```typescript
    type TransactionOptions = {
      skipOpenApp?: boolean;
    };
    ```

  - `skipOpenApp`: An optional boolean indicating whether to skip opening the Tron app automatically (`true`) or not (`false`).

#### **Returns**

- `observable` Emits DeviceActionState updates, including the following details:

```typescript
type Signature = Uint8Array; // 65-byte signature
```

- `cancel` A function to cancel the action on the Ledger device.

---

### Use Case 4: Sign Transaction Hash

This method allows users to sign a raw Tron transaction hash. Signing a bare hash is a blind-signing operation, so use it with caution.

```typescript
const { observable, cancel } = signerTrx.signTransactionHash(
  derivationPath,
  transactionHash,
  options,
);
```

#### **Parameters**

- `derivationPath`

  - **Required**
  - **Type:** `string` (e.g., `"44'/195'/0'/0/0"`)
  - The derivation path used for the Tron transaction hash.

- `transactionHash`

  - **Required**
  - **Type:** `Uint8Array`
  - The 32-byte transaction hash to be signed.

- `options`

  - Optional

  - Type: `TransactionOptions`

    ```typescript
    type TransactionOptions = {
      skipOpenApp?: boolean;
    };
    ```

  - `skipOpenApp`: An optional boolean indicating whether to skip opening the Tron app automatically (`true`) or not (`false`).

#### **Returns**

- `observable` Emits DeviceActionState updates, including the following details:

```typescript
type Signature = Uint8Array; // 65-byte signature
```

- `cancel` A function to cancel the action on the Ledger device.

---

### Use Case 5: Sign Personal Message

This method allows users to sign a personal message (TRON's `signMessage` / TIP-191 flow).

```typescript
const { observable, cancel } = signerTrx.signPersonalMessage(
  derivationPath,
  message,
  options,
);
```

#### **Parameters**

- `derivationPath`

  - **Required**
  - **Type:** `string` (e.g., `"44'/195'/0'/0/0"`)
  - The derivation path used to sign the message.

- `message`

  - **Required**
  - **Type:** `string | Uint8Array`
  - The message to be signed, either as a UTF-8 string or as raw bytes.

- `options`

  - Optional

  - Type: `MessageOptions`

    ```typescript
    type MessageOptions = {
      skipOpenApp?: boolean;
    };
    ```

  - `skipOpenApp`: An optional boolean indicating whether to skip opening the Tron app automatically (`true`) or not (`false`).

#### **Returns**

- `observable` Emits DeviceActionState updates, including the following details:

```typescript
type Signature = Uint8Array; // 65-byte signature
```

- `cancel` A function to cancel the action on the Ledger device.

---

### Use Case 6: Get ECDH Secret

This method computes an ECDH shared secret between the device key (derived from the BIP32 path) and a peer's uncompressed secp256k1 public key. The operation is shown on the device for approval.

```typescript
const { observable, cancel } = signerTrx.getECDHSecret(
  derivationPath,
  publicKey,
  options,
);
```

#### **Parameters**

- `derivationPath`

  - **Required**
  - **Type:** `string` (e.g., `"44'/195'/0'/0/0"`)
  - The derivation path used to derive the device key.

- `publicKey`

  - **Required**
  - **Type:** `Uint8Array`
  - The peer's uncompressed secp256k1 public key (65 bytes, `0x04 || X || Y`).

- `options`

  - Optional

  - Type: `EcdhOptions`

    ```typescript
    type EcdhOptions = {
      skipOpenApp?: boolean;
    };
    ```

  - `skipOpenApp`: An optional boolean indicating whether to skip opening the Tron app automatically (`true`) or not (`false`).

#### **Returns**

- `observable` Emits DeviceActionState updates, including the following details:

```typescript
// The 65-byte ECDH shared point (0x04 || X || Y).
type GetECDHSecretDAOutput = Uint8Array;
```

- `cancel` A function to cancel the action on the Ledger device.

---

## 🔹 Observable Behavior

Each method returns an [Observable](https://rxjs.dev/guide/observable) emitting updates structured as [`DeviceActionState`](https://github.com/LedgerHQ/device-sdk-ts/blob/develop/packages/device-management-kit/src/api/device-action/model/DeviceActionState.ts). These updates reflect the operation's progress and status:

- **NotStarted**: The operation hasn't started.
- **Pending**: The operation is in progress and may require user interaction.
- **Stopped**: The operation was canceled or stopped.
- **Completed**: The operation completed successfully, with results available.
- **Error**: An error occurred.

**Example Observable Subscription:**

```typescript
observable.subscribe({
  next: (state: DeviceActionState) => {
    switch (state.status) {
      case DeviceActionStatus.NotStarted: {
        console.log("The action is not started yet.");
        break;
      }
      case DeviceActionStatus.Pending: {
        const {
          intermediateValue: { requiredUserInteraction },
        } = state;
        // Access the intermediate value here, explained below
        console.log(
          "The action is pending and the intermediate value is: ",
          intermediateValue,
        );
        break;
      }
      case DeviceActionStatus.Stopped: {
        console.log("The action has been stopped.");
        break;
      }
      case DeviceActionStatus.Completed: {
        const { output } = state;
        // Access the output of the completed action here
        console.log("The action has been completed: ", output);
        break;
      }
      case DeviceActionStatus.Error: {
        const { error } = state;
        // Access the error here if occurred
        console.log("An error occurred during the action: ", error);
        break;
      }
    }
  },
});
```

**Intermediate Values in Pending Status:**

When the status is DeviceActionStatus.Pending, the state will include an `intermediateValue` object that provides useful information for interaction:

```typescript
const { requiredUserInteraction } = intermediateValue;

switch (requiredUserInteraction) {
  case UserInteractionRequired.VerifyAddress: {
    // User needs to verify the address displayed on the device
    console.log("User needs to verify the address displayed on the device.");
    break;
  }
  case UserInteractionRequired.SignTransaction: {
    // User needs to sign the transaction displayed on the device
    console.log("User needs to sign the transaction displayed on the device.");
    break;
  }
  case UserInteractionRequired.SignPersonalMessage: {
    // User needs to sign the message displayed on the device
    console.log("User needs to sign the message displayed on the device.");
    break;
  }
  case UserInteractionRequired.None: {
    // No user action required
    console.log("No user action needed.");
    break;
  }
  case UserInteractionRequired.UnlockDevice: {
    // User needs to unlock the device
    console.log("The user needs to unlock the device.");
    break;
  }
  case UserInteractionRequired.ConfirmOpenApp: {
    // User needs to confirm on the device to open the app
    console.log("The user needs to confirm on the device to open the app.");
    break;
  }
  default:
    // Type guard to ensure all cases are handled
    const uncaughtUserInteraction: never = requiredUserInteraction;
    console.error("Unhandled user interaction case:", uncaughtUserInteraction);
}
```

## 🔹 Example

We encourage you to explore the Tron Signer by trying it out in our online [sample application](https://app.devicesdk.ledger-test.com/). Experience how it works and see its capabilities in action. Of course, you will need a Ledger device connected.
