Skip to content

Commit f22f802

Browse files
add seahorse example
1 parent d0d6e9c commit f22f802

File tree

18 files changed

+1540
-0
lines changed

18 files changed

+1540
-0
lines changed

oracles/pyth/seahorse/.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
.anchor
3+
.DS_Store
4+
target
5+
**/*.rs.bk
6+
node_modules
7+
test-ledger

oracles/pyth/seahorse/.prettierignore

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
.anchor
3+
.DS_Store
4+
target
5+
node_modules
6+
dist
7+
build
8+
test-ledger

oracles/pyth/seahorse/Anchor.toml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[features]
2+
seeds = true
3+
skip-lint = false
4+
[programs.localnet]
5+
seahorse = "9USP8f9ooxUxWTyqrQSDfyiXE1FP7Wfsg34NfAbdK1ur"
6+
7+
[registry]
8+
url = "https://api.apr.dev"
9+
10+
[provider]
11+
cluster = "Localnet"
12+
wallet = "~/.config/solana/id.json"
13+
14+
[scripts]
15+
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
16+
17+
[test.validator]
18+
url = "https://api.mainnet-beta.solana.com"
19+
20+
[[test.validator.clone]]
21+
address = "H6ARHf6YXhGYeQfUzQNGk6rDNnLBQKrenN712K4AQJEG"

oracles/pyth/seahorse/Cargo.toml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[workspace]
2+
members = [
3+
"programs/*"
4+
]
5+
6+
[profile.release]
7+
overflow-checks = true
8+
lto = "fat"
9+
codegen-units = 1
10+
[profile.release.build-override]
11+
opt-level = 3
12+
incremental = false
13+
codegen-units = 1

oracles/pyth/seahorse/README.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# seahorse
2+
3+
This project was created by Seahorse 0.2.7.
4+
5+
To get started, just add your code to **programs_py/seahorse.py** and run `seahorse build`.
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Migrations are an early feature. Currently, they're nothing more than this
2+
// single deploy script that's invoked from the CLI, injecting a provider
3+
// configured from the workspace's Anchor.toml.
4+
5+
const anchor = require("@coral-xyz/anchor");
6+
7+
module.exports = async function (provider) {
8+
// Configure client to use the provider.
9+
anchor.setProvider(provider);
10+
11+
// Add your deploy script here.
12+
};

oracles/pyth/seahorse/package.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"scripts": {
3+
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
4+
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
5+
},
6+
"dependencies": {
7+
"@coral-xyz/anchor": "^0.27.0"
8+
},
9+
"devDependencies": {
10+
"chai": "^4.3.4",
11+
"mocha": "^9.0.3",
12+
"ts-mocha": "^10.0.0",
13+
"@types/bn.js": "^5.1.0",
14+
"@types/chai": "^4.3.0",
15+
"@types/mocha": "^9.0.0",
16+
"typescript": "^4.3.5",
17+
"prettier": "^2.6.2"
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[package]
2+
name = "seahorse"
3+
version = "0.1.0"
4+
description = "Created with Anchor"
5+
edition = "2021"
6+
7+
[lib]
8+
crate-type = ["cdylib", "lib"]
9+
name = "seahorse"
10+
11+
[features]
12+
no-entrypoint = []
13+
no-idl = []
14+
no-log-ix-name = []
15+
cpi = ["no-entrypoint"]
16+
default = []
17+
18+
[dependencies]
19+
anchor-lang = "0.27.0"
20+
anchor-spl = "0.27.0"
21+
pyth-sdk-solana = { version = "0.7.1" }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[target.bpfel-unknown-unknown.dependencies.std]
2+
features = []
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod program;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#![allow(unused_imports)]
2+
#![allow(unused_variables)]
3+
#![allow(unused_mut)]
4+
use crate::{id, seahorse_util::*};
5+
use anchor_lang::{prelude::*, solana_program};
6+
use anchor_spl::token::{self, Mint, Token, TokenAccount};
7+
use pyth_sdk_solana::load_price_feed_from_account_info;
8+
use std::{cell::RefCell, rc::Rc};
9+
10+
pub fn get_pyth_price_handler<'info>(
11+
mut pyth_price_account: UncheckedAccount<'info>,
12+
mut signer: SeahorseSigner<'info, '_>,
13+
) -> () {
14+
let mut price_feed = {
15+
if pyth_price_account.key()
16+
!= Pubkey::new_from_array([
17+
239u8, 13u8, 139u8, 111u8, 218u8, 44u8, 235u8, 164u8, 29u8, 161u8, 93u8, 64u8,
18+
149u8, 209u8, 218u8, 57u8, 42u8, 13u8, 47u8, 142u8, 208u8, 198u8, 199u8, 188u8,
19+
15u8, 76u8, 250u8, 200u8, 194u8, 128u8, 181u8, 109u8,
20+
])
21+
{
22+
panic!("Pyth PriceAccount validation failed: expected mainnet-SOL/USD")
23+
}
24+
25+
load_price_feed_from_account_info(&pyth_price_account).unwrap()
26+
};
27+
28+
{
29+
let price = price_feed.get_price_unchecked();
30+
31+
(price.price as f64) * 10f64.powf(price.expo as f64)
32+
};
33+
34+
let mut price = price_feed.get_price_unchecked();
35+
let mut x = {
36+
let price = price;
37+
38+
(price.price as f64) * 10f64.powf(price.expo as f64)
39+
};
40+
41+
let mut p = price.price;
42+
let mut c = price.conf;
43+
let mut e = price.expo;
44+
45+
solana_program::msg!("{} {}", "Pyth price: ".to_string(), x);
46+
47+
solana_program::msg!("{} {}", "Pyth price: ".to_string(), p);
48+
49+
solana_program::msg!("{} {}", "Pyth confidence interval: ".to_string(), c);
50+
51+
solana_program::msg!("{} {}", "Pyth account decimal exponent: ".to_string(), e);
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#![allow(unused_imports)]
2+
#![allow(unused_variables)]
3+
#![allow(unused_mut)]
4+
5+
pub mod dot;
6+
7+
use anchor_lang::prelude::*;
8+
use anchor_spl::{
9+
associated_token::{self, AssociatedToken},
10+
token::{self, Mint, Token, TokenAccount},
11+
};
12+
13+
use dot::program::*;
14+
use std::{cell::RefCell, rc::Rc};
15+
16+
declare_id!("9USP8f9ooxUxWTyqrQSDfyiXE1FP7Wfsg34NfAbdK1ur");
17+
18+
pub mod seahorse_util {
19+
use super::*;
20+
21+
#[cfg(feature = "pyth-sdk-solana")]
22+
pub use pyth_sdk_solana::{load_price_feed_from_account_info, PriceFeed};
23+
use std::{collections::HashMap, fmt::Debug, ops::Deref};
24+
25+
pub struct Mutable<T>(Rc<RefCell<T>>);
26+
27+
impl<T> Mutable<T> {
28+
pub fn new(obj: T) -> Self {
29+
Self(Rc::new(RefCell::new(obj)))
30+
}
31+
}
32+
33+
impl<T> Clone for Mutable<T> {
34+
fn clone(&self) -> Self {
35+
Self(self.0.clone())
36+
}
37+
}
38+
39+
impl<T> Deref for Mutable<T> {
40+
type Target = Rc<RefCell<T>>;
41+
42+
fn deref(&self) -> &Self::Target {
43+
&self.0
44+
}
45+
}
46+
47+
impl<T: Debug> Debug for Mutable<T> {
48+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49+
write!(f, "{:?}", self.0)
50+
}
51+
}
52+
53+
impl<T: Default> Default for Mutable<T> {
54+
fn default() -> Self {
55+
Self::new(T::default())
56+
}
57+
}
58+
59+
impl<T: Clone> Mutable<Vec<T>> {
60+
pub fn wrapped_index(&self, mut index: i128) -> usize {
61+
if index >= 0 {
62+
return index.try_into().unwrap();
63+
}
64+
65+
index += self.borrow().len() as i128;
66+
67+
return index.try_into().unwrap();
68+
}
69+
}
70+
71+
impl<T: Clone, const N: usize> Mutable<[T; N]> {
72+
pub fn wrapped_index(&self, mut index: i128) -> usize {
73+
if index >= 0 {
74+
return index.try_into().unwrap();
75+
}
76+
77+
index += self.borrow().len() as i128;
78+
79+
return index.try_into().unwrap();
80+
}
81+
}
82+
83+
#[derive(Clone)]
84+
pub struct Empty<T: Clone> {
85+
pub account: T,
86+
pub bump: Option<u8>,
87+
}
88+
89+
#[derive(Clone, Debug)]
90+
pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>);
91+
92+
impl<'info> ProgramsMap<'info> {
93+
pub fn get(&self, name: &'static str) -> AccountInfo<'info> {
94+
self.0.get(name).unwrap().clone()
95+
}
96+
}
97+
98+
#[derive(Clone, Debug)]
99+
pub struct WithPrograms<'info, 'entrypoint, A> {
100+
pub account: &'entrypoint A,
101+
pub programs: &'entrypoint ProgramsMap<'info>,
102+
}
103+
104+
impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> {
105+
type Target = A;
106+
107+
fn deref(&self) -> &Self::Target {
108+
&self.account
109+
}
110+
}
111+
112+
pub type SeahorseAccount<'info, 'entrypoint, A> =
113+
WithPrograms<'info, 'entrypoint, Box<Account<'info, A>>>;
114+
115+
pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>;
116+
117+
#[derive(Clone, Debug)]
118+
pub struct CpiAccount<'info> {
119+
#[doc = "CHECK: CpiAccounts temporarily store AccountInfos."]
120+
pub account_info: AccountInfo<'info>,
121+
pub is_writable: bool,
122+
pub is_signer: bool,
123+
pub seeds: Option<Vec<Vec<u8>>>,
124+
}
125+
126+
#[macro_export]
127+
macro_rules! seahorse_const {
128+
($ name : ident , $ value : expr) => {
129+
macro_rules! $name {
130+
() => {
131+
$value
132+
};
133+
}
134+
135+
pub(crate) use $name;
136+
};
137+
}
138+
139+
#[macro_export]
140+
macro_rules! assign {
141+
($ lval : expr , $ rval : expr) => {{
142+
let temp = $rval;
143+
144+
$lval = temp;
145+
}};
146+
}
147+
148+
#[macro_export]
149+
macro_rules! index_assign {
150+
($ lval : expr , $ idx : expr , $ rval : expr) => {
151+
let temp_rval = $rval;
152+
let temp_idx = $idx;
153+
154+
$lval[temp_idx] = temp_rval;
155+
};
156+
}
157+
158+
pub(crate) use assign;
159+
160+
pub(crate) use index_assign;
161+
162+
pub(crate) use seahorse_const;
163+
}
164+
165+
#[program]
166+
mod seahorse {
167+
use super::*;
168+
use seahorse_util::*;
169+
use std::collections::HashMap;
170+
171+
#[derive(Accounts)]
172+
pub struct GetPythPrice<'info> {
173+
#[account()]
174+
#[doc = "CHECK: This account is unchecked."]
175+
pub pyth_price_account: UncheckedAccount<'info>,
176+
#[account(mut)]
177+
pub signer: Signer<'info>,
178+
}
179+
180+
pub fn get_pyth_price(ctx: Context<GetPythPrice>) -> Result<()> {
181+
let mut programs = HashMap::new();
182+
let programs_map = ProgramsMap(programs);
183+
let pyth_price_account = &ctx.accounts.pyth_price_account.clone();
184+
let signer = SeahorseSigner {
185+
account: &ctx.accounts.signer,
186+
programs: &programs_map,
187+
};
188+
189+
get_pyth_price_handler(pyth_price_account.clone(), signer.clone());
190+
191+
return Ok(());
192+
}
193+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# seahorse
2+
# Built with Seahorse v0.2.7
3+
4+
from seahorse.prelude import *
5+
from seahorse.pyth import *
6+
7+
declare_id('9USP8f9ooxUxWTyqrQSDfyiXE1FP7Wfsg34NfAbdK1ur')
8+
9+
@instruction
10+
def get_pyth_price(
11+
pyth_price_account: PriceAccount,
12+
signer: Signer,
13+
):
14+
price_feed = pyth_price_account.validate_price_feed("SOL/USD")
15+
price_feed.get_price().num()
16+
17+
price = price_feed.get_price()
18+
19+
x: f64 = price.num()
20+
p: i64 = price.price
21+
c: u64 = price.conf
22+
e: i32 = price.expo
23+
24+
25+
print("Pyth price: ", x)
26+
print("Pyth price without decimals: ", p)
27+
print("Pyth confidence interval: ", c)
28+
print("Pyth account decimal exponent: ", e)
29+
30+
31+
32+

oracles/pyth/seahorse/programs_py/seahorse/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)