Skip to content

Commit

Permalink
Update BitcoinDepositor upgrade test contract
Browse files Browse the repository at this point in the history
  • Loading branch information
nkuba committed Apr 9, 2024
1 parent f5b6d27 commit 3116317
Showing 1 changed file with 85 additions and 89 deletions.
174 changes: 85 additions & 89 deletions core/contracts/test/upgrades/BitcoinDepositorV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,37 @@ import {stBTC} from "../../stBTC.sol";
contract BitcoinDepositorV2 is AbstractTBTCDepositor, Ownable2StepUpgradeable {
using SafeERC20 for IERC20;

/// @notice State of the stake request.
enum StakeRequestState {
/// @notice Reflects the deposit state:
/// - Unknown deposit has not been initialized yet.
/// - Initialized deposit has been initialized with a call to
/// `initializeDeposit` function and is known to this contract.
/// - Finalized deposit led to tBTC ERC20 minting and was finalized
/// with a call to `finalizeDeposit` function that deposited tBTC
/// to the stBTC contract.
enum DepositState {
Unknown,
Initialized,
Finalized
}

/// @notice Mapping of stake requests.
/// @dev The key is a deposit key identifying the deposit.
mapping(uint256 => StakeRequestState) public stakeRequests;
/// @notice Holds the deposit state, keyed by the deposit key calculated for
/// the individual deposit during the call to `initializeDeposit`
/// function.
mapping(uint256 => DepositState) public deposits;

/// @notice tBTC Token contract.
IERC20 public tbtcToken;

/// @notice stBTC contract.
stBTC public stbtc;

/// @notice Minimum amount of a single stake request (in tBTC token precision).
/// @notice Minimum amount of a single deposit (in tBTC token precision).
/// @dev This parameter should be set to a value exceeding the minimum deposit
/// amount supported by tBTC Bridge.
uint256 public minStakeAmount;
/// amount supported by the tBTC Bridge.
uint256 public minDepositAmount;

/// @notice Divisor used to compute the depositor fee taken from each deposit
/// and transferred to the treasury upon stake request finalization.
/// and transferred to the treasury upon deposit finalization.
/// @dev That fee is computed as follows:
/// `depositorFee = depositedAmount / depositorFeeDivisor`
/// for example, if the depositor fee needs to be 2% of each deposit,
Expand All @@ -52,29 +59,29 @@ contract BitcoinDepositorV2 is AbstractTBTCDepositor, Ownable2StepUpgradeable {
// TEST: New variable;
uint256 public newVariable;

/// @notice Emitted when a stake request is initialized.
/// @notice Emitted when a deposit is initialized.
/// @dev Deposit details can be fetched from {{ Bridge.DepositRevealed }}
/// event emitted in the same transaction.
/// @param depositKey Deposit key identifying the deposit.
/// @param caller Address that initialized the stake request.
/// @param staker The address to which the stBTC shares will be minted.
/// @param caller Address that initialized the deposit.
/// @param depositOwner The address to which the stBTC shares will be minted.
/// @param initialAmount Amount of funding transaction.
event StakeRequestInitialized(
event DepositInitialized(
uint256 indexed depositKey,
address indexed caller,
address indexed staker,
address indexed depositOwner,
uint256 initialAmount
);

/// @notice Emitted when a stake request is finalized.
/// @notice Emitted when a deposit is finalized.
/// @dev Deposit details can be fetched from {{ ERC4626.Deposit }}
/// event emitted in the same transaction.
/// @param depositKey Deposit key identifying the deposit.
/// @param caller Address that finalized the stake request.
/// @param caller Address that finalized the deposit.
/// @param initialAmount Amount of funding transaction.
/// @param bridgedAmount Amount of tBTC tokens that was bridged by the tBTC bridge.
/// @param depositorFee Depositor fee amount.
event StakeRequestFinalized(
event DepositFinalized(
uint256 indexed depositKey,
address indexed caller,
uint16 indexed referral,
Expand All @@ -83,10 +90,10 @@ contract BitcoinDepositorV2 is AbstractTBTCDepositor, Ownable2StepUpgradeable {
uint256 depositorFee
);

/// @notice Emitted when a minimum single stake amount is updated.
/// @param minStakeAmount New value of the minimum single stake
/// @notice Emitted when a minimum single deposit amount is updated.
/// @param minDepositAmount New value of the minimum single deposit
/// amount (in tBTC token precision).
event MinStakeAmountUpdated(uint256 minStakeAmount);
event MinDepositAmountUpdated(uint256 minDepositAmount);

/// @notice Emitted when a depositor fee divisor is updated.
/// @param depositorFeeDivisor New value of the depositor fee divisor.
Expand All @@ -101,14 +108,13 @@ contract BitcoinDepositorV2 is AbstractTBTCDepositor, Ownable2StepUpgradeable {
/// Reverts if the stBTC address is zero.
error StbtcZeroAddress();

/// @dev Staker address is zero.
error StakerIsZeroAddress();
/// @dev Deposit owner address is zero.
error DepositOwnerIsZeroAddress();

/// @dev Attempted to execute function for stake request in unexpected current
/// state.
error UnexpectedStakeRequestState(
StakeRequestState currentState,
StakeRequestState expectedState
/// @dev Attempted to execute function for deposit in unexpected current state.
error UnexpectedDepositState(
DepositState actualState,
DepositState expectedState
);

/// @dev Calculated depositor fee exceeds the amount of minted tBTC tokens.
Expand All @@ -117,10 +123,10 @@ contract BitcoinDepositorV2 is AbstractTBTCDepositor, Ownable2StepUpgradeable {
uint256 bridgedAmount
);

/// @dev Attempted to set minimum stake amount to a value lower than the
/// @dev Attempted to set minimum deposit amount to a value lower than the
/// tBTC Bridge deposit dust threshold.
error MinStakeAmountLowerThanBridgeMinDeposit(
uint256 minStakeAmount,
error MinDepositAmountLowerThanBridgeMinDeposit(
uint256 minDepositAmount,
uint256 bridgeMinDepositAmount
);

Expand All @@ -139,78 +145,78 @@ contract BitcoinDepositorV2 is AbstractTBTCDepositor, Ownable2StepUpgradeable {
newVariable = _newVariable;
}

/// @notice This function allows staking process initialization for a Bitcoin
/// @notice This function allows depositing process initialization for a Bitcoin
/// deposit made by an user with a P2(W)SH transaction. It uses the
/// supplied information to reveal a deposit to the tBTC Bridge contract.
/// @dev Requirements:
/// - The revealed vault address must match the TBTCVault address,
/// - All requirements from {Bridge#revealDepositWithExtraData}
/// function must be met.
/// - `staker` must be the staker address used in the P2(W)SH BTC
/// - `depositOwner` must be the deposit owner address used in the P2(W)SH BTC
/// deposit transaction as part of the extra data.
/// - `referral` must be the referral info used in the P2(W)SH BTC
/// deposit transaction as part of the extra data.
/// - BTC deposit for the given `fundingTxHash`, `fundingOutputIndex`
/// can be revealed only one time.
/// @param fundingTx Bitcoin funding transaction data, see `IBridgeTypes.BitcoinTxInfo`.
/// @param reveal Deposit reveal data, see `IBridgeTypes.DepositRevealInfo`.
/// @param staker The address to which the stBTC shares will be minted.
/// @param depositOwner The address to which the stBTC shares will be minted.
/// @param referral Data used for referral program.
function initializeStake(
function initializeDeposit(
IBridgeTypes.BitcoinTxInfo calldata fundingTx,
IBridgeTypes.DepositRevealInfo calldata reveal,
address staker,
address depositOwner,
uint16 referral
) external {
if (staker == address(0)) revert StakerIsZeroAddress();
if (depositOwner == address(0)) revert DepositOwnerIsZeroAddress();

// We don't check if the request was already initialized, as this check
// is enforced in `_initializeDeposit` when calling the
// `Bridge.revealDepositWithExtraData` function.
(uint256 depositKey, uint256 initialAmount) = _initializeDeposit(
fundingTx,
reveal,
encodeExtraData(staker, referral)
encodeExtraData(depositOwner, referral)
);

// Validate current stake request state.
if (stakeRequests[depositKey] != StakeRequestState.Unknown)
revert UnexpectedStakeRequestState(
stakeRequests[depositKey],
StakeRequestState.Unknown
// Validate current deposit state.
if (deposits[depositKey] != DepositState.Unknown)
revert UnexpectedDepositState(
deposits[depositKey],
DepositState.Unknown
);

// Transition to a new state.
stakeRequests[depositKey] = StakeRequestState.Initialized;
deposits[depositKey] = DepositState.Initialized;

emit StakeRequestInitialized(
emit DepositInitialized(
depositKey,
msg.sender,
staker,
depositOwner,
initialAmount
);
}

/// @notice This function should be called for previously initialized stake
/// @notice This function should be called for previously initialized deposit
/// request, after tBTC minting process completed, meaning tBTC was
/// minted to this contract.
/// @dev It calculates the amount to stake based on the approximate minted
/// @dev It calculates the amount to deposit based on the approximate minted
/// tBTC amount reduced by the depositor fee.
/// @dev IMPORTANT NOTE: The minted tBTC amount used by this function is an
/// approximation. See documentation of the
/// {{AbstractTBTCDepositor#_calculateTbtcAmount}} responsible for calculating
/// this value for more details.
/// @param depositKey Deposit key identifying the deposit.
function finalizeStake(uint256 depositKey) external {
// Validate current stake request state.
if (stakeRequests[depositKey] != StakeRequestState.Initialized)
revert UnexpectedStakeRequestState(
stakeRequests[depositKey],
StakeRequestState.Initialized
function finalizeDeposit(uint256 depositKey) external {
// Validate current deposit state.
if (deposits[depositKey] != DepositState.Initialized)
revert UnexpectedDepositState(
deposits[depositKey],
DepositState.Initialized
);

// Transition to a new state.
stakeRequests[depositKey] = StakeRequestState.Finalized;
deposits[depositKey] = DepositState.Finalized;

(
uint256 initialAmount,
Expand All @@ -235,9 +241,9 @@ contract BitcoinDepositorV2 is AbstractTBTCDepositor, Ownable2StepUpgradeable {
tbtcToken.safeTransfer(stbtc.treasury(), depositorFee);
}

(address staker, uint16 referral) = decodeExtraData(extraData);
(address depositOwner, uint16 referral) = decodeExtraData(extraData);

emit StakeRequestFinalized(
emit DepositFinalized(
depositKey,
msg.sender,
referral,
Expand All @@ -246,33 +252,33 @@ contract BitcoinDepositorV2 is AbstractTBTCDepositor, Ownable2StepUpgradeable {
depositorFee
);

uint256 amountToStake = tbtcAmount - depositorFee;
uint256 amountToDeposit = tbtcAmount - depositorFee;

// Deposit tBTC in stBTC.
tbtcToken.safeIncreaseAllowance(address(stbtc), amountToStake);
tbtcToken.safeIncreaseAllowance(address(stbtc), amountToDeposit);
// slither-disable-next-line unused-return
stbtc.deposit(amountToStake, staker);
stbtc.deposit(amountToDeposit, depositOwner);
}

/// @notice Updates the minimum stake amount.
/// @notice Updates the minimum deposit amount.
/// @dev It requires that the new value is greater or equal to the tBTC Bridge
/// deposit dust threshold, to ensure deposit will be able to be bridged.
/// @param newMinStakeAmount New minimum stake amount (in tBTC precision).
function updateMinStakeAmount(
uint256 newMinStakeAmount
/// @param newMinDepositAmount New minimum deposit amount (in tBTC precision).
function updateMinDepositAmount(
uint256 newMinDepositAmount
) external onlyOwner {
uint256 minBridgeDepositAmount = _minDepositAmount();

// Check if new value is at least equal the tBTC Bridge Deposit Dust Threshold.
if (newMinStakeAmount < minBridgeDepositAmount)
revert MinStakeAmountLowerThanBridgeMinDeposit(
newMinStakeAmount,
if (newMinDepositAmount < minBridgeDepositAmount)
revert MinDepositAmountLowerThanBridgeMinDeposit(
newMinDepositAmount,
minBridgeDepositAmount
);

minStakeAmount = newMinStakeAmount;
minDepositAmount = newMinDepositAmount;

emit MinStakeAmountUpdated(newMinStakeAmount);
emit MinDepositAmountUpdated(newMinDepositAmount);

// TEST: Emit newly added event.
emit NewEvent();
Expand All @@ -283,45 +289,35 @@ contract BitcoinDepositorV2 is AbstractTBTCDepositor, Ownable2StepUpgradeable {
function updateDepositorFeeDivisor(
uint64 newDepositorFeeDivisor
) external onlyOwner {
// TODO: Introduce a parameters update process.
depositorFeeDivisor = newDepositorFeeDivisor;

emit DepositorFeeDivisorUpdated(newDepositorFeeDivisor);
}

/// @notice Minimum stake amount (in tBTC token precision).
/// @dev This function should be used by dApp to check the minimum amount
/// for the stake request.
/// @dev It is not enforced in the `initializeStakeRequest` function, as
/// it is intended to be used in the dApp staking form.
function minStake() external view returns (uint256) {
return minStakeAmount;
}

/// @notice Encodes staker address and referral as extra data.
/// @dev Packs the data to bytes32: 20 bytes of staker address and
/// @notice Encodes deposit owner address and referral as extra data.
/// @dev Packs the data to bytes32: 20 bytes of deposit owner address and
/// 2 bytes of referral, 10 bytes of trailing zeros.
/// @param staker The address to which the stBTC shares will be minted.
/// @param depositOwner The address to which the stBTC shares will be minted.
/// @param referral Data used for referral program.
/// @return Encoded extra data.
function encodeExtraData(
address staker,
address depositOwner,
uint16 referral
) public pure returns (bytes32) {
return bytes32(abi.encodePacked(staker, referral));
return bytes32(abi.encodePacked(depositOwner, referral));
}

/// @notice Decodes staker address and referral from extra data.
/// @dev Unpacks the data from bytes32: 20 bytes of staker address and
/// @notice Decodes deposit owner address and referral from extra data.
/// @dev Unpacks the data from bytes32: 20 bytes of deposit owner address and
/// 2 bytes of referral, 10 bytes of trailing zeros.
/// @param extraData Encoded extra data.
/// @return staker The address to which the stBTC shares will be minted.
/// @return depositOwner The address to which the stBTC shares will be minted.
/// @return referral Data used for referral program.
function decodeExtraData(
bytes32 extraData
) public pure returns (address staker, uint16 referral) {
// First 20 bytes of extra data is staker address.
staker = address(uint160(bytes20(extraData)));
) public pure returns (address depositOwner, uint16 referral) {
// First 20 bytes of extra data is deposit owner address.
depositOwner = address(uint160(bytes20(extraData)));
// Next 2 bytes of extra data is referral info.
referral = uint16(bytes2(extraData << (8 * 20)));
}
Expand Down

0 comments on commit 3116317

Please sign in to comment.