Scope sees all prices in one glance.
Scope is a price oracle aggregator living on the Solana network. It copies data from multiple on-chain oracles' accounts into one "price feed".
Scope prevalidate the prices with a preset of rules and perform the update only if they meet the criteria.
The repository contains two software:
scope
on-chain program.scope-cli
that provide administration commands and a bot feature to trigger the price feed update.
- The association between an price at a given index in the price feed and the token pair associated to this price need is not stored on chain.
- A price feed is currently limited to 512 prices.
- If you do not have access to the Kamino source code, scope can still be built. See Building without Kamino ktokens for more details.
- Support different refresh rates in the bot (stacked stable coin price change less often than other token).
- Open creation of price feed to any user who will became admin of the feed.
- Allow extensible price feed (when resizable account feature is available in Solana mainnet)
- For simplification let's say we only refresh at most 3 prices per IX.
- In this example, we have 10 prices in scope named A, B, C, D, E, F, G, H, I, J.
- We refresh any price older than 30 slots.
- If we fire an IX, we fill the IX as much as possible (minimum refresh size is 3).
- Price age is given by source oracle (pyth) not the current slot of refresh.
- Starting ages: A: 0, B: 5, C: 10, D: 15, E: 20, F: 25, G: 30, H: 35, I: 5, J: 10
- Refresh old prices:
- Sort price by ages (oldest first) H, G, F, E, D, C, J, B, I, A
- Divide by chunk of 3
- For each chunk if oldest price is more than 30, refresh chunk
- Only one refreshed chunk H, G, F
- After refresh operation new price ages is: A: 5, B: 10, C: 15, D: 20, E: 25, F: 12, G: 3, H: 3, I: 10, J: 15 (All prices are older by 5 slots about the time to execute the ix, and just refreshed prices are not at 0 because age come from the oracle)
- Get the new oldest price: E: 25, so sleep for 5 slot (400ms*5).
- Loop
- Starting ages: A: 10, B: 15, C: 20, D: 25, E: 30, F: 17, G: 8, H: 8, I: 15, J: 20
- Refresh old prices:
- Sort price by ages (oldest first) E, D, C, J, B, I, F, A, G, H
- Divide by chunk of 3
- For each chunk if oldest price is more than 30, refresh chunk
- Only one refreshed chunk E, D, C
- After refresh operation new price ages is: A: 15, B: 20, C: 3, D: 5, E: 3, F: 22, G: 13, H: 13, I: 20, J: 25
- Get the new oldest price: J: 25, so sleep for 5 slot (400ms*5).
- Loop
- For your price feed
make build
export CLUSTER=mainnet
export URL=<url>
RUST_BACKTRACE=1 cargo run -p scope-cli -- --keypair <keypair.json> --program-id HFn8GnPADiny6XqUoWE8uRPPxb29ikn4yTuPa9MF2fWJ --price-feed hubble crank --mapping ./configs/mainnet/hubble.json
If you do not have access to the Kamino source code, you can still build scope without the default yvaults
feature:
- Replace the
yvaults
dependency in./programs/scope/Cargo.toml
with theyvaults_stub
package:
[dependencies]
# Comment out the git repo
#yvaults = { git = "ssh://[email protected]/hubbleprotocol/yvault.git", features = ["no-entrypoint", "cpi", "mainnet"], optional = true }
# Add this line
yvaults = { path = "../yvaults_stub", package = "yvaults_stub", optional = true }
- Build scope with the following command:
anchor build -p scope -- --no-default-features --features mainnet
- Build the CLI:
cargo build -p scope-cli --no-default-features --features rpc-client