# Ethers SDK

The `@armchain-ethersv6/ethers` library is Armchain's official JavaScript/TypeScript SDK. If you're familiar with **ethers.js v6**, this is essentially a drop-in replacement with the same API and same patterns, but with all cryptographic operations swapped to use **ML-DSA44 post-quantum signatures**.

## Why This SDK?

Standard ethers.js uses ECDSA for signing, which Armchain nodes reject. Any application that **signs transactions or messages** needs this SDK. Read-only operations (querying balances, reading contract state) work fine with standard ethers.js.

| Operation                | Standard ethers.js | Armchain Ethers SDK  |
| ------------------------ | ------------------ | -------------------- |
| Read blockchain state    | ✅ Works            | ✅ Works              |
| Query balances/blocks    | ✅ Works            | ✅ Works              |
| Call view functions      | ✅ Works            | ✅ Works              |
| **Sign transactions**    | ❌ Rejected         | ✅ ML-DSA44           |
| **Sign messages**        | ❌ Incompatible     | ✅ ML-DSA44           |
| **Create wallets**       | ❌ ECDSA keys       | ✅ ML-DSA44 keys      |
| **HD wallet derivation** | ❌ Wrong coin type  | ✅ Armchain coin type |

## Installation

```bash
npm install @armchain-ethersv6/ethers
```

## Quick Start

### Connect to Armchain

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

// Devnet
const provider = new JsonRpcProvider("https://www.armchain.org/devnet");

// Local (Fakenet)
const localProvider = new JsonRpcProvider("http://localhost:4000");

// Query blockchain
const blockNumber = await provider.getBlockNumber();
const balance = await provider.getBalance("0xADDRESS");
console.log("Block:", blockNumber, "Balance:", balance.toString());
```

### Create a Wallet

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

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

// From private key (ML-DSA44, 2,560 bytes)
const wallet = new Wallet(privateKey, provider);
console.log("Address:", wallet.address);

// Random wallet
const randomWallet = Wallet.createRandom();
console.log("New address:", randomWallet.address);
console.log("New private key:", randomWallet.privateKey);
```

### Send a Transaction

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

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

const tx = await wallet.sendTransaction({
  to: "0xRECIPIENT_ADDRESS",
  value: parseEther("1.0"),
  // type: 3 is automatically set by the SDK
});

console.log("TX Hash:", tx.hash);

console.log("Confirmed in block:", receipt.blockNumber);
```

### Interact with a Smart Contract

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

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

// ERC-20 token contract
const tokenAbi = [
  "function balanceOf(address) view returns (uint256)",
  "function transfer(address to, uint256 amount) returns (bool)",
  "function symbol() view returns (string)",
  "event Transfer(address indexed from, address indexed to, uint256 value)"
];

const token = new Contract("0xTOKEN_ADDRESS", tokenAbi, wallet);

// Read (no signature needed)
const symbol = await token.symbol();
const balance = await token.balanceOf(wallet.address);
console.log(`${symbol} balance:`, balance.toString());

// Write (auto-signed with ML-DSA44)
const tx = await token.transfer("0xRECIPIENT", parseEther("100"));
const receipt = await tx.wait();
console.log("Transfer confirmed:", receipt.hash);
```

### Deploy a Contract

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

const provider = new JsonRpcProvider("http://localhost:4000");
const wallet = new Wallet(privateKey, provider);

const abi = [/* contract ABI */];
const bytecode = "0x...";  // Compiled contract bytecode

const factory = new ContractFactory(abi, bytecode, wallet);
const contract = await factory.deploy(/* constructor args */);
await contract.waitForDeployment();

console.log("Deployed at:", await contract.getAddress());
```

## HD Wallet (Hierarchical Deterministic)

Armchain uses a custom HD wallet derivation path:

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

| Component     | Value           | Description                     |
| ------------- | --------------- | ------------------------------- |
| Purpose       | `44'`           | BIP-44 standard                 |
| Coin Type     | `65536'`        | Armchain's registered coin type |
| Account       | `0'`, `1'`, ... | Account index (hardened)        |
| Change        | `0`             | External addresses              |
| Address Index | `0'`, `1'`, ... | Address index (hardened)        |

> **All derivation is hardened** (denoted by `'`). Non-hardened derivation is not supported with ML-DSA44.

### Create from Mnemonic

```typescript
import { HDNodeWallet, Mnemonic } from "@armchain-ethersv6/ethers";

// Create from seed phrase
const mnemonic = "word1 word2 word3 ...";  // 12 or 24 words
const wallet = HDNodeWallet.fromPhrase(mnemonic);
console.log("Address:", wallet.address);

// Derive multiple accounts
for (let i = 0; i < 5; i++) {
  const path = `m/44'/65536'/${i}'/0/0'`;
  const child = wallet.derivePath(path);
  console.log(`Account ${i}:`, child.address);
}
```

### Generate a New Mnemonic

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

const wallet = Wallet.createRandom();
console.log("Mnemonic:", wallet.mnemonic.phrase);
console.log("Address:", wallet.address);
console.log("Path:", wallet.path);
```

## Signing Messages

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

const wallet = new Wallet(privateKey);

// Sign a message
const message = "Hello, Armchain!";
const signature = await wallet.signMessage(message);
console.log("Signature:", signature);

// The signature contains the full PQC signature blob:
// - Raw ML-DSA44 signature (2,420 bytes) + public key (1,312 bytes) = 3,732 bytes total
```

