pmarket-cli
Version:
CLI tool to trade on Polymarket
115 lines (98 loc) • 4.68 kB
text/typescript
import { ethers } from "ethers";
import { PolymarketService } from "../services/polymarket.service.js";
import { ContractService } from "../services/contract.service.js";
import { Strategy } from "./strategy.js";
interface GroupedPosition {
title: string;
yesSize: number;
noSize: number;
}
export class RedeemStrategy implements Strategy {
constructor(
private polymarketService: PolymarketService,
private contractService: ContractService
) { }
async execute(): Promise<void> {
try {
const address = this.polymarketService.getWalletAddress();
console.log(`Fetching redeemable positions for ${address}...`);
console.log('');
const positions = await this.polymarketService.getPositions();
const redeemable = positions.filter(p => p.redeemable);
if (redeemable.length === 0) {
console.log('No redeemable positions found.');
return;
}
// Group by conditionId
const grouped = new Map<string, GroupedPosition>();
for (const pos of redeemable) {
const current = grouped.get(pos.conditionId) || { title: pos.title, yesSize: 0, noSize: 0 };
if (pos.outcome === 'Yes') {
current.yesSize = pos.size;
} else {
current.noSize = pos.size;
}
grouped.set(pos.conditionId, current);
}
console.log(`Found ${grouped.size} resolved market(s) with redeemable positions:`);
console.log('');
for (const [conditionId, data] of grouped) {
const sizes = [];
if (data.yesSize > 0) sizes.push(`Yes: ${data.yesSize.toFixed(2)}`);
if (data.noSize > 0) sizes.push(`No: ${data.noSize.toFixed(2)}`);
console.log(` ${data.title}`);
console.log(` Condition: ${conditionId}`);
console.log(` Shares: ${sizes.join(', ')}`);
console.log('');
}
console.log('Redeeming positions...');
console.log('');
let redeemed = 0;
const delay = (seconds: number) => {
console.log(` Waiting ${seconds}s to avoid RPC rate limits...`);
return new Promise(resolve => setTimeout(resolve, seconds * 1000));
};
for (const [conditionId, data] of grouped) {
console.log(`Redeeming: ${data.title}`);
try {
// Check if user holds USDC.e-backed tokens (standard) or wrapped collateral tokens (neg_risk)
const isStandard = await this.contractService.isStandardRedemption(conditionId);
await delay(5);
if (isStandard) {
console.log(' Detected: standard market');
const tx = await this.contractService.redeemPositions(conditionId);
console.log(` tx submitted: ${tx.hash}`);
await tx.wait();
console.log(' Confirmed (standard market)');
} else {
console.log(' Detected: neg_risk market');
const amounts = [
ethers.parseUnits(data.yesSize.toFixed(6), 6),
ethers.parseUnits(data.noSize.toFixed(6), 6)
];
const tx = await this.contractService.redeemNegRiskPositions(conditionId, amounts);
console.log(` tx submitted: ${tx.hash}`);
await tx.wait();
console.log(' Confirmed (neg_risk market)');
}
redeemed++;
} catch (error) {
const msg = error instanceof Error ? error.message : String(error);
console.error(` Failed to redeem: ${msg}`);
}
console.log('');
// Delay between redemptions to avoid RPC rate limits
if (grouped.size > 1) {
await delay(15);
}
}
console.log(`Redeemed ${redeemed}/${grouped.size} market(s). USDC.e has been returned to your wallet.`);
} catch (error) {
if (error instanceof Error) {
console.error('Failed to redeem positions:', error.message);
} else {
console.error('Failed to redeem positions:', error);
}
}
}
}