Skip to main content

V2 Contracts

TaskPoolFactory

Creates and manages per-tenant TaskPool + RewardPool pairs via the Beacon proxy pattern.

Functions

// Deploy a new pair of pools for a tenant
function createTenantPools(bytes32 tenantId, bytes calldata config)
    external onlyOwner returns (address taskPool, address rewardPool)

// Upgrade the TaskPool beacon implementation (affects all tenants)
function upgradeTaskPool(address newImplementation) external onlyOwner

// Upgrade the RewardPool beacon implementation (affects all tenants)
function upgradeRewardPool(address newImplementation) external onlyOwner

// Deactivate a tenant's pools
function deactivateTenant(bytes32 tenantId) external onlyOwner

// Deterministically compute a tenant's TaskPool address (CREATE2)
function computeTaskPoolAddress(bytes32 tenantId) external view returns (address)

// Deterministically compute a tenant's RewardPool address (CREATE2)
function computeRewardPoolAddress(bytes32 tenantId) external view returns (address)

// Get a tenant's pool addresses and status
function getTenantPools(bytes32 tenantId) external view returns (TenantPools memory)

// Total number of tenants with deployed pools
function getTotalTenants() external view returns (uint256)

// Get tenant ID at a specific index
function getTenantIdAt(uint256 index) external view returns (bytes32)

TenantPools Struct

struct TenantPools {
    address taskPool;       // Beacon proxy address for TaskPool
    address rewardPool;     // Beacon proxy address for RewardPool
    uint256 createdAt;      // Block timestamp of pool creation
    bool active;            // Whether the tenant is active
}

Events

event TenantPoolsCreated(bytes32 indexed tenantId, address taskPool, address rewardPool);
event BeaconUpgraded(string poolType, address newImplementation);
event TenantDeactivated(bytes32 indexed tenantId);

Custom Errors

error TenantAlreadyExists();  // Tenant ID already has deployed pools
error TenantNotFound();        // No pools found for the given tenant ID

TaskPoolImplementation

Per-tenant task escrow and lifecycle management.

Functions

// Initialize the pool (called once by factory via proxy)
function initialize(
    bytes32 _tenantId,
    address _usdc,
    address _verificationEngine,
    address _solverRegistry,
    address _intentRegistry,
    bytes calldata _config     // Reserved for future use
) external initializer

// Deposit USDC into the merchant's pool balance
function depositFunds(uint256 amount) external

// Withdraw USDC from the merchant's pool balance
function withdrawFunds(uint256 amount) external

// Create a new task with escrowed USDC
function createTask(
    address merchant,                    // Funding merchant address
    uint256 amount,                      // USDC amount (6 decimals)
    uint256 durationSeconds,             // Task deadline in seconds
    bytes32 campaignId,                  // Associated campaign (bytes32(0) if none)
    VerificationMethod verificationMethod, // Consensus, Oracle, or AIEval
    bytes calldata acceptanceCriteria    // Human/machine-readable completion criteria
) external returns (bytes32 taskId)

// Solver claims an open task
function claimTask(bytes32 taskId) external

// Solver submits proof of completion
function submitTask(bytes32 taskId, bytes32 submissionHash) external

// Settle a verified task (called by VerificationEngine only)
function settleTask(bytes32 taskId, address solver) external

// Cancel an open task, refund merchant
function cancelTask(bytes32 taskId) external

// Set the associated RewardPool
function setRewardPool(address _rewardPool) external

// Pause/unpause the pool
function setPaused(bool _paused) external

// View functions
function getTask(bytes32 taskId) external view returns (Task memory)
function getMerchantBalance(address merchant) external view returns (uint256)
function getTenantId() external view returns (bytes32)
function getTotalTasksCreated() external view returns (uint256)
function getTotalValueEscrowed() external view returns (uint256)
function isPaused() external view returns (bool)
function getRewardPool() external view returns (address)
function getVerificationEngine() external view returns (address)
function getSolverRegistry() external view returns (address)
function getUsdc() external view returns (address)

Task Struct

struct Task {
    bytes32 taskId;                      // Deterministic hash
    address merchant;                    // Funding merchant
    address token;                       // Payment token (USDC)
    uint256 amount;                      // Escrowed amount
    uint256 createdAt;                   // Block timestamp
    uint256 deadline;                    // Expiry timestamp
    bytes32 campaignId;                  // Associated campaign
    TaskStatus status;                   // Current lifecycle status
    VerificationMethod verificationMethod; // How completion is verified
    address claimedBy;                   // Solver who claimed (address(0) if unclaimed)
    bytes32 submissionHash;              // Hash of solver's submission
    bytes acceptanceCriteria;            // Completion requirements
}

