diff --git a/test/iBTC_NetworkMiddleware.t.sol b/test/iBTC_NetworkMiddleware.t.sol index 010078f..8e36d3f 100644 --- a/test/iBTC_NetworkMiddleware.t.sol +++ b/test/iBTC_NetworkMiddleware.t.sol @@ -18,6 +18,7 @@ import {IVetoSlasher} from "core/src/interfaces/slasher/IVetoSlasher.sol"; import {IBaseSlasher} from "core/src/interfaces/slasher/IBaseSlasher.sol"; import {IVaultConfigurator} from "core/src/interfaces/IVaultConfigurator.sol"; import {IRegistry} from "core/src/interfaces/common/IRegistry.sol"; +import {IBTC} from "test/mocks/iBTCMock.sol"; contract iBTC_NetworkMiddlewareTest is Test { uint256 sepoliaFork; @@ -133,7 +134,6 @@ contract iBTC_NetworkMiddlewareTest is Test { iBTC_Vault(vault_).renounceRole(iBTC_Vault(vault_).DEFAULT_ADMIN_ROLE(), deployer); } vm.stopPrank(); - network_optIn_service = OptInService(NEWTORK_OPTIN_SERVICE); vault_optIn_service = OptInService(VAULT_OPTIN_SERVICE); //NOTICE @@ -182,7 +182,8 @@ contract iBTC_NetworkMiddlewareTest is Test { assertTrue(enabledTime > 0, "Enabled time should be greater than 0"); assertTrue(disabledTime == 0, "Disabled time should be 0"); - + console.log("enabledTime", enabledTime); + console.log("disabledTime"); vm.stopPrank(); } @@ -235,26 +236,50 @@ contract iBTC_NetworkMiddlewareTest is Test { } function testSlashOperator() public { + uint256 initialStaking = 1e10; testRegisterOperator(); address operator = address(0x1234); + + vm.prank(IBTC(COLLATTERAL).owner()); + IBTC(COLLATTERAL).setMinter(address(this)); + + IBTC(COLLATTERAL).mint(operator, initialStaking); + + uint256 operatorBalance = IBTC(COLLATTERAL).balanceOf(operator); + assertEq(operatorBalance, initialStaking, "Operator should have minted tokens"); + + vm.prank(operator); + IBTC(COLLATTERAL).approve(vaults[0], initialStaking); + vm.startPrank(OWNER); + iBTC_middleware.registerVault(vaults[0]); + // iBTC_Vault(vaults[0]).setDelegator(); // + vm.stopPrank(); uint48 epoch = iBTC_middleware.getCurrentEpoch(); - vm.startPrank(address(iBTC_middleware)); - // NOTE figure out how to stake some into it. + vm.prank(operator); + iBTC_Vault(vaults[0]).deposit(operator, initialStaking); + + assertEq( + initialStaking, + iBTC_Vault(vaults[0]).activeBalanceOfAt(operator, uint48(block.timestamp), ""), + "Initial staking should be done" + ); + + vm.prank(address(iBTC_middleware)); iBTC_middleware.calcAndCacheStakes(epoch); - vm.stopPrank(); uint256 cachedStake = iBTC_middleware.operatorStakeCache(epoch, operator); - assertEq(cachedStake, 0, "Cached stake should match the initial stake"); + assertEq(cachedStake, initialStaking, "Cached stake should match the initial stake"); uint256 slashAmount = 100; - vm.expectRevert(); + + vm.startPrank(OWNER); iBTC_middleware.slash(epoch, operator, slashAmount); - // uint256 updatedStake = iBTC_middleware.getOperatorStake(operator, epoch); - // assertEq(updatedStake, initialStake - slashAmount, "Stake should be reduced by slashed amount"); + cachedStake = iBTC_middleware.operatorStakeCache(epoch, operator); + assertEq(cachedStake, initialStaking - slashAmount, "Cached stake should be reduced by slash amount"); vm.stopPrank(); } diff --git a/test/mocks/iBTCMock.sol b/test/mocks/iBTCMock.sol new file mode 100644 index 0000000..4e51fb3 --- /dev/null +++ b/test/mocks/iBTCMock.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +// ___ __ ___ __ _ _ +// / \/ / / __\ / /(_)_ __ | | __ +// / /\ / / / / / / | | '_ \| |/ / +// / /_// /__/ /____/ /__| | | | | < +// /___,'\____|____(_)____/_|_| |_|_|\_\ + +pragma solidity 0.8.25; + +import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; + +/** + * @author DLC.Link 2024 + * @title iBTC + * @notice The iBTC Token represents Bitcoin locked in self-custody by the DLC.Link protocol. + * @dev Owner is the DLCManager contract + * @dev Minter/Burner rights are given to CCIP token pools + * @custom:contact eng@dlc.link + * @custom:website https://www.dlc.link + */ +contract IBTC is Initializable, ERC20Upgradeable, ERC20PermitUpgradeable, OwnableUpgradeable { + mapping(address => bool) public blacklisted; // deprecated. there is no blacklisting anymore + address private _minter; + address private _burner; + uint256[48] __gap; + + error NotAuthorized(); + + event MinterSet(address minter); + event BurnerSet(address burner); + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize() public initializer { + __ERC20_init("iBTC", "IBTC"); + __Ownable_init(msg.sender); + __ERC20Permit_init("iBTC"); + } + + function reinitializeEIP712() public reinitializer(2) { + // Reinitialize EIP712 with new name + __EIP712_init_unchained("iBTC", "1"); + } + + modifier onlyOwnerOrCCIPMinter() { + if (msg.sender != _minter && msg.sender != owner()) { + revert NotAuthorized(); + } + _; + } + + modifier onlyCCIPBurner() { + if (msg.sender != _burner) revert NotAuthorized(); + _; + } + + // Representing Satoshis + function decimals() public view virtual override returns (uint8) { + return 8; + } + + function name() public view virtual override returns (string memory) { + return "iBTC"; + } + + function symbol() public view virtual override returns (string memory) { + return "IBTC"; + } + + function mint(address to, uint256 amount) external onlyOwnerOrCCIPMinter { + _mint(to, amount); + } + + function burn(address from, uint256 amount) external onlyOwner { + _burn(from, amount); + } + + function burn( + uint256 amount + ) external onlyCCIPBurner { + _burn(msg.sender, amount); + } + + function setMinter( + address minter + ) external onlyOwner { + _minter = minter; + emit MinterSet(minter); + } + + function setBurner( + address burner + ) external onlyOwner { + _burner = burner; + emit BurnerSet(burner); + } +}