Need help with two related Solidity questions.
Question 1. Say, I have a contract calling another one:
contract B {
function f1() {
...
}
}
contract A {
B b;
function f() {
b.f1();
}
}
Will msg.sender for f1 be same as for f()? Of will it be an address of a contract A?
Question 2.
Say, I have contracts A and B.
I want to have
contract A {
B b;
A(address addr) {
b = B(addr);
}
}
In other language, I would use B b = null; in declaration, to avoid double initialization, but it does not work in Solidity. So how do I declare a member variable and then initialize it by address?
Will msg.sender for f1 be same as for f()? Of will it be an address of
a contract A?
msg.sender will be the address of contract A. If you want to reference the original caller, use tx.origin.
So how do I declare a member variable and then initialize it by
address?
You don't need to worry about initialization when you declare the member variable. All variables in Solidity have default values. You can follow something like this:
contract B {
address sender;
function B(address addr) {
sender = addr;
}
}
contract A {
B b;
function A(){
b = B(msg.sender);
}
}
Related
When using solidity, I have a doubt when I need to call a function which was created in a different contract. I know 2 ways of doing it, and I don't understand what is more recommendable and why. These are the ways I know:
Method 1:
contract A {
function foo() external {
return true;
}
}
contract B is A {
foo();
}
Method 2:
contract A {
function foo() external {
return true;
}
}
contract B {
function callFoo() external {
A a = A(addressA);
return a.foo();
}
}
Could anyone tell me the differences, and when it is more convenient wo user wither Method 1 or Method 2?
Thank you!!
Method 1 is used when you're calling a contract that is deployed on the same address. It can be either a parent of your Contract B or a library that your contract has imported.
Since the foo method is external, you'd need to call it using this.foo();.
An external function f cannot be called internally (i.e. f() does not work, but this.f() works).
Source: Solidity docs
If it were public, you could call it internally, just using foo().
Method 2 is used when you're calling a contract that is deployed on a different address.
Your Contract B than doesn't have to redefine the Contract A, and can only define the interface:
// this is just an interface of an external contract
interface A {
function foo() external returns (bool);
}
// this is your contract
contract B {
function callFoo() external returns (bool) {
A a = A(addressA);
return a.foo();
}
}
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.
Lets suppose here are smartcontract A and B. B is deployed already and has BuyService function. User need to call this function to get service with tokens. A has enough tokens(Erc20).
User send TX to A
A call B's BuyService
B receive tokens(erc20) in A and give service to User
Is this logic possible? If not, how can I make A? I dont want to change the code in B. B is very general. Pls correct me.
contract A {
ERC20 token = ERC20(0x...);
B b = B(0x...);
function helpMeBuyService() external {
token.approve(b, 1000);
b.BuyService(msg.sender);
}
}
Your code is correct
pragma solidity ^0.5.0;
interface B {
function BuyService(address receiver) external;
}
interface ERC20 {
function approve(address receiver, uint256 amout) external;
}
contract A {
ERC20 public token = ERC20(0x123);
B public b = B(0x123);
function helpMeBuyService() external {
token.approve(address(b), 1000);
b.BuyService(msg.sender);
}
}
I'm trying to change the value of a variable in a contract that is in the blockchain. I've deducted its code and is something like this:
pragma solidity ^0.4.8;
contract Trial {
address public owner;
address public person;
uint initialEther;
function Trial(address _person) payable {
owner = msg.sender;
person = _person;
initialEther = msg.value;
}
modifier only_person() {
if (msg.sender!=person && tx.origin!=person) throw;
_;
}
function() payable {}
bytes4 public signature = bytes4(sha3("libraryFunction()"));
bool variableToBeChanged = false;
function libraryInvocation(address libraryAddress) only_person {
bool doSomething = libraryAddress.delegatecall(signature);
if (variableToBeChanged) {
.....
}
}
}
Suppose that I have the right signature of the library function, what I'm trying to do is to change the value of "variableToBeChanged" in order to execute the code inside the if.
Probably there is a way to create a library with a function with a proper name and inserting assembler code in some way to change the value of the variable. But it's like using an atomic bomb to kill an ant. I'm looking for the simpler way to do this.
I also know this contract is not safe, I'm trying to understand if this is possible and I want to understand how risky this can be for a contract.
Without a function changing the variable it is not possible. Once the contract code is deployed, it is final, no change is possible. You need to deploy a new contract.
You could control with your contract which wallet is allowed to call the function by checking the msg.sender attribute for a specific wallet address.
address owner = 0x2FD4...;
if(msg.sender != owner) throw;
//code afterwards)
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);
}
}