Trident is not v2. Trident pools use the Bentobox contract to store liquidity. You can flashloan from Bentobox easily.
Here is an old example:
You call flashloan, Bento transfers you the token(s), and then calls-back the onFlashloan function in your contract.
# @notice bento's flashloan ability.
interface Bento:
def flashLoan(
borrower: address, # @param borrower: address of the contract to be called back.
receiver: address, # @param receiver: address of the token receiver.
token: address, # @param token: address of the token to receive.
amount: uint256, # @param amount: number of the tokens to receive.
data: Bytes[B] # @param calldata: encoded data to pass to the `borrower` contract.
): nonpayable
...
# @notice the function that will be called back by bento.
# `amount` + `fee` needs to be repayed to msg.sender (bento) before call returns.
@external
def onFlashLoan(
sender: address, # @param sender: address of the invoker.
token: address, # @param token: address of the token token loaned.
amount: uint256, # @param amount: quantity of `token` loaned.
fee: uint256, # @param fee: amount that needs to be paid for loan. Same as `token`.
data: Bytes[B] # @param data: the calldata we passed to flashloan function.
):
https://github.com/0xMaka/vybes/blob/main/flashBento.vy
For v2 (and clones) the logic is in the pool contract, and you will want to implement IUniswapV2Callee.
That is, your calling contract that will be called back by the pool.
interface IUniswapV2Callee {
function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
}
Pool calls the function in your contract and so your contract needs to have a function that conforms to the interface.
The pool will optimistically transfer the tokens to you expecting them to already be at the pool or for it to be a flash loan.
You just pass some greater than zero length of data with the call to the low level swap, and it will make the callback so that you can repay.
Bot logic is usually in the called-back function in your contract.