This function is only callable by the admin of the contract.
Function to add a new market and automatically deploy a new AMM and a Controller from the implementation contracts (see Implementations). Additionally, when initializing a new market, rate_write() from the MonetaryPolicy contract is called to check if it has a correct ABI.
Returns: AMM and Controller contracts (address).
Emits: AddNewMarket
Input
Type
Description
token
address
Collateral token address
A
uint256
Amplification coefficient. One band size is 1/n
fee
uint256
AMM fee in the market's AMM
admin_fee
uint256
AMM admin fee
_price_oracle_contract
address
Address of the price oracle contract for the market
monetary_policy
address
Monetary policy for the market
loan_discount
uint256
Loan Discount: allowed to borrow only up to x_down * (1 - loan_discount)
liquidation_discount
uint256
Discount defining a bad liquidation threshold
debt_ceiling
uint256
Debt ceiling for the market
Warning
There are some limitation values for adding new markets regarding fee, A and liquidation_discount.
Source code
# LimitsMIN_A:constant(uint256)=2MAX_A:constant(uint256)=10000MIN_FEE:constant(uint256)=10**6# 1e-12, still needs to be above 0MAX_FEE:constant(uint256)=10**17# 10%MAX_ADMIN_FEE:constant(uint256)=10**18# 100%MAX_LOAN_DISCOUNT:constant(uint256)=5*10**17MIN_LIQUIDATION_DISCOUNT:constant(uint256)=10**16@external@nonreentrant('lock')defadd_market(token:address,A:uint256,fee:uint256,admin_fee:uint256,_price_oracle_contract:address,monetary_policy:address,loan_discount:uint256,liquidation_discount:uint256,debt_ceiling:uint256)->address[2]:""" @notice Add a new market, creating an AMM and a Controller from a blueprint @param token Collateral token address @param A Amplification coefficient; one band size is 1/A @param fee AMM fee in the market's AMM @param admin_fee AMM admin fee @param _price_oracle_contract Address of price oracle contract for this market @param monetary_policy Monetary policy for this market @param loan_discount Loan discount: allowed to borrow only up to x_down * (1 - loan_discount) @param liquidation_discount Discount which defines a bad liquidation threshold @param debt_ceiling Debt ceiling for this market @return (Controller, AMM) """assertmsg.sender==self.admin,"Only admin"assertA>=MIN_AandA<=MAX_A,"Wrong A"assertfee<=MAX_FEE,"Fee too high"assertfee>=MIN_FEE,"Fee too low"assertadmin_fee<MAX_ADMIN_FEE,"Admin fee too high"assertliquidation_discount>=MIN_LIQUIDATION_DISCOUNT,"Liquidation discount too low"assertloan_discount<=MAX_LOAN_DISCOUNT,"Loan discount too high"assertloan_discount>liquidation_discount,"need loan_discount>liquidation_discount"MonetaryPolicy(monetary_policy).rate_write()# Test that MonetaryPolicy has correct ABIp:uint256=PriceOracle(_price_oracle_contract).price()# This also validates price oracle ABIassertp>0assertPriceOracle(_price_oracle_contract).price_w()==pA_ratio:uint256=10**18*A/(A-1)amm:address=create_from_blueprint(self.amm_implementation,STABLECOIN.address,10**(18-STABLECOIN.decimals()),token,10**(18-ERC20(token).decimals()),# <- This validates ERC20 ABIA,isqrt(A_ratio*10**18),self.ln_int(A_ratio),p,fee,admin_fee,_price_oracle_contract,code_offset=3)controller:address=create_from_blueprint(self.controller_implementation,token,monetary_policy,loan_discount,liquidation_discount,amm,code_offset=3)AMM(amm).set_admin(controller)self._set_debt_ceiling(controller,debt_ceiling,True)N:uint256=self.n_collateralsself.collaterals[N]=tokenforiinrange(1000):ifself.collaterals_index[token][i]==0:self.collaterals_index[token][i]=2**128+Nbreakasserti!=999,"Too many controllers for same collateral"self.controllers[N]=controllerself.amms[N]=ammself.n_collaterals=N+1logAddMarket(token,controller,amm,monetary_policy,N)return[controller,amm]
@internal@viewdefcalculate_rate()->uint256:sigma:int256=self.sigmatarget_debt_fraction:uint256=self.target_debt_fractionp:int256=convert(PRICE_ORACLE.price(),int256)pk_debt:uint256=0forpkinself.peg_keepers:ifpk.address==empty(address):breakpk_debt+=pk.debt()power:int256=(10**18-p)*10**18/sigma# high price -> negative pow -> low rateifpk_debt>0:total_debt:uint256=CONTROLLER_FACTORY.total_debt()iftotal_debt==0:return0else:power-=convert(pk_debt*10**18/total_debt*10**18/target_debt_fraction,int256)returnself.rate0*min(self.exp(power),MAX_EXP)/10**18@externaldefrate_write()->uint256:# Not needed here but useful for more automated policies# which change rate0 - for example rate0 targeting some fraction pl_debt/total_debtreturnself.calculate_rate()
@external@viewdefprice()->uint256:n:uint256=self.n_price_pairsprices:uint256[MAX_PAIRS]=empty(uint256[MAX_PAIRS])D:uint256[MAX_PAIRS]=empty(uint256[MAX_PAIRS])Dsum:uint256=0DPsum:uint256=0foriinrange(MAX_PAIRS):ifi==n:breakprice_pair:PricePair=self.price_pairs[i]pool_supply:uint256=price_pair.pool.totalSupply()ifpool_supply>=MIN_LIQUIDITY:p:uint256=price_pair.pool.price_oracle()ifprice_pair.is_inverse:p=10**36/pprices[i]=p_D:uint256=price_pair.pool.get_virtual_price()*pool_supply/10**18D[i]=_DDsum+=_DDPsum+=_D*pifDsum==0:return10**18# Placeholder for no active poolsp_avg:uint256=DPsum/Dsume:uint256[MAX_PAIRS]=empty(uint256[MAX_PAIRS])e_min:uint256=max_value(uint256)foriinrange(MAX_PAIRS):ifi==n:breakp:uint256=prices[i]e[i]=(max(p,p_avg)-min(p,p_avg))**2/(SIGMA**2/10**18)e_min=min(e[i],e_min)wp_sum:uint256=0w_sum:uint256=0foriinrange(MAX_PAIRS):ifi==n:breakw:uint256=D[i]*self.exp(-convert(e[i]-e_min,int256))/10**18w_sum+=wwp_sum+=w*prices[i]returnwp_sum/w_sum
@externaldefset_admin(_admin:address):""" @notice Set admin of the AMM. Typically it's a controller (unless it's tests) @param _admin Admin address """assertself.admin==empty(address)self.admin=_adminself.approve_max(BORROWED_TOKEN,_admin)self.approve_max(COLLATERAL_TOKEN,_admin)