← Back
import { createPublicClient, http, encodeFunctionData, erc20Abi } from 'viem';
import { polygon } from 'viem/chains';
import { OperationType, type SafeTransaction } from '@polymarket/builder-relayer-client';

// Polymarket contracts (Polygon mainnet). Same set as the official privy example.
const USDC_E = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174';
const CTF = '0x4d97dcd97ec945f40cf65f87097ace5ea0476045';
const CTF_EXCHANGE = '0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E';
const NEG_RISK_CTF_EXCHANGE = '0xC5d563A36AE78145C45a50134d48A1215220f80a';
const NEG_RISK_ADAPTER = '0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296';
const MAX_UINT256 = (2n ** 256n - 1n);

const erc1155Abi = [
  { inputs: [{ name: 'operator', type: 'address' }, { name: 'approved', type: 'bool' }], name: 'setApprovalForAll', outputs: [], stateMutability: 'nonpayable', type: 'function' },
  { inputs: [{ name: 'account', type: 'address' }, { name: 'operator', type: 'address' }], name: 'isApprovedForAll', outputs: [{ name: '', type: 'bool' }], stateMutability: 'view', type: 'function' },
] as const;

// polygon-rpc.com is gated from our server; drpc works.
const pub = createPublicClient({ chain: polygon, transport: http('https://polygon.drpc.org') });

const USDC_SPENDERS = [CTF, NEG_RISK_ADAPTER, CTF_EXCHANGE, NEG_RISK_CTF_EXCHANGE];
const TOKEN_SPENDERS = [CTF_EXCHANGE, NEG_RISK_CTF_EXCHANGE, NEG_RISK_ADAPTER];

export async function checkAllApprovals(safe: string): Promise<{ allApproved: boolean }> {
  const threshold = 1000000000000n;
  const usdc = await Promise.all(USDC_SPENDERS.map(async (s) => {
    try {
      const a = await pub.readContract({ address: USDC_E, abi: erc20Abi, functionName: 'allowance', args: [safe as `0x${string}`, s as `0x${string}`] });
      return a >= threshold;
    } catch { return false; }
  }));
  const tok = await Promise.all(TOKEN_SPENDERS.map(async (s) => {
    try {
      return await pub.readContract({ address: CTF, abi: erc1155Abi, functionName: 'isApprovedForAll', args: [safe as `0x${string}`, s as `0x${string}`] });
    } catch { return false; }
  }));
  return { allApproved: usdc.every(Boolean) && tok.every(Boolean) };
}

export function createAllApprovalTxs(): SafeTransaction[] {
  const txs: SafeTransaction[] = [];
  for (const spender of USDC_SPENDERS) {
    txs.push({
      to: USDC_E, operation: OperationType.Call, value: '0',
      data: encodeFunctionData({ abi: erc20Abi, functionName: 'approve', args: [spender as `0x${string}`, MAX_UINT256] }),
    });
  }
  for (const spender of TOKEN_SPENDERS) {
    txs.push({
      to: CTF, operation: OperationType.Call, value: '0',
      data: encodeFunctionData({ abi: erc1155Abi, functionName: 'setApprovalForAll', args: [spender as `0x${string}`, true] }),
    });
  }
  return txs;
}

📜 Git History

6c47fa4chore: local Polikopi project home + Phase 1 redesign artifacts12 days ago
Show last diff
Loading...