1

I'm here for asking some tips on calling function from other contracts in solidity. Here is the function for generating a random number (which I need in the main contract) using the chainlink VRF. RandomNumberConsumer.sol

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.6;

import "https://raw.githubusercontent.com/smartcontractkit/chainlink/master/evm-contracts/src/v0.6/VRFConsumerBase.sol"; //import of the VRFConsumerBase for generating random data
import "./MAIN.sol";

contract RandomNumberConsumer is VRFConsumerBase {
    
    MAIN internal cnrfContract;
    
    bytes32 internal keyHash;
    uint256 internal fee;
    
    /**
     * Constructor inherits VRFConsumerBase
     * 
     * Network: Kovan
     * Chainlink VRF Coordinator address: 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9
     * LINK token address:                0xa36085F69e2889c224210F603D836748e7dC0088
     * Key Hash: 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4
     */
    constructor(MAIN addr) 
        VRFConsumerBase(
            0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9, // VRF Coordinator
            0xa36085F69e2889c224210F603D836748e7dC0088  // LINK Token
        ) public
    {
        keyHash = 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4;
        fee = 0.1 * 10 ** 18; // 0.1 LINK
        cnrfContract = MAIN(addr);
    }
    
    /** 
     * Requests randomness from a user-provided seed
     */
    function getRandomNumber(uint256 userProvidedSeed) internal returns (bytes32 requestId) {
        require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
        return requestRandomness(keyHash, fee, userProvidedSeed);
    }

    /**
     * Callback function used by VRF Coordinator
     */
    function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
        //get the carId on our list to set the DNA
        uint carId = cnrfContract.randomFuncRequestIdToCarId(requestId);
        //edit the dna by passing the random dna generated from the oracle
        cnrfContract.editDna(randomness, carId, requestId);
    }
}

this generated number is then passed to the editDna() function in this MAIN.sol contract:

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.6.6;

import "./Ownable.sol";
import "./Safemath.sol";
import "./RandomNumberConsumer.sol";
contract MAIN is Ownable, RandomNumberConsumer(this) {
    [...]
    //dna max digit is 12: ex.  58_21_63_49_85_21_56   ->  58216349852156
    uint dnaDigits = 14;
    //for shrinking the randomNumber and get the correct number of digits
    uint dnaModulus = 10 ** dnaDigits;
   
    //using SafeMath to prevent overflow/underflow of intergers
    using SafeMath for uint256;
    using SafeMath32 for uint32;
    using SafeMath16 for uint16;

    function editDna(uint randomN, uint carId, bytes32 requestId) public {
        //!!!!!!!!!!!**************should check that an external address can't call this function!!!!!!!!!!!**************
        require(msg.sender == address(this));
        //unique DNA generation
        require(carsList[carId].requestIdProcessed == requestId);
        
        //get only x digits of the random number (check variable dnaDigits)
        carsList[carId].carDna = randomN % dnaModulus;
        //set to 0 to be uniquely changed once
        carsList[carId].requestIdProcessed = 0;
        
        emit NewCar(carId, carsList[carId].name, carsList[carId].carDna);
    }
    
    [...]
}

I need to check that the function editDna() can be called only from the contract RandomNumberConsumer.sol and not from any address which sees it as public. [It needs to be public because you need it to call it from another contract]

So the problem is that I don't want a random address to call that function and change my dna variable, so I put "require(msg.sender == address(this));" to check if the caller of the function is the contract itself, but I don't know if it's the correct way to check this security issue.It seems like working, but i'm not really sure about that. Can anyone help me? Thanks in advance, Simone. Sorry for my english :P

1

If the MAIN contract inherits from RandomNumberConsumer making editDna internal should be enough.

// Declare contract as abstract
abstract contract RandomNumberConsumer is VRFConsumerBase {
    // Forward declaration
    function editDna(uint randomN, uint carId, bytes32 requestId) internal virtual;

    constructor() VRFConsumerBase(..) public {
        ..
    }

    function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
        .. 
        editDna(randomness, carId, requestId);
    }
}


contract MAIN is Ownable, RandomNumberConsumer {
    ..
    function editDna(uint randomN, uint carId, bytes32 requestId) internal override {
        ..
    }
}
3
  • remix ide is telling me:" member editdna not found or visible after argument dependent lookup in contract." – Simone Tosatto Feb 20 at 17:32
  • @SimoneTosatto Check now, the function editDna has to be forward declared and RandomNumberConsumer should be declared as abstract. – Ismael Feb 20 at 17:46
  • I've fixed the problem by using all this functions in the same solidity file, so no problem in visibility :P. Thanks anyway! Have a nice day! – Simone Tosatto Feb 20 at 18:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.