์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿช™ ํŒŒ์ด์ฌ์œผ๋กœ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑํ•˜๊ธฐ

๐Ÿช™ ํŒŒ์ด์ฌ์œผ๋กœ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑํ•˜๊ธฐ

๋ธ”๋ก์ฒด์ธ ์„ธ์ƒ์—์„œ ๋‚ด ์†์œผ๋กœ ํ† ํฐ ๊ฒฝ์ œ๋ฅผ ์„ค๊ณ„ํ•˜๋Š” ๋ฐฉ๋ฒ• ๐Ÿ’Ž
๐Ÿช™ โš™๏ธ ๐Ÿ“Š Token Supply Control System
์•ˆ๋…•! ๐Ÿ‘‹ ์˜ค๋Š˜์€ ๋ธ”๋ก์ฒด์ธ ์„ธ๊ณ„์—์„œ ์ •๋ง ์ค‘์š”ํ•œ ์ฃผ์ œ๋ฅผ ๋‹ค๋ค„๋ณผ ๊ฑฐ์•ผ. ๋ฐ”๋กœ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ์ธ๋ฐ, ์ด๊ฒŒ ์™œ ์ค‘์š”ํ•˜๋ƒ๊ณ ? ๐Ÿค”

์ƒ๊ฐํ•ด๋ด. ๋น„ํŠธ์ฝ”์ธ์€ ์™œ 2,100๋งŒ ๊ฐœ๋กœ ์ œํ•œ๋˜์–ด ์žˆ์„๊นŒ? ์ด๋”๋ฆฌ์›€์€ ์™œ ๋งค๋…„ ์ผ์ •๋Ÿ‰๋งŒ ๋ฐœํ–‰๋ ๊นŒ? ๋ฐ”๋กœ ํฌ์†Œ์„ฑ๊ณผ ๊ฐ€์น˜ ๋ณด์กด ๋•Œ๋ฌธ์ด์•ผ. ๋งŒ์•ฝ ๋ˆ„๊ตฐ๊ฐ€ ๋งˆ์Œ๋Œ€๋กœ ํ† ํฐ์„ ๋ฌดํ•œ์ • ์ฐ์–ด๋‚ผ ์ˆ˜ ์žˆ๋‹ค๋ฉด? ๊ทธ๊ฑด ์ง๋ฐ”๋ธŒ์›จ ๋‹ฌ๋Ÿฌ์ฒ˜๋Ÿผ ํœด์ง€์กฐ๊ฐ์ด ๋˜๋Š” ๊ฑฐ์ง€. ๐Ÿ’ธ

์˜ค๋Š˜ ์šฐ๋ฆฌ๋Š” ํŒŒ์ด์ฌ์„ ํ™œ์šฉํ•ด์„œ ์‹ค์ œ๋กœ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰์„ ์ œ์–ดํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ ๊ฑฐ์•ผ. ๋‹จ์ˆœํžˆ ์ฝ”๋“œ๋งŒ ์ž‘์„ฑํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ์™œ ์ด๋Ÿฐ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ํ•„์š”ํ•œ์ง€, ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ™œ์šฉ๋˜๋Š”์ง€๊นŒ์ง€ ๊นŠ์ด ์žˆ๊ฒŒ ํŒŒํ—ค์ณ๋ณผ๊ฒŒ! ๐Ÿš€

๐ŸŽฏ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด๊ฐ€ ๋ญ๊ธธ๋ž˜?

ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด(Token Supply Control)๋Š” ๋ง ๊ทธ๋Œ€๋กœ ๋ธ”๋ก์ฒด์ธ ๋„คํŠธ์›Œํฌ์—์„œ ํ† ํฐ์ด ์–ผ๋งˆ๋‚˜, ์–ธ์ œ, ์–ด๋–ป๊ฒŒ ๋ฐœํ–‰๋˜๋Š”์ง€๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์‹œ์Šคํ…œ์ด์•ผ. ์ด๊ฑด ๋‹จ์ˆœํ•œ ์ˆซ์ž ๊ฒŒ์ž„์ด ์•„๋‹ˆ๋ผ, ์ „์ฒด ํ† ํฐ ๊ฒฝ์ œ(Tokenomics)์˜ ํ•ต์‹ฌ์ด์ง€. ๐Ÿ’ก

์‹ค์ œ๋กœ ๋งŽ์€ ๋ธ”๋ก์ฒด์ธ ํ”„๋กœ์ ํŠธ๋“ค์ด ์ดˆ๊ธฐ์— ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์„ค๊ณ„๋ฅผ ์ž˜๋ชปํ•ด์„œ ๋งํ–ˆ์–ด. ๋„ˆ๋ฌด ๋งŽ์ด ๋ฐœํ–‰ํ•ด์„œ ๊ฐ€์น˜๊ฐ€ ํญ๋ฝํ•˜๊ฑฐ๋‚˜, ๋ฐ˜๋Œ€๋กœ ๋„ˆ๋ฌด ์ ๊ฒŒ ๋ฐœํ–‰ํ•ด์„œ ์œ ๋™์„ฑ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ฑฐ๋‚˜. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๊ฐ€ ๋ฐฐ์šธ ๋‚ด์šฉ์€ ๋‹จ์ˆœํ•œ ์ฝ”๋”ฉ ์Šคํ‚ฌ์ด ์•„๋‹ˆ๋ผ, ์‹ค์ „ ํ† ํฐ ๊ฒฝ์ œ ์„ค๊ณ„ ๋Šฅ๋ ฅ์ด์•ผ! ๐ŸŽ“
๐Ÿ’ฐ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด์˜ ํ•ต์‹ฌ ์š”์†Œ๋“ค

1. ์ด ๋ฐœํ–‰๋Ÿ‰(Total Supply) - ์ „์ฒด ํ† ํฐ์˜ ์ตœ๋Œ€ ์ˆ˜๋Ÿ‰
2. ์ดˆ๊ธฐ ๋ฐœํ–‰๋Ÿ‰(Initial Supply) - ์ฒ˜์Œ ์‹œ์ž‘ํ•  ๋•Œ ๋ฐœํ–‰๋˜๋Š” ์–‘
3. ๋ฐœํ–‰ ์†๋„(Emission Rate) - ์‹œ๊ฐ„๋‹น/๋ธ”๋ก๋‹น ๋ฐœํ–‰๋˜๋Š” ์–‘
4. ์†Œ๊ฐ ๋ฉ”์ปค๋‹ˆ์ฆ˜(Burn Mechanism) - ํ† ํฐ์„ ์ œ๊ฑฐํ•˜๋Š” ๋ฐฉ๋ฒ•
5. ๋ฒ ์ŠคํŒ…(Vesting) - ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์ ์ง„์ ์œผ๋กœ ํ’€๋ฆฌ๋Š” ๊ตฌ์กฐ

๐Ÿ” ์‹ค์ œ ํ”„๋กœ์ ํŠธ ์‚ฌ๋ก€ ๋ถ„์„

์ด๋ก ๋งŒ ๋ฐฐ์šฐ๋ฉด ์žฌ๋ฏธ์—†์ž–์•„? ์‹ค์ œ ์œ ๋ช… ํ”„๋กœ์ ํŠธ๋“ค์ด ์–ด๋–ป๊ฒŒ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰์„ ์ œ์–ดํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด์ž! ๐Ÿ“š

๋น„ํŠธ์ฝ”์ธ(Bitcoin) ๐ŸŸ 
๋น„ํŠธ์ฝ”์ธ์€ ๊ฐ€์žฅ ๋‹จ์ˆœํ•˜๋ฉด์„œ๋„ ๊ฐ•๋ ฅํ•œ ๋ชจ๋ธ์ด์•ผ. ์ด 2,100๋งŒ ๊ฐœ๋กœ ์ œํ•œ๋˜์–ด ์žˆ๊ณ , ์•ฝ 4๋…„๋งˆ๋‹ค ๋ฐœํ–‰๋Ÿ‰์ด ์ ˆ๋ฐ˜์œผ๋กœ ์ค„์–ด๋“œ๋Š” '๋ฐ˜๊ฐ๊ธฐ(Halving)' ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•ด. ์ฒ˜์Œ์—” ๋ธ”๋ก๋‹น 50 BTC์˜€๋Š”๋ฐ, ์ง€๊ธˆ์€ 6.25 BTC์•ผ. 2140๋…„์ฏค ๋˜๋ฉด ๋ชจ๋“  ๋น„ํŠธ์ฝ”์ธ์ด ๋ฐœํ–‰ ์™„๋ฃŒ๋  ๊ฑฐ์•ผ. โฐ

์ด๋”๋ฆฌ์›€(Ethereum) ๐Ÿ”ท
์ด๋”๋ฆฌ์›€์€ ์ดˆ๊ธฐ์— ์ด ๋ฐœํ–‰๋Ÿ‰ ์ œํ•œ์ด ์—†์—ˆ์–ด. ํ•˜์ง€๋งŒ EIP-1559 ์—…๋ฐ์ดํŠธ ์ดํ›„ ๊ฑฐ๋ž˜ ์ˆ˜์ˆ˜๋ฃŒ์˜ ์ผ๋ถ€๋ฅผ ์†Œ๊ฐํ•˜๋ฉด์„œ ์‚ฌ์‹ค์ƒ ๋””ํ”Œ๋ ˆ์ด์…˜ ์ž์‚ฐ์ด ๋์ง€. ๋ฐœํ–‰๋˜๋Š” ์–‘๋ณด๋‹ค ์†Œ๊ฐ๋˜๋Š” ์–‘์ด ๋” ๋งŽ์€ ๊ฒฝ์šฐ๋„ ์ƒ๊ฒจ! ๐Ÿ”ฅ

๋ฐ”์ด๋‚ธ์Šค ์ฝ”์ธ(BNB) ๐ŸŸก
BNB๋Š” ๋ถ„๊ธฐ๋งˆ๋‹ค ์ž์ฒด ์ˆ˜์ต์˜ ์ผ๋ถ€๋กœ ํ† ํฐ์„ ๋งค์ž…ํ•ด์„œ ์†Œ๊ฐํ•ด. ์ด 2์–ต ๊ฐœ ์ค‘ 1์–ต ๊ฐœ๊ฐ€ ์†Œ๊ฐ๋  ๋•Œ๊นŒ์ง€ ๊ณ„์†๋  ์˜ˆ์ •์ด์•ผ. ์ด๋Ÿฐ ๊ฑธ 'Buy-back and Burn' ์ „๋žต์ด๋ผ๊ณ  ํ•ด. ๐Ÿ’ช

๐Ÿ› ๏ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์ค€๋น„ํ•˜๊ธฐ

์ž, ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์ฝ”๋”ฉ์„ ์‹œ์ž‘ํ•ด๋ณผ๊นŒ? ๋จผ์ € ํ•„์š”ํ•œ ๋„๊ตฌ๋“ค์„ ์ค€๋น„ํ•ด์•ผ ํ•ด! ๐Ÿงฐ
โœ… ํ•„์š”ํ•œ ๊ฒƒ๋“ค

โ€ข Python 3.8 ์ด์ƒ
โ€ข Web3.py ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (๋ธ”๋ก์ฒด์ธ ์ƒํ˜ธ์ž‘์šฉ์šฉ)
โ€ข eth-brownie ๋˜๋Š” Hardhat (์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๊ฐœ๋ฐœ์šฉ)
โ€ข ๊ธฐ๋ณธ์ ์ธ ํŒŒ์ด์ฌ ์ง€์‹
โ€ข ๋ธ”๋ก์ฒด์ธ ๊ธฐ์ดˆ ๊ฐœ๋… ์ดํ•ด
๐Ÿ“ฆ ํ•„์ˆ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜
pip install web3
pip install eth-brownie
pip install python-dotenv
pip install requests
์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ๊ฐ๊ฐ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์•Œ์•„๋ณผ๊นŒ? ๐Ÿค“

web3.py๋Š” ์ด๋”๋ฆฌ์›€ ๋ธ”๋ก์ฒด์ธ๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ํŒŒ์ด์ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์•ผ. ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ํŠธ๋žœ์žญ์…˜์„ ๋ณด๋‚ด๊ณ , ๋ธ”๋ก์ฒด์ธ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์–ด.

eth-brownie๋Š” ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๊ฐœ๋ฐœ ํ”„๋ ˆ์ž„์›Œํฌ์•ผ. ์ปจํŠธ๋ž™ํŠธ๋ฅผ ์ปดํŒŒ์ผํ•˜๊ณ , ํ…Œ์ŠคํŠธํ•˜๊ณ , ๋ฐฐํฌํ•˜๋Š” ์ „ ๊ณผ์ •์„ ๊ด€๋ฆฌํ•ด์ค˜.

python-dotenv๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๊ฑฐ์•ผ. API ํ‚ค๋‚˜ ๊ฐœ์ธํ‚ค ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ์ฝ”๋“œ์— ์ง์ ‘ ๋„ฃ์ง€ ์•Š๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€.

requests๋Š” HTTP ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์•ผ. ์™ธ๋ถ€ API์™€ ํ†ต์‹ ํ•  ๋•Œ ํ•„์š”ํ•ด! ๐Ÿ“ก

