# Signing requests for wallet mapping API

### Introduction

The Wallet Mapping API allows users to associate blockchain wallet addresses with domain names. This document explains how to properly sign requests for various operations in the API.

### Authentication

All API requests require:

* An API key provided in the header as 'api-key'
* A valid EIP-712 signature for the operation being performed

### API Endpoints

#### 1. Set Wallet Mapping

Associates a blockchain wallet address with a domain for a specific chain/symbol.

```jsx
// Function to set a wallet mapping
async function setWalletMapping(symbol, name) {
  const payload = {
    domain: name,
    symbol,
    address: wallet.address,
    signatureExpiresAt: Date.now() + 5 * 60 * 1000, // 5 minutes
  };
  
  const signature = await wallet.signTypedData(
    SignDomain, 
    SetWeb3RecordTypes, 
    payload
  );
  
  return fetch(`https://api-public.d3.app/v1/domain/${name}/records/web3`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'api-key': API_KEY,
    },
    body: JSON.stringify({
      symbol,
      address: wallet.address,
      signature,
      signatureExpiresAt: payload.signatureExpiresAt,
    }),
  });
}

```

The `SignDomain` and `SetWeb3RecordTypes` constants are defined as:

```jsx
const SignDomain = {
  name: 'D3 API',
  version: '1',
};

const SetWeb3RecordTypes = {
  SetWeb3Record: [
    { name: 'domain', type: 'string' },
    { name: 'symbol', type: 'string' },
    { name: 'address', type: 'string' },
    { name: 'signatureExpiresAt', type: 'uint256' },
  ],
};

```

#### Example

```jsx
// Set "ETH" wallet mapping for domain "example.com"
const response = await setWalletMapping("ETH", "example.d3");
console.log(await response.json());
// Example response: { success: true }

```

#### 2. Delete Wallet Mapping

Removes the association between a wallet address and a domain for a specific chain/symbol.

```jsx
async function deleteWalletMapping(symbol, name) {
  const payload = {
    domain: name,
    symbol,
    signatureExpiresAt: Date.now() + 5 * 60 * 1000, // 5 minutes
  };
  
  const signature = await wallet.signTypedData(
    SignDomain, 
    DeleteWeb3RecordTypes, 
    payload
  );
  
  return fetch(`https://api-public.d3.app/v1/domain/${name}/records/web3`, {
    method: 'DELETE',
    headers: {
      'Content-Type': 'application/json',
      'api-key': API_KEY,
    },
    body: JSON.stringify({
      symbol,
      signature,
      signatureExpiresAt: payload.signatureExpiresAt,
    }),
  });
}

```

The `DeleteWeb3RecordTypes` constant is defined as:

```jsx
const DeleteWeb3RecordTypes = {
  DeleteWeb3Record: [
    { name: 'domain', type: 'string' },
    { name: 'symbol', type: 'string' },
    { name: 'signatureExpiresAt', type: 'uint256' },
  ],
};

```

#### Example

```jsx
// Delete "ETH" wallet mapping for domain "example.com"
const response = await deleteWalletMapping("ETH", "example.com");
console.log(await response.json());
// Example response: { success: true }

```

#### 3. Set Primary Name

Sets a domain as the primary name for a wallet address (reverse resolution).

```jsx
async function setPrimaryName(wallet, name) {
  const payload = {
    name,
    signatureExpiresAt: Date.now() + 5 * 60 * 1000, // 5 minutes
  };
  
  const signature = await wallet.signTypedData(
    SignDomain, 
    SetPrimaryNameTypes, 
    payload
  );
  
  return fetch(`https://api-public.d3.app/v1/reverse-registry/${wallet.address}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'api-key': API_KEY,
    },
    body: JSON.stringify({
      name,
      signature,
      signatureExpiresAt: payload.signatureExpiresAt,
    }),
  });
}

```

The `SetPrimaryNameTypes` constant is defined as:

```jsx
const SetPrimaryNameTypes = {
  SetPrimaryName: [
    { name: 'name', type: 'string' },
    { name: 'signatureExpiresAt', type: 'uint256' },
  ],
};

```

#### Example

```jsx
// Set "example.com" as the primary name for the wallet
const response = await setPrimaryName(wallet, "example.com");
console.log(await response.json());
// Example response: { success: true }

```

#### 4. Unset Primary Name

Removes the primary name association for a wallet address.

```jsx
async function unsetPrimaryName(wallet) {
  const payload = {
    signatureExpiresAt: Date.now() + 5 * 60 * 1000, // 5 minutes
  };
  
  const signature = await wallet.signTypedData(
    SignDomain, 
    UnsetPrimaryNameTypes, 
    payload
  );
  
  return fetch(`https://api-public.d3.app/v1/reverse-registry/${wallet.address}`, {
    method: 'DELETE',
    headers: {
      'Content-Type': 'application/json',
      'api-key': API_KEY,
    },
    body: JSON.stringify({
      signature,
      signatureExpiresAt: payload.signatureExpiresAt,
    }),
  });
}

