Skip to content

Instantly share code, notes, and snippets.

@poly-rodr
Last active November 27, 2025 07:41
Show Gist options
  • Select an option

  • Save poly-rodr/44313920481de58d5a3f6d1f8226bd5e to your computer and use it in GitHub Desktop.

Select an option

Save poly-rodr/44313920481de58d5a3f6d1f8226bd5e to your computer and use it in GitHub Desktop.
CLOB Allowance Setting Python + Neg Risk
from web3 import Web3
from web3.constants import MAX_INT
from web3.middleware import geth_poa_middleware
rpc_url = "" # Polygon rpc url
priv_key = "" # Polygon account private key (needs some MATIC)
pub_key = "" # Polygon account public key corresponding to private key
chain_id = 137
erc20_approve = """[{"constant": false,"inputs": [{"name": "_spender","type": "address" },{ "name": "_value", "type": "uint256" }],"name": "approve","outputs": [{ "name": "", "type": "bool" }],"payable": false,"stateMutability": "nonpayable","type": "function"}]"""
erc1155_set_approval = """[{"inputs": [{ "internalType": "address", "name": "operator", "type": "address" },{ "internalType": "bool", "name": "approved", "type": "bool" }],"name": "setApprovalForAll","outputs": [],"stateMutability": "nonpayable","type": "function"}]"""
usdc_address = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
ctf_address = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"
web3 = Web3(Web3.HTTPProvider(rpc_url))
web3.middleware_onion.inject(geth_poa_middleware, layer=0)
nonce = web3.eth.getTransactionCount(pub_key)
usdc = web3.eth.contract(address=usdc_address, abi=erc20_approve)
ctf = web3.eth.contract(address=ctf_address, abi=erc1155_set_approval)
# CTF Exchange
raw_usdc_approve_txn = usdc.functions.approve("0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", int(MAX_INT, 0)
).buildTransaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.rawTransaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)
nonce = web3.eth.getTransactionCount(pub_key)
raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", True).buildTransaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.rawTransaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)
nonce = web3.eth.getTransactionCount(pub_key)
# Neg Risk CTF Exchange
raw_usdc_approve_txn = usdc.functions.approve("0xC5d563A36AE78145C45a50134d48A1215220f80a", int(MAX_INT, 0)
).buildTransaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.rawTransaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)
nonce = web3.eth.getTransactionCount(pub_key)
raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0xC5d563A36AE78145C45a50134d48A1215220f80a", True).buildTransaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.rawTransaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)
nonce = web3.eth.getTransactionCount(pub_key)
# Neg Risk Adapter
raw_usdc_approve_txn = usdc.functions.approve("0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", int(MAX_INT, 0)
).buildTransaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.rawTransaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)
nonce = web3.eth.getTransactionCount(pub_key)
raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", True).buildTransaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.rawTransaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)
@lucashhan
Copy link

What version of web3 package using in this gist? I installed the 7.4.0 of web3, there are many funcs and methods's names changed.

@cb-compound
Copy link

@poly-rodr Thanks for sharing. I also had the same issues as yoko330 pointed out earlier. The code doesn't work with the most recent web3 version 7.4.0

@lucashhan
Copy link

@poly-rodr Thanks for sharing. I also had the same issues as yoko330 pointed out earlier. The code doesn't work with the most recent web3 version 7.4.0

I am writting the update version of this gist. To point out, the MATIC have updated to be POL now. I'm not sure this transaction needs some old MATIC coin or POL coin.

@rosesareredroses
Copy link

rosesareredroses commented Oct 30, 2024

from web3 import Web3
from web3.constants import MAX_INT
from web3.middleware import ExtraDataToPOAMiddleware

rpc_url = "https://polygon-rpc.com" # Polygon rpc url 
priv_key = "..." # Polygon account private key (needs some MATIC)
pub_key = "..." # Polygon account public key corresponding to private key

chain_id = 137

