Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migration - Phase 1 #29

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 40 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[workspace]
resolver = "2"
members = ["admin", "api", "program", "server", "types"]
members = ["admin", "api", "program", "server", "types", "migration"]

[workspace.package]
version = "0.2.0"
version = "0.2.1"
edition = "2021"
license = "Apache-2.0"
homepage = "https://ore.supply"
Expand Down Expand Up @@ -38,6 +38,7 @@ reqwest = { version = "0.12", features = ["json"] }
serde = { features = ["derive"], version = "1.0" }
serde_json = "1.0"
sha3 = "0.10"
solana-account-decoder = "^1.18"
solana-client = "^1.18"
solana-program = "^1.18"
solana-sdk = "^1.18"
Expand Down
9 changes: 9 additions & 0 deletions api/src/consts.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use solana_program::pubkey;
use steel::Pubkey;

/// The seed of the member account PDA.
pub const MEMBER: &[u8] = b"member";

Expand All @@ -6,3 +9,9 @@ pub const POOL: &[u8] = b"pool";

/// The seed of the share account PDA.
pub const SHARE: &[u8] = b"share";

/// The seed of the migration account PDA.
pub const MIGRATION: &[u8] = b"migration";

/// The authority allowed to run migrations.
pub const ADMIN_ADDRESS: Pubkey = pubkey!("HBUh9g46wk2X89CvaNN15UmsznP59rh6od1h8JwYAopk");
14 changes: 14 additions & 0 deletions api/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ pub enum PoolInstruction {
Launch = 102,
OpenStake = 103,
Submit = 104,

// Migration
MigratePool = 200,
MigrateMemberBalance = 201,
}

#[repr(C)]
Expand Down Expand Up @@ -79,6 +83,14 @@ pub struct Unstake {
pub amount: [u8; 8],
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct MigratePool {}

#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct MigrateMemberBalance {}

instruction!(PoolInstruction, Attribute);
instruction!(PoolInstruction, Claim);
instruction!(PoolInstruction, Commit);
Expand All @@ -89,3 +101,5 @@ instruction!(PoolInstruction, Join);
instruction!(PoolInstruction, Stake);
instruction!(PoolInstruction, Submit);
instruction!(PoolInstruction, Unstake);
instruction!(PoolInstruction, MigratePool);
instruction!(PoolInstruction, MigrateMemberBalance);
31 changes: 30 additions & 1 deletion api/src/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use steel::*;
use crate::{
error::ApiError,
instruction::*,
state::{member_pda, pool_pda, pool_proof_pda, share_pda},
state::{member_pda, migration_pda, pool_pda, pool_proof_pda, share_pda},
};

/// Builds a launch instruction.
Expand Down Expand Up @@ -276,6 +276,35 @@ pub fn open_stake(signer: Pubkey, mint: Pubkey) -> Instruction {
}
}

pub fn migrate_pool(signer: Pubkey, pool: Pubkey) -> Instruction {
let (migration_address, _) = migration_pda(pool);
Instruction {
program_id: crate::ID,
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(pool, false),
AccountMeta::new(migration_address, false),
AccountMeta::new_readonly(system_program::ID, false),
],
data: MigratePool {}.to_bytes(),
}
}

pub fn migrate_member_balance(signer: Pubkey, pool: Pubkey, member: Pubkey) -> Instruction {
let (migration_address, _) = migration_pda(pool);
Instruction {
program_id: crate::ID,
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(pool, false),
AccountMeta::new_readonly(member, false),
AccountMeta::new(migration_address, false),
AccountMeta::new_readonly(system_program::ID, false),
],
data: MigrateMemberBalance {}.to_bytes(),
}
}

