Security
PredMart is designed with a defense-in-depth security model. This page provides a comprehensive overview of the protocol's security architecture, covering the independent third-party audit, smart contract security, access control, the timelock governance system, oracle integrity, emergency mechanisms, and the upgrade process. Understanding these security measures is essential for users who want to evaluate the trust assumptions of the protocol.
Security Audit
PredMart's smart contracts have been independently audited by Hashlock, an established Web3 security firm. The full report — covering the audit scope, the findings, and how each was resolved — is publicly available:
→ Read the Hashlock audit report
We encourage you to read the report itself rather than relying on the auditor's name alone. It's also available as a direct PDF.
Non-Custodial Design
PredMart's most fundamental security property is its non-custodial architecture. At no point does the PredMart team, company, or any individual have direct access to user funds:
- Lender deposits (USDC) are held by the smart contract on-chain, not in any company wallet.
- Borrower collateral (Polymarket CTF shares) is held by the smart contract, not by PredMart.
- Borrowed USDC is transferred directly from the contract to the borrower's wallet.
- Repayments flow directly from the borrower's wallet to the contract.
All fund movements are governed by the smart contract's immutable logic. The only entity that can move funds is the contract itself, and it only does so according to its programmed rules.
What This Means for Users
- PredMart cannot seize or redirect your funds (beyond what the contract logic allows)
- Even if PredMart (the company) ceased to exist, the smart contract would continue to function
- You can verify all contract logic by reading the source code on-chain or on the verified contract explorer
Smart Contract Architecture
Proxy Pattern (UUPS)
PredMart's lending pool uses the UUPS (Universal Upgradeable Proxy Standard) proxy pattern. This means the contract logic can be upgraded to fix bugs or add features, while the state (balances, positions, parameters) is preserved.
The proxy architecture has two components: - Proxy contract: Holds all state (storage) and delegates calls to the implementation - Implementation contract: Contains the actual logic
When an upgrade occurs, only the implementation address changes — the proxy address and all stored data remain the same.
Upgrade Process
Contract upgrades are protected by a timelocked proposal system:
- Proposal: The admin calls
proposeUpgrade(newImplementation)— this logs the new implementation address and starts the timelock countdown - Waiting period: The timelock delay must pass (the exact duration is set by the admin via
activateTimelock()) - Execution: After the delay, the admin calls
upgradeToAndCall()on the UUPS proxy to switch to the new implementation - Cancellation: At any time before execution, the admin can call
cancelUpgrade()to abort
The timelocked upgrade ensures that users have advance notice before any contract logic changes take effect. If a proposed upgrade is concerning, users can withdraw their funds during the waiting period.
Timelock Ratchet
The timelock mechanism has an important safety feature: the timelock can only be increased, never decreased. The activateTimelock(delay) function requires that the new delay is at least as long as the current delay. This prevents an admin from reducing the timelock to near-zero and pushing through a surprise upgrade.
Active Timelock
The timelock is active. All timelocked operations (oracle changes, LTV parameter updates, contract upgrades) require a mandatory waiting period before they can be executed. Users can monitor for *Proposed events and withdraw their funds during this window if they disagree. The current delay is published in Protocol Constants.
Access Control
Admin Role
The admin is a single Ethereum address that has authority over protocol parameters. The admin can:
Without timelock (immediate):
- setPaused(bool) — Pause or unpause the protocol (emergency use)
- withdrawReserves(amount) — Withdraw protocol fee revenue
- setPoolCapBps(newCap) — Adjust the per-token borrow cap
- transferAdmin(newAdmin) — Transfer admin rights to another address
With timelock (delayed):
- proposeOracle(newOracle) → executeOracle() — Change the oracle signing address
- proposeAnchors(prices, ltvs) → executeAnchors() — Change the LTV parameters
- proposeUpgrade(newImpl) → upgrade — Change the contract implementation
What the Admin Cannot Do
Even with admin access, the following actions are impossible: - Transfer user funds directly (USDC or collateral) - Modify individual user positions or balances - Override the interest rate model calculations - Bypass health factor checks for liquidation - Force a borrow or withdrawal on behalf of a user - Access private keys or user signatures
Relayer Role
The relayer is a separate address authorized to execute borrow, withdrawal, and leverage operations: - Submit borrow transactions (with oracle-signed price data and user signatures) - Submit withdrawal transactions (with oracle-signed price data and user signatures) - Submit leverage transactions (with oracle-signed price data and user signatures)
The relayer cannot:
- Borrow on behalf of a user without their signature
- Withdraw collateral without the user's signature
- Execute leverage without the user's signature
- Redirect borrowed USDC to any address other than the user's signed allowedFrom address
- Access or transfer funds not involved in a legitimate operation
- Modify protocol parameters
Liquidator Role
The liquidator is a dedicated address authorized specifically for liquidation operations: - Execute liquidations (with oracle-signed price data) - Seize and sell collateral from unhealthy positions
The liquidator is separate from the relayer to ensure liquidations can operate independently and remain functional even if other backend services experience issues. The liquidator cannot perform borrow, withdrawal, or leverage operations.
Meta-Transaction Security
All borrow, withdraw, and leverage operations use EIP-712 typed structured data for signing. This provides several security benefits: - Human-readable signing prompts in wallets - Domain separation prevents cross-protocol replay - Typed data prevents signature malleability attacks
Nonce Separation
PredMart uses separate nonces for each operation type (borrow, withdraw, leverage). This prevents cross-operation replay attacks — a signed borrow intent cannot be replayed as a withdraw or leverage operation, even if nonce values coincidentally match.
allowedFrom Protection (Leverage)
For leverage operations, the user signs a LeverageAuth message that includes an allowedFrom field — the address (typically their Gnosis Safe) where borrowed USDC must be sent. The smart contract enforces this constraint, preventing the relayer from redirecting funds to any other address. This is a critical non-custodial safeguard.
Admin Transfer
The admin address can be transferred via transferAdmin(newAdmin). This is an immediate operation (no timelock) because the timelock is already protecting the sensitive operations that the admin can perform. If the admin key is compromised, the ability to quickly transfer to a new address is a security benefit.
Oracle Security
The Oracle's Role
PredMart's oracle is a backend service that signs price and resolution data. The smart contract only accepts data signed by the oracle's authorized address. This prevents users from submitting fabricated price data.
Price Data Security
Every borrow, withdrawal, and liquidation includes oracle-signed price data containing:
- chainId — Prevents cross-chain replay
- pool — The lending pool address (prevents use with other contracts)
- tokenId — The specific token being priced
- price — The oracle price
- timestamp — When the price was fetched
- maxBorrow — The per-market borrow cap
The smart contract verifies: - The signature is from the authorized oracle address - The timestamp is recent (freshness enforced on-chain) - The price is between 0 and 1 (exclusive)
Resolution Data Security
Market resolution data contains:
- chainId, pool, tokenId — Same scoping as price data
- won — Whether the token is the winning outcome
- timestamp — When the resolution was determined
The contract verifies: - Valid oracle signature - Timestamp is sufficiently recent
Oracle Key Rotation
If the oracle key needs to be changed (e.g., suspected compromise), the admin can propose a new oracle address through the timelocked proposeOracle() → executeOracle() flow. This ensures users have notice before the oracle changes.
Trust Assumption
The oracle is a centralized trust point in PredMart's architecture. Users must trust that: - The oracle reports accurate prices from Polymarket's CLOB - The oracle does not selectively delay or withhold price updates - The oracle's private key is properly secured
PredMart mitigates this trust assumption through: - Freshness checks (prices must be recent to be accepted) - Price sanity checks (must be within valid range) - Transparent oracle operations (all signed data is visible on-chain) - Timelocked oracle key rotation (users can react if the oracle changes)
Emergency Mechanisms
Protocol Pause
The admin can pause the protocol at any time via setPaused(true). When paused:
- Blocked: New collateral deposits, new borrows, new lending deposits
- Allowed: Repayments and collateral withdrawals (with health check)
- Allowed: Liquidations (explicitly permitted during pause to protect lenders)
Liquidations are designed to work even when the protocol is paused. This ensures unhealthy positions can always be closed to protect lenders, regardless of protocol state.
The pause is designed to protect the protocol during: - Discovery of a smart contract vulnerability - External events that could compromise price oracle integrity - Other emergency situations
The admin can unpause via setPaused(false) when the situation is resolved.
Auto-Monitoring
PredMart's infrastructure is monitored continuously and can trigger the emergency pause if conditions threaten lending safety. Manual admin pauses are always respected. Liquidations remain available even while paused (see above).
Key Security Properties Summary
| Property | Implementation | Trust Assumption |
|---|---|---|
| Independent audit | Hashlock smart-contract audit (report) | Auditor's review is thorough |
| Funds custody | Smart contract | Code is correct |
| Price integrity | Oracle signatures + freshness checks | Oracle reports accurate prices |
| User authorization | EIP-712 signatures with nonce separation | User controls their private key |
| Leverage safety | allowedFrom constraint in LeverageAuth | Relayer cannot redirect USDC |
| Upgrade safety | UUPS + timelock + one-way ratchet | Admin doesn't act maliciously during timelock |
| Liquidation speed | Continuous monitoring with redundant paths | Backend infrastructure is operational |
| Concentration limits | Pool cap (5%) + per-market liquidity cap | Limits are appropriately calibrated |
| Emergency response | Pause | Admin can respond to emergencies |
| Parameter changes | Timelock governance | Users can exit during waiting period |
Recommendations for Users
- Verify the contract address: always interact with
0xD90D012990F0245cAD29823bDF0B4C9AF207d9ee. - Watch for timelocked proposals (
OracleChangeProposed,AnchorsChangeProposed,UpgradeProposed) so you can exit during the waiting period if you disagree. - Understand the trust assumptions — PredMart is non-custodial, but oracle, relayer, and admin are centralized components.
- Keep a buffer above liquidation — don't borrow the maximum.
- Diversify — don't concentrate all lending or borrowing in a single market.
Next Steps
- Protocol Constants — All on-chain parameters
- Smart Contract — Contract addresses and developer reference
- Risk Parameters — How risk is managed in the protocol
- FAQ — Common questions about security