Solidity合约审计:让你的区块链代码硬核到滴水不漏

Solidity里一个超级硬核的主题——合约审计!在以太坊上写智能合约,钱和数据都直接挂在链上,一个小漏洞就能让黑客把你钱包掏空,项目直接翻车!审计就是给你的合约做个全身体检,找出那些藏得深的bug和安全隐患。这篇干货会用大白话把Solidity合约审计的硬核技巧讲得明明白白,从重入攻击、溢出检查到

Solidity里一个超级硬核的主题——合约审计!在以太坊上写智能合约,钱和数据都直接挂在链上,一个小漏洞就能让黑客把你钱包掏空,项目直接翻车!审计就是给你的合约做个全身体检,找出那些藏得深的bug和安全隐患。这篇干货会用大白话把Solidity合约审计的硬核技巧讲得明明白白,从重入攻击、溢出检查到权限管理、Gas陷阱,配合OpenZeppelin、Hardhat测试和Slither分析,带你一步步打造滴水不漏的合约。

合约审计的核心概念

先搞清楚几个关键点:

  • 为什么审计:以太坊合约不可更改,漏洞上线后修复成本高,资金可能被盗。
  • 常见漏洞
    • 重入攻击:外部调用未完成前被重复调用,篡改状态。
    • 溢出/下溢:数学运算超出变量范围,导致错误结果。
    • 权限控制:未限制函数调用,可能被恶意用户滥用。
    • Gas限制:循环或复杂逻辑耗尽Gas,导致拒绝服务。
    • 逻辑错误:业务逻辑不符合预期,如代币转移错误。
    • 预言机依赖:外部数据不可靠,可能被操控。
  • 审计工具
    • Slither:静态分析工具,检测漏洞和代码问题。
    • Mythril:符号执行,找逻辑漏洞。
    • Hardhat:测试和调试合约。
    • OpenZeppelin:提供安全库,减少重复造轮子。
  • 审计步骤
    • 静态分析:用工具扫描代码。
    • 动态测试:写测试用例模拟攻击。
    • 手动审查:检查逻辑和业务需求。
  • Solidity 0.8.x:自带溢出/下溢检查,减少部分漏洞。

咱们用Solidity 0.8.20,结合OpenZeppelin、Hardhat和Slither,逐一分析常见漏洞和修复方案。

环境准备

用Hardhat搭建开发环境,集成Slither。

mkdir contract-audit-demo
cd contract-audit-demo
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox @openzeppelin/contracts
npm install ethers
npm install --save-dev slither-analyzer

初始化Hardhat:

npx hardhat init

选择TypeScript项目,安装依赖:

npm install --save-dev ts-node typescript @types/node @types/mocha

目录结构:

contract-audit-demo/
├── contracts/
│   ├── Reentrancy.sol
│   ├── Overflow.sol
│   ├── AccessControl.sol
│   ├── GasTrap.sol
│   ├── LogicError.sol
│   ├── OracleDependency.sol
├── scripts/
│   ├── deploy.ts
├── test/
│   ├── Audit.test.ts
├── hardhat.config.ts
├── tsconfig.json
├── package.json

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "CommonJS",
    "strict": true,
    "esModuleInterop": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "outDir": "./dist",
    "rootDir": "./"
  },
  "include": ["hardhat.config.ts", "scripts", "test"]
}

hardhat.config.ts

import { HardhatUserConfig } from "hardhat/config";
import "@nomicfoundation/hardhat-toolbox";

const config: HardhatUserConfig = {
  solidity: {
    version: "0.8.20",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200
      }
    }
  },
  networks: {
    hardhat: {
      chainId: 1337,
    },
  },
};

export default config;

跑本地节点:

npx hardhat node

跑Slither分析:

slither .

重入攻击

重入攻击是合约大杀器,攻击者通过回调重复调用合约,篡改状态。

问题代码

contracts/Reentrancy.sol

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

contract VulnerableBank {
    mapping(address => uint256) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
        balances[msg.sender] -= amount;
    }
}

解析

  • 漏洞
    • withdraw先发送ETH(call),后更新balances
    • 攻击者通过fallbackreceive函数在ETH到达时再次调用withdraw,重复提取。
  • 攻击场景
    • 攻击者存入1 ETH。
    • 调用withdraw(1 ETH),触发call,ETH到达攻击者合约。
    • 攻击者合约的receive再次调用withdraw,余额未更新,继续提取。
  • Slither检测
    • slither .,提示reentrancy-eth漏洞,建议检查调用顺序。