fn url_to_bytes(input: &str) -> Result<[u8; 128], ApiError> {
let bytes = input.as_bytes();
let len = bytes.len();
Expand Down
12 changes: 12 additions & 0 deletions api/src/state/migration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use steel::*;

use super::AccountDiscriminator;

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
pub struct Migration {
pub pool: Pubkey,
pub members_migrated: u64,
}

account!(AccountDiscriminator, Migration);
9 changes: 9 additions & 0 deletions api/src/state/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod member;
mod migration;
mod pool;
mod share;

pub use member::*;
pub use migration::*;
pub use pool::*;
pub use share::*;

Expand All @@ -16,12 +18,19 @@ pub enum AccountDiscriminator {
Member = 100,
Pool = 101,
Share = 102,

// Migration account
Migration = 200,
}

pub fn pool_pda(authority: Pubkey) -> (Pubkey, u8) {
Pubkey::find_program_address(&[POOL, authority.as_ref()], &crate::id())
}

pub fn migration_pda(pool: Pubkey) -> (Pubkey, u8) {
Pubkey::find_program_address(&[MIGRATION, pool.as_ref()], &crate::id())
}

pub fn pool_proof_pda(pool: Pubkey) -> (Pubkey, u8) {
Pubkey::find_program_address(&[ore_api::consts::PROOF, pool.as_ref()], &ore_api::id())
}
Expand Down
3 changes: 3 additions & 0 deletions api/src/state/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub struct Pool {

// The total number of members in this pool at the last submission.
pub last_total_members: u64,
// TODO Uncomment in phase 2
// The total claimable rewards in the pool.
// pub claimable_rewards: u64,
}

account!(AccountDiscriminator, Pool);
36 changes: 36 additions & 0 deletions migration/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "ore-pool-migration"
version = "0.0.1"
edition = "2021"

[dependencies]
actix-cors = { workspace = true }
actix-web = { workspace = true }
base64 = { workspace = true }
bincode = { workspace = true }
bytemuck = { workspace = true }
deadpool-postgres = { workspace = true }
drillx = { workspace = true }
env_logger = { workspace = true }
futures = { workspace = true }
futures-channel = { workspace = true }
futures-util = { workspace = true }
log = { workspace = true }
ore-api = { workspace = true }
ore-boost-api = { workspace = true }
ore-pool-api = { workspace = true }
ore-pool-types = { workspace = true }
postgres-types = { workspace = true }
reqwest = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
sha3 = { workspace = true }
solana-account-decoder = { workspace = true }
solana-client = { workspace = true }
solana-sdk = { workspace = true }
solana-transaction-status = { workspace = true }
steel = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true }
tokio-postgres = { workspace = true }
rand = "0.8.5"
102 changes: 102 additions & 0 deletions migration/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use ore_pool_api::state::{Member, Pool};
use solana_account_decoder::UiAccountEncoding;
use solana_client::{
nonblocking::rpc_client::RpcClient,
rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig},
rpc_filter::{Memcmp, RpcFilterType},
};
use solana_sdk::{
commitment_config::CommitmentConfig, compute_budget::ComputeBudgetInstruction,
signature::read_keypair_file, signer::Signer, transaction::Transaction,
};
use steel::{AccountDeserialize, Discriminator};

#[tokio::main]
pub async fn main() {
// Create client
let signer = read_keypair_file("../migration-admin-key.json").unwrap();
let url = "https://mainnet.helius-rpc.com/?api-key=TODO";
let rpc = RpcClient::new_with_commitment(url.to_owned(), CommitmentConfig::confirmed());

// Fetch pools
let pool_filter = RpcFilterType::Memcmp(Memcmp::new_raw_bytes(
0,
Pool::discriminator().to_le_bytes().to_vec(),
));
let Ok(pools) = rpc
.get_program_accounts_with_config(
&ore_pool_api::ID,
RpcProgramAccountsConfig {
filters: Some(vec![pool_filter]),
account_config: RpcAccountInfoConfig {
encoding: Some(UiAccountEncoding::Base64),
data_slice: None,
commitment: None,
min_context_slot: None,
},
with_context: None,
},
)
.await
else {
return;
};
println!("Pools {:?}\n", pools.len());

// TODO Phase 1: Initialize migration
for pool in pools {
let ix = ore_pool_api::sdk::migrate_pool(signer.pubkey(), pool.0);
let cu_limit_ix = ComputeBudgetInstruction::set_compute_unit_limit(200_000);
let cu_price_ix = ComputeBudgetInstruction::set_compute_unit_price(10_000);
let final_ixs = &[cu_limit_ix, cu_price_ix, ix];
let hash = rpc.get_latest_blockhash().await.unwrap();
let mut tx = Transaction::new_with_payer(final_ixs.as_slice(), Some(&signer.pubkey()));
tx.sign(&[&signer], hash);
rpc.send_transaction(&tx).await.unwrap();
}

// TODO: Phase 2: Migrate member balances
// for pool in pools {
// // Fetch members of the given pool
// let member_filter = RpcFilterType::Memcmp(Memcmp::new_raw_bytes(
// 0,
// Member::discriminator().to_le_bytes().to_vec(),
// ));
// let pool_member_filter =
// RpcFilterType::Memcmp(Memcmp::new_raw_bytes(16, pool.0.to_bytes().to_vec()));
// let Ok(members) = rpc
// .get_program_accounts_with_config(
// &ore_pool_api::ID,
// RpcProgramAccountsConfig {
// filters: Some(vec![member_filter, pool_member_filter]),
// account_config: RpcAccountInfoConfig {
// encoding: Some(UiAccountEncoding::Base64),
// data_slice: None,
// commitment: None,
// min_context_slot: None,
// },
// with_context: None,
// },
// )
// .await
// else {
// return;
// };
// let pool_account = Pool::try_from_bytes(&pool.1.data).unwrap();
// println!("Pool: {}", pool.0);
// println!("Expected members: {}", pool_account.total_members);
// println!("Actual members: {}\n", members.len());

// // Migrate each member balance
// for member in members {
// let ix = ore_pool_api::sdk::migrate_member_balance(signer.pubkey(), pool.0, member.0);
// let cu_limit_ix = ComputeBudgetInstruction::set_compute_unit_limit(200_000);
// let cu_price_ix = ComputeBudgetInstruction::set_compute_unit_price(10_000);
// let final_ixs = &[cu_limit_ix, cu_price_ix, ix];
// let hash = rpc.get_latest_blockhash().await.unwrap();
// let mut tx = Transaction::new_with_payer(final_ixs.as_slice(), Some(&signer.pubkey()));
// tx.sign(&[&signer], hash);
// rpc.send_transaction(&tx).await.unwrap();
// }
// }
}
Loading