erc20_approve = """[{"constant": false,"inputs": [{"name": "_spender","type": "address" },{ "name": "_value", "type": "uint256" }],"name": "approve","outputs": [{ "name": "", "type": "bool" }],"payable": false,"stateMutability": "nonpayable","type": "function"}]"""
erc1155_set_approval = """[{"inputs": [{ "internalType": "address", "name": "operator", "type": "address" },{ "internalType": "bool", "name": "approved", "type": "bool" }],"name": "setApprovalForAll","outputs": [],"stateMutability": "nonpayable","type": "function"}]"""

usdc_address = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"
ctf_address = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"

web3 = Web3(Web3.HTTPProvider(rpc_url))
web3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)
balance = web3.eth.get_balance(pub_key)
print(f"Current MATIC balance: {web3.from_wei(balance, 'ether')} MATIC")
nonce = web3.eth.get_transaction_count(pub_key)

usdc = web3.eth.contract(address=usdc_address, abi=erc20_approve)
ctf = web3.eth.contract(address=ctf_address, abi=erc1155_set_approval)

# CTF Exchange
raw_usdc_approve_txn = usdc.functions.approve("0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", int(MAX_INT, 0)
).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.raw_transaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", True).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.raw_transaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

# Neg Risk CTF Exchange
raw_usdc_approve_txn = usdc.functions.approve("0xC5d563A36AE78145C45a50134d48A1215220f80a", int(MAX_INT, 0)
).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.raw_transaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0xC5d563A36AE78145C45a50134d48A1215220f80a", True).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.raw_transaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

# Neg Risk Adapter
raw_usdc_approve_txn = usdc.functions.approve("0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", int(MAX_INT, 0)
).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.raw_transaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", True).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.raw_transaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)

I've added POL and MATIC to the address, tried using this - it seems to do the txs correctly and all, but my clob is still complaining about allowance...any ideas? am I missing something?
@poly-rodr or more recently active @lucashhan

@SirBenedick
Copy link

SirBenedick commented Oct 30, 2024

This script worked for me with web3 version 6.14.0.
Allowance was was updated correctly.

# works with web3===6.14.0
from web3 import Web3
from web3.constants import MAX_INT
from web3.middleware import geth_poa_middleware

rpc_url = "https://polygon-rpc.com" # Polygon rpc url 
priv_key = "" # Polygon account private key (needs some MATIC)
pub_key = "" # Polygon account public key corresponding to private key
chain_id = 137

erc20_approve = """[{"constant": false,"inputs": [{"name": "_spender","type": "address" },{ "name": "_value", "type": "uint256" }],"name": "approve","outputs": [{ "name": "", "type": "bool" }],"payable": false,"stateMutability": "nonpayable","type": "function"}]"""
erc1155_set_approval = """[{"inputs": [{ "internalType": "address", "name": "operator", "type": "address" },{ "internalType": "bool", "name": "approved", "type": "bool" }],"name": "setApprovalForAll","outputs": [],"stateMutability": "nonpayable","type": "function"}]"""

usdc_address = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174" # MATIC collateral
ctf_address = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045" # MATIC conditionalTokens

web3 = Web3(Web3.HTTPProvider(rpc_url))
web3.middleware_onion.inject(geth_poa_middleware, layer=0)

nonce = web3.eth.get_transaction_count(pub_key)

usdc = web3.eth.contract(address=usdc_address, abi=erc20_approve)
ctf = web3.eth.contract(address=ctf_address, abi=erc1155_set_approval)


# CTF Exchange
raw_usdc_approve_txn = usdc.functions.approve("0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", int(MAX_INT, 0)
).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.rawTransaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", True).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.rawTransaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

# Neg Risk CTF Exchange
raw_usdc_approve_txn = usdc.functions.approve("0xC5d563A36AE78145C45a50134d48A1215220f80a", int(MAX_INT, 0)
).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.rawTransaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0xC5d563A36AE78145C45a50134d48A1215220f80a", True).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.rawTransaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

