Prices
The mine pays per dollar, so it has to know what a token is worth. It asks a price source. Each listed token has one, chosen by the owner when the token is listed and replaceable afterwards.
The price is the only outside input the mine has. Everything else, the rate table, the thresholds, the pool, is fixed in the contract.
In short
- One interface, two implementations: a manual source and a Chainlink source.
- A stale price blocks nothing and is the price used.
- A source that reverts makes its token count as
$0and blocks new stakes of it. - Settlement of a position with no price is skipped, never zeroed.
- The price read at settlement is applied to the whole interval.
One interface
Every price source answers one question, and the mine does not care how.
interface IPriceSource {
function priceUsd(address token)
external view
returns (uint256 price1e18, uint256 updatedAt);
}price1e18 is the USD price of one whole token with 18 decimals. updatedAt is the unix second at which that price was set. The mine turns an amount into dollars the same way everywhere.
usd value = amount x price / 10^decimals40 tokens priced at $250 is a position of $10,000. If the price moves to $300, the same tokens are a position of $12,000 and the tribute per day moves with it. The amount never changed.
The owner can point a token at a different source with setPriceSource, which emits PriceSourceSet. The token keeps its position and its history.
The manual source
ManualPriceSource stores a price per token. The owner, or an address holding the keeper role, pushes prices with setPrice or setPrices for several at once. Each push stamps updatedAt with the block time and emits PriceSet.
This is the source used for the proof of concept and for testnet. It has no view on the market. It reports exactly what was last pushed into it.
A token that has been listed but never priced reads $0, with an updatedAt of 0. The source does not fail in that case, it answers zero. So the token can be staked, it counts as $0 in TVL, and it accrues nothing until a price arrives.
The Chainlink source
ChainlinkPriceSource holds one AggregatorV3 feed per token, set by the owner with setFeed. It reads latestRoundData, normalizes the feed's decimals to 18, and passes the feed's own update time through as updatedAt.
It refuses two cases rather than reporting a wrong number.
FeedNotSetwhen the token has no feed.InvalidAnswerwhen the feed answers zero or below.
Both are reverts, so both land in the section on a source that stops answering, below. The two sources sit behind the same interface, and a token can move from one to the other without touching any position.
Listed tokens
The current set, with the price the mine reads and the time it was set, is live in the mine. The owner can list and delist at any time, so the contract is the only current answer. Anything written here would be a launch list, not the set.
listedTokens returns what can be staked right now. allTokens returns everything the mine has ever tracked, which is the set that still counts toward TVL.
Stale prices
The mine has a constant, MAX_STALENESS, set to 7 days. isStale(token) is true when the price is older than that, when the source does not answer, or when the token was never listed.
Staleness is surfaced and never enforced. A stale price blocks nothing. Staking, unstaking and claiming all work, and the stale price is the price used. The mine reports the age so you can decide what to do about it. It does not decide for you.
Weekends and market close
Stock markets close. The mine does not. When the market is shut, the last pushed price stands, and tribute keeps accruing against it. A position priced on Friday evening accrues all weekend at the Friday price.
Monday's first price does not backdate anything. It becomes the price of the next settlement, and that settlement covers the whole weekend at the Monday price.
When a source stops answering
The mine reads every price inside a try and catch. A source that reverts does not take the mine down with it. It changes four things, and nothing else.
- It counts as
$0in TVL. TVL falls while the source is down, which can delay a crossing. It can never undo one, because the level does not go back. stakeof that token reverts withPriceUnavailable. Other tokens are unaffected.- Settlement of a position in that token is skipped, not zeroed. Its last settled time is kept, so the interval is still there and is paid when the price returns.
- Nothing else. Unstake and claim are never blocked by a price. Claim pays out what was already settled. Unstake returns the token.
One consequence is worth knowing. If you unstake while the source is down, the skipped interval is settled later against whatever is left in the position. Unstaking during an outage gives up the accrual of the part you took out for that interval. Claiming first does not help, because claim also skips that position. Waiting for the price does.
The price at settlement is the price you get
The mine keeps no price history. When a position settles, the price is read once and the whole unsettled interval is paid at that one price. A month untouched is a month paid at the price of the day it is finally settled.
This is the largest approximation in the mine. A time weighted price and price checkpoints are V2. Risks states what it costs, including who else can decide when your position settles.