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.
- Builder
Credentials - Builder API key credentials (HMAC-SHA256).
- Config
- Configuration for contract addresses and relayer defaults.
- Deployed
Response - Response from
GET /deployed. - NonEmpty
Proxy Calls - A non-empty collection of proxy calls.
- NonEmpty
Transactions - A non-empty collection of Safe transactions.
- Proxy
Transaction Args - Parameters for a Proxy wallet relay transaction.
- Relayer
ApiKey - Simple relayer API key.
- Relayer
Client - HTTP client for the Polymarket relayer.
- Relayer
Info - Response from
GET /relay-payload. - Relayer
Transaction - Full transaction record from
GET /transaction. - Safe
Transaction - A single Safe transaction within a MultiSend batch.
- Signature
Params - Parameters for the relayer transaction signature.
- Submit
Request - Request body for
POST /submit. - Submit
Response - Response from
POST /submit. - Unauthenticated
- Marker: client has no credentials attached.
Enums§
- Auth
- Authentication strategy for the relayer.
- Operation
Type - Safe transaction operation type.
- Polyrel
Error - Errors produced by this crate.
- Transaction
State - Transaction lifecycle state.
- Wallet
Type - 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
CreateProxytyped 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.