diff --git a/basics/program-derived-addresses/seahorse/.gitignore b/basics/program-derived-addresses/seahorse/.gitignore new file mode 100644 index 000000000..2e0446b07 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/.gitignore @@ -0,0 +1,7 @@ +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn diff --git a/basics/program-derived-addresses/seahorse/.prettierignore b/basics/program-derived-addresses/seahorse/.prettierignore new file mode 100644 index 000000000..414258343 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/.prettierignore @@ -0,0 +1,7 @@ +.anchor +.DS_Store +target +node_modules +dist +build +test-ledger diff --git a/basics/program-derived-addresses/seahorse/Anchor.toml b/basics/program-derived-addresses/seahorse/Anchor.toml new file mode 100644 index 000000000..5fbafa0d7 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/Anchor.toml @@ -0,0 +1,19 @@ +[toolchain] + +[features] +resolution = true +skip-lint = false +seeds = true + +[programs.localnet] +program_derived_addresses_seahorse = "3AZUzzM9zVoeW1gmkjUYaWWGvHSvmmsajtzJLcgGcEQP" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "devnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/basics/program-derived-addresses/seahorse/Cargo.toml b/basics/program-derived-addresses/seahorse/Cargo.toml new file mode 100644 index 000000000..f39770481 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/Cargo.toml @@ -0,0 +1,14 @@ +[workspace] +members = [ + "programs/*" +] +resolver = "2" + +[profile.release] +overflow-checks = true +lto = "fat" +codegen-units = 1 +[profile.release.build-override] +opt-level = 3 +incremental = false +codegen-units = 1 diff --git a/basics/program-derived-addresses/seahorse/README.md b/basics/program-derived-addresses/seahorse/README.md new file mode 100644 index 000000000..e91db26b7 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/README.md @@ -0,0 +1,5 @@ +# program_derived_addresses_seahorse + +This project was created by Seahorse 0.2.0. + +To get started, just add your code to **programs_py/program_derived_addresses_seahorse.py** and run `seahorse build`. diff --git a/basics/program-derived-addresses/seahorse/migrations/deploy.ts b/basics/program-derived-addresses/seahorse/migrations/deploy.ts new file mode 100644 index 000000000..82fb175fa --- /dev/null +++ b/basics/program-derived-addresses/seahorse/migrations/deploy.ts @@ -0,0 +1,12 @@ +// Migrations are an early feature. Currently, they're nothing more than this +// single deploy script that's invoked from the CLI, injecting a provider +// configured from the workspace's Anchor.toml. + +const anchor = require("@coral-xyz/anchor"); + +module.exports = async function (provider) { + // Configure client to use the provider. + anchor.setProvider(provider); + + // Add your deploy script here. +}; diff --git a/basics/program-derived-addresses/seahorse/package.json b/basics/program-derived-addresses/seahorse/package.json new file mode 100644 index 000000000..04daffe1b --- /dev/null +++ b/basics/program-derived-addresses/seahorse/package.json @@ -0,0 +1,20 @@ +{ + "license": "ISC", + "scripts": { + "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", + "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.30.1" + }, + "devDependencies": { + "chai": "^4.3.4", + "mocha": "^9.0.3", + "ts-mocha": "^10.0.0", + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^9.0.0", + "typescript": "^4.3.5", + "prettier": "^2.6.2" + } +} diff --git a/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/Cargo.toml b/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/Cargo.toml new file mode 100644 index 000000000..d2f6a492e --- /dev/null +++ b/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "program_derived_addresses_seahorse" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "program_derived_addresses_seahorse" + +[features] +default = [] +cpi = ["no-entrypoint"] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +idl-build = ["anchor-lang/idl-build"] + +[dependencies] +anchor-lang = "0.30.1" +anchor-spl = "0.30.1" diff --git a/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/Xargo.toml b/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/Xargo.toml new file mode 100644 index 000000000..475fb71ed --- /dev/null +++ b/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/src/dot/mod.rs b/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/src/dot/mod.rs new file mode 100644 index 000000000..e2c04eaaa --- /dev/null +++ b/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/src/dot/mod.rs @@ -0,0 +1 @@ +pub mod program; diff --git a/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/src/dot/program.rs b/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/src/dot/program.rs new file mode 100644 index 000000000..a47737f18 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/src/dot/program.rs @@ -0,0 +1,58 @@ +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] +use crate::{id, seahorse_util::*}; +use anchor_lang::{prelude::*, solana_program}; +use anchor_spl::token::{self, Mint, Token, TokenAccount}; +use std::{cell::RefCell, rc::Rc}; + +#[account] +#[derive(Debug)] +pub struct PageVisits { + pub visits: u32, +} + +impl<'info, 'entrypoint> PageVisits { + pub fn load( + account: &'entrypoint mut Box>, + programs_map: &'entrypoint ProgramsMap<'info>, + ) -> Mutable> { + let visits = account.visits; + + Mutable::new(LoadedPageVisits { + __account__: account, + __programs__: programs_map, + visits, + }) + } + + pub fn store(loaded: Mutable) { + let mut loaded = loaded.borrow_mut(); + let visits = loaded.visits; + + loaded.__account__.visits = visits; + } +} + +#[derive(Debug)] +pub struct LoadedPageVisits<'info, 'entrypoint> { + pub __account__: &'entrypoint mut Box>, + pub __programs__: &'entrypoint ProgramsMap<'info>, + pub visits: u32, +} + +pub fn create_page_visits_handler<'info>( + mut owner: SeahorseSigner<'info, '_>, + mut page_visits: Empty>>, +) -> () { + page_visits.account.clone(); +} + +pub fn increment_page_visits_handler<'info>( + mut page_visits: Mutable>, +) -> () { + assign!( + page_visits.borrow_mut().visits, + page_visits.borrow().visits + 1 + ); +} diff --git a/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/src/lib.rs b/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/src/lib.rs new file mode 100644 index 000000000..ae9a7d657 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/programs/program_derived_addresses_seahorse/src/lib.rs @@ -0,0 +1,280 @@ +#![allow(unused_imports)] +#![allow(unused_variables)] +#![allow(unused_mut)] + +pub mod dot; + +use anchor_lang::prelude::*; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token::{self, Mint, Token, TokenAccount}, +}; + +use dot::program::*; +use std::{cell::RefCell, rc::Rc}; + +declare_id!("3AZUzzM9zVoeW1gmkjUYaWWGvHSvmmsajtzJLcgGcEQP"); + +pub mod seahorse_util { + use super::*; + use std::{ + collections::HashMap, + fmt::Debug, + ops::{Deref, Index, IndexMut}, + }; + + pub struct Mutable(Rc>); + + impl Mutable { + pub fn new(obj: T) -> Self { + Self(Rc::new(RefCell::new(obj))) + } + } + + impl Clone for Mutable { + fn clone(&self) -> Self { + Self(self.0.clone()) + } + } + + impl Deref for Mutable { + type Target = Rc>; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl Debug for Mutable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + + impl Default for Mutable { + fn default() -> Self { + Self::new(T::default()) + } + } + + pub trait IndexWrapped { + type Output; + + fn index_wrapped(&self, index: i128) -> &Self::Output; + } + + pub trait IndexWrappedMut: IndexWrapped { + fn index_wrapped_mut(&mut self, index: i128) -> &mut ::Output; + } + + impl IndexWrapped for Vec { + type Output = T; + + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += self.len() as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index(index) + } + } + + impl IndexWrappedMut for Vec { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += self.len() as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) + } + } + + impl IndexWrapped for [T; N] { + type Output = T; + + fn index_wrapped(&self, mut index: i128) -> &Self::Output { + if index < 0 { + index += N as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index(index) + } + } + + impl IndexWrappedMut for [T; N] { + fn index_wrapped_mut(&mut self, mut index: i128) -> &mut ::Output { + if index < 0 { + index += N as i128; + } + + let index: usize = index.try_into().unwrap(); + + self.index_mut(index) + } + } + + #[derive(Clone)] + pub struct Empty { + pub account: T, + pub bump: Option, + } + + #[derive(Clone, Debug)] + pub struct ProgramsMap<'info>(pub HashMap<&'static str, AccountInfo<'info>>); + + impl<'info> ProgramsMap<'info> { + pub fn get(&self, name: &'static str) -> AccountInfo<'info> { + self.0.get(name).unwrap().clone() + } + } + + #[derive(Clone, Debug)] + pub struct WithPrograms<'info, 'entrypoint, A> { + pub account: &'entrypoint A, + pub programs: &'entrypoint ProgramsMap<'info>, + } + + impl<'info, 'entrypoint, A> Deref for WithPrograms<'info, 'entrypoint, A> { + type Target = A; + + fn deref(&self) -> &Self::Target { + &self.account + } + } + + pub type SeahorseAccount<'info, 'entrypoint, A> = + WithPrograms<'info, 'entrypoint, Box>>; + + pub type SeahorseSigner<'info, 'entrypoint> = WithPrograms<'info, 'entrypoint, Signer<'info>>; + + #[derive(Clone, Debug)] + pub struct CpiAccount<'info> { + #[doc = "CHECK: CpiAccounts temporarily store AccountInfos."] + pub account_info: AccountInfo<'info>, + pub is_writable: bool, + pub is_signer: bool, + pub seeds: Option>>, + } + + #[macro_export] + macro_rules! seahorse_const { + ($ name : ident , $ value : expr) => { + macro_rules! $name { + () => { + $value + }; + } + + pub(crate) use $name; + }; + } + + pub trait Loadable { + type Loaded; + + fn load(stored: Self) -> Self::Loaded; + + fn store(loaded: Self::Loaded) -> Self; + } + + macro_rules! Loaded { + ($ name : ty) => { + <$name as Loadable>::Loaded + }; + } + + pub(crate) use Loaded; + + #[macro_export] + macro_rules! assign { + ($ lval : expr , $ rval : expr) => {{ + let temp = $rval; + + $lval = temp; + }}; + } + + #[macro_export] + macro_rules! index_assign { + ($ lval : expr , $ idx : expr , $ rval : expr) => { + let temp_rval = $rval; + let temp_idx = $idx; + + $lval[temp_idx] = temp_rval; + }; + } + + pub(crate) use assign; + + pub(crate) use index_assign; + + pub(crate) use seahorse_const; +} + +#[program] +mod program_derived_addresses_seahorse { + use super::*; + use seahorse_util::*; + use std::collections::HashMap; + + #[derive(Accounts)] + pub struct CreatePageVisits<'info> { + #[account(mut)] + pub owner: Signer<'info>, + # [account (init , space = std :: mem :: size_of :: < dot :: program :: PageVisits > () + 8 , payer = owner , seeds = ["page_visits" . as_bytes () . as_ref () , owner . key () . as_ref ()] , bump)] + pub page_visits: Box>, + pub rent: Sysvar<'info, Rent>, + pub system_program: Program<'info, System>, + } + + pub fn create_page_visits(ctx: Context) -> Result<()> { + let mut programs = HashMap::new(); + + programs.insert( + "system_program", + ctx.accounts.system_program.to_account_info(), + ); + + let programs_map = ProgramsMap(programs); + let owner = SeahorseSigner { + account: &ctx.accounts.owner, + programs: &programs_map, + }; + + let page_visits = Empty { + account: dot::program::PageVisits::load(&mut ctx.accounts.page_visits, &programs_map), + bump: Some(ctx.bumps.page_visits), + }; + + create_page_visits_handler(owner.clone(), page_visits.clone()); + + dot::program::PageVisits::store(page_visits.account); + + return Ok(()); + } + + #[derive(Accounts)] + pub struct IncrementPageVisits<'info> { + #[account(mut)] + pub page_visits: Box>, + } + + pub fn increment_page_visits(ctx: Context) -> Result<()> { + let mut programs = HashMap::new(); + let programs_map = ProgramsMap(programs); + let page_visits = + dot::program::PageVisits::load(&mut ctx.accounts.page_visits, &programs_map); + + increment_page_visits_handler(page_visits.clone()); + + dot::program::PageVisits::store(page_visits); + + return Ok(()); + } +} diff --git a/basics/program-derived-addresses/seahorse/programs_py/program_derived_addresses_seahorse.py b/basics/program-derived-addresses/seahorse/programs_py/program_derived_addresses_seahorse.py new file mode 100644 index 000000000..106e0d549 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/programs_py/program_derived_addresses_seahorse.py @@ -0,0 +1,17 @@ +# program_derived_addresses_seahorse +# Built with Seahorse v0.2.0 + +from seahorse.prelude import * + +declare_id('3AZUzzM9zVoeW1gmkjUYaWWGvHSvmmsajtzJLcgGcEQP') + +class PageVisits(Account): + visits: u32 + +@instruction +def create_page_visits(owner: Signer, page_visits: Empty[PageVisits]): + page_visits.init(payer = owner, seeds = ['page_visits', owner]) + +@instruction +def increment_page_visits(page_visits: PageVisits): + page_visits.visits += 1 diff --git a/basics/program-derived-addresses/seahorse/programs_py/seahorse/__init__.py b/basics/program-derived-addresses/seahorse/programs_py/seahorse/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/basics/program-derived-addresses/seahorse/programs_py/seahorse/prelude.py b/basics/program-derived-addresses/seahorse/programs_py/seahorse/prelude.py new file mode 100644 index 000000000..d7f012230 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/programs_py/seahorse/prelude.py @@ -0,0 +1,1062 @@ +# seahorse.prelude: the basis for writing Seahorse programs. +# +# NOTE: this file just contains types and documentation for your editor. This +# is NOT executable code, and you won't be able to change the behavior of your +# Seahorse programs by editing this file. + +from typing import * +from math import floor, ceil + +T = TypeVar('T') +N = TypeVar('N') + + +# ========== +# Rust types +# ========== + +class u8: + """8-bit unsigned integer.""" + + def __init__(self, _: Any) -> 'u8': + """Construct an u8.""" + + def __add__(self, other: 'u8') -> 'u8': + pass + + def __radd__(self, other: 'u8') -> 'u8': + pass + + def __iadd__(self, other: 'u8') -> 'u8': + pass + + def __sub__(self, other: 'u8') -> 'u8': + pass + + def __rsub__(self, other: 'u8') -> 'u8': + pass + + def __isub__(self, other: 'u8') -> 'u8': + pass + + def __mul__(self, other: 'u8') -> 'u8': + pass + + def __rmul__(self, other: 'u8') -> 'u8': + pass + + def __imul__(self, other: 'u8') -> 'u8': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'u8') -> 'u8': + pass + + def __rfloordiv__(self, other: 'u8') -> 'u8': + pass + + def __ifloordiv__(self, other: 'u8') -> 'u8': + pass + + def __lt__(self, other: 'u8') -> bool: + pass + + def __le__(self, other: 'u8') -> bool: + pass + + def __eq__(self, other: 'u8') -> bool: + pass + + def __ne__(self, other: 'u8') -> bool: + pass + + def __ge__(self, other: 'u8') -> bool: + pass + + def __gt__(self, other: 'u8') -> bool: + pass + + +class u16: + """16-bit unsigned integer.""" + + def __init__(self, _: Any) -> 'u16': + """Construct an u16.""" + + def __add__(self, other: 'u16') -> 'u16': + pass + + def __radd__(self, other: 'u16') -> 'u16': + pass + + def __iadd__(self, other: 'u16') -> 'u16': + pass + + def __sub__(self, other: 'u16') -> 'u16': + pass + + def __rsub__(self, other: 'u16') -> 'u16': + pass + + def __isub__(self, other: 'u16') -> 'u16': + pass + + def __mul__(self, other: 'u16') -> 'u16': + pass + + def __rmul__(self, other: 'u16') -> 'u16': + pass + + def __imul__(self, other: 'u16') -> 'u16': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'u16') -> 'u16': + pass + + def __rfloordiv__(self, other: 'u16') -> 'u16': + pass + + def __ifloordiv__(self, other: 'u16') -> 'u16': + pass + + def __lt__(self, other: 'u16') -> bool: + pass + + def __le__(self, other: 'u16') -> bool: + pass + + def __eq__(self, other: 'u16') -> bool: + pass + + def __ne__(self, other: 'u16') -> bool: + pass + + def __ge__(self, other: 'u16') -> bool: + pass + + def __gt__(self, other: 'u16') -> bool: + pass + +class u32: + """32-bit unsigned integer.""" + + def __init__(self, _: Any) -> 'u32': + """Construct an u32.""" + + def __add__(self, other: 'u32') -> 'u32': + pass + + def __radd__(self, other: 'u32') -> 'u32': + pass + + def __iadd__(self, other: 'u32') -> 'u32': + pass + + def __sub__(self, other: 'u32') -> 'u32': + pass + + def __rsub__(self, other: 'u32') -> 'u32': + pass + + def __isub__(self, other: 'u32') -> 'u32': + pass + + def __mul__(self, other: 'u32') -> 'u32': + pass + + def __rmul__(self, other: 'u32') -> 'u32': + pass + + def __imul__(self, other: 'u32') -> 'u32': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'u32') -> 'u32': + pass + + def __rfloordiv__(self, other: 'u32') -> 'u32': + pass + + def __ifloordiv__(self, other: 'u32') -> 'u32': + pass + + def __lt__(self, other: 'u32') -> bool: + pass + + def __le__(self, other: 'u32') -> bool: + pass + + def __eq__(self, other: 'u32') -> bool: + pass + + def __ne__(self, other: 'u32') -> bool: + pass + + def __ge__(self, other: 'u32') -> bool: + pass + + def __gt__(self, other: 'u32') -> bool: + pass + +class u64: + """64-bit unsigned integer.""" + + def __init__(self, _: Any) -> 'u64': + """Construct an u64.""" + + def __add__(self, other: 'u64') -> 'u64': + pass + + def __radd__(self, other: 'u64') -> 'u64': + pass + + def __iadd__(self, other: 'u64') -> 'u64': + pass + + def __sub__(self, other: 'u64') -> 'u64': + pass + + def __rsub__(self, other: 'u64') -> 'u64': + pass + + def __isub__(self, other: 'u64') -> 'u64': + pass + + def __mul__(self, other: 'u64') -> 'u64': + pass + + def __rmul__(self, other: 'u64') -> 'u64': + pass + + def __imul__(self, other: 'u64') -> 'u64': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'u64') -> 'u64': + pass + + def __rfloordiv__(self, other: 'u64') -> 'u64': + pass + + def __ifloordiv__(self, other: 'u64') -> 'u64': + pass + + def __lt__(self, other: 'u64') -> bool: + pass + + def __le__(self, other: 'u64') -> bool: + pass + + def __eq__(self, other: 'u64') -> bool: + pass + + def __ne__(self, other: 'u64') -> bool: + pass + + def __ge__(self, other: 'u64') -> bool: + pass + + def __gt__(self, other: 'u64') -> bool: + pass + +class u128: + """128-bit unsigned integer.""" + + def __init__(self, _: Any) -> 'u128': + """Construct an u128.""" + + def __add__(self, other: 'u128') -> 'u128': + pass + + def __radd__(self, other: 'u128') -> 'u128': + pass + + def __iadd__(self, other: 'u128') -> 'u128': + pass + + def __sub__(self, other: 'u128') -> 'u128': + pass + + def __rsub__(self, other: 'u128') -> 'u128': + pass + + def __isub__(self, other: 'u128') -> 'u128': + pass + + def __mul__(self, other: 'u128') -> 'u128': + pass + + def __rmul__(self, other: 'u128') -> 'u128': + pass + + def __imul__(self, other: 'u128') -> 'u128': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'u128') -> 'u128': + pass + + def __rfloordiv__(self, other: 'u128') -> 'u128': + pass + + def __ifloordiv__(self, other: 'u128') -> 'u128': + pass + + def __lt__(self, other: 'u128') -> bool: + pass + + def __le__(self, other: 'u128') -> bool: + pass + + def __eq__(self, other: 'u128') -> bool: + pass + + def __ne__(self, other: 'u128') -> bool: + pass + + def __ge__(self, other: 'u128') -> bool: + pass + + def __gt__(self, other: 'u128') -> bool: + pass + +class i8: + """8-bit signed integer.""" + + def __init__(self, _: Any) -> 'i8': + """Construct an i8.""" + + def __add__(self, other: 'i8') -> 'i8': + pass + + def __radd__(self, other: 'i8') -> 'i8': + pass + + def __iadd__(self, other: 'i8') -> 'i8': + pass + + def __sub__(self, other: 'i8') -> 'i8': + pass + + def __rsub__(self, other: 'i8') -> 'i8': + pass + + def __isub__(self, other: 'i8') -> 'i8': + pass + + def __mul__(self, other: 'i8') -> 'i8': + pass + + def __rmul__(self, other: 'i8') -> 'i8': + pass + + def __imul__(self, other: 'i8') -> 'i8': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'i8') -> 'i8': + pass + + def __rfloordiv__(self, other: 'i8') -> 'i8': + pass + + def __ifloordiv__(self, other: 'i8') -> 'i8': + pass + +class i16: + """16-bit signed integer.""" + + def __init__(self, _: Any) -> 'i16': + """Construct an i16.""" + + def __add__(self, other: 'i16') -> 'i16': + pass + + def __radd__(self, other: 'i16') -> 'i16': + pass + + def __iadd__(self, other: 'i16') -> 'i16': + pass + + def __sub__(self, other: 'i16') -> 'i16': + pass + + def __rsub__(self, other: 'i16') -> 'i16': + pass + + def __isub__(self, other: 'i16') -> 'i16': + pass + + def __mul__(self, other: 'i16') -> 'i16': + pass + + def __rmul__(self, other: 'i16') -> 'i16': + pass + + def __imul__(self, other: 'i16') -> 'i16': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'i16') -> 'i16': + pass + + def __rfloordiv__(self, other: 'i16') -> 'i16': + pass + + def __ifloordiv__(self, other: 'i16') -> 'i16': + pass + + def __lt__(self, other: 'i16') -> bool: + pass + + def __le__(self, other: 'i16') -> bool: + pass + + def __eq__(self, other: 'i16') -> bool: + pass + + def __ne__(self, other: 'i16') -> bool: + pass + + def __ge__(self, other: 'i16') -> bool: + pass + + def __gt__(self, other: 'i16') -> bool: + pass + +class i32: + """32-bit signed integer.""" + + def __init__(self, _: Any) -> 'i32': + """Construct an i32.""" + + def __add__(self, other: 'i32') -> 'i32': + pass + + def __radd__(self, other: 'i32') -> 'i32': + pass + + def __iadd__(self, other: 'i32') -> 'i32': + pass + + def __sub__(self, other: 'i32') -> 'i32': + pass + + def __rsub__(self, other: 'i32') -> 'i32': + pass + + def __isub__(self, other: 'i32') -> 'i32': + pass + + def __mul__(self, other: 'i32') -> 'i32': + pass + + def __rmul__(self, other: 'i32') -> 'i32': + pass + + def __imul__(self, other: 'i32') -> 'i32': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'i32') -> 'i32': + pass + + def __rfloordiv__(self, other: 'i32') -> 'i32': + pass + + def __ifloordiv__(self, other: 'i32') -> 'i32': + pass + + def __lt__(self, other: 'i32') -> bool: + pass + + def __le__(self, other: 'i32') -> bool: + pass + + def __eq__(self, other: 'i32') -> bool: + pass + + def __ne__(self, other: 'i32') -> bool: + pass + + def __ge__(self, other: 'i32') -> bool: + pass + + def __gt__(self, other: 'i32') -> bool: + pass + +class i64: + """64-bit signed integer.""" + + def __init__(self, _: Any) -> 'i64': + """Construct an i64.""" + + def __add__(self, other: 'i64') -> 'i64': + pass + + def __radd__(self, other: 'i64') -> 'i64': + pass + + def __iadd__(self, other: 'i64') -> 'i64': + pass + + def __sub__(self, other: 'i64') -> 'i64': + pass + + def __rsub__(self, other: 'i64') -> 'i64': + pass + + def __isub__(self, other: 'i64') -> 'i64': + pass + + def __mul__(self, other: 'i64') -> 'i64': + pass + + def __rmul__(self, other: 'i64') -> 'i64': + pass + + def __imul__(self, other: 'i64') -> 'i64': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'i64') -> 'i64': + pass + + def __rfloordiv__(self, other: 'i64') -> 'i64': + pass + + def __ifloordiv__(self, other: 'i64') -> 'i64': + pass + + def __lt__(self, other: 'i64') -> bool: + pass + + def __le__(self, other: 'i64') -> bool: + pass + + def __eq__(self, other: 'i64') -> bool: + pass + + def __ne__(self, other: 'i64') -> bool: + pass + + def __ge__(self, other: 'i64') -> bool: + pass + + def __gt__(self, other: 'i64') -> bool: + pass + +class i128: + """128-bit signed integer.""" + + def __init__(self, _: Any) -> 'i128': + """Construct an i128.""" + + def __add__(self, other: 'i128') -> 'i128': + pass + + def __radd__(self, other: 'i128') -> 'i128': + pass + + def __iadd__(self, other: 'i128') -> 'i128': + pass + + def __sub__(self, other: 'i128') -> 'i128': + pass + + def __rsub__(self, other: 'i128') -> 'i128': + pass + + def __isub__(self, other: 'i128') -> 'i128': + pass + + def __mul__(self, other: 'i128') -> 'i128': + pass + + def __rmul__(self, other: 'i128') -> 'i128': + pass + + def __imul__(self, other: 'i128') -> 'i128': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'i128') -> 'i128': + pass + + def __rfloordiv__(self, other: 'i128') -> 'i128': + pass + + def __ifloordiv__(self, other: 'i128') -> 'i128': + pass + + def __lt__(self, other: 'i128') -> bool: + pass + + def __le__(self, other: 'i128') -> bool: + pass + + def __eq__(self, other: 'i128') -> bool: + pass + + def __ne__(self, other: 'i128') -> bool: + pass + + def __ge__(self, other: 'i128') -> bool: + pass + + def __gt__(self, other: 'i128') -> bool: + pass + +class f64: + """64-bit floating point number.""" + + def __init__(self, _: Any) -> 'f64': + """Construct an f64.""" + + def __add__(self, other: 'f64') -> 'f64': + pass + + def __radd__(self, other: 'f64') -> 'f64': + pass + + def __iadd__(self, other: 'f64') -> 'f64': + pass + + def __sub__(self, other: 'f64') -> 'f64': + pass + + def __rsub__(self, other: 'f64') -> 'f64': + pass + + def __isub__(self, other: 'f64') -> 'f64': + pass + + def __mul__(self, other: 'f64') -> 'f64': + pass + + def __rmul__(self, other: 'f64') -> 'f64': + pass + + def __imul__(self, other: 'f64') -> 'f64': + pass + + def __truediv__(self, other: 'f64') -> 'f64': + pass + + def __rtruediv__(self, other: 'f64') -> 'f64': + pass + + def __itruediv__(self, other: 'f64') -> 'f64': + pass + + def __floordiv__(self, other: 'f64') -> 'f64': + pass + + def __rfloordiv__(self, other: 'f64') -> 'f64': + pass + + def __ifloordiv__(self, other: 'f64') -> 'f64': + pass + + def __lt__(self, other: 'f64') -> bool: + pass + + def __le__(self, other: 'f64') -> bool: + pass + + def __eq__(self, other: 'f64') -> bool: + pass + + def __ne__(self, other: 'f64') -> bool: + pass + + def __ge__(self, other: 'f64') -> bool: + pass + + def __gt__(self, other: 'f64') -> bool: + pass + +class Array(Generic[T, N]): + """ + A fixed-length array: contains type T and has size N. + + N must be known at compile-time, and may not be anything other than a non-negative integer literal. Example: + + ``` + # Good + a: Array[u8, 4] + + # Bad + N = 4 + a: Array[u8, N] + ``` + """ + + def __init__(iterable: Iterable[T], len: N) -> 'Array[T, N]': + """ + Construct an array from an iterable and a length. + + The parameter len must be known at compile-time, and may not be anything other than a non-negative integer literal. Example: + + ``` + a = [0, 1, 2, 3] + + # Good + Array(a, 4) + # Compiles, but will definitely error at runtime + Array(a, 5) + + # Bad (will not compile) + a = [0, 1, 2, 3] + Array(a, len(a)) + ``` + """ + + def __getitem__(self, index: Any) -> T: + """ + Index into this array. + + Like Python's native list type, performs wrapping indexing - if you pass in -1, you'll get the last element of the array. + """ + +def array(*elements: T) -> Array[T, N]: + """ + Create an array from a variadic list of elements. Example: + + ``` + # Array[u64, 3] + array(u64(0), 1, 2) + + # Array[str, 4] + array('seahorse', 'is', 'the', 'best!') + ``` + """ + +class Enum: + """ + A type that can have one of multiple named values. + + Note that unlike Rust enums, these cannot contain any data (other than the variant itself). Example: + + ``` + class MyEnum(Enum): + ONE = 1 + TWO = 2 + THREE = 3 + + @instruction + def use_enum(code: MyEnum): + if code == MyEnum.ONE: + print(1) + # ... + ``` + """ + + +# ============ +# Solana types +# ============ + +class Pubkey: + """32-byte account identifier.""" + + def find_program_address(seeds: List[Any], program_id: 'Pubkey' = None) -> Tuple['Pubkey', u8]: + """ + Find a valid program derived address and its corresponding bump seed. Calls the same function from Solana's Pubkey struct - read more [here](https://docs.rs/solana-program/latest/solana_program/pubkey/struct.Pubkey.html#method.find_program_address). + + @param seeds: A list of parameters to uniquely identify this account among all accounts created by your program. These may be string literals, other accounts, integers, or lists of bytes. + @param program_id: The pubkey of the program that the PDA belongs to. Defaults to the current program's key. + @returns: The canonical pubkey and bump seed. + """ + +class AccountWithKey: + """Generic Solana account.""" + + def key(self) -> Pubkey: + """Get this account's key.""" + +class Account(AccountWithKey): + """User-defined Solana account.""" + + def transfer_lamports(self, to: AccountWithKey, amount: u64): + """ + Transfer some SOL directly to another account. Since this account is program-owned, this transfer does not require a CPI. + + @param to: The recipient Solana account. + @param amount: The amount (in lamports, not SOL) to transfer. + """ + +class Event: + """Anchor event that clients can listen for""" + + def emit(self): + """ + Emit the event to the blockchain + """ + +class Signer(AccountWithKey): + """Instruction signer.""" + + def transfer_lamports(self, to: AccountWithKey, amount: u64): + """ + Transfer some SOL directly to another account. Unlike using transfer_lamports from a program account, this transfer will require a CPI. + + @param to: The recipient Solana account. + @param amount: The amount (in lamports, not SOL) to transfer. + """ + +class Empty(Generic[T]): + """An account that needs to be initialized.""" + + def init(self, payer: Signer, seeds: List[Any] = None, mint: 'TokenMint' = None, decimals: u8 = None, authority: AccountWithKey = None, associated: bool = False, space: u64 = None, padding: u64 = None) -> T: + """ + Initialize the account. + + @param payer: The account that will pay for the rent cost of the initialized account. Must be an instruction signer. + @param seeds: A list of parameters to uniquely identify this account among all accounts created by your program. These may be string literals, other accounts, integers, or lists of bytes. + @param mint: If initializing a TokenAccount, this is the mint that the account belongs to. + @param decimals: If initializing a TokenMint, this is the number of decimals the new token has. + @param authority: If initializing a TokenAccount/TokenMint, this is the account that has authority over the account. + @param associated: If initializing an associated token account, must be set to true. + @param space: If initializing a program account, you can use this to overwrite Seahorse's calculation of the account size. + @param padding: If initializing a program account, you can use this to add extra space to Seahorse's calculation of the account size. + @returns: The new, initialized account. All of the data in this account will be set to 0, bytewise. + """ + + def bump(self) -> u8: + """ + Get this account's bump, needed if you want to use this account to sign CPI calls. + + If you've initialized an account without seeds, then a bump will not have been calculated. This will result in a runtime error when you try to access it. + """ + + def key(self) -> Pubkey: + """Get this account's key.""" + +class CpiAccount: + """Account and metadata used for making arbitrary CPIs (via `Program.invoke`).""" + + def __init__(account: AccountWithKey, mut: bool = False, signer: bool = False, seeds: List[Any] = None) -> 'CpiAccount': + """ + Create the CpiAccount. + + @param account: The account being passed to the CPI. + @param mut: Whether this account needs to be mutable for the CPI - defaults to false. + @param signer: Whether this account needs to be an instruction signer - defaults to false. Mutually exclusive with seeds, and should only really be true if account is a Signer. + @param seeds: PDA signer seeds, if this account needs to sign the CPI. Mutually exclusive with signer. + """ + +class Program(AccountWithKey): + """Arbitrary program.""" + + def invoke(self, accounts: List[CpiAccount], data: List[u8]): + """ + Call this program in a cross-program invocation. Make sure you know what you're doing before you try using this - a poorly crafted data list could cost you real money. + + @param accounts: List of accounts being passed to the CPI - the program itself does not need to be in here. + @param data: "Raw" list of bytes used to tell the program what to do, pass args, etc. + """ + +class UncheckedAccount(AccountWithKey): + """ + Raw account that has had no safety checks performed on it. + + The underlying Anchor code cannot guarantee anything about the account unless you check it in your instruction - not the type, not the data, not the program it came from. Use carefully. + """ + +class Clock: + """ + Solana's Clock sysvar. + + Consult Solana's reference to learn more. Information copied from https://docs.rs/solana-program/1.14.3/solana_program/clock/struct.Clock.html. + """ + + def slot(self) -> u64: + """Get the current network/bank Slot.""" + + def epoch_start_timestamp(self) -> i64: + """Get the timestamp of the first Slot in this Epoch.""" + + def epoch(self) -> u64: + """Get the bank Epoch.""" + + def leader_schedule_epoch(self) -> u64: + """Get the future Epoch for which the leader schedule has most recently been calculated.""" + + def unix_timestamp(self) -> i64: + """ + Get the estimated current UNIX timestamp. + + Originally computed from genesis creation time and network time in slots (drifty); corrected using validator timestamp oracle as of timestamp_correction and timestamp_bounding features. + """ + +class TokenAccount(AccountWithKey): + """SPL token account.""" + + def authority(self) -> Pubkey: + """Get the owner of this token account.""" + + def amount(self) -> u64: + """Get the amount of token stored in this account.""" + + def mint(self) -> Pubkey: + """Get the mint that this token account corresponds to.""" + + def transfer(self, authority: AccountWithKey, to: 'TokenAccount', amount: u64, signer: List[Any] = None): + """ + Transfer funds from this SPL token account to another. + + @param authority: The account that owns this TokenAccount. Must be an instruction signer or the account given by the `signer` param. + @param to: The recipient TokenAccount. + @param amount: How much (in *native* token units) to transfer. + @param signer: (Optional) seeds for the signature of a PDA. + """ + +class TokenMint(AccountWithKey): + """SPL token mint.""" + + def authority(self) -> Pubkey: + """Get the owner of this token mint.""" + + def freeze_authority(self) -> Pubkey: + """Get the freeze authority of this token mint.""" + + def decimals(self) -> u8: + """Get the number of decimals for this token.""" + + def supply(self) -> u64: + """Get the amount of this token that exists.""" + + def mint(self, authority: AccountWithKey, to: TokenAccount, amount: u64, signer: List[Any] = None): + """ + Mint new tokens to a token account. + + @param authority: The account that owns this TokenMint. Must be an instruction signer or the account given by the `signer` param. + @param to: The recipient TokenAccount. + @param amount: How much (in *native* token units) to mint. + @param signer: (Optional) seeds for the signature of a PDA. + """ + + def burn(self, authority: AccountWithKey, holder: TokenAccount, amount: u64, signer: List[Any] = None): + """ + Burn tokens from a token account. + + @param authority: The account that owns the `holder` TokenAccount. Must be an instruction signer or the account given by the `signer` param. + @param holder: The TokenAccount to burn from. + @param amount: How much (in *native* token units) to burn. + @param signer: (Optional) seeds for the signature of a PDA. + """ + + +# ================ +# Helper functions +# ================ + +def declare_id(id: str): + """Inform Anchor what this program's ID is. + + @param id: The program's ID, generated by Anchor in /target/idl/.json. This must be copied-pasted straight from there as a string literal. + """ + +def instruction(function: Callable[..., None]) -> Callable[..., None]: + """Decorator to turn a function into a program instruction.""" + +def dataclass(function: Callable[..., None]) -> Callable[..., None]: + """Decorator to create an automatic default class constructor.""" + +def int_bytes(n: Any, be: bool = False) -> List[u8]: + """ + Convenience method to turn an integer type into a little-endian (by default) list of bytes. + + @param n: The integer you wish to convert to bytes. + @param be: Whether you want the conversion to be big-endian - defaults to false. + """ + +def size(ob: str) -> u64: + """ + Get the size of an object in bytes. + Currently this is only supported for strings. + + @param ob: The object to get the size of. + """ diff --git a/basics/program-derived-addresses/seahorse/tests/program_derived_addresses_seahorse.ts b/basics/program-derived-addresses/seahorse/tests/program_derived_addresses_seahorse.ts new file mode 100644 index 000000000..da20888b8 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/tests/program_derived_addresses_seahorse.ts @@ -0,0 +1,51 @@ +import * as anchor from "@coral-xyz/anchor"; +import { Program } from "@coral-xyz/anchor"; +import { ProgramDerivedAddressesSeahorse } from "../target/types/program_derived_addresses_seahorse"; + +describe("program_derived_addresses_seahorse", () => { + // Set the provider to use the local environment + anchor.setProvider(anchor.AnchorProvider.env()); + + // Get the program instance from the workspace + const program = anchor.workspace + .ProgramDerivedAddressesSeahorse as Program; + + it("Is Created!", async () => { + try { + // Call the createPageVisits method on the program + const tx = await program.methods.createPageVisits().rpc(); + console.log("Your transaction signature", tx); + } catch (error) { + // Handle the case where the account is already created + if (error.message.includes("already in use")) { + console.log("Account already created, skipping creation."); + } else { + throw error; + } + } + }); + + it("Is Updated!", async () => { + // Get the public key of the wallet owner + const owner = anchor.AnchorProvider.env().wallet.publicKey; + + // Derive the pageVisitAccount address using the program ID and a seed + const [pageVisitAccount] = await anchor.web3.PublicKey.findProgramAddress( + [Buffer.from("page_visits"), owner.toBuffer()], + program.programId + ); + + // Call the incrementPageVisits method on the program + const tx = await program.methods + .incrementPageVisits() + .accounts({ + pageVisits: pageVisitAccount, + }) + .rpc(); + console.log("Your transaction signature", tx); + + // Fetch and log the value of pageVisits + const account = await program.account.pageVisits.fetch(pageVisitAccount); + console.log("Page Visits:", account); + }); +}); diff --git a/basics/program-derived-addresses/seahorse/tsconfig.json b/basics/program-derived-addresses/seahorse/tsconfig.json new file mode 100644 index 000000000..cd5d2e3d0 --- /dev/null +++ b/basics/program-derived-addresses/seahorse/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true + } +}