## Transaction Types

The SDK automatically creates **Type 3 (PQC) transactions**:

```typescript
// All transactions are Type 3 by default
const tx = await wallet.sendTransaction({
  to: recipient,
  value: parseEther("1.0"),
  // type: 3 is auto-set
  // gasLimit, maxFeePerGas, maxPriorityFeePerGas are auto-estimated
});
```

### Manual Transaction Construction

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

const tx = Transaction.from({
  type: 3,
  chainId: 55,
  nonce: 42,
  to: "0xRECIPIENT",
  value: parseEther("1.0"),
  data: "0x",
  gasLimit: 21000n,
  maxFeePerGas: parseUnits("20", "gwei"),
  maxPriorityFeePerGas: parseUnits("2", "gwei"),
});

// Sign
const signedTx = await wallet.signTransaction(tx);
console.log("Signed TX:", signedTx);

// Broadcast
const response = await provider.broadcastTransaction(signedTx);
```

## Key Sizes and Formats

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

// Generate a new wallet (handles ML-DSA44 key generation internally)
const wallet = Wallet.createRandom();
console.log("Address:", wallet.address);
console.log("Private key size:", wallet.privateKey.length);  // Large: ML-DSA44 keys are 2,560 bytes
```

### Size Reference

| Component      | Size        | Description                                                          |
| -------------- | ----------- | -------------------------------------------------------------------- |
| Private Key    | 2,560 bytes | ML-DSA44 secret key                                                  |
| Public Key     | 1,312 bytes | ML-DSA44 public key                                                  |
| Raw Signature  | 2,420 bytes | ML-DSA44 detached signature                                          |
| Signature Blob | 3,732 bytes | Raw signature (2,420) + public key (1,312), included in transactions |

## API Compatibility

The SDK maintains the same API as ethers.js v6 wherever possible:

```typescript
// These all work the same as standard ethers.js v6
import {
  JsonRpcProvider,
  WebSocketProvider,
  Contract,
  ContractFactory,
  Wallet,
  HDNodeWallet,
  parseEther,
  parseUnits,
  formatEther,
  formatUnits,
  isAddress,
  getAddress,
  keccak256,
  AbiCoder,
  Interface,
  EventLog,
  // ... and more
} from "@armchain-ethersv6/ethers";
```

### Removed/Changed Methods

| Method                             | Status  | Reason                              |
| ---------------------------------- | ------- | ----------------------------------- |
| `Signature.recoverPublicKey()`     | Removed | Public key is embedded in signature |
| `SigningKey.computeSharedSecret()` | Removed | ECDH not applicable to DSA          |
| `SigningKey.compressedPublicKey`   | Removed | No compression in ML-DSA44          |
| `Transaction.unsignedSerialized`   | Removed | All PQC txns must be signed         |

### Legacy Compatibility Properties

For migration convenience, these properties still exist but return compatibility values:

```typescript
const sig = Signature.from(signatureBlob);
sig.r;        // First 32 bytes of signature (for compatibility)
sig.s;        // Next 32 bytes (for compatibility)  
sig.v;        // Always 27 (not used in PQC)
sig.yParity;  // Always 0 (not applicable)
```

## Error Handling

```typescript
try {
  const tx = await wallet.sendTransaction({
    to: recipient,
    value: parseEther("1000000"),  // More than balance
  });
} catch (error) {
  if (error.code === "INSUFFICIENT_FUNDS") {
    console.log("Not enough ARM");
  } else if (error.code === "NONCE_EXPIRED") {
    console.log("Nonce already used");
  } else if (error.code === "UNPREDICTABLE_GAS_LIMIT") {
    console.log("Transaction would revert");
  } else {
    console.error("Unknown error:", error);
  }
}
```

## Migration from Standard ethers.js

If you're porting an Ethereum dApp to Armchain:

### Step 1: Replace the Package

```bash
npm uninstall ethers
npm install @armchain-ethersv6/ethers
```

### Step 2: Update Imports

```typescript
// Before
import { ethers } from "ethers";

// After
import { ethers } from "@armchain-ethersv6/ethers";
```

### Step 3: Update RPC Endpoint

```typescript
// Before
const provider = new JsonRpcProvider("https://eth-mainnet.g.alchemy.com/...");

// After
const provider = new JsonRpcProvider("https://www.armchain.org/devnet");
```

### Step 4: Key Generation

```typescript
// Before (ECDSA)
const wallet = Wallet.createRandom();  // 32-byte private key

// After (ML-DSA44)
const wallet = Wallet.createRandom();  // 2,560-byte private key
// Same API, larger keys internally
```

### Step 5: No Other Changes

Contract interactions, event listeners, and transaction building work identically to standard ethers.js.

## Performance Notes

| Operation              | Time     |
| ---------------------- | -------- |
| Key Generation         | \~2.0 ms |
| Signature Creation     | \~3.5 ms |
| Signature Verification | \~5.0 ms |
| HD Child Derivation    | \~4.1 ms |
| Address Computation    | \~0.3 ms |

These are approximately 4x slower than ECDSA but negligible for typical dApp usage.

## Further Reading

* [PQC Transaction Types](/pqc/transaction-types.md) for the detailed Type 3 format
* [ML-DSA44 Deep Dive](/pqc/mldsa44.md) for the cryptographic details
* [Smart Contracts](/developers/overview.md) for writing contracts on Armchain


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.armchain.org/developers/overview-1.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
