// SPDX-License-Identifier: MIT pragma solidity ^0.8.6; import {CBORChainlink} from "../../vendor/CBORChainlink.sol"; import {BufferChainlink} from "../../vendor/BufferChainlink.sol"; /** * @title Library for Chainlink Functions */ library Functions { uint256 internal constant DEFAULT_BUFFER_SIZE = 256; using CBORChainlink for BufferChainlink.buffer; enum Location { Inline, Remote } enum CodeLanguage { JavaScript // In future version we may add other languages } struct Request { Location codeLocation; Location secretsLocation; CodeLanguage language; string source; // Source code for Location.Inline or url for Location.Remote bytes secrets; // Encrypted secrets blob for Location.Inline or url for Location.Remote string[] args; } error EmptySource(); error EmptyUrl(); error EmptySecrets(); error EmptyArgs(); /** * @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) { BufferChainlink.buffer memory buf; BufferChainlink.init(buf, DEFAULT_BUFFER_SIZE); buf.encodeString("codeLocation"); buf.encodeUInt(uint256(self.codeLocation)); buf.encodeString("language"); buf.encodeUInt(uint256(self.language)); buf.encodeString("source"); buf.encodeString(self.source); if (self.args.length > 0) { buf.encodeString("args"); buf.startArray(); for (uint256 i = 0; i < self.args.length; i++) { buf.encodeString(self.args[i]); } buf.endSequence(); } if (self.secrets.length > 0) { buf.encodeString("secretsLocation"); buf.encodeUInt(uint256(self.secretsLocation)); buf.encodeString("secrets"); buf.encodeBytes(self.secrets); } return buf.buf; } /** * @notice Initializes a Chainlink Functions Request * @dev Sets the codeLocation and code on the request * @param self The uninitialized request * @param location 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 location, CodeLanguage language, string memory source ) internal pure { if (bytes(source).length == 0) revert EmptySource(); self.codeLocation = location; 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 Inline user encrypted secrets to a Request * @param self The initialized request * @param secrets The user encrypted secrets (must not be empty) */ function addInlineSecrets(Request memory self, bytes memory secrets) internal pure { if (secrets.length == 0) revert EmptySecrets(); self.secretsLocation = Location.Inline; self.secrets = secrets; } /** * @notice Adds Remote user encrypted secrets to a Request * @param self The initialized request * @param encryptedSecretsURLs Encrypted comma-separated string of URLs pointing to off-chain secrets */ function addRemoteSecrets(Request memory self, bytes memory encryptedSecretsURLs) internal pure { if (encryptedSecretsURLs.length == 0) revert EmptySecrets(); self.secretsLocation = Location.Remote; self.secrets = encryptedSecretsURLs; } /** * @notice Adds args for the user run function * @param self The initialized request * @param args The array of args (must not be empty) */ function addArgs(Request memory self, string[] memory args) internal pure { if (args.length == 0) revert EmptyArgs(); self.args = args; } }