修复代码

contracts/Reentrancy.sol(更新):

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

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract SecureBank is ReentrancyGuard {
    mapping(address => uint256) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public nonReentrant {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
    }
}

修复解析

  • 方案
    • 用OpenZeppelin的ReentrancyGuard
    • nonReentrant修饰符防止重复进入。
    • 先更新状态(balances),后发送ETH。
  • 原理
    • nonReentrant设置锁,执行完函数释放,防止重入。
    • 状态更新在前,攻击者无法利用旧余额。
  • Slither:修复后无reentrancy-eth警告。

测试

test/Audit.test.ts

import { ethers } from "hardhat";
import { expect } from "chai";
import { VulnerableBank, SecureBank } from "../typechain-types";

describe("Reentrancy", function () {
  let vulnerable: VulnerableBank;
  let secure: SecureBank;
  let attacker: any;
  let owner: any;

  beforeEach(async function () {
    [owner, attacker] = await ethers.getSigners();
    const VulnerableFactory = await ethers.getContractFactory("VulnerableBank");
    vulnerable = await VulnerableFactory.deploy();
    await vulnerable.deployed();

    const SecureFactory = await ethers.getContractFactory("SecureBank");
    secure = await SecureFactory.deploy();
    await secure.deployed();

    const AttackerFactory = await ethers.getContractFactory("ReentrancyAttacker");
    attacker = await AttackerFactory.deploy(vulnerable.address);
    await attacker.deployed();
  });

  it("should allow reentrancy attack on VulnerableBank", async function () {
    await vulnerable.deposit({ value: ethers.utils.parseEther("1") });
    await attacker.attack({ value: ethers.utils.parseEther("1") });
    expect(await ethers.provider.getBalance(vulnerable.address)).to.equal(0);
  });

  it("should prevent reentrancy on SecureBank", async function () {
    const AttackerFactory = await ethers.getContractFactory("ReentrancyAttacker");
    const secureAttacker = await AttackerFactory.deploy(secure.address);
    await secureAttacker.deployed();
    await secure.deposit({ value: ethers.utils.parseEther("1") });
    await expect(secureAttacker.attack({ value: ethers.utils.parseEther("1") })).to.be.revertedWith("ReentrancyGuard: reentrant call");
  });
});

contracts/ReentrancyAttacker.sol

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

contract ReentrancyAttacker {
    VulnerableBank public bank;

    constructor(address _bank) {
        bank = VulnerableBank(_bank);
    }

    function attack() public payable {
        bank.deposit{value: msg.value}();
        bank.withdraw(msg.value);
    }

    receive() external payable {
        if (address(bank).balance >= msg.value) {
            bank.withdraw(msg.value);
        }
    }
}
  • 测试解析
    • 攻击者合约对VulnerableBank发起重入攻击,掏空余额。
    • SecureBanknonReentrant阻止攻击,调用被revert。
  • GasnonReentrant增加少量Gas(~2k),但安全性大幅提升。

溢出/下溢漏洞

Solidity <0.8.0容易发生溢出/下溢,0.8.x已默认检查。

问题代码

contracts/Overflow.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0; // Vulnerable version

contract VulnerableMath {
    uint256 public balance;

    function addBalance(uint256 amount) public {
        balance += amount;
    }

    function subtractBalance(uint256 amount) public {
        balance -= amount;
    }
}

解析

  • 漏洞
    • uint256溢出:2^256 - 1 + 1变0。
    • uint256下溢:0 - 12^256 - 1
  • 攻击场景
    • 攻击者调用addBalance(2^256 - balance),使balance变0。
    • 攻击者调用subtractBalance(1),使balance变最大值。
  • Slither检测:提示arithmetic漏洞,建议加检查。

修复代码

contracts/Overflow.sol(更新):

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

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

contract SecureMath {
    uint256 public balance;

    function addBalance(uint256 amount) public {
        balance += amount; // Safe in 0.8.20
    }

    function subtractBalance(uint256 amount) public {
        require(balance >= amount, "Underflow");
        balance -= amount;
    }
}

