A one-way lending market is a non-rehypothecating market where one token is considered the collateral token and another token is the borrow token. This means the deposited collateral cannot be lent out but can only be used as collateral.
GitHub
The source code of the OneWayLendingFactory.vy contract can be found on GitHub.
Later on, two-way lending markets will be established, allowing the collateral provided to be lent out and used as liquidity to borrow.
Regarding rates: Minimum and maximum borrow rates for lending markets default to min_default_borrow_rate and max_default_borrow_rate if input values for min_borrow_rate and max_borrow_rate are set to zero. If custom values are used, they need to be within the range of MIN_RATE and MAX_RATE.
Custom minimum borrow rate; if not set will default to min_default_borrow_rate
max_borrow_rate
uint256
Custom maximum borrow rate; if not set will default to max_default_borrow_rate
Source code
eventNewVault:id:indexed(uint256)collateral_token:indexed(address)borrowed_token:indexed(address)vault:addresscontroller:addressamm:addressprice_oracle:addressmonetary_policy:address@external@nonreentrant('lock')defcreate(borrowed_token:address,collateral_token:address,A:uint256,fee:uint256,loan_discount:uint256,liquidation_discount:uint256,price_oracle:address,name:String[64],min_borrow_rate:uint256=0,max_borrow_rate:uint256=0)->Vault:""" @notice Creation of the vault using user-supplied price oracle contract @param borrowed_token Token which is being borrowed @param collateral_token Token used for collateral @param A Amplification coefficient: band size is ~1/A @param fee Fee for swaps in AMM (for ETH markets found to be 0.6%) @param loan_discount Maximum discount. LTV = sqrt(((A - 1) / A) ** 4) - loan_discount @param liquidation_discount Liquidation discount. LT = sqrt(((A - 1) / A) ** 4) - liquidation_discount @param price_oracle Custom price oracle contract @param name Human-readable market name @param min_borrow_rate Custom minimum borrow rate (otherwise min_default_borrow_rate) @param max_borrow_rate Custom maximum borrow rate (otherwise max_default_borrow_rate) """returnself._create(borrowed_token,collateral_token,A,fee,loan_discount,liquidation_discount,price_oracle,name,min_borrow_rate,max_borrow_rate)@internaldef_create(borrowed_token:address,collateral_token:address,A:uint256,fee:uint256,loan_discount:uint256,liquidation_discount:uint256,price_oracle:address,name:String[64],min_borrow_rate:uint256,max_borrow_rate:uint256)->Vault:""" @notice Internal method for creation of the vault """assertborrowed_token!=collateral_token,"Same token"assertborrowed_token==STABLECOINorcollateral_token==STABLECOINvault:Vault=Vault(create_minimal_proxy_to(self.vault_impl))min_rate:uint256=self.min_default_borrow_ratemax_rate:uint256=self.max_default_borrow_rateifmin_borrow_rate>0:min_rate=min_borrow_rateifmax_borrow_rate>0:max_rate=max_borrow_rateassertmin_rate>=MIN_RATEandmax_rate<=MAX_RATEandmin_rate<=max_rate,"Wrong rates"monetary_policy:address=create_from_blueprint(self.monetary_policy_impl,borrowed_token,min_rate,max_rate,code_offset=3)controller:address=empty(address)amm:address=empty(address)controller,amm=vault.initialize(self.amm_impl,self.controller_impl,borrowed_token,collateral_token,A,fee,price_oracle,monetary_policy,loan_discount,liquidation_discount)market_count:uint256=self.market_countlogNewVault(market_count,collateral_token,borrowed_token,vault.address,controller,amm,price_oracle,monetary_policy)self.vaults[market_count]=vaultself.amms[market_count]=AMM(amm)self._vaults_index[vault]=market_count+2**128self.names[market_count]=nameself.market_count=market_count+1token:address=borrowed_tokenifborrowed_token==STABLECOIN:token=collateral_tokenmarket_count=self.token_market_count[token]self.token_to_vaults[token][market_count]=vaultself.token_market_count[token]=market_count+1ERC20(borrowed_token).approve(amm,max_value(uint256))ERC20(collateral_token).approve(amm,max_value(uint256))returnvault
>>>OneWayLendingVaultFactory.create("0xf939e0a03fb07f59a73314e73794be0e57ac1b4e",# borrowed_token"0x8f22779662ad253844013d8e99eccb4d80e31417",# collateral_token50,# A6000000000000000,# fee140000000000000000,# loan_discount110000000000000000,# liquidation_discountexternalpriceoracle,# price_oracle"bobrCRV-long",# name0,# min_borrow_rate1)# max_borrow_rate'0xE16D806c4198955534d4EB10E4861Ea94557602E'# returns address of the created vault
Only oracles from stableswap-ng, twocrypto-ng, and tricrypto-ng pools are valid. Oracles from other pools may not be manipulation resistant and therefore should not be used.
Function to create a new vault using a existing oraclized Curve pool as the price oracle.
Returns: vault (address).
Emits: NewVault
Input
Type
Description
borrowed_token
address
Token which is being borrowed.
collateral_token
address
Token used as collateral.
A
uint256
Amplification coefficient. Band size is ~1/A.
fee
uint256
Fee for swaps in the AMM.
loan_discount
uint256
Maximum discount. LTV = sqrt(((A - 1) / A) ** 4) - loan_discount.
Curve tricrypto-ng, twocrypto-ng or stableswap-ng pool which has non-manipulatable price_oracle(). Must contain both collateral_token and borrowed_token.
name
String[64]
Name of the vault.
min_borrow_rate
uint256
Custom minimum borrow rate; if not set will default to min_default_borrow_rate
max_borrow_rate
uint256
Custom maximum borrow rate; if not set will default to max_default_borrow_rate
Source code
eventNewVault:id:indexed(uint256)collateral_token:indexed(address)borrowed_token:indexed(address)vault:addresscontroller:addressamm:addressprice_oracle:addressmonetary_policy:address@external@nonreentrant('lock')defcreate_from_pool(borrowed_token:address,collateral_token:address,A:uint256,fee:uint256,loan_discount:uint256,liquidation_discount:uint256,pool:address,name:String[64],min_borrow_rate:uint256=0,max_borrow_rate:uint256=0)->Vault:""" @notice Creation of the vault using existing oraclized Curve pool as a price oracle @param borrowed_token Token which is being borrowed @param collateral_token Token used for collateral @param A Amplification coefficient: band size is ~1/A @param fee Fee for swaps in AMM (for ETH markets found to be 0.6%) @param loan_discount Maximum discount. LTV = sqrt(((A - 1) / A) ** 4) - loan_discount @param liquidation_discount Liquidation discount. LT = sqrt(((A - 1) / A) ** 4) - liquidation_discount @param pool Curve tricrypto-ng, twocrypto-ng or stableswap-ng pool which has non-manipulatable price_oracle(). Must contain both collateral_token and borrowed_token. @param name Human-readable market name @param min_borrow_rate Custom minimum borrow rate (otherwise min_default_borrow_rate) @param max_borrow_rate Custom maximum borrow rate (otherwise max_default_borrow_rate) """# Find coins in the poolborrowed_ix:uint256=100collateral_ix:uint256=100N:uint256=0foriinrange(10):success:bool=Falseres:Bytes[32]=empty(Bytes[32])success,res=raw_call(pool,_abi_encode(i,method_id=method_id("coins(uint256)")),max_outsize=32,is_static_call=True,revert_on_failure=False)coin:address=convert(res,address)ifnotsuccessorcoin==empty(address):breakN+=1ifcoin==borrowed_token:borrowed_ix=ielifcoin==collateral_token:collateral_ix=iifcollateral_ix==100orborrowed_ix==100:raise"Tokens not in pool"price_oracle:address=create_from_blueprint(self.pool_price_oracle_impl,pool,N,borrowed_ix,collateral_ix,code_offset=3)returnself._create(borrowed_token,collateral_token,A,fee,loan_discount,liquidation_discount,price_oracle,name,min_borrow_rate,max_borrow_rate)@internaldef_create(borrowed_token:address,collateral_token:address,A:uint256,fee:uint256,loan_discount:uint256,liquidation_discount:uint256,price_oracle:address,name:String[64],min_borrow_rate:uint256,max_borrow_rate:uint256)->Vault:""" @notice Internal method for creation of the vault """assertborrowed_token!=collateral_token,"Same token"assertborrowed_token==STABLECOINorcollateral_token==STABLECOINvault:Vault=Vault(create_minimal_proxy_to(self.vault_impl))min_rate:uint256=self.min_default_borrow_ratemax_rate:uint256=self.max_default_borrow_rateifmin_borrow_rate>0:min_rate=min_borrow_rateifmax_borrow_rate>0:max_rate=max_borrow_rateassertmin_rate>=MIN_RATEandmax_rate<=MAX_RATEandmin_rate<=max_rate,"Wrong rates"monetary_policy:address=create_from_blueprint(self.monetary_policy_impl,borrowed_token,min_rate,max_rate,code_offset=3)controller:address=empty(address)amm:address=empty(address)controller,amm=vault.initialize(self.amm_impl,self.controller_impl,borrowed_token,collateral_token,A,fee,price_oracle,monetary_policy,loan_discount,liquidation_discount)market_count:uint256=self.market_countlogNewVault(market_count,collateral_token,borrowed_token,vault.address,controller,amm,price_oracle,monetary_policy)self.vaults[market_count]=vaultself.amms[market_count]=AMM(amm)self._vaults_index[vault]=market_count+2**128self.names[market_count]=nameself.market_count=market_count+1token:address=borrowed_tokenifborrowed_token==STABLECOIN:token=collateral_tokenmarket_count=self.token_market_count[token]self.token_to_vaults[token][market_count]=vaultself.token_market_count[token]=market_count+1ERC20(borrowed_token).approve(amm,max_value(uint256))ERC20(collateral_token).approve(amm,max_value(uint256))returnvault
>>>OneWayLendingVaultFactory.create_from_pool("0xf939e0a03fb07f59a73314e73794be0e57ac1b4e",# borrowed_token"0x8f22779662ad253844013d8e99eccb4d80e31417",# collateral_token50,# A6000000000000000,# fee140000000000000016,# loan_discount110000000000000000,# liquidation_discount"0x9fee65d5a627e73212989c8bbedc5fa5cae3821f",# pool to use oracle from"bobrCRV-long",# name0,# min_borrow_rate1)# max_borrow_rate'0xE16D806c4198955534d4EB10E4861Ea94557602E'# returns address of the created vault
eventLiquidityGaugeDeployed:vault:addressgauge:address@externaldefdeploy_gauge(_vault:Vault)->address:""" @notice Deploy a liquidity gauge for a vault @param _vault Vault address to deploy a gauge for @return Address of the deployed gauge """ix:uint256=self._vaults_index[_vault]assertix!=0,"Unknown vault"ix-=2**128assertself.gauges[ix]==empty(address),"Gauge already deployed"implementation:address=self.gauge_implassertimplementation!=empty(address),"Gauge implementation not set"gauge:address=create_from_blueprint(implementation,_vault,code_offset=3)self.gauges[ix]=gaugelogLiquidityGaugeDeployed(_vault.address,gauge)returngauge
In[1]:OneWayLendingVaultFactory.deploy_gauge("0xE16D806c4198955534d4EB10E4861Ea94557602E")Out[1]:'0xACEBA186aDF691245dfb20365B48DB87DEA7b98F'# returns address of deployed gauge
The Factory has a MIN_RATE and MAX_RATE. These variables are constants and can not be changed. The minimum rate is 0.1%, the maximum rate is 1000%.
Additionally, the Factory has two variables, min_default_borrow_rate and max_default_borrow_rate, which are used as default values when creating new lending markets. If no value is given when deploying a new market, the default rates are applied. Default rates can be changed by the admin via the set_default_rates method.
Rates are denominated in seconds and have a base unit of 1e18.
Getter for the minimum default borrow rate which is used when creating a new vault. The minimum borrow rate is charged when the utilization is 0. This parameter can be changed via the set_default_rates function.
Returns: minimum default borrow rate (uint256).
Source code
min_default_borrow_rate:public(uint256)@external@nonreentrant('lock')defset_default_rates(min_rate:uint256,max_rate:uint256):""" @notice Change min and max default borrow rates for creating new markets @param min_rate Minimal borrow rate (0 utilization) @param max_rate Maxumum borrow rate (100% utilization) """assertmsg.sender==self.adminassertmin_rate>=MIN_RATEassertmax_rate<=MAX_RATEassertmax_rate>=min_rateself.min_default_borrow_rate=min_rateself.max_default_borrow_rate=max_ratelogSetDefaultRates(min_rate,max_rate)
Getter for the maximum default borrow rate which is used when creating a new vault. The maximum borrow rate is charged when the utilization is 100%. This parameter can be changed via the set_default_rates function.
Returns: maximum default borrow rate (uint256).
Source code
max_default_borrow_rate:public(uint256)@external@nonreentrant('lock')defset_default_rates(min_rate:uint256,max_rate:uint256):""" @notice Change min and max default borrow rates for creating new markets @param min_rate Minimal borrow rate (0 utilization) @param max_rate Maxumum borrow rate (100% utilization) """assertmsg.sender==self.adminassertmin_rate>=MIN_RATEassertmax_rate<=MAX_RATEassertmax_rate>=min_rateself.min_default_borrow_rate=min_rateself.max_default_borrow_rate=max_ratelogSetDefaultRates(min_rate,max_rate)
This function is only callable by the admin of the contract.
Function to set new implementations. If a certain implementation should not be changed, ZER0_ADDRESS can be used as a placeholder.
Emits: SetImplementations
Input
Type
Description
controller
address
New controller implementation.
amm
address
New amm implementation.
vault
address
New vault implementation.
pool_price_oracle
address
New pool price oracle implementation.
monetary_policy
address
New monetary policy implementation.
gauge
address
New gauge implementation.
Source code
eventSetImplementations:amm:addresscontroller:addressvault:addressprice_oracle:addressmonetary_policy:addressgauge:address# Implementations which can be changed by governanceamm_impl:public(address)controller_impl:public(address)vault_impl:public(address)pool_price_oracle_impl:public(address)monetary_policy_impl:public(address)gauge_impl:public(address)@external@nonreentrant('lock')defset_implementations(controller:address,amm:address,vault:address,pool_price_oracle:address,monetary_policy:address,gauge:address):""" @notice Set new implementations (blueprints) for controller, amm, vault, pool price oracle and monetary polcy. Doesn't change existing ones @param controller Address of the controller blueprint @param amm Address of the AMM blueprint @param vault Address of the Vault template @param pool_price_oracle Address of the pool price oracle blueprint @param monetary_policy Address of the monetary policy blueprint @param gauge Address for gauge implementation blueprint """assertmsg.sender==self.adminifcontroller!=empty(address):self.controller_impl=controllerifamm!=empty(address):self.amm_impl=ammifvault!=empty(address):self.vault_impl=vaultifpool_price_oracle!=empty(address):self.pool_price_oracle_impl=pool_price_oracleifmonetary_policy!=empty(address):self.monetary_policy_impl=monetary_policyifgauge!=empty(address):self.gauge_impl=gaugelogSetImplementations(amm,controller,vault,pool_price_oracle,monetary_policy,gauge)
This function is only callable by the admin of the contract.
Function to change the contract ownership by setting a new admin.
Emits: SetAdmin
Input
Type
Description
admin
address
New admin address.
Source code
eventSetAdmin:admin:addressadmin:public(address)@external@nonreentrant('lock')defset_admin(admin:address):""" @notice Set admin of the factory (should end up with DAO) @param admin Address of the admin """assertmsg.sender==self.adminself.admin=adminlogSetAdmin(admin)
Getter for the total market count. This value represents the total number of lending vaults created through this factory. This value is incremented by 1 whenever the internal _create function is called.
Returns: market count (uint256).
Source code
market_count:public(uint256)@internaldef_create(borrowed_token:address,collateral_token:address,A:uint256,fee:uint256,loan_discount:uint256,liquidation_discount:uint256,price_oracle:address,name:String[64],min_borrow_rate:uint256,max_borrow_rate:uint256)->Vault:""" @notice Internal method for creation of the vault """...market_count:uint256=self.market_countself.market_count=market_count+1...
token_market_count:public(HashMap[address,uint256])@internaldef_create(borrowed_token:address,collateral_token:address,A:uint256,fee:uint256,loan_discount:uint256,liquidation_discount:uint256,price_oracle:address,name:String[64],min_borrow_rate:uint256,max_borrow_rate:uint256)->Vault:""" @notice Internal method for creation of the vault """...token:address=borrowed_tokenifborrowed_token==STABLECOIN:token=collateral_tokenmarket_count=self.token_market_count[token]self.token_to_vaults[token][market_count]=vaultself.token_market_count[token]=market_count+1...
In[1]:OneWayLendingVaultFactory.token_market_count("0xD533a949740bb3306d119CC777fa900bA034cd52")Out[1]:2In[2]:OneWayLendingVaultFactory.token_market_count("0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E")Out[2]:0# market count of crvusd will always return 0, because the token is included in every vault (market)