Skip to main content

Contact Management

This guide covers managing contacts (saved privacy addresses) in the Privacy Boost SDK.

Overview

Contacts allow you to save and organize privacy addresses for easy access when sending transfers.

Contact Type

interface Contact {
  id: string;                    // Unique identifier
  name: string;                  // Display name
  privacyAddress: PrivacyAddress; // Privacy address
  note?: string;                 // Optional note
  createdAt: number;             // Creation timestamp
  updatedAt: number;             // Last update timestamp
}

Adding Contacts

const contact = await sdk.contacts.addContact({
  name: 'Alice',
  privacyAddress: '0x04...alice-privacy-address',
  note: 'Friend from work',
});

console.log('Created contact:', contact.id);

Add Contact Parameters

interface CreateContactParams {
  name: string;                   // Required: display name
  privacyAddress: PrivacyAddress; // Required: privacy address
  note?: string;                  // Optional: note
}

Getting Contacts

Get All Contacts

const contacts = sdk.contacts.getContacts();

for (const contact of contacts) {
  console.log(`${contact.name}: ${contact.privacyAddress}`);
}

Find by Privacy Address

const contact = sdk.contacts.findByAddress('0x04...privacy-address');

if (contact) {
  console.log('Found:', contact.name);
} else {
  console.log('Contact not found');
}

Search by Name

const results = sdk.contacts.search('alice');

for (const contact of results) {
  console.log(`${contact.name}: ${contact.privacyAddress}`);
}

Updating Contacts

const updated = await sdk.contacts.updateContact(
  '0x04...privacy-address',
  {
    name: 'Alice Smith',
    note: 'Updated note',
  }
);

console.log('Updated:', updated.name);

Update Parameters

interface UpdateContactParams {
  name?: string;                   // New name
  privacyAddress?: PrivacyAddress; // New privacy address
  note?: string;                   // New note
}

Removing Contacts

await sdk.contacts.removeContact('0x04...privacy-address');

Validation

Always validate privacy addresses before adding contacts:
import { isValidPrivacyAddress } from '@testinprod-io/privacy-boost';

async function addContactSafe(params: CreateContactParams) {
  if (!isValidPrivacyAddress(params.privacyAddress)) {
    throw new Error('Invalid privacy address');
  }

  if (!params.name.trim()) {
    throw new Error('Name is required');
  }

  return sdk.contacts.addContact(params);
}

UI Example: Contact List

import { useState, useEffect } from 'react';

function ContactList() {
  const [contacts, setContacts] = useState<Contact[]>([]);
  const [search, setSearch] = useState('');

  useEffect(() => {
    setContacts(sdk.contacts.getContacts());
  }, []);

  const filteredContacts = search
    ? sdk.contacts.search(search)
    : contacts;

  const handleDelete = async (privacyAddress: string) => {
    if (confirm('Delete this contact?')) {
      await sdk.contacts.removeContact(privacyAddress);
      setContacts(sdk.contacts.getContacts());
    }
  };

  return (
    <div>
      <input
        type="text"
        value={search}
        onChange={(e) => setSearch(e.target.value)}
        placeholder="Search contacts..."
      />

      <ul>
        {filteredContacts.map((contact) => (
          <li key={contact.id}>
            <strong>{contact.name}</strong>
            <span>{contact.privacyAddress.slice(0, 20)}...</span>
            {contact.note && <small>{contact.note}</small>}
            <button onClick={() => handleDelete(contact.privacyAddress)}>
              Delete
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

UI Example: Add Contact Form

function AddContactForm({ onAdd }: { onAdd: () => void }) {
  const [name, setName] = useState('');
  const [privacyAddress, setPrivacyAddress] = useState('');
  const [note, setNote] = useState('');
  const [error, setError] = useState('');

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');

    if (!isValidPrivacyAddress(privacyAddress)) {
      setError('Invalid privacy address');
      return;
    }

    try {
      await sdk.contacts.addContact({
        name: name.trim(),
        privacyAddress,
        note: note.trim() || undefined,
      });
      setName('');
      setPrivacyAddress('');
      setNote('');
      onAdd();
    } catch (err) {
      setError(err.message);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
        placeholder="Name"
        required
      />
      <input
        type="text"
        value={privacyAddress}
        onChange={(e) => setPrivacyAddress(e.target.value)}
        placeholder="Privacy address"
        required
      />
      <textarea
        value={note}
        onChange={(e) => setNote(e.target.value)}
        placeholder="Note (optional)"
      />
      {error && <p style={{ color: 'red' }}>{error}</p>}
      <button type="submit">Add Contact</button>
    </form>
  );
}

Contact Picker for Transfers

function ContactPicker({ onSelect }: { onSelect: (address: string) => void }) {
  const contacts = sdk.contacts.getContacts();

  return (
    <select onChange={(e) => onSelect(e.target.value)}>
      <option value="">Select a contact...</option>
      {contacts.map((contact) => (
        <option key={contact.id} value={contact.privacyAddress}>
          {contact.name}
        </option>
      ))}
    </select>
  );
}

// Usage in transfer form
function TransferWithContacts() {
  const [recipient, setRecipient] = useState('');

  return (
    <div>
      <ContactPicker onSelect={setRecipient} />
      <p>or enter manually:</p>
      <input
        type="text"
        value={recipient}
        onChange={(e) => setRecipient(e.target.value)}
        placeholder="Privacy address"
      />
      <button onClick={() => transfer(recipient)}>
        Send
      </button>
    </div>
  );
}

Import/Export Contacts

Export

function exportContacts(): string {
  const contacts = sdk.contacts.getContacts();
  return JSON.stringify(contacts, null, 2);
}

Import

async function importContacts(json: string) {
  const contacts = JSON.parse(json) as Contact[];

  for (const contact of contacts) {
    // Check if already exists
    const existing = sdk.contacts.findByAddress(contact.privacyAddress);
    if (!existing) {
      await sdk.contacts.addContact({
        name: contact.name,
        privacyAddress: contact.privacyAddress,
        note: contact.note,
      });
    }
  }
}

Best Practices

1. Prevent Duplicates

async function addUniqueContact(params: CreateContactParams) {
  const existing = sdk.contacts.findByAddress(params.privacyAddress);
  if (existing) {
    throw new Error(`Contact already exists: ${existing.name}`);
  }
  return sdk.contacts.addContact(params);
}

2. Validate Before Transfer

function getRecipientName(privacyAddress: string): string | null {
  const contact = sdk.contacts.findByAddress(privacyAddress);
  return contact?.name || null;
}

// Show in UI
const recipientName = getRecipientName(recipient);
if (recipientName) {
  console.log(`Sending to ${recipientName}`);
} else {
  console.log('Sending to unknown address');
}

3. Recent Contacts

function getRecentContacts(limit = 5): Contact[] {
  const contacts = sdk.contacts.getContacts();
  return contacts
    .sort((a, b) => b.updatedAt - a.updatedAt)
    .slice(0, limit);
}

Next Steps