Events

event TaskCreated(
    bytes32 indexed taskId,
    address indexed merchant,
    uint256 amount,
    uint256 deadline,
    bytes32 campaignId,
    VerificationMethod verificationMethod
);
event TaskClaimed(bytes32 indexed taskId, address indexed solver);
event TaskSubmitted(bytes32 indexed taskId, address indexed solver, bytes32 submissionHash);
event TaskSettled(bytes32 indexed taskId, address indexed solver, uint256 amount);
event TaskCancelled(bytes32 indexed taskId);
event FundsDeposited(address indexed merchant, uint256 amount);
event FundsWithdrawn(address indexed merchant, uint256 amount);

Custom Errors

error PoolPaused();                    // Pool is paused
error AmountMustBePositive();          // Zero or negative amount
error InvalidDuration();               // Duration outside allowed range
error InsufficientMerchantBalance();   // Merchant doesn't have enough deposited
error TaskNotOpen();                   // Task is not in Open status
error TaskExpired();                   // Task deadline has passed
error SolverNotEligible();             // Solver not registered or banned
error NotTaskSolver();                 // Caller is not the task's solver
error TaskNotClaimed();                // Task hasn't been claimed yet
error TaskNotPendingSettlement();      // Task not awaiting settlement
error SolverMismatch();                // Solver address doesn't match claim
error OnlyVerificationEngine();        // Only VerificationEngine can call
error CannotCancel();                  // Task can't be cancelled in current state
error OnlyMerchantOrOwner();           // Only merchant or owner can call

RewardPoolImplementation

Manages solver payout calculation, fee splitting, and reward claims.

Functions

// Initialize (called once by factory)
function initialize(
    bytes32 _tenantId,
    address _usdc,
    address _solverRegistry,
    address _intentRegistry
) external initializer

// Queue a payout after task settlement (called by TaskPool)
function queuePayout(bytes32 taskId, address solver, uint256 grossAmount) external

// Solver claims all pending rewards
function claimRewards() external

// Admin: set associated TaskPool
function setTaskPool(address _taskPool) external

// Admin: set protocol fee recipient
function setProtocolFeeRecipient(address recipient) external

// Admin: update fee basis points
function setFees(uint256 protocolFeeBps, uint256 solverFeeBps) external

// View functions
function getPendingPayout(address account) external view returns (uint256)
function getPayoutRecord(bytes32 taskId) external view returns (PayoutRecord memory)
function getTenantId() external view returns (bytes32)
function getTotalRewardsDistributed() external view returns (uint256)
function getProtocolFeeBps() external view returns (uint256)
function getSolverFeeBps() external view returns (uint256)
function getTaskPool() external view returns (address)
function getProtocolFeeRecipient() external view returns (address)

PayoutRecord Struct

struct PayoutRecord {
    bytes32 taskId;        // Associated task
    address solver;        // Recipient solver
    uint256 grossAmount;   // Total task amount
    uint256 solverFee;     // Fee retained by solver (from gross)
    uint256 protocolFee;   // Fee sent to protocol
    uint256 netPayout;     // Amount available to solver (gross - protocolFee)
    uint256 settledAt;     // Block timestamp of settlement
    bool claimed;          // Whether solver has claimed
}

Events

event RewardQueued(bytes32 indexed taskId, address indexed solver, uint256 netPayout);
event RewardClaimed(address indexed solver, uint256 amount);
event FeesUpdated(uint256 protocolFeeBps, uint256 solverFeeBps);

Custom Errors

error OnlyTaskPool();      // Only the linked TaskPool can call
error AlreadyQueued();     // Payout already queued for this task
error NothingToClaim();    // No pending rewards for caller
error FeesTooHigh();       // Combined fees exceed maximum

SolverRegistry

Global registry of solver profiles, reputation tracking, and eligibility checks.

Functions

// Initialize (called once via proxy)
function initialize(address _owner) external initializer

// Register as a solver
function register(bytes calldata metadata) external

// Check if a solver is eligible for a task
function isEligible(address solver, bytes32 taskId) external view returns (bool)

// Accrue rewards to solver's profile (called by authorized RewardPools)
function accrueReward(address solver, uint256 amount) external

// Record a task claim against solver's profile
function recordClaim(address solver) external

// Admin: ban a solver permanently
function banSolver(address solver) external

// Admin: deactivate a solver (reversible)
function deactivateSolver(address solver) external

// Admin: authorize a RewardPool to update solver stats
function authorizeRewardPool(address rewardPool) external

// Admin: revoke RewardPool authorization
function revokeRewardPool(address rewardPool) external

