# Becoming an Issuer

## Issuer Setup

An issuer needs:

1. A funded wallet account
2. ODIS quota for identifier obfuscation
3. Verification infrastructure
4. Optional: Data Encryption Key (DEK) for enhanced authentication

## Step 1: Set Up Issuer Account

```typescript
import { createWalletClient, http, parseEther } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { celoAlfajores } from "viem/chains";

// Issuer private key - KEEP SECURE
const ISSUER_PRIVATE_KEY = process.env.ISSUER_PRIVATE_KEY;
const account = privateKeyToAccount(ISSUER_PRIVATE_KEY);

// Create Viem client
const walletClient = createWalletClient({
  account,
  transport: http(),
  chain: celoAlfajores
});

const issuerAddress = account.address;
console.log("Issuer Address:", issuerAddress);
```

## Step 2: Authentication Methods

Self Connect supports multiple authentication methods for ODIS:

**Wallet Key Authentication**

```typescript
import { OdisUtils } from "@celo/identity";
import { AuthSigner } from "@celo/identity/lib/odis/query";

const authSigner: AuthSigner = {
  authenticationMethod: OdisUtils.Query.AuthenticationMethod.WALLET_KEY,
  sign191: ({ message, account }) => walletClient.signMessage({
    message,
    account
  })
};
```

**Encryption Key (DEK) Authentication**

```typescript
const authSigner: AuthSigner = {
  authenticationMethod: OdisUtils.Query.AuthenticationMethod.ENCRYPTION_KEY,
  rawKey: process.env.DEK_PRIVATE_KEY
};
```

## Step 3: Configure ODIS Service Context

```typescript
import { OdisContextName } from "@celo/identity/lib/odis/query";

const serviceContext = OdisUtils.Query.getServiceContext(
  OdisContextName.ALFAJORES // or OdisContextName.MAINNET
);

console.log("ODIS Endpoint:", serviceContext.odisUrl);
console.log("ODIS Public Key:", serviceContext.odisPubKey);
```

## ODIS Quota Management

**Check Current Quota**

```typescript
const { remainingQuota } = await OdisUtils.Quota.getPnpQuotaStatus(
  issuerAddress,
  authSigner,
  serviceContext
);

console.log("Remaining ODIS Quota:", remainingQuota);
```

**Purchase Quota**

```typescript
import { getContract } from "viem";
import { stableTokenABI, odisPaymentsABI } from "@celo/abis";

// Contract addresses (Alfajores testnet)
const STABLE_TOKEN_ADDRESS = "0x874069Fa1Eb16D44d622F2e0Ca25eeA172369bC1"; // cUSD
const ODIS_PAYMENTS_ADDRESS = "0x645170cdB6B5c1bc80847bb728dBa56C50a20a49";

// Amount to pay (0.01 cUSD = 10 queries)
const ONE_CENT_CUSD = parseEther("0.01");

// Approve ODIS Payments to spend cUSD
const stableToken = getContract({
  address: STABLE_TOKEN_ADDRESS,
  abi: stableTokenABI,
  client: walletClient
});

const approveHash = await stableToken.write.approve([
  ODIS_PAYMENTS_ADDRESS,
  ONE_CENT_CUSD
]);

await walletClient.waitForTransactionReceipt({ hash: approveHash });

// Pay for quota
const odisPayments = getContract({
  address: ODIS_PAYMENTS_ADDRESS,
  abi: odisPaymentsABI,
  client: walletClient
});

const paymentHash = await odisPayments.write.payInCUSD([
  issuerAddress,
  ONE_CENT_CUSD
]);

await walletClient.waitForTransactionReceipt({ hash: paymentHash });

console.log("ODIS quota purchased successfully");
```

## Verification Responsibilities

As an issuer, you must verify user ownership of identifiers. Implementation depends on identifier type:

**Phone Number Verification**

```typescript
// Example using Twilio
import twilio from "twilio";

const client = twilio(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN);

async function verifyPhoneNumber(phoneNumber: string): Promise<boolean> {
  // Send verification code
  await client.verify.v2
    .services(TWILIO_VERIFY_SERVICE_SID)
    .verifications.create({ to: phoneNumber, channel: "sms" });

  // User enters code (from your UI)
  const verificationCode = await getUserInput();

  // Check verification
  const verification = await client.verify.v2
    .services(TWILIO_VERIFY_SERVICE_SID)
    .verificationChecks.create({ to: phoneNumber, code: verificationCode });

  return verification.status === "approved";
}
```

**Twitter Verification**

```typescript
// Example using Twitter OAuth
async function verifyTwitterHandle(handle: string, userAddress: string): Promise<boolean> {
  // Implement OAuth flow
  const oauth = await initiateTwitterOAuth(userAddress);

  // User authenticates with Twitter
  const twitterUser = await completeOAuthFlow(oauth);

  // Verify handle matches
  return twitterUser.username === handle;
}
```

**Email Verification**

```typescript
// Example verification flow
async function verifyEmail(email: string, userAddress: string): Promise<boolean> {
  // Generate verification token
  const token = generateSecureToken();

  // Store token with expiry
  await storeVerificationToken(email, userAddress, token);

  // Send verification email
  await sendEmail(email, {
    subject: "Verify your email",
    body: `Click here to verify: ${BASE_URL}/verify/${token}`
  });

  // User clicks link, returns true if token is valid
  return await checkTokenVerified(token);
}
```
