Bancor3: Depositing BNT Tokens Code Guide

Aw Kai Shin
6 min readJun 1, 2022

--

This guide focuses on the single sided staking of BNT on Bancor3. As BNT forms the base token for the omnipool, BNT deposits are handled differently from other ERC20 tokens which is covered in a separate article here.

A consequence of the Bancor3 omnipool design is that BNT providers are supporting trades across all pools instead of specific pools. As such, the APYs for BNT liquidity providers are homogenized and reflects the whole protocol performance. From a technical standpoint, it is important to note that this design also means that there is no spot or moving average price as the price is now a function of the virtual balances which are inputted by the BancorDAO during pool bootstrapping. In other words, the BancorDAO is required to set a virtual balance ratio before trading is enabled for a pool.

Unlike non-BNT token deposits which results in the corresponding pool token (ie bnTKN) being minted, BNT differs in that bnBNT pool tokens are not minted but instead transferred from the Bancor protocol to the liquidity provider in exchange for their burning of the equivalent BNT. bnBNT pool tokens are only minted to the protocol when the BancorDAO co-invests BNT to liquidity pools. Consequently, BNT provision is best thought of as a private exchange of BNT directly for protocol owned bnBNT. There are no changes to the BNT vault balance nor staked balance when users deposit BNT.

In addition to bnBNT transfers, BNT stakes generate vBNT which is minted to the liquidity provider. vBNT is the governance token of the BancorDAO which enables creation of proposals and voting on existing proposals.

The details of the tokenomics is a topic for another day but the above summary provides a framework for the depositing of BNT in Bancor3.

States

Read

//BancorNetwork.sol
IERC20 private immutable _bnt;

_bnt refers to the BNT contract. It is used in this case to check if the token being deposited is BNT as BNT deposits are handled differently from other tokens.

//BancorNetwork.sol
IMasterVault private immutable _masterVault;

_masterVault is the master vault contract address which is initialized in the PoolCollection constructor. The master vault contract holds all the base token deposits.

Write

//BancorNetwork.sol
IBNTPool internal _bntPool;

_bntPool refers to the BNT pool contract.

//BNTPool.sol
uint256 private _stakedBalance;

_stakedBalance refers to the total staked BNT balance in the network. This variable is maintained by the BNTPool contract.

//ERC20.sol - OpenZeppelin
uint256 private _totalSupply;
mapping(address => uint256) private _balances;

Both _totalSupply, total supply of the token, and _balances, address balances for the token, are updated when there is a mint/burn event.

//BNTPool.sol
IPoolToken internal immutable _poolToken;

_poolToken refers to the BNT pool token. For deposits, BNT pool tokens are transferred from the protocol address to that of the provider.

//Vault.sol
ITokenGovernance internal immutable _bntGovernance;

_bntGovernance refers to the BNT token governance address.

//Vault.sol
ITokenGovernance internal immutable _vbntGovernance;

_vbntGovernance refers to the vBNT token address.

Depositing BNT Tokens

Source

There are 2 entry points to initiate a deposit, depositFor() and deposit(), which are both defined in BancorNetwork.sol. Both functions calls _depositFor() with a different provider address, depositFor() requires a provider’s address to be passed in while deposit() sets the msg.sender as the provider. As such, Bancor3 provides the ability for differentiating between the msg.sender from the actual provider where required.

Additionally, there are also gasless approval variations for both these cases which uses the permit function per EIP-2612 (depositPermitted() and depositForPermitted()). This guide will focus on the non-permitted versions for the sake of understanding the core deposit flow.

Code
Code

_depositFor() generates the context ID for the deposit and differentiates the next function based on whether BNT is being deposited. This token check is done using isEqual() from TokenLibrary.sol.

Code
Code

For BNT, _depositBNTFor() is then called which first queries the the BNT pool contract. Subsequently, the BNT tokens are then transferred to the the BNT pool using transferFrom() from OpenZeppelin’s ERC20.sol. Lastly, the depositFor() function is then called on the BNT pool contract.

Code

despositFor() does a number of things:

  • Calculates the pool token amount for transfer using _underlyingToPoolToken(). mulDivC() will return the smallest integer larger than or equal to bntAmount*(poolTokenSupply/stakedBalance). Recall that the staking ledger is the source of valuation for the pool token and all fees and rewards accrue to it. As such, the calculation above is returning the amount of BNT pool tokens to mint based on the current value that each existing pool token is entitled to withdraw.
  • Transfers the pool tokens from the protocol to the provider. It should be noted that the Bancor protocol is the only entity capable of providing BNT directly to the system (and therefore the only entity minting/burning bnBNT pool tokens) and hence deposits/withdrawals done by BNT users are a simple exchange with the Bancor protocol. Pool tokens are not created or destroyed as a result of BNT user actions.
  • Burn the BNT tokens received from the users deposit. This effectively means that non-protocol BNT liquidity providers burn their BNT in exchange for the protocol’s own bnBNT pool tokens.
  • Calculate the vBNT to be minted and mint vBNT to the provider.
  • Returns the amount of pool tokens which were transferred to the provider.
Code

Following the above, the total amount of pool tokens which were minted is returned to the initial deposit() and depositFor() functions. Enabling trades against a pool requires the BancorDAO to set the exchange rates which creates trading liquidity by minting the minimum BNT liquidity. Trading against a pool will be covered in greater depth in a future article.

Thanks for staying till the end. Would love to hear your thought/comments so do drop a comment. I’m active on twitter @AwKaiShin if you would like to receive more digestible tidbits of crypto-related info or visit my personal website if you would like my services :)

Bancor3 Deep Dive Series

Analysis

Smart Contract Guides

Other Links

Official Links

--

--

Aw Kai Shin

Web3, Crypto & Blockchain: Building a More Equitable Web | Technical Writer @FactorDAO | www.awkaishin.com