# Neg Risk Adapter
raw_usdc_approve_txn = usdc.functions.approve("0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", int(MAX_INT, 0)
).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.rawTransaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", True).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.rawTransaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)

@shaunlebron
Copy link

The pub_key is the 42-character wallet address derived from the 130-character public key, not the public key itself.

@joachim23344
Copy link

Hi all, when i run this script i get the following response: ValueError: {'code': -32000, 'message': 'INTERNAL_ERROR: insufficient funds'}. I have 15 MATIC on my wallet tho. Do i need more or am I missing something? All help would be appreciated. :)

@aebenbach
Copy link

Hi all, when i run this script i get the following response: ValueError: {'code': -32000, 'message': 'INTERNAL_ERROR: insufficient funds'}. I have 15 MATIC on my wallet tho. Do i need more or am I missing something? All help would be appreciated. :)

I think you need to use POL instead. I was getting the same error until I added POL to my wallet. That being said, I am still getting the "not enough allowance" error, even though I ran the above successfully.

@joachim23344
Copy link

@aebenbach yes thanks i added POL to my wallet and i think this script ran succesfully. But indeed when running the following, i get py_clob_client.exceptions.PolyApiException: PolyApiException[status_code=400, error_message={'error': 'not enough balance / allowance'}] as a response while i have usdc in my polymarket account: chain_id = POLYGON
client = ClobClient(host, key=key, chain_id=chain_id, creds=creds)

order_args = OrderArgs(
    price=0.01,
    size=1,
    side=BUY,
    token_id="59658166739979955015642910311638409776513450405422998760953344989158397038866",
)
signed_order = client.create_order(order_args)
resp = client.post_order(signed_order)
print(resp)
print("Done!").    -> if anyone knows how to solve this i would love to hear it :)

@aebenbach
Copy link

@joachim23344
I found the problem on my end to be with the way I was initializing the client, since I am using the Polygon Proxy. So instead initialize like this:
### Initialization of a client using a Polymarket Proxy associated with an Email/Magic account client = ClobClient(host, key=key, chain_id=chain_id, signature_type=1, funder=POLYMARKET_PROXY_ADDRESS)
Also, important detail was to input the address that's provided when going to deposit USDC into the polymarket account in the "funder" argument.

Hope this helps!

@DanielOllivier
Copy link

Hallo ,I used Metamask Keys to ran file-set_allowances-py. I think it was successfully, now what ?

when I tried to create an API I got:

PolyApiException[status_code=401 error_message={'error': 'Invalid L1 Request headers'}]

@DanielOllivier
Copy link

I ran using Metamask keys "set_allowences.py" succesfully. but when I tried to create an API a got:
PolyApiException[status_code=401, error_message={'error': 'Invalid L1 Request headers'}]
what I'm missing ?
Regards

@DavidSanf0rd
Copy link

I'm using the nodeJs api and I followed what @aebenbach said (ty). So no allowances needed to be set at all.

here's my clob client initialization
const clobClient = new ClobClient(host, Chain.POLYGON, signer, creds, 1, process.env.POLY_WALLET);

@talleyra
Copy link

Hello,
I would greatly appreciate a more extensive explanation of what needs to be done to set the allowances.
Where can I find the values I need to set rpc_url, priv_key and pub_key, or what are the steps to get them.
Many thanks in advance and the best of luck while trading!

@hugeterry
Copy link

hugeterry commented Feb 26, 2025

I am using the following for login: signature_type=2 Proxy associated with a Browser Wallet (Metamask, Coinbase Wallet, etc.). I don't know the private key for my POLYMARKET_PROXY_ADDRESS. How can I execute this script?

When I use the private key of the main wallet to execute this script, it still reports: {'error': 'not enough balance / allowance'}.

@Yjejuy
Copy link

Yjejuy commented Jul 14, 2025