๐Ÿ’ป ๊ธฐ๋ณธ ํ† ํฐ ์ปจํŠธ๋ž™ํŠธ ๊ตฌ์กฐ ์ดํ•ดํ•˜๊ธฐ

ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰์„ ์ œ์–ดํ•˜๋ ค๋ฉด ๋จผ์ € ํ† ํฐ ์ปจํŠธ๋ž™ํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€ ์•Œ์•„์•ผ ํ•ด. ERC-20 ํ‘œ์ค€์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ์‚ดํŽด๋ณด์ž! ๐Ÿ“‹
๐Ÿ” ๊ธฐ๋ณธ ERC-20 ํ† ํฐ ์ปจํŠธ๋ž™ํŠธ (Solidity)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ControlledToken {
    string public name = "Controlled Token";
    string public symbol = "CTK";
    uint8 public decimals = 18;
    uint256 public totalSupply;
    uint256 public maxSupply = 1000000 * 10**18; // 100๋งŒ ๊ฐœ ์ œํ•œ
    
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;
    
    address public owner;
    uint256 public emissionRate = 100 * 10**18; // ๋ธ”๋ก๋‹น 100๊ฐœ
    uint256 public lastMintBlock;
    
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Mint(address indexed to, uint256 amount);
    event Burn(address indexed from, uint256 amount);
    
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }
    
    constructor() {
        owner = msg.sender;
        lastMintBlock = block.number;
    }
    
    function mint(address to, uint256 amount) public onlyOwner {
        require(totalSupply + amount <= maxSupply, "Exceeds max supply");
        totalSupply += amount;
        balanceOf[to] += amount;
        emit Mint(to, amount);
        emit Transfer(address(0), to, amount);
    }
    
    function burn(uint256 amount) public {
        require(balanceOf[msg.sender] >= amount, "Insufficient balance");
        balanceOf[msg.sender] -= amount;
        totalSupply -= amount;
        emit Burn(msg.sender, amount);
        emit Transfer(msg.sender, address(0), amount);
    }
    
    function autoMint() public {
        uint256 blocksPassed = block.number - lastMintBlock;
        uint256 mintAmount = blocksPassed * emissionRate;
        
        if (totalSupply + mintAmount > maxSupply) {
            mintAmount = maxSupply - totalSupply;
        }
        
        if (mintAmount > 0) {
            mint(owner, mintAmount);
            lastMintBlock = block.number;
        }
    }
}
์ด ์ปจํŠธ๋ž™ํŠธ์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ๋“ค์„ ํ•˜๋‚˜์”ฉ ๋œฏ์–ด๋ณด์ž! ๐Ÿ”ฌ

maxSupply๋Š” ์ ˆ๋Œ€ ๋„˜์„ ์ˆ˜ ์—†๋Š” ์ตœ๋Œ€ ๋ฐœํ–‰๋Ÿ‰์ด์•ผ. ๋น„ํŠธ์ฝ”์ธ์˜ 2,100๋งŒ ๊ฐœ ์ œํ•œ๊ณผ ๊ฐ™์€ ๊ฐœ๋…์ด์ง€.

emissionRate๋Š” ๋ธ”๋ก๋‹น ๋ฐœํ–‰๋˜๋Š” ํ† ํฐ์˜ ์–‘์ด์•ผ. ์ด๊ฑธ ์กฐ์ ˆํ•˜๋ฉด ์ธํ”Œ๋ ˆ์ด์…˜ ์†๋„๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์–ด.

autoMint() ํ•จ์ˆ˜๋Š” ์ž๋™์œผ๋กœ ์‹œ๊ฐ„์— ๋”ฐ๋ผ ํ† ํฐ์„ ๋ฐœํ–‰ํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด์•ผ. ์‹ค์ œ๋กœ๋Š” ๋” ๋ณต์žกํ•œ ๋กœ์ง์ด ๋“ค์–ด๊ฐ€์ง€๋งŒ, ๊ธฐ๋ณธ ๊ฐœ๋…์€ ์ด๊ฑฐ์•ผ! โš™๏ธ

๐Ÿ ํŒŒ์ด์ฌ์œผ๋กœ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํฌ๋ฆฝํŠธ ๋งŒ๋“ค๊ธฐ

์ด์ œ ํŒŒ์ด์ฌ์œผ๋กœ ์‹ค์ œ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ณ  ์ œ์–ดํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! ์ด๊ฑด ์‹ค์ „์—์„œ ์ •๋ง ์œ ์šฉํ•ด. ๐ŸŽฏ
๐Ÿ“Š ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํฌ๋ฆฝํŠธ
from web3 import Web3
import json
import time
from datetime import datetime
import os
from dotenv import load_dotenv

load_dotenv()

