Created
October 6, 2025 03:14
-
-
Save mgild/63bd892db33802d694e14cabd2dce0b7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bun | |
| import { CrossbarClient } from "@switchboard-xyz/common"; | |
| import * as fs from 'fs'; | |
| import * as crypto from 'crypto'; | |
| import yargs from 'yargs'; | |
| import { hideBin } from 'yargs/helpers'; | |
| interface Arguments { | |
| apiKeyId: string; | |
| privateKeyPath: string; | |
| crossbarUrl: string; | |
| orderId?: string; | |
| } | |
| const argv = yargs(hideBin(process.argv)) | |
| .option('api-key-id', { | |
| alias: 'k', | |
| type: 'string', | |
| description: 'Kalshi API Key ID', | |
| demandOption: true | |
| }) | |
| .option('private-key-path', { | |
| alias: 'p', | |
| type: 'string', | |
| description: 'Path to the private key PEM file', | |
| demandOption: true | |
| }) | |
| .option('order-id', { | |
| alias: 'o', | |
| type: 'string', | |
| description: 'Order ID to fetch (if not provided, lists all orders)', | |
| demandOption: false | |
| }) | |
| .option('crossbar-url', { | |
| alias: 'u', | |
| type: 'string', | |
| description: 'Crossbar server URL', | |
| default: 'https://crossbar.switchboardlabs.xyz' | |
| }) | |
| .example('$0 -k <api-key-id> -p /path/to/key.pem', 'List all orders') | |
| .example('$0 -k <api-key-id> -p /path/to/key.pem -o <order-id>', 'Get specific order') | |
| .help() | |
| .alias('help', 'h') | |
| .parseSync() as Arguments; | |
| function validatePrivateKeyPath(keyPath: string): void { | |
| if (!fs.existsSync(keyPath)) { | |
| throw new Error(`Private key file not found: ${keyPath}`); | |
| } | |
| } | |
| function loadPrivateKey(keyPath: string): crypto.KeyObject { | |
| const privateKeyPem = fs.readFileSync(keyPath, 'utf8'); | |
| return crypto.createPrivateKey(privateKeyPem); | |
| } | |
| function createSignature( | |
| privateKey: crypto.KeyObject, | |
| timestamp: string, | |
| method: string, | |
| path: string | |
| ): string { | |
| const message = `${timestamp}${method}${path}`; | |
| const messageBuffer = Buffer.from(message, "utf8"); | |
| const signature = crypto.sign("sha256", messageBuffer, { | |
| key: privateKey, | |
| padding: crypto.constants.RSA_PKCS1_PSS_PADDING, | |
| saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST, | |
| }); | |
| return signature.toString("base64"); | |
| } | |
| (async function main() { | |
| try { | |
| validatePrivateKeyPath(argv.privateKeyPath); | |
| const privateKey = loadPrivateKey(argv.privateKeyPath); | |
| const timestamp = Date.now().toString(); | |
| const method = 'GET'; | |
| const isListOrders = !argv.orderId; | |
| const path = isListOrders | |
| ? '/trade-api/v2/portfolio/orders' | |
| : `/trade-api/v2/portfolio/orders/${argv.orderId}`; | |
| const signature = createSignature(privateKey, timestamp, method, path); | |
| if (isListOrders) { | |
| console.log('π Listing Orders'); | |
| console.log('=================\n'); | |
| const url = `https://api.elections.kalshi.com${path}`; | |
| const response = await fetch(url, { | |
| method: 'GET', | |
| headers: { | |
| 'KALSHI-ACCESS-KEY': argv.apiKeyId, | |
| 'KALSHI-ACCESS-SIGNATURE': signature, | |
| 'KALSHI-ACCESS-TIMESTAMP': timestamp | |
| } | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`API request failed: ${response.status} ${response.statusText}`); | |
| } | |
| const data = await response.json(); | |
| console.log('Orders:'); | |
| console.log(JSON.stringify(data, null, 2)); | |
| return; | |
| } | |
| const url = `https://api.elections.kalshi.com${path}`; | |
| console.log('π― Kalshi Job Testing via Crossbar'); | |
| console.log('===================================\n'); | |
| console.log('π Configuration:'); | |
| console.log(`π API Key ID: ${argv.apiKeyId}`); | |
| console.log(`π Order ID: ${argv.orderId}`); | |
| console.log(`β° Timestamp: ${timestamp}`); | |
| console.log(`βοΈ Signature: ${signature.substring(0, 50)}...${signature.substring(signature.length - 20)}`); | |
| console.log(`π Crossbar URL: ${argv.crossbarUrl}\n`); | |
| const crossbar = new CrossbarClient(argv.crossbarUrl); | |
| console.log('π Simulating Kalshi get-order job via Crossbar...\n'); | |
| const simulation = await crossbar.simulateJobs({ | |
| jobs: [ | |
| { | |
| tasks: [ | |
| { | |
| kalshiApiTask: { | |
| url, | |
| apiKeyId: argv.apiKeyId, | |
| signature: "${KALSHI_SIGNATURE}", | |
| timestamp: "${KALSHI_TIMESTAMP}" | |
| } | |
| }, | |
| { | |
| jsonParseTask: { | |
| path: "$.order.yes_price_dollars", | |
| } | |
| } | |
| ] | |
| } | |
| ], | |
| includeReceipts: true, | |
| variableOverrides: { | |
| KALSHI_SIGNATURE: signature, | |
| KALSHI_TIMESTAMP: timestamp | |
| } | |
| }); | |
| console.log('β Success! Simulation Result:'); | |
| console.log('=============================='); | |
| console.log(JSON.stringify(simulation, null, 2)); | |
| } catch (error) { | |
| console.error('β Error:', error); | |
| if (error instanceof Error) { | |
| console.error('Message:', error.message); | |
| if (error.stack) { | |
| console.error('Stack:', error.stack); | |
| } | |
| } | |
| process.exit(1); | |
| } | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment