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 {
...
}
Related
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 ?
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();
}
I have simple smart contract in Solidity. I want to call the function getHello() after I deployed the smart contract (to see variable in deployed contract without calling it by myself). Can I do this?
pragma solidity 0.5.12;
contract Hello {
string public helloStr = "Hello, world 2!";
uint[] public nums = [10, 20, 30];
function getHello() public view returns (string memory) {
return helloStr;
}
function pushNewElement(uint newElement) public returns (uint) {
nums.push(newElement);
}
function popLastElement () public returns (uint) {
nums.pop();
}
function setHello(string memory newHello) public {
helloStr = newHello;
}
}
For getting public variable the compiler automatically formed function.
In you case you can get hello string with function with hash c660ab0e
Or use your function getHello().
For calling function(example, helloStr()) you should use:
{"jsonrpc":"2.0","method":"eth_call", "params":[{"to":"address your smart contract", "data":"0xc660ab0e"}, "latest"],"id":1}
Or use web3 with call:
https://web3js.readthedocs.io/en/v1.2.0/web3-eth.html#call
Yes, you will see "hello world 2" after deployed the contract but you will never be able to see "newHello" output. because it sets the empty string whenever you setHello() function is using.
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();
}
}
My dapp will grab some data from client and send it to contract. I want to avoid spoofing of it.
Use Modifiers
pragma solidity ^0.4.0;
contract MyContract {
address mAdmin;
modifier adminOnly {
if (msg.sender == mAdmin) _;
}
function MyContract() {
mAdmin = msg.sender;
}
function doSomething() adminOnly {
...
}
}