修复解析

  • 方案
    • 用Solidity 0.8.x,自带溢出/下溢检查,抛出异常。
    • 可选:用OpenZeppelin的SafeMath(0.8.x前)。
    • 显式检查(如require)防止下溢。
  • Slither:0.8.x代码无arithmetic警告。
  • 注意:0.8.x检查增加Gas(~100),但安全第一。

测试

test/Audit.test.ts(添加):

import { VulnerableMath, SecureMath } from "../typechain-types";

describe("Overflow", function () {
  let vulnerable: VulnerableMath;
  let secure: SecureMath;

  beforeEach(async function () {
    const VulnerableFactory = await ethers.getContractFactory("VulnerableMath", { signer: owner, libraries: {} });
    vulnerable = await VulnerableFactory.deploy();
    await vulnerable.deployed();

    const SecureFactory = await ethers.getContractFactory("SecureMath");
    secure = await SecureFactory.deploy();
    await secure.deployed();
  });

  it("should allow overflow in VulnerableMath", async function () {
    await vulnerable.addBalance(ethers.constants.MaxUint256);
    await vulnerable.addBalance(1);
    expect(await vulnerable.balance()).to.equal(0);
  });

  it("should prevent overflow in SecureMath", async function () {
    await expect(secure.addBalance(ethers.constants.MaxUint256)).to.be.reverted;
  });

  it("should prevent underflow in SecureMath", async function () {
    await expect(secure.subtractBalance(1)).to.be.revertedWith("Underflow");
  });
});
  • 测试解析
    • VulnerableMath允许溢出,balance变0。
    • SecureMath阻止溢出和下溢,抛出异常。
  • Gas:0.8.x检查增加少量Gas,值安全。

权限控制漏洞

权限控制不严,恶意用户可调用敏感函数。

问题代码

contracts/AccessControl.sol

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

contract VulnerableAccess {
    address public owner;
    uint256 public funds;

    constructor() {
        owner = msg.sender;
    }

    function withdraw(uint256 amount) public {
        require(funds >= amount, "Insufficient funds");
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
        funds -= amount;
    }
}

解析

  • 漏洞
    • withdraw无权限检查,任何用户可调用。
    • 攻击者可直接提取funds
  • Slither检测:提示missing-access-control,建议加权限。

修复代码

contracts/AccessControl.sol(更新):

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

import "@openzeppelin/contracts/access/Ownable.sol";

contract SecureAccess is Ownable {
    uint256 public funds;

    constructor() Ownable() {}

    function deposit() public payable {
        funds += msg.value;
    }

    function withdraw(uint256 amount) public onlyOwner {
        require(funds >= amount, "Insufficient funds");
        funds -= amount;
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
    }
}

修复解析

  • 方案
    • 用OpenZeppelin的Ownable,限制withdrawonlyOwner
    • 先更新状态,后发送ETH。
  • Slither:修复后无missing-access-control警告。
  • 注意Ownable增加少量Gas(~1k),但权限安全。

测试

test/Audit.test.ts(添加):

import { VulnerableAccess, SecureAccess } from "../typechain-types";

describe("AccessControl", function () {
  let vulnerable: VulnerableAccess;
  let secure: SecureAccess;
  let owner: any, attacker: any;

  beforeEach(async function () {
    [owner, attacker] = await ethers.getSigners();
    const VulnerableFactory = await ethers.getContractFactory("VulnerableAccess");
    vulnerable = await VulnerableFactory.deploy();
    await vulnerable.deployed();

    const SecureFactory = await ethers.getContractFactory("SecureAccess");
    secure = await SecureFactory.deploy();
    await secure.deployed();

    await owner.sendTransaction({ to: vulnerable.address, value: ethers.utils.parseEther("1") });
    await secure.deposit({ value: ethers.utils.parseEther("1") });
  });

  it("should allow unauthorized access in VulnerableAccess", async function () {
    await vulnerable.connect(attacker).withdraw(ethers.utils.parseEther("1"));
    expect(await ethers.provider.getBalance(vulnerable.address)).to.equal(0);
  });

  it("should restrict access in SecureAccess", async function () {
    await expect(secure.connect(attacker).withdraw(ethers.utils.parseEther("1"))).to.be.revertedWith("Ownable: caller is not the owner");
    await secure.connect(owner).withdraw(ethers.utils.parseEther("1"));
    expect(await ethers.provider.getBalance(secure.address)).to.equal(0);
  });
});
  • 测试解析
    • VulnerableAccess允许任何人提取资金。
    • SecureAccess限制withdrawowner,攻击者调用失败。

