@longdotxyz/shared

v0.0.137

Published

Shared types and utilities for Long.xyz API

Downloads

1,975

Readme

@longdotxyz/shared

Shared TypeScript library for Long.xyz API containing GraphQL types, REST API contracts, and utilities.

Installation

npm install @longdotxyz/shared
# or
pnpm add @longdotxyz/shared

Features

  • GraphQL Types & SDK: Auto-generated types and SDK client from GraphQL schema
  • REST API Contracts: Type-safe API contracts built with ts-rest
  • Type Utilities: Common types for blockchain addresses, pool keys, and more
  • Utilities: Helper functions for native token handling

GraphQL Types and SDK

The library includes auto-generated GraphQL types and a ready-to-use SDK client.

Basic Setup

import { GraphQLClient } from "graphql-request";

import { getSdk } from "@longdotxyz/shared";

// Initialize GraphQL client
const client = new GraphQLClient("https://graphql.long.xyz");

// Create SDK instance
const sdk = getSdk(client);

Example: Fetch Auction by Address

import { GetAuctionByAddressQuery, getSdk } from "@longdotxyz/shared";

// Query an auction
const { auction_pool } = await sdk.GetAuctionByAddress({
    address: "0x123...",
});

// Type-safe access to auction data
if (auction_pool) {
    console.log(auction_pool.auction_pool_address);
    console.log(auction_pool.asset_address);
    console.log(auction_pool.numeraire_address);
}

Available GraphQL Types

import type { Asset, Asset_Bool_Exp, Asset_Order_By, AuctionPool, GraduationPool } from "@longdotxyz/shared";

// Use types for type-safe queries
const assetFilter: Asset_Bool_Exp = {
    chain_id: { _eq: 1 },
    asset_address: { _ilike: "0x%" },
};

REST API Client (ts-rest)

The library provides type-safe REST API contracts using ts-rest.

Initialize API Client

import { initClient } from "@ts-rest/core";

import { rootContract } from "@longdotxyz/shared";

// Create typed API client
const apiClient = initClient(rootContract, {
    baseUrl: "https://api.long.xyz/v1",
    baseHeaders: {
        "Content-Type": "application/json",
    },
});

Auction Endpoints

// Get dynamic auction details
const auctionResponse = await apiClient.auctions.getDynamicAuction({
    params: {
        address: "0x123...",
    },
});

if (auctionResponse.status === 200) {
    const { auction_pool_address, auction_base_token_symbol } = auctionResponse.body.result;
    console.log(`Pool: ${auction_pool_address}, Symbol: ${auction_base_token_symbol}`);
}

// Create dynamic auction
const createResponse = await apiClient.auctions.createDynamicAuction({
    body: {
        chain_id: 8453, // Base
        template_id: "template_123",
        metadata: {
            token_name: "My Token",
            token_symbol: "MTK",
            token_uri: "ipfs://...",
            migration_duration: 86400,
            migration_beneficiaries: [{ address: "0xabc...", amount: 10000 }],
            user_address: "0xdef...",
        },
    },
});

if (createResponse.status === 200) {
    const { governance_factory, pool_initializer, liquidity_migrator } = createResponse.body.result;
    console.log("Auction created with factories:", { governance_factory, pool_initializer });
}

Quote Endpoints (Uniswap V3/V4)

// V4 Exact Input Quote
const v4InputQuote = await apiClient.quotes.v4ExactInputSingle({
    body: {
        chain_id: 8453,
        pool_key: {
            currency0: "0x0000000000000000000000000000000000000000", // ETH
            currency1: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC
            fee: 500,
            tick_spacing: 10,
            hooks: "0x0000000000000000000000000000000000000000",
        },
        zero_for_one: true,
        exact_amount: "1000000000000000000", // 1 ETH
        hook_data: "0x", // Optional hook data
    },
});

if (v4InputQuote.status === 200) {
    console.log(`Output amount: ${v4InputQuote.body.result.amount_out}`);
    console.log(`Gas estimate: ${v4InputQuote.body.result.gas_estimate}`);
}

// V4 Exact Output Quote
const v4OutputQuote = await apiClient.quotes.v4ExactOutputSingle({
    body: {
        chain_id: 8453,
        pool_key: {
            currency0: "0x0000000000000000000000000000000000000000", // ETH
            currency1: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC
            fee: 500,
            tick_spacing: 10,
            hooks: "0x0000000000000000000000000000000000000000",
        },
        zero_for_one: true,
        exact_amount: "1000000000", // 1000 USDC output
        hook_data: "0x", // Optional hook data
    },
});

if (v4OutputQuote.status === 200) {
    console.log(`Input required: ${v4OutputQuote.body.result.amount_in}`);
    console.log(`Gas estimate: ${v4OutputQuote.body.result.gas_estimate}`);
}

// V3 Exact Input Quote
const v3InputQuote = await apiClient.quotes.v3ExactInputSingle({
    body: {
        chain_id: 1,
        token_in: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
        token_out: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
        amount_in: "1000000000000000000", // 1 WETH
        fee: 500, // 0.05%
        sqrt_price_limit_x96: "0", // Optional price limit
    },
});

if (v3InputQuote.status === 200) {
    console.log(`Output amount: ${v3InputQuote.body.result.amount_out}`);
    console.log(`Price after: ${v3InputQuote.body.result.sqrt_price_x96_after}`);
    console.log(`Ticks crossed: ${v3InputQuote.body.result.initialized_ticks_crossed}`);
    console.log(`Gas estimate: ${v3InputQuote.body.result.gas_estimate}`);
}

// V3 Exact Output Quote
const v3OutputQuote = await apiClient.quotes.v3ExactOutputSingle({
    body: {
        chain_id: 1,
        token_in: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
        token_out: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
        amount_out: "1000000000", // 1000 USDC
        fee: 500, // 0.05%
    },
});

