npm package: @solforge/qr-tx-decoder
Description: Decode QR payloads back into Solana transactions for wallets
Author: nitishxyz
Latest version: 0.0.1

# @solforge/qr-tx-decoder

Decode QR payloads back into Solana transactions for wallets to sign.

Part of the [Solana QR Transaction Standard](https://github.com/nitishxyz/solforge-qr-sdk) - an open standard for transferring Solana transactions between dApps and wallets without extensions or WalletConnect.

## Installation

```bash
bun add @solforge/qr-tx-decoder
```

## Quick Start

```typescript
import { decodeTransaction } from '@solforge/qr-tx-decoder';

// QR frames scanned from camera (can be in any order)
const frames = [
  'frame-1-data-from-qr-scan',
  'frame-2-data-from-qr-scan',
  // ... more frames if transaction was split
];

try {
  const result = await decodeTransaction(frames);

  // Verify transaction details before signing
  console.log('Network:', result.payload.network);
  console.log('Origin:', result.payload.meta.origin);
  console.log('Description:', result.payload.meta.description);
  console.log('Required signers:', result.payload.meta.required_signers);
  console.log('Expires at:', new Date(result.payload.meta.expires_at * 1000));

  // The decoded Solana transaction ready for signing
  const transaction = result.transaction;

  // Sign with your wallet
  const signature = await wallet.signTransaction(transaction);

  // Return signature to dApp
  const returnUrl = result.payload.sig_return.url.replace(':id', result.payload.session);
  await fetch(returnUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ signature: signature.toString() })
  });

} catch (error) {
  console.error('Failed to decode transaction:', error);
}
```

## API Reference

### `decodeTransaction(frames, options?)`

Decodes QR frame data back into a Solana transaction.

**Parameters:**
- `frames`: `string[]` - Array of QR frame data (order doesn't matter)
- `options?`: `DecodeOptions` - Optional configuration

**Returns:** `Promise<DecodeResult>`

### `DecodeOptions`

```typescript
interface DecodeOptions {
  validateExpiration?: boolean;  // Check if transaction expired (default: true)
  validateChecksum?: boolean;    // Verify payload checksum (default: true)
  requiredSigner?: string;       // Verify this pubkey is in required_signers
}
```

### `DecodeResult`

```typescript
interface DecodeResult {
  transaction: Transaction | VersionedTransaction;  // Decoded Solana transaction
  payload: TransactionPayload;                      // Original payload metadata
  isExpired: boolean;                              // Whether transaction has expired
}
```

## Features

- **Frame Reassembly**: Handles animated QR sequences in any order
- **Automatic Decompression**: Detects and decompresses gzipped payloads
- **Validation**: Built-in checksum and expiration validation
- **Type Safety**: Full TypeScript support with proper transaction types
- **Error Recovery**: Graceful handling of missing or corrupted frames

## Validation

The decoder performs several security validations:

1. **Checksum Verification**: Ensures payload integrity
2. **Expiration Check**: Validates transaction hasn't expired
3. **Required Signers**: Optionally verifies wallet can sign
4. **Frame Completeness**: Ensures all frames are present
5. **Format Validation**: Validates payload structure

## Error Handling

```typescript
try {
  const result = await decodeTransaction(frames);
} catch (error) {
  switch (error.code) {
    case 'MISSING_FRAMES':
      // Not all frames have been scanned yet
      console.log(`Missing frames: ${error.missingFrames.join(', ')}`);
      break;

    case 'CHECKSUM_MISMATCH':
      // Payload corruption detected
      console.error('Transaction data corrupted');
      break;

    case 'TRANSACTION_EXPIRED':
      // Transaction past expiration time
      console.error('Transaction expired');
      break;

    case 'INVALID_SIGNER':
      // Wallet cannot sign this transaction
      console.error('Wallet not authorized to sign');
      break;

    case 'DECOMPRESSION_FAILED':
      // Failed to decompress payload
      console.error('Failed to decompress transaction data');
      break;

    default:
      console.error('Unknown decode error:', error);
  }
}
```

## Frame Collection

For animated QR codes, collect frames until you have all pieces:

```typescript
import { getFrameInfo, decodeTransaction } from '@solforge/qr-tx-decoder';

const collectedFrames = new Set<string>();

// When scanning each QR frame
function onQRScanned(frameData: string) {
  try {
    const frameInfo = getFrameInfo(frameData);
    collectedFrames.add(frameData);

    console.log(`Collected ${collectedFrames.size}/${frameInfo.totalFrames} frames`);

    if (collectedFrames.size === frameInfo.totalFrames) {
      // All frames collected, decode transaction
      decodeTransaction(Array.from(collectedFrames))
        .then(result => {
          // Handle decoded transaction
        });
    }
  } catch (error) {
    console.error('Invalid QR frame:', error);
  }
}
```

## Security Best Practices

1. **Always Validate**: Don't skip checksum or expiration validation
2. **Verify Origin**: Check `payload.meta.origin` matches expected dApp
3. **Review Details**: Show transaction details to user before signing
4. **Secure Transport**: Only return signatures over HTTPS
5. **Rate Limiting**: Implement limits on signature return endpoints

## Transaction Types

The decoder handles both transaction formats:

```typescript
// Legacy Transaction
if (result.transaction instanceof Transaction) {
  const signature = await wallet.signTransaction(result.transaction);
}

// Versioned Transaction
if (result.transaction instanceof VersionedTransaction) {
  const signature = await wallet.signTransaction(result.transaction);
}
```

## Related Packages

- [@solforge/qr-tx-encoder](https://www.npmjs.com/package/@solforge/qr-tx-encoder) - Encode transactions for QR display

## License

MIT

## Links

- [GitHub Repository](https://github.com/nitishxyz/solforge-qr-sdk)
- [Full Documentation](https://github.com/nitishxyz/solforge-qr-sdk#readme)
- [Report Issues](https://github.com/nitishxyz/solforge-qr-sdk/issues)