Money market hook is a liquidity hook contract to handle basic interactions (create position, deposit/withdraw, add/remove collateral, and borrow/repay) via multicall to InitCore in a single transaction. Money market hook stores its running position id for each user, starting from 1, when a user creates a new position via the contract.
The interaction flow consists of:
Create a position on the hook and InitCore, if not existed
Perform multicall to InitCore, which performs:
Decollateralize inToken from the position and redeem token in lending pool
Withdraw from lending pool
Change position mode, if specified
Borrow tokens from lending pool
Mint inToken from lending pool and collateralize to the position
Unwrap rebase tokens, if specified
Unwrap wrapped native token to native token, if specified
The interaction is done via function.
struct OperationParams {
uint posId; // position id to execute (0 to create new position)
address viewer; // address to view position
uint16 mode; // position mode to be used
DepositParams[] depositParams; // deposit parameters
WithdrawParams[] withdrawParams; // withdraw parameters
BorrowParams[] borrowParams; // borrow parameters
RepayParams[] repayParams; // repay parameters
uint minHealth_e18; // minimum health to maintain after execute
bool returnNative; // return native token or not (using balanceOf(address(this)))
}
function execute(OperationParams calldata _params)
external
payable
nonReentrant
returns (uint posId, uint initPosId, bytes[] memory results)
{
// create position if not exist
if (_params.posId == 0) {
(posId, initPosId) = createPos(_params.mode, _params.viewer);
} else {
// for existing position, only owner can execute
posId = _params.posId;
initPosId = initPosIds[msg.sender][posId];
_require(IERC721(POS_MANAGER).ownerOf(initPosId) == address(this), Errors.NOT_OWNER);
}
results = _handleMulticall(initPosId, _params);
// check slippage
_require(_params.minHealth_e18 <= IInitCore(CORE).getPosHealthCurrent_e18(initPosId), Errors.SLIPPAGE_CONTROL);
// unwrap token if needed
for (uint i; i < _params.withdrawParams.length; i = i.uinc()) {
address helper = _params.withdrawParams[i].rebaseHelperParams.helper;
if (helper != address(0)) IRebaseHelper(helper).unwrap(_params.withdrawParams[i].to);
}
// return native token
if (_params.returnNative) {
uint wNativeBal = IERC20(WNATIVE).balanceOf(address(this));
// NOTE: no need receive function since we will use TransparentUpgradeableProxyReceiveETH
if (wNativeBal != 0) IWNative(WNATIVE).withdraw(wNativeBal);
uint nativeBal = address(this).balance;
if (nativeBal != 0) {
(bool success,) = payable(msg.sender).call{value: address(this).balance}('');
_require(success, Errors.CALL_FAILED);
}
}
}