mbhound
mbhound

Reputation: 33

Can chainlink external adapters be made so they can only called by a specific smart contract?

I want to make an external adapter which can only be called by a specific function in a smart contract so that I can assure that the caller is an authorized address. Is anyone able to make a call to an external adapter or can I restrict it to a certain smart contract? If anyone is able to make a call, is there a way for me to ensure that the caller is from the smart contract?

What I am trying to do is to have a smart contract which can provide a decryption key for a file. Essentially, the smart contract would store a decryption key encrypted to the adapter's public key. Then, when an event in the smart contract occurs where someone should gain access to the file, the smart contract makes a call to the adapter. The adapter would then take the encrypted decryption key, decrypt it, and return the decryption key encrypted to the recipient's public key. The smart contract would then receive the decryption key encrypted to the recipient's public key and store this so that the recipient could use this to decrypt the file. Is something like this possible with an external adapter?

Upvotes: 3

Views: 255

Answers (2)

Pedro Henrique Bufulin
Pedro Henrique Bufulin

Reputation: 769

If whitelisting addresses doesn't do the trick, I believe you can do the following to the oracle contract:


    /**
     * @notice Creates the Chainlink request. This is a backwards compatible API
     * with the Oracle.sol contract, but the behavior changes because
     * callbackAddress is assumed to be the same as the request sender.
     * @param callbackAddress The consumer of the request
     * @param payment The amount of payment given (specified in wei)
     * @param specId The Job Specification ID
     * @param callbackAddress The address the oracle data will be sent to
     * @param callbackFunctionId The callback function ID for the response
     * @param nonce The nonce sent by the requester
     * @param dataVersion The specified data version
     * @param data The extra request parameters
     */
    function oracleRequest(
        address sender,
        uint256 payment,
        bytes32 specId,
        address callbackAddress,
        bytes4 callbackFunctionId,
        uint256 nonce,
        uint256 dataVersion,
        bytes calldata data
    ) external override validateFromLINK validateIsAuthorizedConsumer(sender) {
        revert("use the operatorRequest only");
    }

    /**
     * @notice Creates the Chainlink request
     * @dev Stores the hash of the params as the on-chain commitment for the request.
     * Emits OracleRequest event for the Chainlink node to detect.
     * @param sender The sender of the request
     * @param payment The amount of payment given (specified in wei)
     * @param specId The Job Specification ID
     * @param callbackFunctionId The callback function ID for the response
     * @param nonce The nonce sent by the requester
     * @param dataVersion The specified data version
     * @param data The extra request parameters
     */
    function operatorRequest(
        address sender,
        uint256 payment,
        bytes32 specId,
        bytes4 callbackFunctionId,
        uint256 nonce,
        uint256 dataVersion,
        bytes calldata data
    ) external override validateIsAuthorizedConsumer(sender) validateFromLINK {
        (
            bytes32 requestId,
            uint256 expiration
        ) = _verifyAndProcessOracleRequest(
                sender,
                payment,
                sender,
                callbackFunctionId,
                nonce,
                dataVersion
            );
        emit OracleRequest(
            specId,
            sender,
            requestId,
            payment,
            sender,
            callbackFunctionId,
            expiration,
            dataVersion,
            data
        );
    }

I removed the oracleRequest() function because it exceeds stack size by adding more modifiers to it and since I can use operatorRequest() to fulfill both multi-word and single-word requests I will make that method deprecated by reverting everytime it's called.

The modifier that sets the authorized consumer is basically the following:

    /**
     * @dev function used to change the authorized consumer. Can only be set once
     */
    function setAuthorizedConsumer(address _consumer) public onlyOwner {
        require(
            authorizedConsumer == address(0),
            "authorized consumer is already set"
        );
        authorizedConsumer = _consumer;
    }

    /**
     * @notice validates the consumer is an authorized consumer
     */
    function _validateIsAuthorizedConsumer(address _consumer) internal view {
        require(_consumer == authorizedConsumer, "Not authorized sender");
    }

    /**
     * @notice prevents non-authorized addresses from calling this method
     */
    modifier validateIsAuthorizedConsumer(address _consumer) {
        _validateIsAuthorizedConsumer(_consumer);
        _;
    }


Upvotes: 0

Roger LinkRiver
Roger LinkRiver

Reputation: 106

You can restrict the access by adding whitelisted requesters (authorized smart contract addresses) to the database of the Chainlink node that is picking up your requests and running the job calling your external adapter.

We wrote a short guide on how to do this: https://github.com/Linkriver/Chainlink-node-whitelisting

Upvotes: 2

Related Questions