从 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.sender
和 msg.value
。存储、当前地址和余额仍然参考调用合约(合约A
),只是代码取自被调用地址(合约B
)。
在您的情况下,setTokenName
更新 ContractB
的 tokenName
,因此 ContractB
的存储槽 0。Counter
处的相同存储槽智能合约是 uint256 public counter
。当您执行 delegatecall
时,您使用 ContractB
的 setTokenName
函数逻辑更新了 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);
}
}
目的是使用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.sender
和 msg.value
。存储、当前地址和余额仍然参考调用合约(合约A
),只是代码取自被调用地址(合约B
)。
在您的情况下,setTokenName
更新 ContractB
的 tokenName
,因此 ContractB
的存储槽 0。Counter
处的相同存储槽智能合约是 uint256 public counter
。当您执行 delegatecall
时,您使用 ContractB
的 setTokenName
函数逻辑更新了 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);
}
}