diff --git a/public/changelog.json b/public/changelog.json
index 34d7a3e2b63..3d17e27ba35 100644
--- a/public/changelog.json
+++ b/public/changelog.json
@@ -1883,6 +1883,1118 @@
"title": "Cross-chain token (CCT) standard: Added support for new tokens",
"topic": "CCIP"
},
+ {
+ "category": "integration",
+ "date": "2026-03-15",
+ "description": "New Data Streams available on all [supported networks](https://docs.chain.link/data-streams/crypto-streams):",
+ "relatedNetworks": [
+ "0g",
+ "apechain",
+ "adi",
+ "aptos",
+ "arbitrum",
+ "arc",
+ "avalanche",
+ "base",
+ "berachain",
+ "bitlayer",
+ "blast",
+ "bnb-chain",
+ "bob",
+ "botanix",
+ "celo",
+ "dogeos",
+ "ethereum",
+ "giwa",
+ "gnosis-chain",
+ "gravity",
+ "hashkey",
+ "hedera",
+ "hyperliquid",
+ "injective",
+ "ink",
+ "jovay",
+ "katana",
+ "lens",
+ "linea",
+ "mantle",
+ "metis",
+ "monad",
+ "opbnb",
+ "optimism",
+ "polygon",
+ "perennial",
+ "pharos",
+ "plasma",
+ "ronin",
+ "scroll",
+ "shibarium",
+ "sei",
+ "seismic",
+ "soneium",
+ "sonic",
+ "solana",
+ "stable",
+ "xlayer",
+ "taiko",
+ "unichain",
+ "worldchain",
+ "zksync"
+ ],
+ "relatedTokens": [
+ {
+ "assetName": "ADI Token",
+ "baseAsset": "ADI",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/adi-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/adi.webp"
+ },
+ {
+ "assetName": "Oklo Inc",
+ "baseAsset": "OKLO",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/oklo-usd-overnighthoursequityprice-streams",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/oklo.webp"
+ },
+ {
+ "assetName": "Oklo Inc",
+ "baseAsset": "OKLO",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/oklo-usd-regularhoursequityprice-streams",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/oklo.webp"
+ },
+ {
+ "assetName": "Oklo Inc",
+ "baseAsset": "OKLO",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/oklo-usd-extendedhoursequityprice-streams",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/oklo.webp"
+ },
+ {
+ "assetName": "OpenDelta NX8",
+ "baseAsset": "NX8",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/nx8-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/nx8.webp"
+ },
+ {
+ "assetName": "SanDisk Corp",
+ "baseAsset": "SNDK",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/sndk-usd-regularhoursequityprice-streams",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/sndk.webp"
+ },
+ {
+ "assetName": "SanDisk Corp",
+ "baseAsset": "SNDK",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/sndk-usd-extendedhoursequityprice-streams",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/sndk.webp"
+ },
+ {
+ "assetName": "SanDisk Corp",
+ "baseAsset": "SNDK",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/sndk-usd-overnighthoursequityprice-streams",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/sndk.webp"
+ },
+ {
+ "assetName": "Strategy Variable Rate Perpetual xStock",
+ "baseAsset": "STRCx",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/strcx-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/strcx.webp"
+ },
+ {
+ "assetName": "Tessera tKalshi",
+ "baseAsset": "tKalshi",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/tkalshi-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/tkalshi.webp"
+ },
+ {
+ "assetName": "Tessera tSpaceX",
+ "baseAsset": "tSpaceX",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/tspacex-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/tspacex.webp"
+ },
+ {
+ "assetName": "Unitas USDu",
+ "baseAsset": "USDu",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/usdu-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdu.webp"
+ }
+ ],
+ "title": "Added support to Data Streams",
+ "topic": "Data Streams"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-15",
+ "description": "New SmartData Feeds available:",
+ "relatedNetworks": ["ethereum"],
+ "relatedTokens": [
+ {
+ "assetName": "Treasury+",
+ "baseAsset": "Treasury+",
+ "network": "ethereum",
+ "productTypeCode": "NAV",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/treasuryplus-nav",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/treasury+.webp"
+ }
+ ],
+ "title": "Added support to SmartData",
+ "topic": "SmartData"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-15",
+ "description": "New Data Feeds available:",
+ "relatedNetworks": ["ethereum", "tron", "bnb-chain", "sonic"],
+ "relatedTokens": [
+ {
+ "assetName": "AUSD",
+ "baseAsset": "AUSD",
+ "quoteAsset": "USD",
+ "network": "ethereum",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/ausd-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ausd.webp"
+ },
+ {
+ "assetName": "HTX DAO",
+ "baseAsset": "HTX",
+ "quoteAsset": "USD",
+ "network": "tron",
+ "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?page=1&network=tron&search=htx",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/htx.webp"
+ },
+ {
+ "assetName": "RLP / USD Exchange Rate",
+ "baseAsset": "RLP",
+ "quoteAsset": "USD",
+ "network": "bnb-chain",
+ "url": "https://data.chain.link/feeds/bsc/mainnet/rlp-usd-exchange-rate",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/rlp.webp"
+ },
+ {
+ "assetName": "stGLD / tGLD Exchange Rate",
+ "baseAsset": "stGLD",
+ "quoteAsset": "tGLD",
+ "network": "ethereum",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/stgld-tgld-exchange-rate",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/stgld.webp"
+ },
+ {
+ "assetName": "sUSDD / USDD Exchange Rate",
+ "baseAsset": "sUSDD",
+ "quoteAsset": "sUSDD",
+ "network": "tron",
+ "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?page=1&network=tron&search=susdd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susdd.webp"
+ },
+ {
+ "assetName": "US Sonic Dollar",
+ "baseAsset": "USSD",
+ "quoteAsset": "USD",
+ "network": "sonic",
+ "url": "https://data.chain.link/feeds/sonic/sonic/ussd-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ussd.webp"
+ },
+ {
+ "assetName": "USDD / USDC Exchange Rate",
+ "baseAsset": "USDD",
+ "quoteAsset": "USDC",
+ "network": "tron",
+ "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?page=1&network=tron&search=usdd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdd.webp"
+ },
+ {
+ "assetName": "USDD / USDT Exchange Rate",
+ "baseAsset": "USDD",
+ "quoteAsset": "USDT",
+ "network": "tron",
+ "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?page=1&network=tron&search=usdd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdd.webp"
+ },
+ {
+ "assetName": "Wrapped Bitcoin",
+ "baseAsset": "WBTC",
+ "quoteAsset": "USD",
+ "network": "tron",
+ "url": "https://docs.chain.link/data-feeds/price-feeds/addresses?page=1&network=tron&search=wbtc",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wbtc.webp"
+ }
+ ],
+ "title": "Added support to Data Feeds",
+ "topic": "Data Feeds"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-13",
+ "description": "Chainlink CCIP expands support to new networks:",
+ "newNetworks": [
+ {
+ "displayName": "Robinhood Chain Testnet",
+ "network": "robinhood",
+ "url": "https://docs.chain.link/ccip/directory/testnet/chain/robinhood-testnet"
+ },
+ {
+ "displayName": "Ronin Saigon Testnet",
+ "network": "ronin",
+ "url": "https://docs.chain.link/ccip/directory/testnet/chain/ronin-testnet-saigon"
+ }
+ ],
+ "relatedNetworks": ["robinhood", "ronin"],
+ "title": "CCIP on Robinhood Chain Testnet and Ronin Saigon Testnet",
+ "topic": "CCIP"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-08",
+ "description": "New Data Streams available on all [supported networks](https://docs.chain.link/data-streams/crypto-streams):",
+ "relatedNetworks": [
+ "0g",
+ "apechain",
+ "adi-network",
+ "aptos",
+ "arbitrum",
+ "arc",
+ "avalanche",
+ "base",
+ "berachain",
+ "bitlayer",
+ "blast",
+ "bnb-chain",
+ "bob",
+ "botanix",
+ "celo",
+ "dogeos",
+ "ethereum",
+ "giwa",
+ "gnosis-chain",
+ "gravity",
+ "hashkey",
+ "hedera",
+ "hyperliquid",
+ "injective",
+ "ink",
+ "jovay",
+ "katana",
+ "lens",
+ "linea",
+ "mantle",
+ "metis",
+ "monad",
+ "opbnb",
+ "optimism",
+ "polygon",
+ "perennial",
+ "pharos",
+ "plasma",
+ "ronin",
+ "scroll",
+ "shibarium",
+ "sei",
+ "seismic",
+ "soneium",
+ "sonic",
+ "solana",
+ "stable",
+ "xlayer",
+ "taiko",
+ "unichain",
+ "worldchain",
+ "zksync"
+ ],
+ "relatedTokens": [
+ {
+ "assetName": "DeFi Janus Henderson Anemoy AAA CLO Fund",
+ "baseAsset": "deJAAA",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/dejaaa-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/dejaaa.webp"
+ },
+ {
+ "assetName": "DeFi Janus Henderson Anemoy Treasury Fund",
+ "baseAsset": "deJTRSY",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/dejtrsy-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/dejtrsy.webp"
+ },
+ {
+ "assetName": "Saakuru",
+ "baseAsset": "SKR",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/skr-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/skr.webp"
+ }
+ ],
+ "title": "Added support to Data Streams",
+ "topic": "Data Streams"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-08",
+ "description": "New Data Feeds available:",
+ "relatedNetworks": ["ethereum", "unichain", "xlayer"],
+ "relatedTokens": [
+ {
+ "assetName": "Alphabet Inc - A",
+ "baseAsset": "GOOGL",
+ "quoteAsset": "USD",
+ "network": "ethereum",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/googl-usd-kalman-24-5",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/googl.webp"
+ },
+ {
+ "assetName": "Bitcoin",
+ "baseAsset": "BTC",
+ "quoteAsset": "USD",
+ "network": "unichain",
+ "url": "https://data.chain.link/feeds/unichain/mainnet/btc-usd-svr",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/btc.webp"
+ },
+ {
+ "assetName": "Chainlink",
+ "baseAsset": "LINK",
+ "quoteAsset": "USD",
+ "network": "unichain",
+ "url": "https://data.chain.link/feeds/unichain/mainnet/link-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/link.webp"
+ },
+ {
+ "assetName": "Circle USD",
+ "baseAsset": "USDC",
+ "quoteAsset": "USD",
+ "network": "unichain",
+ "url": "https://data.chain.link/feeds/unichain/mainnet/usdc-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdc.webp"
+ },
+ {
+ "assetName": "Circle USD",
+ "baseAsset": "USDC",
+ "quoteAsset": "USD",
+ "network": "unichain",
+ "url": "https://data.chain.link/feeds/unichain/mainnet/usdc-usd-svr",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdc.webp"
+ },
+ {
+ "assetName": "Ethereum",
+ "baseAsset": "ETH",
+ "quoteAsset": "USD",
+ "network": "unichain",
+ "url": "https://data.chain.link/feeds/unichain/mainnet/eth-usd-svr",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eth.webp"
+ },
+ {
+ "assetName": "Invesco QQQ",
+ "baseAsset": "QQQ",
+ "quoteAsset": "USD",
+ "network": "ethereum",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/qqq-usd-kalman-24-5",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/qqq.webp"
+ },
+ {
+ "assetName": "Kelp DAO Restaked ETH",
+ "baseAsset": "RSETH",
+ "quoteAsset": "ETH",
+ "network": "unichain",
+ "url": "https://data.chain.link/feeds/unichain/mainnet/rseth-eth-exchange-rate",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/rseth.webp"
+ },
+ {
+ "assetName": "NVIDIA Corporation",
+ "baseAsset": "NVDA",
+ "quoteAsset": "USD",
+ "network": "ethereum",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/nvda-usd-kalman-24-5",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/nvda.webp"
+ },
+ {
+ "assetName": "Renzo Restaked ETH",
+ "baseAsset": "EZETH",
+ "quoteAsset": "ETH",
+ "network": "unichain",
+ "url": "https://data.chain.link/feeds/unichain/mainnet/ezeth-eth-exchange-rate",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ezeth.webp"
+ },
+ {
+ "assetName": "Solana",
+ "baseAsset": "SOL",
+ "quoteAsset": "USD",
+ "network": "xlayer",
+ "url": "https://data.chain.link/feeds/xlayer/xlayer/sol-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/sol.webp"
+ },
+ {
+ "assetName": "SPDR S&P 500 ETF",
+ "baseAsset": "SPY",
+ "quoteAsset": "USD",
+ "network": "ethereum",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/spy-usd-kalman-24-5",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/spy.webp"
+ },
+ {
+ "assetName": "Tesla Inc",
+ "baseAsset": "TSLA",
+ "quoteAsset": "USD",
+ "network": "ethereum",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/tsla-usd-kalman-24-5",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/tsla.webp"
+ },
+ {
+ "assetName": "Uniswap",
+ "baseAsset": "UNI",
+ "quoteAsset": "USD",
+ "network": "unichain",
+ "url": "https://data.chain.link/feeds/unichain/mainnet/uni-usd-svr",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/uni.webp"
+ },
+ {
+ "assetName": "Wrapped eETH",
+ "baseAsset": "weETH",
+ "quoteAsset": "eETH",
+ "network": "unichain",
+ "url": "https://data.chain.link/feeds/unichain/mainnet/weeth-eeth-exchange-rate",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/weeth.webp"
+ },
+ {
+ "assetName": "wstETH / stETH Exchange Rate",
+ "baseAsset": "wstETH",
+ "quoteAsset": "stETH",
+ "network": "unichain",
+ "url": "https://data.chain.link/feeds/unichain/mainnet/wsteth-steth-exchange-rate",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wsteth.webp"
+ }
+ ],
+ "title": "Added support to Data Feeds",
+ "topic": "Data Feeds"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-08",
+ "description": "Newly supported tokens: ZYPTO, cbBTC",
+ "relatedTokens": [
+ {
+ "assetName": "Zypto Token",
+ "baseAsset": "ZYPTO",
+ "url": "https://docs.chain.link/ccip/directory/mainnet/token/ZYPTO",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/zypto.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover"
+ },
+ {
+ "assetName": "Coinbase Wrapped BTC",
+ "baseAsset": "cbBTC",
+ "url": "https://docs.chain.link/ccip/directory/mainnet/token/cbBTC",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/cbbtc.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover"
+ }
+ ],
+ "title": "Cross-chain token (CCT) standard: Added support for new tokens",
+ "topic": "CCIP"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-06",
+ "description": "Chainlink CCIP expands support to new networks:",
+ "newNetworks": [
+ {
+ "displayName": "ADI Network Mainnet",
+ "network": "adi-network",
+ "url": "https://docs.chain.link/ccip/directory/mainnet/chain/adi-network-mainnet"
+ },
+ {
+ "displayName": "Edge Mainnet",
+ "network": "edge-mainnet",
+ "url": "https://docs.chain.link/ccip/directory/mainnet/chain/edge-mainnet"
+ },
+ {
+ "displayName": "Edge Testnet",
+ "network": "edge-testnet",
+ "url": "https://docs.chain.link/ccip/directory/testnet/chain/edge-testnet"
+ }
+ ],
+ "relatedNetworks": ["adi-network", "edge"],
+ "title": "CCIP on ADI Network Mainnet, Edge Mainnet and Edge Testnet",
+ "topic": "CCIP"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-06",
+ "description": "Newly supported tokens: ZYPTO",
+ "relatedTokens": [
+ {
+ "assetName": "ZYPTO",
+ "baseAsset": "ZYPTO",
+ "url": "https://docs.chain.link/ccip/directory/mainnet/token/ZYPTO",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/zypto.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover"
+ }
+ ],
+ "title": "Cross-chain token (CCT) standard: Added support for new tokens",
+ "topic": "CCIP"
+ },
+ {
+ "category": "release",
+ "date": "2026-03-05",
+ "description": "CLI version 1.3.0 adds TypeScript EVM binding generation, explicit `--target` prompting, Jovay/Pharos/XLayer mainnet support, and Pharos Atlantic testnet support.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.2.0...v1.3.0)",
+ "title": "CRE CLI v1.3.0 — TypeScript Bindings and New Networks",
+ "topic": "CRE"
+ },
+ {
+ "category": "release",
+ "date": "2026-03-05",
+ "description": "Go SDK version 1.5.0 adds Pharos Atlantic network support.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-go/compare/v1.4.0...v1.5.0)",
+ "title": "CRE Go SDK v1.5.0 — Pharos Atlantic Support",
+ "topic": "CRE"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-03",
+ "description": "Chainlink Data Feeds is available on Unichain Mainnet. View the available price feed information on the [Price Feed Addresses](https://docs.chain.link/data-feeds/price-feeds/addresses?network=unichain&page=1) page.",
+ "relatedNetworks": ["unichain"],
+ "title": "Data Feeds Expands to Unichain Mainnet",
+ "topic": "Data Feeds"
+ },
+ {
+ "category": "release",
+ "date": "2026-03-02",
+ "description": "Go SDK version 1.4.0 adds Solana LogTrigger SDK generation and Solana workflow bindings, and expands network support to Jovay Testnet, Pharos Testnet, and XLayer. Note: previously generated Solana SDK types have been removed and replaced by the new Solana bindings.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-sdk-go/compare/v1.3.0...v1.4.0)",
+ "title": "CRE Go SDK v1.4.0 — Solana Bindings and New Networks",
+ "topic": "CRE"
+ },
+ {
+ "category": "release",
+ "date": "2026-03-02",
+ "description": "The CCIP SDK, CLI, and REST API are now generally available:\n\n- **CCIP SDK v1.0** ([@chainlink/ccip-sdk](https://www.npmjs.com/package/@chainlink/ccip-sdk)): Programmatic tools for sending messages, transferring tokens, estimating fees, and querying CCIP activity.\n- **CCIP CLI v1.0** ([@chainlink/ccip-cli](https://www.npmjs.com/package/@chainlink/ccip-cli)): Command-line interface for the same capabilities.\n- **CCIP API v2** ([REST API](https://docs.chain.link/ccip/tools/api/)): Endpoints for messages and their details, lane latency, and intents.\n\nSee the [CCIP Tools](https://docs.chain.link/ccip/tools/) documentation for details.",
+ "title": "CCIP SDK v1.0, CLI v1.0, and API v2",
+ "topic": "CCIP"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-01",
+ "description": "New Data Streams available on all [supported networks](https://docs.chain.link/data-streams/crypto-streams):",
+ "relatedNetworks": [
+ "0g",
+ "apechain",
+ "adi-network",
+ "aptos",
+ "arbitrum",
+ "arc",
+ "avalanche",
+ "base",
+ "berachain",
+ "bitlayer",
+ "blast",
+ "bnb-chain",
+ "bob",
+ "botanix",
+ "celo",
+ "dogeos",
+ "ethereum",
+ "gnosis-chain",
+ "gravity",
+ "hashkey",
+ "hedera",
+ "hyperliquid",
+ "injective",
+ "ink",
+ "jovay",
+ "katana",
+ "lens",
+ "linea",
+ "mantle",
+ "metis",
+ "monad",
+ "opbnb",
+ "optimism",
+ "polygon",
+ "perennial",
+ "pharos",
+ "plasma",
+ "ronin",
+ "scroll",
+ "shibarium",
+ "sei",
+ "soneium",
+ "sonic",
+ "solana",
+ "stable",
+ "taiko",
+ "unichain",
+ "worldchain",
+ "zksync"
+ ],
+ "relatedTokens": [
+ {
+ "assetName": " Rocket Lab Corp",
+ "baseAsset": "RKLB",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/rklb-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/rklb.webp"
+ },
+ {
+ "assetName": "Advanced Micro Devices / AMD",
+ "baseAsset": "AMD",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/amd-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/amd.webp"
+ },
+ {
+ "assetName": "Alibaba Group Holding Ltd (ADRs)",
+ "baseAsset": "BABA",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/baba-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/baba.webp"
+ },
+ {
+ "assetName": "Beyond Meat Inc",
+ "baseAsset": "BYND",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/bynd-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/bynd.webp"
+ },
+ {
+ "assetName": "CoreWeave Inc",
+ "baseAsset": "CRWV",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/crwv-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/crwv.webp"
+ },
+ {
+ "assetName": "DeFi Janus Henderson Anemoy AAA CLO Fund",
+ "baseAsset": "deJAAA",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/dejaaa-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/dejaaa.webp"
+ },
+ {
+ "assetName": "DeFi Janus Henderson Anemoy Treasury Fund",
+ "baseAsset": "deJTRSY",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/dejtrsy-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/dejtrsy.webp"
+ },
+ {
+ "assetName": "Global Dollar",
+ "baseAsset": "USDG",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/usdg-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdg.webp"
+ },
+ {
+ "assetName": "Global X AI & Tech ETF",
+ "baseAsset": "AIQ",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/aiq-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/aiq.webp"
+ },
+ {
+ "assetName": "Global X Robotics & Artificial Intelligence (BOTZ)",
+ "baseAsset": "BOTZ",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/botz-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/botz.webp"
+ },
+ {
+ "assetName": "Intel Corp",
+ "baseAsset": "INTC",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/intc-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/intc.webp"
+ },
+ {
+ "assetName": "iPath Series B S&P 500 VIX Short-Term Futures ETF",
+ "baseAsset": "VXX",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/vxx-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/vxx.webp"
+ },
+ {
+ "assetName": "iShares 20+ Year Treasury Bond ETF",
+ "baseAsset": "TLT",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/tlt-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/tlt.webp"
+ },
+ {
+ "assetName": "iShares Core MSCI Emerging Mkts ETF",
+ "baseAsset": "IEMG",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/iemg-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/iemg.webp"
+ },
+ {
+ "assetName": "iShares Gold Trust",
+ "baseAsset": "IAU",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/iau-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/iau.webp"
+ },
+ {
+ "assetName": "iShares MSCI Japan ETF",
+ "baseAsset": "EWJ",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/ewj-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ewj.webp"
+ },
+ {
+ "assetName": "iShares Russell 2000 ETF",
+ "baseAsset": "IWM",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/iwm-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/iwm.webp"
+ },
+ {
+ "assetName": "iShares Silver Trust ETF",
+ "baseAsset": "SLV",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/slv-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/slv.webp"
+ },
+ {
+ "assetName": "Kraneshares CSI China Internet ETF",
+ "baseAsset": "KWEB",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/kweb-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/kweb.webp"
+ },
+ {
+ "assetName": "Micron Technology Inc",
+ "baseAsset": "MU",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/mu-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/mu.webp"
+ },
+ {
+ "assetName": "Nebius Group",
+ "baseAsset": "NBIS",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/nbis-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/nbis.webp"
+ },
+ {
+ "assetName": "Real Estate Select Sector SPDR Fund ETF",
+ "baseAsset": "XLRE",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/xlre-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/xlre.webp"
+ },
+ {
+ "assetName": "Rigetti Computing Inc",
+ "baseAsset": "RGTI",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/rgti-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/rgti.webp"
+ },
+ {
+ "assetName": "Roundhill Magnificent Seven ETF",
+ "baseAsset": "MAGS",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/mags-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/mags.webp"
+ },
+ {
+ "assetName": "Schwab US REIT",
+ "baseAsset": "SCHH",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/schh-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/schh.webp"
+ },
+ {
+ "assetName": "Sentient",
+ "baseAsset": "SENT",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/sent-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/sent.webp"
+ },
+ {
+ "assetName": "SPDR DJIA ETF",
+ "baseAsset": "DIA",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/dia-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/dia.webp"
+ },
+ {
+ "assetName": "STRC",
+ "baseAsset": "STRC",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/strc-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/strc.webp"
+ },
+ {
+ "assetName": "TSMC / Taiwan Semiconductor Man Co (ADRs)",
+ "baseAsset": "TSM",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/tsm-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/tsm.webp"
+ },
+ {
+ "assetName": "United States Oil Fund LP ETF",
+ "baseAsset": "USO",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/uso-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/uso.webp"
+ },
+ {
+ "assetName": "USD",
+ "baseAsset": "USD",
+ "quoteAsset": "ARS",
+ "url": "https://data.chain.link/streams/usd-ars",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usd.webp"
+ },
+ {
+ "assetName": "USX / USD Redemption Rate",
+ "baseAsset": "USX",
+ "quoteAsset": "USD",
+ "url": "https://data.chain.link/streams/usx-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usx.webp"
+ }
+ ],
+ "title": "Added support to Data Streams",
+ "topic": "Data Streams"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-01",
+ "description": "New SmartData Feeds available:",
+ "relatedNetworks": ["ethereum", "bnb-chain"],
+ "relatedTokens": [
+ {
+ "assetName": "CRDYX NAV",
+ "baseAsset": "CRDYX",
+ "network": "ethereum",
+ "productTypeCode": "NAV",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/crdyx-nav",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/crdyx.webp"
+ },
+ {
+ "assetName": "JAAA NAV",
+ "baseAsset": "JAAA",
+ "network": "ethereum",
+ "productTypeCode": "NAV",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/jaaa-nav-v2",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/jaaa.webp"
+ },
+ {
+ "assetName": "JTRSY NAV",
+ "baseAsset": "JTRSY",
+ "network": "ethereum",
+ "productTypeCode": "NAV",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/jtrsy-nav-v2",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/jtrsy.webp"
+ },
+ {
+ "assetName": "Kinesis Gold (KAU)",
+ "baseAsset": "KAU",
+ "network": "ethereum",
+ "productTypeCode": "PoR",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/kau-por",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/kau.webp"
+ },
+ {
+ "assetName": "Kinesis Silver (KAG)",
+ "baseAsset": "KAG",
+ "network": "ethereum",
+ "productTypeCode": "PoR",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/kag-por",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/kag.webp"
+ },
+ {
+ "assetName": "Renzo Restaked ETH",
+ "baseAsset": "ezETH",
+ "network": "ethereum",
+ "productTypeCode": "PoR",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/ezeth-por",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/ezeth.webp"
+ },
+ {
+ "assetName": "US Dollar (USD) total reserves",
+ "baseAsset": "C1USD",
+ "network": "ethereum",
+ "productTypeCode": "PoR",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/c1usd-por",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/c1usd.webp"
+ },
+ {
+ "assetName": "WTGXX NAV",
+ "baseAsset": "WTGXX",
+ "network": "ethereum",
+ "productTypeCode": "NAV",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/wtgxx-nav-24h",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/wtgxx.webp"
+ },
+ {
+ "assetName": "XAUM Reference Rate",
+ "baseAsset": "XAUM",
+ "network": "bnb-chain",
+ "productTypeCode": "NAV",
+ "url": "https://data.chain.link/feeds/bsc/mainnet/xaum-reference-rate",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/xaum.webp"
+ }
+ ],
+ "title": "Added support to SmartData",
+ "topic": "SmartData"
+ },
+ {
+ "category": "integration",
+ "date": "2026-03-01",
+ "description": "New Data Feeds available:",
+ "relatedNetworks": ["arbitrum", "scroll", "base", "polygonkatana", "optimism", "ethereum"],
+ "relatedTokens": [
+ {
+ "assetName": "Avant Staked USD",
+ "baseAsset": "savUSD",
+ "quoteAsset": "avUSD",
+ "network": "arbitrum",
+ "url": "https://data.chain.link/feeds/arbitrum/mainnet/savusd-avusd-exchange-rate",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/savusd.webp"
+ },
+ {
+ "assetName": "Circle EUR",
+ "baseAsset": "EURC",
+ "quoteAsset": "USD",
+ "network": "scroll",
+ "url": "https://data.chain.link/feeds/scroll/mainnet/eurc-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/eurc.webp"
+ },
+ {
+ "assetName": "Ripple USD",
+ "baseAsset": "RLUSD",
+ "quoteAsset": "USD",
+ "network": "base",
+ "url": "https://data.chain.link/feeds/base/base/rlusd-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/rlusd.webp"
+ },
+ {
+ "assetName": "Silver",
+ "baseAsset": "XAG",
+ "quoteAsset": "USD",
+ "network": "base",
+ "url": "https://data.chain.link/feeds/base/base/xag-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/xag.webp"
+ },
+ {
+ "assetName": "Solv Protocol SOLVBTC / BTC Exchange Rate",
+ "baseAsset": "SOLVBTC",
+ "quoteAsset": "BTC",
+ "network": "arbitrum",
+ "url": "https://data.chain.link/feeds/arbitrum/mainnet/solvbtc-btc-exchange-rate",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/solvbtc.webp"
+ },
+ {
+ "assetName": "SUSDA / USDA Exchange Rate",
+ "baseAsset": "SUSDA",
+ "quoteAsset": "USDA",
+ "network": "polygonkatana",
+ "url": "https://data.chain.link/feeds/katana/polygon-mainnet-katana/susda-usda-exchange-rate",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/susda.webp"
+ },
+ {
+ "assetName": "UMA",
+ "baseAsset": "UMA",
+ "quoteAsset": "USD",
+ "network": "optimism",
+ "url": "https://data.chain.link/feeds/optimism/mainnet/uma-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/uma.webp"
+ },
+ {
+ "assetName": "Zcash",
+ "baseAsset": "ZEC",
+ "quoteAsset": "USD",
+ "network": "ethereum",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/zec-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/zec.webp"
+ },
+ {
+ "assetName": "ZCash",
+ "baseAsset": "ZEC",
+ "quoteAsset": "USD",
+ "network": "arbitrum",
+ "url": "https://data.chain.link/feeds/arbitrum/mainnet/zec-usd",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/zec.webp"
+ }
+ ],
+ "title": "Added support to Data Feeds",
+ "topic": "Data Feeds"
+ },
+ {
+ "category": "integration",
+ "date": "2026-02-26",
+ "description": "Chainlink Data Streams is available for new blockchains:\n\n- Giwa Sepolia Testnet\n- Injective EVM Testnet\n- Seismic Testnet\n- X Layer Mainnet\n- X Layer Testnet\n\nThe verifier proxy addresses and stream IDs are available on the [Stream Addresses](https://docs.chain.link/data-streams/crypto-streams) page.",
+ "relatedNetworks": ["giwa", "injective", "seismic", "xlayer"],
+ "title": "Data Streams Expands to New Blockchains",
+ "topic": "Data Streams"
+ },
+ {
+ "category": "deprecation",
+ "date": "2026-02-26",
+ "description": "We have announced the deprecation of select Data Feeds, scheduled for shutdown on March 12th, 2026. Check [the list of Deprecating Data Feeds to learn more](https://docs.chain.link/data-feeds/deprecating-feeds).",
+ "title": "Deprecating Data Feeds",
+ "topic": "Data Feeds"
+ },
+ {
+ "category": "release",
+ "date": "2026-02-26",
+ "description": "CRE CLI version 1.2.0 is now available. This release adds dynamic template fetching, new `cre templates` commands for managing template sources, and a new `cre account access` command for checking and requesting deployment access.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.1.0...v1.2.0)",
+ "title": "CRE CLI v1.2.0 — Dynamic Templates and Deploy Access Management",
+ "topic": "CRE"
+ },
+ {
+ "category": "release",
+ "date": "2026-02-25",
+ "description": "CRE now supports the Confidential HTTP capability for production workflows, allowing you to make privacy-preserving API calls with enclave execution. See the [Confidential HTTP](https://docs.chain.link/cre/capabilities/confidential-http) page for more information.",
+ "title": "CRE supports Confidential HTTP capability for production workflows",
+ "topic": "CRE"
+ },
+ {
+ "category": "integration",
+ "date": "2026-02-25",
+ "description": "Chainlink Data Streams is available for Canton. See the [Canton Integration](https://docs.chain.link/data-streams/canton-integration) page for more information.",
+ "relatedNetworks": ["canton"],
+ "title": "Data Streams Expands to Canton",
+ "topic": "Data Streams"
+ },
+ {
+ "category": "integration",
+ "date": "2026-02-22",
+ "description": "New Data Feeds available:",
+ "relatedNetworks": ["ethereum", "arbitrum"],
+ "relatedTokens": [
+ {
+ "assetName": "Swell Ethereum",
+ "baseAsset": "SWETH",
+ "quoteAsset": "ETH",
+ "network": "ethereum",
+ "url": "https://data.chain.link/feeds/ethereum/mainnet/sweth-eth",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/sweth.webp"
+ },
+ {
+ "assetName": "Swell Ethereum",
+ "baseAsset": "SWETH",
+ "quoteAsset": "ETH",
+ "network": "arbitrum",
+ "url": "https://data.chain.link/feeds/arbitrum/mainnet/sweth-eth",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/sweth.webp"
+ }
+ ],
+ "title": "Added support to Data Feeds",
+ "topic": "Data Feeds"
+ },
+ {
+ "category": "integration",
+ "date": "2026-02-22",
+ "description": "Newly supported tokens: USDi",
+ "relatedTokens": [
+ {
+ "assetName": "USDi Coin",
+ "baseAsset": "USDi",
+ "url": "https://docs.chain.link/ccip/directory/mainnet/token/USDi",
+ "iconUrl": "https://d2f70xi62kby8n.cloudfront.net/tokens/usdi.webp?auto=compress%2Cformat&q=60&w=40&h=40&fit=cover"
+ }
+ ],
+ "title": "Cross-chain token (CCT) standard: Added support for new tokens",
+ "topic": "CCIP"
+ },
{
"category": "integration",
"date": "2026-02-19",
diff --git a/public/images/cre/crosschain-replay-attack-vector-diagram.png b/public/images/cre/crosschain-replay-attack-vector-diagram.png
new file mode 100644
index 00000000000..968fe330866
Binary files /dev/null and b/public/images/cre/crosschain-replay-attack-vector-diagram.png differ
diff --git a/public/images/cre/same-chain-replay-on-failure.png b/public/images/cre/same-chain-replay-on-failure.png
new file mode 100644
index 00000000000..a4e8ffaa18e
Binary files /dev/null and b/public/images/cre/same-chain-replay-on-failure.png differ
diff --git a/src/content/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts.mdx b/src/content/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts.mdx
index f05c3f441e2..f4d3d8a7fd2 100644
--- a/src/content/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts.mdx
+++ b/src/content/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts.mdx
@@ -525,13 +525,170 @@ The deployment and configuration process involves these steps:
While the `setForwarderAddress()` function allows updating to `address(0)`, this disables the critical security check and allows **anyone** to call your `onReport()` function with arbitrary data. The function emits a `SecurityWarning` event if you attempt this. Only use `address(0)` for testing if you fully understand the implications.
-### Replay protection
+### Replay attacks
-The `KeystoneForwarder` contract includes built-in replay protection that prevents successful reports from being executed multiple times. By requiring the forwarder address at construction time, `ReceiverTemplate` ensures your consumer benefits from this protection automatically.
+CRE reports carry DON signatures that any compatible `KeystoneForwarder` will accept. This creates two distinct replay vectors that workflow authors must explicitly protect against by embedding protective metadata in their report payloads and verifying it in their consumer contracts.
+
+#### Cross-chain replay
+
+**The risk**: While publishing a single signed report to multiple chains simultaneously enables patterns like [Proof of Reserve (PoR)](/data-feeds/smartdata#proof-of-reserve-feeds) or feed-style publish-once-post-many, it also means **anyone holding a valid report can replay it on any chain that recognizes the DON's signing keys**.
+
+The forwarder validates cryptographic signatures but those signatures do not commit to a specific chain—without additional protection in your consumer contract, a replayed report can land on an unintended chain.
+
+
+
+**The mitigation**: Embed the target chain selector in the report payload. The consumer contract decodes this value and rejects reports not intended for the current chain. Chain selectors are `uint64` identifiers used throughout the CRE platform to identify blockchain networks — see [Chain Selectors](/cre/reference/sdk/evm-client-ts#chain-selectors) for the full list of constants and the `ChainSelectorFromName` helper.
+
+**Workflow (embed chain selector in the report payload):**
+
+```go
+// Define your report struct with a ChainSelector field.
+// ChainSelector is a uint64 — the same type used when instantiating evm.Client.
+type PaymentReport struct {
+ Recipient common.Address
+ Amount *big.Int
+ ChainSelector uint64 // Target chain — used by the consumer to reject cross-chain replays
+}
+
+paymentReport := PaymentReport{
+ Recipient: common.HexToAddress(config.Recipient),
+ Amount: big.NewInt(100_000_000), // e.g., 100 USDC (6 decimals)
+ ChainSelector: config.ChainSelector, // e.g., 16015286601757825753 for Ethereum Sepolia
+}
+
+// ABI-encode paymentReport and pass to runtime.GenerateReport() as normal
+```
+
+**Consumer contract (verify the embedded chain selector):**
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.26;
+
+import { ReceiverTemplate } from "./ReceiverTemplate.sol";
+import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+
+contract ChainRestrictedConsumer is ReceiverTemplate {
+ IERC20 public immutable i_token;
+ uint64 public immutable i_expectedChainSelector;
+
+ error UnexpectedChainSelector(uint64 received, uint64 expected);
+
+ constructor(
+ address _forwarderAddress,
+ address _token,
+ uint64 _expectedChainSelector
+ ) ReceiverTemplate(_forwarderAddress) {
+ i_token = IERC20(_token);
+ i_expectedChainSelector = _expectedChainSelector;
+ }
+
+ function _processReport(bytes calldata report) internal override {
+ (address recipient, uint256 amount, uint64 chainSelector) = abi.decode(
+ report,
+ (address, uint256, uint64)
+ );
+
+ if (chainSelector != i_expectedChainSelector) {
+ revert UnexpectedChainSelector(chainSelector, i_expectedChainSelector);
+ }
+
+ i_token.transfer(recipient, amount);
+ }
+}
+```
+
+#### Same-chain replay on failure
+
+**The risk**: While allowing failed deliveries to be retried without requiring a new signed report enables permissionless recovery from transient failures, it also means the forwarder does not mark reverted transmissions as used.
+
+**A malicious actor can exploit this window**: after your workflow has already reacted to a failure (for example, scheduled a corrective action), an attacker can replay the original signed report once conditions recover, causing double-execution.
+
+
+
+{/* prettier-ignore */}
+
+
+**The mitigation**: Embed the scheduled execution timestamp in the report payload. The consumer contract stores the last accepted timestamp and rejects any report with a timestamp equal to or earlier than the stored value. Once a later execution has been accepted, earlier failed reports can never land.
+
+{/* prettier-ignore */}
+
+
+**Workflow (embed scheduled execution timestamp in the report payload):**
+
+```go
+// Use the trigger's scheduled slot time — deterministic across all DON nodes.
+// Refer to the cron trigger reference for the exact field name on cron.Payload.
+scheduledAt := trigger.ScheduledAt.Unix()
+
+// Define your report struct with a ScheduledAt field
+type PaymentReport struct {
+ Recipient common.Address
+ Amount *big.Int
+ ScheduledAt *big.Int // Monotonic execution timestamp — used to reject stale replays
+}
+
+paymentReport := PaymentReport{
+ Recipient: common.HexToAddress(config.Recipient),
+ Amount: big.NewInt(100_000_000), // e.g., 100 USDC (6 decimals)
+ ScheduledAt: big.NewInt(scheduledAt),
+}
+
+// ABI-encode paymentReport and pass to runtime.GenerateReport() as normal
+```
+
+**Consumer contract (reject reports from earlier executions):**
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.26;
+
+import { ReceiverTemplate } from "./ReceiverTemplate.sol";
+import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+
+contract ScheduledPaymentConsumer is ReceiverTemplate {
+ IERC20 public immutable i_token;
+ uint256 public s_lastAcceptedTimestamp;
+
+ error ReportTooOld(uint256 reportTimestamp, uint256 lastAccepted);
+
+ event PaymentProcessed(address indexed recipient, uint256 amount, uint256 scheduledAt);
+
+ constructor(address _forwarderAddress, address _token) ReceiverTemplate(_forwarderAddress) {
+ i_token = IERC20(_token);
+ }
+
+ function _processReport(bytes calldata report) internal override {
+ (address recipient, uint256 amount, uint256 scheduledAt) = abi.decode(
+ report,
+ (address, uint256, uint256)
+ );
+
+ if (scheduledAt <= s_lastAcceptedTimestamp) {
+ revert ReportTooOld(scheduledAt, s_lastAcceptedTimestamp);
+ }
+
+ s_lastAcceptedTimestamp = scheduledAt;
+
+ i_token.transfer(recipient, amount);
+ emit PaymentProcessed(recipient, amount, scheduledAt);
+ }
+}
+```
{/* prettier-ignore */}
-
+{/* prettier-ignore */}
+
+ If your workflow performs state-changing actions (payments, minting, position updates), embed protective fields in the payload you ABI-encode **before** calling `runtime.report()`:
+
+- **Chain selector**: Include the target chain selector so the consumer contract can reject reports replayed on a different chain.
+- **Execution timestamp**: Include the cron trigger's scheduled slot time so the consumer can reject stale reports that were previously reverted and are being replayed by an attacker.
+
+See [Replay attacks](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#replay-attacks) in the Building Consumer Contracts guide for full Solidity and workflow code examples.
+
+
+
### Step 3: Generate the signed report
Convert the encoded data to base64 and generate a report:
diff --git a/src/content/cre/llms-full-go.txt b/src/content/cre/llms-full-go.txt
index 78c01a4cfb9..b426f7da5a0 100644
--- a/src/content/cre/llms-full-go.txt
+++ b/src/content/cre/llms-full-go.txt
@@ -3070,13 +3070,163 @@ The deployment and configuration process involves these steps:
While the `setForwarderAddress()` function allows updating to `address(0)`, this disables the critical security check and allows **anyone** to call your `onReport()` function with arbitrary data. The function emits a `SecurityWarning` event if you attempt this. Only use `address(0)` for testing if you fully understand the implications.
-### Replay protection
+### Replay attacks
+
+CRE reports carry DON signatures that any compatible `KeystoneForwarder` will accept. This creates two distinct replay vectors that workflow authors must explicitly protect against by embedding protective metadata in their report payloads and verifying it in their consumer contracts.
+
+#### Cross-chain replay
+
+**The risk**: While publishing a single signed report to multiple chains simultaneously enables patterns like [Proof of Reserve (PoR)](/data-feeds/smartdata#proof-of-reserve-feeds) or feed-style publish-once-post-many, it also means **anyone holding a valid report can replay it on any chain that recognizes the DON's signing keys**.
+
+The forwarder validates cryptographic signatures but those signatures do not commit to a specific chain—without additional protection in your consumer contract, a replayed report can land on an unintended chain.
+
+**The mitigation**: Embed the target chain selector in the report payload. The consumer contract decodes this value and rejects reports not intended for the current chain. Chain selectors are `uint64` identifiers used throughout the CRE platform to identify blockchain networks — see [Chain Selectors](/cre/reference/sdk/evm-client-ts#chain-selectors) for the full list of constants and the `ChainSelectorFromName` helper.
+
+**Workflow (embed chain selector in the report payload):**
+
+```go
+// Define your report struct with a ChainSelector field.
+// ChainSelector is a uint64 — the same type used when instantiating evm.Client.
+type PaymentReport struct {
+ Recipient common.Address
+ Amount *big.Int
+ ChainSelector uint64 // Target chain — used by the consumer to reject cross-chain replays
+}
+
+paymentReport := PaymentReport{
+ Recipient: common.HexToAddress(config.Recipient),
+ Amount: big.NewInt(100_000_000), // e.g., 100 USDC (6 decimals)
+ ChainSelector: config.ChainSelector, // e.g., 16015286601757825753 for Ethereum Sepolia
+}
+
+// ABI-encode paymentReport and pass to runtime.GenerateReport() as normal
+```
+
+**Consumer contract (verify the embedded chain selector):**
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.26;
+
+import { ReceiverTemplate } from "./ReceiverTemplate.sol";
+import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+
+contract ChainRestrictedConsumer is ReceiverTemplate {
+ IERC20 public immutable i_token;
+ uint64 public immutable i_expectedChainSelector;
+
+ error UnexpectedChainSelector(uint64 received, uint64 expected);
+
+ constructor(
+ address _forwarderAddress,
+ address _token,
+ uint64 _expectedChainSelector
+ ) ReceiverTemplate(_forwarderAddress) {
+ i_token = IERC20(_token);
+ i_expectedChainSelector = _expectedChainSelector;
+ }
+
+ function _processReport(bytes calldata report) internal override {
+ (address recipient, uint256 amount, uint64 chainSelector) = abi.decode(
+ report,
+ (address, uint256, uint64)
+ );
+
+ if (chainSelector != i_expectedChainSelector) {
+ revert UnexpectedChainSelector(chainSelector, i_expectedChainSelector);
+ }
+
+ i_token.transfer(recipient, amount);
+ }
+}
+```
+
+#### Same-chain replay on failure
+
+**The risk**: While allowing failed deliveries to be retried without requiring a new signed report enables permissionless recovery from transient failures, it also means the forwarder does not mark reverted transmissions as used.
+
+**A malicious actor can exploit this window**: after your workflow has already reacted to a failure (for example, scheduled a corrective action), an attacker can replay the original signed report once conditions recover, causing double-execution.
+
+
+
+ 1. A cron workflow attempts to pay a wallet $100 USDC. The consumer contract **reverts** (insufficient funds).
+ 2. CRE returns a reverted transaction hash. The workflow records the failure and plans to correct the balance on the next run.
+ 3. Funds are replenished — by the owner, another workflow, or a user deposit.
+ 4. An attacker (or a bot) replays the original signed report. The consumer now has funds and the payment **executes again** — the recipient is paid twice.
+
+
+**The mitigation**: Embed the scheduled execution timestamp in the report payload. The consumer contract stores the last accepted timestamp and rejects any report with a timestamp equal to or earlier than the stored value. Once a later execution has been accepted, earlier failed reports can never land.
+
+
+
+ The timestamp must be deterministic across all DON nodes so they agree during consensus. Use the cron trigger's scheduled execution slot time rather than `time.Now()`. Refer to the [cron trigger reference](/cre/reference/sdk/triggers/cron-trigger-go) for the exact field name on the trigger payload.
+
-The `KeystoneForwarder` contract includes built-in replay protection that prevents successful reports from being executed multiple times. By requiring the forwarder address at construction time, `ReceiverTemplate` ensures your consumer benefits from this protection automatically.
+**Workflow (embed scheduled execution timestamp in the report payload):**
+```go
+// Use the trigger's scheduled slot time — deterministic across all DON nodes.
+// Refer to the cron trigger reference for the exact field name on cron.Payload.
+scheduledAt := trigger.ScheduledAt.Unix()
+
+// Define your report struct with a ScheduledAt field
+type PaymentReport struct {
+ Recipient common.Address
+ Amount *big.Int
+ ScheduledAt *big.Int // Monotonic execution timestamp — used to reject stale replays
+}
+
+paymentReport := PaymentReport{
+ Recipient: common.HexToAddress(config.Recipient),
+ Amount: big.NewInt(100_000_000), // e.g., 100 USDC (6 decimals)
+ ScheduledAt: big.NewInt(scheduledAt),
+}
+
+// ABI-encode paymentReport and pass to runtime.GenerateReport() as normal
+```
+
+**Consumer contract (reject reports from earlier executions):**
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.26;
+
+import { ReceiverTemplate } from "./ReceiverTemplate.sol";
+import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+
+contract ScheduledPaymentConsumer is ReceiverTemplate {
+ IERC20 public immutable i_token;
+ uint256 public s_lastAcceptedTimestamp;
+
+ error ReportTooOld(uint256 reportTimestamp, uint256 lastAccepted);
+
+ event PaymentProcessed(address indexed recipient, uint256 amount, uint256 scheduledAt);
+
+ constructor(address _forwarderAddress, address _token) ReceiverTemplate(_forwarderAddress) {
+ i_token = IERC20(_token);
+ }
+
+ function _processReport(bytes calldata report) internal override {
+ (address recipient, uint256 amount, uint256 scheduledAt) = abi.decode(
+ report,
+ (address, uint256, uint256)
+ );
+
+ if (scheduledAt <= s_lastAcceptedTimestamp) {
+ revert ReportTooOld(scheduledAt, s_lastAcceptedTimestamp);
+ }
-
- If a report fails (reverts), the forwarder's replay protection allows it to be retried. This is safe because reverts undo all state changes, ensuring no duplicate effects occur in your contract.
+ s_lastAcceptedTimestamp = scheduledAt;
+
+ i_token.transfer(recipient, amount);
+ emit PaymentProcessed(recipient, amount, scheduledAt);
+ }
+}
+```
+
+
+
+ For maximum safety, embed both `chainSelector` and `scheduledAt` in a single report struct. This protects against cross-chain and same-chain replay simultaneously with one encoding step.
### Additional validation layers
@@ -3107,9 +3257,13 @@ The forwarder address provides baseline security, but you can add additional val
- **Single workflow**: Use `setExpectedWorkflowId()` to restrict to one specific workflow (highest security)
- **Multiple workflows from same owner**: Use `setExpectedAuthor()` to restrict to workflows you own
- **Multiple workflows from different owners**: Implement custom validation logic in your `onReport()` override
-3. **Keep your owner key secure** - The owner can update all permission settings
-4. **Test permission configurations** - Verify your security settings work as expected before production deployment
-5. **Workflow name validation** - Can be used with `setExpectedWorkflowName()` but requires `setExpectedAuthor()` to also be configured for security
+3. **Protect against replay attacks** - For any workflow that performs state-changing actions (payments, minting, position updates):
+ - Embed the **target chain selector** in the report payload and verify it in `_processReport` to prevent cross-chain replay
+ - Embed a **monotonic execution timestamp** from the cron trigger and reject reports with a timestamp ≤ the last accepted value to prevent same-chain replay on failure
+ - See [Replay attacks](#replay-attacks) for complete code examples
+4. **Keep your owner key secure** - The owner can update all permission settings
+5. **Test permission configurations** - Verify your security settings work as expected before production deployment
+6. **Workflow name validation** - Can be used with `setExpectedWorkflowName()` but requires `setExpectedAuthor()` to also be configured for security
---
@@ -3530,6 +3684,16 @@ This report is designed to be passed directly to either:
- `evm.Client.WriteReport()` for onchain delivery
- `http.Client` for offchain delivery
+
+
+ If your workflow performs state-changing actions (payments, minting, position updates), embed protective metadata in the payload you pass to `runtime.GenerateReport()`:
+
+ - **Chain selector**: Include the target chain selector so the consumer contract can reject reports replayed on a different chain.
+ - **Execution timestamp**: Include the cron trigger's scheduled slot time so the consumer can reject stale reports that were previously reverted and are being replayed by an attacker.
+
+ See [Replay attacks](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#replay-attacks) in the Building Consumer Contracts guide for full code examples.
+
+
### 4. Submit the report
Now that you have a generated report, choose where to send it:
@@ -3776,6 +3940,16 @@ This report is designed to be passed directly to either:
- `evm.Client.WriteReport()` for onchain delivery
- `http.Client` for offchain delivery
+
+
+ If your workflow performs state-changing actions (payments, minting, position updates), add protective fields to your struct before encoding:
+
+ - **Chain selector**: Include the target chain selector so the consumer contract can reject reports replayed on a different chain.
+ - **Execution timestamp**: Include the cron trigger's scheduled slot time so the consumer can reject stale reports that were previously reverted and are being replayed by an attacker.
+
+ See [Replay attacks](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#replay-attacks) in the Building Consumer Contracts guide for full code examples.
+
+
The report can now be [submitted onchain](/cre/guides/workflow/using-evm-client/onchain-write/submitting-reports-onchain) or [sent via HTTP](/cre/guides/workflow/using-http-client/submitting-reports-http).
## Manual encoding
@@ -4120,6 +4294,11 @@ type WriteReportReply struct {
- **`ReceiverContractExecutionStatus`**: Whether your consumer contract's `onReport()` function executed successfully
- **`ErrorMessage`**: If the transaction failed, this field contains details about what went wrong
+
+
+ A signed report can be replayed on a different chain or resubmitted on the same chain after a revert. If your workflow performs state-changing actions, embed a chain selector and a scheduled execution timestamp in your report payload **before** calling `WriteReport()`, and verify them in your consumer contract. See [Replay attacks](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#replay-attacks) for full examples.
+
+
## Best practices
When submitting reports onchain, follow these practices to ensure reliability and observability:
@@ -4295,6 +4474,7 @@ See the [CLI Reference](/cre/reference/cli/workflow#cre-workflow-simulate) for m
- Verify your consumer contract implements the `IReceiver` interface correctly (see [Building Consumer Contracts](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts))
- Review your consumer contract's `onReport()` validation logic—it may be rejecting the report
- Ensure the report data format matches what your consumer contract expects
+- **Important**: A reverted transaction opens a replay window. The forwarder does not mark reverted reports as used, meaning anyone can resubmit the signed report once conditions change. If your workflow takes corrective action after seeing a revert, see [Same-chain replay on failure](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#same-chain-replay-on-failure) for how to protect against double-execution
**"out of gas" error or transaction runs out of gas**
@@ -13069,6 +13249,11 @@ Here's the journey your workflow's data takes to reach the blockchain:
Your workflow code handles this process using the [`evm.Client`](/cre/reference/sdk/evm-client), which manages the interaction with the Forwarder contract. Depending on your approach (covered below), this can be fully automated via generated binding helpers or done manually with direct client calls.
+
+
+ Signed reports can be replayed on a different chain or resubmitted on the same chain after a revert. For any workflow that performs state-changing actions, you must embed protective metadata in the report payload and verify it in your consumer contract. See [Replay attacks](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#replay-attacks) for full examples.
+
+
## What you need: A consumer contract
Before you can write data onchain, you need a **consumer contract**. This is the smart contract that will receive your workflow's data.
diff --git a/src/content/cre/llms-full-ts.txt b/src/content/cre/llms-full-ts.txt
index 9ae4619811f..5ecc4acdf00 100644
--- a/src/content/cre/llms-full-ts.txt
+++ b/src/content/cre/llms-full-ts.txt
@@ -3056,13 +3056,163 @@ The deployment and configuration process involves these steps:
While the `setForwarderAddress()` function allows updating to `address(0)`, this disables the critical security check and allows **anyone** to call your `onReport()` function with arbitrary data. The function emits a `SecurityWarning` event if you attempt this. Only use `address(0)` for testing if you fully understand the implications.
-### Replay protection
+### Replay attacks
+
+CRE reports carry DON signatures that any compatible `KeystoneForwarder` will accept. This creates two distinct replay vectors that workflow authors must explicitly protect against by embedding protective metadata in their report payloads and verifying it in their consumer contracts.
+
+#### Cross-chain replay
+
+**The risk**: While publishing a single signed report to multiple chains simultaneously enables patterns like [Proof of Reserve (PoR)](/data-feeds/smartdata#proof-of-reserve-feeds) or feed-style publish-once-post-many, it also means **anyone holding a valid report can replay it on any chain that recognizes the DON's signing keys**.
+
+The forwarder validates cryptographic signatures but those signatures do not commit to a specific chain—without additional protection in your consumer contract, a replayed report can land on an unintended chain.
+
+**The mitigation**: Embed the target chain selector in the report payload. The consumer contract decodes this value and rejects reports not intended for the current chain. Chain selectors are `uint64` identifiers used throughout the CRE platform to identify blockchain networks — see [Chain Selectors](/cre/reference/sdk/evm-client-ts#chain-selectors) for the full list of constants and the `ChainSelectorFromName` helper.
+
+**Workflow (embed chain selector in the report payload):**
+
+```go
+// Define your report struct with a ChainSelector field.
+// ChainSelector is a uint64 — the same type used when instantiating evm.Client.
+type PaymentReport struct {
+ Recipient common.Address
+ Amount *big.Int
+ ChainSelector uint64 // Target chain — used by the consumer to reject cross-chain replays
+}
+
+paymentReport := PaymentReport{
+ Recipient: common.HexToAddress(config.Recipient),
+ Amount: big.NewInt(100_000_000), // e.g., 100 USDC (6 decimals)
+ ChainSelector: config.ChainSelector, // e.g., 16015286601757825753 for Ethereum Sepolia
+}
+
+// ABI-encode paymentReport and pass to runtime.GenerateReport() as normal
+```
+
+**Consumer contract (verify the embedded chain selector):**
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.26;
+
+import { ReceiverTemplate } from "./ReceiverTemplate.sol";
+import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+
+contract ChainRestrictedConsumer is ReceiverTemplate {
+ IERC20 public immutable i_token;
+ uint64 public immutable i_expectedChainSelector;
+
+ error UnexpectedChainSelector(uint64 received, uint64 expected);
+
+ constructor(
+ address _forwarderAddress,
+ address _token,
+ uint64 _expectedChainSelector
+ ) ReceiverTemplate(_forwarderAddress) {
+ i_token = IERC20(_token);
+ i_expectedChainSelector = _expectedChainSelector;
+ }
+
+ function _processReport(bytes calldata report) internal override {
+ (address recipient, uint256 amount, uint64 chainSelector) = abi.decode(
+ report,
+ (address, uint256, uint64)
+ );
+
+ if (chainSelector != i_expectedChainSelector) {
+ revert UnexpectedChainSelector(chainSelector, i_expectedChainSelector);
+ }
+
+ i_token.transfer(recipient, amount);
+ }
+}
+```
+
+#### Same-chain replay on failure
+
+**The risk**: While allowing failed deliveries to be retried without requiring a new signed report enables permissionless recovery from transient failures, it also means the forwarder does not mark reverted transmissions as used.
+
+**A malicious actor can exploit this window**: after your workflow has already reacted to a failure (for example, scheduled a corrective action), an attacker can replay the original signed report once conditions recover, causing double-execution.
+
+
+
+ 1. A cron workflow attempts to pay a wallet $100 USDC. The consumer contract **reverts** (insufficient funds).
+ 2. CRE returns a reverted transaction hash. The workflow records the failure and plans to correct the balance on the next run.
+ 3. Funds are replenished — by the owner, another workflow, or a user deposit.
+ 4. An attacker (or a bot) replays the original signed report. The consumer now has funds and the payment **executes again** — the recipient is paid twice.
+
+
+**The mitigation**: Embed the scheduled execution timestamp in the report payload. The consumer contract stores the last accepted timestamp and rejects any report with a timestamp equal to or earlier than the stored value. Once a later execution has been accepted, earlier failed reports can never land.
+
+
+
+ The timestamp must be deterministic across all DON nodes so they agree during consensus. Use the cron trigger's scheduled execution slot time rather than `time.Now()`. Refer to the [cron trigger reference](/cre/reference/sdk/triggers/cron-trigger-go) for the exact field name on the trigger payload.
+
+
+**Workflow (embed scheduled execution timestamp in the report payload):**
+
+```go
+// Use the trigger's scheduled slot time — deterministic across all DON nodes.
+// Refer to the cron trigger reference for the exact field name on cron.Payload.
+scheduledAt := trigger.ScheduledAt.Unix()
+
+// Define your report struct with a ScheduledAt field
+type PaymentReport struct {
+ Recipient common.Address
+ Amount *big.Int
+ ScheduledAt *big.Int // Monotonic execution timestamp — used to reject stale replays
+}
+
+paymentReport := PaymentReport{
+ Recipient: common.HexToAddress(config.Recipient),
+ Amount: big.NewInt(100_000_000), // e.g., 100 USDC (6 decimals)
+ ScheduledAt: big.NewInt(scheduledAt),
+}
+
+// ABI-encode paymentReport and pass to runtime.GenerateReport() as normal
+```
+
+**Consumer contract (reject reports from earlier executions):**
+
+```solidity
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.26;
+
+import { ReceiverTemplate } from "./ReceiverTemplate.sol";
+import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+
+contract ScheduledPaymentConsumer is ReceiverTemplate {
+ IERC20 public immutable i_token;
+ uint256 public s_lastAcceptedTimestamp;
+
+ error ReportTooOld(uint256 reportTimestamp, uint256 lastAccepted);
+
+ event PaymentProcessed(address indexed recipient, uint256 amount, uint256 scheduledAt);
+
+ constructor(address _forwarderAddress, address _token) ReceiverTemplate(_forwarderAddress) {
+ i_token = IERC20(_token);
+ }
-The `KeystoneForwarder` contract includes built-in replay protection that prevents successful reports from being executed multiple times. By requiring the forwarder address at construction time, `ReceiverTemplate` ensures your consumer benefits from this protection automatically.
+ function _processReport(bytes calldata report) internal override {
+ (address recipient, uint256 amount, uint256 scheduledAt) = abi.decode(
+ report,
+ (address, uint256, uint256)
+ );
+ if (scheduledAt <= s_lastAcceptedTimestamp) {
+ revert ReportTooOld(scheduledAt, s_lastAcceptedTimestamp);
+ }
-
- If a report fails (reverts), the forwarder's replay protection allows it to be retried. This is safe because reverts undo all state changes, ensuring no duplicate effects occur in your contract.
+ s_lastAcceptedTimestamp = scheduledAt;
+
+ i_token.transfer(recipient, amount);
+ emit PaymentProcessed(recipient, amount, scheduledAt);
+ }
+}
+```
+
+
+
+ For maximum safety, embed both `chainSelector` and `scheduledAt` in a single report struct. This protects against cross-chain and same-chain replay simultaneously with one encoding step.
### Additional validation layers
@@ -3093,9 +3243,13 @@ The forwarder address provides baseline security, but you can add additional val
- **Single workflow**: Use `setExpectedWorkflowId()` to restrict to one specific workflow (highest security)
- **Multiple workflows from same owner**: Use `setExpectedAuthor()` to restrict to workflows you own
- **Multiple workflows from different owners**: Implement custom validation logic in your `onReport()` override
-3. **Keep your owner key secure** - The owner can update all permission settings
-4. **Test permission configurations** - Verify your security settings work as expected before production deployment
-5. **Workflow name validation** - Can be used with `setExpectedWorkflowName()` but requires `setExpectedAuthor()` to also be configured for security
+3. **Protect against replay attacks** - For any workflow that performs state-changing actions (payments, minting, position updates):
+ - Embed the **target chain selector** in the report payload and verify it in `_processReport` to prevent cross-chain replay
+ - Embed a **monotonic execution timestamp** from the cron trigger and reject reports with a timestamp ≤ the last accepted value to prevent same-chain replay on failure
+ - See [Replay attacks](#replay-attacks) for complete code examples
+4. **Keep your owner key secure** - The owner can update all permission settings
+5. **Test permission configurations** - Verify your security settings work as expected before production deployment
+6. **Workflow name validation** - Can be used with `setExpectedWorkflowName()` but requires `setExpectedAuthor()` to also be configured for security
---
@@ -3201,6 +3355,16 @@ const reportData = encodeAbiParameters(parseAbiParameters("bool"), [true])
When scaling values to match a token's decimals (e.g., converting `"1.5"` to `1500000000000000000n`), use viem's `parseUnits()` instead of `BigInt(value * 1e18)`. Floating-point multiplication causes silent precision loss. See [Safe decimal scaling](/cre/getting-started/before-you-build-ts#safe-decimal-scaling) for details and examples.
+
+
+ If your workflow performs state-changing actions (payments, minting, position updates), embed protective fields in the payload you ABI-encode **before** calling `runtime.report()`:
+
+ - **Chain selector**: Include the target chain selector so the consumer contract can reject reports replayed on a different chain.
+ - **Execution timestamp**: Include the cron trigger's scheduled slot time so the consumer can reject stale reports that were previously reverted and are being replayed by an attacker.
+
+ See [Replay attacks](/cre/guides/workflow/using-evm-client/onchain-write/building-consumer-contracts#replay-attacks) in the Building Consumer Contracts guide for full Solidity and workflow code examples.
+
+
### Step 3: Generate the signed report
Convert the encoded data to base64 and generate a report: