IPcl.globalPeriodicVolume

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

요청한 (asset, resetPeriodSeconds) 쌍에 해당하는 모든 전역 주기 거래량 카운터를 user에 대해 반환합니다. 전역 PERIODIC_VOLUME_POLICY 중 해당 (자산, 주기) 튜플과 일치하는 정책이 없으면 빈 배열을 반환합니다. 그렇지 않으면 등록된 각 한도마다 하나씩 PeriodicVolume 항목을 담습니다. 동일한 주기에 서로 다른 maxAmount 값이 여러 개 등록될 수 있으며, 호출자가 그중 가장 엄격한 한도를 선택할 수 있도록 모두 반환합니다. resolveAgentOwnerstrue로 설정하면 조회 주소가 소유한 모든 에이전트의 거래량을 합산합니다.

파라미터

이름 타입 필수 설명
user address 누적 거래량을 조회할 계정 주소입니다.
asset string PeriodicVolumePolicy.tokens 배열에 선언된 자산 식별자입니다(보통 base denom, 예: "aokrw"). 서버에서 정규화됩니다.
resetPeriodSeconds uint64 조회할 카운터를 식별하는 초 단위 주기 길이입니다(예: 24시간 윈도는 86400). 등록된 주기가 이 값과 정확히 일치하는 항목만 반환됩니다.
resolveAgentOwners bool true이면 소유자가 user인 모든 에이전트의 거래량을 합산합니다. false이면 user 자신의 카운터만 조회합니다.

반환값

타입: PeriodicVolume[]

PeriodicVolume { uint256 amount; uint256 maxAmount; uint64 resetPeriodSeconds; uint64 resetAt; } 배열입니다. (자산, 주기) 튜플과 일치하는 등록 한도마다 하나씩 항목이 담깁니다. 빈 배열은 해당 튜플에 등록된 정책이 없다는 뜻입니다.

예제

사용자에게 적용되는 모든 전역 일일 OKRW 한도 조회

동일한 (자산, 주기) 튜플에 여러 한도가 공존할 수 있으므로, 단일 레코드를 가정하지 말고 반환 배열을 순회하여 결합해야 합니다. 보통은 남은 여유(remaining headroom)의 최솟값을 취합니다.

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`);
}

Solidity에서 동일한 카운터 조회

Solidity view가 메모리 배열을 반환하므로, 컨트랙트가 추가 RPC 호출 없이 순회하며 가장 엄격한 한도를 선택할 수 있습니다.

// 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
검색어를 입력하세요