Links

UniswapV3PriceProvider

UniswapV3PriceProvider
Price provider contract that reads prices from UniswapV3

Methods

acceptOwnership

function acceptOwnership() external nonpayable
Transfers ownership of the contract to a pending owner Can only be called by the pending owner.

adjustOracleCardinality

function adjustOracleCardinality(address _asset) external nonpayable
Adjust UniV3 pool cardinality to Silo's requirements
This could be used manually to setup pool, so it will be ready to use in the future. There is only one case, when it could be needed: if we have more than one pool for _asset and you want to use UniswapV3 but the pool does not have enough observations (liquidity == 1). You can run this method manually and it will set valid number of observations, so the pool can be used once price data is ready.

Parameters

Name
Type
Description
_asset
address
asset used to lookup the pool address to increase the cardinality for

assetSupported

function assetSupported(address _asset) external view returns (bool supported)
Informs if PriceProvider is setup for asset. It does not means PriceProvider can provide price right away. Some providers implementations need time to "build" buffor for TWAP price, so price may not be available yet but this method will return true.

Parameters

Name
Type
Description
_asset
address
asset in question

Returns

Name
Type
Description
supported
bool
TRUE if asset has been setup, otherwise false

changeBlockTime

function changeBlockTime(uint8 _blockTime) external nonpayable
Change block time which is used to adjust oracle cardinality fot providing TWAP prices

Parameters

Name
Type
Description
_blockTime
uint8
it is better to set it bit lower than higher that avg block time eg. if ETH block time is 13~13.5s, you can set it to 11-12s based on priceCalculationData.periodForAvgPrice and priceCalculationData.blockTime price provider calculates number of blocks for (cardinality) requires for TWAP price. Unfortunately block time can change and this can lead to issues with getting price. Edge case will be when we set _blockTime to 1, then we have 100% guarantee, that no matter how real block time changes, we always can get price. Downside will be cost of initialization. That's why it is better to set a bit lower and adjust (decrease) in case of issues.

changePeriodForAvgPrice

function changePeriodForAvgPrice(uint32 _period) external nonpayable
Change period for which to calcualted TWAP prices
WARNING: There is a possibility that when we change this period, UniV3 pool that is already initialized and set as oracle for asset, can throw. This can happen when it will not be able calculate TWAP for new period and it can potentially lock the Silo until we have necessary observations. If UniV3 is NOT only available oracle for asset, we can change the oracle and Silo will be unlocked.

Parameters

Name
Type
Description
_period
uint32
new period in seconds, ie. 1800 means 30 min

getPrice

function getPrice(address _asset) external view returns (uint256 price)
Returns "Time-Weighted Average Price" for an asset. Calculates TWAP price for quote/asset. It unifies all tokens decimal to 18, examples: - if asses == quote it returns 1e18 - if asset is USDC and quote is ETH and ETH costs ~$3300 then it returns ~0.0003e18 WETH per 1 USDC
UniV3 saves price only on: mint, burn and swap. Mint and burn will write observation only when "current tick is inside the passed range" of ticks. I think that means, that if we minting/burning outside ticks range (so outside current price) it will not modify observation. So we left with swap. Swap will write observation under this condition: // update tick and write an oracle entry if the tick change if (state.tick != slot0Start.tick) { that means, it is possible that price will be up to date (in a range of same tick) but observation timestamp will be old. Every pool by default comes with just one slot for observation (cardinality == 1). We can increase number of slots so TWAP price will be "better". When we increase, we have to wait until new tx will write new observation. Based on all above, we can tell how old is observation, but this does not mean the price is wrong. UniV3 recommends to use observe and OracleLibrary.consult uses it. observe reverts if secondsAgos > oldest observation, means, if there is any price observation in selected time frame, it will revert. Otherwise it will return either exact TWAP price or by interpolation. Conclusion: we can choose how many observation pool will be storing, but we need to remember, not all of them might be used to provide our price. Final question is: how many observations we need? How UniV3 calculates TWAP we ask for TWAP on time range ago:now using OracleLibrary.consult, it is all about find the right tick - we call IUniswapV3Pool(pool).observe(secondAgos) that returns two accumulator values (for ago and now) - each observation is resolved by observeSingle - for now we just using latest observation, and if it does not match timestamp, we interpolate (!) and this is how we got the tickCumulative, so in extreme situation, if last observation was made day ago, UniV3 will interpolate to reflect tickCumulative at current time - for ago we search for observation using getSurroundingObservations that give us before and after observation, base on which we calculate "avg" and we have target tickCumulative - getSurroundingObservations: it's job is to find 2 observations based on which we calculate tickCumulative here is where all calculations can revert, if ago < oldest observation, otherwise it will be calculated either by interpolation or we will have exact match - now with both _tickCumulative_s we calculating TWAP recommended observations are = 30 min / blockTime

