// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {CBOR} from "../../../../vendor/solidity-cborutils/v2.0.0/CBOR.sol"; /// @title Library for encoding the input data of a Functions request into CBOR library FunctionsRequest { using CBOR for CBOR.CBORBuffer; uint16 public constant REQUEST_DATA_VERSION = 1; uint256 internal constant DEFAULT_BUFFER_SIZE = 256; enum Location { Inline, // Provided within the Request Remote, // Hosted through remote location that can be accessed through a provided URL DONHosted // Hosted on the DON's storage } enum CodeLanguage { JavaScript } // In future version we may add other languages struct Request { Location codeLocation; // ════════════╸ The location of the source code that will be // executed on each node in the DON Location secretsLocation; // ═════════╸ The location of secrets that will be passed into the // source code. *Only Remote secrets are supported CodeLanguage language; // ════════════╸ The coding language that the source code is written in string source; // ════════════════════╸ Raw source code for // Request.codeLocation of Location.Inline, URL for Request.codeLocation of Location.Remote, or slot decimal // number for Request.codeLocation of Location.DONHosted bytes encryptedSecretsReference; // ══╸ Encrypted URLs for Request.secretsLocation of Location.Remote (use // addSecretsReference()), or CBOR encoded slotid+version for Request.secretsLocation of Location.DONHosted (use // addDONHostedSecrets()) string[] args; // ════════════════════╸ String arguments that will be passed into the source code bytes[] bytesArgs; // ════════════════╸ Bytes arguments that will be passed into the source code } error EmptySource(); error EmptySecrets(); error EmptyArgs(); error NoInlineSecrets(); /// @notice Encodes a Request to CBOR encoded bytes /// @param self The request to encode /// @return CBOR encoded bytes function _encodeCBOR( Request memory self ) internal pure returns (bytes memory) { CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE); buffer.writeString("codeLocation"); buffer.writeUInt256(uint256(self.codeLocation)); buffer.writeString("language"); buffer.writeUInt256(uint256(self.language)); buffer.writeString("source"); buffer.writeString(self.source); if (self.args.length > 0) { buffer.writeString("args"); buffer.startArray(); for (uint256 i = 0; i < self.args.length; ++i) { buffer.writeString(self.args[i]); } buffer.endSequence(); } if (self.encryptedSecretsReference.length > 0) { if (self.secretsLocation == Location.Inline) { revert NoInlineSecrets(); } buffer.writeString("secretsLocation"); buffer.writeUInt256(uint256(self.secretsLocation)); buffer.writeString("secrets"); buffer.writeBytes(self.encryptedSecretsReference); } if (self.bytesArgs.length > 0) { buffer.writeString("bytesArgs"); buffer.startArray(); for (uint256 i = 0; i < self.bytesArgs.length; ++i) { buffer.writeBytes(self.bytesArgs[i]); } buffer.endSequence(); } return buffer.buf.buf; } /// @notice Initializes a Chainlink Functions Request /// @dev Sets the codeLocation and code on the request /// @param self The uninitialized request /// @param codeLocation The user provided source code location /// @param language The programming language of the user code /// @param source The user provided source code or a url function _initializeRequest( Request memory self, Location codeLocation, CodeLanguage language, string memory source ) internal pure { if (bytes(source).length == 0) revert EmptySource(); self.codeLocation = codeLocation; self.language = language; self.source = source; } /// @notice Initializes a Chainlink Functions Request /// @dev Simplified version of initializeRequest for PoC /// @param self The uninitialized request /// @param javaScriptSource The user provided JS code (must not be empty) function _initializeRequestForInlineJavaScript(Request memory self, string memory javaScriptSource) internal pure { _initializeRequest(self, Location.Inline, CodeLanguage.JavaScript, javaScriptSource); } /// @notice Adds Remote user encrypted secrets to a Request /// @param self The initialized request /// @param encryptedSecretsReference Encrypted comma-separated string of URLs pointing to off-chain secrets function _addSecretsReference(Request memory self, bytes memory encryptedSecretsReference) internal pure { if (encryptedSecretsReference.length == 0) revert EmptySecrets(); self.secretsLocation = Location.Remote; self.encryptedSecretsReference = encryptedSecretsReference; } /// @notice Adds DON-hosted secrets reference to a Request /// @param self The initialized request /// @param slotID Slot ID of the user's secrets hosted on DON /// @param version User data version (for the slotID) function _addDONHostedSecrets(Request memory self, uint8 slotID, uint64 version) internal pure { CBOR.CBORBuffer memory buffer = CBOR.create(DEFAULT_BUFFER_SIZE); buffer.writeString("slotID"); buffer.writeUInt64(slotID); buffer.writeString("version"); buffer.writeUInt64(version); self.secretsLocation = Location.DONHosted; self.encryptedSecretsReference = buffer.buf.buf; } /// @notice Sets args for the user run function /// @param self The initialized request /// @param args The array of string args (must not be empty) function _setArgs(Request memory self, string[] memory args) internal pure { if (args.length == 0) revert EmptyArgs(); self.args = args; } /// @notice Sets bytes args for the user run function /// @param self The initialized request /// @param args The array of bytes args (must not be empty) function _setBytesArgs(Request memory self, bytes[] memory args) internal pure { if (args.length == 0) revert EmptyArgs(); self.bytesArgs = args; } }