Skip to main content

Crate polyrel

Crate polyrel 

Source
Expand description

Unofficial Polymarket relayer client for gasless transactions.

This crate provides a typed Rust client for the Polymarket relayer API, enabling gasless on-chain operations through Safe and Proxy wallets.

§Client construction

The client uses a typestate pattern: start unauthenticated, then attach credentials to unlock submission methods.

use polyrel::{RelayerClient, Auth, BuilderCredentials};
use secrecy::SecretString;

let client = RelayerClient::builder()
    .build()
    .expect("default config is valid");

let auth = Auth::Builder(BuilderCredentials {
    api_key: SecretString::from("key"),
    secret: SecretString::from("c2VjcmV0"),
    passphrase: SecretString::from("pass"),
});
let client = client.authenticate(auth);

Override defaults for testnets or custom deployments. When pointing at a non-Polygon deployment, override all contract addresses and init-code hashes that differ — base_url and chain_id alone are not sufficient:

use alloy_primitives::{address, B256};
use polyrel::RelayerClient;

let client = RelayerClient::builder()
    .base_url("https://relayer-testnet.example.com".into())
    .chain_id(80002_u64)
    .safe_factory(address!("aacFeEa03eb1561C4e67d661e40682Bd20E3541b"))
    .safe_multisend(address!("A238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761"))
    .safe_init_code_hash(B256::from(polyrel::SAFE_INIT_CODE_HASH))
    .build()
    .expect("valid config");

§Wallet address derivation

Derive deterministic Safe or Proxy wallet addresses from an owner and factory using CREATE2:

use alloy_primitives::{address, Address, B256};
use polyrel::{derive_safe_address, derive_proxy_address};

let owner = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045");
let safe_factory = address!("aacFeEa03eb1561C4e67d661e40682Bd20E3541b");
let proxy_factory = address!("aB45c5A4B0c941a2F231C04C3f49182e1A254052");
let safe_hash = B256::from(polyrel::SAFE_INIT_CODE_HASH);
let proxy_hash = B256::from(polyrel::PROXY_INIT_CODE_HASH);

let safe_addr = derive_safe_address(owner, safe_factory, safe_hash);
let proxy_addr = derive_proxy_address(owner, proxy_factory, proxy_hash);

assert_ne!(safe_addr, Address::ZERO);
assert_ne!(proxy_addr, Address::ZERO);

§Configuration

Config holds all contract addresses, init-code hashes, and the relayer base URL. It defaults to Polygon mainnet values and can be inspected after construction:

use polyrel::Config;

let config = Config::builder().build().unwrap();
assert_eq!(config.chain_id(), 137);
assert_eq!(config.base_url().scheme(), "https");

§Batch approvals with MultiSend

Combine multiple approvals into a single relayer transaction using the public calldata builders and aggregate_transactions:

use alloy_primitives::U256;
use polyrel::{Config, NonEmptyTransactions, OperationType, SafeTransaction};

let config = Config::builder().build().unwrap();

let (to1, data1) = polyrel::usdc_approve_exchange(&config, U256::MAX);
let (to2, data2) = polyrel::ctf_approve_exchange(&config);

let tx1 = SafeTransaction {
    to: to1,
    value: U256::ZERO,
    data: data1.to_vec(),
    operation: OperationType::Call,
};
let tx2 = SafeTransaction {
    to: to2,
    value: U256::ZERO,
    data: data2.to_vec(),
    operation: OperationType::Call,
};

let batch = NonEmptyTransactions::new(vec![tx1, tx2]).unwrap();
let combined = polyrel::aggregate_transactions(batch, config.safe_multisend());

assert_eq!(combined.operation, OperationType::DelegateCall);
assert_eq!(combined.to, config.safe_multisend());

Then submit with client.sign_and_submit_safe(&signer, combined, nonce).await.

§Safe signature packing

Raw ECDSA signatures must be packed into Safe’s expected format before submission. The v-value is adjusted: 0/1 → +31, 27/28 → +4.

use polyrel::pack_safe_signature;

// 64 bytes of r+s, then v=27
let mut sig = vec![0xaa; 64];
sig.push(27);
let hex = alloy_primitives::hex::encode(&sig);

let packed = pack_safe_signature(&hex).unwrap();
let bytes = alloy_primitives::hex::decode(packed.strip_prefix("0x").unwrap()).unwrap();
assert_eq!(bytes[64], 31); // 27 + 4

§Submitting transactions

Authenticated clients can sign and submit Safe transactions. The Safe address is derived automatically from the signer and factory:

