53021 sc medium deposit and bridge workflow bricked by immediate share lock users cannot bridge immediately after deposit
Submitted on Aug 14th 2025 at 17:09:44 UTC by @farman1094 for Attackathon | Plume Network
- Report ID: #53021
- Report Type: Smart Contract
- Report severity: Medium
- Target: https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/base/Roles/TellerWithMultiAssetSupportPredicateProxy.sol
- Impacts:
- Contract fails to deliver promised returns, but doesn't lose value
Description
Brief/Intro
There is a critical logic flaw in all the depositAndBridge* functions of the TellerWithMultiAssetSupportPredicateProxy and DexAggregatorWrapperWithPredicateProxy contracts. When a user calls the deposit function, their newly minted shares are immediately locked by the share-lock mechanism, preventing their subsequent transfer. Later, when the bridge logic checks the lock time (via beforeTransfer), the check triggers and causes a revert — making it impossible to complete the deposit-and-bridge operation in a single transaction.
Vulnerability Details
The vulnerable code path is in DexAggregatorWrapperWithPredicateProxy.depositAndBridgeOneInch, which calls:
teller.depositAndBridge{ value: msg.value - nativeValueToWrap }(
supportedAsset, supportedAssetAmount, minimumMint, bridgeData
);
Internally, this runs _erc20Deposit to mint shares for the user, followed immediately by _afterPublicDeposit, which executes:
shareUnlockTime[user] = block.timestamp + currentShareLockPeriod;
This lock is set before the bridge transfer is attempted. The bridge logic then calls beforeTransfer(from), which checks:
if (shareUnlockTime[from] > block.timestamp) revert TellerWithMultiAssetSupport__SharesAreLocked();
Since the shares were just locked, the transfer will always revert, making it impossible to complete the deposit-and-bridge operation in a single transaction. This logic error effectively disables the combined deposit-and-bridge feature.
Impact Details
Users will be unable to use Deposit-and-Bridge flows that expect to mint shares and immediately bridge them in the same transaction, breaking a core workflow of the protocol. The contract does not lose funds, but the feature is unusable as designed.
Proof of Concept
Step: User intends to deposit and bridge in one transaction
- Alice calls
TellerWithMultiAssetSupportPredicateProxy::depositAndBridge(or the dex wrapper variant) expecting:- Deposit accepted
- Shares minted to Alice
- Newly minted shares bridged immediately, completing a cross-chain transfer in a single transaction
Deposit Phase
- The wrapper calls
teller.depositAndBridge. - Inside
depositAndBridge:_erc20Depositmints shares to Alice._afterPublicDepositis immediately called:
shareUnlockTime[Alice] = block.timestamp + currentShareLockPeriod;
- This sets a lock on Alice's shares, preventing their transfer until the lock period expires.
Bridge Phase
- The next step calls
TellerWithMultiAssetSupport::bridge. - Inside bridge flow,
beforeTransfer(Alice)is called:
if (shareUnlockTime[Alice] > block.timestamp) revert TellerWithMultiAssetSupport__SharesAreLocked();
- Because the lock was just set, this condition is true and the call reverts.
- The entire transaction fails, so deposit-and-bridge cannot complete in one transaction.
Conclusion
Immediate locking of freshly minted shares before the bridge transfer causes beforeTransfer to always revert, breaking the intended deposit-and-bridge workflow. The issue prevents the combined operation from being completed atomically; users cannot bridge immediately after deposit.