I deployed two contracts (A,B). Function A.delegateUpdateIDX[contract_B,1] triggers function B.updateIDX[1]
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.4;
contract A {
string[] private arr = ['a','b','c'];
function showIDX(uint _IDX) public view returns(string memory)
{
return arr[_IDX];
}
function delegateUpdateIDX(address _contractB, uint _IDX) external returns(bool _success)
{
(bool b,)=_contractB.delegatecall( abi.encodeWithSignature("updateIDX(uint _IDX)", _IDX) );
return b;
}
}
//###################################
contract B {
string[] private arr;
function updateIDX(uint _IDX) external
{
arr[_IDX]='X';
}
}
Then I call functions (in Remix):
A.showIDX[1]
returns 'b'
A.delegateUpdateIDX(B.address,1)
no errors
(should update A.storage and set A.arr[1] to 'X')
but the delegateCall() returns 'success=false' for some reason
and A.arr[1] doesn't change to 'X'
A.showIDX[1]
returns 'b' again (not 'X' as expected)
So, basically, I have no idea why delegateCall() returns 'success=false' and therefore why doesn't A.arr[1] change from 'b' to 'X'. What am I doing wrong?
Managed to make it work
abi.encodeWithSignature("updateIDX(uint _IDX)", _IDX) shouldn't have '_IDX' name in it, so I changed it to abi.encodeWithSignature("updateIDX(uint)", _IDX)
-- it still didn't work, the delegateCall() kept returning 'false' --
changed 'uint' to 'uint256' in both encodeWithSignature() and B.updateIDX()
worked fine this time
Related
I have created a solidity that record data CRUD like where I can create read update delete but I want to create a readAll function wondering how can I write in solidity since I write like below it does not work. For calling with id it return the correct but not readAll. Looking forward for your help <3
example
function readAllTask() public view returns (uint, uint256, uint256) {
return (tasks.id, tasks.stackAddress, tasks.nftId); <============= return everything
}
pragma solidity ^0.8.6;
contract RecordData {
struct Task {
uint id;
uint256 stackAddress;
uint256 nftId;
}
Task[] tasks;
uint nextId; // default value 0, add public to see the value
function createTask(uint256 _stackAddress, uint256 _nftId) public {
tasks.push(Task(nextId, _stackAddress, _nftId));
nextId++;
}
function findIndex(uint _id) internal view returns (uint) {
for (uint i = 0; i < tasks.length; i++) {
if (tasks[i].id == _id) {
return i;
}
}
revert("Task not found");
}
function updateTask(uint _id, uint256 _stackAddress, uint256 _nftId) public {
uint index = findIndex(_id);
tasks[index].stackAddress = _stackAddress;
tasks[index].nftId = _nftId;
}
function readTask(uint _id) public view returns (uint, uint256, uint256) {
uint index = findIndex(_id);
return (tasks[index].id, tasks[index].stackAddress, tasks[index].nftId);
}
function deleteTask(uint _id) public {
uint index = findIndex(_id);
delete tasks[index];
}
}
You can return an array of structs:
function readAllTask() public view returns (Task[] memory) {
return tasks;
}
I think you have reason to do it, but just a remind that saving the data into blockchain is not a good deal, due to the high cost.
If you would like to return all the task, then simply make the tasks public. Solidity automatically assign a get function for it.
If you would like to get some specific content of task struct, then consider something like this:
function readAllTask() public view returns (uint, uint256, uint256 [] memory) {
// something
}
I am a newbie studying Uniswap V3's github code. I came up with noDelegateCall.sol and I found out the way to prevent a contract to be delegatecalled from another cotract. As I tried to implement this, I caught up with the problem.
pragma solidity >0.8.0;
contract Receiver {
string greeting = "Hello";
address private immutable original;
event Greeting(string greeting, address original, address addressThis);
constructor() {
original = address(this);
}
function checkNotDelegateCall() private view {
require(address(this) == original);
}
modifier noDelegateCall() {
checkNotDelegateCall();
_;
}
function greet() external noDelegateCall {
emit Greeting(greeting, original, address(this));
}
}
contract Sender {
string greeting = "Hi";
function delegatedGreeting(address _contract) external {
(bool success,) = _contract.delegatecall(
abi.encodeWithSignature("greet()")
);
}
}
If I call function delegatedGreeting, I expect the function to be reverted because variables original and address(this) differs. However, although it emits an empty event, it still doesn't reverts. Why does this happen?
When the low-level delegatecall reverts, it doesn't automatically revert the main transaction. Instead, it returns false as the first return value of the delegatecall() function.
So you need to check the return value (in your case bool success) and validate that.
function delegatedGreeting(address _contract) external {
(bool success,) = _contract.delegatecall(
abi.encodeWithSignature("greet()")
);
require(success == true, "delegatecall failed");
}
I'm here to ask my problem on solidity code.
Here is simple example code. Contract 'Map' has a mapped data. It has each address's T/F values. I created an account X and add it to 'simpleMap'.
Contract 'Ask' lookup mapping data through 'Map' contract. What I expected result when X called askMe() was TRUE but it was always FALSE.
When I called whoIsMsgSender it returns the exact X's account. What's the problem??
pragma solidity ^0.4.24;
contract Map {
mapping (address => bool) simpleMap;
function add(address _address) external {
simpleMap[_address] = true;
}
function isTrue(address _address) external view returns (bool _ret) {
return simpleMap[_address];
}
}
contract Ask {
Map public map = Map(Map's address like 0x~~ just for test);
function askMe() external view returns (bool _ret) {
return map.isTrue(msg.sender);
}
function whoIsMsgSender() external view returns (address _address) {
return msg.sender;
}
}
I tried your contracts in Remix, but askMe() returned true for me. How are you separating the two contracts? Maybe Map is not yet deployed before Ask is trying to call a function on it. I separated the two contracts:
pragma solidity ^0.4.24;
contract Map {
mapping (address => bool) simpleMap;
function add(address _address) external {
simpleMap[_address] = true;
}
function isTrue(address _address) external view returns (bool _ret) {
return simpleMap[_address];
}
}
pragma solidity ^0.4.24;
contract Map { function isTrue(address _address) external view returns (bool _ret); }
contract Ask {
Map public map = Map(MAP_ADDRESS);
function askMe() external view returns (bool _ret) {
return map.isTrue(msg.sender);
}
function whoIsMsgSender() external view returns (address _address) {
return msg.sender;
}
}
I have created a contract where I am taking 2 Hashes from the user and trying to compare them both which in return would give a boolean value of true or false. It works good on remix but when I try to run the contract on Mist the compareString function just shows a message "NO". here is my code.
pragma solidity ^0.4.18;
contract Hash {
string fhash;
string comphash;
event Instructor(string _fhash);
event Instructors(string _comphash);
function setinstructor(string _fhash) public {
fhash = _fhash;
emit Instructor(_fhash);
}
function getinstructor() public constant returns(string){
return(fhash);
}
function setinstructors(string _comphash) public {
comphash = _comphash;
emit Instructors(_comphash);
}
function getinstructors() public constant returns(string){
return(comphash);
}
function compareStrings() public view returns (bool){
return sha256(fhash) == sha256(comphash)? true : false;
}
}
Image of Mist response
I'm new to smart contracts and I've deployed this test contract
contract test {
function callme(address dest, uint num, bytes data, uint nonce)
public
returns (bytes32 myhash)
{
myhash = sha3(dest, num, data, nonce);
return (myhash);
}
}
I then call test.callme(eth.accounts[0], 10, 0xaaaaa, 1234) expecting it to return the sha3 hash of the passed parameters but there's no return value.
> test.callme(eth.accounts[0], 10, 0xaaaaa, 1234)
INFO [12-24|19:35:40] Submitted transaction fullhash=0x694e0e38d0cf8744e62113750339a65f1d5a35cdc634eeb02b93581a926fea1a recipient=0xed712462999f8f68BbF618C3845F4333eDC31cD5
"0x694e0e38d0cf8744e62113750339a65f1d5a35cdc634eeb02b93581a926fea1a"
Any help is appreciated
Your syntax is a little off - you don't need to name your return value myhash. Something like this should do the trick:
contract test {
function callme(address dest, uint num, bytes data, uint nonce)
public
constant
returns (bytes32)
{
bytes32 myhash = sha3(dest, num, data, nonce);
return myhash;
}
}
I also threw in a constant keyword since the function isn't planning on changing anything in your contract's storage. It's a small change, but necessary for what you're trying to do.
Including the constant enables you to get a 'return' value, so to speak, because it says that you won't need to be modifying the blockchain - in essence, you're 'reading' the chain, not 'writing' to it.
Imagine a contract that did something like this:
contract test {
uint example;
function callme()
public
returns (uint)
{
example = example + 1;
return example;
}
}
The transaction we send to callme actually has to be executed before we return the value (since we're modifying the blockchain). Therefore, we can't really return the final value instantly (and we instead return information about the transaction), since we have to wait for the blockchain to be updated first.