Skip to content

Commit aad2f77

Browse files
committed
cleanup withdraw signaling
1 parent 7bc4f21 commit aad2f77

File tree

3 files changed

+49
-41
lines changed

3 files changed

+49
-41
lines changed

src/SovaBTC.sol

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ contract SovaBTC is ISovaBTC, UBTC20, Ownable, ReentrancyGuard {
2525
/// @notice Maximum deposit amount in satoshis
2626
uint64 public maxDepositAmount;
2727

28-
/// @notice Maximum gas limit amount in satoshis
29-
uint64 public maxGasLimitAmount;
30-
3128
/// @notice Pause state of the contract
3229
bool private _paused;
3330

@@ -173,11 +170,24 @@ contract SovaBTC is ISovaBTC, UBTC20, Ownable, ReentrancyGuard {
173170
emit Deposit(msg.sender, btcTx.txid, amount);
174171
}
175172

173+
/**
174+
* @notice Signals a withdrawal request by saving the withdrawal request.
175+
*
176+
* @dev The user must have enough sovaBTC to cover the amount + gas limit + operatorFee fee.
177+
*
178+
* @param amount The amount of satoshis to withdraw (excluding gas)
179+
* @param btcGasLimit The gas limit bid for the Bitcoin transaction in satoshis
180+
* @param operatorFee The fee offered to the operator for processing the withdrawal in satoshis
181+
* @param dest The Bitcoin address to send the withdrawn BTC to
182+
*/
176183
function signalWithdraw(uint64 amount, uint64 btcGasLimit, uint64 operatorFee, string calldata dest)
177184
external
178185
whenNotPaused
179-
noPendingTransactions(msg.sender)
180186
{
187+
if (bytes(dest).length == 0) {
188+
revert EmptyDestination();
189+
}
190+
181191
if (amount == 0) {
182192
revert ZeroAmount();
183193
}
@@ -186,37 +196,40 @@ contract SovaBTC is ISovaBTC, UBTC20, Ownable, ReentrancyGuard {
186196
revert ZeroGasLimit();
187197
}
188198

189-
if (btcGasLimit > maxGasLimitAmount) {
199+
if (btcGasLimit > amount) {
190200
revert GasLimitTooHigh();
191201
}
192202

193-
uint256 totalRequired = amount + btcGasLimit;
203+
uint256 totalRequired = amount + btcGasLimit + operatorFee;
194204
if (balanceOf(msg.sender) < totalRequired) {
195205
revert InsufficientAmount();
196206
}
197207

198-
if (bytes(dest).length == 0) {
199-
revert EmptyDestination();
200-
}
201-
202208
// check if user already has a pending withdrawal
203209
if (_pendingWithdrawals[msg.sender].amount > 0) {
204210
revert PendingWithdrawalExists();
205211
}
206212

207-
// check if user already has a pending withdraw request
208-
if (_pendingUserWithdrawRequests[msg.sender].amount > 0) {
209-
revert PendingTransactionExists();
210-
}
211-
213+
// Store the withdraw request
212214
_pendingUserWithdrawRequests[msg.sender] =
213215
UserWithdrawRequest({amount: amount, btcGasLimit: btcGasLimit, operatorFee: operatorFee, destination: dest});
214216

215217
emit WithdrawSignaled(msg.sender, amount, btcGasLimit, operatorFee, dest);
216218
}
217219

218-
function withdraw(address user, bytes calldata signedTx) external onlyWithdrawSigner whenNotPaused {
219-
// decode signed tx so that we can validate it against the user request
220+
/**
221+
* @notice Processes a withdrawal signal by broadcasting a signed Bitcoin transaction.
222+
*
223+
* @dev Only authorized withdraw signers can call this function.
224+
*
225+
* @param user The address of the user who signaled the withdrawal
226+
* @param signedTx The signed Bitcoin transaction to broadcast
227+
*/
228+
function withdraw(address user, bytes calldata signedTx) external whenNotPaused onlyWithdrawSigner {
229+
// Check if user has a pending withdrawal already
230+
if (_pendingWithdrawals[user].amount > 0) revert PendingWithdrawalExists();
231+
232+
// decode signed tx so that we know it is a valid bitcoin tx
220233
SovaBitcoin.BitcoinTx memory btcTx = SovaBitcoin.decodeBitcoinTx(signedTx);
221234

222235
UserWithdrawRequest memory request = _pendingUserWithdrawRequests[user];
@@ -226,12 +239,10 @@ contract SovaBTC is ISovaBTC, UBTC20, Ownable, ReentrancyGuard {
226239
revert PendingTransactionExists();
227240
}
228241

229-
uint256 totalRequired = request.amount + uint256(request.btcGasLimit);
242+
uint256 totalRequired = request.amount + uint256(request.btcGasLimit) + uint256(request.operatorFee);
230243

231244
if (balanceOf(user) < totalRequired) revert InsufficientAmount();
232245

233-
if (_pendingWithdrawals[user].amount > 0) revert PendingWithdrawalExists();
234-
235246
// Track pending withdrawal
236247
_setPendingWithdrawal(user, totalRequired);
237248

@@ -286,22 +297,6 @@ contract SovaBTC is ISovaBTC, UBTC20, Ownable, ReentrancyGuard {
286297
emit MaxDepositAmountUpdated(oldAmount, _maxAmount);
287298
}
288299

289-
/**
290-
* @notice Admin function to set the maximum gas limit amount
291-
*
292-
* @param _maxGasLimitAmount New maximum gas limit amount in satoshis
293-
*/
294-
function setMaxGasLimitAmount(uint64 _maxGasLimitAmount) external onlyOwner {
295-
if (_maxGasLimitAmount == 0) {
296-
revert ZeroAmount();
297-
}
298-
299-
uint64 oldAmount = maxGasLimitAmount;
300-
maxGasLimitAmount = _maxGasLimitAmount;
301-
302-
emit MaxGasLimitAmountUpdated(oldAmount, _maxGasLimitAmount);
303-
}
304-
305300
/**
306301
* @notice Admin function to pause the contract
307302
*/

src/UBTC20.sol

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ abstract contract UBTC20 is ERC20 {
1818

1919
mapping(address => Pending) internal _pendingDeposits;
2020
mapping(address => Pending) internal _pendingWithdrawals;
21+
2122
mapping(address => UserWithdrawRequest) internal _pendingUserWithdrawRequests;
2223

2324
error PendingTransactionExists();
@@ -26,10 +27,7 @@ abstract contract UBTC20 is ERC20 {
2627

2728
/// @notice Modifier to prevent transfers when user has a pending deposit or withdrawal.
2829
modifier noPendingTransactions(address user) {
29-
if (
30-
_pendingDeposits[user].amount > 0 || _pendingWithdrawals[user].amount > 0
31-
|| _pendingUserWithdrawRequests[user].amount > 0
32-
) {
30+
if (_pendingDeposits[user].amount > 0 || _pendingWithdrawals[user].amount > 0) {
3331
revert PendingTransactionExists();
3432
}
3533
_;
@@ -53,6 +51,22 @@ abstract contract UBTC20 is ERC20 {
5351
return _pendingWithdrawals[user].timestamp;
5452
}
5553

54+
function pendingUserWithdrawRequestAmountOf(address user) public view returns (uint256) {
55+
return _pendingUserWithdrawRequests[user].amount;
56+
}
57+
58+
function pendingUserWithdrawRequestBtcGasLimitOf(address user) public view returns (uint64) {
59+
return _pendingUserWithdrawRequests[user].btcGasLimit;
60+
}
61+
62+
function pendingUserWithdrawRequestOperatorFeeOf(address user) public view returns (uint64) {
63+
return _pendingUserWithdrawRequests[user].operatorFee;
64+
}
65+
66+
function pendingUserWithdrawRequestDestinationOf(address user) public view returns (string memory) {
67+
return _pendingUserWithdrawRequests[user].destination;
68+
}
69+
5670
/* ----------------------------- OVERRIDES ------------------------------ */
5771

5872
/// @notice Override transfer to prevent transfers during pending states

src/interfaces/ISovaBTC.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ interface ISovaBTC {
1313
function adminBurn(address wallet, uint256 amount) external;
1414
function setMinDepositAmount(uint64 _minAmount) external;
1515
function setMaxDepositAmount(uint64 _maxAmount) external;
16-
function setMaxGasLimitAmount(uint64 _maxGasLimitAmount) external;
1716
function pause() external;
1817
function unpause() external;
1918
function addWithdrawSigner(address signer) external;

0 commit comments

Comments
 (0)