Gas陷阱

复杂逻辑或循环可能耗尽Gas,导致拒绝服务。

问题代码

contracts/GasTrap.sol

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

contract VulnerableLoop {
    address[] public users;

    function addUser(address user) public {
        users.push(user);
    }

    function distributeFunds() public {
        for (uint256 i = 0; i &lt; users.length; i++) {
            (bool success, ) = users[i].call{value: 1 ether}("");
            require(success, "Transfer failed");
        }
    }
}

解析

  • 漏洞
    • distributeFunds循环发送ETH,users数组过大耗尽Gas。
    • 攻击者可不断调用addUser,增加循环成本。
  • Slither检测:提示gas-limit,建议优化循环。
  • 攻击场景:攻击者添加大量用户,导致distributeFunds失败。

修复代码

contracts/GasTrap.sol(更新):

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

contract SecureLoop {
    mapping(address => bool) public users;
    uint256 public userCount;
    mapping(address => uint256) public pendingWithdrawals;

    function addUser(address user) public {
        require(!users[user], "User already added");
        users[user] = true;
        userCount++;
    }

    function deposit() public payable {}

    function withdraw() public {
        uint256 amount = pendingWithdrawals[msg.sender];
        require(amount > 0, "No funds");
        pendingWithdrawals[msg.sender] = 0;
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
    }

    function distributeFunds() public {
        uint256 amount = address(this).balance / userCount;
        for (uint256 i = 0; i &lt; userCount; i++) {
            address user = users.keys[i]; // Assume keys tracked separately
            pendingWithdrawals[user] += amount;
        }
    }
}

修复解析

  • 方案
    • mapping代替数组,降低存储成本。
    • 推式转账(withdraw)代替拉式(distributeFunds)。
    • distributeFunds只更新pendingWithdrawals,不直接转账。
  • Slither:修复后无gas-limit警告。
  • 注意:需额外跟踪用户列表,mapping不直接支持遍历。

测试

test/Audit.test.ts(adding):

import { VulnerableLoop, SecureLoop } from "../typechain-types";

describe("GasTrap", function () {
  let vulnerable: VulnerableLoop;
  let secure: SecureLoop;
  let owner: any, user1: any;

  beforeEach(async function () {
    [owner, user1] = await ethers.getSigners();
    const VulnerableFactory = await ethers.getContractFactory("VulnerableLoop");
    vulnerable = await VulnerableFactory.deploy();
    await vulnerable.deployed();

    const SecureFactory = await ethers.getContractFactory("SecureLoop");
    secure = await SecureFactory.deploy();
    await secure.deployed();

    await vulnerable.addUser(user1.address);
    await secure.addUser(user1.address);
    await owner.sendTransaction({ to: vulnerable.address, value: ethers.utils.parseEther("1") });
    await secure.deposit({ value: ethers.utils.parseEther("1") });
  });

  it("should fail with large user list in VulnerableLoop", async function () {
    for (let i = 0; i &lt; 1000; i++) {
      await vulnerable.addUser(ethers.Wallet.createRandom().address);
    }
    await expect(vulnerable.distributeFunds()).to.be.reverted;
  });

  it("should handle large user list in SecureLoop", async function () {
    await secure.distributeFunds();
    await secure.connect(user1).withdraw();
    expect(await ethers.provider.getBalance(secure.address)).to.be.lt(ethers.utils.parseEther("1"));
  });
});
  • 测试解析
    • VulnerableLoop在大量用户时Gas超限。
    • SecureLoop通过推式转账避免Gas问题。

逻辑错误

业务逻辑错误可能导致功能不符合预期。

问题代码

contracts/LogicError.sol

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

contract VulnerableToken {
    mapping(address => uint256) public balances;
    uint256 public totalSupply;

    function transfer(address to, uint256 amount) public {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }

    function mint(address to, uint256 amount) public {
        totalSupply += amount;
        balances[to] += amount;
    }
}

解析

  • 漏洞
    • mint无权限控制,任何人可铸造代币。
    • 无事件记录,链上无法追踪。
  • Slither检测:提示missing-access-controlmissing-events

修复代码

contracts/LogicError.sol(update):

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract SecureToken is ERC20, Ownable {
    constructor() ERC20("SecureToken", "STK") Ownable() {}

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}

