IPcl.globalPeriodicVolume

globalPeriodicVolume(
  address user,
  string calldata asset,
  uint64 resetPeriodSeconds,
  bool resolveAgentOwners
) external view returns (PeriodicVolume[] memory statuses)

Returns every global periodic-volume counter that shares the requested (asset, resetPeriodSeconds) pair for user. The array is empty when no global PERIODIC_VOLUME_POLICY matches the (asset, reset-period) tuple; otherwise it contains one PeriodicVolume entry per registered limit — a single reset period can back several distinct maxAmount variants, and each is returned so callers can pick the tightest applicable cap. Set resolveAgentOwners to true to accumulate volume across every agent owned by the queried address.

Parameters

Name Type Required Description
user address The account whose accumulated volume should be read.
asset string Asset identifier as declared in the PeriodicVolumePolicy.tokens array (typically the base denom, e.g. "aokrw"). Normalized server-side.
resetPeriodSeconds uint64 The period length in seconds identifying which counter to read (for example 86400 for a 24-hour window). Only entries whose registered period equals this value are returned.
resolveAgentOwners bool When true, volume is aggregated across every agent whose owner is user; when false, only user's own accumulator is read.

Returns

Type: PeriodicVolume[]

Array of PeriodicVolume { uint256 amount; uint256 maxAmount; uint64 resetPeriodSeconds; uint64 resetAt; } — one entry per registered limit matching the (asset, reset-period) tuple. Empty array means no policy is currently registered for that tuple.

Examples

Read every global daily OKRW cap that applies to a user

Because multiple limits can share the same (asset, reset-period) tuple, clients must fold across the returned array — usually by taking the minimum remaining headroom — instead of assuming a single record.

import { createPublicClient, http } from "viem";

const PCL = "0x1000000000000000000000000000000000000005" as const;
const pclAbi = [{
  name: "globalPeriodicVolume", type: "function", stateMutability: "view",
  inputs: [
    { name: "user",                type: "address" },
    { name: "asset",               type: "string" },
    { name: "resetPeriodSeconds",  type: "uint64" },
    { name: "resolveAgentOwners",  type: "bool" },
  ],
  outputs: [{
    type: "tuple[]",
    components: [
      { name: "amount",             type: "uint256" },
      { name: "maxAmount",          type: "uint256" },
      { name: "resetPeriodSeconds", type: "uint64" },
      { name: "resetAt",            type: "uint64" },
    ],
  }],
}] as const;

const client = createPublicClient({ transport: http("https://rpc-testnet.maroo.io") });

// TODO: replace with the real end-user address before production.
const statuses = await client.readContract({
  address: PCL,
  abi: pclAbi,
  functionName: "globalPeriodicVolume",
  args: ["0x8f3aC2b1D9e74C05a6B18Fe27dC4913E5A0f7b62", "aokrw", 86_400n, false],
});

if (statuses.length === 0) {
  console.log("no periodic-volume policy is currently registered for this (asset, period)");
} else {
  // Pick the tightest applicable cap — remaining headroom is min(maxAmount - amount) across entries.
  const headroom = statuses.reduce<bigint>((min, s) => {
    const left = s.maxAmount - s.amount;
    return left < min ? left : min;
  }, statuses[0].maxAmount - statuses[0].amount);
  console.log(`tightest remaining headroom: ${headroom} aokrw`);
}

Reading the same counter from Solidity

The Solidity view returns an in-memory array, so contracts can iterate and pick the tightest cap without any additional RPC calls.

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.22;

import "@maroo-chain/contracts/precompiles/pcl/IPcl.sol";

contract HeadroomView {
    IPcl constant pcl = IPcl(0x1000000000000000000000000000000000000005);

    /// @return tightest Minimum remaining headroom across every registered
    ///         global periodic-volume limit for the (aokrw, 24h) counter.
    function remainingDailyHeadroom(address user) external view returns (uint256 tightest) {
        PeriodicVolume[] memory rows =
            pcl.globalPeriodicVolume(user, "aokrw", 86_400, false);
        if (rows.length == 0) {
            return type(uint256).max; // no policy → unbounded
        }
        tightest = type(uint256).max;
        for (uint256 i = 0; i < rows.length; ++i) {
            uint256 left = rows[i].maxAmount - rows[i].amount;
            if (left < tightest) tightest = left;
        }
    }
}
ESC
Type to search