1Do App
Flash Loan
Assets do not move into a shared pool; lending, callback, repayment, and fee allocation complete atomically inside the wallet Runtime.
Liquidity model
Flash Loan reads balances in wallet delegatecall context, so the available amount for a token is the wallet's entire live ERC-20 balance. There is no separate pool and no deposit step.
The current version has no per-token whitelist, wallet-specific loan cap, or configurable fee. Once enabled, any compatible ERC-20 balance may be requested by an external caller, subject to same-transaction repayment.
interface IERC3156FlashBorrower {
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32);
}
interface IERC3156FlashLender {
function maxFlashLoan(address token) external view returns (uint256);
function flashFee(address token, uint256 amount) external view returns (uint256);
function flashLoan(
IERC3156FlashBorrower receiver,
address token,
uint256 amount,
bytes calldata data
) external returns (bool);
}
interface IFlashLoanApp is IERC3156FlashLender {
function earnings(address token) external view returns (uint256);
function onedoFeeReceiver() external view returns (address);
}Atomic loan flow
Record balance
The app records the pre-loan token balance and rejects zero amount or a request above current liquidity.
Transfer and callback
It sends amount to receiver, then calls onFlashLoan(initiator, token, amount, fee, data).
Borrower pushes repayment
Before returning, the receiver must actively transfer principal plus fee back to the wallet and return the ERC-3156 magic value.
Verify and allocate fee
The post-callback balance must reach balanceBefore + fee. The 1Do share is then sent to the fee receiver and the wallet share remains in the wallet.
Fees and earnings accounting
flashFee uses integer floor division, so very small loans may have a zero fee. The 1Do share is floored again.
The token argument does not affect flashFee; every ERC-20 uses the same fixed formula in the current version.
earnings(token) is cumulative accounting for the wallet's historical fee share, not a separately escrowed or claimable pot. Those tokens already remain in the wallet and may later be spent, so earnings need not equal the current balance.
flash fee = floor(amount × 5 / 10,000) // 0.05%
1Do share = floor(flash fee × 1,000 / 10,000) // 10% of fee
wallet share = flash fee - 1Do shareBorrower integration
- initiator is the caller entering flashLoan, while receiver gets the assets and callback; they may be different addresses.
- The implementation does not pull repayment with transferFrom after callback. A generic borrower that only approves the lender must be adapted to push repayment.
- onFlashLoan must return keccak256("ERC3156FlashBorrower.onFlashLoan"); any other value reverts the transaction.
- The call targets the enabled wallet and enters through executeRuntimeApp. Calling shared logic directly does not read the user's wallet balance or state.
State reads and events
- Read maxFlashLoan, flashFee, and earnings in the target wallet Runtime context; an eth_call can invoke executeRuntimeApp and decode its returned bytes.
- FlashLoanExecuted records initiator, receiver, token, amount, fee, and onedoFee. Because execution is delegatecall, the liquidity wallet is the event emitter.
- onedoFeeReceiver is immutable in the deployed app logic rather than independently configured by each wallet.
Failure and asset boundaries
- Zero amount, insufficient initial liquidity, invalid callback value, insufficient repayment, or any token transfer failure reverts the full transaction.
- The borrower callback remains inside the same Runtime execution lock and cannot start a nested Runtime app execution.
- The current app lends ERC-20 only, not native currency or NFTs.
- Fee-on-transfer, rebasing, and other nonstandard ERC-20 behavior receive no dedicated handling and may fail the balance-increase check.
Enabling exposes the current balance
Flash Loan does not reserve a dedicated slice of funds. While the app remains enabled and Registry-allowed, external callers may request the wallet's entire current balance of a token. Wallets should enable it only when that liquidity policy is appropriate.