修复解析

  • 方案
    • 用OpenZeppelin的ERC20Ownable
    • mint限制为onlyOwner
    • ERC20自带Transfer事件,记录代币转移。
  • Slither:修复后无相关警告。

测试

test/Audit.test.ts(adding):

import { VulnerableToken, SecureToken } from "../typechain-types";

describe("LogicError", function () {
  let vulnerable: VulnerableToken;
  let secure: SecureToken;
  let owner: any, attacker: any;

  beforeEach(async function () {
    [owner, attacker] = await ethers.getSigners();
    const VulnerableFactory = await ethers.getContractFactory("VulnerableToken");
    vulnerable = await VulnerableFactory.deploy();
    await vulnerable.deployed();

    const SecureFactory = await ethers.getContractFactory("SecureToken");
    secure = await SecureFactory.deploy();
    await secure.deployed();
  });

  it("should allow unauthorized minting in VulnerableToken", async function () {
    await vulnerable.connect(attacker).mint(attacker.address, 1000);
    expect(await vulnerable.balances(attacker.address)).to.equal(1000);
  });

  it("should restrict minting in SecureToken", async function () {
    await expect(secure.connect(attacker).mint(attacker.address, 1000)).to.be.revertedWith("Ownable: caller is not the owner");
    await secure.connect(owner).mint(owner.address, 1000);
    expect(await secure.balanceOf(owner.address)).to.equal(1000);
  });
});
  • 测试解析
    • VulnerableToken允许任何人铸造。
    • SecureToken限制mintowner

预言机依赖

依赖不可靠预言机可能导致数据被操控。

问题 code

contracts/OracleDependency.sol

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

contract VulnerableOracle {
    address public oracle;
    uint256 public price;

    constructor(address _oracle) {
        oracle = _oracle;
    }

    function updatePrice(uint256 _price) public {
        require(msg.sender == oracle, "Not oracle");
        price = _price;
    }

    function buy(uint256 amount) public payable {
        require(msg.value >= amount * price, "Insufficient payment");
        // Process purchase
    }
}

解析

  • 漏洞
    • oracle可随意更新price,无验证。
    • 攻击者控制oracle,可设置错误价格。
  • Slither检测:提示unprotected-oracle

修复代码

contracts/OracleDependency.sol(update):

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

import "@openzeppelin/contracts/access/Ownable.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract SecureOracle is Ownable {
    AggregatorV3Interface public oracle;
    uint256 public price;

    constructor(address _oracle) Ownable() {
        oracle = AggregatorV3Interface(_oracle);
    }

    function updatePrice() public onlyOwner {
        (, int256 answer,,,) = oracle.latestRoundData();
        require(answer > 0, "Invalid price");
        price = uint256(answer);
    }

    function buy(uint256 amount) public payable {
        require(msg.value >= amount * price, "Insufficient payment");
        // Process purchase
    }
}

修复解析

  • 方案
    • 用Chainlink的AggregatorV3Interface获取可信价格。
    • updatePrice限制为onlyOwner
    • 验证价格有效性。
  • Slither:修复后无unprotected-oracle警告。
  • 注意:需配置Chainlink Feed地址(如Sepolia ETH/USD)。

测试

test/Audit.test.ts(adding):

import { VulnerableOracle, SecureOracle } from "../typechain-types";

describe("OracleDependency", function () {
  let vulnerable: VulnerableOracle;
  let secure: SecureOracle;
  let owner: any, attacker: any;

  beforeEach(async function () {
    [owner, attacker] = await ethers.getSigners();
    const VulnerableFactory = await ethers.getContractFactory("VulnerableOracle");
    vulnerable = await VulnerableFactory.deploy(attacker.address);
    await vulnerable.deployed();

    const SecureFactory = await ethers.getContractFactory("SecureOracle");
    secure = await SecureFactory.deploy("0x694AA1769357215DE4FAC081bf1f309aDC325306");
    await secure.deployed();
  });

  it("should allow oracle manipulation in VulnerableOracle", async function () {
    await vulnerable.connect(attacker).updatePrice(1);
    expect(await vulnerable.price()).to.equal(1);
  });

  it("should restrict oracle updates in SecureOracle", async function () {
    await expect(secure.connect(attacker).updatePrice()).to.be.revertedWith("Ownable: caller is not the owner");
    await secure.connect(owner).updatePrice();
    expect(await secure.price()).to.be.gt(0);
  });
});
  • 测试解析
    • VulnerableOracle允许攻击者操控价格。
    • SecureOracle限制更新并验证价格。