class TokenSupplyController:
    def __init__(self, contract_address, abi_path, rpc_url):
        """
        ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด ํด๋ž˜์Šค ์ดˆ๊ธฐํ™”
        """
        self.w3 = Web3(Web3.HTTPProvider(rpc_url))
        
        # ์—ฐ๊ฒฐ ํ™•์ธ
        if not self.w3.is_connected():
            raise Exception("๋ธ”๋ก์ฒด์ธ ์—ฐ๊ฒฐ ์‹คํŒจ!")
        
        # ์ปจํŠธ๋ž™ํŠธ ๋กœ๋“œ
        with open(abi_path, 'r') as f:
            abi = json.load(f)
        
        self.contract = self.w3.eth.contract(
            address=Web3.to_checksum_address(contract_address),
            abi=abi
        )
        
        self.owner_address = os.getenv('OWNER_ADDRESS')
        self.private_key = os.getenv('PRIVATE_KEY')
        
        print(f"โœ… ์ปจํŠธ๋ž™ํŠธ ์—ฐ๊ฒฐ ์™„๋ฃŒ: {contract_address}")
    
    def get_supply_info(self):
        """
        ํ˜„์žฌ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ •๋ณด ์กฐํšŒ
        """
        try:
            total_supply = self.contract.functions.totalSupply().call()
            max_supply = self.contract.functions.maxSupply().call()
            emission_rate = self.contract.functions.emissionRate().call()
            
            # Wei๋ฅผ ํ† ํฐ ๋‹จ์œ„๋กœ ๋ณ€ํ™˜
            total_supply_tokens = self.w3.from_wei(total_supply, 'ether')
            max_supply_tokens = self.w3.from_wei(max_supply, 'ether')
            emission_rate_tokens = self.w3.from_wei(emission_rate, 'ether')
            
            supply_percentage = (total_supply / max_supply) * 100
            
            info = {
                'total_supply': float(total_supply_tokens),
                'max_supply': float(max_supply_tokens),
                'emission_rate': float(emission_rate_tokens),
                'supply_percentage': supply_percentage,
                'remaining': float(max_supply_tokens - total_supply_tokens),
                'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            }
            
            return info
        
        except Exception as e:
            print(f"โŒ ์ •๋ณด ์กฐํšŒ ์‹คํŒจ: {str(e)}")
            return None
    
    def print_supply_dashboard(self):
        """
        ๋ฐœํ–‰๋Ÿ‰ ๋Œ€์‹œ๋ณด๋“œ ์ถœ๋ ฅ
        """
        info = self.get_supply_info()
        
        if info:
            print("\n" + "="*60)
            print("๐Ÿช™ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ๋Œ€์‹œ๋ณด๋“œ")
            print("="*60)
            print(f"๐Ÿ“… ์กฐํšŒ ์‹œ๊ฐ„: {info['timestamp']}")
            print(f"๐Ÿ’ฐ ํ˜„์žฌ ๋ฐœํ–‰๋Ÿ‰: {info['total_supply']:,.2f} ํ† ํฐ")
            print(f"๐ŸŽฏ ์ตœ๋Œ€ ๋ฐœํ–‰๋Ÿ‰: {info['max_supply']:,.2f} ํ† ํฐ")
            print(f"๐Ÿ“Š ๋ฐœํ–‰ ๋น„์œจ: {info['supply_percentage']:.2f}%")
            print(f"โฐ ๋ธ”๋ก๋‹น ๋ฐœํ–‰: {info['emission_rate']:,.2f} ํ† ํฐ")
            print(f"๐Ÿ”„ ๋‚จ์€ ๋ฐœํ–‰๋Ÿ‰: {info['remaining']:,.2f} ํ† ํฐ")
            print("="*60 + "\n")
            
            # ์ง„ํ–‰๋ฅ  ๋ฐ” ํ‘œ์‹œ
            bar_length = 50
            filled = int(bar_length * info['supply_percentage'] / 100)
            bar = 'โ–ˆ' * filled + 'โ–‘' * (bar_length - filled)
            print(f"์ง„ํ–‰๋ฅ : [{bar}] {info['supply_percentage']:.1f}%\n")
    
    def calculate_emission_schedule(self, days=365):
        """
        ํ–ฅํ›„ ๋ฐœํ–‰ ์Šค์ผ€์ค„ ๊ณ„์‚ฐ
        """
        info = self.get_supply_info()
        
        if not info:
            return None
        
        # ์ด๋”๋ฆฌ์›€ ๊ธฐ์ค€ ํ•˜๋ฃจ ์•ฝ 6500 ๋ธ”๋ก
        blocks_per_day = 6500
        daily_emission = info['emission_rate'] * blocks_per_day
        
        schedule = []
        current_supply = info['total_supply']
        
        for day in range(1, days + 1):
            projected_supply = current_supply + (daily_emission * day)
            
            # ์ตœ๋Œ€ ๋ฐœํ–‰๋Ÿ‰ ์ดˆ๊ณผ ์ฒดํฌ
            if projected_supply > info['max_supply']:
                projected_supply = info['max_supply']
                schedule.append({
                    'day': day,
                    'supply': projected_supply,
                    'note': '์ตœ๋Œ€ ๋ฐœํ–‰๋Ÿ‰ ๋„๋‹ฌ'
                })
                break
            
            if day % 30 == 0:  # ๋งค์›” ๊ธฐ๋ก
                schedule.append({
                    'day': day,
                    'supply': projected_supply,
                    'percentage': (projected_supply / info['max_supply']) * 100
                })
        
        return schedule
    
    def check_supply_alerts(self):
        """
        ๋ฐœํ–‰๋Ÿ‰ ์•Œ๋ฆผ ์ฒดํฌ
        """
        info = self.get_supply_info()
        
        if not info:
            return
        
        alerts = []
        
        # 90% ๋„๋‹ฌ ์•Œ๋ฆผ
        if info['supply_percentage'] >= 90:
            alerts.append("โš ๏ธ ๊ฒฝ๊ณ : ๋ฐœํ–‰๋Ÿ‰์ด 90%๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค!")
        
        # 95% ๋„๋‹ฌ ์•Œ๋ฆผ
        if info['supply_percentage'] >= 95:
            alerts.append("๐Ÿšจ ๊ธด๊ธ‰: ๋ฐœํ–‰๋Ÿ‰์ด 95%๋ฅผ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค!")
        
        # 99% ๋„๋‹ฌ ์•Œ๋ฆผ
        if info['supply_percentage'] >= 99:
            alerts.append("๐Ÿ”ด ์ตœ๊ณ  ๊ฒฝ๊ณ : ๋ฐœํ–‰๋Ÿ‰์ด ๊ฑฐ์˜ ํ•œ๊ณ„์— ๋„๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค!")
        
        for alert in alerts:
            print(alert)
        
        return alerts
    
    def mint_tokens(self, to_address, amount):
        """
        ํ† ํฐ ๋ฐœํ–‰ (owner๋งŒ ๊ฐ€๋Šฅ)
        """
        try:
            # Wei ๋‹จ์œ„๋กœ ๋ณ€ํ™˜
            amount_wei = self.w3.to_wei(amount, 'ether')
            
            # ํŠธ๋žœ์žญ์…˜ ์ค€๋น„
            nonce = self.w3.eth.get_transaction_count(self.owner_address)
            
            transaction = self.contract.functions.mint(
                Web3.to_checksum_address(to_address),
                amount_wei
            ).build_transaction({
                'from': self.owner_address,
                'nonce': nonce,
                'gas': 200000,
                'gasPrice': self.w3.eth.gas_price
            })
            
            # ํŠธ๋žœ์žญ์…˜ ์„œ๋ช…
            signed_txn = self.w3.eth.account.sign_transaction(
                transaction,
                private_key=self.private_key
            )
            
            # ํŠธ๋žœ์žญ์…˜ ์ „์†ก
            tx_hash = self.w3.eth.send_raw_transaction(signed_txn.rawTransaction)
            
            print(f"โณ ํ† ํฐ ๋ฐœํ–‰ ์ค‘... TX: {tx_hash.hex()}")
            
            # ํŠธ๋žœ์žญ์…˜ ์™„๋ฃŒ ๋Œ€๊ธฐ
            receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
            
            if receipt['status'] == 1:
                print(f"โœ… {amount} ํ† ํฐ ๋ฐœํ–‰ ์™„๋ฃŒ!")
                return tx_hash.hex()
            else:
                print("โŒ ํŠธ๋žœ์žญ์…˜ ์‹คํŒจ")
                return None
        
        except Exception as e:
            print(f"โŒ ๋ฐœํ–‰ ์‹คํŒจ: {str(e)}")
            return None
    
    def monitor_continuous(self, interval=60):
        """
        ์ง€์†์ ์ธ ๋ชจ๋‹ˆํ„ฐ๋ง
        """
        print("๐Ÿ”„ ์ง€์† ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์ž‘...")
        print(f"โฐ ๊ฐฑ์‹  ์ฃผ๊ธฐ: {interval}์ดˆ\n")
        
        try:
            while True:
                self.print_supply_dashboard()
                self.check_supply_alerts()
                time.sleep(interval)
        
        except KeyboardInterrupt:
            print("\nโน๏ธ ๋ชจ๋‹ˆํ„ฐ๋ง ์ข…๋ฃŒ")


# ์‚ฌ์šฉ ์˜ˆ์‹œ
if __name__ == "__main__":
    # ์„ค์ •
    CONTRACT_ADDRESS = "0x..."  # ์‹ค์ œ ์ปจํŠธ๋ž™ํŠธ ์ฃผ์†Œ
    ABI_PATH = "token_abi.json"
    RPC_URL = "https://mainnet.infura.io/v3/YOUR_PROJECT_ID"
    
    # ์ปจํŠธ๋กค๋Ÿฌ ์ดˆ๊ธฐํ™”
    controller = TokenSupplyController(CONTRACT_ADDRESS, ABI_PATH, RPC_URL)
    
    # ํ˜„์žฌ ์ƒํƒœ ํ™•์ธ
    controller.print_supply_dashboard()
    
    # ๋ฐœํ–‰ ์Šค์ผ€์ค„ ๊ณ„์‚ฐ
    schedule = controller.calculate_emission_schedule(365)
    
    if schedule:
        print("\n๐Ÿ“… ํ–ฅํ›„ 12๊ฐœ์›” ๋ฐœํ–‰ ์˜ˆ์ธก:")
        print("-" * 60)
        for item in schedule:
            if 'note' in item:
                print(f"Day {item['day']}: {item['supply']:,.2f} - {item['note']}")
            else:
                print(f"Day {item['day']}: {item['supply']:,.2f} ({item['percentage']:.1f}%)")
    
    # ์•Œ๋ฆผ ์ฒดํฌ
    controller.check_supply_alerts()
    
    # ์ง€์† ๋ชจ๋‹ˆํ„ฐ๋ง (์„ ํƒ์‚ฌํ•ญ)
    # controller.monitor_continuous(interval=300)  # 5๋ถ„๋งˆ๋‹ค
์™€! ์ฝ”๋“œ๊ฐ€ ์ข€ ๊ธธ์ง€? ๐Ÿ˜… ํ•˜์ง€๋งŒ ํ•˜๋‚˜ํ•˜๋‚˜ ๋œฏ์–ด๋ณด๋ฉด ๋ณ„๊ฑฐ ์•„๋‹ˆ์•ผ. ํ•ต์‹ฌ ๊ธฐ๋Šฅ๋“ค์„ ์‚ดํŽด๋ณด์ž!

get_supply_info()๋Š” ํ˜„์žฌ ํ† ํฐ์˜ ๋ฐœํ–‰ ์ƒํƒœ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๊ฐ€์ ธ์™€. ์ด ๋ฐœํ–‰๋Ÿ‰, ์ตœ๋Œ€ ๋ฐœํ–‰๋Ÿ‰, ๋ฐœํ–‰ ์†๋„ ๋“ฑ์„ ํ•œ๋ˆˆ์— ๋ณผ ์ˆ˜ ์žˆ์ง€.

calculate_emission_schedule()์€ ๋ฏธ๋ž˜์˜ ๋ฐœํ–‰๋Ÿ‰์„ ์˜ˆ์ธกํ•ด. ์ด๊ฒŒ ์ง„์งœ ์ค‘์š”ํ•œ๋ฐ, ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐ์— ํ† ํฐ ๊ฒฝ์ œ๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ ์ด๋Ÿฐ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์ด ํ•„์ˆ˜์•ผ! ๐Ÿ“ˆ

check_supply_alerts()๋Š” ๋ฐœํ–‰๋Ÿ‰์ด ์œ„ํ—˜ ์ˆ˜์ค€์— ๋„๋‹ฌํ•˜๋ฉด ์•Œ๋ฆผ์„ ๋ณด๋‚ด. ์‹ค์ „์—์„œ๋Š” ์ด๊ฑธ ํ…”๋ ˆ๊ทธ๋žจ์ด๋‚˜ ์Šฌ๋ž™ ๋ด‡๊ณผ ์—ฐ๋™ํ•ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์•„.

mint_tokens()๋Š” ์‹ค์ œ๋กœ ํ† ํฐ์„ ๋ฐœํ–‰ํ•˜๋Š” ํ•จ์ˆ˜์•ผ. ๋ฌผ๋ก  owner ๊ถŒํ•œ์ด ์žˆ์–ด์•ผ ํ•˜๊ณ , ๊ฐ€์Šค๋น„๋„ ํ•„์š”ํ•ด! โ›ฝ

๐ŸŽฎ ๊ณ ๊ธ‰ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด ์ „๋žต

๊ธฐ๋ณธ์ ์ธ ๋ชจ๋‹ˆํ„ฐ๋ง์„ ๋„˜์–ด์„œ, ์ด์ œ ์ง„์งœ ๊ณ ๊ธ‰ ์ „๋žต๋“ค์„ ๋ฐฐ์›Œ๋ณด์ž! ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ํ…Œํฌ๋‹‰๋“ค์ด์•ผ. ๐Ÿš€

โฐ ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ๋ฒ ์ŠคํŒ… (Time-based Vesting)

๋ฒ ์ŠคํŒ…์€ ํ† ํฐ์„ ํ•œ ๋ฒˆ์— ๋‹ค ์ฃผ์ง€ ์•Š๊ณ , ์‹œ๊ฐ„์— ๋”ฐ๋ผ ์กฐ๊ธˆ์”ฉ ํ’€์–ด์ฃผ๋Š” ๊ฑฐ์•ผ. ํŒ€ ํ† ํฐ์ด๋‚˜ ํˆฌ์ž์ž ํ† ํฐ์— ์ฃผ๋กœ ์‚ฌ์šฉ๋ผ. ๊ฐ‘์ž๊ธฐ ๋Œ€๋Ÿ‰ ๋งค๋„๋ฅผ ๋ง‰์„ ์ˆ˜ ์žˆ๊ฑฐ๋“ ! ๐Ÿ”’
โณ ๋ฒ ์ŠคํŒ… ์Šค์ผ€์ค„ ๊ด€๋ฆฌ ์Šคํฌ๋ฆฝํŠธ
import time
from datetime import datetime, timedelta
from typing import List, Dict

class VestingScheduler:
    def __init__(self):
        self.schedules = {}
    
    def create_vesting_schedule(
        self,
        beneficiary: str,
        total_amount: float,
        start_date: datetime,
        cliff_months: int,
        vesting_months: int,
        release_frequency: str = 'monthly'
    ):
        """
        ๋ฒ ์ŠคํŒ… ์Šค์ผ€์ค„ ์ƒ์„ฑ
        
        Args:
            beneficiary: ์ˆ˜ํ˜œ์ž ์ฃผ์†Œ
            total_amount: ์ด ํ† ํฐ ์–‘
            start_date: ์‹œ์ž‘ ๋‚ ์งœ
            cliff_months: ํด๋ฆฌํ”„ ๊ธฐ๊ฐ„ (์ด ๊ธฐ๊ฐ„ ๋™์•ˆ์€ 0๊ฐœ)
            vesting_months: ์ด ๋ฒ ์ŠคํŒ… ๊ธฐ๊ฐ„
            release_frequency: ๋ฆด๋ฆฌ์ฆˆ ์ฃผ๊ธฐ (monthly, quarterly, etc.)
        """
        
        schedule = {
            'beneficiary': beneficiary,
            'total_amount': total_amount,
            'start_date': start_date,
            'cliff_date': start_date + timedelta(days=cliff_months * 30),
            'end_date': start_date + timedelta(days=vesting_months * 30),
            'cliff_months': cliff_months,
            'vesting_months': vesting_months,
            'released_amount': 0,
            'release_frequency': release_frequency,
            'releases': []
        }
        
        # ๋ฆด๋ฆฌ์ฆˆ ์Šค์ผ€์ค„ ๊ณ„์‚ฐ
        if release_frequency == 'monthly':
            periods = vesting_months - cliff_months
            amount_per_period = total_amount / vesting_months
            
            for i in range(periods):
                release_date = schedule['cliff_date'] + timedelta(days=(i+1) * 30)
                schedule['releases'].append({
                    'date': release_date,
                    'amount': amount_per_period,
                    'released': False
                })
        
        self.schedules[beneficiary] = schedule
        
        print(f"โœ… ๋ฒ ์ŠคํŒ… ์Šค์ผ€์ค„ ์ƒ์„ฑ ์™„๋ฃŒ")
        print(f"   ์ˆ˜ํ˜œ์ž: {beneficiary}")
        print(f"   ์ด์•ก: {total_amount:,.2f} ํ† ํฐ")
        print(f"   ํด๋ฆฌํ”„: {cliff_months}๊ฐœ์›”")
        print(f"   ๋ฒ ์ŠคํŒ…: {vesting_months}๊ฐœ์›”")
        
        return schedule
    
    def get_vested_amount(self, beneficiary: str) -> float:
        """
        ํ˜„์žฌ๊นŒ์ง€ ๋ฒ ์ŠคํŒ…๋œ ๊ธˆ์•ก ๊ณ„์‚ฐ
        """
        if beneficiary not in self.schedules:
            return 0
        
        schedule = self.schedules[beneficiary]
        now = datetime.now()
        
        # ํด๋ฆฌํ”„ ๊ธฐ๊ฐ„ ์ฒดํฌ
        if now < schedule['cliff_date']:
            return 0
        
        # ๋ฒ ์ŠคํŒ… ์™„๋ฃŒ ์ฒดํฌ
        if now >= schedule['end_date']:
            return schedule['total_amount']
        
        # ์„ ํ˜• ๋ฒ ์ŠคํŒ… ๊ณ„์‚ฐ
        total_days = (schedule['end_date'] - schedule['cliff_date']).days
        elapsed_days = (now - schedule['cliff_date']).days
        
        vested_amount = (schedule['total_amount'] * elapsed_days) / total_days
        
        return vested_amount
    
    def get_releasable_amount(self, beneficiary: str) -> float:
        """
        ํ˜„์žฌ ๋ฆด๋ฆฌ์ฆˆ ๊ฐ€๋Šฅํ•œ ๊ธˆ์•ก ๊ณ„์‚ฐ
        """
        vested = self.get_vested_amount(beneficiary)
        schedule = self.schedules.get(beneficiary)
        
        if not schedule:
            return 0
        
        releasable = vested - schedule['released_amount']
        return max(0, releasable)
    
    def release_tokens(self, beneficiary: str) -> Dict:
        """
        ํ† ํฐ ๋ฆด๋ฆฌ์ฆˆ ์‹คํ–‰
        """
        releasable = self.get_releasable_amount(beneficiary)
        
        if releasable <= 0:
            return {
                'success': False,
                'message': '๋ฆด๋ฆฌ์ฆˆ ๊ฐ€๋Šฅํ•œ ํ† ํฐ์ด ์—†์Šต๋‹ˆ๋‹ค.'
            }
        
        schedule = self.schedules[beneficiary]
        schedule['released_amount'] += releasable
        
        return {
            'success': True,
            'amount': releasable,
            'total_released': schedule['released_amount'],
            'remaining': schedule['total_amount'] - schedule['released_amount']
        }
    
    def print_vesting_status(self, beneficiary: str):
        """
        ๋ฒ ์ŠคํŒ… ์ƒํƒœ ์ถœ๋ ฅ
        """
        if beneficiary not in self.schedules:
            print("โŒ ๋ฒ ์ŠคํŒ… ์Šค์ผ€์ค„์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
            return
        
        schedule = self.schedules[beneficiary]
        vested = self.get_vested_amount(beneficiary)
        releasable = self.get_releasable_amount(beneficiary)
        
        print("\n" + "="*60)
        print(f"๐Ÿ” ๋ฒ ์ŠคํŒ… ์ƒํƒœ: {beneficiary[:10]}...")
        print("="*60)
        print(f"๐Ÿ’ฐ ์ด ํ• ๋‹น๋Ÿ‰: {schedule['total_amount']:,.2f} ํ† ํฐ")
        print(f"โœ… ๋ฒ ์ŠคํŒ… ์™„๋ฃŒ: {vested:,.2f} ํ† ํฐ ({vested/schedule['total_amount']*100:.1f}%)")
        print(f"๐ŸŽ ๋ฆด๋ฆฌ์ฆˆ ์™„๋ฃŒ: {schedule['released_amount']:,.2f} ํ† ํฐ")
        print(f"๐Ÿ”“ ๋ฆด๋ฆฌ์ฆˆ ๊ฐ€๋Šฅ: {releasable:,.2f} ํ† ํฐ")
        print(f"๐Ÿ”’ ์ž ๊ธˆ ์ƒํƒœ: {schedule['total_amount'] - vested:,.2f} ํ† ํฐ")
        print(f"๐Ÿ“… ์‹œ์ž‘์ผ: {schedule['start_date'].strftime('%Y-%m-%d')}")
        print(f"โฐ ํด๋ฆฌํ”„ ์ข…๋ฃŒ: {schedule['cliff_date'].strftime('%Y-%m-%d')}")
        print(f"๐Ÿ ๋ฒ ์ŠคํŒ… ์ข…๋ฃŒ: {schedule['end_date'].strftime('%Y-%m-%d')}")
        print("="*60 + "\n")


# ์‚ฌ์šฉ ์˜ˆ์‹œ
if __name__ == "__main__":
    scheduler = VestingScheduler()
    
    # ํŒ€ ํ† ํฐ ๋ฒ ์ŠคํŒ… (12๊ฐœ์›” ํด๋ฆฌํ”„, 48๊ฐœ์›” ๋ฒ ์ŠคํŒ…)
    team_schedule = scheduler.create_vesting_schedule(
        beneficiary="0xTeamWallet...",
        total_amount=1000000,  # 100๋งŒ ํ† ํฐ
        start_date=datetime.now(),
        cliff_months=12,
        vesting_months=48,
        release_frequency='monthly'
    )
    
    # ํˆฌ์ž์ž ํ† ํฐ ๋ฒ ์ŠคํŒ… (6๊ฐœ์›” ํด๋ฆฌํ”„, 24๊ฐœ์›” ๋ฒ ์ŠคํŒ…)
    investor_schedule = scheduler.create_vesting_schedule(
        beneficiary="0xInvestorWallet...",
        total_amount=500000,  # 50๋งŒ ํ† ํฐ
        start_date=datetime.now(),
        cliff_months=6,
        vesting_months=24,
        release_frequency='monthly'
    )
    
    # ์ƒํƒœ ํ™•์ธ
    scheduler.print_vesting_status("0xTeamWallet...")
    
    # ๋ฆด๋ฆฌ์ฆˆ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ์ฒดํฌ
    result = scheduler.release_tokens("0xTeamWallet...")
    print(f"๋ฆด๋ฆฌ์ฆˆ ๊ฒฐ๊ณผ: {result}")
๋ฒ ์ŠคํŒ…์€ ์ •๋ง ์ค‘์š”ํ•ด! ๐ŸŽฏ ์‹ค์ œ๋กœ ๋งŽ์€ ํ”„๋กœ์ ํŠธ๋“ค์ด ํŒ€ ํ† ํฐ์„ ์ œ๋Œ€๋กœ ์ž ๊ทธ์ง€ ์•Š์•„์„œ ์ดˆ๊ธฐ์— ๋Œ€๋Ÿ‰ ๋งค๋„๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ๊ฐ€๊ฒฉ์ด ํญ๋ฝํ–ˆ๊ฑฐ๋“ .

์ผ๋ฐ˜์ ์ธ ๋ฒ ์ŠคํŒ… ๊ตฌ์กฐ๋Š” ์ด๋ž˜:
โ€ข ํŒ€ ํ† ํฐ: 12๊ฐœ์›” ํด๋ฆฌํ”„ + 36~48๊ฐœ์›” ๋ฒ ์ŠคํŒ…
โ€ข ์–ด๋“œ๋ฐ”์ด์ €: 6๊ฐœ์›” ํด๋ฆฌํ”„ + 18~24๊ฐœ์›” ๋ฒ ์ŠคํŒ…
โ€ข ์ดˆ๊ธฐ ํˆฌ์ž์ž: 6~12๊ฐœ์›” ํด๋ฆฌํ”„ + 18~36๊ฐœ์›” ๋ฒ ์ŠคํŒ…
โ€ข ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ณด์ƒ: ํด๋ฆฌํ”„ ์—†์Œ, ์ฆ‰์‹œ ๋ฆด๋ฆฌ์ฆˆ ๊ฐ€๋Šฅ ๐ŸŽ

๐Ÿ”ฅ ๋™์  ์†Œ๊ฐ ๋ฉ”์ปค๋‹ˆ์ฆ˜ (Dynamic Burn Mechanism)

์†Œ๊ฐ์€ ํ† ํฐ์„ ์˜๊ตฌ์ ์œผ๋กœ ์ œ๊ฑฐํ•ด์„œ ํฌ์†Œ์„ฑ์„ ๋†’์ด๋Š” ๊ฑฐ์•ผ. ์ด๋”๋ฆฌ์›€์˜ EIP-1559๊ฐ€ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์ง€! ๐Ÿ”ฅ
๐Ÿ”ฅ ์Šค๋งˆํŠธ ์†Œ๊ฐ ์‹œ์Šคํ…œ
class DynamicBurnController:
    def __init__(self, token_controller):
        self.controller = token_controller
        self.burn_history = []
        self.burn_strategies = {
            'fixed': self.fixed_burn,
            'percentage': self.percentage_burn,
            'dynamic': self.dynamic_burn
        }
    
    def fixed_burn(self, amount: float) -> Dict:
        """
        ๊ณ ์ • ๊ธˆ์•ก ์†Œ๊ฐ
        """
        info = self.controller.get_supply_info()
        
        if amount > info['total_supply']:
            return {
                'success': False,
                'message': '์†Œ๊ฐ ๊ธˆ์•ก์ด ์ด ๋ฐœํ–‰๋Ÿ‰์„ ์ดˆ๊ณผํ•ฉ๋‹ˆ๋‹ค.'
            }
        
        # ์‹ค์ œ ์†Œ๊ฐ ๋กœ์ง (์—ฌ๊ธฐ์„œ๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜)
        new_supply = info['total_supply'] - amount
        
        burn_record = {
            'timestamp': datetime.now(),
            'strategy': 'fixed',
            'amount': amount,
            'supply_before': info['total_supply'],
            'supply_after': new_supply,
            'burn_percentage': (amount / info['total_supply']) * 100
        }
        
        self.burn_history.append(burn_record)
        
        return {
            'success': True,
            'burned': amount,
            'new_supply': new_supply,
            'deflation_rate': burn_record['burn_percentage']
        }
    
    def percentage_burn(self, percentage: float) -> Dict:
        """
        ๋น„์œจ ๊ธฐ๋ฐ˜ ์†Œ๊ฐ
        """
        info = self.controller.get_supply_info()
        burn_amount = info['total_supply'] * (percentage / 100)
        
        return self.fixed_burn(burn_amount)
    
    def dynamic_burn(self, transaction_volume: float, burn_rate: float = 0.1) -> Dict:
        """
        ๊ฑฐ๋ž˜๋Ÿ‰ ๊ธฐ๋ฐ˜ ๋™์  ์†Œ๊ฐ (EIP-1559 ์Šคํƒ€์ผ)
        
        Args:
            transaction_volume: ๊ฑฐ๋ž˜๋Ÿ‰
            burn_rate: ์†Œ๊ฐ ๋น„์œจ (๊ธฐ๋ณธ 10%)
        """
        burn_amount = transaction_volume * burn_rate
        
        result = self.fixed_burn(burn_amount)
        result['transaction_volume'] = transaction_volume
        result['burn_rate'] = burn_rate
        
        return result
    
    def calculate_deflation_impact(self, burn_amount: float) -> Dict:
        """
        ์†Œ๊ฐ์ด ํ† ํฐ ๊ฒฝ์ œ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ ๊ณ„์‚ฐ
        """
        info = self.controller.get_supply_info()
        
        # ํ˜„์žฌ ๊ฐ€๊ฒฉ ๊ฐ€์ • (์‹ค์ œ๋กœ๋Š” ์˜ค๋ผํด์ด๋‚˜ DEX์—์„œ ๊ฐ€์ ธ์™€์•ผ ํ•จ)
        assumed_price = 1.0  # $1
        
        # ์†Œ๊ฐ ํ›„ ๊ณต๊ธ‰๋Ÿ‰
        new_supply = info['total_supply'] - burn_amount
        
        # ๋‹จ์ˆœ ๊ณต๊ธ‰-์ˆ˜์š” ๋ชจ๋ธ (์‹ค์ œ๋กœ๋Š” ํ›จ์”ฌ ๋ณต์žกํ•จ)
        supply_reduction = (burn_amount / info['total_supply']) * 100
        
        # ๊ฐ€๊ฒฉ ์ƒ์Šน ์˜ˆ์ธก (๋งค์šฐ ๋‹จ์ˆœํ™”๋œ ๋ชจ๋ธ)
        # ์‹ค์ œ๋กœ๋Š” ์œ ๋™์„ฑ, ๊ฑฐ๋ž˜๋Ÿ‰, ์‹œ์žฅ ์‹ฌ๋ฆฌ ๋“ฑ ๊ณ ๋ คํ•ด์•ผ ํ•จ
        estimated_price_impact = supply_reduction * 0.5  # 50% ํšจ๊ณผ ๊ฐ€์ •
        
        return {
            'burn_amount': burn_amount,
            'supply_reduction_pct': supply_reduction,
            'new_supply': new_supply,
            'estimated_price_impact_pct': estimated_price_impact,
            'estimated_new_price': assumed_price * (1 + estimated_price_impact / 100)
        }
    
    def get_optimal_burn_rate(self, target_deflation: float, time_period_days: int) -> float:
        """
        ๋ชฉํ‘œ ๋””ํ”Œ๋ ˆ์ด์…˜์œจ์„ ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์ตœ์  ์†Œ๊ฐ๋ฅ  ๊ณ„์‚ฐ
        
        Args:
            target_deflation: ๋ชฉํ‘œ ๋””ํ”Œ๋ ˆ์ด์…˜์œจ (%)
            time_period_days: ๊ธฐ๊ฐ„ (์ผ)
        """
        info = self.controller.get_supply_info()
        
        # ์ผ์ผ ์†Œ๊ฐ๋Ÿ‰ ๊ณ„์‚ฐ
        total_burn_needed = info['total_supply'] * (target_deflation / 100)
        daily_burn = total_burn_needed / time_period_days
        
        # ์ผ์ผ ์†Œ๊ฐ๋ฅ 
        daily_burn_rate = (daily_burn / info['total_supply']) * 100
        
        return {
            'target_deflation': target_deflation,
            'time_period_days': time_period_days,
            'total_burn_needed': total_burn_needed,
            'daily_burn_amount': daily_burn,
            'daily_burn_rate': daily_burn_rate
        }
    
    def print_burn_analytics(self):
        """
        ์†Œ๊ฐ ๋ถ„์„ ๋ฆฌํฌํŠธ ์ถœ๋ ฅ
        """
        if not self.burn_history:
            print("๐Ÿ“Š ์†Œ๊ฐ ๊ธฐ๋ก์ด ์—†์Šต๋‹ˆ๋‹ค.")
            return
        
        total_burned = sum(record['amount'] for record in self.burn_history)
        
        print("\n" + "="*60)
        print("๐Ÿ”ฅ ์†Œ๊ฐ ๋ถ„์„ ๋ฆฌํฌํŠธ")
        print("="*60)
        print(f"๐Ÿ“… ์ด ์†Œ๊ฐ ํšŸ์ˆ˜: {len(self.burn_history)}ํšŒ")
        print(f"๐Ÿ’ฐ ์ด ์†Œ๊ฐ๋Ÿ‰: {total_burned:,.2f} ํ† ํฐ")
        print(f"๐Ÿ“Š ํ‰๊ท  ์†Œ๊ฐ๋Ÿ‰: {total_burned/len(self.burn_history):,.2f} ํ† ํฐ")
        print("\n์ตœ๊ทผ ์†Œ๊ฐ ๊ธฐ๋ก:")
        print("-"*60)
        
        for record in self.burn_history[-5:]:  # ์ตœ๊ทผ 5๊ฐœ
            print(f"โฐ {record['timestamp'].strftime('%Y-%m-%d %H:%M:%S')}")
            print(f"   ์ „๋žต: {record['strategy']}")
            print(f"   ์†Œ๊ฐ๋Ÿ‰: {record['amount']:,.2f} ({record['burn_percentage']:.2f}%)")
            print(f"   ๊ณต๊ธ‰๋Ÿ‰: {record['supply_before']:,.2f} โ†’ {record['supply_after']:,.2f}")
            print()
        
        print("="*60 + "\n")


# ์‚ฌ์šฉ ์˜ˆ์‹œ
if __name__ == "__main__":
    # ๊ธฐ์กด ์ปจํŠธ๋กค๋Ÿฌ ์‚ฌ์šฉ
    burn_controller = DynamicBurnController(controller)
    
    # ๊ณ ์ • ๊ธˆ์•ก ์†Œ๊ฐ
    result = burn_controller.fixed_burn(1000)
    print(f"์†Œ๊ฐ ๊ฒฐ๊ณผ: {result}")
    
    # ๊ฑฐ๋ž˜๋Ÿ‰ ๊ธฐ๋ฐ˜ ๋™์  ์†Œ๊ฐ
    result = burn_controller.dynamic_burn(
        transaction_volume=10000,  # $10,000 ๊ฑฐ๋ž˜๋Ÿ‰
        burn_rate=0.1  # 10% ์†Œ๊ฐ
    )
    print(f"๋™์  ์†Œ๊ฐ ๊ฒฐ๊ณผ: {result}")
    
    # ์†Œ๊ฐ ์˜ํ–ฅ ๋ถ„์„
    impact = burn_controller.calculate_deflation_impact(5000)
    print(f"\n์†Œ๊ฐ ์˜ํ–ฅ ๋ถ„์„:")
    print(f"  ๊ณต๊ธ‰ ๊ฐ์†Œ: {impact['supply_reduction_pct']:.2f}%")
    print(f"  ์˜ˆ์ƒ ๊ฐ€๊ฒฉ ์˜ํ–ฅ: +{impact['estimated_price_impact_pct']:.2f}%")
    
    # ์ตœ์  ์†Œ๊ฐ๋ฅ  ๊ณ„์‚ฐ
    optimal = burn_controller.get_optimal_burn_rate(
        target_deflation=5.0,  # 5% ๋””ํ”Œ๋ ˆ์ด์…˜ ๋ชฉํ‘œ
        time_period_days=365  # 1๋…„
    )
    print(f"\n์ตœ์  ์†Œ๊ฐ ์ „๋žต:")
    print(f"  ์ผ์ผ ์†Œ๊ฐ๋Ÿ‰: {optimal['daily_burn_amount']:,.2f} ํ† ํฐ")
    print(f"  ์ผ์ผ ์†Œ๊ฐ๋ฅ : {optimal['daily_burn_rate']:.4f}%")
    
    # ๋ถ„์„ ๋ฆฌํฌํŠธ
    burn_controller.print_burn_analytics()
์†Œ๊ฐ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์•ผ! ๐Ÿ’ช ํ•˜์ง€๋งŒ ์กฐ์‹ฌํ•ด์•ผ ํ•  ์ ๋“ค์ด ์žˆ์–ด:

1. ๊ณผ๋„ํ•œ ์†Œ๊ฐ์€ ๋…์ด ๋  ์ˆ˜ ์žˆ์–ด
๋„ˆ๋ฌด ๋งŽ์ด ์†Œ๊ฐํ•˜๋ฉด ์œ ๋™์„ฑ์ด ๋ถ€์กฑํ•ด์ ธ์„œ ๊ฑฐ๋ž˜๊ฐ€ ์–ด๋ ค์›Œ์งˆ ์ˆ˜ ์žˆ์–ด. ์ ์ ˆํ•œ ๊ท ํ˜•์ด ์ค‘์š”ํ•ด! โš–๏ธ

2. ์†Œ๊ฐ์€ ๋˜๋Œ๋ฆด ์ˆ˜ ์—†์–ด
ํ•œ ๋ฒˆ ์†Œ๊ฐ๋œ ํ† ํฐ์€ ์˜์›ํžˆ ์‚ฌ๋ผ์ ธ. ๊ทธ๋ž˜์„œ ์‹ ์ค‘ํ•˜๊ฒŒ ๊ฒฐ์ •ํ•ด์•ผ ํ•ด. ๐Ÿšซ

3. ์‹œ์žฅ ๋ฐ˜์‘์„ ๊ณ ๋ คํ•ด์•ผ ํ•ด
์†Œ๊ฐ ๋ฐœํ‘œ๋งŒ์œผ๋กœ๋„ ๊ฐ€๊ฒฉ์ด ์›€์ง์ผ ์ˆ˜ ์žˆ์–ด. ํƒ€์ด๋ฐ๊ณผ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์ด ์ค‘์š”ํ•˜์ง€! ๐Ÿ“ข

๐Ÿ“Š ์‹ค์‹œ๊ฐ„ ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์ถ•ํ•˜๊ธฐ

์ด์ œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์‹œ๊ฐํ™”ํ•ด์„œ ๋ณด์—ฌ์ฃผ๋Š” ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! ์‹ค์ „์—์„œ๋Š” ์ด๋Ÿฐ ๊ฒŒ ์ •๋ง ์ค‘์š”ํ•ด. ๐Ÿ“ˆ
๐Ÿ“Š ์›น ๊ธฐ๋ฐ˜ ๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์‹œ๋ณด๋“œ
from flask import Flask, render_template, jsonify
import plotly.graph_objs as go
import plotly.express as px
from datetime import datetime, timedelta
import json

app = Flask(__name__)

class TokenDashboard:
    def __init__(self, controller, burn_controller, vesting_scheduler):
        self.controller = controller
        self.burn_controller = burn_controller
        self.vesting_scheduler = vesting_scheduler
    
    def get_supply_chart_data(self):
        """
        ๋ฐœํ–‰๋Ÿ‰ ์ฐจํŠธ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ
        """
        info = self.controller.get_supply_info()
        
        labels = ['๋ฐœํ–‰๋จ', '๋‚จ์€ ๋ฐœํ–‰๋Ÿ‰']
        values = [info['total_supply'], info['remaining']]
        colors = ['#66bb6a', '#e0e0e0']
        
        fig = go.Figure(data=[go.Pie(
            labels=labels,
            values=values,
            hole=0.4,
            marker=dict(colors=colors),
            textinfo='label+percent',
            textfont=dict(size=16)
        )])
        
        fig.update_layout(
            title='ํ† ํฐ ๋ฐœํ–‰ ํ˜„ํ™ฉ',
            showlegend=True,
            height=400
        )
        
        return fig.to_json()
    
    def get_emission_projection_data(self, days=365):
        """
        ๋ฐœํ–‰ ์˜ˆ์ธก ์ฐจํŠธ ๋ฐ์ดํ„ฐ
        """
        schedule = self.controller.calculate_emission_schedule(days)
        
        if not schedule:
            return None
        
        dates = [datetime.now() + timedelta(days=item['day']) for item in schedule]
        supplies = [item['supply'] for item in schedule]
        
        fig = go.Figure()
        
        fig.add_trace(go.Scatter(
            x=dates,
            y=supplies,
            mode='lines+markers',
            name='์˜ˆ์ƒ ๋ฐœํ–‰๋Ÿ‰',
            line=dict(color='#5e35b1', width=3),
            marker=dict(size=6)
        ))
        
        # ์ตœ๋Œ€ ๋ฐœํ–‰๋Ÿ‰ ๋ผ์ธ
        info = self.controller.get_supply_info()
        fig.add_hline(
            y=info['max_supply'],
            line_dash="dash",
            line_color="red",
            annotation_text="์ตœ๋Œ€ ๋ฐœํ–‰๋Ÿ‰"
        )
        
        fig.update_layout(
            title='ํ–ฅํ›„ ๋ฐœํ–‰๋Ÿ‰ ์˜ˆ์ธก',
            xaxis_title='๋‚ ์งœ',
            yaxis_title='ํ† ํฐ ์ˆ˜๋Ÿ‰',
            hovermode='x unified',
            height=400
        )
        
        return fig.to_json()
    
    def get_burn_history_data(self):
        """
        ์†Œ๊ฐ ํžˆ์Šคํ† ๋ฆฌ ์ฐจํŠธ
        """
        if not self.burn_controller.burn_history:
            return None
        
        dates = [record['timestamp'] for record in self.burn_controller.burn_history]
        amounts = [record['amount'] for record in self.burn_controller.burn_history]
        
        fig = go.Figure()
        
        fig.add_trace(go.Bar(
            x=dates,
            y=amounts,
            name='์†Œ๊ฐ๋Ÿ‰',
            marker=dict(color='#ff6b6b')
        ))
        
        fig.update_layout(
            title='์†Œ๊ฐ ํžˆ์Šคํ† ๋ฆฌ',
            xaxis_title='๋‚ ์งœ',
            yaxis_title='์†Œ๊ฐ๋Ÿ‰',
            height=400
        )
        
        return fig.to_json()
    
    def get_metrics_summary(self):
        """
        ์ฃผ์š” ์ง€ํ‘œ ์š”์•ฝ
        """
        info = self.controller.get_supply_info()
        
        # ์†Œ๊ฐ ํ†ต๊ณ„
        total_burned = sum(
            record['amount'] 
            for record in self.burn_controller.burn_history
        ) if self.burn_controller.burn_history else 0
        
        # ๋ฒ ์ŠคํŒ… ํ†ต๊ณ„
        total_vested = 0
        total_locked = 0
        for beneficiary, schedule in self.vesting_scheduler.schedules.items():
            vested = self.vesting_scheduler.get_vested_amount(beneficiary)
            total_vested += vested
            total_locked += schedule['total_amount'] - vested
        
        return {
            'current_supply': info['total_supply'],
            'max_supply': info['max_supply'],
            'supply_percentage': info['supply_percentage'],
            'total_burned': total_burned,
            'total_vested': total_vested,
            'total_locked': total_locked,
            'circulating_supply': info['total_supply'] - total_locked
        }


# Flask ๋ผ์šฐํŠธ
@app.route('/')
def index():
    return '''
    <!DOCTYPE html>
    <html>
    <head>
        <title>ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ๋Œ€์‹œ๋ณด๋“œ</title>
        <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
        <style>
            body {
                font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                margin: 0;
                padding: 20px;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            }
            .container {
                max-width: 1400px;
                margin: 0 auto;
                background: white;
                border-radius: 20px;
                padding: 30px;
                box-shadow: 0 10px 40px rgba(0,0,0,0.2);
            }
            h1 {
                color: #5e35b1;
                text-align: center;
                margin-bottom: 40px;
            }
            .metrics {
                display: grid;
                grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
                gap: 20px;
                margin-bottom: 40px;
            }
            .metric-card {
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                padding: 25px;
                border-radius: 15px;
                box-shadow: 0 5px 15px rgba(0,0,0,0.1);
            }
            .metric-value {
                font-size: 2em;
                font-weight: bold;
                margin: 10px 0;
            }
            .metric-label {
                font-size: 0.9em;
                opacity: 0.9;
            }
            .charts {
                display: grid;
                grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
                gap: 30px;
            }
            .chart-container {
                background: #f8f9fa;
                padding: 20px;
                border-radius: 15px;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <h1>๐Ÿช™ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด ๋Œ€์‹œ๋ณด๋“œ</h1>
            
            <div class="metrics" id="metrics"></div>
            
            <div class="charts">
                <div class="chart-container">
                    <div id="supply-chart"></div>
                </div>
                <div class="chart-container">
                    <div id="emission-chart"></div>
                </div>
                <div class="chart-container">
                    <div id="burn-chart"></div>
                </div>
            </div>
        </div>
        
        <script>
            // ๋ฐ์ดํ„ฐ ๋กœ๋“œ ๋ฐ ์ฐจํŠธ ๋ Œ๋”๋ง
            async function loadDashboard() {
                // ๋ฉ”ํŠธ๋ฆญ ๋กœ๋“œ
                const metrics = await fetch('/api/metrics').then(r => r.json());
                renderMetrics(metrics);
                
                // ์ฐจํŠธ ๋กœ๋“œ
                const supplyChart = await fetch('/api/supply-chart').then(r => r.json());
                Plotly.newPlot('supply-chart', JSON.parse(supplyChart).data, JSON.parse(supplyChart).layout);
                
                const emissionChart = await fetch('/api/emission-chart').then(r => r.json());
                Plotly.newPlot('emission-chart', JSON.parse(emissionChart).data, JSON.parse(emissionChart).layout);
                
                const burnChart = await fetch('/api/burn-chart').then(r => r.json());
                if (burnChart) {
                    Plotly.newPlot('burn-chart', JSON.parse(burnChart).data, JSON.parse(burnChart).layout);
                }
            }
            
            function renderMetrics(metrics) {
                const container = document.getElementById('metrics');
                container.innerHTML = `
                    <div class="metric-card">
                        <div class="metric-label">ํ˜„์žฌ ๋ฐœํ–‰๋Ÿ‰</div>
                        <div class="metric-value">${metrics.current_supply.toLocaleString()}</div>
                    </div>
                    <div class="metric-card">
                        <div class="metric-label">๋ฐœํ–‰๋ฅ </div>
                        <div class="metric-value">${metrics.supply_percentage.toFixed(1)}%</div>
                    </div>
                    <div class="metric-card">
                        <div class="metric-label">์ด ์†Œ๊ฐ๋Ÿ‰</div>
                        <div class="metric-value">${metrics.total_burned.toLocaleString()}</div>
                    </div>
                    <div class="metric-card">
                        <div class="metric-label">์œ ํ†ต๋Ÿ‰</div>
                        <div class="metric-value">${metrics.circulating_supply.toLocaleString()}</div>
                    </div>
                `;
            }
            
            // 5์ดˆ๋งˆ๋‹ค ์ž๋™ ๊ฐฑ์‹ 
            loadDashboard();
            setInterval(loadDashboard, 5000);
        </script>
    </body>
    </html>
    '''

@app.route('/api/metrics')
def api_metrics():
    dashboard = TokenDashboard(controller, burn_controller, vesting_scheduler)
    return jsonify(dashboard.get_metrics_summary())

@app.route('/api/supply-chart')
def api_supply_chart():
    dashboard = TokenDashboard(controller, burn_controller, vesting_scheduler)
    return dashboard.get_supply_chart_data()

@app.route('/api/emission-chart')
def api_emission_chart():
    dashboard = TokenDashboard(controller, burn_controller, vesting_scheduler)
    return dashboard.get_emission_projection_data()

@app.route('/api/burn-chart')
def api_burn_chart():
    dashboard = TokenDashboard(controller, burn_controller, vesting_scheduler)
    return dashboard.get_burn_history_data()

if __name__ == '__main__':
    app.run(debug=True, port=5000)
์™€! ์ด์ œ ์ง„์งœ ํ”„๋กœํŽ˜์…”๋„ํ•œ ๋Œ€์‹œ๋ณด๋“œ๊ฐ€ ์™„์„ฑ๋์–ด! ๐ŸŽ‰

์ด ๋Œ€์‹œ๋ณด๋“œ๋Š” ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐฑ์‹ ํ•˜๊ณ , ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ์ฐจํŠธ๋กœ ์‹œ๊ฐํ™”ํ•ด์ค˜. ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์ด๋Ÿฐ ๋Œ€์‹œ๋ณด๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ํŒ€์›๋“ค์ด๋‚˜ ํˆฌ์ž์ž๋“ค์—๊ฒŒ ๋ณด์—ฌ์ฃผ๊ธฐ ์ •๋ง ์ข‹์•„! ๐Ÿ“Š

Flask๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, ์›ํ•œ๋‹ค๋ฉด FastAPI๋‚˜ Django๋กœ๋„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ์ค‘์š”ํ•œ ๊ฑด ๋ฐ์ดํ„ฐ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ์‹œ๊ฐํ™”ํ•˜๋Š” ๊ฑฐ์•ผ! ๐Ÿ‘€

๐Ÿ” ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ

ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด๋Š” ์—„์ฒญ๋‚œ ๊ถŒํ•œ์ด์•ผ. ๊ทธ๋งŒํผ ๋ณด์•ˆ์ด ์ •๋ง ์ค‘์š”ํ•ด! ๐Ÿ›ก๏ธ
โš ๏ธ ์ ˆ๋Œ€ ํ•˜์ง€ ๋ง์•„์•ผ ํ•  ๊ฒƒ๋“ค

1. ๊ฐœ์ธํ‚ค๋ฅผ ์ฝ”๋“œ์— ํ•˜๋“œ์ฝ”๋”ฉ
์ ˆ๋Œ€๋กœ, ์ ˆ๋Œ€๋กœ ํ•˜์ง€ ๋งˆ! ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋‚˜ ํ•˜๋“œ์›จ์–ด ์›”๋ ›์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ด.

2. ๋‹จ์ผ ๊ด€๋ฆฌ์ž ๊ณ„์ •
๋ฉ€ํ‹ฐ์‹œ๊ทธ(Multi-signature) ์ง€๊ฐ‘์„ ์‚ฌ์šฉํ•ด์„œ ์—ฌ๋Ÿฌ ๋ช…์˜ ์Šน์ธ์ด ํ•„์š”ํ•˜๋„๋ก ํ•ด์•ผ ํ•ด.

3. ๋ฌด์ œํ•œ ๋ฐœํ–‰ ๊ถŒํ•œ
์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๋ ˆ๋ฒจ์—์„œ ์ตœ๋Œ€ ๋ฐœํ–‰๋Ÿ‰์„ ๊ฐ•์ œํ•ด์•ผ ํ•ด.

4. ๊ฐ์‚ฌ ๋กœ๊ทธ ์—†์Œ
๋ชจ๋“  ๋ฐœํ–‰/์†Œ๊ฐ ํ™œ๋™์„ ๊ธฐ๋กํ•˜๊ณ  ์ถ”์ ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ด.
๐Ÿ” ๋ณด์•ˆ ๊ฐ•ํ™” ์ฝ”๋“œ
import hashlib
import hmac
from cryptography.fernet import Fernet
import logging
from datetime import datetime

class SecureTokenController:
    def __init__(self, controller):
        self.controller = controller
        self.setup_logging()
        self.setup_encryption()
        self.action_history = []
    
    def setup_logging(self):
        """
        ๊ฐ์‚ฌ ๋กœ๊ทธ ์„ค์ •
        """
        logging.basicConfig(
            filename='token_operations.log',
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s'
        )
        self.logger = logging.getLogger(__name__)
    
    def setup_encryption(self):
        """
        ์•”ํ˜ธํ™” ์„ค์ •
        """
        # ์‹ค์ œ๋กœ๋Š” ์•ˆ์ „ํ•œ ๊ณณ์—์„œ ํ‚ค๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•จ
        self.encryption_key = Fernet.generate_key()
        self.cipher = Fernet(self.encryption_key)
    
    def verify_signature(self, message: str, signature: str, secret: str) -> bool:
        """
        HMAC ์„œ๋ช… ๊ฒ€์ฆ
        """
        expected_signature = hmac.new(
            secret.encode(),
            message.encode(),
            hashlib.sha256
        ).hexdigest()
        
        return hmac.compare_digest(signature, expected_signature)
    
    def log_action(self, action: str, details: dict, user: str):
        """
        ๋ชจ๋“  ์•ก์…˜ ๋กœ๊น…
        """
        log_entry = {
            'timestamp': datetime.now().isoformat(),
            'action': action,
            'user': user,
            'details': details
        }
        
        self.action_history.append(log_entry)
        self.logger.info(f"Action: {action} | User: {user} | Details: {details}")
    
    def require_multisig(self, action: str, approvers: list, required_approvals: int = 2):
        """
        ๋ฉ€ํ‹ฐ์‹œ๊ทธ ์Šน์ธ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
        """
        print(f"\n๐Ÿ” ๋ฉ€ํ‹ฐ์‹œ๊ทธ ์Šน์ธ ํ•„์š”: {action}")
        print(f"   ํ•„์š”ํ•œ ์Šน์ธ ์ˆ˜: {required_approvals}/{len(approvers)}")
        
        approvals = []
        
        for approver in approvers:
            # ์‹ค์ œ๋กœ๋Š” ๊ฐ ์Šน์ธ์ž์˜ ์„œ๋ช…์„ ๋ฐ›์•„์•ผ ํ•จ
            approval = input(f"   {approver}์˜ ์Šน์ธ์„ ๋ฐ›์•˜์Šต๋‹ˆ๊นŒ? (y/n): ")
            if approval.lower() == 'y':
                approvals.append(approver)
            
            if len(approvals) >= required_approvals:
                print(f"โœ… ์ถฉ๋ถ„ํ•œ ์Šน์ธ์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค! ({len(approvals)}/{required_approvals})")
                return True
        
        print(f"โŒ ์Šน์ธ์ด ๋ถ€์กฑํ•ฉ๋‹ˆ๋‹ค. ({len(approvals)}/{required_approvals})")
        return False
    
    def secure_mint(self, to_address: str, amount: float, user: str, approvers: list):
        """
        ๋ณด์•ˆ ๊ฐ•ํ™”๋œ ํ† ํฐ ๋ฐœํ–‰
        """
        # 1. ๋ฉ€ํ‹ฐ์‹œ๊ทธ ์Šน์ธ
        if not self.require_multisig(f"Mint {amount} tokens", approvers):
            self.log_action('mint_rejected', {
                'to': to_address,
                'amount': amount,
                'reason': 'insufficient_approvals'
            }, user)
            return False
        
        # 2. ๋ฐœํ–‰๋Ÿ‰ ์ œํ•œ ์ฒดํฌ
        info = self.controller.get_supply_info()
        if info['total_supply'] + amount > info['max_supply']:
            self.log_action('mint_rejected', {
                'to': to_address,
                'amount': amount,
                'reason': 'exceeds_max_supply'
            }, user)
            return False
        
        # 3. ์‹ค์ œ ๋ฐœํ–‰
        try:
            result = self.controller.mint_tokens(to_address, amount)
            
            self.log_action('mint_success', {
                'to': to_address,
                'amount': amount,
                'tx_hash': result
            }, user)
            
            return True
        
        except Exception as e:
            self.log_action('mint_error', {
                'to': to_address,
                'amount': amount,
                'error': str(e)
            }, user)
            return False
    
    def get_audit_report(self, days: int = 30):
        """
        ๊ฐ์‚ฌ ๋ฆฌํฌํŠธ ์ƒ์„ฑ
        """
        cutoff_date = datetime.now() - timedelta(days=days)
        
        recent_actions = [
            action for action in self.action_history
            if datetime.fromisoformat(action['timestamp']) > cutoff_date
        ]
        
        print(f"\n๐Ÿ“‹ ์ตœ๊ทผ {days}์ผ ๊ฐ์‚ฌ ๋ฆฌํฌํŠธ")
        print("="*60)
        print(f"์ด ์•ก์…˜ ์ˆ˜: {len(recent_actions)}")
        
        # ์•ก์…˜ ํƒ€์ž…๋ณ„ ์ง‘๊ณ„
        action_types = {}
        for action in recent_actions:
            action_type = action['action']
            action_types[action_type] = action_types.get(action_type, 0) + 1
        
        print("\n์•ก์…˜ ํƒ€์ž…๋ณ„ ํ†ต๊ณ„:")
        for action_type, count in action_types.items():
            print(f"  {action_type}: {count}ํšŒ")
        
        print("\n์ตœ๊ทผ ์•ก์…˜:")
        for action in recent_actions[-10:]:
            print(f"  [{action['timestamp']}] {action['action']} by {action['user']}")
        
        print("="*60 + "\n")


# ์‚ฌ์šฉ ์˜ˆ์‹œ
if __name__ == "__main__":
    secure_controller = SecureTokenController(controller)
    
    # ๋ณด์•ˆ ๊ฐ•ํ™”๋œ ๋ฐœํ–‰
    approvers = ['Admin1', 'Admin2', 'Admin3']
    
    secure_controller.secure_mint(
        to_address="0x...",
        amount=10000,
        user="Admin1",
        approvers=approvers
    )
    
    # ๊ฐ์‚ฌ ๋ฆฌํฌํŠธ
    secure_controller.get_audit_report(days=30)
๋ณด์•ˆ์€ ์•„๋ฌด๋ฆฌ ๊ฐ•์กฐํ•ด๋„ ์ง€๋‚˜์น˜์ง€ ์•Š์•„! ๐Ÿ”’

์‹ค์ œ๋กœ ๋งŽ์€ ํ”„๋กœ์ ํŠธ๋“ค์ด ๋ณด์•ˆ ์ทจ์•ฝ์  ๋•Œ๋ฌธ์— ํ•ดํ‚น๋‹นํ–ˆ์–ด. 2021๋…„ Poly Network ํ•ดํ‚น์—์„œ๋Š” 6์–ต ๋‹ฌ๋Ÿฌ๊ฐ€ ๋„˜๋Š” ์•”ํ˜ธํ™”ํ๊ฐ€ ๋„๋‚œ๋‹นํ–ˆ๊ณ , 2022๋…„ Ronin Bridge ํ•ดํ‚น์—์„œ๋Š” 6์–ต 2์ฒœ๋งŒ ๋‹ฌ๋Ÿฌ๊ฐ€ ์‚ฌ๋ผ์กŒ์–ด. ๐Ÿ˜ฑ

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ์‹œ์Šคํ…œ์—๋Š”:
โ€ข ๋ฉ€ํ‹ฐ์‹œ๊ทธ ์Šน์ธ - ์—ฌ๋Ÿฌ ๋ช…์˜ ๋™์˜๊ฐ€ ํ•„์š”
โ€ข ๊ฐ์‚ฌ ๋กœ๊ทธ - ๋ชจ๋“  ํ™œ๋™ ๊ธฐ๋ก
โ€ข ์•”ํ˜ธํ™” - ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ ๋ณดํ˜ธ
โ€ข ์ œํ•œ ๊ฒ€์ฆ - ์ตœ๋Œ€ ๋ฐœํ–‰๋Ÿ‰ ๊ฐ•์ œ

์ด๋Ÿฐ ๋ณด์•ˆ ์žฅ์น˜๋“ค์ด ํ•„์ˆ˜์•ผ! ๐Ÿ’ช

๐ŸŒ ์‹ค์ „ ํ”„๋กœ์ ํŠธ ์ ์šฉ ์‚ฌ๋ก€

์ด๋ก ๊ณผ ์ฝ”๋“œ๋ฅผ ๋ฐฐ์› ์œผ๋‹ˆ, ์ด์ œ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ์ ์šฉํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด์ž! ๐Ÿš€

๐Ÿ’ก ์‚ฌ๋ก€ 1: DeFi ํ”„๋กœํ† ์ฝœ์˜ ๊ฑฐ๋ฒ„๋„Œ์Šค ํ† ํฐ

ํ”„๋กœ์ ํŠธ ๊ฐœ์š”
ํƒˆ์ค‘์•™ํ™” ๊ฑฐ๋ž˜์†Œ(DEX)์˜ ๊ฑฐ๋ฒ„๋„Œ์Šค ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ๊ด€๋ฆฌ

ํ† ํฐ ๊ฒฝ์ œ ์„ค๊ณ„
โ€ข ์ด ๋ฐœํ–‰๋Ÿ‰: 1์–ต ๊ฐœ
โ€ข ์ดˆ๊ธฐ ์œ ํ†ต๋Ÿ‰: 1,000๋งŒ ๊ฐœ (10%)
โ€ข ์œ ๋™์„ฑ ์ฑ„๊ตด ๋ณด์ƒ: 5,000๋งŒ ๊ฐœ (50%, 4๋…„๊ฐ„ ๋ถ„๋ฐฐ)
โ€ข ํŒ€ & ์–ด๋“œ๋ฐ”์ด์ €: 2,000๋งŒ ๊ฐœ (20%, 4๋…„ ๋ฒ ์ŠคํŒ…)
โ€ข ์žฌ๋‹จ ๋ณด์œ : 2,000๋งŒ ๊ฐœ (20%, ์ƒํƒœ๊ณ„ ๋ฐœ์ „์šฉ)

๋ฐœํ–‰ ์ „๋žต
1. ๋งค์ผ ์œ ๋™์„ฑ ๊ณต๊ธ‰์ž์—๊ฒŒ ๋ณด์ƒ ๋ถ„๋ฐฐ
2. ๊ฑฐ๋ž˜ ์ˆ˜์ˆ˜๋ฃŒ์˜ 50%๋ฅผ ํ† ํฐ์œผ๋กœ ์†Œ๊ฐ
3. ๋ถ„๊ธฐ๋งˆ๋‹ค ๋ฐœํ–‰ ์†๋„ ์กฐ์ • (DAO ํˆฌํ‘œ)
4. ํŒ€ ํ† ํฐ์€ 12๊ฐœ์›” ํด๋ฆฌํ”„ ํ›„ 36๊ฐœ์›” ๋ฒ ์ŠคํŒ…
๐ŸŽฏ DeFi ํ”„๋กœํ† ์ฝœ ํ† ํฐ ์ปจํŠธ๋กค๋Ÿฌ
class DeFiTokenController:
    def __init__(self, base_controller):
        self.controller = base_controller
        self.liquidity_mining_pool = 50000000  # 5์ฒœ๋งŒ ๊ฐœ
        self.daily_reward_rate = 0.001  # 0.1% per day
        self.fee_burn_rate = 0.5  # 50% of fees
    
    def calculate_liquidity_rewards(self, user_liquidity: float, total_liquidity: float) -> float:
        """
        ์œ ๋™์„ฑ ์ฑ„๊ตด ๋ณด์ƒ ๊ณ„์‚ฐ
        """
        # ์‚ฌ์šฉ์ž์˜ ์œ ๋™์„ฑ ๋น„์œจ
        user_share = user_liquidity / total_liquidity
        
        # ์ผ์ผ ์ด ๋ณด์ƒ
        daily_total_reward = self.liquidity_mining_pool * self.daily_reward_rate
        
        # ์‚ฌ์šฉ์ž ๋ณด์ƒ
        user_reward = daily_total_reward * user_share
        
        return user_reward
    
    def process_trading_fees(self, fee_amount: float, token_price: float):
        """
        ๊ฑฐ๋ž˜ ์ˆ˜์ˆ˜๋ฃŒ ์ฒ˜๋ฆฌ (์ผ๋ถ€ ์†Œ๊ฐ)
        """
        # ์†Œ๊ฐํ•  ํ† ํฐ ์–‘ ๊ณ„์‚ฐ
        burn_amount = (fee_amount * self.fee_burn_rate) / token_price
        
        print(f"๐Ÿ’ฐ ๊ฑฐ๋ž˜ ์ˆ˜์ˆ˜๋ฃŒ: ${fee_amount:.2f}")
        print(f"๐Ÿ”ฅ ์†Œ๊ฐ ์˜ˆ์ •: {burn_amount:.2f} ํ† ํฐ")
        
        # ์‹ค์ œ ์†Œ๊ฐ ์‹คํ–‰
        # burn_controller.fixed_burn(burn_amount)
        
        return burn_amount
    
    def adjust_emission_rate(self, new_rate: float, dao_approval: bool):
        """
        ๋ฐœํ–‰ ์†๋„ ์กฐ์ • (DAO ๊ฑฐ๋ฒ„๋„Œ์Šค)
        """
        if not dao_approval:
            print("โŒ DAO ์Šน์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค!")
            return False
        
        old_rate = self.daily_reward_rate
        self.daily_reward_rate = new_rate
        
        print(f"โœ… ๋ฐœํ–‰ ์†๋„ ์กฐ์ • ์™„๋ฃŒ")
        print(f"   ์ด์ „: {old_rate*100:.3f}% per day")
        print(f"   ๋ณ€๊ฒฝ: {new_rate*100:.3f}% per day")
        
        return True


# ์‹ค์ œ ์‚ฌ์šฉ
defi_controller = DeFiTokenController(controller)

# ์œ ๋™์„ฑ ๋ณด์ƒ ๊ณ„์‚ฐ
user_liquidity = 100000  # $100,000
total_liquidity = 10000000  # $10,000,000

reward = defi_controller.calculate_liquidity_rewards(user_liquidity, total_liquidity)
print(f"์ผ์ผ ๋ณด์ƒ: {reward:.2f} ํ† ํฐ")

# ๊ฑฐ๋ž˜ ์ˆ˜์ˆ˜๋ฃŒ ์ฒ˜๋ฆฌ
defi_controller.process_trading_fees(fee_amount=1000, token_price=2.5)

๐ŸŽฎ ์‚ฌ๋ก€ 2: ๊ฒŒ์ž„ ๋‚ด ํ† ํฐ ๊ฒฝ์ œ

ํ”„๋กœ์ ํŠธ ๊ฐœ์š”
Play-to-Earn ๊ฒŒ์ž„์˜ ์ธ๊ฒŒ์ž„ ํ† ํฐ ๊ด€๋ฆฌ

ํ† ํฐ ๊ฒฝ์ œ ์„ค๊ณ„
โ€ข ๋ฌด์ œํ•œ ๋ฐœํ–‰ (์ธํ”Œ๋ ˆ์ด์…˜ ๋ชจ๋ธ)
โ€ข ํ”Œ๋ ˆ์ด์–ด ํ™œ๋™์— ๋”ฐ๋ผ ๋ณด์ƒ
โ€ข ๊ฒŒ์ž„ ๋‚ด ์•„์ดํ…œ ๊ตฌ๋งค ์‹œ ์†Œ๊ฐ
โ€ข ๋™์  ๋ฐธ๋Ÿฐ์‹ฑ์œผ๋กœ ๊ฒฝ์ œ ์•ˆ์ •ํ™”

ํ•ต์‹ฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜
1. ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ํ€˜์ŠคํŠธ ์™„๋ฃŒ ์‹œ ํ† ํฐ ํš๋“
2. ์•„์ดํ…œ ๊ตฌ๋งค/์—…๊ทธ๋ ˆ์ด๋“œ ์‹œ ํ† ํฐ ์†Œ๊ฐ
3. ์ผ์ผ ๋ฐœํ–‰๋Ÿ‰๊ณผ ์†Œ๊ฐ๋Ÿ‰ ๋ชจ๋‹ˆํ„ฐ๋ง
4. ์ธํ”Œ๋ ˆ์ด์…˜์œจ์ด 5%๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ๋ณด์ƒ ๊ฐ์†Œ
๐ŸŽฎ ๊ฒŒ์ž„ ํ† ํฐ ๊ฒฝ์ œ ์‹œ์Šคํ…œ
class GameTokenEconomy:
    def __init__(self):
        self.total_minted = 0
        self.total_burned = 0
        self.daily_mint_limit = 1000000
        self.target_inflation = 0.05  # 5%
        self.base_reward = 100
    
    def calculate_quest_reward(self, difficulty: str, player_level: int) -> float:
        """
        ํ€˜์ŠคํŠธ ๋ณด์ƒ ๊ณ„์‚ฐ
        """
        difficulty_multiplier = {
            'easy': 1.0,
            'medium': 2.0,
            'hard': 3.5,
            'legendary': 5.0
        }
        
        base = self.base_reward
        diff_mult = difficulty_multiplier.get(difficulty, 1.0)
        level_mult = 1 + (player_level * 0.1)
        
        # ์ธํ”Œ๋ ˆ์ด์…˜ ์กฐ์ •
        inflation_rate = self.get_inflation_rate()
        if inflation_rate > self.target_inflation:
            inflation_penalty = 0.8  # 20% ๊ฐ์†Œ
        else:
            inflation_penalty = 1.0
        
        reward = base * diff_mult * level_mult * inflation_penalty
        
        return reward
    
    def process_item_purchase(self, item_price: float, burn_rate: float = 0.3):
        """
        ์•„์ดํ…œ ๊ตฌ๋งค ์ฒ˜๋ฆฌ (์ผ๋ถ€ ์†Œ๊ฐ)
        """
        burn_amount = item_price * burn_rate
        
        self.total_burned += burn_amount
        
        print(f"๐Ÿ›’ ์•„์ดํ…œ ๊ตฌ๋งค: {item_price:.2f} ํ† ํฐ")
        print(f"๐Ÿ”ฅ ์†Œ๊ฐ: {burn_amount:.2f} ํ† ํฐ")
        print(f"๐Ÿ’ฐ ํŒ๋งค์ž ์ˆ˜๋ น: {item_price - burn_amount:.2f} ํ† ํฐ")
        
        return burn_amount
    
    def get_inflation_rate(self) -> float:
        """
        ํ˜„์žฌ ์ธํ”Œ๋ ˆ์ด์…˜์œจ ๊ณ„์‚ฐ
        """
        if self.total_burned == 0:
            return 1.0
        
        net_supply = self.total_minted - self.total_burned
        inflation = (self.total_minted - self.total_burned) / self.total_minted
        
        return inflation
    
    def daily_economy_report(self):
        """
        ์ผ์ผ ๊ฒฝ์ œ ๋ฆฌํฌํŠธ
        """
        inflation = self.get_inflation_rate()
        net_supply = self.total_minted - self.total_burned
        
        print("\n" + "="*60)
        print("๐ŸŽฎ ๊ฒŒ์ž„ ๊ฒฝ์ œ ์ผ์ผ ๋ฆฌํฌํŠธ")
        print("="*60)
        print(f"๐Ÿ’ฐ ์ด ๋ฐœํ–‰: {self.total_minted:,.2f} ํ† ํฐ")
        print(f"๐Ÿ”ฅ ์ด ์†Œ๊ฐ: {self.total_burned:,.2f} ํ† ํฐ")
        print(f"๐Ÿ“Š ์ˆœ ๊ณต๊ธ‰: {net_supply:,.2f} ํ† ํฐ")
        print(f"๐Ÿ“ˆ ์ธํ”Œ๋ ˆ์ด์…˜: {inflation*100:.2f}%")
        
        if inflation > self.target_inflation:
            print(f"โš ๏ธ ๊ฒฝ๊ณ : ๋ชฉํ‘œ ์ธํ”Œ๋ ˆ์ด์…˜({self.target_inflation*100}%)์„ ์ดˆ๊ณผํ–ˆ์Šต๋‹ˆ๋‹ค!")
            print(f"   ๋ณด์ƒ์ด ์ž๋™์œผ๋กœ ์กฐ์ •๋ฉ๋‹ˆ๋‹ค.")
        else:
            print(f"โœ… ๊ฒฝ์ œ๊ฐ€ ์•ˆ์ •์ ์ž…๋‹ˆ๋‹ค.")
        
        print("="*60 + "\n")


# ๊ฒŒ์ž„ ๊ฒฝ์ œ ์‹œ๋ฎฌ๋ ˆ์ด์…˜
game_economy = GameTokenEconomy()

# ํ”Œ๋ ˆ์ด์–ด๋“ค์ด ํ€˜์ŠคํŠธ ์™„๋ฃŒ
for i in range(100):
    reward = game_economy.calculate_quest_reward('medium', player_level=10)
    game_economy.total_minted += reward

# ์•„์ดํ…œ ๊ตฌ๋งค
for i in range(50):
    game_economy.process_item_purchase(item_price=200)

# ์ผ์ผ ๋ฆฌํฌํŠธ
game_economy.daily_economy_report()
๊ฒŒ์ž„ ํ† ํฐ ๊ฒฝ์ œ๋Š” ์ •๋ง ๋ณต์žกํ•ด! ๐ŸŽฎ

Axie Infinity ๊ฐ™์€ ๊ฒŒ์ž„์ด ์ดˆ๊ธฐ์— ์—„์ฒญ๋‚œ ์„ฑ๊ณต์„ ๊ฑฐ๋’€์ง€๋งŒ, ๋‚˜์ค‘์— ํ† ํฐ ๊ฒฝ์ œ ๋ฐธ๋Ÿฐ์Šค๊ฐ€ ๋ฌด๋„ˆ์ง€๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ์–ด. ๋„ˆ๋ฌด ๋งŽ์€ ํ† ํฐ์ด ๋ฐœํ–‰๋˜๊ณ , ์†Œ๊ฐ์€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์•„์„œ ๊ฐ€์น˜๊ฐ€ ํญ๋ฝํ•œ ๊ฑฐ์ง€. ๐Ÿ“‰

๊ทธ๋ž˜์„œ ๋™์  ๋ฐธ๋Ÿฐ์‹ฑ์ด ์ •๋ง ์ค‘์š”ํ•ด! ๋ฐœํ–‰๋Ÿ‰๊ณผ ์†Œ๊ฐ๋Ÿ‰์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ณ , ์ž๋™์œผ๋กœ ์กฐ์ •ํ•˜๋Š” ์‹œ์Šคํ…œ์ด ํ•„์š”ํ•ด. ๐ŸŽฏ

๐Ÿ”ง ์‹ค์ „ ํŒ๊ณผ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

๋งˆ์ง€๋ง‰์œผ๋กœ, ์‹ค์ „์—์„œ ์ •๋ง ์œ ์šฉํ•œ ํŒ๋“ค์„ ๊ณต์œ ํ• ๊ฒŒ! ์ด๊ฑด ๋‚ด๊ฐ€ ์ง์ ‘ ๊ฒฝํ—˜ํ•˜๋ฉด์„œ ๋ฐฐ์šด ๊ฒƒ๋“ค์ด์•ผ. ๐Ÿ’ก
โœจ ์‹ค์ „ ํŒ ๋ชจ์Œ

1. ํ…Œ์ŠคํŠธ๋„ท์—์„œ ์ถฉ๋ถ„ํžˆ ํ…Œ์ŠคํŠธํ•˜๊ธฐ
๋ฉ”์ธ๋„ท์— ๋ฐฐํฌํ•˜๊ธฐ ์ „์— Goerli, Sepolia ๊ฐ™์€ ํ…Œ์ŠคํŠธ๋„ท์—์„œ ์ตœ์†Œ 2์ฃผ๋Š” ํ…Œ์ŠคํŠธํ•ด์•ผ ํ•ด. ์‹ค์ œ ๋ˆ์ด ๊ฑธ๋ฆฐ ๋ฌธ์ œ๋‹ˆ๊นŒ! ๐Ÿงช

2. ์ ์ง„์  ๋กค์•„์›ƒ
์ฒ˜์Œ๋ถ€ํ„ฐ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ๋‹ค ์ผœ์ง€ ๋งˆ. ๋‹จ๊ณ„์ ์œผ๋กœ ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”ํ•˜๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ์—†๋Š”์ง€ ํ™•์ธํ•ด. ๐Ÿšฆ

3. ์ปค๋ฎค๋‹ˆํ‹ฐ์™€ ์†Œํ†ต
ํ† ํฐ ๊ฒฝ์ œ ๋ณ€๊ฒฝ์‚ฌํ•ญ์€ ๋ฐ˜๋“œ์‹œ ์‚ฌ์ „์— ๊ณต์ง€ํ•˜๊ณ , ์ปค๋ฎค๋‹ˆํ‹ฐ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›์•„. ๊ฐ‘์ž‘์Šค๋Ÿฌ์šด ๋ณ€๊ฒฝ์€ ์‹ ๋ขฐ๋ฅผ ์žƒ๊ฒŒ ๋งŒ๋“ค์–ด. ๐Ÿ“ข

4. ๋น„์ƒ ์ •์ง€ ๋ฉ”์ปค๋‹ˆ์ฆ˜
๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ์„ ๋•Œ ์ฆ‰์‹œ ์‹œ์Šคํ…œ์„ ๋ฉˆ์ถœ ์ˆ˜ ์žˆ๋Š” 'Circuit Breaker'๋ฅผ ๋งŒ๋“ค์–ด๋‘ฌ. ํ•ดํ‚น์ด๋‚˜ ๋ฒ„๊ทธ ๋ฐœ์ƒ ์‹œ ํ”ผํ•ด๋ฅผ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ์–ด. ๐Ÿ›‘

5. ์ •๊ธฐ์ ์ธ ๊ฐ์‚ฌ
์ตœ์†Œ ๋ถ„๊ธฐ๋งˆ๋‹ค ํ•œ ๋ฒˆ์”ฉ์€ ์ „์ฒด ์‹œ์Šคํ…œ์„ ๊ฐ์‚ฌํ•ด. ์™ธ๋ถ€ ๋ณด์•ˆ ์—…์ฒด์— ์˜๋ขฐํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์•„. ๐Ÿ”

6. ๋ฐ์ดํ„ฐ ๋ฐฑ์—…
๋ชจ๋“  ํŠธ๋žœ์žญ์…˜ ๋ฐ์ดํ„ฐ์™€ ๋กœ๊ทธ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋ฐฑ์—…ํ•ด. ๋‚˜์ค‘์— ๋ถ„์Ÿ์ด ์ƒ๊ธฐ๊ฑฐ๋‚˜ ๋ถ„์„์ด ํ•„์š”ํ•  ๋•Œ ํ•„์ˆ˜์•ผ. ๐Ÿ’พ

7. ๊ฐ€์Šค๋น„ ์ตœ์ ํ™”
์ด๋”๋ฆฌ์›€์—์„œ๋Š” ๊ฐ€์Šค๋น„๊ฐ€ ๋น„์‹ธ๋‹ˆ๊นŒ, ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ๋‚˜ ๋ ˆ์ด์–ด2 ์†”๋ฃจ์…˜์„ ๊ณ ๋ คํ•ด๋ด. ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ํ›จ์”ฌ ์ข‹์•„์ ธ. โ›ฝ

8. ๋ชจ๋‹ˆํ„ฐ๋ง ์•Œ๋ฆผ ์„ค์ •
์ด์ƒ ์ง•ํ›„๊ฐ€ ๊ฐ์ง€๋˜๋ฉด ์ฆ‰์‹œ ์•Œ๋ฆผ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•ด. ํ…”๋ ˆ๊ทธ๋žจ, ์Šฌ๋ž™, ์ด๋ฉ”์ผ ๋“ฑ ๋‹ค์–‘ํ•œ ์ฑ„๋„์„ ํ™œ์šฉํ•ด. ๐Ÿšจ

๐ŸŽ“ ํ•™์Šต ๋ฆฌ์†Œ์Šค์™€ ๋‹ค์Œ ๋‹จ๊ณ„

์—ฌ๊ธฐ๊นŒ์ง€ ๋”ฐ๋ผ์™”๋‹ค๋ฉด ์ •๋ง ๋Œ€๋‹จํ•ด! ๐Ÿ‘ ํ•˜์ง€๋งŒ ๋ฐฐ์›€์€ ์—ฌ๊ธฐ์„œ ๋์ด ์•„๋‹ˆ์•ผ. ๊ณ„์† ๊ณต๋ถ€ํ•˜๊ณ  ๋ฐœ์ „ํ•ด์•ผ ํ•ด! ๐Ÿ“š
๐Ÿ“– ์ถ”์ฒœ ํ•™์Šต ์ž๋ฃŒ

๊ณต์‹ ๋ฌธ์„œ
โ€ข Ethereum.org - ์ด๋”๋ฆฌ์›€ ๊ณต์‹ ๋ฌธ์„œ
โ€ข OpenZeppelin Docs - ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ ๋ณด์•ˆ
โ€ข Web3.py Documentation - ํŒŒ์ด์ฌ ๋ธ”๋ก์ฒด์ธ ๊ฐœ๋ฐœ

์˜จ๋ผ์ธ ์ฝ”์Šค
โ€ข Coursera - Blockchain Specialization
โ€ข Udemy - Ethereum and Solidity ์™„์ „ ์ •๋ณต
โ€ข CryptoZombies - ๊ฒŒ์ž„์œผ๋กœ ๋ฐฐ์šฐ๋Š” ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ

์ปค๋ฎค๋‹ˆํ‹ฐ
โ€ข Ethereum Stack Exchange
โ€ข Reddit r/ethdev
โ€ข Discord - Ethereum ๊ฐœ๋ฐœ์ž ์ฑ„๋„

์‹ค์ „ ํ”„๋กœ์ ํŠธ
โ€ข GitHub์—์„œ ์œ ๋ช… DeFi ํ”„๋กœ์ ํŠธ ์ฝ”๋“œ ๋ถ„์„
โ€ข ํ•ด์ปคํ†ค ์ฐธ์—ฌ (ETHGlobal ๋“ฑ)
โ€ข ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ ๊ธฐ์—ฌ
๊ทธ๋ฆฌ๊ณ  ๋งŒ์•ฝ ๋ธ”๋ก์ฒด์ธ ๊ฐœ๋ฐœ์ด๋‚˜ ํ† ํฐ ๊ฒฝ์ œ ์„ค๊ณ„์— ๋Œ€ํ•ด ๋” ๋ฐฐ์šฐ๊ณ  ์‹ถ๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท์—์„œ ์ „๋ฌธ๊ฐ€๋“ค์˜ ๋„์›€์„ ๋ฐ›์„ ์ˆ˜๋„ ์žˆ์–ด! ์‹ค์ œ ํ”„๋กœ์ ํŠธ ๊ฒฝํ—˜์ด ์žˆ๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด ๋ฉ˜ํ† ๋ง์„ ํ•ด์ฃผ๊ฑฐ๋“ . ๐ŸŽฏ

๋˜ํ•œ ๋„ค๊ฐ€ ์ด ๋ถ„์•ผ์—์„œ ์ „๋ฌธ์„ฑ์„ ์Œ“์•˜๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์„ ๋„์™€์ฃผ๋ฉด์„œ ์ˆ˜์ต๋„ ์ฐฝ์ถœํ•  ์ˆ˜ ์žˆ์–ด. ์ง€์‹์„ ๋‚˜๋ˆ„๋Š” ๊ฑด ์ •๋ง ๋ณด๋žŒ์ฐฌ ์ผ์ด์•ผ! ๐Ÿ’ช

๐ŸŽฏ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€! ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์ง€? ๐Ÿ˜… ์šฐ๋ฆฌ๊ฐ€ ์˜ค๋Š˜ ๋ฐฐ์šด ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณด์ž:

1. ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰ ์ œ์–ด์˜ ์ค‘์š”์„ฑ
ํ† ํฐ ๊ฒฝ์ œ์˜ ํ•ต์‹ฌ์ด๋ฉฐ, ํ”„๋กœ์ ํŠธ์˜ ์„ฑํŒจ๋ฅผ ์ขŒ์šฐํ•ด. ๐Ÿ’ฐ

2. ํŒŒ์ด์ฌ์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•
Web3.py๋ฅผ ํ™œ์šฉํ•ด์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ† ํฐ ์ƒํƒœ๋ฅผ ์ถ”์ ํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๐Ÿ“Š

3. ๊ณ ๊ธ‰ ์ œ์–ด ์ „๋žต
๋ฒ ์ŠคํŒ…, ์†Œ๊ฐ, ๋™์  ๋ฐธ๋Ÿฐ์‹ฑ ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๋ฐฐ์› ์–ด. ๐ŸŽฎ

4. ๋ณด์•ˆ์˜ ์ค‘์š”์„ฑ
๋ฉ€ํ‹ฐ์‹œ๊ทธ, ๊ฐ์‚ฌ ๋กœ๊ทธ, ์•”ํ˜ธํ™” ๋“ฑ ๋ณด์•ˆ์€ ์ ˆ๋Œ€ ํƒ€ํ˜‘ํ•  ์ˆ˜ ์—†์–ด. ๐Ÿ”

5. ์‹ค์ „ ์ ์šฉ ์‚ฌ๋ก€
DeFi์™€ ๊ฒŒ์ž„ ๋“ฑ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์–ด๋–ป๊ฒŒ ํ™œ์šฉ๋˜๋Š”์ง€ ์‚ดํŽด๋ดค์–ด. ๐Ÿš€

์ด์ œ ๋„ˆ๋„ ํ† ํฐ ๋ฐœํ–‰๋Ÿ‰์„ ์ œ์–ดํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด! ๋ฌผ๋ก  ์ฒ˜์Œ์—๋Š” ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ณ„์† ์—ฐ์Šตํ•˜๊ณ  ์‹คํ—˜ํ•˜๋‹ค ๋ณด๋ฉด ์ ์  ์ต์ˆ™ํ•ด์งˆ ๊ฑฐ์•ผ. ๐Ÿ’ช

๋ธ”๋ก์ฒด์ธ ์„ธ๊ณ„๋Š” ์ •๋ง ๋น ๋ฅด๊ฒŒ ๋ณ€ํ•˜๊ณ  ์žˆ์–ด. ๋งค์ผ ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๊ฐ€ ๋‚˜์˜ค๊ณ , ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ์ด ๊ฐœ๋ฐœ๋˜๊ณ  ์žˆ์ง€. ๊ทธ๋ž˜์„œ ๊ณ„์† ๋ฐฐ์šฐ๊ณ  ๋ฐœ์ „ํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ด! ๐Ÿ“š

ํ˜น์‹œ ์ด ๊ธ€์„ ์ฝ์œผ๋ฉด์„œ ๊ถ๊ธˆํ•œ ์ ์ด ์ƒ๊ธฐ๊ฑฐ๋‚˜, ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๋‹ค๊ฐ€ ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด, ๋ธ”๋ก์ฒด์ธ ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์งˆ๋ฌธํ•ด๋ด. ๋‹ค๋“ค ์นœ์ ˆํ•˜๊ฒŒ ๋„์™€์ค„ ๊ฑฐ์•ผ! ๐Ÿค

๊ทธ๋ฆฌ๊ณ  ๊ธฐ์–ตํ•ด! ํ† ํฐ ๊ฒฝ์ œ ์„ค๊ณ„๋Š” ๋‹จ์ˆœํžˆ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ ์ด์ƒ์ด์•ผ. ๊ฒฝ์ œํ•™, ๊ฒŒ์ž„ ์ด๋ก , ์‹ฌ๋ฆฌํ•™๊นŒ์ง€ ๋‹ค์–‘ํ•œ ๋ถ„์•ผ์˜ ์ง€์‹์ด ํ•„์š”ํ•ด. ๊ทธ๋ž˜์„œ ๋” ์žฌ๋ฏธ์žˆ๊ณ  ๋„์ „์ ์ด์ง€! ๐ŸŽฏ

์ž, ์ด์ œ ๋„ˆ๋งŒ์˜ ํ† ํฐ ๊ฒฝ์ œ๋ฅผ ์„ค๊ณ„ํ•ด๋ณผ ์‹œ๊ฐ„์ด์•ผ! ํ™”์ดํŒ…! ๐Ÿš€โœจ
Happy Coding! ๐Ÿš€ ํ† ํฐ ๊ฒฝ์ œ์˜ ์„ธ๊ณ„๋กœ ๋– ๋‚˜๋Š” ์—ฌ์ • ๐Ÿช™ ๐Ÿ’Ž ๐Ÿ”ฅ
๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.