从 Keeper 更改合约 B 的变量状态

Change the state of a variable of a contract B from a Keeper

目的是使用B合约中的这个变量 我正在尝试使用委托调用但不起作用,仅适用于事件

ContractB.sol

// SPDX-License-Identifier: MIT
pragma solidity >0.8.0;

contract ContractB {
    
    uint256 public tokenName = uint256(2);
    event SetToken(uint256 _tokenName); 

    function setTokenName(uint256 _newName) external returns (uint256) {                
        setInternal(_newName);  
    }
    
    function setInternal (uint256 _newName) public returns (uint256)
    {
        tokenName = _newName;
        emit SetToken(tokenName);
        return tokenName;
    }
            
    function getTokenName() public view returns (uint256)
    {
        return tokenName;
    }        
}

Counter.sol

//Begin
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;

interface KeeperCompatibleInterface {
    function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
    function performUpkeep(bytes calldata performData) external;
}

contract Counter is KeeperCompatibleInterface {
    
    uint256 public counter;    // Public counter variable

    // Use an interval in seconds and a timestamp to slow execution of Upkeep
    //60 seconds
    uint public immutable interval;
    uint public lastTimeStamp;  //My counter was updated  
    
    //**
    address contractBAddress;
    uint256 public tokenName = uint256(2);
    //**
    
    constructor(uint updateInterval,address _contractBAddress) {
      interval = updateInterval;
      lastTimeStamp = block.timestamp;
      counter = 0;
      contractBAddress=_contractBAddress;
    }

    function checkUpkeep(bytes calldata checkData) external view override returns (bool upkeepNeeded, bytes memory performData) {
        upkeepNeeded = (block.timestamp - lastTimeStamp) > interval;
        performData = checkData;
    }

    
    //When checkUpKeep its already to launch, this task is executed
    function performUpkeep(bytes calldata) external override {
        lastTimeStamp = block.timestamp;
        counter=0;
        counter = counter + 1;
        (bool success, bytes memory returndata) = contractBAddress.delegatecall(
              abi.encodeWithSignature("setTokenName(uint256)", counter)
        );

        // if the function call reverted
        if (success == false) {
            // if there is a return reason string
            if (returndata.length > 0) {
                // bubble up any reason for revert
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert("Function call reverted");
            }
        }
    }
    function getTokenName() public view returns (uint256)
    {
        return tokenName;
    }
    
}

活动完美,但我无法更改 ContractB.sol 中的状态 ... https://kovan.etherscan.io/tx/0x7fbacd6fa79d73b3b3233e955c9b95ae83efe2149002d1561c696061f6b1695e#eventlog

你应该使用这个:

    ContractB contractB = ContractB(contractBAddress);
    contractB.setTokenName(counter);

文档: https://solidity-by-example.org/calling-contract/

Counter.sol

//Begin
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;

interface KeeperCompatibleInterface {
    function checkUpkeep(bytes calldata checkData) external returns (bool upkeepNeeded, bytes memory performData);
    function performUpkeep(bytes calldata performData) external;
}

contract Counter is KeeperCompatibleInterface {
    
    uint256 public counter;    // Public counter variable

    // Use an interval in seconds and a timestamp to slow execution of Upkeep
    //60 seconds
    uint public immutable interval;
    uint public lastTimeStamp;  //My counter was updated  
    
    //**
    address public contractBAddress;
    //**
    
    constructor(uint updateInterval,address _contractBAddress) {
      interval = updateInterval;
      lastTimeStamp = block.timestamp;
      counter = 0;
      contractBAddress=_contractBAddress;
    }

    function checkUpkeep(bytes calldata checkData) external view override returns (bool upkeepNeeded, bytes memory performData) {
        upkeepNeeded = (block.timestamp - lastTimeStamp) > interval;
        performData = checkData;
    }

    
    //When checkUpKeep its already to launch, this task is executed
    function performUpkeep(bytes calldata) external override {
        lastTimeStamp = block.timestamp;
        counter = counter + 1;
        ContractB contractB = ContractB(contractBAddress);
        contractB.setTokenName(counter);
    }
    
}

ContractB.sol

contract ContractB {
    
    uint256 public tokenName = uint256(2);

    function setTokenName(uint256 _newName) external {                
      tokenName=_newName;
    }
    
    
    function getTokenName() public view returns (uint256)
    {
        return tokenName;
    }
    
}

该活动的完美运作证明了 Keeper 的工作做得很好。这里的问题是 delegatecall 本身。

当合约A执行delegatecall到合约B时,B的代码用合约A的存储执行,msg.sendermsg.value。存储、当前地址和余额仍然参考调用合约(合约A),只是代码取自被调用地址(合约B)。

在您的情况下,setTokenName 更新 ContractBtokenName,因此 ContractB 的存储槽 0。Counter 处的相同存储槽智能合约是 uint256 public counter。当您执行 delegatecall 时,您使用 ContractBsetTokenName 函数逻辑更新了 Counter 的存储(counter 变量)。

既然知道 ContractB 的 ABI,为什么不这样做呢?

pragma solidity ^0.8.0;

import "./ContractB.sol";

contract Counter is KeeperCompatibleInterface {
    ContractB public contractB;
    uint256 public counter;

    constructor(ContractB _contractBAddress) {
        contractB = _contractBAddress;
    }

    function performUpkeep(bytes calldata) external override {
        counter = counter + 1;
        contractB.setTokenName(counter);
    }
}