-
Notifications
You must be signed in to change notification settings - Fork 4
Implement tBTC Bridge fees reimbursement #942
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
72b5571
Implement tBTC Bridge fees reimbursement
nkuba ba3b5be
Remove default initialization of bridgeFeesReimbursementThreshold
nkuba 831ef55
Update BitcoinDepositorV2 contract for tests
nkuba e856fa2
Add function to update fees reimbursement pool address
nkuba a388a24
Unit tests for BitcoinDepositor setters
nkuba 4a04eb2
Update amount to be inclusive of the threshold amount
nkuba 4ff4d53
Check if the fees reimbursement pool is set before calling
nkuba f48a7c8
Add deployment scripts for the fees reimbursement pool
nkuba 63fabf3
Add unit tests for the fees reimbursement pool
nkuba 3b12709
Return FeesReimbursementPool reference from the deployment fixture
pdyraga 9795ebb
Emit events from FeesReimbursementPool
pdyraga 4cb4b6f
Unit tests for FeesReimbursementPool
pdyraga d2b275a
Check for zero-address params when initializing FeesReimbursementPool
pdyraga d4d2453
Fixed typo in deployment step 51 name
pdyraga 5bca04d
Updated network-based skip rules for FeesReimbursementPool configuration
pdyraga a0f0a61
Add check to test function return value
nkuba 04addd0
Minimum -> Maximum
nkuba fbd1f52
Emit event before storage update
nkuba 819fe69
Upgrade hardhat to 2.24.3
nkuba File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// SPDX-License-Identifier: GPL-3.0-only | ||
pragma solidity 0.8.24; | ||
|
||
import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; | ||
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
|
||
/// @title Fees Reimbursement Pool | ||
/// @notice A contract that allows the Bitcoin Depositor to reimburse fees | ||
/// for deposits. | ||
contract FeesReimbursementPool is Ownable2StepUpgradeable { | ||
using SafeERC20 for IERC20; | ||
|
||
address public tbtcToken; | ||
address public bitcoinDepositor; | ||
|
||
/// @dev Reverts if the tBTC Token address is zero. | ||
error TbtcTokenZeroAddress(); | ||
|
||
/// @dev Reverts if the BitcoinDepositor address is zero. | ||
error BitcoinDepositorZeroAddress(); | ||
|
||
/// @dev Caller is not the Bitcoin Depositor contract. | ||
error CallerNotBitcoinDepositor(); | ||
|
||
/// @dev Attempted to reimburse zero amount. | ||
error ZeroAmount(); | ||
|
||
/// @dev Emitted when the amount is reimbursed. | ||
event Reimbursed(uint256 amount); | ||
|
||
/// @dev Emitted when the given amount is withdrawn by the governance. | ||
event Withdrawn(address indexed recipient, uint256 amount); | ||
|
||
/// @custom:oz-upgrades-unsafe-allow constructor | ||
constructor() { | ||
_disableInitializers(); | ||
} | ||
|
||
/// @notice Initialize the fees reimbursement pool. | ||
/// @param _tbtcToken The tBTC token address. | ||
/// @param _bitcoinDepositor The bitcoin depositor address. | ||
function initialize( | ||
address _tbtcToken, | ||
address _bitcoinDepositor | ||
) external initializer { | ||
if (_tbtcToken == address(0)) { | ||
revert TbtcTokenZeroAddress(); | ||
} | ||
if (_bitcoinDepositor == address(0)) { | ||
revert BitcoinDepositorZeroAddress(); | ||
} | ||
|
||
__Ownable2Step_init(); | ||
pdyraga marked this conversation as resolved.
Show resolved
Hide resolved
|
||
__Ownable_init(msg.sender); | ||
|
||
tbtcToken = _tbtcToken; | ||
bitcoinDepositor = _bitcoinDepositor; | ||
} | ||
|
||
/// @notice Reimburse the fees. | ||
/// @param reimbursedAmount The amount to reimburse. | ||
/// @return The amount reimbursed. | ||
function reimburse(uint256 reimbursedAmount) external returns (uint256) { | ||
if (msg.sender != bitcoinDepositor) revert CallerNotBitcoinDepositor(); | ||
if (reimbursedAmount == 0) revert ZeroAmount(); | ||
|
||
uint256 availableBalance = IERC20(tbtcToken).balanceOf(address(this)); | ||
|
||
if (availableBalance < reimbursedAmount) { | ||
reimbursedAmount = availableBalance; | ||
} | ||
|
||
emit Reimbursed(reimbursedAmount); | ||
|
||
if (reimbursedAmount > 0) { | ||
IERC20(tbtcToken).safeTransfer(msg.sender, reimbursedAmount); | ||
} | ||
|
||
return reimbursedAmount; | ||
} | ||
|
||
/// @notice Withdraw the tokens from the pool. | ||
/// @param to The address to withdraw to. | ||
/// @param amount The amount to withdraw. | ||
function withdraw(address to, uint256 amount) external onlyOwner { | ||
emit Withdrawn(to, amount); | ||
IERC20(tbtcToken).safeTransfer(to, amount); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import type { DeployFunction } from "hardhat-deploy/types" | ||
import type { HardhatRuntimeEnvironment } from "hardhat/types" | ||
import { waitForTransaction } from "../helpers/deployment" | ||
|
||
const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { | ||
const { deployments, helpers, getNamedAccounts } = hre | ||
const { governance } = await getNamedAccounts() | ||
const { deployer } = await helpers.signers.getNamedSigners() | ||
const { log } = deployments | ||
|
||
const tbtcToken = await deployments.get("TBTC") | ||
const bitcoinDepositor = await deployments.get("BitcoinDepositor") | ||
|
||
let deployment = await deployments.getOrNull("FeesReimbursementPool") | ||
if (deployment && helpers.address.isValid(deployment.address)) { | ||
log(`using FeesReimbursementPool at ${deployment.address}`) | ||
} else { | ||
;[, deployment] = await helpers.upgrades.deployProxy( | ||
"FeesReimbursementPool", | ||
{ | ||
contractName: "FeesReimbursementPool", | ||
initializerArgs: [tbtcToken.address, bitcoinDepositor.address], | ||
factoryOpts: { signer: deployer }, | ||
proxyOpts: { | ||
kind: "transparent", | ||
initialOwner: governance, | ||
}, | ||
}, | ||
) | ||
|
||
if (deployment.transactionHash && hre.network.tags.etherscan) { | ||
await waitForTransaction(hre, deployment.transactionHash) | ||
await helpers.etherscan.verify(deployment) | ||
} | ||
|
||
// TODO: Add Tenderly verification | ||
} | ||
} | ||
|
||
export default func | ||
|
||
func.tags = ["FeesReimbursementPool"] | ||
func.dependencies = ["BitcoinDepositor", "TBTC"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import type { DeployFunction } from "hardhat-deploy/types" | ||
import type { HardhatRuntimeEnvironment } from "hardhat/types" | ||
|
||
const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { | ||
const { deployments, getNamedAccounts } = hre | ||
|
||
const { deployer } = await getNamedAccounts() | ||
const { log } = deployments | ||
|
||
const feesReimbursementPool = await deployments.get("FeesReimbursementPool") | ||
|
||
log( | ||
`updating fees reimbursement pool of BitcoinDepositor to ${feesReimbursementPool.address}`, | ||
) | ||
|
||
await deployments.execute( | ||
"BitcoinDepositor", | ||
{ from: deployer, log: true, waitConfirmations: 1 }, | ||
"updateFeesReimbursementPool", | ||
feesReimbursementPool.address, | ||
) | ||
} | ||
|
||
export default func | ||
|
||
func.tags = ["UpdateFeesReimbursementPool"] | ||
func.dependencies = ["BitcoinDepositor", "FeesReimbursementPool"] | ||
|
||
// Run only on Hardhat network. On all other networks this function needs to be | ||
// called by the governance. | ||
func.skip = async (hre: HardhatRuntimeEnvironment): Promise<boolean> => | ||
Promise.resolve(hre.network.name !== "hardhat") |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.