Ironbank: Extension Authorization in v2

Iron Bank is a lending protocol. In its v2 eth code branch, protected calls accept the account itself or, for a non-credit account, an extension the account has allowed. Each operation keeps its own market, balance, and liquidity restrictions.

Updated on
Page sections

Permission registration and caller checks

setUserExtension(extension, allowed) changes the caller’s own extension permissions, keyed to msg.sender . Setting allowed to true adds an address if it isn’t already allowed; setting it to false removes an existing permission. Those changes emit ExtensionAdded or ExtensionRemoved .

The authorization check for protected functions evaluates this expression:

from == operator ||
    (!isCreditAccount(from) && isAllowedExtension(from, operator))

from is the account the modifier protects, and operator is the address calling Iron Bank. A direct call from that account passes the first condition. An extension needs both an allowed entry and a non-credit account to pass the second.

getUserAllowedExtensions(user) returns the recorded extension list; isAllowedExtension(user, extension) returns the stored permission for one address. The core stores permission for an account-extension pair, with no market or amount parameter in that permission.

Credit-account restrictions

isCreditAccount(user) returns true when the account’s credit-market list isn’t empty. The credit-limit manager adds a market to that list when assigning a previously zero limit a nonzero value. An unused nonzero limit therefore also makes the account a credit account. Resetting that limit to zero removes its entry; any remaining credit-market entry keeps the account classified as a credit account.

Credit limits belong to individual account-market pairs, while the extension restriction covers the account across markets in that Iron Bank instance. A credit account can pass authorization by calling directly. Its borrow must send funds to itself, and its resulting debt in the requested market can’t exceed its assigned credit limit. Repayment to a credit account also requires the payer and debt account to be the same address. Supply rejects a credit account as the recipient of the supply balance.

Hypothetical approval after a credit assignment

In this hypothetical example, Account A has allowed Extension E and initially has no credit-market entries. E calls borrow with A as both from and to . The extension branch passes because E is allowed and A isn’t a credit account.

Now suppose the credit-limit manager gives A a nonzero limit in one listed market, leaving E’s stored permission unchanged. E’s next call for A fails with !authorized , including an attempted borrow in a different market in that instance. A’s own direct call still passes the caller check, but borrowing remains subject to the requested market’s credit limit, available cash, and other operation checks.

Protected accounts and token recipients

borrow protects from , the account taking on debt, while to receives the borrowed tokens. For redeem , from owns the supply claim, and to receives the underlying asset. For non-credit accounts, these recipients can differ from the protected account. An allowed extension can therefore pass authorization for a borrow or redemption with a separate recipient.

supply and repay authorize the token-paying from account. Their to parameter identifies the account receiving the supply balance or having its debt reduced, respectively. For a supply made on an account’s behalf, the core’s safeTransferFrom still needs the payer’s tokens and applicable token spending allowance. The liquidate function applies its authorization check to the named liquidator.

Visual summary: Ironbank - Protected accounts and token recipients

Open full-size image

Authorization alone doesn’t complete an operation. A borrow still requires a listed market with borrowing unpaused, enough market cash, and compliance with any configured borrow cap. It then applies the credit-limit or account-liquidity condition appropriate to the borrower. Redemption checks the supply claim and market cash, then calls the account-liquidity check. The deferral mechanism changes the timing of that last check under its own conditions.

Batch operations and deferred liquidity checks

The v2 extension contracts include TxBuilderExtension.sol for combining operations in one transaction and UniswapExtension.sol for leverage, debt swaps, and collateral swaps. Calls these extensions make to protected pool functions remain subject to the affected account’s authorization.

deferLiquidityCheck(user, data) requires authorization for user and excludes credit accounts. It starts only from the normal liquidity-check state and invokes onDeferredLiquidityCheck(data) on the caller, which must implement DeferLiquidityCheckInterface .

The core restores the normal state after the callback returns. If the account’s deferred state was marked dirty, it then checks account liquidity. The deferral stays within that transaction; market pauses, caps, cash requirements, and other operation rules remain in force.