{"_id":"@atlas-oracle/pull-oracle-consumer","_rev":"2-5e8b4fb772a1f7a443368ebe2165c6c3","name":"@atlas-oracle/pull-oracle-consumer","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@atlas-oracle/pull-oracle-consumer","version":"1.0.0","license":"BUSL-1.1","_id":"@atlas-oracle/pull-oracle-consumer@1.0.0","maintainers":[{"name":"michael_wgy","email":"michael.wang@atlasoracle.io"}],"homepage":"https://github.com/oracle-atlas/pull-oracle-consumer#readme","bugs":{"url":"https://github.com/oracle-atlas/pull-oracle-consumer/issues"},"dist":{"shasum":"20d1bdf5d04df747691ec2e0483c5ac38b15513c","tarball":"https://registry.npmjs.org/@atlas-oracle/pull-oracle-consumer/-/pull-oracle-consumer-1.0.0.tgz","fileCount":16,"integrity":"sha512-nwLbxM1Sw9MTnyjBntoPYZImWibBc+qNKl70OsBuqHkMlG9duAZgX/REF+QCZmF66OLLnAqoOOfWvj/P73I8mg==","signatures":[{"sig":"MEQCIAXkeQGctUB9ZlaHZpUJo+fDsZvGayfj+xABEtku+jjYAiBSfmOp1B6cG6qAxKJ3ur/DhMuvgAeekWVQ9eEZ0nBrMw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":124024},"gitHead":"fae36318e0a5bdf48956b9a54aa4fd19fe20b587","scripts":{"check":"prettier --check 'src*/**/*.sol' 'test/**/*.sol' 'examples/**/*.sol'","format":"prettier --write 'src*/**/*.sol' 'test/**/*.sol' 'examples/**/*.sol'"},"_npmUser":{"name":"michael_wgy","email":"michael.wang@atlasoracle.io"},"repository":{"url":"git+https://github.com/oracle-atlas/pull-oracle-consumer.git","type":"git"},"_npmVersion":"11.6.2","description":"Solidity SDK for verifying and consuming Atlas Oracle pull-based price feeds","directories":{},"_nodeVersion":"24.13.0","_hasShrinkwrap":false,"packageManager":"yarn@4.11.0","devDependencies":{"prettier":"^3.8.1","prettier-plugin-solidity":"^2.2.1"},"_npmOperationalInternal":{"tmp":"tmp/pull-oracle-consumer_1.0.0_1780625789023_0.46278814501308063","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2026-06-05T02:16:28.837Z","modified":"2026-06-09T07:23:37.159Z","1.0.0":"2026-06-05T02:16:29.184Z"},"bugs":{"url":"https://github.com/oracle-atlas/pull-oracle-consumer/issues"},"license":"BUSL-1.1","homepage":"https://github.com/oracle-atlas/pull-oracle-consumer#readme","repository":{"url":"git+https://github.com/oracle-atlas/pull-oracle-consumer.git","type":"git"},"description":"Solidity SDK for verifying and consuming Atlas Oracle pull-based price feeds","maintainers":[{"email":"same.h@atlasoracle.io","name":"layne96"},{"email":"michael.wang@atlasoracle.io","name":"michael_wgy"}],"readme":"# Pull Oracle Consumer SDK\n\nA gas-optimized Solidity SDK for consuming pull-based oracle price feeds. Contracts inherit the SDK to cryptographically verify signed price data appended to transaction calldata, with zero external calls and minimal on-chain overhead.\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Architecture](#architecture)\n- [Which Consumer to Use](#which-consumer-to-use)\n- [Wire Format](#wire-format)\n- [Installation](#installation)\n- [Usage](#usage)\n- [Examples](#examples)\n- [Development](#development)\n- [Security](#security)\n- [License](#license)\n\n## Overview\n\nThe Pull Oracle Consumer SDK enables on-chain contracts to verify and decode signed price feeds delivered via trailing calldata. The relay service appends a signed payload to the end of a normal function call, and the consumer transparently parses, authenticates, and returns verified price data — all within a single transaction.\n\n**Key features:**\n\n- All feed packages in a single payload share one ECDSA signature — the on-chain consumer pays the `ecrecover` cost only once per call, regardless of how many feeds are requested\n- Inline assembly throughout for minimal gas overhead\n- No external contract calls — fully self-contained\n- Two performance tiers: Standard (O(M×N) batch) and Transient (O(M+N) batch via EIP-1153)\n- Two configuration strategies: hardcoded (zero SLOAD) and storage-backed (runtime governance)\n- Comprehensive timestamp validation (staleness + future drift protection)\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────────────────────────┐\n│                         Your Protocol Contract                       │\n│                     (inherits one of the four consumers)             │\n└─────────────────────────────────┬────────────────────────────────────┘\n                                  │ calls _getVerifiedFeedData(...)\n                                  ▼\n┌──────────────────────────────────────────────────────────────────────┐\n│                       PullOracleConsumerBase                         │\n│                                                                      │\n│  ┌──────────────────┐  ┌─────────────────────┐  ┌──────────────────┐ │\n│  │ PullOracleCodec  │  │ PullOracleSignature │  │  Hook Functions  │ │\n│  │ (payload decode) │  │  (ECDSA recovery)   │  │  (configurable)  │ │\n│  └──────────────────┘  └─────────────────────┘  └──────────────────┘ │\n└──────────────────────────────────────────────────────────────────────┘\n```\n\nThe four consumer contracts:\n\n1. **PullOracleConsumerStandard** (`src/PullOracleConsumerStandard.sol`) — hardcoded hooks, O(M×N) batch\n2. **PullOracleConsumerStandardStorage** (`src/PullOracleConsumerStandardStorage.sol`) — storage-backed hooks, O(M×N) batch\n3. **PullOracleConsumerTransient** (`src-advanced/PullOracleConsumerTransient.sol`) — hardcoded hooks, O(M+N) batch (EIP-1153)\n4. **PullOracleConsumerTransientStorage** (`src-advanced/PullOracleConsumerTransientStorage.sol`) — storage-backed hooks, O(M+N) batch (EIP-1153)\n\n## Which Consumer to Use\n\n| Variant | Solidity | Min. EVM | Batch Complexity | Hooks | Use Case |\n|---------|----------|----------|------------------|-------|----------|\n| **Standard** | ≥0.8.13 | ≥Paris | O(M×N) | Hardcoded (0 SLOAD) | Maximum gas efficiency, broad chain compatibility |\n| **StandardStorage** | ≥0.8.13 | ≥Paris | O(M×N) | Storage-backed | Runtime governance (signer rotation, threshold tuning) |\n| **Transient** | ≥0.8.24 | ≥Cancun | O(M+N) | Hardcoded (0 SLOAD) | Large batch requests on Cancun-compatible chains |\n| **TransientStorage** | ≥0.8.24 | ≥Cancun | O(M+N) | Storage-backed | Large batches + runtime governance |\n\n> **Note:** Lower algorithmic complexity does not always mean lower gas cost. The Transient variants incur TSTORE/TLOAD setup overhead that only pays off when `M × N` is sufficiently large. Benchmark both paths against your expected workload.\n\n## Wire Format\n\nOracle data is appended to the end of normal calldata. The official TypeScript SDK provides helpers to fetch signed oracle payloads from the service, append them to your business calldata, and submit the assembled transaction on-chain.\n\n```\n[Business Calldata] [Feed Packages × N] [Footer (68 bytes)]\n\nFeed Package (20 bytes):\n┌──────────┬────────────────┬───────────────┐\n│ Feed ID  │     Price      │  Timestamp    │\n│ (4 bytes)│   (10 bytes)   │  (6 bytes)    │\n└──────────┴────────────────┴───────────────┘\n\nFooter (68 bytes):\n┌───────────────┬─────────────────────────┬──────────────────┐\n│ Package Count │    ECDSA Signature      │  Magic Marker    │\n│   (1 byte)    │      (65 bytes)         │   (2 bytes)      │\n└───────────────┴─────────────────────────┴──────────────────┘\n```\n\n- **Price**: 80-bit unsigned integer (18 decimal precision)\n- **Timestamp**: 48-bit Unix timestamp (off-chain aggregation time)\n- **Magic Marker**: `0x7096` (derived from `keccak256(\"ATLAS\")`)\n\n## Installation\n\n### Foundry\n\n```bash\nforge install oracle-atlas/pull-oracle-consumer\n```\n\nOr add as a git submodule:\n\n```bash\ngit submodule add https://github.com/oracle-atlas/pull-oracle-consumer.git lib/pull-oracle-consumer\n```\n\nAdd to your `remappings.txt`:\n\n```\npull-oracle-consumer/=lib/pull-oracle-consumer/src/\n```\n\n### Hardhat\n\n```bash\nnpm install @atlas-oracle/pull-oracle-consumer\n# or\nyarn add @atlas-oracle/pull-oracle-consumer\n```\n\nImport directly from `node_modules`:\n\n```solidity\nimport {PullOracleConsumerStandard} from \"@atlas-oracle/pull-oracle-consumer/src/PullOracleConsumerStandard.sol\";\n```\n\nConfigure the Solidity compiler in `hardhat.config.ts`:\n\n```typescript\nconst config: HardhatUserConfig = {\n  solidity: {\n    compilers: [\n      { version: \"0.8.13\", settings: { evmVersion: \"paris\" } },\n      // Add if using Transient variants:\n      // { version: \"0.8.24\", settings: { evmVersion: \"cancun\" } },\n    ],\n  },\n};\n```\n\n## Usage\n\n### Minimal Integration (Standard)\n\n```solidity\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.13;\n\nimport {PullOracleConsumerStandard} from \"pull-oracle-consumer/PullOracleConsumerStandard.sol\";\n\ncontract MyProtocol is PullOracleConsumerStandard {\n    bytes4 internal constant BTC_USD = 0x00000001;\n\n    function settle() external {\n        (uint256 price, uint256 timestamp) = _getVerifiedFeedData(BTC_USD);\n        // Use verified price in your business logic...\n    }\n}\n```\n\n### Available Data Accessor Functions\n\n| Function | Behavior | Availability |\n|----------|----------|--------------|\n| `_getVerifiedFeedData(feedId)` | Single feed, reverts if missing | All variants |\n| `_getVerifiedFeedDataLenient(feedId)` | Single feed, returns (0,0) if missing | All variants |\n| `_getVerifiedFeedDataBatch(feedIds)` | Batch O(M×N), reverts if any missing | All variants |\n| `_getVerifiedFeedDataBatchLenient(feedIds)` | Batch O(M×N), returns 0 for missing | All variants |\n| `_getVerifiedFeedDataBatchTransient(feedIds)` | Batch O(M+N), reverts if any missing | Transient variants only |\n| `_getVerifiedFeedDataBatchLenientTransient(feedIds)` | Batch O(M+N), returns 0 for missing | Transient variants only |\n\n### Storage-Backed Consumer (Governance)\n\n```solidity\nimport {PullOracleConsumerStandardStorage} from \"pull-oracle-consumer/PullOracleConsumerStandardStorage.sol\";\n\ncontract MyProtocol is PullOracleConsumerStandardStorage {\n    constructor(address[] memory signers)\n        PullOracleConsumerStandardStorage(\n            255,    // maxPackageCount\n            180,    // maxDelay (seconds)\n            60,     // maxFutureDrift (seconds)\n            signers\n        )\n    {}\n\n    // Expose governance setters behind access control:\n    function rotateSigner(address signer, bool status) external onlyAdmin {\n        _setSignerStatus(signer, status);\n    }\n}\n```\n\n### Hook Overrides (Hardcoded Variants)\n\nThe hardcoded consumers (`PullOracleConsumerStandard`, `PullOracleConsumerTransient`) delegate security policy to three virtual hook functions. Without any overrides, the contract uses the default implementation provided by `PullOracleReferenceHooks` — no additional configuration is required and the consumer works out of the box.\n\nHowever, the reference defaults may not suit every protocol. **Integrators should evaluate whether these defaults align with their security model and operational requirements, and override the corresponding hooks if they do not.**\n\n#### The Three Hook Functions\n\n| Hook | Responsibility | Parameter | Default | Description |\n|------|---------------|-----------|---------|-------------|\n| `_validateTimestamp` | Enforce price freshness | maxDelay | 180s | Revert if price older than this |\n| | | maxFutureDrift | 60s | Revert if price timestamp ahead of block by this |\n| `_getMaxPackageCount` | Cap gas per call | maxPackageCount | 255 | Maximum feed packages allowed |\n| `_isAuthorizedSigner` | Verify oracle signer | authorizedSigner | `0x59eD...600` | Atlas Oracle official signing key |\n\nEach hook is a compile-time constant override (no SLOAD), preserving the gas-efficiency guarantee of the hardcoded consumer.\n\nFor complete override examples of all three hooks, see [`examples/standard/ExamplePullOracleConsumerStandard.sol`](examples/standard/ExamplePullOracleConsumerStandard.sol).\n\n> **Recommendation:** Review the reference defaults in `PullOracleReferenceHooks` and determine whether they align with your protocol's latency tolerance, gas budget, and trust assumptions. If not, override the corresponding hooks. Refer to the official oracle documentation for the current production signing address.\n\n## Examples\n\nComplete integration examples are provided under `examples/`. Use these as reference implementations when building your own consumer contracts — each file is a self-contained, compilable contract that you can copy and adapt to your protocol's needs.\n\n```\nexamples/\n├── standard/\n│   ├── ExamplePullOracleConsumerStandard.sol           # Hardcoded hooks, 4 API patterns\n│   └── ExamplePullOracleConsumerStandardStorage.sol    # Storage governance, 4 API patterns\n└── advanced/\n    ├── ExamplePullOracleConsumerTransient.sol           # Transient batch, 6 API patterns\n    └── ExamplePullOracleConsumerTransientStorage.sol    # Transient + governance, 6 API patterns\n```\n\nEach example demonstrates:\n- All available data accessor functions with return value consumption\n- Business logic placeholder guidance\n- Hook override patterns (hardcoded variants)\n- Governance setter patterns (storage variants)\n\n## Development\n\nRequires [Foundry](https://book.getfoundry.sh/getting-started/installation) installed.\n\n```bash\nforge build                                 # Build Standard (solc 0.8.13, Paris)\nFOUNDRY_PROFILE=advanced forge build        # Build Advanced (solc 0.8.24, Cancun)\nFOUNDRY_PROFILE=examples-standard forge build   # Build Standard examples\nFOUNDRY_PROFILE=examples-advanced forge build   # Build Advanced examples\n\nforge test                                  # Run Standard tests\nFOUNDRY_PROFILE=advanced forge test         # Run Advanced tests\n```\n\n## Security\n\nThis SDK has been audited by **CertiK**. Key security properties:\n\n- **ECDSA malleability protection** — EIP-2 low-S enforcement prevents signature replay with flipped `s` values\n- **Timestamp validation** — Configurable staleness and future-drift bounds per feed\n- **Memory safety** — All assembly blocks annotated `(\"memory-safe\")`; free memory pointer 32-byte aligned after use\n- **Transient storage isolation** — Batch functions always clear TSTORE slots after use to prevent cross-call data leakage within a transaction\n\n## License\n\nBUSL-1.1 (Business Source License 1.1)\n","readmeFilename":"README.md"}