sdk, miner

This commit is contained in:
Hardhat Chad
2025-07-18 14:25:57 -07:00
parent c02551b032
commit 870796400c
9 changed files with 196 additions and 25 deletions

View File

@@ -68,6 +68,7 @@ pub struct Swap {
pub amount: [u8; 8],
pub direction: u8,
pub precision: u8,
pub seed: [u8; 32],
}
#[repr(C)]

View File

@@ -21,26 +21,41 @@ pub fn program_log(accounts: &[AccountInfo], msg: &[u8]) -> Result<(), ProgramEr
invoke_signed(&log(*accounts[0].key, msg), accounts, &crate::ID, &[MARKET])
}
pub fn initialize(signer: Pubkey) -> Instruction {
let config_address = config_pda().0;
let market_address = market_pda().0;
let mint_address = MINT_ADDRESS;
let treasury_address = TREASURY_ADDRESS;
let treasury_tokens_address = treasury_tokens_address();
let vault_address = vault_pda().0;
Instruction {
program_id: crate::ID,
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(config_address, false),
AccountMeta::new(market_address, false),
AccountMeta::new(mint_address, false),
AccountMeta::new(treasury_address, false),
AccountMeta::new(treasury_tokens_address, false),
AccountMeta::new(vault_address, false),
AccountMeta::new_readonly(system_program::ID, false),
AccountMeta::new_readonly(spl_token::ID, false),
AccountMeta::new_readonly(spl_associated_token_account::ID, false),
],
data: Initialize {}.to_bytes(),
}
}
pub fn mine(signer: Pubkey, authority: Pubkey, id: u64, nonce: u64) -> Instruction {
let block_adddress = block_pda(id).0;
let market_address = market_pda().0;
let miner_address = miner_pda(authority).0;
let recipient = get_associated_token_address(&authority, &MINT_ADDRESS);
Instruction {
program_id: crate::ID,
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(authority, false),
AccountMeta::new(block_adddress, false),
AccountMeta::new(market_address, false),
AccountMeta::new(miner_address, false),
AccountMeta::new(MINT_ADDRESS, false),
AccountMeta::new(recipient, false),
AccountMeta::new(TREASURY_ADDRESS, false),
AccountMeta::new_readonly(system_program::ID, false),
AccountMeta::new_readonly(spl_token::ID, false),
AccountMeta::new_readonly(crate::ID, false),
AccountMeta::new_readonly(sysvar::slot_hashes::ID, false),
],
data: Mine {
nonce: nonce.to_le_bytes(),
@@ -49,15 +64,94 @@ pub fn mine(signer: Pubkey, authority: Pubkey, id: u64, nonce: u64) -> Instructi
}
}
pub fn open(signer: Pubkey, id: u64) -> Instruction {
let block_adddress = block_pda(id).0;
let market_address = market_pda().0;
Instruction {
program_id: crate::ID,
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(block_adddress, false),
AccountMeta::new(market_address, false),
AccountMeta::new_readonly(system_program::ID, false),
],
data: Open {
id: id.to_le_bytes(),
}
.to_bytes(),
}
}
pub fn close(signer: Pubkey, opener: Pubkey, winner: Pubkey, id: u64) -> Instruction {
let block_adddress = block_pda(id).0;
let miner_tokens_address = get_associated_token_address(&winner, &MINT_ADDRESS);
let mint_address = MINT_ADDRESS;
let treasury_address = TREASURY_ADDRESS;
let treasury_tokens_address = treasury_tokens_address();
Instruction {
program_id: crate::ID,
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(block_adddress, false),
AccountMeta::new(winner, false),
AccountMeta::new(miner_tokens_address, false),
AccountMeta::new(mint_address, false),
AccountMeta::new(opener, false),
AccountMeta::new(treasury_address, false),
AccountMeta::new(treasury_tokens_address, false),
AccountMeta::new_readonly(system_program::ID, false),
AccountMeta::new_readonly(spl_token::ID, false),
AccountMeta::new_readonly(spl_associated_token_account::ID, false),
],
data: Close {}.to_bytes(),
}
}
pub fn reset(signer: Pubkey, fee_collector: Pubkey, id: u64) -> Instruction {
let block_prev_adddress = block_pda(id).0;
let block_next_adddress = block_pda(id + 1).0;
let config_address = config_pda().0;
let market_address = market_pda().0;
let mint_address = MINT_ADDRESS;
let treasury_address = TREASURY_ADDRESS;
let treasury_tokens_address = treasury_tokens_address();
let vault_address = vault_pda().0;
Instruction {
program_id: crate::ID,
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(block_prev_adddress, false),
AccountMeta::new(block_next_adddress, false),
AccountMeta::new_readonly(config_address, false),
AccountMeta::new(fee_collector, false),
AccountMeta::new(market_address, false),
AccountMeta::new(mint_address, false),
AccountMeta::new(treasury_address, false),
AccountMeta::new(treasury_tokens_address, false),
AccountMeta::new(vault_address, false),
AccountMeta::new_readonly(system_program::ID, false),
AccountMeta::new_readonly(spl_token::ID, false),
AccountMeta::new_readonly(crate::ID, false),
AccountMeta::new_readonly(sysvar::slot_hashes::ID, false),
],
data: Reset {}.to_bytes(),
}
}
// let [signer_info, block_info, config_info, fee_collector_info, market_info, miner_info, mint_info, tokens_info, vault_info, system_program, token_program, associated_token_program, ore_program] =
pub fn swap(
signer: Pubkey,
id: u64,
fee_collector: Pubkey,
amount: u64,
direction: SwapDirection,
precision: SwapPrecision,
seed: [u8; 32],
) -> Instruction {
let block_adddress = block_pda(id).0;
let config_address = config_pda().0;
let market_address = market_pda().0;
let miner_address = miner_pda(signer).0;
let tokens_quote_address = get_associated_token_address(&signer, &MINT_ADDRESS);
let vault_address = vault_pda().0;
Instruction {
@@ -65,7 +159,10 @@ pub fn swap(
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(block_adddress, false),
AccountMeta::new(config_address, false),
AccountMeta::new(fee_collector, false),
AccountMeta::new(market_address, false),
AccountMeta::new(miner_address, false),
AccountMeta::new(MINT_ADDRESS, false),
AccountMeta::new(tokens_quote_address, false),
AccountMeta::new(vault_address, false),
@@ -78,6 +175,7 @@ pub fn swap(
amount: amount.to_le_bytes(),
direction: direction as u8,
precision: precision as u8,
seed: seed,
}
.to_bytes(),
}

View File

@@ -13,9 +13,6 @@ pub struct Miner {
/// The ID of the last block this miner mined in.
pub block_id: u64,
/// The hash of the last block this miner mined in.
pub hash: [u8; 32],
/// The amount of hashpower this miner has committed to the current block.
pub hashpower: u64,

View File

@@ -55,3 +55,7 @@ pub fn vault_pda() -> (Pubkey, u8) {
pub fn treasury_pda() -> (Pubkey, u8) {
Pubkey::find_program_address(&[TREASURY], &crate::ID)
}
pub fn treasury_tokens_address() -> Pubkey {
spl_associated_token_account::get_associated_token_address(&TREASURY_ADDRESS, &MINT_ADDRESS)
}

View File

@@ -35,9 +35,18 @@ async fn main() {
"blocks" => {
log_blocks(&rpc).await.unwrap();
}
"initialize" => {
initialize(&rpc, &payer).await.unwrap();
}
"open" => {
open(&rpc, &payer).await.unwrap();
}
"swap" => {
swap(&rpc, &payer).await.unwrap();
}
"miner" => {
log_miner(&rpc, payer.pubkey()).await.unwrap();
}
"set_admin" => {
set_admin(&rpc, &payer).await.unwrap();
}
@@ -48,18 +57,42 @@ async fn main() {
};
}
async fn initialize(
rpc: &RpcClient,
payer: &solana_sdk::signer::keypair::Keypair,
) -> Result<(), anyhow::Error> {
let ix = ore_api::sdk::initialize(payer.pubkey());
submit_transaction(rpc, payer, &[ix]).await?;
Ok(())
}
async fn open(
rpc: &RpcClient,
payer: &solana_sdk::signer::keypair::Keypair,
) -> Result<(), anyhow::Error> {
let id_str = std::env::var("ID").expect("Missing ID env var");
let id = id_str.parse::<u64>()?;
let ix = ore_api::sdk::open(payer.pubkey(), id);
submit_transaction(rpc, payer, &[ix]).await?;
Ok(())
}
async fn swap(
rpc: &RpcClient,
payer: &solana_sdk::signer::keypair::Keypair,
) -> Result<(), anyhow::Error> {
let id_str = std::env::var("ID").expect("Missing ID env var");
let id = id_str.parse::<u64>()?;
let config = get_config(rpc).await?;
let fee_collector = config.fee_collector;
let ix = ore_api::sdk::swap(
payer.pubkey(),
id,
10000000,
fee_collector,
100_000_000,
SwapDirection::Buy,
SwapPrecision::ExactIn,
[0; 32],
);
submit_transaction(rpc, payer, &[ix]).await?;
Ok(())
@@ -74,6 +107,17 @@ async fn set_admin(
Ok(())
}
async fn log_miner(rpc: &RpcClient, authority: Pubkey) -> Result<(), anyhow::Error> {
let miner = get_miner(&rpc, authority).await?;
println!("Miner");
println!(" authority: {}", authority);
println!(" block_id: {}", miner.block_id);
println!(" hashpower: {}", miner.hashpower);
println!(" total_hashpower: {}", miner.total_hashpower);
println!(" total_rewards: {}", miner.total_rewards);
Ok(())
}
async fn log_clock(rpc: &RpcClient) -> Result<(), anyhow::Error> {
let clock = get_clock(&rpc).await?;
println!("Clock");
@@ -126,6 +170,13 @@ async fn get_config(rpc: &RpcClient) -> Result<Config, anyhow::Error> {
Ok(*config)
}
async fn get_miner(rpc: &RpcClient, authority: Pubkey) -> Result<Miner, anyhow::Error> {
let miner_pda = ore_api::state::miner_pda(authority);
let account = rpc.get_account(&miner_pda.0).await?;
let miner = Miner::try_from_bytes(&account.data)?;
Ok(*miner)
}
async fn get_clock(rpc: &RpcClient) -> Result<Clock, anyhow::Error> {
let data = rpc.get_account_data(&solana_sdk::sysvar::clock::ID).await?;
let clock = bincode::deserialize::<Clock>(&data)?;

View File

@@ -5,7 +5,7 @@ use steel::*;
pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
// Load accounts.
let clock = Clock::get()?;
let [signer_info, block_info, miner_info, miner_tokens_info, mint_info, opener_info, recipient_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program] =
let [signer_info, block_info, miner_info, miner_tokens_info, mint_info, opener_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program] =
accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
@@ -41,11 +41,10 @@ pub fn process_close(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResul
// Payout block reward to winning miner.
if block.best_hash_miner != Pubkey::default() {
// Load recipient.
recipient_info.as_associated_token_account(&block.best_hash_miner, &mint_info.key)?;
// Load winning miner.
let miner = miner_info
.as_account_mut::<Miner>(&ore_api::ID)?
.assert_mut(|m| m.authority == block.best_hash_miner)?;
.has_address(&block.best_hash_miner)?
.as_account_mut::<Miner>(&ore_api::ID)?;
// Update stats.
miner.total_rewards += block.reward;

View File

@@ -38,7 +38,7 @@ pub fn process_mine(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
// If hash is best hash, update best hash.
if h < block.best_hash {
block.best_hash = h;
block.best_hash_miner = miner.authority;
block.best_hash_miner = *miner_info.key;
}
Ok(())

View File

@@ -8,7 +8,7 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
let id = u64::from_le_bytes(args.id);
// Load accounts.
let [signer_info, block_info, market_info, system_program, ore_program] = accounts else {
let [signer_info, block_info, market_info, system_program] = accounts else {
return Err(ProgramError::NotEnoughAccountKeys);
};
signer_info.is_signer()?;
@@ -16,7 +16,6 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
.as_account::<Market>(&ore_api::ID)?
.assert(|m| m.block_id < id)?; // Only allow opening blocks in forward bias
system_program.is_program(&system_program::ID)?;
ore_program.is_program(&ore_api::ID)?;
// Create block, if it doesn't exist.
if block_info.data_is_empty() {

View File

@@ -30,9 +30,6 @@ pub fn process_swap(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
.assert_mut(|m| m.block_id == block.id)?
.assert_mut(|m| m.base.liquidity() > 0)?
.assert_mut(|m| m.quote.liquidity() > 0)?;
let miner = miner_info
.as_account_mut::<Miner>(&ore_api::ID)?
.assert_mut(|m| m.authority == *signer_info.key)?;
mint_info
.has_address(&market.quote.mint)?
.has_address(&MINT_ADDRESS)?
@@ -46,10 +43,35 @@ pub fn process_swap(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
associated_token_program.is_program(&spl_associated_token_account::ID)?;
ore_program.is_program(&ore_api::ID)?;
// Load miner.
let miner = if miner_info.data_is_empty() {
create_program_account::<Miner>(
miner_info,
system_program,
signer_info,
&ore_api::ID,
&[MINER, &signer_info.key.to_bytes()],
)?;
let miner = miner_info.as_account_mut::<Miner>(&ore_api::ID)?;
miner.authority = *signer_info.key;
miner.block_id = block.id;
miner.hashpower = 0;
miner.seed = [0; 32];
miner.total_hashpower = 0;
miner.total_rewards = 0;
miner
} else {
miner_info
.as_account_mut::<Miner>(&ore_api::ID)?
.assert_mut(|m| m.authority == *signer_info.key)?
.assert_mut(|m| m.block_id <= block.id)?
};
// Reset miner.
if miner.block_id != block.id {
miner.block_id = block.id;
miner.hashpower = 0;
miner.seed = args.seed;
}
// Pay swap fee.