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 값이 여러 개 등록될 수 있으며, 호출자가 그중 가장 엄격한 한도를 선택할 수 있도록 모두 반환합니다. resolveAgentOwners를 true로 설정하면 대신 에이전트 지갑 소유자들의 카운터를 읽어 그중 가장 큰 값을 반환합니다.

파라미터

이름 타입 필수 설명
user address ✓ 누적 거래량을 조회할 계정 주소입니다.
asset string ✓ PeriodicVolumePolicy.tokens 배열에 선언된 자산 식별자입니다(보통 base denom, 예: "atokrw"). 서버에서 정규화됩니다.
resetPeriodSeconds uint64 ✓ 조회할 카운터를 식별하는 초 단위 주기 길이입니다(예: 24시간 윈도는 86400). 등록된 주기가 이 값과 정확히 일치하는 항목만 반환됩니다.
resolveAgentOwners bool ✓ true이면 user를 에이전트 지갑으로 보고 그 에이전트 소유자들의 카운터(소유자가 없으면 user 자신의 카운터)를 읽어 가장 큰 값을 반환합니다. 에이전트 지갑의 전송이 소유자들의 카운터에 기록되는 것은 상한을 에이전트 소유자를 순회하는 FOR_EACH_POLICY로 감쌌을 때뿐입니다. maroo-testnet-1의 전역 일일 한도가 이렇게 감싸여 있으므로, 테스트넷에서는 true가 상한에 가장 가까운 소유자의 값을 반환합니다. 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", "atokrw", 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.
  // `amount` can pass `maxAmount`: the testnet records volume for attested senders too, who are not held to the cap.
  const left = (s: (typeof statuses)[number]) => (s.amount >= s.maxAmount ? 0n : s.maxAmount - s.amount);
  const headroom = statuses.reduce<bigint>((min, s) => (left(s) < min ? left(s) : min), left(statuses[0]));
  console.log(`tightest remaining headroom: ${headroom} atokrw`);
}

Solidity에서 동일한 카운터 조회

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

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

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 (atokrw, 24h) counter.
    function remainingDailyHeadroom(address user) external view returns (uint256 tightest) {
        PeriodicVolume[] memory rows =
            pcl.globalPeriodicVolume(user, "atokrw", 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) {
            // amount can pass maxAmount (attested senders are recorded but not held to the cap)
            uint256 left = rows[i].amount >= rows[i].maxAmount ? 0 : rows[i].maxAmount - rows[i].amount;
            if (left < tightest) tightest = left;
        }
    }
}
ESC
검색어를 입력하세요