Helpful?
Context
For developers looking to support custom liquidity mining, Subscriber contracts can be used to receive notifications about position modifications or transfers.
Guide
1. Implement the ISubscriber
interface
Can also refer to MockSubscriber for an actual implementation example.
import {ISubscriber} from "v4-periphery/src/interfaces/ISubscriber.sol";
contract MySubscriber is ISubscriber {
uint256 public notifySubscribeCount;
uint256 public notifyUnsubscribeCount;
uint256 public notifyModifyLiquidityCount;
uint256 public notifyBurnCount;
// other implementations...
function notifySubscribe(uint256, bytes memory) external onlyByPosm {
notifySubscribeCount++;
}
function notifyUnsubscribe(uint256) external onlyByPosm {
notifyUnsubscribeCount++;
}
function notifyModifyLiquidity(uint256, int256, BalanceDelta) external onlyByPosm {
notifyModifyLiquidityCount++;
}
function notifyBurn(uint256, address, PositionInfo, uint256, BalanceDelta)
external
onlyByPosm
{
notifyBurnCount++;
}
}
2. A caveat on unsubscribe()
There is a variable unsubscribeGasLimit
specifically set at deployment of PositionManager
to prevent gas griefing on unsubscribe()
- which could result in the subscriber contract not being notified during unsubscribe()
.
If notifying the subscriber contract is not necessary users can still specify a gas limit where notifyUnsubscribe()
hits OutOfGas
and reverts yet the unsubscription will still succeed.
From _unsubscribe()
on Notifier
:
if (address(_subscriber).code.length > 0) {
// require that the remaining gas is sufficient to notify the subscriber
// otherwise, users can select a gas limit where .notifyUnsubscribe hits OutOfGas yet the
// transaction/unsubscription can still succee
if (gasleft() < unsubscribeGasLimit) GasLimitTooLow.selector.revertWith();
try _subscriber.notifyUnsubscribe{gas: unsubscribeGasLimit}(tokenId) {} catch {}
}
3. Opt-in to a subscriber contract
To opt-in to a subscriber contract, call subscribe()
on PositionManager
.
import {IPositionManager} from "v4-periphery/src/interfaces/IPositionManager.sol";
IPositionManager posm = IPositionManager(<address>);
ISubscriber mySubscriber = ISubscriber(<address>);
bytes memory optionalData = ...;
posm.subscribe(tokenId, mySubscriber, optionalData);