// SPDX-License-Identifier: MIT pragma solidity ^0.7.0; abstract contract LinkTokenReceiver { bytes4 constant private ORACLE_REQUEST_SELECTOR = 0x40429946; uint256 constant private SELECTOR_LENGTH = 4; uint256 constant private EXPECTED_REQUEST_WORDS = 2; uint256 constant private MINIMUM_REQUEST_LENGTH = SELECTOR_LENGTH + (32 * EXPECTED_REQUEST_WORDS); /** * @notice Called when LINK is sent to the contract via `transferAndCall` * @dev The data payload's first 2 words will be overwritten by the `sender` and `amount` * values to ensure correctness. Calls oracleRequest. * @param sender Address of the sender * @param amount Amount of LINK sent (specified in wei) * @param data Payload of the transaction */ function onTokenTransfer( address sender, uint256 amount, bytes memory data ) public onlyLINK validRequestLength(data) permittedFunctionsForLINK(data) { assembly { // solhint-disable-next-line avoid-low-level-calls mstore(add(data, 36), sender) // ensure correct sender is passed // solhint-disable-next-line avoid-low-level-calls mstore(add(data, 68), amount) // ensure correct amount is passed } // solhint-disable-next-line avoid-low-level-calls (bool success, ) = address(this).delegatecall(data); // calls oracleRequest require(success, "Unable to create request"); } function getChainlinkToken() public view virtual returns (address); /** * @dev Reverts if not sent from the LINK token */ modifier onlyLINK() { require(msg.sender == getChainlinkToken(), "Must use LINK token"); _; } /** * @dev Reverts if the given data does not begin with the `oracleRequest` function selector * @param data The data payload of the request */ modifier permittedFunctionsForLINK(bytes memory data) { bytes4 funcSelector; assembly { // solhint-disable-next-line avoid-low-level-calls funcSelector := mload(add(data, 32)) } require(funcSelector == ORACLE_REQUEST_SELECTOR, "Must use whitelisted functions"); _; } /** * @dev Reverts if the given payload is less than needed to create a request * @param data The request payload */ modifier validRequestLength(bytes memory data) { require(data.length >= MINIMUM_REQUEST_LENGTH, "Invalid request length"); _; } }