Calling functions from other contracts solidity - function

I am trying to create a new instance of the Taker contract from the Maker contract and send some value to it.
Then later I would like to send a value back to the Maker contract from the Taker contract
maker.change.value(5)(y);
However it cannot find the function called "change" and throws the error. The only possible explanation I can think of is that they need to be executed asynchronously but are compiled at the same time.
Untitled:27:3: Error: Member "change" not found or not visible after argument-dependent lookup in address
maker.change.value(5)(y);
^----------^
(This is tested in Browser Solidity, Ethereum Studio and Truffle - all with the same error message)
Below is the full code.
I would be very grateful for any advice on how to solve this (and or references).
Thank you!
pragma solidity ^0.4.2;
contract Maker {
uint x;
function Maker() {
x = 5;
Taker take = new Taker(this, 2);
bool a = take.call.gas(200000).value(10)();
}
function change(uint val) external payable {
x = val;
}
}
contract Taker {
uint y;
address maker;
function Taker(address makerAddr, uint val) {
y = val;
maker = makerAddr;
}
function sendChange() {
maker.change.value(5)(y);
}
}

This code worked with me in Browser Solidity
pragma solidity ^0.4.2;
contract Maker {
uint x;
function Maker() {
x = 5;
Taker take = new Taker(this, 2);
bool a = take.call.gas(200000).value(10)();
}
function change(uint val) external {
x = val;
}
}
contract Taker {
uint y;
Maker maker;
function Taker(address makerAddr, uint val) {
y = val;
maker = Maker(makerAddr);
}
function sendChange() {
maker.change(5);
}
}

Related

Creating an external payable function based on other functions (confusing question/challenge wording)

I'm trying to complete an online Solidity bootcamp but I'm having a lot of trouble trying to figure out what this specific question is asking from me exactly. The question is as follows:
"Write an external, payable function placeBet on the Bet Contract. This function should take a Game.Teams choice parameter and return a uint256 representing the payout of the bet.
Use the calculatePayout function to determine the payout of the bet. The inputs to this function will be the amount of ether sent to the placeBet function and the score difference determined by the getScoreDifference function."
Below are the contracts in question that are being used:
contract Game {
int public team1Score;
int public team2Score;
enum Teams { Team1, Team2 }
function addScore(Teams teamNumber) external {
// TODO: add score to the specified team
if (teamNumber == Teams.Team1) {
team1Score += 1;
} else if (teamNumber == Teams.Team2) {
team2Score += 1;
}
}
}
And the main question contract:
import "./Game.sol";
contract Bet {
Game public game;
constructor(address _gameAddress) {
game = Game(_gameAddress);
}
// calculates the payout of a bet based on the score difference between the two teams
function calculatePayout(uint amount, int scoreDifference) private pure returns(uint) {
uint abs = uint(scoreDifference > 0 ? scoreDifference : scoreDifference * -1);
uint odds = 2 ** abs;
if(scoreDifference < 0) {
return amount + amount / odds;
}
return amount + amount * odds;
}
function getScoreDifference(Game.Teams x) public view returns (int256) {
if (x == Game.Teams.Team1) {
return game.team1Score() - game.team2Score();
} else if (x == Game.Teams.Team2) {
return game.team2Score() - game.team1Score();
} return game.team1Score();
}
function placeBet(Game.Teams x) external payable returns (uint256) {
}
}
So the question is asking me to "use the calculatePayout function to determine the payout of the bet. The inputs to this function will be the amount of ether sent to the placeBet function and the score difference determined by the getScoreDifference function."
I wrote the function name, parameters etc. correctly (I think), but I have no idea what to include in the body, as the question is not worded very well. Any assistance would be great! Thanks.
This is how I would write it according to the question:
function placeBet(Game.Teams x) external payable returns (uint256) {
int256 _diff = getScoreDifference(x);
return calculatePayout(msg.value, _diff);
}
However in a production code it wouldn't make sense cause the user is paying for the bet, but this isn't registered anywhere. But the question doesn't mention writing a complete betting system so I guess it's ok.

Ethernaut level 24 - Puzzle Wallet: to which contract the wallet object on the browser console refers to?

