Skip to main content
Some points programs expire or get deprecated after a certain date. The adapter framework supports marking points as deprecated with specific timestamps, allowing the frontend to display appropriate messaging to users.

What Are Deprecated Points?

Deprecated points are rewards from programs that have:
  • Expired: The points program has ended
  • Concluded: Points are no longer being accumulated
  • Migrated: The program has moved to a new system
  • Snapshot Taken: Final snapshot has been taken and accumulation has stopped
When you mark points as deprecated, the frontend can:
  • Display a deprecation notice to users
  • Show when the program ended
  • Indicate that points are no longer accumulating
  • Still display historical point balances

Basic Implementation

Add a deprecated function to your adapter export that returns labels and their expiration timestamps:
export default {
  fetch: async (address: string) => { /* ... */ },
  data: (data) => { /* ... */ },
  total: (data) => { /* ... */ },
  deprecated: () => ({
    Minerals: 1736467200, // Jan 10th 2025, 00:00 UTC
  }),
  supportedAddressTypes: ["evm"],
} as AdapterExport;

UNIX Timestamp Format

Deprecation timestamps use UNIX time format - the number of seconds since January 1, 1970, 00:00:00 UTC.

Converting Dates to UNIX Timestamps

// Get current timestamp
const now = Math.floor(Date.now() / 1000);

// Convert specific date to timestamp
const date = new Date('2025-01-10T00:00:00Z');
const timestamp = Math.floor(date.getTime() / 1000);
// Result: 1736467200
Use seconds, not milliseconds. JavaScript’s Date.now() returns milliseconds, so divide by 1000.

Complete Example: Dolomite Adapter

Here’s the complete Dolomite adapter showing how deprecated points work with custom terminology:
adapters/dolomite.ts
import type { AdapterExport } from "../utils/adapter.ts";
import { checksumAddress } from "viem";
import { maybeWrapCORSProxy } from "../utils/cors.ts";

const AIRDROP_URL = await maybeWrapCORSProxy(
  "https://api.dolomite.io/airdrop/regular/{address}"
);

export default {
  fetch: async (address: string) => {
    address = checksumAddress(address as `0x${string}`);

    const milestones = await (
      await fetch(AIRDROP_URL.replace("{address}", address), {
        headers: {
          "User-Agent": "Checkpoint API (https://checkpoint.exchange)",
        },
      })
    ).json();

    return milestones;
  },
  data: ({
    airdrop,
  }: {
    airdrop?: { amount: string; level_snapshot: number | null };
  }) => {
    return {
      Minerals: {
        "Airdrop Amount": airdrop ? parseFloat(airdrop.amount) ?? 0 : 0,
        "Level Snapshot": airdrop?.level_snapshot ?? 0,
      },
    };
  },
  total: ({ airdrop }: { airdrop?: { amount: string } }) => ({
    Minerals: airdrop ? parseFloat(airdrop.amount) ?? 0 : 0,
  }),
  claimable: ({ airdrop }: { airdrop?: unknown }) => Boolean(airdrop),
  deprecated: () => ({
    Minerals: 1736467200, // Jan 10th 2025, 00:00 UTC
  }),
  supportedAddressTypes: ["evm"],
} as AdapterExport;
According to Dolomite’s documentation, Minerals expired on January 10th, 2025. The adapter marks this with the timestamp 1736467200.

Label Matching Requirements

The labels in your deprecated function must match the labels used in your adapter:

For Custom Terminology

If you use custom terminology, the deprecated labels must match your data/total labels:
data: (data) => ({
  Minerals: {
    "Airdrop Amount": data.amount,
  },
})

total: (data) => ({
  Minerals: data.amount,
})

deprecated: () => ({
  Minerals: 1736467200,  // ✅ Matches "Minerals" from data/total
})
Invalid Example:
data: (data) => ({
  Minerals: {
    "Airdrop Amount": data.amount,
  },
})

total: (data) => ({
  Minerals: data.amount,
})

deprecated: () => ({
  Points: 1736467200,  // ❌ Label doesn't match!
})

For Default Points Terminology

If you use the default “Points” terminology (no custom labels), use the label "Points":
data: (data) => ({
  "Total Points": data.total,
  "Bonus Points": data.bonus,
})

total: (data) => data.total

deprecated: () => ({
  Points: 1736467200,  // Use "Points" for default terminology
})
When your adapter doesn’t use custom terminology (returns plain objects), use the label "Points" in the deprecated function.

Multiple Deprecated Programs

If your protocol has multiple points programs with different expiration dates:
deprecated: () => ({
  "Season 1": 1704067200,  // Jan 1st 2024
  "Season 2": 1720051200,  // Jul 4th 2024
  "Beta Points": 1730851200,  // Nov 5th 2024
})
Each label must match a label from your data export.

