Pooled Liquidity Node — DobPooledLN
Source on GitHub:
Dobhooks/contracts/src/DobPooledLN.sol
DobPooledLN is a shared USDC vault that registers as a single LP position in DobLPRegistry. Anyone can deposit USDC and receive shares. The operator (typically Dobprotocol) decides which RWA assets to back, the discount rate (minPenaltyBps), and the per-asset cap. RWA tokens earned from fills are claimed from the registry into the pool and then distributed to depositors proportional to their share.
This is the "shared LN" the landing page advertises — a way for users to participate as an LP without having to set their own per-asset conditions.
Key state
ERC20 public immutable usdc;
DobLPRegistry public immutable lpRegistry;
uint256 public totalPoolUsdc; // grows on deposit, shrinks on withdraw
uint256 public totalShares; // outstanding shares
mapping(address => uint256) public shares;
mapping(address => uint48) public depositedAt;
uint48 public constant MIN_DEPOSIT_DURATION = 1 hours;
uint256 private constant DEAD_SHARES = 1000;
uint256 public minDeposit;
bool public paused;
bool public registered; // registered in DobLPRegistry?
mapping(address => uint256) public totalRwaOwed;
mapping(address => uint256) public totalRwaClaimed;
mapping(address => uint256) public totalRwaPending;
mapping(address => mapping(address => uint256)) public rwaClaimable;
address[] public backedAssets;
mapping(address => bool) public isBackedAsset;
Lifecycle
1. Operator registers the pool in the LP registry
function registerInRegistry(uint256 amount) external onlyOwner; // one-shot
function addCapitalToRegistry(uint256 amount) external onlyOwner; // top-ups
registerInRegistry calls lpRegistry.register(amount) once. Subsequent capital additions go through lpRegistry.depositMore(amount).
2. Operator backs assets (admin only)
function backAsset(
address rwaToken,
uint256 minOraclePrice,
uint16 minPenaltyBps,
uint256 maxExposure,
uint256 usdcAllocation
) external onlyOwner;
function stopBacking(address rwaToken) external onlyOwner;
function increaseAllocation(address rwaToken, uint256 amount) external onlyOwner;
The pool calls through to the registry's backAsset / stopBacking / increaseAllocation. backedAssets enumerates the assets this LN has ever backed (used to discover what depositors can claim).
3. Operator updates discounts dynamically
function updateDiscount(address rwaToken, uint16 newPenaltyBps) external onlyOwner;
function updateConditions(address rwaToken, uint256 minOraclePrice, uint16 minPenaltyBps, uint256 maxExposure) external onlyOwner;
updateDiscount reads the current AssetBacking from the registry and calls updateConditions(...) keeping minOraclePrice and maxExposure unchanged.
4. Depositors put USDC in, get shares
function deposit(uint256 amount) external returns (uint256 sharesOut);
function withdraw(uint256 sharesToBurn) external returns (uint256 amount);
Standard share-vault math (shares = amount * totalShares / totalPoolUsdc). The first deposit burns 1000 dead shares (DEAD_SHARES) to prevent the first-depositor inflation attack. Withdrawals enforce MIN_DEPOSIT_DURATION = 1 hours and can only return USDC currently sitting in the contract (not USDC locked in registry backings).
5. Operator claims earned RWA from the registry into the pool
function claimRwaFromRegistry(address rwaToken, uint256 dobRwaAmount) external onlyOwner;
Calls lpRegistry.claimRwaTokens(rwaToken, dobRwaAmount), which routes through the hook and the vault to deliver underlying RWA tokens into this contract. Updates totalRwaClaimed[rwaToken].
6. Operator distributes RWA pro-rata, depositors withdraw
function distributeRwa(address rwaToken, address depositor) external onlyOwner;
function batchDistributeRwa(address rwaToken, address[] calldata depositors) external onlyOwner;
function withdrawRwa(address rwaToken, uint256 amount) external;
distributeRwa allocates (undistributed * shares[depositor]) / totalShares to rwaClaimable[depositor][rwaToken]. The depositor calls withdrawRwa(token, amount) to actually transfer the tokens out.
How DobPooledLN relates to individual LPs
DobLPRegistry itself only sees a single LP at this contract's address. From the registry's perspective there is one LPPosition with one (or more) AssetBacking entries, contributing one slot toward the per-asset MAX_BACKERS_PER_ASSET = 50.
The pool layers share-based co-investment on top: every depositor owns a slice of the registered position and earns a slice of every fill. The operator decides backing strategy; depositors trust that strategy.
Multiple DobPooledLN instances can co-exist (e.g. one per strategy, or a single "main LN" run by Dobprotocol).
Events
Deposited, Withdrawn, AssetBacked, AssetStopped, DiscountUpdated, ConditionsUpdated, AllocationIncreased, RwaClaimed, RwaDistributed, CapitalAdded, Paused, Unpaused, MinDepositSet.
Errors
ContractPaused, ZeroAmount, BelowMinDeposit, InsufficientShares, DepositDurationNotMet, NotRegistered, AlreadyRegistered, NothingToClaim, InsufficientRwa.
Deployed Addresses
TODO: verify and fill in once published. See
Dobhooks/deployments/in the repo.