I am using the following for login: signature_type=2 Proxy associated with a Browser Wallet (Metamask, Coinbase Wallet, etc.). I don't know the private key for my POLYMARKET_PROXY_ADDRESS. How can I execute this script?

When I use the private key of the main wallet to execute this script, it still reports: {'error': 'not enough balance / allowance'}.

Hi, I also had the trouble of calling the API through metamask logged account. It turns out that I need to use the EOA method to place the order. Be careful that the polymarket has two types of USDC, and you need the USDC.e in your wallet to place the order.

from py_clob_client.client import ClobClient
from py_clob_client.clob_types import OrderArgs, OrderType
from py_clob_client.order_builder.constants import BUY

host: str = "https://clob.polymarket.com"
key: str = "" #This is your Private Key from your wallet application
chain_id: int = 137 #No need to adjust this

### Initialization of a client that trades directly from an EOA. 
# Use this for metamask created wallets
client = ClobClient(host, key=key, chain_id=chain_id)

client.set_api_creds(client.create_or_derive_api_creds()) 

order_args = OrderArgs(
    price=0.05,
    size=20.0,
    side=BUY,
    token_id="101555267111013378040255679961119612294196849321877000878970972184407343215893", # Market: xi-jinping-out-before-october, outcome: No
)
signed_order = client.create_order(order_args)

## GTC(Good-Till-Cancelled) Order
resp = client.post_order(signed_order, OrderType.GTC)
print(resp)

@to1dev
Copy link

to1dev commented Sep 14, 2025

Here’s a simple TypeScript script that performs the same allowance operation.

To make everything work smoothly, you'll need to…

  1. Install viem (npm install viem / bun add viem)
  2. Transfer some USDC.e to your wallet (withdraw USDC.e to your wallet from your polymarket dashboard)
