0

I'm trying to create a contract factory that creates "Oracles". Oracles have state variables that are initialized in the contract constructor, and I'm trying to use Truffle Test to verify that those values are what I'm expecting them to be.

I'm operating under the assumption that public state variables generate a getter function, so in the case of "string public dataType", it should generate a function that would return that string.

I'm trying to use the function from the contract factory Aggregator.sol, "createOracle" to generate a contract. That seems to work, but I run into issues when I try to check that the parameter values in the oracle.sol constructor are set. Running "truffle test" has 'testUserCanCreateSensor' "failing with Error: Returned error: VM Exception while processing transaction: revert". What can I do to verify the values in oracle contract without triggering this error?

testAggregator.sol

pragma solidity ^0.5.0;

import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/aggregator.sol";

contract TestAggregator{
   Aggregator a = Aggregator(DeployedAddresses.Aggregator());

   function testUserCanCreateSensor() public {
      string memory dtype = "Temperature";
      string memory dformat = "JSON";
      uint cost = 1000;
      uint cycle = 3600;
      uint length;
      Oracle oracle;
      address o;

      bool result = a.createOracle(
         dtype,
         dformat,
         cost,
         cycle
      );
      Assert.isTrue(result, "Sensor created.");
      length = a.getOwnedLength();
      Assert.equal(length, 1, "One Contract added");
      o = a.getContractTaken(length - 1);
      Assert.isZero(o, "Oralce exists");
      oracle = Oracle(address(uint160(o)));
      //Oracle Default Values
      Assert.equal(oracle.dataType(), dtype, "Validating DataType");
      Assert.equal(oracle.dataFormat(), dformat, "Validating DataFormat");
      Assert.equal(oracle.updateCost(), cost, "Validating Cost");
      Assert.equal(oracle.updateCycle(), cycle, "Validating Cycle");
      Assert.equal(oracle.data(), "", "Validating default data");
     
   }

}

oracle.sol

pragma solidity ^0.5.0;