use polyrel::{RelayerClient, Auth, BuilderCredentials};
use secrecy::SecretString;
use alloy_primitives::U256;
use alloy_signer::Signer;

async fn run(signer: &(impl Signer + Sync)) -> Result<(), polyrel::PolyrelError> {
    let client = RelayerClient::builder().build()?
        .authenticate(Auth::Builder(BuilderCredentials {
            api_key: SecretString::from("key"),
            secret: SecretString::from("c2VjcmV0"),
            passphrase: SecretString::from("pass"),
        }));

    // fetch the current nonce for this signer's Safe wallet
    let nonce_str = client.safe_nonce(signer.address()).await?;
    let nonce = nonce_str.parse::<U256>().expect("valid nonce");

    // approve USDC for the CTF Exchange
    let resp = client
        .approve_usdc_for_exchange(signer, U256::MAX, nonce)
        .await?;

    // poll until confirmed
    let txn = client
        .poll_until_state(
            &resp.transaction_id,
            &["STATE_MINED", "STATE_CONFIRMED"],
            Some("STATE_FAILED"),
            None,
            None,
        )
        .await?;
    Ok(())
}

Structs§

Authenticated
Marker: client has credentials attached.
BuilderCredentials
Builder API key credentials (HMAC-SHA256).
Config
Configuration for contract addresses and relayer defaults.
DeployedResponse
Response from GET /deployed.
NonEmptyProxyCalls
A non-empty collection of proxy calls.
NonEmptyTransactions
A non-empty collection of Safe transactions.
ProxyTransactionArgs
Parameters for a Proxy wallet relay transaction.
RelayerApiKey
Simple relayer API key.
RelayerClient
HTTP client for the Polymarket relayer.
RelayerInfo
Response from GET /relay-payload.
RelayerTransaction
Full transaction record from GET /transaction.
SafeTransaction
A single Safe transaction within a MultiSend batch.
SignatureParams
Parameters for the relayer transaction signature.
SubmitRequest
Request body for POST /submit.
SubmitResponse
Response from POST /submit.
Unauthenticated
Marker: client has no credentials attached.

Enums§

Auth
Authentication strategy for the relayer.
OperationType
Safe transaction operation type.
PolyrelError
Errors produced by this crate.
TransactionState
Transaction lifecycle state.
WalletType
Wallet type for relayer transactions.

Constants§

PROXY_INIT_CODE_HASH
Proxy init code hash for CREATE2 derivation (Polygon mainnet default).
SAFE_FACTORY
Gnosis Safe Factory (Polygon mainnet default).
SAFE_FACTORY_NAME
Safe factory EIP-712 domain name for CreateProxy typed data.
SAFE_INIT_CODE_HASH
Safe init code hash for CREATE2 derivation (Polygon mainnet default).

Functions§

aggregate_transactions
Aggregate a batch of Safe transactions into one.
ctf_approve_exchange
Approve the CTF Exchange as operator for Conditional Tokens.
ctf_approve_neg_risk_adapter
Approve the Neg-Risk Adapter as operator for Conditional Tokens.
ctf_approve_neg_risk_exchange
Approve the Neg-Risk CTF Exchange as operator for Conditional Tokens.
ctf_merge_positions
Merge conditional outcome tokens back into collateral.
ctf_redeem_positions
Redeem resolved outcome tokens for collateral.
ctf_split_position
Split a collateral position into conditional outcome tokens.
ctf_transfer
Transfer a conditional token position (ERC-1155).
derive_proxy_address
Derive the deterministic Proxy wallet address for an owner.
derive_safe_address
Derive the deterministic Safe wallet address for an owner.
encode_proxy_calls
Encode transactions for the Proxy Wallet Factory proxy(calls) function.
neg_risk_redeem_positions
Redeem positions via the Neg-Risk Adapter.
pack_safe_signature
Pack a signature into Safe’s expected format.
safe_tx_hash
Compute the EIP-712 Safe transaction hash.
sign_proxy_transaction
Sign a Proxy wallet transaction and return a ready-to-submit SubmitRequest.
usdc_approve_conditional_tokens
Approve the Conditional Tokens contract to spend USDC.e (for split/merge).
usdc_approve_exchange
Approve the CTF Exchange to spend USDC.e.
usdc_approve_neg_risk_adapter
Approve the Neg-Risk Adapter to spend USDC.e (for neg-risk operations).
usdc_approve_neg_risk_exchange
Approve the Neg-Risk CTF Exchange to spend USDC.e.
usdc_transfer
Transfer USDC.e to a recipient.

Type Aliases§

Call
Target contract and encoded calldata pair.