Decentralized Finance on Bitcoin

Bitcoin-Native
Lending &
Borrowing Protocol

Built on OP_NET with AssemblyScript. Real OP_20 token flows,
collateral-backed loans, and permissionless liquidations — on Bitcoin.

5%
Annual Interest
150%
Min Collateral
120%
Liquidation Trigger
+5%
Liquidator Bonus
01
Protocol Flows
💧
Lender: Deposit Liquidity
  • Call loanToken.approve(lendingContract, amount)
  • Call lending.depositLiquidity(amount)
  • Contract pulls tokens via transferFrom
  • Pool balance increases, interest accrues
📤
Lender: Withdraw Liquidity
  • No approve needed (contract sends)
  • Call lending.withdrawLiquidity(0)
  • Contract sends principal + accrued interest
  • Pass 0 to withdraw full balance
🔒
Borrower: Deposit Collateral
  • Call collateralToken.approve(lending, amount)
  • Call lending.depositCollateral(amount)
  • Collateral locked via transferFrom
  • Position becomes borrowing-eligible
💸
Borrower: Borrow & Repay
  • Call lending.borrow(amount, colPrice)
  • Contract transfers loanToken to borrower
  • Approve totalDebt, call lending.repay()
  • Collateral returned after full repayment
Liquidation
  • Monitor positions where colRatio < 120%
  • Approve totalDebt in loanToken
  • Call lending.liquidate(borrower, colPrice)
  • Receive collateral + 5% bonus
🛡️
Security Model
  • Every transfer is a two-step: approve → transferFrom
  • Allowance checked before execution
  • Reentrancy-safe by design
  • Matches Solidity ERC-20 security model
02
Protocol Parameters
500
Annual Interest BPS
5% yearly rate
150%
Collateral Ratio
Min collateralization
120%
Liquidation Threshold
Triggers liquidation
500
Liquidation Bonus BPS
+5% for liquidators
03
Token Flow Architecture
Lender
👤 User
approve(lending, amount)
OP_20 Token
🪙 loanToken
↓ depositLiquidity(amount)
Borrower
👤 User
depositCollateral + borrow
Smart Contract
⚙️ BTCLendingProtocol
transfer(lender, principal+interest)
OP_20 Token
🪙 collateralToken
Internal Operations
transferFrom(lender → self) — liquidity deposited
transfer(self → lender) — liquidity + interest withdrawn
transferFrom(borrower → self) — collateral locked
transfer(self → borrower) — loan disbursed
transferFrom(borrower → self) — debt repaid
transfer(self → borrower) — collateral returned
04
Usage Examples
Lender
Borrower
Liquidator
Deploy
// Step 1: Approve loanToken spending await loanToken.approve(lendingContractAddress, amount); // Step 2: Deposit into the liquidity pool await lending.depositLiquidity(amount); // → Contract calls: loanToken.transferFrom(caller, self, amount) // Withdraw (no approve needed — contract sends to you) await lending.withdrawLiquidity(0n); // 0 = withdraw all // → loanToken.transfer(caller, principal + interest)
// Step 1: Lock collateral await collateralToken.approve(lendingContractAddress, collateralAmount); await lending.depositCollateral(collateralAmount); // Step 2: Borrow loan tokens (colPrice: 1e18 = 1:1 value) await lending.borrow(loanAmount, BigInt(1e18)); // → loanToken.transfer(caller, loanAmount) // Step 3: Repay debt const { result: totalDebt } = await lending.getTotalDebt(myAddress); await loanToken.approve(lendingContractAddress, totalDebt); await lending.repay(); // → collateralToken returned to borrower
// Find undercollateralized positions (ratio < 120) const { result: ratio } = await lending.getCollateralRatio(borrower, currentPrice); if (ratio < 120n) { // Get total outstanding debt const { result: debt } = await lending.getTotalDebt(borrower); // Approve loan token repayment await loanToken.approve(lendingContractAddress, debt); // Liquidate — receive collateral + 5% bonus await lending.liquidate(borrower, currentPrice); }
# Set environment variables export WALLET_WIF="cQz..." export LOAN_TOKEN_ADDRESS="bcrt1p..." export COLLATERAL_TOKEN_ADDRESS="bcrt1p..." export NETWORK="regtest" export RPC_URL="https://regtest.opnet.org" # Build the contract npm run build # → build/contract.wasm # Deploy and run full flow npm run deploy # deploys → approve → deposit → borrow → repay → withdraw
05
Security Architecture
🔐
Approve-First Pattern
Every token transfer requires a prior approve() call. The contract uses transferFrom(), matching Solidity's ERC-20 battle-tested security model.
🛡️
Allowance Checks
Before every transferFrom, the contract verifies sufficient allowance via allowance(). Insufficient funds abort the transaction immediately.
Bitcoin UTXO Compatible
Contracts can't hold native BTC on OP_NET. All value flows through OP_20 wrapper tokens, staying compatible with Bitcoin's UTXO model.