rs-builder-relayer-client 0.1.2

A Rust SDK for Polymarket's Builder Relayer — gasless on-chain operations
Documentation

rs-builder-relayer-client

Rust SDK for Polymarket's gasless relayer. Redeem positions, approve tokens, split/merge — zero gas.

30-Second Quickstart

cargo new my-redeemer && cd my-redeemer
cargo add rs-builder-relayer-client ethers tokio --features tokio/full
cargo add anyhow dotenvy hex

Create .env:

PRIVATE_KEY=0x...
BUILDER_KEY=...
BUILDER_SECRET=...
BUILDER_PASSPHRASE=...
# Optional: Use Alchemy or QuickNode for Direct Fallback. Default polygon-rpc.com is unstable.
POLYGON_RPC_URL=https://...

src/main.rs:

use polymarket_relayer::{RelayClient, AuthMethod, RelayerTxType};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    let wallet = std::env::var("PRIVATE_KEY")?.parse()?;
    let mut client = RelayClient::new(
        137, wallet,
        AuthMethod::builder(
            &std::env::var("BUILDER_KEY")?,
            &std::env::var("BUILDER_SECRET")?,
            &std::env::var("BUILDER_PASSPHRASE")?,
        ),
        RelayerTxType::Safe,
    ).await?;

    // Read nonce from on-chain (avoids stale relayer API nonce → GS026)
    if let Ok(rpc) = std::env::var("POLYGON_RPC_URL") {
        client.set_rpc_url(rpc);
    }

    client.setup_approvals().await?.wait().await?;
    println!("Done. You can now trade gaslessly.");
    Ok(())
}
cargo run

Getting Your Credentials

Credential Where
PRIVATE_KEY Your Polygon wallet private key (MetaMask > Account Details > Export)
Relayer API key polymarket.com/settings > Relayer API Keys (anyone)

No Builder keys? Use AuthMethod::relayer_key("key", "address") instead — same features, simpler setup.


Install

[dependencies]
rs-builder-relayer-client = "0.1"
ethers = "2"
tokio = { version = "1", features = ["full"] }
anyhow = "1"
dotenvy = "0.15"
hex = "0.4"

Redeem Example

Add CONDITION_ID=0x... to your .env, then:

use polymarket_relayer::{AuthMethod, RelayClient, RelayerTxType, operations};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();

    let wallet = std::env::var("PRIVATE_KEY")?.parse()?;
    let client = RelayClient::new(
        137,
        wallet,
        AuthMethod::builder(
            &std::env::var("BUILDER_KEY")?,
            &std::env::var("BUILDER_SECRET")?,
            &std::env::var("BUILDER_PASSPHRASE")?,
        ),
        RelayerTxType::Safe,
    ).await?;

    let condition_id_hex = std::env::var("CONDITION_ID")?;
    let condition_id_bytes = hex::decode(condition_id_hex.trim_start_matches("0x"))?;
    let mut cid = [0u8; 32];
    cid.copy_from_slice(&condition_id_bytes);

    let tx = operations::redeem_regular(cid, &[1, 2]);
    let result = client.execute(vec![tx], "Redeem").await?.wait().await?;
    println!("Transaction Hash: {:?}", result.tx_hash);

    Ok(())
}

API

Operation Code
Redeem regular position operations::redeem_regular(condition_id, &[1, 2])
Redeem neg-risk position operations::redeem_neg_risk_positions(condition_id, &[1, 2])
Approve USDC for exchange client.setup_approvals()
Deploy Safe wallet client.deploy()
Split USDC into tokens operations::split_regular(cid, &[1, 2], amount)
Merge tokens back to USDC operations::merge_regular(cid, &[1, 2], amount)
Batch multiple ops client.execute(vec![tx1, tx2], "desc")
Direct on-chain fallback DirectExecutor::new(rpc_url, wallet, 137)?

Auth

// Builder API keys (HMAC — enables gasless)
AuthMethod::builder("key", "secret", "passphrase")

// Relayer API keys (from polymarket.com/settings > API Keys)
AuthMethod::relayer_key("api_key", "wallet_address")

Direct Fallback (when relayer returns 429)

Warning: Do not use https://polygon-rpc.com/ as your RPC URL — it frequently causes TLS handshake EOF errors and connection resets, especially under load. Use a dedicated provider instead:

  • Alchemy (recommended): https://polygon-mainnet.g.alchemy.com/v2/YOUR_KEY
  • QuickNode: https://YOUR_ENDPOINT.quiknode.pro/YOUR_KEY/
  • LlamaRPC: https://polygon.llamarpc.com
use polymarket_relayer::{DirectExecutor, RelayerError};

let rpc_url = std::env::var("POLYGON_RPC_URL")
    .expect("Set POLYGON_RPC_URL to an Alchemy/QuickNode endpoint");

// Safe wallet (signature_type=2, default)
let direct = DirectExecutor::new(&rpc_url, wallet, 137)?;

// Proxy wallet (signature_type=1, e.g. magic.link)
let direct = DirectExecutor::new_proxy(&rpc_url, wallet, 137)?;

// Proxy with explicit address (when derived address differs)
let direct = DirectExecutor::new_proxy_with_address(&rpc_url, wallet, 137, proxy_addr)?;

match client.execute(vec![tx], "Redeem").await {
    Err(RelayerError::QuotaExhausted) => {
        let result = direct.execute(&tx).await?;  // pays gas in MATIC
    }
    other => { /* handle normally */ }
}

Examples

cp .env.example .env   # fill in your keys

cargo run --example redeem_all                  # dry-run: scan positions
cargo run --example redeem_all -- --execute     # actually redeem
cargo run --example setup_wallet                # deploy Safe + approvals
cargo run --example redeem_single               # redeem one position
cargo run --example split_merge                 # split/merge demo
cargo run --example redeem_magic                # magic.link proxy wallet redeem

References

Donate

Ethereum / Polygon: 0xF4c6635dFfB53f21c500c1604EC284f8A8a7150D