> For the complete documentation index, see [llms.txt](https://docs.armchain.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.armchain.org/developers/overview-2.md).

# Wallets

This guide covers two perspectives: connecting your **dApp** to the Armchain Wallet, and building **custom wallet** support for Armchain.

## Armchain Wallet

The **Armchain Wallet** is the official browser extension wallet for the Armchain network. It is a fork of Wigwam wallet, customized for ML-DSA44 post-quantum cryptography.

### Key Features

* **ML-DSA44 key management**: Generates and stores post-quantum keys
* **HD wallet derivation**: BIP-39 mnemonic with Armchain coin type (`65536`)
* **Hardened derivation only**: All child keys use hardened paths for security
* **Type 3 transactions**: Signs PQC transactions natively
* **EIP-1559 gas pricing**: Dynamic fee support
* **Multi-account support**: Derive multiple accounts from a single seed phrase
* **ARM token support**: Native token balance display and transfers

### Network Configuration

The wallet ships with built-in Armchain network configurations:

```typescript
// Devnet
{
  chainId: 55,
  name: "Armchain Devnet",
  rpcUrls: ["https://www.armchain.org/devnet"],
  nativeCurrency: { symbol: "ARM", name: "Armchain", decimals: 18 },
}

// Local Development
{
  chainId: 55,
  name: "Armchain Local",
  rpcUrls: ["http://localhost:4000"],
  nativeCurrency: { symbol: "ARM", name: "Armchain", decimals: 18 },
}
```

## For dApp Developers

### Connecting to the Wallet

The Armchain Wallet injects a provider into the browser, similar to MetaMask:

```typescript
// Check if wallet is available
if (typeof window.ethereum !== "undefined") {
  // Armchain Wallet detected
}

// Request account access
const accounts = await window.ethereum.request({
  method: "eth_requestAccounts"
});
console.log("Connected account:", accounts[0]);
```

### Using with Armchain Ethers SDK

```typescript
import { BrowserProvider, Contract } from "@armchain-ethersv6/ethers";

// Connect to injected wallet
const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();

console.log("Connected:", await signer.getAddress());
console.log("Balance:", await provider.getBalance(signer.address));

// Interact with contracts
const contract = new Contract(contractAddress, abi, signer);
const tx = await contract.someFunction(arg1, arg2);
await tx.wait();
```

### Handling Chain Switching

```typescript
// Switch to Armchain devnet
try {
  await window.ethereum.request({
    method: "wallet_switchEthereumChain",
    params: [{ chainId: "0x37" }],  // 55 in hex
  });
} catch (switchError) {
  // Chain not added - request to add it
  if (switchError.code === 4902) {
    await window.ethereum.request({
      method: "wallet_addEthereumChain",
      params: [{
        chainId: "0x37",
        chainName: "Armchain Devnet",
        rpcUrls: ["https://www.armchain.org/devnet"],
        nativeCurrency: {
          name: "Armchain",
          symbol: "ARM",
          decimals: 18,
        },
        blockExplorerUrls: ["https://www.armchain.org/explorer"],
      }],
    });
  }
}
```

### Listening for Events

```typescript
// Account changed
window.ethereum.on("accountsChanged", (accounts) => {
  console.log("Account switched to:", accounts[0]);
  // Refresh account-dependent UI
});

// Chain changed
window.ethereum.on("chainChanged", (chainId) => {
  console.log("Chain switched to:", parseInt(chainId, 16));
  // Reload the page or refresh state
  window.location.reload();
});

// Disconnected
window.ethereum.on("disconnect", () => {
  console.log("Wallet disconnected");
});
```

### Signing Messages

```typescript
const signer = await provider.getSigner();

// Personal sign (EIP-191)
const message = "Sign this message to verify your identity";
const signature = await signer.signMessage(message);

// The signature is an ML-DSA44 signature (3,732 bytes)
console.log("Signature:", signature);
```

### EIP-712 Typed Data Signing

```typescript
const domain = {
  name: "My dApp",
  version: "1",
  chainId: 55,
  verifyingContract: "0xCONTRACT_ADDRESS",
};

const types = {
  Order: [
    { name: "maker", type: "address" },
    { name: "amount", type: "uint256" },
    { name: "nonce", type: "uint256" },
  ],
};

const value = {
  maker: await signer.getAddress(),
  amount: parseEther("100"),
  nonce: 1,
};

const signature = await signer.signTypedData(domain, types, value);
```

## For Wallet Developers

If you're building a wallet that supports Armchain, here are the key requirements. The recommended approach is to use the `@armchain-ethersv6/ethers` SDK, which handles all cryptographic operations internally.

### Key Generation

Armchain uses ML-DSA44 (NIST FIPS 204) for all key operations. Key pairs are generated from a 32-byte random seed.

| Component   | Size        |
| ----------- | ----------- |
| Private Key | 2,560 bytes |
| Public Key  | 1,312 bytes |

The SDK's `Wallet.createRandom()` and `HDNodeWallet.fromPhrase()` handle key generation automatically. If implementing from scratch, use a FIPS 204-compliant ML-DSA44 library.

### HD Wallet Derivation

Armchain uses a BIP-44 compatible derivation path with all hardened indices:

```
m/44'/65536'/account'/0/address'
```

> **Critical**: Non-hardened derivation is NOT supported with ML-DSA44. All path components must use hardened derivation.

Since ML-DSA44 key generation takes a 32-byte seed (unlike ECDSA's scalar), the HD derivation chain produces child seeds rather than child keys directly. See the `@armchain-ethersv6/ethers` SDK source for the reference implementation.

```typescript
// Derive accounts using the SDK
import { HDNodeWallet } from "@armchain-ethersv6/ethers";

const wallet = HDNodeWallet.fromPhrase(mnemonic);
const child = wallet.derivePath("m/44'/65536'/0'/0/0'");
console.log("Address:", child.address);
```

### Transaction Signing

All Armchain transactions must be Type 3 (PQC). The SDK handles transaction construction and signing:

```typescript
import { Wallet, JsonRpcProvider } from "@armchain-ethersv6/ethers";

const provider = new JsonRpcProvider("https://www.armchain.org/devnet");
const wallet = new Wallet(privateKey, provider);

// The SDK automatically creates Type 3 transactions and signs with ML-DSA44
const tx = await wallet.sendTransaction({
  to: recipient,
  value: amount,
  // type: 3 is auto-set
});
```

For custom implementations, the signing process involves computing a transaction hash and producing an ML-DSA44 signature blob that includes both the raw signature and the public key (since ML-DSA44 does not support public key recovery). Refer to the [Transaction Types](/pqc/transaction-types.md) page for the wire format specification.

### Address Computation

Armchain addresses are derived from ML-DSA44 public keys using `keccak256`, producing standard 20-byte Ethereum-format addresses. The SDK handles this automatically via `SigningKey.computeAddress()`.

### Key Storage Considerations

ML-DSA44 private keys are **2,560 bytes** (vs 32 bytes for ECDSA). This affects:

| Aspect              | ECDSA       | ML-DSA44        | Impact                             |
| ------------------- | ----------- | --------------- | ---------------------------------- |
| Private key storage | 32 bytes    | 2,560 bytes     | \~80× more storage                 |
| Key encryption time | Fast        | Slightly slower | Negligible                         |
| Key backup size     | Small       | Larger          | QR codes may not work for raw keys |
| Mnemonic backup     | 12/24 words | 12/24 words     | Same: mnemonic derives the key     |

> **Recommendation**: Always support mnemonic-based backup. The 12/24 word seed phrase is the same size regardless of the underlying key type.

## Common Integration Patterns

### Connect Wallet Button

```typescript
async function connectWallet() {
  if (!window.ethereum) {
    alert("Please install Armchain Wallet");
    return;
  }

  try {
    const accounts = await window.ethereum.request({
      method: "eth_requestAccounts"
    });
    
    const chainId = await window.ethereum.request({
      method: "eth_chainId"
    });

    if (parseInt(chainId, 16) !== 55) {
      // Not on Armchain - request switch
      await switchToArmchain();
    }

    return accounts[0];
  } catch (error) {
    console.error("Connection failed:", error);
  }
}
```

### Transaction Helper

```typescript
import { BrowserProvider, parseEther } from "@armchain-ethersv6/ethers";

async function sendARM(to: string, amount: string) {
  const provider = new BrowserProvider(window.ethereum);
  const signer = await provider.getSigner();

  const tx = await signer.sendTransaction({
    to,
    value: parseEther(amount),
  });

  // Instant finality means one confirmation is enough
  const receipt = await tx.wait();
  return receipt;
}
```

## Further Reading

* [Armchain Ethers SDK](/developers/overview-1.md) for the full SDK reference
* [PQC Overview](/pqc/overview.md) to understand post-quantum cryptography
* [Transaction Types](/pqc/transaction-types.md) for the Type 3 transaction format
* [Network Configuration](/get-started/network-configuration.md) for RPC endpoints and chain details
