Calling the function of an other contract in Solidity - blockchain

Do you know if is it possible to call the function of an other contract in Solidity used in Substrate based chain and compiled with solang ? At first glance it seems impossible but I doubt it.
As a basic example I'm trying to get a "incrementor" working only if a "flipper" is on:
contract Flipper {
bool private value;
constructor (bool initValue) {
value = initValue;
}
function flip () public {
value = !value;
}
function get () public view returns (bool) {
return value;
}
}
I want to use a Flipper instance in my Incrementor contract to allow / disallow incrementing.
import "flipper.sol";
contract Incrementor {
uint256 _count;
Flipper _flipper;
constructor (uint256 _initialValue, Flipper _flipperContract) {
_count = _initialValue;
_flipper = _flipperContract;
}
// --
// Mutators
// --
function increment () public {
require(_flipper.get(), "Flipper must be ON");
_count += 1;
}
function superFlip () public {
_flipper.flip();
}
function setValue (uint256 v) public {
_count = v;
}
// --
// Accessors
// --
function count () public view returns (uint256) {
return _count;
}
}
When testing all of this on polkadotjs; I have a negative answer saying contract trapped ALONG with a success message (but the totality doesn't work).
(Failure on the "increment" message):
I'm not sure but I suspect this problem to arise from the difference in addressing in the EVM vs WASM.
In the article linked bellow, we can see how an external contract function is "manually" invoked with an "address.call(bytes4(keccack25('...')), args)".
https://medium.com/#blockchain101/calling-the-function-of-another-contract-in-solidity-f9edfa921f4c
Except this is working in a EVM environment; not a WASM substrate environment.
Can someone help ?

Related

Solidity: How to test if a function is called from another contract?

I was wondering how I can test if a function is called from another contract using chai.
Contracts will be like:
contract ContractA {
function shouldBeCalledByOthers() { // some code... };
}
contract ContractB {
ContractA contractA;
constructor(address addr) {
contractA = ContractA(addr);
}
function shouldCallA() {
contractA.shouldBeCalledByOthers();
}
}
Then I would like to test if ContractA's shouldBeCalledByOthers method is called when ContractB's shouldCallA method is called.
Can chai spy be used for this purpose?
https://www.chaijs.com/plugins/chai-spies/
In Solidity, you can verify if the function caller is a contract or not:
modifier callerIsUser() {
require(tx.origin == msg.sender, "The caller is another contract");
_;
}
function example() callerIsUser {
...
}

How to get right msg.sender calling from contract instance a.foo() and have all secure from 3rd parties

I got stucked in thoughts guys and I need bit of clarification to move it forward.
(Description is about real problem, code is for best (I hope so..) understanding me)
I have main contract A that uses erc20 token and its transfer functions, there is also inherited Ownable and whitelist with accessing addresses of contracts e.g. B,
I passing A address to the B constructor
I created instance of A in B (because in B I calculate collateral and I want to split to two different contracts)
Protecting A using Ownable it's enough from accessing A from 3rd party while interacting with A from A, Ownable in B isnt work because can't use right msg.sender, without modifiers someone can create instance of B in his contract and have access to my A, isn't it?
Thanks in advance
EDIT: I change a code for more to understand
// SPDX-License-Identifier: MIT
pragma solidity 0.8;
contract Ownable {
mapping (address => bool) private whiteListed;
modifier onlyWhiteListed {
require(whiteListed[msg.sender] == true, "You're not whitelisted");
_;
}
constructor () {
whiteListed[msg.sender] = true;
}
function setWhiteListed(address addr, bool trueOrFalse) public onlyWhiteListed {
whiteListed[addr] = trueOrFalse;
}
function getWhiteListed(address addr) public view returns (bool) {
return whiteListed[addr];
}
}
contract A is Ownable {
B public b;
event LogMsgSender(address who);
constructor() {
b = new B(address(this));
//setWhiteListed(address(this),true);
setWhiteListed(address(b),true);
}
function callMe() public onlyWhiteListed { // here I can only get real caller msg.sender
emit LogMsgSender(msg.sender); // when interact with that contract, not outside of contract
}
function callSender(address sender) public onlyWhiteListed { // here I can get real caller msg.sender from other contract
emit LogMsgSender(sender); // but is it worth to passing addresses ?
} // and HERE is my question: is this aproach secure??
}
contract B is Ownable {
A public a;
constructor(address addr) { //in remix I can't deploy in one time while
a = A(addr); //deploying A, I have to deploy copying addresses of A and do it separately
} //and after deploying also setWhiteListed() to whiteList in A
function callMe() public onlyWhiteListed { // this call isn't good for interact with sender, it's exlusive for calling as contract B
a.callMe(); // copies of this contract can
}
function callSender() public onlyWhiteListed { // modifiers protect from 3rd party contracts but
a.callSender(msg.sender); // that way it only can be used by deployer and whitelisted, (without modifiers they aren't secure)
} // bad idea ofc is adding to whitelist all over and over and
// it's impossible to recognize which to add which not
}
contract C {
B public b;
constructor(address addr) {
b = B(addr);
}
function callMe() public { //when modifiers is added this contract can't call these functions
b.callMe(); // but with modifiers functions can't be used to get right sender address
}
function callSender() public {
b.callSender();
}
}
So now I'm deciding to inherite e.g. B is A and I simply get right sender, what do you think?
You've got a lot of syntax/logic errors in the code you posted. Not only are you missing onlyOwner modifiers, but your calls in B are via the type A: A.receiveToken() is not the same as a.receiveToken() ... so you've probably made several typos in posting your question (Should say a=A(aAddr); in the constructor etc).
The msg.sender will be "b" when b calls a.sendToken() but tx.origin will be unchanged. Checking msg.sender checks which contract called you. In other words, it is checking (inside onlyOwner of A.sendToken) whether b is the one that called a.sendToken().
Start by fixing all the errors and then insert some debug logging for yourself, so you can see how msg.sender is changing during the calls. You can also log tx.origin to see how that remains the original sender.
The point is that the owner of the A that B created is that particular instance of B (b). It's therefore "natural" that inside B, it can call a.whatever() as a's owner.
You didn't specify, but if you are using the Ownable contract from openzeppelin you need to pass the modifier onlyOwner for the methods that you want to be protected. Ex:
function sendToken(uint value) public onlyOwner {
//transferFrom
emit Sent(value);
}

Figuring out a solidity Interface issue

I got an example of a solidity Interface.
1/ Any clue if this method is accurate as it's implementing the Interface within the inherited from Contract and not within the extension Contract.
2/ I tried implementing it, contractA functions run correctly, however contractB getCount function is not running correctly.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface InterfaceA {
function count() external view returns (uint256);
function increment() external;
}
contract contractA {
uint256 number = 0;
function count() external view returns (uint256) {
return number;
}
function increment() external {
number++ ;
}
}
// SPDX-License-Identifier: MIT
import './contractA.sol' ;
pragma solidity ^0.8.0;
contract contractB {
address addressA;
function setPointer(address _addressA) external {
addressA = _addressA;
}
function getCount() external view returns (uint256) {
InterfaceA b = InterfaceA(addressA);
b.count();
}
function addToIncrement() external {
InterfaceA b = InterfaceA(addressA);
b.increment();
}
}
I think the only issue is you are not returning anything from getCount. You added the return signature, you should had a warning when you compiled it.
function getCount() external view returns (uint256) {
InterfaceA b = InterfaceA(addressA);
return b.count();
}

Data location must be "memory" for return parameter in function, but none was given

I tried solidity example like as above in remix, solidity version > 0.5.0
But I am getting this error now.
What is the way to solve this error?
contract MyContract {
string value;
function get() public view returns (string) {
return value;
}
function set(string _value) public {
value = _value;
}
constructor() public {
value = "myValue";
}
}
You should add memory keyword for string parameter, which was introduced in solidity version 0.5.0
As per the documentation:
Explicit data location for all variables of struct, array or mapping types is now mandatory. This is also applied to function parameters and return variables. For example, change uint[] x = m_x to uint[] storage x = m_x, and function f(uint[][] x) to function f(uint[][] memory x) where memory is the data location and might be replaced by storage or calldata accordingly. Note that external functions require parameters with a data location of calldata.
Corrected code
contract MyContract {
string value;
function get() public view returns (string memory) {
return value;
}
function set(string memory _value) public {
value = _value;
}
constructor() public {
value = "myValue";
}
}
Refer to official documentation on breaking changes made in version 0.5.0
Values of reference type can be modified through multiple different
names. Contrast this with value types where you get an independent
copy whenever a variable of value type is used. Because of that,
reference types have to be handled more carefully than value types.
Currently, reference types comprise structs, arrays and mappings. If
you use a reference type, you always have to explicitly provide the
data area where the type is stored: memory (whose lifetime is limited
to an external function call), storage (the location where the state
variables are stored, where the lifetime is limited to the lifetime of
a contract) or calldata (special data location that contains the
function arguments).
Warning
Prior to version 0.5.0 the data location could be omitted, and would default to different locations depending on the kind of variable, function type, etc., but all complex types must now give an explicit data location.
https://docs.soliditylang.org/en/latest/types.html#reference-types
so you have to put memory or calldata after String as follows:
contract MyContract {
string value;
function get() public view returns (string memory) {
return value;
}
function set(string memory _value) public {
value = _value;
}
constructor() {
value = "myValue";
}
}
another thing to notice that you dont have to put public in the constructor any more:
Warning: Prior to version 0.7.0, you had to specify the visibility of
constructors as either internal or public.
https://docs.soliditylang.org/en/latest/contracts.html?highlight=constructor#constructors
In the case of returning address array, you can declare memory after your return address type.
function getAllPlayers() public view returns(address[] memory){
return players;
}
Solidity is updated on a daily basis so there are changes made of which you should be aware of. For that keep referring to the updated solidity docs.
The Code should be this:
contract MyContract {
string value;
function get() public view returns (string memory) {
return value;
}
function set(string memory _value) public {
value = _value;
}
constructor() public {
value = "myValue";
}
}
OR
contract MyContract {
string value;
function get() public view returns (string calldata) {
return value;
}
function set(string calldata _value) public {
value = _value;
}
constructor() public {
value = "myValue";
}
}
pragma solidity 0.8.11;
contract Greeter{
string greeting;
function greeter(string memory _greeting) public{
greeting = _greeting;
}
function greet() public returns(string memory)
{
return greeting;
}
}

How to Call contract inside another contarct in solidity version 0.5.2?

I'm using solidity version 0.5.2
pragma solidity ^0.5.2;
contract CampaignFactory{
address[] public deployedCampaigns;
function createCampaign(uint minimum) public{
address newCampaign = new Campaign(minimum,msg.sender); //Error
//here!!!
deployedCampaigns.push(newCampaign);
}
function getDeployedCampaigns() public view returns(address[] memory){
return deployedCampaigns;
}
}
I'm getting the error while assigning calling the Campaign contract inside CampaignFactory contract
TypeError: Type contract Campaign is not implicitly convertible to expected
type address.
address newCampaign = new Campaign(minimum,msg.sender);
I have another contract called Campaign which i want to access inside CampaignFactory.
contract Campaign{
//some variable declarations and some codes here......
and I have the constructor as below
constructor (uint minimum,address creator) public{
manager=creator;
minimumContribution=minimum;
}
You can just cast it:
address newCampaign = address(new Campaign(minimum,msg.sender));
Or better yet, stop using address and use the more specific type Campaign:
pragma solidity ^0.5.2;
contract CampaignFactory{
Campaign[] public deployedCampaigns;
function createCampaign(uint minimum) public {
Campaign newCampaign = new Campaign(minimum, msg.sender);
deployedCampaigns.push(newCampaign);
}
function getDeployedCampaigns() public view returns(Campaign[] memory) {
return deployedCampaigns;
}
}
To call an existing contract from another contract ,pass the contract address inside cast
pragma solidity ^0.5.1;
contract D {
uint x;
constructor (uint a) public {
x = a;
}
function getX() public view returns(uint a)
{
return x;
}
}
contract C {
//DAddress : is the exsiting contract instance address after deployment
function getValue(address DAddress) public view returns(uint a){
D d =D(DAddress);
a=d.getX();
}
}