How adding liquidity could result in a loss of funds

Adding liquidity to UniswapV2 is trivial: one can simply directly transfer tokens to the pair contract and then call the mint function. This function calculates the liquidity tokens you should receive based on the current balance in the contract and the recorded reserves. The process is be straightforward: your deposited tokens are converted into liquidity tokens, representing your share of the pool. The pair will just check how much was transferred to it:

There is a small problem: If the transfer and the mint call are not atomic, you risk losing the deposited tokens.

This is where skim and sync come into play, providing solutions to potential issues arising from non-atomic transactions:

The skim function

This function is designed to address the issue of tokens being sent to the pair without a corresponding mint operation. This can happen if a user mistakenly does not execute the deposit in a single transaction. The skim function allows anyone to call it and transfers the excess tokens (the difference between the current balance and the recorded reserves) out of the pair to the caller. In essence, if there's a discrepancy because of a non-atomic transaction, skim can be invoked by a bot or an opportunistic user to "drain" these tokens.

The sync function:

Instead of transferring out excess tokens, sync updates the pair's reserves to match the current balances of the tokens in the contract. This is crucial after direct token transfers or any event that could cause the reserves recorded in the contract to diverge from the actual token balances. By calling sync, the contract aligns its reserves with reality, ensuring that the liquidity in the pool accurately reflects the tokens held in the contract. This action doesn't transfer tokens out but rather incorporates these into the pair.

Link to the article