部署脚本

scripts/deploy.ts

import { ethers } from "hardhat";

async function main() {
  const [owner] = await ethers.getSigners();

  const VulnerableBankFactory = await ethers.getContractFactory("VulnerableBank");
  const vulnerableBank = await VulnerableBankFactory.deploy();
  await vulnerableBank.deployed();
  console.log(`VulnerableBank deployed to: ${vulnerableBank.address}`);

  const SecureBankFactory = await ethers.getContractFactory("SecureBank");
  const secureBank = await SecureBankFactory.deploy();
  await secureBank.deployed();
  console.log(`SecureBank deployed to: ${secureBank.address}`);

  const VulnerableMathFactory = await ethers.getContractFactory("VulnerableMath", { signer: owner, libraries: {} });
  const vulnerableMath = await VulnerableMathFactory.deploy();
  await vulnerableMath.deployed();
  console.log(`VulnerableMath deployed to: ${vulnerableMath.address}`);

  const SecureMathFactory = await ethers.getContractFactory("SecureMath");
  const secureMath = await SecureMathFactory.deploy();
  await secureMath.deployed();
  console.log(`SecureMath deployed to: ${secureMath.address}`);

  const VulnerableAccessFactory = await ethers.getContractFactory("VulnerableAccess");
  const vulnerableAccess = await VulnerableAccessFactory.deploy();
  await vulnerableAccess.deployed();
  console.log(`VulnerableAccess deployed to: ${vulnerableAccess.address}`);

  const SecureAccessFactory = await ethers.getContractFactory("SecureAccess");
  const secureAccess = await SecureAccessFactory.deploy();
  await secureAccess.deployed();
  console.log(`SecureAccess deployed to: ${secureAccess.address}`);

  const VulnerableLoopFactory = await ethers.getContractFactory("VulnerableLoop");
  const vulnerableLoop = await VulnerableLoopFactory.deploy();
  await vulnerableLoop.deployed();
  console.log(`VulnerableLoop deployed to: ${vulnerableLoop.address}`);

  const SecureLoopFactory = await ethers.getContractFactory("SecureLoop");
  const secureLoop = await SecureLoopFactory.deploy();
  await secureLoop.deployed();
  console.log(`SecureLoop deployed to: ${secureLoop.address}`);

  const VulnerableTokenFactory = await ethers.getContractFactory("VulnerableToken");
  const vulnerableToken = await VulnerableTokenFactory.deploy();
  await vulnerableToken.deployed();
  console.log(`VulnerableToken deployed to: ${vulnerableToken.address}`);

  const SecureTokenFactory = await ethers.getContractFactory("SecureToken");
  const secureToken = await SecureTokenFactory.deploy();
  await secureToken.deployed();
  console.log(`SecureToken deployed to: ${secureToken.address}`);

  const VulnerableOracleFactory = await ethers.getContractFactory("VulnerableOracle");
  const vulnerableOracle = await VulnerableOracleFactory.deploy(owner.address);
  await vulnerableOracle.deployed();
  console.log(`VulnerableOracle deployed to: ${vulnerableOracle.address}`);

  const SecureOracleFactory = await ethers.getContractFactory("SecureOracle");
  const secureOracle = await SecureOracleFactory.deploy("0x694AA1769357215DE4FAC081bf1f309aDC325306");
  await secureOracle.deployed();
  console.log(`SecureOracle deployed to: ${secureOracle.address}`);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

跑部署:

npx hardhat run scripts/deploy.ts --network hardhat

审计流程

  • 静态分析
    • slither .,检查reentrancyarithmeticaccess-control等。
    • 修正所有高危和中危问题。
  • 动态测试
    • 用Hardhat写攻击测试用例,模拟漏洞利用。
    • 验证修复代码的安全性。
  • 手动审查
    • 检查业务逻辑,确保符合需求。
    • 核对存储布局,防止冲突。
    • 验证权限和事件。

跑代码,体验Solidity合约审计的硬核玩法吧!

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
天涯学馆
天涯学馆
0x9d6d...50d5
资深大厂程序员,12年开发经验,致力于探索前沿技术!