{"file_path":"src/tokenAuthority/tokenHandler/ReserveLedgerBackedHandler.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport { ReserveStore } from \"../../reserveStore/ReserveStore.sol\";\nimport { IERC20Mintable } from \"../../utils/IERC20Mintable.sol\";\nimport { IWrappedERC20 } from \"../../utils/IWrappedERC20.sol\";\nimport { TokenHandler } from \"./TokenHandler.sol\";\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport { SafeERC20 } from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\n/// @title ReserveLedgerBackedHandler\n/// @author Bridge\n/// @notice Token handler for stablecoins backed by reserve ledger tokens held in separate reserve\n/// stores\n/// @dev Each stablecoin has its own ReserveStore contract that holds the collateral\ncontract ReserveLedgerBackedHandler is TokenHandler {\n\n    using SafeERC20 for IERC20;\n    using SafeERC20 for IERC20Mintable;\n\n    /// @notice The address of the reserve ledger token used as collateral\n    address public immutable RESERVE_LEDGER_TOKEN;\n\n    /// @notice Mapping from stablecoin contract address to its reserve store address\n    mapping(address stablecoinContract => address reserveStore) public reserveStores;\n\n    /// @notice Thrown when attempting to burn or unwrap from a stablecoin with no reserve store\n    error ReserveStoreNotFound();\n\n    /// @notice Initializes the handler with the reserve ledger token and token authority\n    /// @param _reserveLedgerToken The address of the reserve ledger token\n    /// @param _tokenAuthority The address of the token authority\n    constructor(address _reserveLedgerToken, address _tokenAuthority)\n        TokenHandler(_tokenAuthority)\n    {\n        require(_reserveLedgerToken != address(0), ZeroAddress());\n        RESERVE_LEDGER_TOKEN = _reserveLedgerToken;\n    }\n\n    /**\n     * @notice Mints reserve ledger tokens to a reserve store and mints stablecoins to the recipient\n     * @dev Creates a new ReserveStore if one doesn't exist for the stablecoin\n     * @param stablecoinContract The address of the stablecoin contract\n     * @param to The address to receive the minted stablecoins\n     * @param amount The amount of tokens to mint\n     */\n    function mint(address stablecoinContract, address to, uint256 amount)\n        external\n        onlyTokenAuthority\n    {\n        require(to != address(0), ZeroAddress());\n        IERC20Mintable(RESERVE_LEDGER_TOKEN).mint(address(this), amount);\n        address reserveStore = reserveStores[stablecoinContract];\n        if (reserveStore == address(0)) {\n            reserveStore =\n                address(new ReserveStore(RESERVE_LEDGER_TOKEN, address(this), stablecoinContract));\n            reserveStores[stablecoinContract] = reserveStore;\n        }\n        IERC20(RESERVE_LEDGER_TOKEN).safeTransfer(reserveStore, amount);\n        IERC20Mintable(stablecoinContract).mint(to, amount);\n        emit Minted(stablecoinContract, to, amount);\n    }\n\n    /**\n     * @notice Burns stablecoins and the corresponding reserve ledger tokens from the reserve store\n     * @param stablecoinContract The address of the stablecoin contract\n     * @param amount The amount of stablecoins to burn\n     */\n    function burn(address stablecoinContract, uint256 amount) external onlyTokenAuthority {\n        address reserveStore = reserveStores[stablecoinContract];\n        require(reserveStore != address(0), ReserveStoreNotFound());\n        IERC20(stablecoinContract).safeTransferFrom(msg.sender, address(this), amount);\n        IERC20Mintable(stablecoinContract).burn(amount);\n        IERC20(RESERVE_LEDGER_TOKEN).safeTransferFrom(reserveStore, address(this), amount);\n        IERC20Mintable(RESERVE_LEDGER_TOKEN).burn(amount);\n        emit Burned(stablecoinContract, amount);\n    }\n\n    /**\n     * @notice Wraps reserve ledger tokens into stablecoins by transferring to reserve store\n     * @dev Creates a new ReserveStore if one doesn't exist for the stablecoin\n     * @param stablecoinContract The address of the stablecoin contract\n     * @param to The address to receive the wrapped stablecoins\n     * @param amount The amount of reserve ledger tokens to wrap\n     */\n    function wrap(address stablecoinContract, address to, uint256 amount)\n        external\n        onlyTokenAuthority\n    {\n        require(to != address(0), ZeroAddress());\n        address reserveStore = reserveStores[stablecoinContract];\n        if (reserveStore == address(0)) {\n            reserveStore =\n                address(new ReserveStore(RESERVE_LEDGER_TOKEN, address(this), stablecoinContract));\n            reserveStores[stablecoinContract] = reserveStore;\n        }\n        IERC20(RESERVE_LEDGER_TOKEN).safeTransferFrom(msg.sender, reserveStore, amount);\n        IERC20Mintable(stablecoinContract).mint(to, amount);\n        emit Wrapped(stablecoinContract, to, amount);\n    }\n\n    /**\n     * @notice Unwraps stablecoins into reserve ledger tokens from the reserve store\n     * @param stablecoinContract The address of the stablecoin contract\n     * @param to The address to receive the reserve ledger tokens\n     * @param amount The amount of stablecoins to unwrap\n     */\n    function unwrap(address stablecoinContract, address to, uint256 amount)\n        external\n        onlyTokenAuthority\n    {\n        require(to != address(0), ZeroAddress());\n        address reserveStore = reserveStores[stablecoinContract];\n        require(reserveStore != address(0), ReserveStoreNotFound());\n        IERC20(stablecoinContract).safeTransferFrom(msg.sender, address(this), amount);\n        IERC20Mintable(stablecoinContract).burn(amount);\n        IERC20(RESERVE_LEDGER_TOKEN).safeTransferFrom(reserveStore, to, amount);\n        emit Unwrapped(stablecoinContract, to, amount);\n    }\n\n}\n","deployed_bytecode":"0x6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a7146108ef5750806317937488146108ab5780631f9b49bb1461086c5780632903980a14610828578063623556381461060a5780638cc7104f146104c85780639dc29fac146103315763c6c3bbe614610076575f80fd5b3461032e5761008436610958565b9091907f000000000000000000000000f37a982d1f6c9d1cc9d792aaba494264e0f315d76001600160a01b0316330361031f576001600160a01b038316928315610310577f00000000000000000000000000b65e1153a839570f38b506fd46f8a14540485a928591906001600160a01b038516803b15610220576040516340c10f1960e01b81523060048201526024810186905291848360448183865af1801561030557869386916102ea575b50506001600160a01b038181168087526020879052604087205490989116918215610233575b505060405163a9059cbb60e01b60208201526001600160a01b0391909116602482015260448082019390935291825261019b9190610196606483610992565b6109fa565b833b1561022f576040516340c10f1960e01b81526001600160a01b0391909116600482015260248101839052818160448183885af180156102245761020b575b505060207f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f091604051908152a380f35b8161021591610992565b61022057835f6101db565b8380fd5b6040513d84823e3d90fd5b5080fd5b60405195965092949350610299808501925067ffffffffffffffff8311858410176102d6579284939261028b928c98979694610a5386396001600160a01b039081168252306020830152909116604082015260600190565b039084f080156102cb5785845260208490526040842080546001600160a01b0319166001600160a01b03909216918217905584919061019661019b610157565b6040513d85823e3d90fd5b634e487b7160e01b8b52604160045260248bfd5b81929450906102f891610992565b610220578491845f610131565b6040513d87823e3d90fd5b63d92e233d60e01b8552600485fd5b63c3b2717360e01b8452600484fd5b80fd5b503461032e57604036600319011261032e5761034b610942565b602435907f000000000000000000000000f37a982d1f6c9d1cc9d792aaba494264e0f315d76001600160a01b031633036104b9576001600160a01b03908116808452602084905260408420549092911680156104aa5783906103af833033876109b4565b833b1561022f57604051630852cd8d60e31b815260048101849052828160248183895af19081156102cb578391610495575b50507f00000000000000000000000000b65e1153a839570f38b506fd46f8a14540485a6001600160a01b03169061041c9084903090846109b4565b803b1561022f57818091602460405180948193630852cd8d60e31b83528860048401525af180156102245761047c575b505060207f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df791604051908152a280f35b8161048691610992565b61049157825f61044c565b8280fd5b8161049f91610992565b61022f57815f6103e1565b63522954b560e01b8452600484fd5b63c3b2717360e01b8352600483fd5b503461032e576104d736610958565b907f000000000000000000000000f37a982d1f6c9d1cc9d792aaba494264e0f315d76001600160a01b0316330361031f576001600160a01b038116928315610310576001600160a01b03908116808652602086905260408620549093911680156105fb57610547823033876109b4565b833b156105f75785604051630852cd8d60e31b81528360048201528181602481838a5af18015610224576105de575b507f742cbb4a6bddd5e23aa0c14356065c236bdbc921cddb7f1f763161eb2030f3ef93602093926105d492508391907f00000000000000000000000000b65e1153a839570f38b506fd46f8a14540485a6001600160a01b03166109b4565b604051908152a380f35b816105eb91949394610992565b6105f75790855f610576565b8580fd5b63522954b560e01b8652600486fd5b50346107485761061936610958565b9091907f000000000000000000000000f37a982d1f6c9d1cc9d792aaba494264e0f315d76001600160a01b03163303610819576001600160a01b03831692831561080a576001600160a01b038381165f81815260208190526040902054909491849116801561074c575b6106b89250337f00000000000000000000000000b65e1153a839570f38b506fd46f8a14540485a6001600160a01b03166109b4565b823b15610748576040516340c10f1960e01b81526001600160a01b03919091166004820152602481018290525f8160448183875af1801561073d57610727575b5060207f29b3b451f9779df34ec8a67ec6c96fa910b17a579a66b7428d94f481be6900d991604051908152a380f35b6107349194505f90610992565b5f9260206106f8565b6040513d5f823e3d90fd5b5f80fd5b5050604051906102998083019183831067ffffffffffffffff8411176107f65783926107b892610a5385396001600160a01b037f00000000000000000000000000b65e1153a839570f38b506fd46f8a14540485a81168252306020830152909116604082015260600190565b03905ff0801561073d575f84815260208190526040902080546001600160a01b0319166001600160a01b0390921691821790556106b8908390610683565b634e487b7160e01b5f52604160045260245ffd5b63d92e233d60e01b5f5260045ffd5b63c3b2717360e01b5f5260045ffd5b34610748575f366003190112610748576040517f00000000000000000000000000b65e1153a839570f38b506fd46f8a14540485a6001600160a01b03168152602090f35b34610748576020366003190112610748576001600160a01b0361088d610942565b165f525f602052602060018060a01b0360405f205416604051908152f35b34610748575f366003190112610748576040517f000000000000000000000000f37a982d1f6c9d1cc9d792aaba494264e0f315d76001600160a01b03168152602090f35b34610748576020366003190112610748576004359063ffffffff60e01b82168092036107485760209163b5f3623d60e01b8114908115610931575b5015158152f35b6301ffc9a760e01b1490508361092a565b600435906001600160a01b038216820361074857565b6060906003190112610748576004356001600160a01b038116810361074857906024356001600160a01b0381168103610748579060443590565b90601f8019910116810190811067ffffffffffffffff8211176107f657604052565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526109f891610196608483610992565b565b905f602091828151910182855af11561073d575f513d610a4957506001600160a01b0381163b155b610a295750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415610a2256fe60e0806040523461011057606081610299803803809161001f8285610136565b833981010312610110576100328161016d565b9061004b60406100446020840161016d565b920161016d565b916001600160a01b03168015610127576001600160a01b038216928315610127576001600160a01b0316918215610127575f936020936044928460805260a05260c052604051948593849263095ea7b360e01b84526004840152811960248401525af1801561011c576100e0575b604051610117908161018282396080518160db015260a051816052015260c05181609a0152f35b6020813d602011610114575b816100f960209383610136565b81010312610110575180151503610110575f6100b9565b5f80fd5b3d91506100ec565b6040513d5f823e3d90fd5b63d92e233d60e01b5f5260045ffd5b601f909101601f19168101906001600160401b0382119082101761015957604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101105756fe6080806040526004361015610012575f80fd5b5f3560e01c90816304139656146100c95750806393a39776146100855763ee0fc1211461003d575f80fd5b34610081575f366003190112610081576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5f80fd5b34610081575f366003190112610081576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610081575f366003190112610081577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f3fea164736f6c634300081e000aa164736f6c634300081e000a","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"prague","libraries":{},"metadata":{"appendCBOR":true,"bytecodeHash":"none","useLiteralContent":false},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}},"remappings":["@openzeppelin-contracts-5.2.0/=dependencies/deterministic-proxy-factory-0.1.4/dependencies/@openzeppelin-contracts-5.2.0/","@openzeppelin-contracts-5.3.0/=dependencies/@openzeppelin-contracts-5.3.0/","@openzeppelin-contracts-upgradeable-5.2.0/=dependencies/deterministic-proxy-factory-0.1.4/dependencies/@openzeppelin-contracts-upgradeable-5.2.0/","@openzeppelin-contracts-upgradeable-5.3.0/=dependencies/@openzeppelin-contracts-upgradeable-5.3.0/","@openzeppelin-contracts-upgradeable/=dependencies/deterministic-proxy-factory-0.1.4/dependencies/@openzeppelin-contracts-upgradeable-5.2.0/","@openzeppelin-contracts/=dependencies/deterministic-proxy-factory-0.1.4/dependencies/@openzeppelin-contracts-5.2.0/src/","@openzeppelin/contracts-upgradeable/=dependencies/@openzeppelin-contracts-upgradeable-5.3.0/","@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.3.0/","auth-registry-1/=dependencies/auth-registry-1/","auth-registry/=dependencies/auth-registry-1/","create2-helpers-0.4.0/=dependencies/deterministic-proxy-factory-0.1.4/dependencies/create2-helpers-0.4.0/src/","create2-helpers-0.5.0/=dependencies/create2-helpers-0.5.0/","create2-helpers/=dependencies/create2-helpers-0.5.0/src/","deterministic-proxy-factory-0.1.4/=dependencies/deterministic-proxy-factory-0.1.4/","deterministic-proxy-factory/=dependencies/deterministic-proxy-factory-0.1.4/src/","forge-std-1.9.6/=dependencies/create2-helpers-0.5.0/dependencies/forge-std-1.9.6/","forge-std-1.9.7/=dependencies/forge-std-1.9.7/","forge-std/=dependencies/forge-std-1.9.7/src/","solady-0.1.12/=dependencies/deterministic-proxy-factory-0.1.4/dependencies/solady-0.1.12/src/","solady/=dependencies/deterministic-proxy-factory-0.1.4/dependencies/solady-0.1.12/src/","tempo-std-0.1.1/=dependencies/tempo-std-0.1.1/","tempo-std/=dependencies/tempo-std-0.1.1/src/","a16z-halmos-cheatcodes-0.1.0/=dependencies/auth-registry-1/dependencies/a16z-halmos-cheatcodes-0.1.0/","a16z-halmos-cheatcodes/=dependencies/auth-registry-1/dependencies/a16z-halmos-cheatcodes-0.1.0/src/","forge-std-1.9.8/=dependencies/auth-registry-1/dependencies/forge-std-1.9.8/"],"viaIR":true},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":[["0x00b65E1153a839570F38B506fd46F8A14540485a",{"internalType":"address","name":"_reserveLedgerToken","type":"address"}],["0xF37a982d1f6c9D1cC9d792aaba494264e0f315d7",{"internalType":"address","name":"_tokenAuthority","type":"address"}]],"compiler_version":"v0.8.30+commit.73712a01","is_verified_via_verifier_alliance":false,"verified_at":"2026-07-15T01:05:11.018736Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x60c0346100e357601f610e0838819003918201601f19168301916001600160401b038311848410176100e75780849260409485528339810103126100e357610052602061004b836100fb565b92016100fb565b6001600160a01b038116156100d4576080526001600160a01b038116156100d45760a052604051610cf890816101108239608051818181608901528181610351015281816104da0152818161061e01526108c0015260a05181818160ca015281816103e5015281816105a70152818161068b01528181610781015261083d0152f35b63d92e233d60e01b5f5260045ffd5b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036100e35756fe6080806040526004361015610012575f80fd5b5f905f3560e01c90816301ffc9a7146108ef5750806317937488146108ab5780631f9b49bb1461086c5780632903980a14610828578063623556381461060a5780638cc7104f146104c85780639dc29fac146103315763c6c3bbe614610076575f80fd5b3461032e5761008436610958565b9091907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361031f576001600160a01b038316928315610310577f0000000000000000000000000000000000000000000000000000000000000000928591906001600160a01b038516803b15610220576040516340c10f1960e01b81523060048201526024810186905291848360448183865af1801561030557869386916102ea575b50506001600160a01b038181168087526020879052604087205490989116918215610233575b505060405163a9059cbb60e01b60208201526001600160a01b0391909116602482015260448082019390935291825261019b9190610196606483610992565b6109fa565b833b1561022f576040516340c10f1960e01b81526001600160a01b0391909116600482015260248101839052818160448183885af180156102245761020b575b505060207f9d228d69b5fdb8d273a2336f8fb8612d039631024ea9bf09c424a9503aa078f091604051908152a380f35b8161021591610992565b61022057835f6101db565b8380fd5b6040513d84823e3d90fd5b5080fd5b60405195965092949350610299808501925067ffffffffffffffff8311858410176102d6579284939261028b928c98979694610a5386396001600160a01b039081168252306020830152909116604082015260600190565b039084f080156102cb5785845260208490526040842080546001600160a01b0319166001600160a01b03909216918217905584919061019661019b610157565b6040513d85823e3d90fd5b634e487b7160e01b8b52604160045260248bfd5b81929450906102f891610992565b610220578491845f610131565b6040513d87823e3d90fd5b63d92e233d60e01b8552600485fd5b63c3b2717360e01b8452600484fd5b80fd5b503461032e57604036600319011261032e5761034b610942565b602435907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633036104b9576001600160a01b03908116808452602084905260408420549092911680156104aa5783906103af833033876109b4565b833b1561022f57604051630852cd8d60e31b815260048101849052828160248183895af19081156102cb578391610495575b50507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169061041c9084903090846109b4565b803b1561022f57818091602460405180948193630852cd8d60e31b83528860048401525af180156102245761047c575b505060207f696de425f79f4a40bc6d2122ca50507f0efbeabbff86a84871b7196ab8ea8df791604051908152a280f35b8161048691610992565b61049157825f61044c565b8280fd5b8161049f91610992565b61022f57815f6103e1565b63522954b560e01b8452600484fd5b63c3b2717360e01b8352600483fd5b503461032e576104d736610958565b907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361031f576001600160a01b038116928315610310576001600160a01b03908116808652602086905260408620549093911680156105fb57610547823033876109b4565b833b156105f75785604051630852cd8d60e31b81528360048201528181602481838a5af18015610224576105de575b507f742cbb4a6bddd5e23aa0c14356065c236bdbc921cddb7f1f763161eb2030f3ef93602093926105d492508391907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166109b4565b604051908152a380f35b816105eb91949394610992565b6105f75790855f610576565b8580fd5b63522954b560e01b8652600486fd5b50346107485761061936610958565b9091907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303610819576001600160a01b03831692831561080a576001600160a01b038381165f81815260208190526040902054909491849116801561074c575b6106b89250337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166109b4565b823b15610748576040516340c10f1960e01b81526001600160a01b03919091166004820152602481018290525f8160448183875af1801561073d57610727575b5060207f29b3b451f9779df34ec8a67ec6c96fa910b17a579a66b7428d94f481be6900d991604051908152a380f35b6107349194505f90610992565b5f9260206106f8565b6040513d5f823e3d90fd5b5f80fd5b5050604051906102998083019183831067ffffffffffffffff8411176107f65783926107b892610a5385396001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081168252306020830152909116604082015260600190565b03905ff0801561073d575f84815260208190526040902080546001600160a01b0319166001600160a01b0390921691821790556106b8908390610683565b634e487b7160e01b5f52604160045260245ffd5b63d92e233d60e01b5f5260045ffd5b63c3b2717360e01b5f5260045ffd5b34610748575f366003190112610748576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610748576020366003190112610748576001600160a01b0361088d610942565b165f525f602052602060018060a01b0360405f205416604051908152f35b34610748575f366003190112610748576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610748576020366003190112610748576004359063ffffffff60e01b82168092036107485760209163b5f3623d60e01b8114908115610931575b5015158152f35b6301ffc9a760e01b1490508361092a565b600435906001600160a01b038216820361074857565b6060906003190112610748576004356001600160a01b038116810361074857906024356001600160a01b0381168103610748579060443590565b90601f8019910116810190811067ffffffffffffffff8211176107f657604052565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526109f891610196608483610992565b565b905f602091828151910182855af11561073d575f513d610a4957506001600160a01b0381163b155b610a295750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415610a2256fe60e0806040523461011057606081610299803803809161001f8285610136565b833981010312610110576100328161016d565b9061004b60406100446020840161016d565b920161016d565b916001600160a01b03168015610127576001600160a01b038216928315610127576001600160a01b0316918215610127575f936020936044928460805260a05260c052604051948593849263095ea7b360e01b84526004840152811960248401525af1801561011c576100e0575b604051610117908161018282396080518160db015260a051816052015260c05181609a0152f35b6020813d602011610114575b816100f960209383610136565b81010312610110575180151503610110575f6100b9565b5f80fd5b3d91506100ec565b6040513d5f823e3d90fd5b63d92e233d60e01b5f5260045ffd5b601f909101601f19168101906001600160401b0382119082101761015957604052565b634e487b7160e01b5f52604160045260245ffd5b51906001600160a01b03821682036101105756fe6080806040526004361015610012575f80fd5b5f3560e01c90816304139656146100c95750806393a39776146100855763ee0fc1211461003d575f80fd5b34610081575f366003190112610081576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5f80fd5b34610081575f366003190112610081576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b34610081575f366003190112610081577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f3fea164736f6c634300081e000aa164736f6c634300081e000a00000000000000000000000000b65e1153a839570f38b506fd46f8a14540485a000000000000000000000000f37a982d1f6c9d1cc9d792aaba494264e0f315d7","name":"ReserveLedgerBackedHandler","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"prague","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"dependencies/@openzeppelin-contracts-5.3.0/interfaces/IERC1363.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n    /*\n     * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n     * 0xb0202a11 ===\n     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n     */\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @param data Additional data with no specified format, sent in call to `spender`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.3.0/interfaces/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.3.0/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.3.0/token/ERC20/IERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\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    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) 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 changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: 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 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.3.0/token/ERC20/utils/SafeERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    /**\n     * @dev An operation with an ERC-20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     *\n     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n     * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n     * set here.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            safeTransfer(token, to, value);\n        } else if (!token.transferAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferFromAndCallRelaxed(\n        IERC1363 token,\n        address from,\n        address to,\n        uint256 value,\n        bytes memory data\n    ) internal {\n        if (to.code.length == 0) {\n            safeTransferFrom(token, from, to, value);\n        } else if (!token.transferFromAndCall(from, to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n     * once without retrying, and relies on the returned value to be true.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            forceApprove(token, to, value);\n        } else if (!token.approveAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            // bubble errors\n            if iszero(success) {\n                let ptr := mload(0x40)\n                returndatacopy(ptr, 0, returndatasize())\n                revert(ptr, returndatasize())\n            }\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n\n        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        bool success;\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.3.0/utils/introspection/ERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n    /**\n     * @dev See {IERC165-supportsInterface}.\n     */\n    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n        return interfaceId == type(IERC165).interfaceId;\n    }\n}\n"},{"file_path":"dependencies/@openzeppelin-contracts-5.3.0/utils/introspection/IERC165.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"},{"file_path":"src/reserveStore/ReserveStore.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @title ReserveStore\n/// @author Bridge\n/// @notice A minimal contract to hold reserve ledger tokens for a specific stablecoin\n/// @dev Deployed per stablecoin to keep ledger token reserves separate for reconciliation purposes.\n///      Pre-approves the controller to transfer tokens on its behalf.\ncontract ReserveStore {\n\n    /// @notice Error thrown when zero address is used\n    error ZeroAddress();\n\n    /// @notice The reserve ledger token\n    IERC20 public immutable RESERVE_LEDGER;\n\n    /// @notice The controller that can move tokens from this store\n    address public immutable CONTROLLER;\n\n    /// @notice The stablecoin this store backs\n    IERC20 public immutable STABLECOIN;\n\n    /// @param reserveLedger The reserve ledger token address\n    /// @param controller The controller contract address\n    /// @param stablecoin The stablecoin this store backs\n    constructor(address reserveLedger, address controller, address stablecoin) {\n        require(reserveLedger != address(0), ZeroAddress());\n        require(controller != address(0), ZeroAddress());\n        require(stablecoin != address(0), ZeroAddress());\n\n        RESERVE_LEDGER = IERC20(reserveLedger);\n        CONTROLLER = controller;\n        STABLECOIN = IERC20(stablecoin);\n\n        RESERVE_LEDGER.approve(controller, type(uint256).max);\n    }\n\n}\n"},{"file_path":"src/tokenAuthority/tokenHandler/ITokenHandler.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport { IERC165 } from \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\n\n/// @title ITokenHandler\n/// @author Bridge\n/// @notice Interface for token handlers that manage minting, burning, wrapping, and unwrapping of\n/// tokens\n/// @dev Token handlers are called by TokenAuthority to execute token operations\ninterface ITokenHandler is IERC165 {\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    Errors\n    //////////////////////////////////////////////////////////////////////////*/\n\n    /// @notice Thrown when the caller is not the token authority\n    error OnlyTokenAuthority();\n\n    /// @notice Thrown when the address is the zero address\n    error ZeroAddress();\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    Events\n    //////////////////////////////////////////////////////////////////////////*/\n\n    /// @notice Emitted when tokens are minted\n    /// @param stablecoinContract The address of the stablecoin contract\n    /// @param to The address receiving the minted tokens\n    /// @param amount The amount of tokens minted\n    event Minted(address indexed stablecoinContract, address indexed to, uint256 amount);\n\n    /// @notice Emitted when tokens are burned\n    /// @param stablecoinContract The address of the stablecoin contract\n    /// @param amount The amount of tokens burned\n    event Burned(address indexed stablecoinContract, uint256 amount);\n\n    /// @notice Emitted when reserve ledger tokens are wrapped into stablecoins\n    /// @param stablecoinContract The address of the stablecoin contract\n    /// @param to The address receiving the wrapped tokens\n    /// @param amount The amount of tokens wrapped\n    event Wrapped(address indexed stablecoinContract, address indexed to, uint256 amount);\n\n    /// @notice Emitted when stablecoins are unwrapped into reserve ledger tokens\n    /// @param stablecoinContract The address of the stablecoin contract\n    /// @param to The address receiving the unwrapped tokens\n    /// @param amount The amount of tokens unwrapped\n    event Unwrapped(address indexed stablecoinContract, address indexed to, uint256 amount);\n\n    /*//////////////////////////////////////////////////////////////////////////\n                                    Functions\n    //////////////////////////////////////////////////////////////////////////*/\n\n    /**\n     * @notice Mints tokens to a specified address\n     * @param stablecoinContract The address of the stablecoin contract\n     * @param to The address to mint the tokens to\n     * @param amount The amount of tokens to mint\n     */\n    function mint(address stablecoinContract, address to, uint256 amount) external;\n\n    /**\n     * @notice Burns tokens from a specified address\n     * @param stablecoinContract The address of the stablecoin contract\n     * @param amount The amount of tokens to burn\n     */\n    function burn(address stablecoinContract, uint256 amount) external;\n\n    /**\n     * @notice Wraps reserve ledger tokens into stablecoins\n     * @param stablecoinContract The address of the stablecoin contract\n     * @param to The address to receive the wrapped stablecoins\n     * @param amount The amount of tokens to wrap\n     */\n    function wrap(address stablecoinContract, address to, uint256 amount) external;\n\n    /**\n     * @notice Unwraps stablecoins into reserve ledger tokens\n     * @param stablecoinContract The address of the stablecoin contract\n     * @param to The address to receive the unwrapped reserve ledger tokens\n     * @param amount The amount of tokens to unwrap\n     */\n    function unwrap(address stablecoinContract, address to, uint256 amount) external;\n\n}\n"},{"file_path":"src/tokenAuthority/tokenHandler/TokenHandler.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport { ITokenHandler } from \"./ITokenHandler.sol\";\nimport { ERC165, IERC165 } from \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\n\n/// @title TokenHandler\n/// @author Bridge\n/// @notice Abstract base contract for token handlers that restricts access to the token authority\n/// @dev Implements access control modifier for token authority and stores the authority address\nabstract contract TokenHandler is ITokenHandler, ERC165 {\n\n    /// @notice The address of the token authority that can call handler functions\n    address public immutable TOKEN_AUTHORITY;\n\n    /// @notice Restricts function access to the token authority\n    modifier onlyTokenAuthority() {\n        require(msg.sender == TOKEN_AUTHORITY, OnlyTokenAuthority());\n        _;\n    }\n\n    /// @notice Initializes the token handler with the token authority address\n    /// @param _tokenAuthority The address of the token authority\n    constructor(address _tokenAuthority) {\n        require(_tokenAuthority != address(0), ZeroAddress());\n        TOKEN_AUTHORITY = _tokenAuthority;\n    }\n\n    /// @notice Returns true if the contract implements the given interface\n    /// @param interfaceId The interface identifier to check\n    /// @return True if the contract implements the interface, false otherwise\n    function supportsInterface(bytes4 interfaceId)\n        public\n        view\n        override(ERC165, IERC165)\n        returns (bool)\n    {\n        return interfaceId == type(ITokenHandler).interfaceId\n            || super.supportsInterface(interfaceId);\n    }\n\n}\n"},{"file_path":"src/utils/IERC20Mintable.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @title IERC20Mintable\n/// @author Bridge\n/// @notice Interface for ERC20 tokens with mint and burn functionality\n/// @dev Extends the standard ERC20 interface with controlled token supply management\ninterface IERC20Mintable is IERC20 {\n\n    /// @notice Burns tokens from the caller's balance\n    /// @dev Reduces the total supply by destroying tokens\n    /// @param amount The amount of tokens to burn\n    function burn(uint256 amount) external;\n\n    /// @notice Mints new tokens to a specified address\n    /// @dev Increases the total supply by creating new tokens\n    /// @param to The address that will receive the newly minted tokens\n    /// @param amount The amount of tokens to mint\n    function mint(address to, uint256 amount) external;\n\n}\n"},{"file_path":"src/utils/IWrappedERC20.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.20;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/// @title IWrappedERC20\n/// @author Bridge\n/// @notice Interface for ERC20 tokens that support wrapping and unwrapping functionality\n/// @dev Extends the standard ERC20 interface to enable conversion between wrapped and underlying\n/// tokens\ninterface IWrappedERC20 is IERC20 {\n\n    /// @notice Wraps underlying tokens into wrapped tokens\n    /// @dev Transfers underlying tokens from the caller and mints wrapped tokens to the specified\n    /// address\n    /// @param to The address that will receive the wrapped tokens\n    /// @param amount The amount of underlying tokens to wrap\n    function wrap(address to, uint256 amount) external;\n\n    /// @notice Unwraps a specified amount of wrapped tokens held by the caller\n    /// @dev Burns the caller's wrapped token balance and transfers underlying tokens to the caller\n    /// @param amount The amount of wrapped tokens to unwrap\n    function unwrap(uint256 amount) external;\n\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"address","name":"_reserveLedgerToken","type":"address"},{"internalType":"address","name":"_tokenAuthority","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"OnlyTokenAuthority","type":"error"},{"inputs":[],"name":"ReserveStoreNotFound","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stablecoinContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stablecoinContract","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stablecoinContract","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unwrapped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stablecoinContract","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Wrapped","type":"event"},{"inputs":[],"name":"RESERVE_LEDGER_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_AUTHORITY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinContract","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinContract","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinContract","type":"address"}],"name":"reserveStores","outputs":[{"internalType":"address","name":"reserveStore","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinContract","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unwrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinContract","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wrap","outputs":[],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"00000000000000000000000000b65e1153a839570f38b506fd46f8a14540485a000000000000000000000000f37a982d1f6c9d1cc9d792aaba494264e0f315d7"}