← back to hangjie2013__tradingcup

Function bodies 94 total

All specs Real LLM only Function bodies
FormControl function · typescript · L107-L123 (17 LOC)
components/ui/form.tsx
function FormControl({ ...props }: React.ComponentProps<typeof Slot.Root>) {
  const { error, formItemId, formDescriptionId, formMessageId } = useFormField()

  return (
    <Slot.Root
      data-slot="form-control"
      id={formItemId}
      aria-describedby={
        !error
          ? `${formDescriptionId}`
          : `${formDescriptionId} ${formMessageId}`
      }
      aria-invalid={!!error}
      {...props}
    />
  )
}
FormDescription function · typescript · L125-L136 (12 LOC)
components/ui/form.tsx
function FormDescription({ className, ...props }: React.ComponentProps<"p">) {
  const { formDescriptionId } = useFormField()

  return (
    <p
      data-slot="form-description"
      id={formDescriptionId}
      className={cn("text-muted-foreground text-sm", className)}
      {...props}
    />
  )
}
FormMessage function · typescript · L138-L156 (19 LOC)
components/ui/form.tsx
function FormMessage({ className, ...props }: React.ComponentProps<"p">) {
  const { error, formMessageId } = useFormField()
  const body = error ? String(error?.message ?? "") : props.children

  if (!body) {
    return null
  }

  return (
    <p
      data-slot="form-message"
      id={formMessageId}
      className={cn("text-destructive text-sm", className)}
      {...props}
    >
      {body}
    </p>
  )
}
Input function · typescript · L5-L19 (15 LOC)
components/ui/input.tsx
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
  return (
    <input
      type={type}
      data-slot="input"
      className={cn(
        "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
        "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
        "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
        className
      )}
      {...props}
    />
  )
}
Label function · typescript · L8-L22 (15 LOC)
components/ui/label.tsx
function Label({
  className,
  ...props
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
  return (
    <LabelPrimitive.Root
      data-slot="label"
      className={cn(
        "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
        className
      )}
      {...props}
    />
  )
}
SelectTrigger function · typescript · L27-L51 (25 LOC)
components/ui/select.tsx
function SelectTrigger({
  className,
  size = "default",
  children,
  ...props
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
  size?: "sm" | "default"
}) {
  return (
    <SelectPrimitive.Trigger
      data-slot="select-trigger"
      data-size={size}
      className={cn(
        "border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:da
SelectContent function · typescript · L53-L88 (36 LOC)
components/ui/select.tsx
function SelectContent({
  className,
  children,
  position = "item-aligned",
  align = "center",
  ...props
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
  return (
    <SelectPrimitive.Portal>
      <SelectPrimitive.Content
        data-slot="select-content"
        className={cn(
          "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
          position === "popper" &&
            "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
SelectLabel function · typescript · L90-L101 (12 LOC)
components/ui/select.tsx
function SelectLabel({
  className,
  ...props
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
  return (
    <SelectPrimitive.Label
      data-slot="select-label"
      className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
      {...props}
    />
  )
}
SelectItem function · typescript · L103-L128 (26 LOC)
components/ui/select.tsx
function SelectItem({
  className,
  children,
  ...props
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
  return (
    <SelectPrimitive.Item
      data-slot="select-item"
      className={cn(
        "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
        className
      )}
      {...props}
    >
      <span
        data-slot="select-item-indicator"
        className="absolute right-2 flex size-3.5 items-center justify-center"
      >
        <SelectPrimitive.ItemIndicator>
          <CheckIcon className="size-4" />
        </SelectPrimitive.ItemIndicator>
      </span>
      <SelectPrimitive.ItemText>
SelectSeparator function · typescript · L130-L141 (12 LOC)
components/ui/select.tsx
function SelectSeparator({
  className,
  ...props
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
  return (
    <SelectPrimitive.Separator
      data-slot="select-separator"
      className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
      {...props}
    />
  )
}
SelectScrollUpButton function · typescript · L143-L159 (17 LOC)
components/ui/select.tsx
function SelectScrollUpButton({
  className,
  ...props
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
  return (
    <SelectPrimitive.ScrollUpButton
      data-slot="select-scroll-up-button"
      className={cn(
        "flex cursor-default items-center justify-center py-1",
        className
      )}
      {...props}
    >
      <ChevronUpIcon className="size-4" />
    </SelectPrimitive.ScrollUpButton>
  )
}
SelectScrollDownButton function · typescript · L161-L177 (17 LOC)
components/ui/select.tsx
function SelectScrollDownButton({
  className,
  ...props
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
  return (
    <SelectPrimitive.ScrollDownButton
      data-slot="select-scroll-down-button"
      className={cn(
        "flex cursor-default items-center justify-center py-1",
        className
      )}
      {...props}
    >
      <ChevronDownIcon className="size-4" />
    </SelectPrimitive.ScrollDownButton>
  )
}
Table function · typescript · L7-L20 (14 LOC)
components/ui/table.tsx
function Table({ className, ...props }: React.ComponentProps<"table">) {
  return (
    <div
      data-slot="table-container"
      className="relative w-full overflow-x-auto"
    >
      <table
        data-slot="table"
        className={cn("w-full caption-bottom text-sm", className)}
        {...props}
      />
    </div>
  )
}
TableHeader function · typescript · L22-L30 (9 LOC)
components/ui/table.tsx
function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
  return (
    <thead
      data-slot="table-header"
      className={cn("[&_tr]:border-b", className)}
      {...props}
    />
  )
}
TableBody function · typescript · L32-L40 (9 LOC)
components/ui/table.tsx
function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
  return (
    <tbody
      data-slot="table-body"
      className={cn("[&_tr:last-child]:border-0", className)}
      {...props}
    />
  )
}
Source: Repobility analyzer · https://repobility.com
TableFooter function · typescript · L42-L53 (12 LOC)
components/ui/table.tsx
function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
  return (
    <tfoot
      data-slot="table-footer"
      className={cn(
        "bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
        className
      )}
      {...props}
    />
  )
}
TableRow function · typescript · L55-L66 (12 LOC)
components/ui/table.tsx
function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
  return (
    <tr
      data-slot="table-row"
      className={cn(
        "hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
        className
      )}
      {...props}
    />
  )
}
TableHead function · typescript · L68-L79 (12 LOC)
components/ui/table.tsx
function TableHead({ className, ...props }: React.ComponentProps<"th">) {
  return (
    <th
      data-slot="table-head"
      className={cn(
        "text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
        className
      )}
      {...props}
    />
  )
}
TableCell function · typescript · L81-L92 (12 LOC)
components/ui/table.tsx
function TableCell({ className, ...props }: React.ComponentProps<"td">) {
  return (
    <td
      data-slot="table-cell"
      className={cn(
        "p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
        className
      )}
      {...props}
    />
  )
}
TableCaption function · typescript · L94-L105 (12 LOC)
components/ui/table.tsx
function TableCaption({
  className,
  ...props
}: React.ComponentProps<"caption">) {
  return (
    <caption
      data-slot="table-caption"
      className={cn("text-muted-foreground mt-4 text-sm", className)}
      {...props}
    />
  )
}
Tabs function · typescript · L9-L26 (18 LOC)
components/ui/tabs.tsx
function Tabs({
  className,
  orientation = "horizontal",
  ...props
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
  return (
    <TabsPrimitive.Root
      data-slot="tabs"
      data-orientation={orientation}
      orientation={orientation}
      className={cn(
        "group/tabs flex gap-2 data-[orientation=horizontal]:flex-col",
        className
      )}
      {...props}
    />
  )
}
TabsList function · typescript · L43-L57 (15 LOC)
components/ui/tabs.tsx
function TabsList({
  className,
  variant = "default",
  ...props
}: React.ComponentProps<typeof TabsPrimitive.List> &
  VariantProps<typeof tabsListVariants>) {
  return (
    <TabsPrimitive.List
      data-slot="tabs-list"
      data-variant={variant}
      className={cn(tabsListVariants({ variant }), className)}
      {...props}
    />
  )
}
TabsTrigger function · typescript · L59-L76 (18 LOC)
components/ui/tabs.tsx
function TabsTrigger({
  className,
  ...props
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
  return (
    <TabsPrimitive.Trigger
      data-slot="tabs-trigger"
      className={cn(
        "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
        "group-data-[
Repobility · MCP-ready · https://repobility.com
TabsContent function · typescript · L78-L89 (12 LOC)
components/ui/tabs.tsx
function TabsContent({
  className,
  ...props
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
  return (
    <TabsPrimitive.Content
      data-slot="tabs-content"
      className={cn("flex-1 outline-none", className)}
      {...props}
    />
  )
}
Textarea function · typescript · L5-L16 (12 LOC)
components/ui/textarea.tsx
function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
  return (
    <textarea
      data-slot="textarea"
      className={cn(
        "border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
        className
      )}
      {...props}
    />
  )
}
ConnectButton function · typescript · L14-L104 (91 LOC)
components/wallet/ConnectButton.tsx
export function ConnectButton({ onAuthenticated }: ConnectButtonProps) {
  const { address, isConnected } = useAccount()
  const { signMessageAsync } = useSignMessage()
  const [isAuthenticating, setIsAuthenticating] = useState(false)
  const [isAuthenticated, setIsAuthenticated] = useState(false)

  useEffect(() => {
    const checkSession = async () => {
      const res = await fetch('/api/auth/wallet/check', { method: 'GET' }).catch(() => null)
      if (res?.ok) {
        const data = await res.json()
        if (data.authenticated) setIsAuthenticated(true)
      }
    }
    if (isConnected) checkSession()
  }, [isConnected])

  const handleSignIn = async () => {
    if (!address) return

    setIsAuthenticating(true)
    try {
      const timestamp = Date.now()
      const message = `Welcome to TradingCup!\n\nPlease sign this message to verify your wallet ownership.\n\nWallet: ${address}\nTimestamp: ${timestamp}`

      const signature = await signMessageAsync({ message })

      
LbankStatusBadge function · typescript · L5-L25 (21 LOC)
components/wallet/LbankStatusBadge.tsx
export function LbankStatusBadge() {
  const [connected, setConnected] = useState<boolean | null>(null)

  useEffect(() => {
    fetch('/api/lbank/status')
      .then((r) => r.json())
      .then((d) => setConnected(d.connected))
      .catch(() => setConnected(false))
  }, [])

  if (connected === null) return <span className="inline-block h-2 w-2 rounded-full bg-zinc-600" />

  return (
    <span
      className={`inline-block h-2 w-2 rounded-full shrink-0 ${
        connected ? 'bg-green-400' : 'bg-zinc-500'
      }`}
      title={connected ? 'LBank 接続済み' : 'LBank 未接続'}
    />
  )
}
getKey function · typescript · L7-L12 (6 LOC)
lib/crypto/encryption.ts
function getKey(): Buffer {
  const key = process.env.ENCRYPTION_KEY
  if (!key) throw new Error('ENCRYPTION_KEY is not set')
  // Derive 32-byte key from the env string
  return createHash('sha256').update(key).digest()
}
encrypt function · typescript · L14-L28 (15 LOC)
lib/crypto/encryption.ts
export function encrypt(plaintext: string): string {
  const key = getKey()
  const iv = randomBytes(IV_LENGTH)
  const cipher = createCipheriv(ALGORITHM, key, iv)

  const encrypted = Buffer.concat([
    cipher.update(plaintext, 'utf8'),
    cipher.final(),
  ])
  const tag = cipher.getAuthTag()

  // Format: iv(12) + tag(16) + encrypted
  const combined = Buffer.concat([iv, tag, encrypted])
  return combined.toString('base64')
}
decrypt function · typescript · L30-L46 (17 LOC)
lib/crypto/encryption.ts
export function decrypt(ciphertext: string): string {
  const key = getKey()
  const combined = Buffer.from(ciphertext, 'base64')

  const iv = combined.subarray(0, IV_LENGTH)
  const tag = combined.subarray(IV_LENGTH, IV_LENGTH + TAG_LENGTH)
  const encrypted = combined.subarray(IV_LENGTH + TAG_LENGTH)

  const decipher = createDecipheriv(ALGORITHM, key, iv)
  decipher.setAuthTag(tag)

  const decrypted = Buffer.concat([
    decipher.update(encrypted),
    decipher.final(),
  ])
  return decrypted.toString('utf8')
}
buildSignature function · typescript · L20-L39 (20 LOC)
lib/lbank/api.ts
function buildSignature(params: Record<string, string>, secretKey: string): string {
  // Sort params alphabetically
  const sortedKeys = Object.keys(params).sort()
  const sorted = sortedKeys.map((k) => `${k}=${params[k]}`).join('&')

  // MD5 hash -> uppercase hex
  const md5Hash = md5Uppercase(sorted)

  // HmacSHA256 with secretKey -> HEX (LBank requires hex, not base64)
  const signature = createHmac('sha256', secretKey)
    .update(md5Hash)
    .digest('hex')

  console.log('[LBank sign] sorted keys:', sortedKeys)
  console.log('[LBank sign] signed string:', sorted)
  console.log('[LBank sign] md5:', md5Hash)
  console.log('[LBank sign] signature:', signature)

  return signature
}
Repobility · severity-and-effort ranking · https://repobility.com
lbankPost function · typescript · L80-L107 (28 LOC)
lib/lbank/api.ts
async function lbankPost<T>(
  endpoint: string,
  params: LBankRequestParams,
  apiKey: string,
  secretKey: string
): Promise<T> {
  const { body, headers } = buildLBankRequest(params, apiKey, secretKey)

  const res = await fetch(`${LBANK_BASE_URL}${endpoint}`, {
    method: 'POST',
    headers,
    body: body.toString(),
  })

  if (!res.ok) {
    throw new Error(`LBank API error: ${res.status} ${res.statusText}`)
  }

  const json: LBankResponse<T> = await res.json()

  console.log('[LBank raw response]', JSON.stringify(json))

  if (json.result !== 'true' && json.result !== 'True' && json.result !== true) {
    throw new Error(`LBank error ${json.error_code}: ${json.msg ?? 'unknown error'}`)
  }

  return json.data as T
}
getUSDTBalance function · typescript · L129-L137 (9 LOC)
lib/lbank/api.ts
export async function getUSDTBalance(
  apiKey: string,
  secretKey: string
): Promise<number> {
  const balances = await getAccountBalance(apiKey, secretKey)
  const usdt = balances.find((b) => b.asset.toLowerCase() === 'usdt')
  if (!usdt) return 0
  return parseFloat(usdt.available) + parseFloat(usdt.freeze)
}
getTransactionHistory function · typescript · L140-L156 (17 LOC)
lib/lbank/api.ts
export async function getTransactionHistory(
  apiKey: string,
  secretKey: string,
  symbol: string = 'izky_usdt',
  startTime?: number,
  endTime?: number,
  limit: number = 100
): Promise<{
  orderId: string
  symbol: string
  side: string
  price: string
  volume: string
  dealVolume: string
  dealPrice: string
  transactTime: string
}[]> {
getVolumeForPair function · typescript · L189-L211 (23 LOC)
lib/lbank/api.ts
export async function getVolumeForPair(
  apiKey: string,
  secretKey: string,
  startTimestamp: number
): Promise<number> {
  const trades = await getTransactionHistory(
    apiKey,
    secretKey,
    'izky_usdt',
    startTimestamp,
    undefined,
    100
  )

  let totalVolume = 0
  for (const trade of trades) {
    // Volume in USDT = dealVolume * dealPrice (or use dealVolume directly if it's USDT side)
    const vol = parseFloat(trade.dealVolume) * parseFloat(trade.dealPrice)
    if (!isNaN(vol)) totalVolume += vol
  }

  return totalVolume
}
createClient function · typescript · L3-L8 (6 LOC)
lib/supabase/client.ts
export function createClient() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  )
}
createClient function · typescript · L5-L28 (24 LOC)
lib/supabase/server.ts
export async function createClient() {
  const cookieStore = await cookies()

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll()
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options)
            )
          } catch {
            // Server component - cookies cannot be set
          }
        },
      },
    }
  )
}
createServiceClient function · typescript · L31-L42 (12 LOC)
lib/supabase/server.ts
export function createServiceClient() {
  return createSupabaseClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.SUPABASE_SERVICE_ROLE_KEY!,
    {
      auth: {
        autoRefreshToken: false,
        persistSession: false,
      },
    }
  )
}
proxy function · typescript · L5-L44 (40 LOC)
proxy.ts
export async function proxy(request: NextRequest) {
  let response = NextResponse.next({
    request: {
      headers: request.headers,
    },
  })

  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return request.cookies.getAll()
        },
        setAll(cookiesToSet) {
          cookiesToSet.forEach(({ name, value }) =>
            request.cookies.set(name, value)
          )
          response = NextResponse.next({ request })
          cookiesToSet.forEach(({ name, value, options }) =>
            response.cookies.set(name, value, options)
          )
        },
      },
    }
  )

  const { data: { user } } = await supabase.auth.getUser()

  // Admin routes: require authenticated Supabase user
  if (request.nextUrl.pathname.startsWith('/admin') &&
      !request.nextUrl.pathname.startsWith('/admin/login')) {
    if (!user) {
      return NextResponse.
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
decryptAesGcm function · typescript · L122-L144 (23 LOC)
supabase/functions/update-rankings/index.ts
async function decryptAesGcm(ciphertext: string, keyString: string): Promise<string> {
  const combined = Uint8Array.from(atob(ciphertext), (c) => c.charCodeAt(0))
  const iv = combined.slice(0, 12)
  const tag = combined.slice(12, 28) // ignored by Web Crypto (tag is appended to ciphertext)
  const encrypted = combined.slice(28)
  const encryptedWithTag = new Uint8Array([...encrypted, ...tag])

  const keyBytes = await crypto.subtle.digest(
    'SHA-256',
    new TextEncoder().encode(keyString)
  )
  const cryptoKey = await crypto.subtle.importKey(
    'raw', keyBytes, { name: 'AES-GCM' }, false, ['decrypt']
  )

  const decrypted = await crypto.subtle.decrypt(
    { name: 'AES-GCM', iv },
    cryptoKey,
    encryptedWithTag
  )

  return new TextDecoder().decode(decrypted)
}
buildLBankRequest function · typescript · L147-L195 (49 LOC)
supabase/functions/update-rankings/index.ts
async function buildLBankRequest(
  params: Record<string, string>,
  apiKey: string,
  secretKey: string
) {
  const timestamp = Date.now().toString()
  const echostr = Array.from({ length: 35 }, () =>
    'abcdefghijklmnopqrstuvwxyz0123456789'.charAt(Math.floor(Math.random() * 36))
  ).join('')

  const allParams: Record<string, string> = {
    ...params,
    api_key: apiKey,
    signature_method: 'HmacSHA256',
    timestamp,
    echostr,
  }

  // Sort and build string
  const sorted = Object.keys(allParams)
    .sort()
    .map((k) => `${k}=${allParams[k]}`)
    .join('&')

  // MD5 hash (uppercase)
  const md5Hash = await md5Uppercase(sorted)

  // HmacSHA256 signature
  const keyBytes = new TextEncoder().encode(secretKey)
  const hmacKey = await crypto.subtle.importKey(
    'raw', keyBytes, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']
  )
  const sigBytes = await crypto.subtle.sign('HMAC', hmacKey, new TextEncoder().encode(md5Hash))
  const signature = Array.from(new Uint8A
md5Uppercase function · typescript · L197-L207 (11 LOC)
supabase/functions/update-rankings/index.ts
async function md5Uppercase(str: string): Promise<string> {
  const msgBuffer = new TextEncoder().encode(str)
  const hashBuffer = await crypto.subtle.digest('MD5', msgBuffer).catch(() => {
    // MD5 not available in some environments - fallback
    throw new Error('MD5 not available')
  })
  return Array.from(new Uint8Array(hashBuffer))
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('')
    .toUpperCase()
}
getLBankUSDTBalance function · typescript · L209-L220 (12 LOC)
supabase/functions/update-rankings/index.ts
async function getLBankUSDTBalance(apiKey: string, secretKey: string): Promise<number> {
  const { body, headers } = await buildLBankRequest({}, apiKey, secretKey)
  const res = await fetch('https://api.lbkex.com/v2/supplement/user_info_account.do', {
    method: 'POST',
    headers,
    body,
  })
  const json = await res.json()
  const free = json?.data?.info?.free?.usdt ?? '0'
  const freeze = json?.data?.info?.freeze?.usdt ?? '0'
  return parseFloat(free) + parseFloat(freeze)
}
getLBankVolume function · typescript · L222-L248 (27 LOC)
supabase/functions/update-rankings/index.ts
async function getLBankVolume(
  apiKey: string,
  secretKey: string,
  startTimestamp: number
): Promise<number> {
  const { body, headers } = await buildLBankRequest(
    { symbol: 'izky_usdt', current_page: '1', page_length: '100' },
    apiKey,
    secretKey
  )
  const res = await fetch('https://api.lbkex.com/v2/supplement/transaction_history.do', {
    method: 'POST',
    headers,
    body,
  })
  const json = await res.json()
  const orders = json?.data?.orders ?? []

  let total = 0
  for (const order of orders) {
    const t = parseInt(order.transactTime ?? '0')
    if (t < startTimestamp) continue
    const vol = parseFloat(order.dealVolume ?? '0') * parseFloat(order.dealPrice ?? '0')
    if (!isNaN(vol)) total += vol
  }
  return total
}
‹ prevpage 2 / 2