import {
    createPublicClient,
    createWalletClient,
    http,
    parseAbi,
    maxUint256,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { polygon } from "viem/chains";

// ==== Basic Config ====
const rpcUrl = process.env.POLYGON_RPC;
const privKey = process.env.PRIVATE_KEY as `0x${string}`;
const account = privateKeyToAccount(privKey);

const publicClient = createPublicClient({
    chain: polygon,
    transport: http(rpcUrl),
});

const walletClient = createWalletClient({
    account,
    chain: polygon,
    transport: http(rpcUrl),
});

// ==== ABI ====
const erc20Abi = parseAbi([
    "function approve(address spender, uint256 value) returns (bool)",
]);

const erc1155Abi = parseAbi([
    "function setApprovalForAll(address operator, bool approved)",
]);

// ==== Contract Addresses ====
const usdc = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
const ctf = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045";

const targets: `0x${string}`[] = [
    "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", // CTF Exchange
    "0xC5d563A36AE78145C45a50134d48A1215220f80a", // Neg Risk CTF Exchange
    "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", // Neg Risk Adapter
];

// ==== Execute approve / setApprovalForAll ====
async function main() {
    console.log(`🔑 Using account: ${account.address}`);

    for (const target of targets) {
        console.log(`🔑 Granting approvals to ${target}...`);

        // --- 1. ERC20 approve ---
        const { request: approveReq } = await publicClient.simulateContract({
            address: usdc,
            abi: erc20Abi,
            functionName: "approve",
            args: [target, maxUint256],
            account, // 👈 Must pass account to avoid zero address
        });

        const approveHash = await walletClient.writeContract(approveReq);
        const approveReceipt = await publicClient.waitForTransactionReceipt({
            hash: approveHash,
        });
        console.log("✅ USDC approve tx:", approveReceipt.transactionHash);

        // --- 2. ERC1155 setApprovalForAll ---
        const { request: setApprovalReq } = await publicClient.simulateContract(
            {
                address: ctf,
                abi: erc1155Abi,
                functionName: "setApprovalForAll",
                args: [target, true],
                account, // 👈 Must also pass account here
            }
        );

        const setApprovalHash = await walletClient.writeContract(
            setApprovalReq
        );
        const setApprovalReceipt = await publicClient.waitForTransactionReceipt(
            { hash: setApprovalHash }
        );
        console.log(
            "✅ CTF setApproval tx:",
            setApprovalReceipt.transactionHash
        );
    }
}

main().catch((err) => {
    console.error("❌ Error:", err);
});

@skewliness
Copy link

以下是一个简单的 TypeScript 脚本,可以执行相同的权限操作。

为了确保一切顺利进行,你需要……

  1. 安装 viem(npm install viem/bun add viem)
  2. 将一些 USDC.e 转入您的钱包(从您的 Polymarket 控制面板提取 USDC.e 到您的钱包)
import {
    createPublicClient,
    createWalletClient,
    http,
    parseAbi,
    maxUint256,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { polygon } from "viem/chains";

// ==== Basic Config ====
const rpcUrl = process.env.POLYGON_RPC;
const privKey = process.env.PRIVATE_KEY as `0x${string}`;
const account = privateKeyToAccount(privKey);

const publicClient = createPublicClient({
    chain: polygon,
    transport: http(rpcUrl),
});

const walletClient = createWalletClient({
    account,
    chain: polygon,
    transport: http(rpcUrl),
});

// ==== ABI ====
const erc20Abi = parseAbi([
    "function approve(address spender, uint256 value) returns (bool)",
]);

const erc1155Abi = parseAbi([
    "function setApprovalForAll(address operator, bool approved)",
]);

// ==== Contract Addresses ====
const usdc = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
const ctf = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045";

const targets: `0x${string}`[] = [
    "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", // CTF Exchange
    "0xC5d563A36AE78145C45a50134d48A1215220f80a", // Neg Risk CTF Exchange
    "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", // Neg Risk Adapter
];

// ==== Execute approve / setApprovalForAll ====
async function main() {
    console.log(`🔑 Using account: ${account.address}`);

    for (const target of targets) {
        console.log(`🔑 Granting approvals to ${target}...`);

        // --- 1. ERC20 approve ---
        const { request: approveReq } = await publicClient.simulateContract({
            address: usdc,
            abi: erc20Abi,
            functionName: "approve",
            args: [target, maxUint256],
            account, // 👈 Must pass account to avoid zero address
        });

        const approveHash = await walletClient.writeContract(approveReq);
        const approveReceipt = await publicClient.waitForTransactionReceipt({
            hash: approveHash,
        });
        console.log("✅ USDC approve tx:", approveReceipt.transactionHash);

        // --- 2. ERC1155 setApprovalForAll ---
        const { request: setApprovalReq } = await publicClient.simulateContract(
            {
                address: ctf,
                abi: erc1155Abi,
                functionName: "setApprovalForAll",
                args: [target, true],
                account, // 👈 Must also pass account here
            }
        );

        const setApprovalHash = await walletClient.writeContract(
            setApprovalReq
        );
        const setApprovalReceipt = await publicClient.waitForTransactionReceipt(
            { hash: setApprovalHash }
        );
        console.log(
            "✅ CTF setApproval tx:",
            setApprovalReceipt.transactionHash
        );
    }
}

main().catch((err) => {
    console.error("❌ Error:", err);
});

What I don't understand is that it's actually just using Metamask to log in to PolyMarkets. The actual transaction address is the address generated by PM. Why put USDC on Metamask?

@x011
Copy link

x011 commented Nov 18, 2025

This script worked for me with web3 version 6.14.0. Allowance was was updated correctly.

# works with web3===6.14.0
from web3 import Web3
from web3.constants import MAX_INT
from web3.middleware import geth_poa_middleware

rpc_url = "https://polygon-rpc.com" # Polygon rpc url 
priv_key = "" # Polygon account private key (needs some MATIC)
pub_key = "" # Polygon account public key corresponding to private key
chain_id = 137

erc20_approve = """[{"constant": false,"inputs": [{"name": "_spender","type": "address" },{ "name": "_value", "type": "uint256" }],"name": "approve","outputs": [{ "name": "", "type": "bool" }],"payable": false,"stateMutability": "nonpayable","type": "function"}]"""
erc1155_set_approval = """[{"inputs": [{ "internalType": "address", "name": "operator", "type": "address" },{ "internalType": "bool", "name": "approved", "type": "bool" }],"name": "setApprovalForAll","outputs": [],"stateMutability": "nonpayable","type": "function"}]"""

usdc_address = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174" # MATIC collateral
ctf_address = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045" # MATIC conditionalTokens

web3 = Web3(Web3.HTTPProvider(rpc_url))
web3.middleware_onion.inject(geth_poa_middleware, layer=0)

nonce = web3.eth.get_transaction_count(pub_key)

usdc = web3.eth.contract(address=usdc_address, abi=erc20_approve)
ctf = web3.eth.contract(address=ctf_address, abi=erc1155_set_approval)


# CTF Exchange
raw_usdc_approve_txn = usdc.functions.approve("0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", int(MAX_INT, 0)
).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.rawTransaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", True).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.rawTransaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

# Neg Risk CTF Exchange
raw_usdc_approve_txn = usdc.functions.approve("0xC5d563A36AE78145C45a50134d48A1215220f80a", int(MAX_INT, 0)
).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.rawTransaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0xC5d563A36AE78145C45a50134d48A1215220f80a", True).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.rawTransaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

# Neg Risk Adapter
raw_usdc_approve_txn = usdc.functions.approve("0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", int(MAX_INT, 0)
).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_usdc_approve_tx = web3.eth.account.sign_transaction(raw_usdc_approve_txn, private_key=priv_key)
send_usdc_approve_tx = web3.eth.send_raw_transaction(signed_usdc_approve_tx.rawTransaction)
usdc_approve_tx_receipt = web3.eth.wait_for_transaction_receipt(send_usdc_approve_tx, 600)
print(usdc_approve_tx_receipt)

nonce = web3.eth.get_transaction_count(pub_key)

raw_ctf_approval_txn = ctf.functions.setApprovalForAll("0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", True).build_transaction({"chainId": chain_id, "from": pub_key, "nonce": nonce})
signed_ctf_approval_tx = web3.eth.account.sign_transaction(raw_ctf_approval_txn, private_key=priv_key)
send_ctf_approval_tx = web3.eth.send_raw_transaction(signed_ctf_approval_tx.rawTransaction)
ctf_approval_tx_receipt = web3.eth.wait_for_transaction_receipt(send_ctf_approval_tx, 600)
print(ctf_approval_tx_receipt)

Thank you, this worked for me with python3.11 and web3===6.14.0

@ShayenK
Copy link

ShayenK commented Nov 27, 2025

Hi This Version wasn't working for me but I made this version that works for the most recent version of web3 as of 27/11/2025

Extra Tips to Help with a Successful Bot:

  • make sure you have USDC.e (contract addy: 0x2791bca1f2de4661ed88a30c99a7a9449aa84174) for the actual trading execution otherwise it will still show balance / allowance error (NOT the other USDC contract addy: 0x3c499c542cef5e3811e1192ce70d8cc03d5c3359)
  • had to also test using a higher fill price i.e. 0.55 as opposed to 0.5 (just when testing)
  • MOST IMPORTANTLY: build out a redemption system for settlement back into your wallet -> last thing you want is to not be able to claim the money that you won
import os
from web3 import Web3
from web3.constants import MAX_INT
from web3.middleware import ExtraDataToPOAMiddleware  # Updated for web3.py v6+
from dotenv import load_dotenv
load_dotenv()

rpc_url = "https://polygon-rpc.com"
priv_key = ""  # Polygon account private key (needs some MATIC)
pub_key = ""  # Polygon account public key corresponding to private key
chain_id = 137

erc20_approve_abi = '[{"constant": false,"inputs": [{"name": "_spender","type": "address" },{ "name": "_value", "type": "uint256" }],"name": "approve","outputs": [{ "name": "", "type": "bool" }],"payable": false,"stateMutability": "nonpayable","type": "function"}]'
erc1155_set_approval_abi = '[{"inputs": [{ "internalType": "address", "name": "operator", "type": "address" },{ "internalType": "bool", "name": "approved", "type": "bool" }],"name": "setApprovalForAll","outputs": [],"stateMutability": "nonpayable","type": "function"}]'

usdc_address = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174"  # USDC.e on Polygon
ctf_address = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"   # Conditional Tokens

web3 = Web3(Web3.HTTPProvider(rpc_url))
web3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)

# Get initial nonce
nonce = web3.eth.get_transaction_count(pub_key)

usdc = web3.eth.contract(address=usdc_address, abi=erc20_approve_abi)
ctf = web3.eth.contract(address=ctf_address, abi=erc1155_set_approval_abi)

# Helper to send and wait for tx
def send_and_wait(raw_tx):
    signed_tx = web3.eth.account.sign_transaction(raw_tx, private_key=priv_key)
    tx_hash = web3.eth.send_raw_transaction(signed_tx.raw_transaction)  # Fixed: raw_transaction
    receipt = web3.eth.wait_for_transaction_receipt(tx_hash, timeout=600)
    print(f"Success: {receipt.transactionHash.hex()} (status: {receipt.status})")
    return receipt

# === CTF Exchange ===
# USDC approve
raw_tx = usdc.functions.approve(
    "0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", int(MAX_INT, 0)
).build_transaction({
    "chainId": chain_id,
    "from": pub_key,
    "nonce": nonce,
    "gasPrice": web3.eth.gas_price  # Auto gas price
})
send_and_wait(raw_tx)
nonce += 1

# CTF setApprovalForAll
raw_tx = ctf.functions.setApprovalForAll("0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E", True).build_transaction({
    "chainId": chain_id,
    "from": pub_key,
    "nonce": nonce,
    "gasPrice": web3.eth.gas_price
})
send_and_wait(raw_tx)
nonce += 1

# === Neg Risk CTF Exchange ===
# USDC approve
raw_tx = usdc.functions.approve(
    "0xC5d563A36AE78145C45a50134d48A1215220f80a", int(MAX_INT, 0)
).build_transaction({
    "chainId": chain_id,
    "from": pub_key,
    "nonce": nonce,
    "gasPrice": web3.eth.gas_price
})
send_and_wait(raw_tx)
nonce += 1

# CTF setApprovalForAll
raw_tx = ctf.functions.setApprovalForAll("0xC5d563A36AE78145C45a50134d48A1215220f80a", True).build_transaction({
    "chainId": chain_id,
    "from": pub_key,
    "nonce": nonce,
    "gasPrice": web3.eth.gas_price
})
send_and_wait(raw_tx)
nonce += 1

# === Neg Risk Adapter ===
# USDC approve
raw_tx = usdc.functions.approve(
    "0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", int(MAX_INT, 0)
).build_transaction({
    "chainId": chain_id,
    "from": pub_key,
    "nonce": nonce,
    "gasPrice": web3.eth.gas_price
})
send_and_wait(raw_tx)
nonce += 1

# CTF setApprovalForAll
raw_tx = ctf.functions.setApprovalForAll("0xd91E80cF2E7be2e162c6513ceD06f1dD0dA35296", True).build_transaction({
    "chainId": chain_id,
    "from": pub_key,
    "nonce": nonce,
    "gasPrice": web3.eth.gas_price
})
send_and_wait(raw_tx)

print("All 6 approvals completed! Your wallet is now permanently set up for Polymarket trading.")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment