一种非常简单的模拟Solidity智能合约交易的方法

一种非常简单的模拟Solidity智能合约交易的方法

我们知道,在MetaMask调用合约时,会模拟执行一次,如果调用失败,会提前显示失败并问你是否要强制执行。这个功能很有用的,那么我们自己能不能实现类似的功能呢?

答案是肯定的,并且也相当简单。

示例合约

我们先看测试合约:

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

contract MockTest {
    uint public x = 5;

    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner {
        require(msg.sender == owner, "only owner");
        _;
    }

    function changeX(uint _x) external onlyOwner returns(uint value, address sender) {
        x = _x;
        return (_x * _x,msg.sender);
    }
}

合约很简单,只有管理员能改变x的值并且进行相关计算(操作)。这里只是简单计算了x的平方来模拟合约中复杂的操作过程。

那我们有时候想自己模拟运行一下,并得到相应的操作结果,能否实现呢?

答案就在下方 -_- !

模拟方法

请看下面的单元测试文件:

const { expect,assert } = require("chai");
const { ethers } = require("hardhat");

describe("Mock test", function () {

    let instance;

    beforeEach(async () => {
        const MockTest = await ethers.getContractFactory("MockTest");
        instance = await MockTest.deploy();
    });

    it("Call without owner will be failed" , async () => {

        let data = instance.interface.encodeFunctionData("changeX",[9]);
        let AddressOne = ethers.utils.getAddress("0x" + "0".repeat(39) + "1");

        let transaction = {
            from:AddressOne,
            to:instance.address,
            data
        };
        try {
            await ethers.provider.call(transaction);
        }catch(e) {
            assert.equal(e.message,"VM Exception while processing transaction: reverted with reason string 'only owner'");
            return;
        }
        throw("Test Failed");
    });

    it("Call with owner will be successful", async () => {

        let data = instance.interface.encodeFunctionData("changeX",[9]);
        let owner = await instance.owner();

        let transaction = {
            from:owner,
            to:instance.address,
            data
        };
        let result =  await ethers.provider.call(transaction);
        const {value,sender} = instance.interface.decodeFunctionResult("changeX",result);
        expect(value).to.be.equal(81);
        expect(sender).to.be.equal(owner);
        expect(await instance.x()).to.be.equal(5);
    });
});

运行单元测试的结果为:

  Mock test
    ✔ Call without owner will be failed (40ms)
    ✔ Call with owner will be successful


  2 passing (619ms)

那么,有的小伙伴要问了,如果别人把这个owner设置为私有变量,我怎么去获取这个owner呢?

记住,私有变量只是对链上合约不可见,对链下是没有办法隐藏的。以太坊一切可是公开透明的。

例如我们可以通过观察合约部署者,平常具有管理员权限的函数的调用,直接读取相应插槽等方法来获取这个owner

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AiMateZero

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值