contract Oracle{
   
   address payable public provider;
   address payable public buyer;
   
   string public data;
   bool public needsUpdate;
   uint lastUpdate;
   enum Status { Available, Active, Paused, Ended }
   Status status;

   string public dataType;
   string public dataFormat;

   uint public updateCost;  //ether
   uint public balance;     //ether
   uint public updateCycle; //seconds
   
   constructor(
      address payable owner,
      string memory dtype,
      string memory dformat,
      uint cost,
      uint cycle
   )public{
      provider = owner;
      dataType = dtype;
      dataFormat = dformat;
      updateCost = cost;
      updateCycle = cycle;
      needsUpdate = false;
      status = Status.Available;
      data = "";
      balance = 0;
   }
   function takeContract() public returns(bool success){
      if(status == Status.Available){
         buyer = msg.sender;
         status = Status.Active;
         return true;
      }
      return false;
   }
   function update(string memory newData) public returns(bool success){
      if((msg.sender != provider)||(!needsUpdate))
         return false;
      if(now >= lastUpdate + updateCycle)
         provider.transfer(updateCost);
      data = newData;
      needsUpdate = false;
      lastUpdate = now;
      return true;
   }
   function request() public returns(bool success){
      if((msg.sender != buyer)||(balance < balance - updateCost))
         return false;
      needsUpdate = true;
      return true;
   }
   function endSell() public returns(bool success){
      if((msg.sender != provider)||(needsUpdate))
         return false;
      if(!(buyer.send(balance))){
         return false;
      }
      return true;
   }
   function endBuy() public returns(bool success){
      if(msg.sender != buyer)
         return false;
      if(!(buyer.send(balance))){
         return false;
      }
      status = Status.Ended;
      return true;
   }

   //Contract Mutators
   function setType(string memory dtype) public returns(bool success){
      if((msg.sender != provider)||(balance > 0))
         return false;
      dataType = dtype;
      return true;
   }
   function setFormat(string memory format) public returns(bool success){
      if((msg.sender != provider)||(balance > 0))
         return false;
      dataFormat = format;
      return true;
   }
   function setCycle(uint cycle) public returns(bool success){
      if((msg.sender != provider)||(balance > 0))
         return false;
      updateCycle = cycle;
      return true;
   }
   function setCost(uint cost) public returns(bool success){
      if((msg.sender != provider)&&(balance > 0))
         return false;
      updateCost = cost;
      return true;
   }
   function() external payable{
      balance += msg.value;
   }

aggregator.sol

pragma solidity ^0.5.0;

import './oracle.sol';

contract Aggregator{

   mapping(address => address[]) public contractsOwned;
   mapping(address => address[]) public contractsTaken;
   mapping(address => bool) public contractExists;
   
   function createOracle(
      string memory dtype, 
      string memory dformat, 
      uint cost,
      uint cycle
   ) public returns(bool success){
      address s = address(new Oracle(
         address(uint160(address(this))),
         dtype,
         dformat,
         cost,
         cycle
      ));
      contractsOwned[msg.sender].push(s);
      contractExists[s] = true;
      return true;
   }

   function getTakenLength() public view returns(uint length){
      return contractsTaken[msg.sender].length;
   }
   function getOwnedLength() public view returns(uint length){
      return contractsOwned[msg.sender].length;
   }
   function getContractTaken(uint index) public view returns(address taken){
      if(contractsTaken[msg.sender].length <= index)
         return address(0);
      return contractsTaken[msg.sender][index];
   }
   function getContractOwned(uint index) public view returns(address owned){
      if(contractsOwned[msg.sender].length <= index)
         return address(0);
      return contractsOwned[msg.sender][index];
   }
   
   /* Contract Functions */
   function takeContract(address payable oracle) public returns(bool success){
      Oracle o; 
      if(!contractExists[oracle])
         return false;
      if(!ownsContract(msg.sender, oracle))
         return false; 
      o = Oracle(oracle);
      contractsTaken[msg.sender].push(oracle);
      return o.takeContract();
   }
   function updateContract(address payable oracle, string memory data) public returns(bool success){
      Oracle o;
      if(!contractExists[oracle])
         return false;
      if(!ownsContract(msg.sender, oracle))
         return false;
      o = Oracle(oracle);
      return o.update(data);
   }
   function requestContract(address payable oracle) public returns(bool success){
      Oracle o;
      if(!contractExists[oracle])
         return false;
      if(!takenContract(msg.sender, oracle))
         return false;
      o = Oracle(oracle);
      return o.request();
   }
   function endSell(address payable oracle) public returns(bool success){
      Oracle o;
      if(!contractExists[oracle])
         return false;
      if(!ownsContract(msg.sender, oracle))
         return false;
      o = Oracle(oracle);
      if(!o.endSell())
         return false;
      contractExists[oracle] = false;
      //remove from contracts owned
   }
   function endBuy(address payable oracle) public returns(bool success){
      Oracle o;
      if(!contractExists[oracle])
         return false;
      if(!takenContract(msg.sender, oracle))
         return false;
      o = Oracle(oracle);
      if(!o.endSell())
         return false;
      contractExists[oracle] = false;
      //remove from contracts taken
   }

   /* Contract Parameter Edits */
   function setType(address payable oracle, string memory dtype) public returns (bool success){
      Oracle o;
      if(!contractExists[oracle])
         return false;
      if(!ownsContract(msg.sender, oracle))
         return false;
      o = Oracle(oracle);
      return o.setType(dtype);
   }
   function setFormat(address payable oracle, string memory format) public returns (bool success){
      Oracle o;
      if(!contractExists[oracle])
         return false;
      if(!ownsContract(msg.sender, oracle))
         return false;
      o = Oracle(oracle);
      return o.setFormat(format);
   }
   function setCycle(address payable oracle, uint cycle) public returns(bool success){
      Oracle o;
      if(!contractExists[oracle])
         return false;
      if(!ownsContract(msg.sender, oracle))
         return false;
      o = Oracle(oracle);
      return o.setCycle(cycle);
   }
   function setCost(address payable oracle, uint cost) public returns(bool success){
      Oracle o;
      if(!contractExists[oracle])
         return false;
      if(!ownsContract(msg.sender, oracle))
         return false;
      o = Oracle(oracle);
      return o.setCost(cost);
   }
   
   /*Internal Functions */
   function removeContractTaken(address payable oracle) internal returns(bool success){
      uint length = contractsTaken[msg.sender].length;
      uint i = 0;
      if(length <= 0)
         return false;
      for(i = 0; i < length; ++i){
         if(contractsTaken[msg.sender][i] == oracle){
            if(i != length - 1)
               contractsTaken[msg.sender][i] = contractsTaken[msg.sender][length - 1];
            delete contractsTaken[msg.sender][length - 1];
            return true;
         }
      }
      return false;
   }
   function removeContractOwned(address payable oracle) internal returns(bool success){
      uint length = contractsOwned[msg.sender].length;
      uint i = 0;
      if(length <= 0)
         return false;
      for(i = 0; i < length; ++i){
         if(contractsOwned[msg.sender][i] == oracle){
            if(i != length - 1)
               contractsOwned[msg.sender][i] = contractsOwned[msg.sender][length - 1];
            delete contractsOwned[msg.sender][length - 1];
            return true;

         }
      }
      return false;
   }
   function takenContract(address buyer, address oracle) internal view returns(bool success){
      uint length = contractsTaken[buyer].length;
      uint i = 0;
      if(contractsTaken[buyer].length <= 0)
         return false;
      for(i = 0; i < length; ++i){
         if(contractsTaken[buyer][i] == oracle)
            return true;
      }
      return false;
   }
   function ownsContract(address owner, address oracle) internal view returns(bool success){
      uint length = contractsOwned[owner].length;
      uint i = 0;
      if(contractsOwned[owner].length <= 0)
         return false;
      for(i = 0; i < length; ++i){
         if(contractsOwned[owner][i] == oracle)
            return true;
      }
      return false;
   }
}
  • Oracles are pushed to contractsOwned array, but you get the address from getContractTaken. Doesn't it have to call getContractOwned instead? – Ismael Oct 20 at 13:51
  • 1
    @Ismael yep, that did it. I guess I just needed a fresh pair of eyes. Thanks for the help. – Eduardo Gutierrez Oct 20 at 23:58

Your Answer

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

Browse other questions tagged or ask your own question.