Commit 09ccef1b authored by Developer's avatar Developer

add new contract

parent ea5dffbe
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract Callee {
uint256 public value;
uint256 public counter;
event Wrote(uint256 newValue, uint256 newCounter);
function setValue(uint256 v) external {
value = v;
counter += 1;
emit Wrote(value, counter);
}
// 先改状态,再 REVERT
function setThenRevert(uint256 v) external {
value = v;
counter += 1;
emit Wrote(value, counter);
revert("callee reverted after write");
}
// 先改状态,再 assert 触发 panic(更像“异常失败”)
function setThenAssert(uint256 v) external {
value = v;
counter += 1;
emit Wrote(value, counter);
assert(false);
}
}
contract RevertingConstructor {
uint256 public x;
constructor(uint256 v) {
x = v;
revert("constructor revert");
}
}
contract Caller {
Callee public callee;
event CallResult(bool success, bytes data);
// 新增:Caller 本地日志(persistent) — 用来演示即使内部调用回滚,Caller 的日志会保留
event CallerLog(string info);
constructor() {
callee = new Callee();
}
// 基线:成功调用会真正改 callee 状态
function okCall(uint256 v) external {
emit CallerLog("okCall: before callee.setValue");
callee.setValue(v);
emit CallerLog("okCall: after callee.setValue");
}
/**
* 关键测试1:低级 call 调用 setThenRevert
* 预期:
* - 返回 success=false
* - callee.value / callee.counter 不会改变(保持调用前的值)
* - callee 发出的 Wrote 事件不会出现在最终的 receipt 中(已被回滚)
*/
function testRevertRollback(uint256 v) external returns (bool) {
emit CallerLog("testRevertRollback: before low-level call");
(bool ok, bytes memory data) = address(callee).call(
abi.encodeWithSignature("setThenRevert(uint256)", v)
);
emit CallResult(ok, data);
emit CallerLog("testRevertRollback: after low-level call");
return ok;
}
/**
* 关键测试2:低级 call 调用 setThenAssert (panic)
* 预期同上:success=false + callee 状态不变
*/
function testPanicRollback(uint256 v) external returns (bool) {
emit CallerLog("testPanicRollback: before low-level call");
(bool ok, bytes memory data) = address(callee).call(
abi.encodeWithSignature("setThenAssert(uint256)", v)
);
emit CallResult(ok, data);
emit CallerLog("testPanicRollback: after low-level call");
return ok;
}
/**
* 关键测试3:CREATE 失败会回滚本次 CREATE 的所有副作用
* 这里我们用 try/catch 捕获创建失败,让外层不 revert。
*/
function testCreateRollback(uint256 v) external returns (bool) {
emit CallerLog("testCreateRollback: before CREATE");
bool success;
try new RevertingConstructor(v) returns (RevertingConstructor /*rc*/) {
// 这个分支理论上不会走到
success = true;
} catch (bytes memory reason) {
emit CallResult(false, reason);
success = false;
}
emit CallerLog("testCreateRollback: after CREATE");
return success;
}
// 方便读取被测状态
function readCallee() external view returns (uint256 v, uint256 c) {
v = callee.value();
c = callee.counter();
}
}
const hre = require("hardhat");
async function decodeLogs(receipt, ifaces) {
const decoded = [];
for (const log of receipt.logs) {
let parsed = null;
for (const iface of ifaces) {
try {
parsed = iface.parseLog(log);
break;
} catch (e) {
// not this iface
}
}
if (parsed) {
decoded.push({
name: parsed.name,
args: parsed.args,
address: log.address,
});
} else {
decoded.push({ raw: log });
}
}
return decoded;
}
async function main() {
const [deployer] = await hre.ethers.getSigners();
console.log("Signer:", deployer.address);
const Caller = await hre.ethers.getContractFactory("Caller");
const caller = await Caller.deploy();
await caller.waitForDeployment();
const callerAddr = await caller.getAddress();
console.log("Caller deployed to:", callerAddr);
const calleeAddr = await caller.callee();
const Callee = await hre.ethers.getContractFactory("Callee");
const callee = Callee.attach(calleeAddr);
console.log("Callee (created by Caller) address:", callee.address);
const ifaces = [caller.interface, callee.interface];
console.log("\n== 1) okCall (should change callee and emit Wrote) ==");
let tx = await caller.okCall(100);
let rcpt = await tx.wait();
console.log("okCall txHash", rcpt.transactionHash);
console.log("Decoded logs:", await decodeLogs(rcpt, ifaces));
console.log("Callee storage after okCall:", await caller.readCallee());
console.log("\n== 2) testRevertRollback (callee reverts after write) ==");
tx = await caller.testRevertRollback(200);
rcpt = await tx.wait();
console.log("testRevertRollback txHash", rcpt.transactionHash);
const logs2 = await decodeLogs(rcpt, ifaces);
console.log("Decoded logs:", logs2);
console.log("Callee storage after testRevertRollback:", await caller.readCallee());
console.log("\n== 3) testPanicRollback (callee assert -> panic) ==");
tx = await caller.testPanicRollback(300);
rcpt = await tx.wait();
console.log("testPanicRollback txHash", rcpt.transactionHash);
const logs3 = await decodeLogs(rcpt, ifaces);
console.log("Decoded logs:", logs3);
console.log("Callee storage after testPanicRollback:", await caller.readCallee());
console.log("\n== 4) testCreateRollback (constructor reverts) ==");
tx = await caller.testCreateRollback(999);
rcpt = await tx.wait();
console.log("testCreateRollback txHash", rcpt.transactionHash);
const logs4 = await decodeLogs(rcpt, ifaces);
console.log("Decoded logs:", logs4);
console.log("Callee storage after testCreateRollback:", await caller.readCallee());
console.log('\nDone');
}
main().catch((e) => {
console.error(e);
process.exitCode = 1;
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment