Severity: HIGH — No Incident Response Without This
Problem
If a vulnerability is discovered post-deployment, there is currently no way to halt new lock() calls. Existing funds would be at risk while waiting for users to manually claim refunds.
Fix Required
Soroban HTLC Contract
Add an admin-controlled pause flag to DataKey:
```rust
pub enum DataKey {
Lock(BytesN<32>),
Admin,
Paused, // new
}
```
Add functions:
initialize(env, admin) — store admin address
pause(env) — admin only, set Paused = true
unpause(env) — admin only, set Paused = false
is_paused(env) -> bool
Add guard to lock() only:
```rust
if env.storage().instance().get::<DataKey, bool>(&DataKey::Paused).unwrap_or(false) {
panic_with_error!(&env, HTLCError::ContractPaused);
}
```
Do NOT pause withdraw() or refund() — users must always be able to recover funds.
EVM HTLC Contract
Use OpenZeppelin Pausable:
```solidity
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract HTLCEvm is ReentrancyGuard, Pausable, Ownable {
function lock(...) external nonReentrant whenNotPaused returns (bytes32) { ... }
function pause() external onlyOwner { _pause(); }
function unpause() external onlyOwner { _unpause(); }
}
```
Acceptance Criteria
Severity: HIGH — No Incident Response Without This
Problem
If a vulnerability is discovered post-deployment, there is currently no way to halt new lock() calls. Existing funds would be at risk while waiting for users to manually claim refunds.
Fix Required
Soroban HTLC Contract
Add an admin-controlled pause flag to
DataKey:```rust
pub enum DataKey {
Lock(BytesN<32>),
Admin,
Paused, // new
}
```
Add functions:
initialize(env, admin)— store admin addresspause(env)— admin only, setPaused = trueunpause(env)— admin only, setPaused = falseis_paused(env) -> boolAdd guard to
lock()only:```rust
if env.storage().instance().get::<DataKey, bool>(&DataKey::Paused).unwrap_or(false) {
panic_with_error!(&env, HTLCError::ContractPaused);
}
```
EVM HTLC Contract
Use OpenZeppelin
Pausable:```solidity
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract HTLCEvm is ReentrancyGuard, Pausable, Ownable {
function lock(...) external nonReentrant whenNotPaused returns (bytes32) { ... }
function pause() external onlyOwner { _pause(); }
function unpause() external onlyOwner { _unpause(); }
}
```
Acceptance Criteria
lock()is blocked when paused on both Soroban and EVMwithdraw()andrefund()work even when pausedPausedandUnpausedevents emittedsettle()as well