Parameters

Name
Type
Description
_asset
address
address of an asset for which to read price

Returns

Name
Type
Description
price
uint256
of asses with 18 decimals, throws when pool is not ready yet to provide price

hasEnoughObservations

function hasEnoughObservations(address _pool) external view returns (bool, uint32 oldestObservationTimestamp)
Check if UniV3 pool has enough cardinality to meet Silo's requirements

Parameters

Name
Type
Description
_pool
address
UniV3 pool address

Returns

Name
Type
Description
_0
bool
TURE if has enough observations
oldestObservationTimestamp
uint32
timestamp of the oldest observation

owner

function owner() external view returns (address)
Returns the address of the current owner.

Returns

Name
Type
Description
_0
address
undefined

pendingOwner

function pendingOwner() external view returns (address)
Returns the address of the pending owner.

Returns

Name
Type
Description
_0
address
undefined

pools

function pools(address) external view returns (contract IUniswapV3Pool)
Maps asset address to UniV3 pool

Parameters

Name
Type
Description
_0
address
undefined

Returns

Name
Type
Description
_0
contract IUniswapV3Pool
undefined

priceCalculationData

function priceCalculationData() external view returns (uint32 periodForAvgPrice, uint8 blockTime)
priceCalculationData: - periodForAvgPrice: Number of seconds for which time-weighted average should be calculated, ie. 1800 is 30 min - blockTime: Estimated blockchain block time

Returns

Name
Type
Description
periodForAvgPrice
uint32
undefined
blockTime
uint8
undefined

priceProviderPing

function priceProviderPing() external pure returns (bool)
Helper method that allows easily detects, if contract is PriceProvider
this can save us from simple human errors, in case we use invalid address but this should NOT be treated as security check

Returns

Name
Type
Description
_0
bool
always true

priceProvidersRepository

function priceProvidersRepository() external view returns (contract IPriceProvidersRepository)
PriceProvidersRepository address

Returns

Name
Type
Description
_0
contract IPriceProvidersRepository
undefined

quoteToken

function quoteToken() external view returns (address)
Token address which prices are quoted in. Must be the same as PriceProvidersRepository.quoteToken

Returns

Name
Type
Description
_0
address
undefined

renounceOwnership

function renounceOwnership() external nonpayable
Leaves the contract without owner. It will not be possible to call onlyOwner functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.

setupAsset

function setupAsset(address _asset, contract IUniswapV3Pool _pool) external nonpayable
Setup pool for asset. Use it also for update.

Parameters

Name
Type
Description
_asset
address
asset address
_pool
contract IUniswapV3Pool
UniV3 pool address

transferOwnership

function transferOwnership(address newOwner) external nonpayable
Transfers ownership of the contract to a new account (newOwner). Can only be called by the current owner.

Parameters

Name
Type
Description
newOwner
address
undefined

transferPendingOwnership

function transferPendingOwnership(address newPendingOwner) external nonpayable
Transfers pending ownership of the contract to a new account (newPendingOwner). Can only be called by the current owner.

Parameters

Name
Type
Description
newPendingOwner
address
undefined

uniswapV3Factory

function uniswapV3Factory() external view returns (contract IUniswapV3Factory)
UniswapV3 factory contract

Returns

Name
Type
Description
_0
contract IUniswapV3Factory
undefined

verifyPool

function verifyPool(address _asset, contract IUniswapV3Pool _pool) external view returns (bool)
It verifies if provider pool for asset (and quote token) is valid. Throws when there is no pool or pool is empty (zero liquidity).

Parameters

Name
Type
Description
_asset
address
asset for which prices are going to be calcualted
_pool
contract IUniswapV3Pool
UniV3 pool address

Returns

Name
Type
Description
_0
bool
true if verification successful, otherwise throws

Events

NewBlockTime

event NewBlockTime(uint8 blockTime)
Emitted when blockTime changes

Parameters

Name
Type
Description
blockTime
uint8
block time in seconds

NewPeriod

event NewPeriod(uint32 period)
Emitted when TWAP period changes

Parameters

Name
Type
Description
period
uint32
new period in seconds, ie. 1800 means 30 min

OwnershipPending

event OwnershipPending(address indexed previousOwner, address indexed newOwner)

Parameters

Name
Type
Description
previousOwner indexed
address
undefined
newOwner indexed
address
undefined

OwnershipTransferred

event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)

Parameters

Name
Type
Description
previousOwner indexed
address
undefined
newOwner indexed
address
undefined

PoolForAsset

event PoolForAsset(address indexed asset, contract IUniswapV3Pool indexed pool)
Emitted when UniV3 pool is set for asset

Parameters

Name
Type
Description
asset indexed
address
asset address
pool indexed
contract IUniswapV3Pool
UniV3 pool address