UNPKG

pmarket-cli

Version:
150 lines 8.21 kB
import { ethers } from "ethers"; import { usdcContractABI } from "../abi/usdc.js"; import { conditionalTokensABI } from "../abi/conditional-tokens.js"; import { negRiskAdapterABI } from "../abi/neg-risk-adapter.js"; const CONDITIONAL_TOKENS_ADDRESS = '0x4D97DCd97eC945f40cF65F87097ACe5EA0476045'; const NEG_RISK_ADAPTER_ADDRESS = '0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296'; const USDC_E_ADDRESS = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174'; export class ContractService { configService; polygonProvider; wallet; constructor(configService) { this.configService = configService; this.polygonProvider = new ethers.JsonRpcProvider(this.configService.getRpcProvider()); try { this.wallet = new ethers.Wallet(this.configService.getPrivateKey(), this.polygonProvider); } catch { console.log("Please provide valid private key in config.json file"); } } async setAllowance(amountOfAllowedUSDC) { if (!this.wallet) { throw new Error("Wallet not initialized"); } const usdcContractAddress = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174'; const usdcContract = new ethers.Contract(usdcContractAddress, usdcContractABI, this.wallet); // CTFExchange for regular markets const ctfExchangeAddress = '0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E'; // NegRiskExchange for neg_risk markets const negRiskExchangeAddress = '0xC5d563A36AE78145C45a50134d48A1215220f80a'; // NegRiskAdapter for neg_risk markets const negRiskAdapterAddress = '0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296'; const allowanceValue = ethers.parseUnits(amountOfAllowedUSDC.toString(), 6); // Get current gas prices from the network const feeData = await this.polygonProvider.getFeeData(); // Polygon requires minimum 25 gwei priority fee, use 30 gwei to be safe const minPriorityFee = ethers.parseUnits('30', 'gwei'); const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas && feeData.maxPriorityFeePerGas > minPriorityFee ? feeData.maxPriorityFeePerGas : minPriorityFee; // Max fee = base fee * 2 + priority fee (to handle base fee fluctuations) const baseFee = feeData.maxFeePerGas || ethers.parseUnits('30', 'gwei'); const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas; const gasLimit = 100000; const txOptions = { gasLimit, maxPriorityFeePerGas, maxFeePerGas }; const delay = (seconds) => { console.log(`Waiting ${seconds} seconds to avoid RPC rate limits...`); return new Promise(resolve => setTimeout(resolve, seconds * 1000)); }; console.log('Setting allowance for CTFExchange...'); const ctfTx = await usdcContract.approve(ctfExchangeAddress, allowanceValue, txOptions); console.log(`CTFExchange tx submitted: ${ctfTx.hash}`); console.log('Waiting for confirmation...'); await delay(15); await ctfTx.wait(); console.log('CTFExchange allowance confirmed!'); console.log(''); await delay(30); console.log('Setting allowance for NegRiskExchange...'); const negRiskTx = await usdcContract.approve(negRiskExchangeAddress, allowanceValue, txOptions); console.log(`NegRiskExchange tx submitted: ${negRiskTx.hash}`); console.log('Waiting for confirmation...'); await delay(15); await negRiskTx.wait(); console.log('NegRiskExchange allowance confirmed!'); console.log(''); await delay(30); console.log('Setting allowance for NegRiskAdapter...'); const negRiskAdapterTx = await usdcContract.approve(negRiskAdapterAddress, allowanceValue, txOptions); return { ctf: ctfTx, negRisk: negRiskTx, negRiskAdapter: negRiskAdapterTx }; } async isStandardRedemption(conditionId) { if (!this.wallet) { throw new Error("Wallet not initialized"); } const ctf = new ethers.Contract(CONDITIONAL_TOKENS_ADDRESS, conditionalTokensABI, this.polygonProvider); const walletAddress = await this.wallet.getAddress(); // Check if user holds USDC.e-backed conditional tokens (standard market) // For neg_risk markets, tokens are backed by wrapped collateral, not USDC.e directly // Only check Yes position (indexSet=1) to minimize RPC calls on public endpoint const yesCollectionId = await ctf.getCollectionId(ethers.ZeroHash, conditionId, 1); await this.rpcDelay(2); const yesPositionId = await ctf.getPositionId(USDC_E_ADDRESS, yesCollectionId); await this.rpcDelay(2); const yesBalance = await ctf.balanceOf(walletAddress, yesPositionId); if (yesBalance > 0n) return true; // Also check No position if Yes was empty await this.rpcDelay(2); const noCollectionId = await ctf.getCollectionId(ethers.ZeroHash, conditionId, 2); await this.rpcDelay(2); const noPositionId = await ctf.getPositionId(USDC_E_ADDRESS, noCollectionId); await this.rpcDelay(2); const noBalance = await ctf.balanceOf(walletAddress, noPositionId); return noBalance > 0n; } rpcDelay(seconds) { return new Promise(resolve => setTimeout(resolve, seconds * 1000)); } async redeemPositions(conditionId) { if (!this.wallet) { throw new Error("Wallet not initialized"); } const ctf = new ethers.Contract(CONDITIONAL_TOKENS_ADDRESS, conditionalTokensABI, this.wallet); const parentCollectionId = ethers.ZeroHash; const indexSets = [1, 2]; // YES and NO outcomes const feeData = await this.polygonProvider.getFeeData(); const minPriorityFee = ethers.parseUnits('30', 'gwei'); const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas && feeData.maxPriorityFeePerGas > minPriorityFee ? feeData.maxPriorityFeePerGas : minPriorityFee; const baseFee = feeData.maxFeePerGas || ethers.parseUnits('30', 'gwei'); const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas; const txOptions = { gasLimit: 200000, maxPriorityFeePerGas, maxFeePerGas }; const tx = await ctf.redeemPositions(USDC_E_ADDRESS, parentCollectionId, conditionId, indexSets, txOptions); return tx; } async redeemNegRiskPositions(conditionId, amounts) { if (!this.wallet) { throw new Error("Wallet not initialized"); } const ctf = new ethers.Contract(CONDITIONAL_TOKENS_ADDRESS, conditionalTokensABI, this.wallet); const negRiskAdapter = new ethers.Contract(NEG_RISK_ADAPTER_ADDRESS, negRiskAdapterABI, this.wallet); // Check if NegRiskAdapter is approved to transfer ERC-1155 tokens const walletAddress = await this.wallet.getAddress(); await this.rpcDelay(3); const isApproved = await ctf.isApprovedForAll(walletAddress, NEG_RISK_ADAPTER_ADDRESS); await this.rpcDelay(3); const feeData = await this.polygonProvider.getFeeData(); const minPriorityFee = ethers.parseUnits('30', 'gwei'); const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas && feeData.maxPriorityFeePerGas > minPriorityFee ? feeData.maxPriorityFeePerGas : minPriorityFee; const baseFee = feeData.maxFeePerGas || ethers.parseUnits('30', 'gwei'); const maxFeePerGas = baseFee * 2n + maxPriorityFeePerGas; const txOptions = { gasLimit: 300000, maxPriorityFeePerGas, maxFeePerGas }; if (!isApproved) { console.log('Approving NegRiskAdapter to transfer conditional tokens...'); const approvalTx = await ctf.setApprovalForAll(NEG_RISK_ADAPTER_ADDRESS, true, txOptions); console.log(`Approval tx submitted: ${approvalTx.hash}`); await approvalTx.wait(); console.log('Approval confirmed.'); console.log(''); } const tx = await negRiskAdapter.redeemPositions(conditionId, amounts, txOptions); return tx; } } //# sourceMappingURL=contract.service.js.map