"""One-off: move pUSD from weather Safe -> Rick's Privy Safe (copy-trading live test).
Reuses the proven Safe execTransaction path. Funds recoverable by the Safe owner."""
import time
from config import PRIVATE_KEY, SIGNATURE_TYPE
from polymarket_apis import PolymarketWeb3Client
from polymarket_apis.clients.web3_client import (
get_packed_signature, sign_safe_transaction, ADDRESS_ZERO,
)
PUSD = '0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB'
DEST = '0x7570210eACa5F3783577997fF74e8FEbe9B9E1f4' # Rick's Privy Safe (maker)
AMOUNT_USD = 2.0
amount_int = int(AMOUNT_USD * 1e6)
wc = PolymarketWeb3Client(private_key=PRIVATE_KEY, signature_type=SIGNATURE_TYPE)
w3, safe, eoa = wc.w3, wc.address, wc.account
pusd = w3.to_checksum_address(PUSD)
dest = w3.to_checksum_address(DEST)
erc20 = w3.eth.contract(address=pusd, abi=[
{"name":"balanceOf","type":"function","stateMutability":"view","inputs":[{"name":"a","type":"address"}],"outputs":[{"type":"uint256"}]},
])
print(f"before: weatherSafe {erc20.functions.balanceOf(safe).call()/1e6:.4f} | dest {erc20.functions.balanceOf(dest).call()/1e6:.4f} pUSD")
selector = w3.keccak(text='transfer(address,uint256)')[:4].hex()
data = '0x' + selector + dest[2:].lower().zfill(64) + hex(amount_int)[2:].zfill(64)
safe_txn = {'to': pusd, 'data': data, 'operation': 0, 'value': 0}
for attempt in range(1, 4):
try:
safe_nonce = wc.safe.functions.nonce().call()
packed_sig = get_packed_signature(sign_safe_transaction(eoa, wc.safe, safe_txn, safe_nonce))
nonce = w3.eth.get_transaction_count(eoa.address, 'pending')
txn = wc.safe.functions.execTransaction(
safe_txn['to'], safe_txn['value'], safe_txn['data'], 0, 0, 0, 0, ADDRESS_ZERO, ADDRESS_ZERO, packed_sig,
).build_transaction({'from': eoa.address, 'nonce': nonce, 'gas': 300000, 'gasPrice': w3.eth.gas_price, 'chainId': 137})
signed = eoa.sign_transaction(txn)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print('tx:', tx_hash.hex())
rc = w3.eth.wait_for_transaction_receipt(tx_hash, timeout=120)
print('status:', rc['status'])
break
except Exception as e:
if 'nonce too low' in str(e).lower() and attempt < 3:
time.sleep(2); continue
raise
print(f"after: weatherSafe {erc20.functions.balanceOf(safe).call()/1e6:.4f} | dest {erc20.functions.balanceOf(dest).call()/1e6:.4f} pUSD")