I got a little confused when trying to solve this level and I got even more confused when I read this solution.
I thought that the contract object loaded in the browser console was the PuzzleWallet contract, because when I look at its ABI, there are all the functions from that contract and none from the PuzzleProxy. And the PuzzleWallet does not inherit from any other contract. I don't understand how it is possible to call proposeNewAdmin() function from the PuzzleProxy contract, if it does not inherit from PuzzleProxy...
On the other hand, if the contract object in the browser console is the PuzzleProxy, why there are all the functions from the PuzzleWallet in the ABI and none from the PuzzleProxy?
Here is the Ethernaut level.
The contracts are:
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
import "#openzeppelin/contracts/math/SafeMath.sol";
import "#openzeppelin/contracts/proxy/UpgradeableProxy.sol";
contract PuzzleProxy is UpgradeableProxy {
address public pendingAdmin;
address public admin;
constructor(address _admin, address _implementation, bytes memory _initData) UpgradeableProxy(_implementation, _initData) public {
admin = _admin;
}
modifier onlyAdmin {
require(msg.sender == admin, "Caller is not the admin");
_;
}
function proposeNewAdmin(address _newAdmin) external {
pendingAdmin = _newAdmin;
}
function approveNewAdmin(address _expectedAdmin) external onlyAdmin {
require(pendingAdmin == _expectedAdmin, "Expected new admin by the current admin is not the pending admin");
admin = pendingAdmin;
}
function upgradeTo(address _newImplementation) external onlyAdmin {
_upgradeTo(_newImplementation);
}
}
contract PuzzleWallet {
using SafeMath for uint256;
address public owner;
uint256 public maxBalance;
mapping(address => bool) public whitelisted;
mapping(address => uint256) public balances;
function init(uint256 _maxBalance) public {
require(maxBalance == 0, "Already initialized");
maxBalance = _maxBalance;
owner = msg.sender;
}
modifier onlyWhitelisted {
require(whitelisted[msg.sender], "Not whitelisted");
_;
}
function setMaxBalance(uint256 _maxBalance) external onlyWhitelisted {
require(address(this).balance == 0, "Contract balance is not 0");
maxBalance = _maxBalance;
}
function addToWhitelist(address addr) external {
require(msg.sender == owner, "Not the owner");
whitelisted[addr] = true;
}
function deposit() external payable onlyWhitelisted {
require(address(this).balance <= maxBalance, "Max balance reached");
balances[msg.sender] = balances[msg.sender].add(msg.value);
}
function execute(address to, uint256 value, bytes calldata data) external payable onlyWhitelisted {
require(balances[msg.sender] >= value, "Insufficient balance");
balances[msg.sender] = balances[msg.sender].sub(value);
(bool success, ) = to.call{ value: value }(data);
require(success, "Execution failed");
}
function multicall(bytes[] calldata data) external payable onlyWhitelisted {
bool depositCalled = false;
for (uint256 i = 0; i < data.length; i++) {
bytes memory _data = data[i];
bytes4 selector;
assembly {
selector := mload(add(_data, 32))
}
if (selector == this.deposit.selector) {
require(!depositCalled, "Deposit can only be called once");
// Protect against reusing msg.value
depositCalled = true;
}
(bool success, ) = address(this).delegatecall(data[i]);
require(success, "Error while delegating call");
}
}
}
The contract.abi object on the browser console is:
I understand the concept of proxy patterns. But I thought that it would be done via delegatecall() functions. For example, the addToWhiteList() function on the PuzzleWallet contract would be called by a function as follows on the PuzzleProxy contract:
function addToWhitelist(address _add) external {
puzzleWalletAddress.delegatecall(abi.encodeWithSignature("addToWhitelist(address)", _add);)
}
Hopefully my question here is not as confusing as I got while trying to solve this level :)
Appreciate very much if anyone coould help me! Thanks!
I also got confused by the same thing :)
The answer is that they created the Web3 contract object with the ABI of the logic contract but with the address of the proxy contract so you can interact with the logic as if there wasn't a proxy pattern under the hood.
In reality it is calling the proxy contract with the data of a function of the logic contract. As the function doesn't exist in the proxy, its fallback function runs and redirects the call to the logic contract via delegatecall.
So if you want to call proposeNewAdmin() in the proxy, call the contract mounted in the console (aka the proxy contract) but instead of using any function from the ABI defined there (which is the logic abi), make a generic transaction calling proposeNewAdmin(). As the function does exist in the proxy, it won't trigger the fallback.
web3.eth.abi.encodeFunctionSignature("proposeNewAdmin(address)");
> '0xa6376746'
web3.eth.abi.encodeParameter("address", player);
> '0x000000000000000000000000c3a005e15cb35689380d9c1318e981bca9339942'
contract.sendTransaction({ data: '0xa6376746000000000000000000000000c3a005e15cb35689380d9c1318e981bca9339942' });

Trouble calling contract functions from another contract

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);
}

Why are all my Remix test accounts showing 0 ETH?

I'm trying to write a TicTacToe game on remix.ethereum.org but all of a sudden all my test accounts show 0 ETH balance, so I can't use them to deploy my contracts anymore.
Here is the solidity code that I was deploying when it happened:
pragma solidity ^0.4.19;
contract TicTacToe {
uint8 public boardSize = 3;
address[3][3] board;
address public player1;
address public player2;
constructor() public {
player1 = msg.sender;
}
function joinGame() public {
assert(player2 == address(0));
player2 = msg.sender;
}
function setStone(uint8 x, uint8 y) public {
board[x][y] = msg.sender;
}
}
New test accounts still show 100 ETH upon creation.
I don't think this is anything to do with deploying your Solidity code.
What blockchain environment are you using? It is most likely a problem there.
Remix environment menu

How to call contract function from other contract in Ethereum

I have a deployed contract "greeter" in Ethereum
contract mortal {
address owner;
function mortal() { owner = msg.sender; }
function kill() { if (msg.sender == owner) selfdestruct(owner); }
}
contract greeter is mortal {
string greeting;
function greeter(string _greeting) public {
greeting = _greeting;
}
function greet() constant returns (string) {
return greeting;
}
}
And I want to create another contract, which will call function "kill" from my first contract. The main idea is that this 2 contracts is different. I publish contract A and then publish contract B, which calls A.
How I can do that?
Something like this, but from contract...
var contract = web3.eth.contract(contractAddress, ABI);
contract.call().kill();
Approximately like this, but there's a catch.
pragma solidity ^0.4.6;
contract Mortal {
address owner;
function Mortal() { owner = msg.sender; }
function kill() { if (msg.sender == owner) selfdestruct(owner); }
}
contract Greeter is Mortal {
string greeting;
function Greeter(string _greeting) public {
greeting = _greeting;
}
function greet() constant returns (string) {
return greeting;
}
}
contract Killer {
function destroyVictim(address victim) {
Greeter g = Greeter(victim);
g.kill();
}
}
That's a basic syntax. The ABI gets picked up by including Greeter in the source file along with Killer; that is, the compiler can "see it".
So far, so good.
The issue that arises is that Greeter is going to ignore the command, owing to if(msg.sender==owner). It won't be. It will be whatever address Killer got.
A possible solution to this before Greeter is deployed is to anticipate the need for a changeOwner() function, usually reserved for only the current owner.
Hope it helps.