if (v3OutputQuote.status === 200) {
    console.log(`Input required: ${v3OutputQuote.body.result.amount_in}`);
    console.log(`Price after: ${v3OutputQuote.body.result.sqrt_price_x96_after}`);
    console.log(`Ticks crossed: ${v3OutputQuote.body.result.initialized_ticks_crossed}`);
    console.log(`Gas estimate: ${v3OutputQuote.body.result.gas_estimate}`);
}

Community Endpoints

// Fetch all communities
const communities = await apiClient.communities.fetchCommunities();

if (communities.status === 200) {
    communities.body.result.forEach((community) => {
        console.log(`${community.label}: ${community.description}`);
        console.log(`Funding: ${community.funding_amount}`);
    });
}

// Get specific community
const community = await apiClient.communities.getCommunity({
    params: { id: 1 },
});

IPFS Endpoints

// Upload an image to IPFS
const formData = new FormData();
formData.append("image", imageFile); // imageFile is a File object

const imageUpload = await apiClient.ipfs.uploadImage({
    body: formData,
});

if (imageUpload.status === 200) {
    const imageHash = imageUpload.body.result;
    console.log(`Image IPFS hash: ${imageHash}`);
}

// Upload metadata to IPFS
const metadataUpload = await apiClient.ipfs.uploadMetadata({
    body: {
        name: "My Token",
        description: "Token description",
        image_hash: imageHash, // From previous upload
        social_links: [
            { label: "Twitter", url: "https://twitter.com/mytoken" },
            { label: "Discord", url: "https://discord.gg/mytoken" },
        ],
        vesting_recipients: [
            { address: "0xabc...", amount: 5000 },
            { address: "0xdef...", amount: 5000 },
        ],
        fee_receiver: "0x123...",
    },
});

if (metadataUpload.status === 200) {
    const metadataHash = metadataUpload.body.result;
    console.log(`Metadata IPFS hash: ${metadataHash}`);
}

Pathfinding Endpoints

Get Swap Paths

import { apiClient } from "@longdotxyz/shared";

// Basic usage (Codex only)
const paths = await apiClient.pathfinding.fetchTokenPaths({
    params: { tokenInAddress: "0xTokenAddress" },
});

// With Kyber fallback (when amount provided)
const pathsWithFallback = await apiClient.pathfinding.fetchTokenPaths({
    params: { tokenInAddress: "0xTokenAddress" },
    query: {
        amount: "1000000000000000000", // 1 token in wei
        tokenOut: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", // Optional: USDC
    },
});

if (pathsWithFallback.status === 200) {
    const { paths, paths_count } = pathsWithFallback.body;

    paths.forEach((path) => {
        if (path.source === "kyber") {
            // Kyber route includes executable calldata
            console.log("Router:", path.router_address);
            console.log("Calldata:", path.encoded_calldata);
            console.log("Expected output:", path.amount_out);
        } else {
            // Codex route includes liquidity metrics
            console.log("Liquidity:", path.total_liquidity_usd);
            console.log("Volume:", path.total_volume_usd);
        }
    });
}

Query Parameters:

  • amount (optional): Swap amount in wei. When provided, enables Kyber fallback if Codex returns no paths.
  • tokenOut (optional): Target token address. If omitted, queries all exit tokens (WETH, USDC, ETH on Base).

Response Fields:

  • source: Either "codex" or "kyber" - indicates which service provided the route
  • encoded_calldata (Kyber only): Ready-to-execute swap calldata
  • router_address (Kyber only): Kyber router contract address
  • amount_in (Kyber only): Input amount in wei
  • amount_out (Kyber only): Expected output amount in wei
  • gas_estimate (Kyber only): Estimated gas for the swap

Type Utilities

Pool Key Type (Uniswap V4)

import { PoolKey } from "@longdotxyz/shared";

const poolKey: PoolKey = {
    currency0: "0x0000000000000000000000000000000000000000",
    currency1: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    fee: 500,
    tick_spacing: 10,
    hooks: "0x0000000000000000000000000000000000000000",
};

Hex Address Validation

import { z } from "zod";

import { hex } from "@longdotxyz/shared";

// Validate and normalize hex addresses
const addressSchema = z.string().pipe(hex);
const validAddress = addressSchema.parse("0xabc..."); // Returns lowercase hex

BigInt Coercion

import { coerceBigInt } from "@longdotxyz/shared";

const amount = coerceBigInt.parse("1000000000000000000"); // Returns bigint
const amount2 = coerceBigInt.parse(1000n); // Also accepts bigint

Native Token Utilities

import { isNativeToken, isNativeTokenAddress } from "@longdotxyz/shared";

// Check if address is native token (ETH)
isNativeTokenAddress("0x0000000000000000000000000000000000000000"); // true
isNativeTokenAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"); // true

// Check token object
isNativeToken({
    address: "0x0000000000000000000000000000000000000000",
    symbol: "ETH",
}); // true

Development

Building the Library

# Generate GraphQL types
pnpm codegen

# Build TypeScript
pnpm build

# Run tests
pnpm test

# Format and lint
pnpm format
pnpm lint

GraphQL Code Generation

The GraphQL types are generated from a schema using @graphql-codegen. Configuration is in codegen.ts.

pnpm codegen

API Contract Structure

All API contracts are defined using ts-rest and exported from @longdotxyz/shared/contracts:

  • Auctions: /auctions/* - Dynamic auction creation and management
  • Quotes: /quotes/* - Uniswap V3/V4 swap quotes
  • Communities: /communities/* - Community data management
  • IPFS: /ipfs/* - IPFS content creation

License

UNLICENSED