Test Output

When you run the test script on an adapter with deprecated points, you’ll see:
deno run -A test.ts adapters/dolomite.ts 0x3c2573b002cf51e64ab6d051814648eb3a305363

Deprecated Points Table

Deprecated Points:
┌───────────┬──────────────────────────────────┐
│           │                                  │
├───────────┼──────────────────────────────────┤
│ Minerals  │ Fri, 10 Jan 2025 00:00:00 GMT    │
└───────────┴──────────────────────────────────┘
The timestamp is automatically converted to a human-readable UTC date string.

Validation

The test script validates your deprecated points:

Label Validation

Checks that deprecated labels match your data export:
Invalid deprecated keys found: OldPoints
Deprecated keys must match exported data keys or use the default key `Points`.

Timestamp Validation

Verifies timestamps are valid and in the past:
Invalid deprecated dates found for keys: Minerals. 
Dates must be valid UNIX timestamps in the past.
Valid timestamps must:
  1. Be positive numbers
  2. Be in seconds (not milliseconds)
  3. Represent dates in the past
Timestamps in the future will fail validation. Deprecated points must have already expired.

Common Timestamp Examples

deprecated: () => ({
  "Q1 Points": 1711929600,  // Mar 31, 2024 00:00:00 UTC
})
deprecated: () => ({
  "Q2 Points": 1719705600,  // Jun 30, 2024 00:00:00 UTC
})
deprecated: () => ({
  "Q3 Points": 1727654400,  // Sep 30, 2024 00:00:00 UTC
})
deprecated: () => ({
  "Q4 Points": 1735603200,  // Dec 31, 2024 00:00:00 UTC
})
deprecated: () => ({
  Minerals: 1736467200,  // Jan 10, 2025 00:00:00 UTC
})

Dynamic Deprecation

You can also make deprecation dynamic based on API data:
export default {
  fetch: async (address: string) => {
    const data = await fetchFromAPI(address);
    return data;
  },
  data: (data) => ({
    "Season Points": data.points,
    "Season Status": data.status,
  }),
  total: (data) => data.points,
  deprecated: (data) => {
    // Only mark as deprecated if API indicates season ended
    if (data.status === "ended" && data.endTimestamp) {
      return {
        Points: data.endTimestamp,
      };
    }
    return {};  // Not deprecated yet
  },
  supportedAddressTypes: ["evm"],
} as AdapterExport;
Returning an empty object {} from the deprecated function means nothing is deprecated.

How It Appears on the Frontend

When points are marked as deprecated:
  1. Deprecation Badge: A “Deprecated” or “Ended” badge appears on the protocol card
  2. Expiration Date: The expiration date is displayed prominently
  3. Historical Data: Points balances are still shown but marked as final/historical
  4. Warning Message: Users see a message indicating the program has ended

Complete Type Definition

type DeprecatedLabels = { 
  [label: string]: number  // UNIX timestamp in seconds
};

type AdapterExport = {
  fetch: (address: string) => Promise<any>;
  data: (data: any) => DetailedData | LabelledDetailedData;
  total: (data: any) => number | LabelledPoints;
  claimable?: (data: any) => boolean;
  rank?: (data: any) => number;
  deprecated?: (data: any) => DeprecatedLabels;  // Optional
  supportedAddressTypes: AddressType[];
};

Best Practices

  1. Document the Source: Include a comment with the official announcement or documentation
  2. Use UTC Midnight: For clarity, use 00:00:00 UTC for the deprecation time
  3. Match Labels Exactly: Ensure deprecated labels match your data export labels exactly (case-sensitive)
  4. Validate Timestamps: Use the test script to verify your timestamps are valid
  5. Keep Historical Data: Even when deprecated, continue returning point balances for historical reference

Troubleshooting

Error: Invalid deprecated keys foundSolution: Make sure your deprecated labels match the labels from your data function:
// If data uses "Minerals"
data: () => ({ Minerals: { ... } })

// Then deprecated must use "Minerals"
deprecated: () => ({ Minerals: 1736467200 })
Error: Invalid deprecated dates foundSolution: Verify your timestamp is:
  • In seconds (not milliseconds)
  • A positive number
  • A date in the past
// Wrong - milliseconds
deprecated: () => ({ Points: 1736467200000 })

// Correct - seconds
deprecated: () => ({ Points: 1736467200 })
Error: Timestamp must be in the pastSolution: Deprecated points must have already expired. Use a timestamp before the current date:
// Check if date is in the past
const timestamp = 1736467200;
console.log(new Date(timestamp * 1000) < new Date());  // Should be true

Next Steps

Custom Terminology

Learn how to use custom terms with deprecated points

Testing Your Adapter

Validate your deprecated points implementation

Build docs developers (and LLMs) love