{"id":"defi-protocol-templates","name":"defi-protocol-templates","summary":"ステーキング、AMM、ガバナンス、フラッシュローンのための本番対応テンプレートを備えたDeFiプロトコルを実装しましょう。","body":"# DeFi Protocol Templates\n\nProduction-ready templates for common DeFi protocols including staking, AMMs, governance, and flash loans.\n\n## When to Use This Skill\n\n- Building staking platforms with reward distribution\n- Implementing AMM (Automated Market Maker) protocols\n- Creating governance token systems\n- Integrating flash loan functionality\n\n## Staking Contract\n\n```solidity\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\n\ncontract StakingRewards is ReentrancyGuard, Ownable {\n    IERC20 public stakingToken;\n    IERC20 public rewardsToken;\n\n    uint256 public rewardRate = 100; // Rewards per second\n    uint256 public lastUpdateTime;\n    uint256 public rewardPerTokenStored;\n\n    mapping(address => uint256) public userRewardPerTokenPaid;\n    mapping(address => uint256) public rewards;\n    mapping(address => uint256) public balances;\n\n    uint256 private _totalSupply;\n\n    event Staked(address indexed user, uint256 amount);\n    event Withdrawn(address indexed user, uint256 amount);\n    event RewardPaid(address indexed user, uint256 reward);\n\n    constructor(address _stakingToken, address _rewardsToken) {\n        stakingToken = IERC20(_stakingToken);\n        rewardsToken = IERC20(_rewardsToken);\n    }\n\n    modifier updateReward(address account) {\n        rewardPerTokenStored = rewardPerToken();\n        lastUpdateTime = block.timestamp;\n\n        if (account != address(0)) {\n            rewards[account] = earned(account);\n            userRewardPerTokenPaid[account] = rewardPerTokenStored;\n        }\n        _;\n    }\n\n    function rewardPerToken() public view returns (uint256) {\n        if (_totalSupply == 0) {\n            return rewardPerTokenStored;\n        }\n        return rewardPerTokenStored +\n            ((block.timestamp - lastUpdateTime) * rewardRate * 1e18) / _totalSupply;\n    }\n\n    function earned(address account) public view returns (uint256) {\n        return (balances[account] *\n            (rewardPerToken() - userRewardPerTokenPaid[account])) / 1e18 +\n            rewards[account];\n    }\n\n    function stake(uint256 amount) external nonReentrant updateReward(msg.sender) {\n        require(amount > 0, \"Cannot stake 0\");\n        _totalSupply += amount;\n        balances[msg.sender] += amount;\n        stakingToken.transferFrom(msg.sender, address(this), amount);\n        emit Staked(msg.sender, amount);\n    }\n\n    function withdraw(uint256 amount) public nonReentrant updateReward(msg.sender) {\n        require(amount > 0, \"Cannot withdraw 0\");\n        _totalSupply -= amount;\n        balances[msg.sender] -= amount;\n        stakingToken.transfer(msg.sender, amount);\n        emit Withdrawn(msg.sender, amount);\n    }\n\n    function getReward() public nonReentrant updateReward(msg.sender) {\n        uint256 reward = rewards[msg.sender];\n        if (reward > 0) {\n            rewards[msg.sender] = 0;\n            rewardsToken.transfer(msg.sender, reward);\n            emit RewardPaid(msg.sender, reward);\n        }\n    }\n\n    function exit() external {\n        withdraw(balances[msg.sender]);\n        getReward();\n    }\n}\n```\n\n## AMM (Automated Market Maker)\n\n```solidity\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ncontract SimpleAMM {\n    IERC20 public token0;\n    IERC20 public token1;\n\n    uint256 public reserve0;\n    uint256 public reserve1;\n\n    uint256 public totalSupply;\n    mapping(address => uint256) public balanceOf;\n\n    event Mint(address indexed to, uint256 amount);\n    event Burn(address indexed from, uint256 amount);\n    event Swap(address indexed trader, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out);\n\n    constructor(address _token0, address _token1) {\n        token0 = IERC20(_token0);\n        token1 = IERC20(_token1);\n    }\n\n    function addLiquidity(uint256 amount0, uint256 amount1) external returns (uint256 shares) {\n        token0.transferFrom(msg.sender, address(this), amount0);\n        token1.transferFrom(msg.sender, address(this), amount1);\n\n        if (totalSupply == 0) {\n            shares = sqrt(amount0 * amount1);\n        } else {\n            shares = min(\n                (amount0 * totalSupply) / reserve0,\n                (amount1 * totalSupply) / reserve1\n            );\n        }\n\n        require(shares > 0, \"Shares = 0\");\n        _mint(msg.sender, shares);\n        _update(\n            token0.balanceOf(address(this)),\n            token1.balanceOf(address(this))\n        );\n\n        emit Mint(msg.sender, shares);\n    }\n\n    function removeLiquidity(uint256 shares) external returns (uint256 amount0, uint256 amount1) {\n        uint256 bal0 = token0.balanceOf(address(this));\n        uint256 bal1 = token1.balanceOf(address(this));\n\n        amount0 = (shares * bal0) / totalSupply;\n        amount1 = (shares * bal1) / totalSupply;\n\n        require(amount0 > 0 && amount1 > 0, \"Amount0 or amount1 = 0\");\n\n        _burn(msg.sender, shares);\n        _update(bal0 - amount0, bal1 - amount1);\n\n        token0.transfer(msg.sender, amount0);\n        token1.transfer(msg.sender, amount1);\n\n        emit Burn(msg.sender, shares);\n    }\n\n    function swap(address tokenIn, uint256 amountIn) external returns (uint256 amountOut) {\n        require(tokenIn == address(token0) || tokenIn == address(token1), \"Invalid token\");\n\n        bool isToken0 = tokenIn == address(token0);\n        (IERC20 tokenIn_, IERC20 tokenOut, uint256 resIn, uint256 resOut) = isToken0\n            ? (token0, token1, reserve0, reserve1)\n            : (token1, token0, reserve1, reserve0);\n\n        tokenIn_.transferFrom(msg.sender, address(this), amountIn);\n\n        // 0.3% fee\n        uint256 amountInWithFee = (amountIn * 997) / 1000;\n        amountOut = (resOut * amountInWithFee) / (resIn + amountInWithFee);\n\n        tokenOut.transfer(msg.sender, amountOut);\n\n        _update(\n            token0.balanceOf(address(this)),\n            token1.balanceOf(address(this))\n        );\n\n        emit Swap(msg.sender, isToken0 ? amountIn : 0, isToken0 ? 0 : amountIn, isToken0 ? 0 : amountOut, isToken0 ? amountOut : 0);\n    }\n\n    function _mint(address to, uint256 amount) private {\n        balanceOf[to] += amount;\n        totalSupply += amount;\n    }\n\n    function _burn(address from, uint256 amount) private {\n        balanceOf[from] -= amount;\n        totalSupply -= amount;\n    }\n\n    function _update(uint256 res0, uint256 res1) private {\n        reserve0 = res0;\n        reserve1 = res1;\n    }\n\n    function sqrt(uint256 y) private pure returns (uint256 z) {\n        if (y > 3) {\n            z = y;\n            uint256 x = y / 2 + 1;\n            while (x < z) {\n                z = x;\n                x = (y / x + x) / 2;\n            }\n        } else if (y != 0) {\n            z = 1;\n        }\n    }\n\n    function min(uint256 x, uint256 y) private pure returns (uint256) {\n        return x <= y ? x : y;\n    }\n}\n```\n\n## Additional patterns and templates\n\nMore detailed templates and worked examples live in `references/details.md`. Read that file for the full pattern library.","author":"@wshobson","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/wshobson/agents/tree/main/plugins/blockchain-web3/skills/defi-protocol-templates","license":"MIT","category":"security","lang":"en","tokens":1700,"stars":0,"calls30d":1,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[{"path":"references/details.md","size":5625,"sha256":"117a158bbd5da74ae6330949b85ea6e7f3fd632a8404d46be93823ae19973b99"}],"requires":{"mcp":[],"tools":[]},"safety":{"flags":[],"scannedAt":"2026-08-22","hasScripts":false,"networkEndpoints":[]}}