Templar Protocol User Guide
This is a high-level user guide for the Templar Protocol smart contracts.
For definitions of key terms and concepts, refer to the Glossary.
The API documentation can be found here.
Market
A single Templar market represents a pair of collateral and borrow assets, such as BTC/USDC for Bitcoin-collateralized USDC loans.
Suppliers may deposit borrow assets into the market, and their funds will earn yield from the protocol fees paid by borrowers. Borrowers may borrow available supply assets from the market, paying a variable interest rate based on the supply utilization rate.
Markets support NEAR fungible asset contracts implementing the NEP-141 standard or the NEP-245 standard. The borrow and collateral assets do not need to implement the same standard.
Storage Management
Before interacting with a market (supplying, borrowing, depositing collateral, etc.), accounts must first register with the market contract by making a storage deposit. This is required because the market contract implements NEP-145 (Storage Management) to cover the storage costs of maintaining user positions on-chain.
Making a Storage Deposit
To register with a market and deposit the required storage cost:
near contract call-function as-transaction \
<market-id> storage_deposit \
json-args '{}' \
prepaid-gas '10.0 Tgas' \
attached-deposit '0.00125 NEAR' \
sign-as <account-id>
The minimum required deposit can be obtained by calling the storage_balance_bounds
function:
near contract call-function as-read-only \
<market-id> storage_balance_bounds \
json-args '{}' \
network-config mainnet \
now
Note: This storage deposit step is handled automatically in the Templar frontend application, but must be done manually when interacting directly with the market contracts.
Interactions
Accounts can interact with markets in seven primary ways:
- Deposit supply
- Withdraw supply
- Deposit collateral
- Withdraw collateral
- Borrow supply
- Repay supply
- Liquidate borrow position
Configuration
A market's configuration is immutable after deployment. It can be obtained from the market contract by calling the get_configuration
function.
Example
near contract \
call-function as-read-only ibtc-usdc.v1.tmplr.near get_configuration \
json-args {} \
network-config mainnet \
now
Output
{
"borrow_asset": {
"Nep141": "17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1"
},
"borrow_asset_maximum_usage_ratio": "0.99000000000000000000000000000000000001",
"borrow_interest_rate_strategy": {
"Piecewise": {
"base": "0",
"optimal": "0.90000000000000000000000000000000000001",
"rate_1": "0.08888888888888888888888888888888888889",
"rate_2": "2.40000000000000000000000000000000000001"
}
},
"borrow_maximum_duration_ms": null,
"borrow_mcr_liquidation": "1.19999999999999999999999999999999999999",
"borrow_mcr_maintenance": "1.25",
"borrow_origination_fee": {
"Proportional": "0.00099999999999999999999999999999999999"
},
"borrow_range": {
"maximum": null,
"minimum": "1"
},
"collateral_asset": {
"Nep245": {
"contract_id": "intents.near",
"token_id": "nep141:btc.omft.near"
}
},
"liquidation_maximum_spread": "0.05000000000000000000000000000000000001",
"price_oracle_configuration": {
"account_id": "pyth-oracle.near",
"borrow_asset_decimals": 6,
"borrow_asset_price_id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a",
"collateral_asset_decimals": 8,
"collateral_asset_price_id": "e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43",
"price_maximum_age_s": 60
},
"protocol_account_id": "revenue.tmplr.near",
"supply_range": {
"maximum": null,
"minimum": "40000"
},
"supply_withdrawal_fee": {
"behavior": "Fixed",
"duration": "0",
"fee": {
"Flat": "0"
}
},
"supply_withdrawal_range": {
"maximum": null,
"minimum": "40000"
},
"time_chunk_configuration": {
"BlockTimestampMs": {
"divisor": "600000"
}
},
"yield_weights": {
"static": {
"revenue.tmplr.near": 1,
"rewards.tmplr.near": 1
},
"supply": 1
}
}
Snapshots
Interest and yield on borrow and supply positions are calculated using a snapshot system.
After a "time chunk" (e.g. 1 hour) elapses, the contract takes a snapshot, recording such things as the total supply deposit, amount borrowed, timestamp, etc.
Whenever a borrow or supply position update requires, interest/yield calculations are triggered. (They can also be triggered explicitly using harvest_yield
and apply_interest
.) These calculations iterate from the snapshot at which the record was last updated until the most-recently-finalized snapshot unless a snapshot limit is provided.
Supply
Accounts may deposit assets to the market's supply to earn yield.
Deposit
To add funds to a market's supply, send the to the contract, specifying "Supply"
as the transfer msg
.
For example:
near contract call-function as-transaction \
<borrow-asset-contract-id> ft_transfer_call \
json-args '{
"receiver_id": "<market-id>",
"amount": "<amount>",
"msg": "\"Supply\""
}' \
prepaid-gas '100.0 Tgas' \
attached-deposit '1 yoctoNEAR' \
sign-as <account-id>
Withdraw
Since borrowers borrow the assets that suppliers have supplied, when a supplier wishes to withdraw their supply, there might not be enough available to withdraw at that time. However, through fees, interest, etc., as time passes, borrow assets should become available to withdraw again.
Because the market may not have sufficient borrow asset liquidity when a supplier wishes to withdraw, the market uses a queue-based withdrawal system.
In order to withdraw supply from the market, a supplier must first enter the supply withdrawal queue with their withdrawal request:
near contract call-function as-transaction \
<market-id> create_supply_withdrawal_request \
json-args '{"amount": "<amount>"}' \
prepaid-gas '100.0 Tgas' \
attached-deposit '0 NEAR' \
sign-as <account-id>
Now the account has a position in the queue. Should the account wish to update the amount of the request, it can call create_supply_withdrawal_request
again, however, this will also reset its position to the end of the queue.
A supply withdrawal request can be cancelled via cancel_supply_withdrawal_request
.
In order for an account's supply withdrawal request to be fulfilled, all of the requests that are ahead of it in the queue must be fulfilled first.
To execute the next withdrawal request, use the execute_next_supply_withdrawal_request
function:
near contract call-function as-transaction \
<market-id> execute_next_supply_withdrawal_request \
json-args '{}' \
prepaid-gas '100.0 Tgas' \
attached-deposit '0 NEAR' \
sign-as <account-id>
This function is not permissioned; anyone may call it to advance the withdrawal queue.
Borrow
Accounts may borrow assets from the market's supply.
Borrow positions must be collateralized with a minimum amount of collateral asset determined by the market's configuration.
Deposit collateral
To add collateral to an account's position, transfer-call the market tokens with a msg
of "Collateralize"
:
near contract call-function as-transaction \
<collateral-asset-contract-id> ft_transfer_call \
json-args '{
"receiver_id": "<market-id>",
"amount": "<amount>",
"msg": "\"Collateralize\""
}' \
prepaid-gas '100.0 Tgas' \
attached-deposit '1 yoctoNEAR' \
sign-as <account-id>
Withdraw collateral
The collateral withdrawal process is relatively straightforward as compared to the supply withdrawal process: simply call withdraw_collateral
, passing the amount of collateral asset tokens you wish to withdraw:
near contract call-function as-transaction \
<market-id> withdraw_collateral \
json-args '{ "amount": "<amount>" }' \
prepaid-gas '100.0 Tgas' \
attached-deposit '0 NEAR' \
sign-as <account-id>
While this process is simple, collateral can only be withdraw so long as the value of the remaining collateral continues to satisfy the market's borrow_mcr_maintenance
requirement.
Borrow
Once an account's position is collateralized, borrow asset can be withdrawn.
near contract call-function as-transaction \
<market-id> borrow \
json-args '{ "amount": "<amount>" }' \
prepaid-gas '100.0 Tgas' \
attached-deposit '0 NEAR' \
sign-as <account-id>
As long as the collateralization requirements are met, the borrow amount (minus fees) will be sent to the predecessor account.
Repay
As long as an account has a liability (principal + interest/fees), some or all of their collateral will be locked so that it cannot be withdrawn.
To unlock the collateral, the account must repay its liability to the market.
To perform a repayment, transfer-call tokens to the market with a msg
of "Repay"
:
near contract call-function as-transaction \
<borrow-asset-contract-id> ft_transfer_call \
json-args '{
"receiver_id": "<market-id>",
"amount": "<amount>",
"msg": "\"Repay\""
}' \
prepaid-gas '100.0 Tgas' \
attached-deposit '1 yoctoNEAR' \
sign-as <account-id>
Liquidate
Liquidation is the process by which the asset collateralizing certain positions may be reappropriated e.g. to recover assets for an undercollateralized position.
A liquidator is a third party willing to send a quantity of a market's borrow asset (usually a stablecoin) to the market in exchange for the amount of collateral asset supporting a specific account's position. As compensation for this service, the liquidator receives an exchange rate that is slightly better than the current rate. This difference in rates is called the "liquidator spread," and the maximum liquidator spread is configurable on a per-market basis.
A liquidator will follow this high-level workflow:
- The liquidator obtains a list of accounts borrowing from the market by calling
list_borrow_positions
. - The liquidator checks the status of each account by calling
get_borrow_status
. - If an account's status is
Liquidation
, that means the liquidator can obtain a spread by sending an amount of borrow asset to the market. The maximum spread isliquidation_maximum_spread
in the market configuration. - To perform the liquidation, the liquidator transfer-calls the appropriate amount of borrow asset to the market. That is to say, the liquidator calls
ft_transfer_call
/mt_transfer_call
on the borrow asset's smart contract, specifying the market as the receiver. Themsg
parameter indicates 1) that the transfer is for a liquidation, and 2) which account is to be liquidated.
Thus, the arguments to a liquidation call might look something like this:
{
"amount": "<amount>",
"msg": {
"Liquidate": {
"account_id": "<account-to-liquidate>"
}
},
"receiver_id": "<market-id>"
}
It is the responsibility of the liquidator to calculate the optimal amount of tokens to attach to a liquidation call. The market will either completely accept or completely reject the liquidation attempt—no refunds!
Example
near contract call-function as-transaction \
<borrow-asset-contract-id> ft_transfer_call \
json-args '{
"receiver_id": "<market-id>",
"amount": "<amount>",
"msg": "{ \"Liquidate\": { \"account_id\": \"<account-to-liquidate>\" } }"
}' \
prepaid-gas '100.0 Tgas' \
attached-deposit '1 yoctoNEAR' \
sign-as <account-id>
Glossary
This glossary provides definitions for key terms used throughout the Templar Protocol documentation and smart contracts.
A
APY (Annual Percentage Yield) : The total return on an investment over one year, including compound interest. In Templar, this represents the effective yearly return for suppliers or the cost for borrowers.
Asset Pair : The combination of collateral asset and borrow asset that defines a market (e.g., BTC/USDC means Bitcoin collateral, USDC borrowing).
B
Borrow Asset : The token that users can borrow from the market. Typically a stablecoin like USDC, but can be any supported token.
Borrow Position : A user's borrowing account containing collateral deposits, borrowed amounts, accumulated interest, and current status.
Borrower : A user who deposits collateral and borrows assets from the market, paying interest on the borrowed amount.
C
Collateral Asset : The token deposited by borrowers to secure their loans. Must be worth more than the borrowed amount due to over-collateralization requirements.
Collateralization Ratio (CR) : The ratio of collateral value to borrowed value. A 150% ratio means $150 of collateral backs $100 of debt.
Compounding : The process of automatically reinvesting earned yield to generate additional returns over time.
D
Debt : The total amount owed by a borrower, including principal plus accumulated interest and fees.
F
FMV (Fair Market Value) : The current market price of an asset as determined by oracle price feeds.
G
Gas : The computational cost for executing transactions on the NEAR blockchain.
H
Harvest Yield : The action of claiming accumulated yield from a supply position. Can be withdrawn or compounded.
I
Interest Accumulation : The process of calculating and adding accrued interest to a borrower's total liability.
L
Lending : The general practice of providing assets to borrowers in exchange for interest payments. In Templar, suppliers lend to the market pool.
Liability : The total debt owed by a borrower, including principal, accumulated interest, and fees.
Liquidation : The forced sale of a borrower's collateral when their position becomes undercollateralized or expires.
Liquidator : A third party who performs liquidations by repaying part of a borrower's debt in exchange for discounted collateral.
Liquidator Spread : The discount liquidators receive when purchasing collateral, serving as incentive for providing the liquidation service.
Liquidity : The availability of assets in the market for borrowing or withdrawal. When liquidity is low, withdrawal requests may need to wait in the queue.
Liquidity Pool : The combined supply of assets deposited by all suppliers in a market, available for borrowers to access.
M
Market : A smart contract managing lending and borrowing for a specific asset pair (e.g., BTC/USDC market).
Maximum Usage Ratio : The maximum percentage of supplied assets that can be borrowed from a market, preventing over-utilization and maintaining liquidity reserves.
MCR (Minimum Collateralization Ratio) : The minimum ratio of collateral value to borrowed value required to maintain a position. Different MCR levels trigger maintenance requirements or liquidation.
MCR Liquidation : The minimum collateralization ratio below which a position becomes eligible for liquidation.
MCR Maintenance : The minimum collateralization ratio required for new borrows or collateral withdrawals.
N
NEAR Intents : A NEAR Protocol feature that allows users to express desired outcomes (intents) that can be fulfilled by solvers, enabling more flexible and efficient transaction execution. See the official NEAR Intents documentation.
NEP-141 : The NEAR Protocol standard for fungible tokens, similar to Ethereum's ERC-20. See the official NEP-141 specification.
NEP-245 : The NEAR Protocol standard for multi-token contracts, similar to Ethereum's ERC-1155. See the official NEP-245 specification.
O
Oracle : A service providing real-time price data for assets, essential for calculating collateralization ratios and liquidations.
Origination Fee : A fee charged when creating a new borrow position, can be flat amount or percentage-based.
Over-collateralization : The requirement for borrowers to deposit collateral worth more than the borrowed amount, providing a safety buffer against price volatility.
P
Partial Liquidation : Liquidating only enough collateral to bring a position back to the maintenance MCR, rather than liquidating the entire position.
Principal : The original amount borrowed or supplied, excluding accumulated interest and fees.
Protocol Revenue : Fees collected by the protocol from borrowers and suppliers, distributed to suppliers and other accounts according to configured yield weights.
Pyth Network : A decentralized oracle network providing high-frequency price feeds for various assets.
R
Registry : A smart contract that manages deployment and versioning of market contracts within the Templar Protocol.
Repay : The action of returning borrowed assets plus interest to reduce or eliminate a borrower's debt.
S
Snapshot : A point-in-time record of market state including interest rates, asset amounts, and yield distribution.
Stablecoin : A cryptocurrency designed to maintain stable value, typically pegged to a fiat currency like USD. Commonly used as borrow assets in lending protocols.
Static Yield : A fixed allocation of market revenue to specific accounts, independent of their supply activity. Defined in the market's yield_weights configuration, static yield is distributed proportionally to designated accounts and can be withdrawn using the withdraw_static_yield function.
Supply : The total amount of assets deposited by suppliers that are available for borrowing in a market.
Supplier : A user who deposits assets into the market to earn yield from borrower interest payments.
Supply Withdrawal Fee : A fee charged when suppliers withdraw their assets from the market, configured per market to manage liquidity.
T
Time Chunk : A configurable time period (based on blocks, epochs, or timestamps) that determines when new snapshots are created.
Transfer Call : A token transfer that includes data, allowing the receiving contract to execute logic based on the transfer.
U
Undercollateralized : A borrow position where the collateral value falls below the required minimum ratio, making it eligible for liquidation.
Utilization Rate
: The percentage of supplied assets currently borrowed. Calculated as: borrowed_amount / total_supplied_amount
.
W
Withdrawal Queue : A first-in-first-out system for processing supply withdrawals when market liquidity is insufficient.
Y
Yield : The return earned by suppliers on their deposited assets, generated from borrower interest payments and fees.
Notes
Sending funds to the market contract
When sending funds to a contract, you must call the asset contract's *_transfer_call
function with the market as the receiver_id
. So, for a token contract that implements the NEP-141 (Fungible Token) standard, you must call ft_transfer_call
, specifying the market account ID as the receiver_id
argument. For a token contract that implements the NEP-245 (Multi Token) standard, you must call mt_transfer_call
.
If the funds are not sent using a *_transfer_call
function, the contract will not be able to respond to the transfer: the funds will not be tracked by the contract, they will not be added to the supply, and the funds cannot be returned or withdrawn.
Contract interaction syntax
Contract interactions will be shown using near-cli-rs
syntax. It can be installed via:
cargo install near-cli-rs
Example
near contract call-function as-transaction \
ibtc-usdc.v1.tmplr.near borrow \
json-args '{ "amount": "1000" }' \
prepaid-gas '100.0 Tgas' \
attached-deposit '0 NEAR' \
sign-as account.near \
network-config mainnet \
sign-with-keychain \
send
This command calls the function borrow
on the contract ibtc-usdc.v1.tmplr.near
with the arguments payload:
{
"amount": "1000"
}
Large numbers are serialized as strings instead of numerical literals to ensure that the precision limitations of JSON parsers do not affect the values. (See "Notes on Serialization" on docs.near.org.)
The command attaches 100 teragas units and 0 NEAR to the call, signs the transaction as account.near
using a key saved to the local keychain, and sends the transaction to NEAR mainnet.
Please refer to the near-cli-rs
user guide for more details.