// View functions
function getProfile(address solver) external view returns (SolverProfile memory)
function isBanned(address solver) external view returns (bool)
function getTotalSolvers() external view returns (uint256)
function isAuthorizedRewardPool(address pool) external view returns (bool)

SolverProfile Struct

struct SolverProfile {
    address solver;                // Solver's address
    uint256 registeredAt;          // Registration timestamp
    uint256 totalTasksClaimed;     // Lifetime tasks claimed
    uint256 totalTasksCompleted;   // Lifetime tasks completed
    uint256 totalRewardsEarned;    // Lifetime USDC earned (6 decimals)
    uint256 reputationScore;       // Computed reputation (0-1000)
    bool active;                   // Whether solver is active
    bytes metadata;                // Encoded metadata (name, type, capabilities)
}

Events

event SolverRegistered(address indexed solver);
event SolverDeactivated(address indexed solver);
event SolverBanned(address indexed solver);
event ReputationUpdated(address indexed solver, uint256 newScore);
event RewardPoolAuthorized(address indexed rewardPool);
event RewardPoolRevoked(address indexed rewardPool);

Custom Errors

error AlreadyRegistered();       // Solver address already registered
error AddressBanned();           // Address is permanently banned
error SolverNotFound();          // No profile for this address
error NotAuthorizedRewardPool(); // Caller is not an authorized RewardPool

VerificationEngine

Routes verification requests to the appropriate handler (consensus, oracle, or AI) and records resolutions.

Functions

// Initialize (called once via proxy)
function initialize(address _owner, address _aiOracleAddress) external initializer

// Request verification for a submitted task (called by TaskPools)
function requestVerification(
    bytes32 taskId,
    address solver,
    bytes32 submissionHash,
    bytes calldata acceptanceCriteria,
    uint8 verificationMethodInt       // Cast to VerificationMethod enum
) external

// Resolve a pending verification (called by authorized oracles)
function resolveVerification(bytes32 taskId, bool approved) external

// Admin: add an authorized oracle
function addOracle(address oracle) external

// Admin: remove an oracle
function removeOracle(address oracle) external

// Admin: set the AI evaluation oracle
function setAiOracle(address oracle) external

// Admin: authorize a TaskPool to submit verification requests
function authorizeTaskPool(address taskPool) external

// Admin: revoke TaskPool authorization
function revokeTaskPool(address taskPool) external

// View functions
function getRequest(bytes32 taskId) external view returns (VerificationRequest memory)
function isAuthorizedOracle(address oracle) external view returns (bool)
function isAuthorizedTaskPool(address taskPool) external view returns (bool)
function getAiOracle() external view returns (address)

VerificationRequest Struct

struct VerificationRequest {
    bytes32 taskId;                      // Task being verified
    address taskPool;                    // Originating TaskPool
    address solver;                      // Solver who submitted
    bytes32 submissionHash;              // Hash of submission content
    bytes acceptanceCriteria;            // What the submission is evaluated against
    VerificationMethod method;           // Consensus, Oracle, or AIEval
    VerificationStatus status;           // Pending, Approved, or Rejected
    uint256 requestedAt;                 // Block timestamp of request
    uint256 resolvedAt;                  // Block timestamp of resolution (0 if pending)
}

Events

event VerificationRequested(
    bytes32 indexed taskId,
    VerificationMethod method,
    address indexed taskPool
);
event VerificationResolved(
    bytes32 indexed taskId,
    VerificationStatus status,
    address indexed resolver
);

Custom Errors

error AlreadyRequested();        // Verification already pending for this task
error NotAuthorizedOracle();     // Caller is not an authorized oracle
error NotPending();              // Verification is not in Pending status
error NotAuthorizedTaskPool();   // Caller is not an authorized TaskPool

IntentRegistryV2

Upgradeable intent ledger with access control. Used by TaskPools to record financial intents.

Functions

// Initialize (called once via proxy)
function initialize(address _owner) external initializer

// Register a new intent (called by authorized callersTaskPools via Factory)
function registerIntent(
    bytes32 intentId,
    address merchant,
    address recipient,
    uint256 amount
) external

// Mark an intent as fulfilled
function markFulfilled(bytes32 intentId, address solver) external

// Admin: authorize a caller (e.g., TaskPoolFactory)
function addAuthorizedCaller(address caller) external

// Admin: revoke caller authorization
function removeAuthorizedCaller(address caller) external

// View functions
function getIntent(bytes32 intentId) external view returns (IntentRecord memory)
function getMerchantIntents(address merchant) external view returns (bytes32[] memory)
function getSolverIntents(address solver) external view returns (bytes32[] memory)
function getTotalIntents() external view returns (uint256)
function isAuthorizedCaller(address caller) external view returns (bool)

IntentRecord Struct