```

The `UnsetPrimaryNameTypes` constant is defined as:

```jsx
const UnsetPrimaryNameTypes = {
  UnsetPrimaryName: [
    { name: 'signatureExpiresAt', type: 'uint256' }
  ],
};

```

#### Example

```jsx
// Remove the primary name for the wallet
const response = await unsetPrimaryName(wallet);
console.log(await response.json());
// Example response: { success: true }

```

### Complete Working Example

Here's a complete example that demonstrates all operations:

```jsx
const { ethers } = require('ethers');

// Configuration
const API_KEY = 'your-api-key-here';
const PRIVATE_KEY = 'your-private-key'; // Should be stored securely
const wallet = new ethers.Wallet(PRIVATE_KEY);

// EIP-712 domain
const SignDomain = {
  name: 'D3 API',
  version: '1',
};

// Type definitions for signatures
const SetWeb3RecordTypes = {
  SetWeb3Record: [
    { name: 'domain', type: 'string' },
    { name: 'symbol', type: 'string' },
    { name: 'address', type: 'string' },
    { name: 'signatureExpiresAt', type: 'uint256' },
  ],
};

const DeleteWeb3RecordTypes = {
  DeleteWeb3Record: [
    { name: 'domain', type: 'string' },
    { name: 'symbol', type: 'string' },
    { name: 'signatureExpiresAt', type: 'uint256' },
  ],
};

const SetPrimaryNameTypes = {
  SetPrimaryName: [
    { name: 'name', type: 'string' },
    { name: 'signatureExpiresAt', type: 'uint256' },
  ],
};

const UnsetPrimaryNameTypes = {
  UnsetPrimaryName: [
    { name: 'signatureExpiresAt', type: 'uint256' }
  ],
};

// Example usage
async function demonstrateAllOperations() {
  const domain = "example.com";
  const symbol = "ETH";
  
  // 1. Set wallet mapping
  console.log(`Setting ${symbol} wallet mapping for ${domain}...`);
  const setResponse = await setWalletMapping(symbol, domain);
  console.log(await setResponse.json());
  
  // 2. Set primary name
  console.log(`Setting ${domain} as primary name for wallet...`);
  const setPrimaryResponse = await setPrimaryName(wallet, domain);
  console.log(await setPrimaryResponse.json());
  
  // Wait to demonstrate the operations
  await new Promise(resolve => setTimeout(resolve, 2000));
  
  // 3. Delete wallet mapping
  console.log(`Deleting ${symbol} wallet mapping for ${domain}...`);
  const deleteResponse = await deleteWalletMapping(symbol, domain);
  console.log(await deleteResponse.json());
  
  // 4. Unset primary name
  console.log(`Unsetting primary name for wallet...`);
  const unsetResponse = await unsetPrimaryName(wallet);
  console.log(await unsetResponse.json());
}

// Implementation of API functions
// [Include all the function implementations from above]

// Run the demonstration
demonstrateAllOperations().catch(console.error);

```

### Important Notes

* All signatures expire after the time specified in `signatureExpiresAt` (in milliseconds since epoch)
* The wallet address is derived from the signature, ensuring that only the wallet owner can make changes
* Store your API key and private key securely and never expose them in client-side code
* All endpoints will respond with 200 with an empty body in case of success

### Error Handling

The API returns appropriate HTTP status codes and JSON responses for errors:

* 400 - Bad Request: Invalid parameters or signature
* 401 - Unauthorized: Invalid API key
* 403 - Forbidden: Signature expired or incorrect
* 404 - Not Found: Domain or wallet not found
