I have a wrapper contract that instantiates and calls another contract, and my test cases say the owners (msg.sender)s don't match. Why?
contract A
pragma solidity ^0.4.4;
contract A {
address public owner;
function A() {
owner = msg.sender;
}
function createB(string name) {
return new B(msg.sender, name);
}
}
contract B
pragma solidity ^0.4.4;
contract B {
address public owner;
string public name;
function B(address _owner, string _name) {
owner = _owner;
name = _name;
}
}
test case
pragma solidity ^0.4.0;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/B.sol";
contract TestB {
B testB;
A testA;
function beforeEach() {
A = A(DeployedAddresses.A());
B = testA.createB("test");
}
function testOwnerIsSet() {
Assert.equal(address(A), address(B), "Owner's address does not match");
}
}
Test Results
1) TestB testOwnerIsSet:
Error: Owner's address does not match
at /Users/xxx/.config/yarn/global/node_modules/truffle/build/cli.bundled.js:214233:17
at Array.forEach (native)
at processResult (/Users/xxx/.config/yarn/global/node_modules/truffle/build/cli.bundled.js:214231:19)
at process._tickCallback (internal/process/next_tick.js:109:7)
EDIT
I have added the address public owner to contract A. And made owner public in contract B.
And now my TestB contract looks like this:
pragma solidity ^0.4.0;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/B.sol";
contract TestB {
B testB;
A testA;
function beforeEach() {
A = A(DeployedAddresses.A());
B = testA.createB("test");
}
function testOwnerIsSet() {
address aOwner = A.owner();
address bOwner = B.owner();
Assert.equal(aOwner, bOwner, "Owner's address does not match");
}
}
Based on what you have shown I am assuming you are using truffle? And to be honest I am surprised that this compiles.
When you call,
B = testA.createB("test");
you are calling it from TestB. msg.sender will be the address of TestB.
function createB(string name) {
return new B(msg.sender, name); // msg.sender = TestB instance address
}
This may be helpful to achieve what you are attempting.
Related
I'm trying to test this contract using "truffle test" but it show the following error:
Error: Returned error: VM Exception while processing transaction: revert only owner can call this function - - Reason given: Only owner can call this function.
Gaming.sol
pragma solidity ^0.5.0;
contract Gaming {
/* Our Online gaming contract */
address public owner;
bool public online;
struct Player {
uint wins;
uint losses;
}
mapping (address => Player) public players;
constructor() public payable {
owner = msg.sender;
online = true;
}
modifier isOwner() {
require(msg.sender == owner, "Only owner can call this function");
_;
}
}
TestGaming.sol
pragma solidity ^0.5.0;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Gaming.sol";
contract TestGaming {
uint public initialBalance = 10 ether;
Gaming gaming;
address owner;
function beforeAll() public {
gaming = Gaming(DeployedAddresses.Gaming());
owner = gaming.owner();
}
function testWithdrawFunds() public {
uint ownerBalanceBefore = owner.balance;
gaming.withdrawFunds();
uint ownerBalanceAfter = owner.balance;
Assert.equal (initialBalance, ownerBalanceAfter - ownerBalanceBefore, "The owner's balance should have increased by 10 ether");
}
Error
Error: Returned error: VM Exception while processing transaction: revert only owner can call this function - - Reason given: Only owner can call this function.
You may deployed the Contract with other account and test it with another accounts..
please do add your test script
I have a roulette smart contract, that uses another smart contract to provide it with random numbers. The issue i'm having is during compilation, i get the error:
TypeError: Type contract IRandomNumberGenerator is not implicitly convertible to expected type address.
project:/contracts/Roulette.sol:34:29:
randomNumberGenerator = IRandomNumberGenerator(randomNumberGenerator);
I'm not exactly sure where i'm going wrong, i've seen this code used in other contracts. Here is my full code, any help would be much appreciated.
// SPDX-License-Identifier: UNLICENSED"
pragma solidity ^0.8.7;
import "#openzeppelin/contracts/token/ERC20/IERC20.sol";
import "#openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "./IRandomNumberGenerator.sol";
contract Roulette is Ownable {
using SafeERC20 for IERC20;
IERC20 public gameToken;
uint256[100] internal randomNumbers;
IRandomNumberGenerator internal randomNumberGenerator;
// ensure caller is the random number generator contract
modifier onlyRandomGenerator() {
require(msg.sender == address(randomNumberGenerator), "Only random generator");
_;
}
constructor(address tokenAddress) {
gameToken = IERC20(tokenAddress);
}
function setRandomNumberGenerator(address randomNumberGenerator) external onlyOwner {
randomNumberGenerator = IRandomNumberGenerator(randomNumberGenerator);
}
function getRandomNumber() internal onlyOwner returns (uint) {
uint result = randomNumbers[randomNumbers.length-1];
delete randomNumbers[randomNumbers.length-1];
return result;
}
function numberGenerated(uint randomNumber) external onlyRandomGenerator {
randomNumbers = expand(randomNumber);
}
// generate 100 random numbers from the random number seed
function expand(uint256 randomValue) public pure returns (uint256[] memory expandedValues) {
expandedValues = new uint256[](100);
for (uint256 i = 0; i < 100; i++) {
expandedValues[i] = uint256(keccak256(abi.encode(randomValue, i)));
}
return expandedValues;
// TODO - ensure random numbers are roulette numbers
}
}
// SPDX-License-Identifier: UNLICENSED"
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
import "./IRoulette.sol";
contract RandomNumberGenerator is VRFConsumerBase {
address public roulette;
bytes32 internal keyHash;
uint256 internal fee;
uint256 internal randomResult;
// modifier to check if caller of owner is the admin
modifier onlyRoulette() {
require(msg.sender == roulette, "Caller to function is not the roulette contract");
_;
}
constructor(address _roulette)
VRFConsumerBase(
0xa555fC018435bef5A13C6c6870a9d4C11DEC329C, // VRF Coordinator
0x84b9B910527Ad5C03A9Ca831909E21e236EA7b06 // LINK Token
)
{
keyHash = 0xcaf3c3727e033261d383b315559476f48034c13b18f8cafed4d871abe5049186;
fee = 0.1 * 10 ** 18;
roulette = _roulette;
}
function getRandomNumber() public onlyRoulette returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
return requestRandomness(keyHash, fee);
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
randomResult = randomness;
IRoulette(roulette).numberGenerated(randomResult);
}
}
Found out the issue was having the same name for both the parameter and the variable.
Updated the function to:
function setRandomNumberGenerator(address _randomNumberGenerator) external onlyOwner {
randomNumberGenerator = IRandomNumberGenerator(_randomNumberGenerator);
}
I am really new to Solidity and smart contracts and would really appreciate some help. I am following a tutorial and this is the exact code they use. But when I compile the code I get this error:
ParserError: Expected primary expression.
address public constant approver = ;
pragma solidity ^0.6.0;
contract ApprovalContract {
address public sender;
address public receiver;
address public constant approver = ;
function deposit(address _receiver) external payable {
require(msg.value > 0);
sender = msg.sender;
receiver = _receiver;
}
function viewApprover() external pure returns(address) {
return(approver);
}
function approve() external {
require(msg.sender == approver);
receiver.transfer(address(this).balance);
}
}
The constant needs to be initialized
address public constant approver = YOURADDRESS;
There are 2 types of constant variables in Solidity:
Constants: a variable that is hardcoded in the smart contract and that you cannot change the value
Immutables: variables you can only define the value in the constructor and that cannot be updated afterwards
Here is an example:
uint256 public constant EXAMPLE_NUMBER = 123;
unit256 public immutable EXAMPLE_NUMBER_2;
constructor(uint256 _number) {
EXAMPLE_NUMBER_2 = _number;
}
You can read more about it here.
In deployed contract with address abc I have:
function CallContract(address tosend,uint amount,bytes hexdata,uint zgas) public payable {
tosend.call.gas(zgas).value(amount)(hexdata);
}
In web3 I have
await AbcContract.methods
.CallContract(this.state.tosend,amounttowei,web3.utils.fromAscii(data),gas)
.send({
from:accounts[0]
});
In the deployed contract with address xyz I have:
uint public somevar;
uint public anothervar;
function DoSomething() public payable {
uint somevar = 1;
}
function DoSomethingAgain(uint justanumber) public payble {
uint anothervar = justanumber;
}
What am I doing wrong?
In etherscan I get
Although one or more Error Occurred [Out of gas] Contract Execution Completed
Currently, I want to test a contract called B which is generated from another contract Registry by using truffle. For example:
Contract Registry
pragma solidity >=0.4.17;
import "./B.sol";
contract Registry is Owned {
function createContract(
address userAddress)
public
returns(
bool res
)
{
// create a contract B which the owner is the user.
B b = new B(userAddress);
return true;
}
Contract B
pragma solidity >=0.4.17;
contract B {
address private owner;
constructor (
address _owner
)
public
{
owner = _owner;
}
function logData(
bytes32 data,
uint timestamp
)
public
returns(bool res)
{
...
}
...
testing script B.js in truffle/test:
const Registry = artifacts.require('./Registry.sol');
const B = artifacts.require('./B.sol');
const truffleAssert = require('truffle-assertions');
const assert = require('assert');
contract('Registry', (accounts) => {
let registry;
let B;
beforeEach(async () => {
// create a reportSummary contract from registry contract.
registry = await Registry.deployed();
// How can I retrieve the contract B's instance?
});
Because I am a newbie in solidity, thus I cannot find any way to test the function logData or other functions in contract B which depends on the contract Registry. Is there any suitable way or should I change the contract designed? Thanks.
You can check my this answer it has example too about accessing the function from imported contract
Solidity: Can a Parent contract see data updates from a Child contract?
To access the function through web3, just use the instance of Registry contract and you can call the function of Contract B