[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-1be53bc6-f38d-4ce9-aff1-7ce43de87612":3,"$fUse25pBfQgUiKkTMdd3OcZv5MwHTURaybmTw4dEyTrU":43},{"id":4,"title":5,"description":6,"categoryId":7,"moduleId":8,"tags":9,"prompt":10,"icon":11,"source":12,"sourceUrl":13,"authorId":14,"authorName":15,"isPublic":16,"stars":17,"runs":18,"createdAt":19,"updatedAt":19,"module":20,"category":27,"packages":34},"1be53bc6-f38d-4ce9-aff1-7ce43de87612","web3-testing","掌握使用Hardhat、Foundry和高级测试模式进行智能合约全面测试的策略。","cat_coding_review","mod_coding","sickn33,coding","---\nname: web3-testing\ndescription: \"Master comprehensive testing strategies for smart contracts using Hardhat, Foundry, and advanced testing patterns.\"\nrisk: unknown\nsource: community\ndate_added: \"2026-02-27\"\n---\n\n# Web3 Smart Contract Testing\n\nMaster comprehensive testing strategies for smart contracts using Hardhat, Foundry, and advanced testing patterns.\n\n## Do not use this skill when\n\n- The task is unrelated to web3 smart contract testing\n- You need a different domain or tool outside this scope\n\n## Instructions\n\n- Clarify goals, constraints, and required inputs.\n- Apply relevant best practices and validate outcomes.\n- Provide actionable steps and verification.\n- If detailed examples are required, open `resources\u002Fimplementation-playbook.md`.\n\n## Use this skill when\n\n- Writing unit tests for smart contracts\n- Setting up integration test suites\n- Performing gas optimization testing\n- Fuzzing for edge cases\n- Forking mainnet for realistic testing\n- Automating test coverage reporting\n- Verifying contracts on Etherscan\n\n## Hardhat Testing Setup\n\n```javascript\n\u002F\u002F hardhat.config.js\nrequire(\"@nomicfoundation\u002Fhardhat-toolbox\");\nrequire(\"@nomiclabs\u002Fhardhat-etherscan\");\nrequire(\"hardhat-gas-reporter\");\nrequire(\"solidity-coverage\");\n\nmodule.exports = {\n  solidity: {\n    version: \"0.8.19\",\n    settings: {\n      optimizer: {\n        enabled: true,\n        runs: 200,\n      },\n    },\n  },\n  networks: {\n    hardhat: {\n      forking: {\n        url: process.env.MAINNET_RPC_URL,\n        blockNumber: 15000000,\n      },\n    },\n    goerli: {\n      url: process.env.GOERLI_RPC_URL,\n      accounts: [process.env.PRIVATE_KEY],\n    },\n  },\n  gasReporter: {\n    enabled: true,\n    currency: \"USD\",\n    coinmarketcap: process.env.COINMARKETCAP_API_KEY,\n  },\n  etherscan: {\n    apiKey: process.env.ETHERSCAN_API_KEY,\n  },\n};\n```\n\n## Unit Testing Patterns\n\n```javascript\nconst { expect } = require(\"chai\");\nconst { ethers } = require(\"hardhat\");\nconst {\n  loadFixture,\n  time,\n} = require(\"@nomicfoundation\u002Fhardhat-network-helpers\");\n\ndescribe(\"Token Contract\", function () {\n  \u002F\u002F Fixture for test setup\n  async function deployTokenFixture() {\n    const [owner, addr1, addr2] = await ethers.getSigners();\n\n    const Token = await ethers.getContractFactory(\"Token\");\n    const token = await Token.deploy();\n\n    return { token, owner, addr1, addr2 };\n  }\n\n  describe(\"Deployment\", function () {\n    it(\"Should set the right owner\", async function () {\n      const { token, owner } = await loadFixture(deployTokenFixture);\n      expect(await token.owner()).to.equal(owner.address);\n    });\n\n    it(\"Should assign total supply to owner\", async function () {\n      const { token, owner } = await loadFixture(deployTokenFixture);\n      const ownerBalance = await token.balanceOf(owner.address);\n      expect(await token.totalSupply()).to.equal(ownerBalance);\n    });\n  });\n\n  describe(\"Transactions\", function () {\n    it(\"Should transfer tokens between accounts\", async function () {\n      const { token, owner, addr1 } = await loadFixture(deployTokenFixture);\n\n      await expect(token.transfer(addr1.address, 50)).to.changeTokenBalances(\n        token,\n        [owner, addr1],\n        [-50, 50],\n      );\n    });\n\n    it(\"Should fail if sender doesn't have enough tokens\", async function () {\n      const { token, addr1 } = await loadFixture(deployTokenFixture);\n      const initialBalance = await token.balanceOf(addr1.address);\n\n      await expect(\n        token.connect(addr1).transfer(owner.address, 1),\n      ).to.be.revertedWith(\"Insufficient balance\");\n    });\n\n    it(\"Should emit Transfer event\", async function () {\n      const { token, owner, addr1 } = await loadFixture(deployTokenFixture);\n\n      await expect(token.transfer(addr1.address, 50))\n        .to.emit(token, \"Transfer\")\n        .withArgs(owner.address, addr1.address, 50);\n    });\n  });\n\n  describe(\"Time-based tests\", function () {\n    it(\"Should handle time-locked operations\", async function () {\n      const { token } = await loadFixture(deployTokenFixture);\n\n      \u002F\u002F Increase time by 1 day\n      await time.increase(86400);\n\n      \u002F\u002F Test time-dependent functionality\n    });\n  });\n\n  describe(\"Gas optimization\", function () {\n    it(\"Should use gas efficiently\", async function () {\n      const { token } = await loadFixture(deployTokenFixture);\n\n      const tx = await token.transfer(addr1.address, 100);\n      const receipt = await tx.wait();\n\n      expect(receipt.gasUsed).to.be.lessThan(50000);\n    });\n  });\n});\n```\n\n## Foundry Testing (Forge)\n\n```solidity\n\u002F\u002F SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"forge-std\u002FTest.sol\";\nimport \"..\u002Fsrc\u002FToken.sol\";\n\ncontract TokenTest is Test {\n    Token token;\n    address owner = address(1);\n    address user1 = address(2);\n    address user2 = address(3);\n\n    function setUp() public {\n        vm.prank(owner);\n        token = new Token();\n    }\n\n    function testInitialSupply() public {\n        assertEq(token.totalSupply(), 1000000 * 10**18);\n    }\n\n    function testTransfer() public {\n        vm.prank(owner);\n        token.transfer(user1, 100);\n\n        assertEq(token.balanceOf(user1), 100);\n        assertEq(token.balanceOf(owner), token.totalSupply() - 100);\n    }\n\n    function testFailTransferInsufficientBalance() public {\n        vm.prank(user1);\n        token.transfer(user2, 100); \u002F\u002F Should fail\n    }\n\n    function testCannotTransferToZeroAddress() public {\n        vm.prank(owner);\n        vm.expectRevert(\"Invalid recipient\");\n        token.transfer(address(0), 100);\n    }\n\n    \u002F\u002F Fuzzing test\n    function testFuzzTransfer(uint256 amount) public {\n        vm.assume(amount > 0 && amount \u003C= token.totalSupply());\n\n        vm.prank(owner);\n        token.transfer(user1, amount);\n\n        assertEq(token.balanceOf(user1), amount);\n    }\n\n    \u002F\u002F Test with cheatcodes\n    function testDealAndPrank() public {\n        \u002F\u002F Give ETH to address\n        vm.deal(user1, 10 ether);\n\n        \u002F\u002F Impersonate address\n        vm.prank(user1);\n\n        \u002F\u002F Test functionality\n        assertEq(user1.balance, 10 ether);\n    }\n\n    \u002F\u002F Mainnet fork test\n    function testForkMainnet() public {\n        vm.createSelectFork(\"https:\u002F\u002Feth-mainnet.alchemyapi.io\u002Fv2\u002F...\");\n\n        \u002F\u002F Interact with mainnet contracts\n        address dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n        assertEq(IERC20(dai).symbol(), \"DAI\");\n    }\n}\n```\n\n## Advanced Testing Patterns\n\n### Snapshot and Revert\n\n```javascript\ndescribe(\"Complex State Changes\", function () {\n  let snapshotId;\n\n  beforeEach(async function () {\n    snapshotId = await network.provider.send(\"evm_snapshot\");\n  });\n\n  afterEach(async function () {\n    await network.provider.send(\"evm_revert\", [snapshotId]);\n  });\n\n  it(\"Test 1\", async function () {\n    \u002F\u002F Make state changes\n  });\n\n  it(\"Test 2\", async function () {\n    \u002F\u002F State reverted, clean slate\n  });\n});\n```\n\n### Mainnet Forking\n\n```javascript\ndescribe(\"Mainnet Fork Tests\", function () {\n  let uniswapRouter, dai, usdc;\n\n  before(async function () {\n    await network.provider.request({\n      method: \"hardhat_reset\",\n      params: [\n        {\n          forking: {\n            jsonRpcUrl: process.env.MAINNET_RPC_URL,\n            blockNumber: 15000000,\n          },\n        },\n      ],\n    });\n\n    \u002F\u002F Connect to existing mainnet contracts\n    uniswapRouter = await ethers.getContractAt(\n      \"IUniswapV2Router\",\n      \"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D\",\n    );\n\n    dai = await ethers.getContractAt(\n      \"IERC20\",\n      \"0x6B175474E89094C44Da98b954EedeAC495271d0F\",\n    );\n  });\n\n  it(\"Should swap on Uniswap\", async function () {\n    \u002F\u002F Test with real Uniswap contracts\n  });\n});\n```\n\n### Impersonating Accounts\n\n```javascript\nit(\"Should impersonate whale account\", async function () {\n  const whaleAddress = \"0x...\";\n\n  await network.provider.request({\n    method: \"hardhat_impersonateAccount\",\n    params: [whaleAddress],\n  });\n\n  const whale = await ethers.getSigner(whaleAddress);\n\n  \u002F\u002F Use whale's tokens\n  await dai\n    .connect(whale)\n    .transfer(addr1.address, ethers.utils.parseEther(\"1000\"));\n});\n```\n\n## Gas Optimization Testing\n\n```javascript\nconst { expect } = require(\"chai\");\n\ndescribe(\"Gas Optimization\", function () {\n  it(\"Compare gas usage between implementations\", async function () {\n    const Implementation1 =\n      await ethers.getContractFactory(\"OptimizedContract\");\n    const Implementation2 = await ethers.getContractFactory(\n      \"UnoptimizedContract\",\n    );\n\n    const contract1 = await Implementation1.deploy();\n    const contract2 = await Implementation2.deploy();\n\n    const tx1 = await contract1.doSomething();\n    const receipt1 = await tx1.wait();\n\n    const tx2 = await contract2.doSomething();\n    const receipt2 = await tx2.wait();\n\n    console.log(\"Optimized gas:\", receipt1.gasUsed.toString());\n    console.log(\"Unoptimized gas:\", receipt2.gasUsed.toString());\n\n    expect(receipt1.gasUsed).to.be.lessThan(receipt2.gasUsed);\n  });\n});\n```\n\n## Coverage Reporting\n\n```bash\n# Generate coverage report\nnpx hardhat coverage\n\n# Output shows:\n# File                | % Stmts | % Branch | % Funcs | % Lines |\n# -------------------|---------|----------|---------|---------|\n# contracts\u002FToken.sol |   100   |   90     |   100   |   95    |\n```\n\n## Contract Verification\n\n```javascript\n\u002F\u002F Verify on Etherscan\nawait hre.run(\"verify:verify\", {\n  address: contractAddress,\n  constructorArguments: [arg1, arg2],\n});\n```\n\n```bash\n# Or via CLI\nnpx hardhat verify --network mainnet CONTRACT_ADDRESS \"Constructor arg1\" \"arg2\"\n```\n\n## CI\u002FCD Integration\n\n```yaml\n# .github\u002Fworkflows\u002Ftest.yml\nname: Tests\n\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions\u002Fcheckout@v2\n      - uses: actions\u002Fsetup-node@v2\n        with:\n          node-version: \"16\"\n\n      - run: npm install\n      - run: npx hardhat compile\n      - run: npx hardhat test\n      - run: npx hardhat coverage\n\n      - name: Upload coverage to Codecov\n        uses: codecov\u002Fcodecov-action@v2\n```\n\n## Resources\n\n- **references\u002Fhardhat-setup.md**: Hardhat configuration guide\n- **references\u002Ffoundry-setup.md**: Foundry testing framework\n- **references\u002Ftest-patterns.md**: Testing best practices\n- **references\u002Fmainnet-forking.md**: Fork testing strategies\n- **references\u002Fcontract-verification.md**: Etherscan verification\n- **assets\u002Fhardhat-config.js**: Complete Hardhat configuration\n- **assets\u002Ftest-suite.js**: Comprehensive test examples\n- **assets\u002Ffoundry.toml**: Foundry configuration\n- **scripts\u002Ftest-contract.sh**: Automated testing script\n\n## Best Practices\n\n1. **Test Coverage**: Aim for >90% coverage\n2. **Edge Cases**: Test boundary conditions\n3. **Gas Limits**: Verify functions don't hit block gas limit\n4. **Reentrancy**: Test for reentrancy vulnerabilities\n5. **Access Control**: Test unauthorized access attempts\n6. **Events**: Verify event emissions\n7. **Fixtures**: Use fixtures to avoid code duplication\n8. **Mainnet Fork**: Test with real contracts\n9. **Fuzzing**: Use property-based testing\n10. **CI\u002FCD**: Automate testing on every commit\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.\n","","imported","https:\u002F\u002Fgithub.com\u002Fsickn33\u002Fantigravity-awesome-skills","user_system_seed","SkillOPIC",true,188,1893,"2026-05-16 13:46:47",{"id":8,"name":21,"slug":22,"icon":23,"description":24,"sort":25,"createdAt":26},"编程开发","coding","mdi-code-braces","代码生成、调试、审查，提升开发效率",2,"2026-05-16 12:53:40",{"id":7,"name":28,"slug":29,"icon":30,"description":31,"moduleId":8,"sort":32,"skillCount":33,"createdAt":26},"代码审查","review","mdi-magnify-scan","代码质量分析、安全审查",4,145,[35],{"id":36,"skillId":4,"version":37,"fileName":38,"fileSize":39,"filePath":40,"fileHash":41,"manifest":42,"createdAt":19},"41a61f30-3e8e-468b-a649-4501f0fa03fd","1.0.0","web3-testing.zip",3941,"uploads\u002Fskills\u002F1be53bc6-f38d-4ce9-aff1-7ce43de87612\u002Fweb3-testing.zip","b1890a0aeb4ae0f63a07a7728692edf37a298a146020804bcec3502bfc04b785","[{\"path\":\"SKILL.md\",\"isDirectory\":false,\"size\":11386}]",{"code":44,"message":45,"data":46},200,"success",{"items":47,"stats":48,"page":51},[],{"averageRating":49,"totalRatings":49,"ratingCounts":50},0,[49,49,49,49,49],{"limit":52,"offset":49,"hasMore":53,"nextOffset":52,"ratedOnly":16},15,false]