struct IntentRecord {
    bytes32 intentId;      // Unique intent identifier
    address merchant;      // Funding merchant
    address recipient;     // Reward recipient
    uint256 amount;        // USDC amount
    uint256 createdAt;     // Registration timestamp
    uint256 fulfilledAt;   // Fulfillment timestamp (0 if pending)
    address solver;        // Fulfilling solver (address(0) if pending)
    bool fulfilled;        // Whether the intent has been fulfilled
}

Events

event IntentRegistered(bytes32 indexed intentId, address indexed merchant, uint256 amount);
event IntentFulfilled(bytes32 indexed intentId, address indexed solver);
event CallerAuthorized(address indexed caller);
event CallerRevoked(address indexed caller);

Custom Errors

error NotAuthorized();       // Caller is not authorized
error AlreadyRegistered();   // Intent ID already exists
error AlreadyFulfilled();    // Intent already fulfilled

V1 Contracts

IntentRegistry (V1)

function setOriginSettler(address _originSettler) external
function registerIntent(bytes32 intentId, address merchant, address recipient, uint256 amount) external
function markFulfilled(bytes32 intentId, address solver) external
function getIntent(bytes32 intentId) external view returns (IntentRecord memory)
function getMerchantIntents(address merchant) external view returns (bytes32[] memory)
function getRecipientIntents(address recipient) external view returns (bytes32[] memory)
function getSolverIntents(address solver) external view returns (bytes32[] memory)
function getTotalIntents() external view returns (uint256)
function getAllIntents(uint256 offset, uint256 limit) external view returns (bytes32[] memory)

PodiumOriginSettler (V1)

function depositFunds(address token, uint256 amount) external
function withdrawFunds(address token, uint256 amount) external
function createIntent(address merchant, address recipient, address token, uint256 amount, uint256 duration, bytes32 campaignId) external returns (bytes32)
function lockIntent(bytes32 intentId) external
function markFulfilled(bytes32 intentId, address solver, bytes32 fulfillmentTxHash) external
function cancelIntent(bytes32 intentId) external
function setDestinationSettler(address _destinationSettler) external
function setRegistry(address _registry) external
function getIntent(bytes32 intentId) external view returns (RewardIntent memory)
function getMerchantBalance(address merchant) external view returns (uint256)

PodiumDestinationSettler (V1)

function fulfillIntent(bytes32 intentId, address token, address recipient, uint256 amount) external returns (bytes32)
function verifyProof(bytes32 intentId) external
function claimRewards(address token) external
function setOriginSettler(address _originSettler) external
function getProof(bytes32 intentId) external view returns (FulfillmentProof memory)
function getSolverRewards(address solver) external view returns (uint256)
See V1: Intent Settlers for full V1 documentation including structs and events.

Enums

// Task lifecycle
enum TaskStatus {
    Open,                    // 0 — Awaiting solver
    Claimed,                 // 1 — Solver committed
    SubmittedForVerification, // 2 — Proof submitted, awaiting verification
    Verified,                // 3 — Verification passed
    Settled,                 // 4 — Payout queued
    Expired,                 // 5 — Deadline passed
    Cancelled                // 6 — Cancelled by merchant/admin
}

// How task completion is verified
enum VerificationMethod {
    Consensus,  // 0 — Multi-party agreement
    Oracle,     // 1 — Single authorized oracle
    AIEval      // 2 — AI evaluation engine
}

// Verification outcome
enum VerificationStatus {
    Pending,    // 0 — Awaiting resolution
    Approved,   // 1 — Task passed verification
    Rejected    // 2 — Task failed verification
}

// V1 intent lifecycle
enum IntentStatus {
    Pending,    // 0 — Created, awaiting solver
    Locked,     // 1 — Solver committed
    Fulfilled,  // 2 — Settlement complete
    Expired,    // 3 — Deadline passed
    Cancelled   // 4 — Cancelled by merchant
}

Proxy Patterns

ContractPatternRationale
SolverRegistryUUPS (ERC1967)Singleton — one per deployment
VerificationEngineUUPS (ERC1967)Singleton — one per deployment
IntentRegistryV2UUPS (ERC1967)Singleton — one per deployment
TaskPoolImplementationBeaconMulti-tenant — all pools share same implementation
RewardPoolImplementationBeaconMulti-tenant — all pools share same implementation
V1 ContractsNoneNon-upgradeable

Storage Namespacing

V2 contracts use EIP-7201 storage namespacing to prevent storage collisions during upgrades:
bytes32 private constant STORAGE_SLOT =
    keccak256(abi.encode(uint256(keccak256("podium.storage.TaskPool")) - 1)) & ~bytes32(uint256(0xff));