{"file_path":"contracts/StablecoinBridge.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./interface/IERC20.sol\";\nimport \"./interface/IERC677Receiver.sol\";\nimport \"./interface/IFrankencoin.sol\";\n\n/**\n * @title Stable Coin Bridge\n * @notice A minting contract for another Swiss franc stablecoin ('source stablecoin') that we trust.\n * @author Frankencoin\n */\ncontract StablecoinBridge {\n    IERC20 public immutable chf; // the source stablecoin\n    IFrankencoin public immutable zchf; // the Frankencoin\n\n    /**\n     * @notice The time horizon after which this bridge expires and needs to be replaced by a new contract.\n     */\n    uint256 public immutable horizon;\n\n    /**\n     * The maximum amount of outstanding converted source stablecoins.\n     */\n    uint256 public immutable limit;\n    uint256 public minted;\n\n    error Limit(uint256 amount, uint256 limit);\n    error Expired(uint256 time, uint256 expiration);\n    error UnsupportedToken(address token);\n\n    constructor(address other, address zchfAddress, uint256 limit_) {\n        chf = IERC20(other);\n        zchf = IFrankencoin(zchfAddress);\n        horizon = block.timestamp + 52 weeks;\n        limit = limit_;\n        minted = 0;\n    }\n\n    /**\n     * @notice Convenience method for mint(msg.sender, amount)\n     */\n    function mint(uint256 amount) external {\n        mintTo(msg.sender, amount);\n    }\n\n    /**\n     * @notice Mint the target amount of Frankencoins, taking the equal amount of source coins from the sender.\n     * @dev This only works if an allowance for the source coins has been set and the caller has enough of them.\n     */\n    function mintTo(address target, uint256 amount) public {\n        chf.transferFrom(msg.sender, address(this), amount);\n        _mint(target, amount);\n    }\n\n    function _mint(address target, uint256 amount) internal {\n        if (block.timestamp > horizon) revert Expired(block.timestamp, horizon);\n        zchf.mint(target, amount);\n        minted += amount;\n        if (minted > limit) revert Limit(amount, limit);\n    }\n\n    /**\n     * @notice Convenience method for burnAndSend(msg.sender, amount)\n     */\n    function burn(uint256 amount) external {\n        _burn(msg.sender, msg.sender, amount);\n    }\n\n    /**\n     * @notice Burn the indicated amount of Frankencoin and send the same number of source coin to the caller.\n     */\n    function burnAndSend(address target, uint256 amount) external {\n        _burn(msg.sender, target, amount);\n    }\n\n    function _burn(address zchfHolder, address target, uint256 amount) internal {\n        zchf.burnFrom(zchfHolder, amount);\n        chf.transfer(target, amount);\n        minted -= amount;\n    }\n}\n","deployed_bytecode":"0x608060405234801561001057600080fd5b50600436106100935760003560e01c80634f02c420116100665780634f02c420146101395780639e41b44d14610142578063a0712d6814610155578063a4d66daf14610168578063c4d4803a1461018f57600080fd5b80631ce832b51461009857806337b272b0146100d257806342966c6814610111578063449a52f814610126575b600080fd5b6100bf7f00000000000000000000000000000000000000000000000000000000671d683f81565b6040519081526020015b60405180910390f35b6100f97f000000000000000000000000b4272071ecadd69d933adcd19ca99fe80664fc0881565b6040516001600160a01b0390911681526020016100c9565b61012461011f366004610522565b6101b6565b005b61012461013436600461053b565b6101c4565b6100bf60005481565b61012461015036600461053b565b61026a565b610124610163366004610522565b610275565b6100bf7f000000000000000000000000000000000000000000084595161401484a00000081565b6100f97f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb81565b6101c133338361027f565b50565b6040516323b872dd60e01b8152336004820152306024820152604481018290527f000000000000000000000000b4272071ecadd69d933adcd19ca99fe80664fc086001600160a01b0316906323b872dd906064016020604051808303816000875af1158015610237573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025b9190610573565b5061026682826103b0565b5050565b61026633838361027f565b6101c133826101c4565b60405163079cc67960e41b81526001600160a01b038481166004830152602482018390527f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb16906379cc679090604401600060405180830381600087803b1580156102e957600080fd5b505af11580156102fd573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018590527f000000000000000000000000b4272071ecadd69d933adcd19ca99fe80664fc0816925063a9059cbb91506044016020604051808303816000875af1158015610370573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103949190610573565b50806000808282546103a691906105b2565b9091555050505050565b7f00000000000000000000000000000000000000000000000000000000671d683f42111561041e5760405163aa2fd92560e01b81524260048201527f00000000000000000000000000000000000000000000000000000000671d683f60248201526044015b60405180910390fd5b6040516340c10f1960e01b81526001600160a01b038381166004830152602482018390527f000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb16906340c10f1990604401600060405180830381600087803b15801561048857600080fd5b505af115801561049c573d6000803e3d6000fd5b50505050806000808282546104b191906105cb565b90915550506000547f000000000000000000000000000000000000000000084595161401484a000000101561026657604051631927a4b960e21b8152600481018290527f000000000000000000000000000000000000000000084595161401484a0000006024820152604401610415565b60006020828403121561053457600080fd5b5035919050565b6000806040838503121561054e57600080fd5b82356001600160a01b038116811461056557600080fd5b946020939093013593505050565b60006020828403121561058557600080fd5b8151801515811461059557600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b818103818111156105c5576105c561059c565b92915050565b808201808211156105c5576105c561059c56fea26469706673582212200d23349045d49a02089d7b39302762f8a2d7ded4cba49045aa129e8f1f7fb75d64736f6c63430008140033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"paris","libraries":{},"metadata":{"bytecodeHash":"ipfs","useLiteralContent":true},"optimizer":{"enabled":true,"runs":200},"remappings":[]},"optimization_runs":200,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/partial_match/1/0x7bbe8F18040aF0032f4C2435E7a76db6F1E346DF/","decoded_constructor_args":[["0xB4272071eCAdd69d933AdcD19cA99fe80664fc08",{"internalType":"address","name":"other","type":"address"}],["0xB58E61C3098d85632Df34EecfB899A1Ed80921cB",{"internalType":"address","name":"zchfAddress","type":"address"}],["10000000000000000000000000",{"internalType":"uint256","name":"limit_","type":"uint256"}]],"compiler_version":"0.8.20+commit.a1b79de6","is_verified_via_verifier_alliance":false,"verified_at":"2024-08-02T20:13:15.991774Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x61010060405234801561001157600080fd5b506040516107643803806107648339810160408190526100309161007e565b6001600160a01b03808416608052821660a052610051426301dfe2006100ba565b60c05260e0525050600080556100e1565b80516001600160a01b038116811461007957600080fd5b919050565b60008060006060848603121561009357600080fd5b61009c84610062565b92506100aa60208501610062565b9150604084015190509250925092565b808201808211156100db57634e487b7160e01b600052601160045260246000fd5b92915050565b60805160a05160c05160e0516106146101506000396000818161016d015281816104bb01526104f6015260008181609d015281816103b201526103ed015260008181610194015281816102a5015261044401526000818160d7015281816101e6015261032501526106146000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c80634f02c420116100665780634f02c420146101395780639e41b44d14610142578063a0712d6814610155578063a4d66daf14610168578063c4d4803a1461018f57600080fd5b80631ce832b51461009857806337b272b0146100d257806342966c6814610111578063449a52f814610126575b600080fd5b6100bf7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020015b60405180910390f35b6100f97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100c9565b61012461011f366004610522565b6101b6565b005b61012461013436600461053b565b6101c4565b6100bf60005481565b61012461015036600461053b565b61026a565b610124610163366004610522565b610275565b6100bf7f000000000000000000000000000000000000000000000000000000000000000081565b6100f97f000000000000000000000000000000000000000000000000000000000000000081565b6101c133338361027f565b50565b6040516323b872dd60e01b8152336004820152306024820152604481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd906064016020604051808303816000875af1158015610237573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025b9190610573565b5061026682826103b0565b5050565b61026633838361027f565b6101c133826101c4565b60405163079cc67960e41b81526001600160a01b038481166004830152602482018390527f000000000000000000000000000000000000000000000000000000000000000016906379cc679090604401600060405180830381600087803b1580156102e957600080fd5b505af11580156102fd573d6000803e3d6000fd5b505060405163a9059cbb60e01b81526001600160a01b038581166004830152602482018590527f000000000000000000000000000000000000000000000000000000000000000016925063a9059cbb91506044016020604051808303816000875af1158015610370573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103949190610573565b50806000808282546103a691906105b2565b9091555050505050565b7f000000000000000000000000000000000000000000000000000000000000000042111561041e5760405163aa2fd92560e01b81524260048201527f000000000000000000000000000000000000000000000000000000000000000060248201526044015b60405180910390fd5b6040516340c10f1960e01b81526001600160a01b038381166004830152602482018390527f000000000000000000000000000000000000000000000000000000000000000016906340c10f1990604401600060405180830381600087803b15801561048857600080fd5b505af115801561049c573d6000803e3d6000fd5b50505050806000808282546104b191906105cb565b90915550506000547f0000000000000000000000000000000000000000000000000000000000000000101561026657604051631927a4b960e21b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006024820152604401610415565b60006020828403121561053457600080fd5b5035919050565b6000806040838503121561054e57600080fd5b82356001600160a01b038116811461056557600080fd5b946020939093013593505050565b60006020828403121561058557600080fd5b8151801515811461059557600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b818103818111156105c5576105c561059c565b92915050565b808201808211156105c5576105c561059c56fea26469706673582212200d23349045d49a02089d7b39302762f8a2d7ded4cba49045aa129e8f1f7fb75d64736f6c63430008140033000000000000000000000000b4272071ecadd69d933adcd19ca99fe80664fc08000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb000000000000000000000000000000000000000000084595161401484a000000","name":"StablecoinBridge","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"paris","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"file_path":"contracts/interface/IERC20.sol","source_code":"/**\n * SPDX-License-Identifier: MIT\n *\n * Copyright (c) 2016-2019 zOS Global Limited\n *\n */\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see `ERC20Detailed`.\n */\n\ninterface IERC20 {\n    function name() external view returns (string memory);\n\n    function symbol() external view returns (string memory);\n\n    function decimals() external view returns (uint8);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns always true. Throws error on failure.\n     *\n     * Emits a `Transfer` event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through `transferFrom`. This is\n     * zero by default.\n     *\n     * This value can change when `approve` or `transferFrom` are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * > Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an `Approval` event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns always true. Throws error on failure.\n     *\n     * Emits a `Transfer` event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to `approve`. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},{"file_path":"contracts/interface/IERC677Receiver.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IERC677Receiver {\n    \n    function onTokenTransfer(address from, uint256 amount, bytes calldata data) external returns (bool);\n\n}"},{"file_path":"contracts/interface/IFrankencoin.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\nimport \"./IReserve.sol\";\n\ninterface IFrankencoin is IERC20 {\n    function suggestMinter(address _minter, uint256 _applicationPeriod, uint256 _applicationFee, string calldata _message) external;\n\n    function registerPosition(address position) external;\n\n    function denyMinter(address minter, address[] calldata helpers, string calldata message) external;\n\n    function reserve() external view returns (IReserve);\n\n    function minterReserve() external view returns (uint256);\n\n    function calculateAssignedReserve(uint256 mintedAmount, uint32 _reservePPM) external view returns (uint256);\n\n    function equity() external view returns (uint256);\n\n    function isMinter(address minter) external view returns (bool);\n\n    function getPositionParent(address position) external view returns (address);\n\n    function mint(address target, uint256 amount) external;\n\n    function mintWithReserve(address target, uint256 amount, uint32 reservePPM, uint32 feePPM) external;\n\n    function burnFrom(address target, uint256 amount) external;\n\n    function burnWithoutReserve(uint256 amountIncludingReserve, uint32 reservePPM) external;\n\n    function burnFromWithReserve(address payer, uint256 targetTotalBurnAmount, uint32 _reservePPM) external returns (uint256);\n\n    function burnWithReserve(uint256 amountExcludingReserve, uint32 reservePPM) external returns (uint256);\n\n    function coverLoss(address source, uint256 amount) external;\n\n    function collectProfits(address source, uint256 _amount) external;\n}\n"},{"file_path":"contracts/interface/IReserve.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./IERC20.sol\";\n\ninterface IReserve is IERC20 {\n   function invest(uint256 amount, uint256 expected) external returns (uint256);\n   function checkQualified(address sender, address[] calldata helpers) external view;\n}"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"other","type":"address"},{"internalType":"address","name":"zchfAddress","type":"address"},{"internalType":"uint256","name":"limit_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"time","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"}],"name":"Expired","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"Limit","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"UnsupportedToken","type":"error"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnAndSend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chf","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"horizon","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mintTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"zchf","outputs":[{"internalType":"contract IFrankencoin","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"000000000000000000000000b4272071ecadd69d933adcd19ca99fe80664fc08000000000000000000000000b58e61c3098d85632df34eecfb899a1ed80921cb000000000000000000000000000000000000000000084595161401484a000000"}