mirror of
https://github.com/d0zingcat/ore.git
synced 2026-05-14 07:26:51 +00:00
permit
This commit is contained in:
@@ -5,3 +5,8 @@
|
||||
## Programs
|
||||
- [`ore`](ore/) – ORE mining program.
|
||||
- [`ore-delegate`](ore-delegate/) – Delegate mining to another party.
|
||||
|
||||
|
||||
TODO
|
||||
- [ ] Hash token metadata
|
||||
- [ ]
|
||||
@@ -32,6 +32,9 @@ pub const MINER: &[u8] = b"miner";
|
||||
/// The seed of the mint account PDA.
|
||||
pub const MINT: &[u8] = b"mint";
|
||||
|
||||
/// The seed of the permit account PDA.
|
||||
pub const PERMIT: &[u8] = b"permit";
|
||||
|
||||
/// The seed of the treasury account PDA.
|
||||
pub const TREASURY: &[u8] = b"treasury";
|
||||
|
||||
|
||||
@@ -5,8 +5,10 @@ use steel::*;
|
||||
pub enum OreInstruction {
|
||||
Open = 0,
|
||||
Close = 1,
|
||||
Mine = 2,
|
||||
Swap = 3,
|
||||
Commit = 2,
|
||||
Decommit = 3,
|
||||
Mine = 4,
|
||||
Swap = 5,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@@ -19,6 +21,18 @@ pub struct Open {
|
||||
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
|
||||
pub struct Close {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
|
||||
pub struct Commit {
|
||||
pub amount: [u8; 8],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
|
||||
pub struct Decommit {
|
||||
pub amount: [u8; 8],
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
|
||||
pub struct Mine {
|
||||
@@ -35,5 +49,7 @@ pub struct Swap {
|
||||
|
||||
instruction!(OreInstruction, Open);
|
||||
instruction!(OreInstruction, Close);
|
||||
instruction!(OreInstruction, Commit);
|
||||
instruction!(OreInstruction, Decommit);
|
||||
instruction!(OreInstruction, Mine);
|
||||
instruction!(OreInstruction, Swap);
|
||||
|
||||
@@ -2,12 +2,14 @@ mod block;
|
||||
mod config;
|
||||
mod market;
|
||||
mod miner;
|
||||
mod permit;
|
||||
mod treasury;
|
||||
|
||||
pub use block::*;
|
||||
pub use config::*;
|
||||
pub use market::*;
|
||||
pub use miner::*;
|
||||
pub use permit::*;
|
||||
pub use treasury::*;
|
||||
|
||||
use crate::consts::*;
|
||||
@@ -21,7 +23,8 @@ pub enum OreAccount {
|
||||
Config = 101,
|
||||
Market = 102,
|
||||
Miner = 103,
|
||||
Treasury = 104,
|
||||
Permit = 104,
|
||||
Treasury = 105,
|
||||
}
|
||||
|
||||
pub fn block_pda(id: u64) -> (Pubkey, u8) {
|
||||
@@ -44,6 +47,13 @@ pub fn mint_pda(id: u64) -> (Pubkey, u8) {
|
||||
Pubkey::find_program_address(&[MINT, &id.to_le_bytes()], &crate::ID)
|
||||
}
|
||||
|
||||
pub fn permit_pda(authority: Pubkey, block_id: u64) -> (Pubkey, u8) {
|
||||
Pubkey::find_program_address(
|
||||
&[PERMIT, &authority.to_bytes(), &block_id.to_le_bytes()],
|
||||
&crate::ID,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn treasury_pda() -> (Pubkey, u8) {
|
||||
Pubkey::find_program_address(&[TREASURY], &crate::ID)
|
||||
}
|
||||
|
||||
26
ore/api/src/state/permit.rs
Normal file
26
ore/api/src/state/permit.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use steel::*;
|
||||
|
||||
use crate::state::permit_pda;
|
||||
|
||||
use super::OreAccount;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
|
||||
pub struct Permit {
|
||||
/// The amount of ORE this miner has mined.
|
||||
pub amount: u64,
|
||||
|
||||
/// The authority of this miner account.
|
||||
pub authority: Pubkey,
|
||||
|
||||
/// The ID of the last block this miner mined in.
|
||||
pub block_id: u64,
|
||||
}
|
||||
|
||||
impl Permit {
|
||||
pub fn pda(&self) -> (Pubkey, u8) {
|
||||
permit_pda(self.authority, self.block_id)
|
||||
}
|
||||
}
|
||||
|
||||
account!(OreAccount, Permit);
|
||||
73
ore/program/src/commit.rs
Normal file
73
ore/program/src/commit.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use ore_api::prelude::*;
|
||||
use steel::*;
|
||||
|
||||
/// Commit to a block.
|
||||
pub fn process_commit(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
|
||||
// Parse data.
|
||||
let args = Commit::try_from_bytes(data)?;
|
||||
let amount = u64::from_le_bytes(args.amount);
|
||||
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, block_info, commitment_info, market_info, miner_info, mint_info, permit_info, sender_info, system_program, token_program, slot_hashes_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
let block = block_info
|
||||
.as_account::<Block>(&ore_api::ID)?
|
||||
.assert(|b| clock.slot < b.start_slot)?;
|
||||
commitment_info.as_associated_token_account(block_info.key, mint_info.key)?;
|
||||
let market = market_info
|
||||
.as_account::<Market>(&ore_api::ID)?
|
||||
.assert(|m| m.id == block.id)?;
|
||||
miner_info
|
||||
.as_account::<Miner>(&ore_api::ID)?
|
||||
.assert(|m| m.authority == *signer_info.key)?;
|
||||
mint_info.has_address(&market.base.mint)?.as_mint()?;
|
||||
let sender = sender_info
|
||||
.is_writable()?
|
||||
.as_associated_token_account(signer_info.key, &mint_info.key)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
token_program.is_program(&spl_token::ID)?;
|
||||
slot_hashes_sysvar.is_sysvar(&sysvar::slot_hashes::ID)?;
|
||||
|
||||
// Normalize amount.
|
||||
let amount = sender.amount().min(amount);
|
||||
|
||||
// Load permit account.
|
||||
let permit = if permit_info.data_is_empty() {
|
||||
create_program_account::<Permit>(
|
||||
permit_info,
|
||||
system_program,
|
||||
signer_info,
|
||||
&ore_api::ID,
|
||||
&[PERMIT, &signer_info.key.to_bytes(), &block.id.to_le_bytes()],
|
||||
)?;
|
||||
let permit = permit_info.as_account_mut::<Permit>(&ore_api::ID)?;
|
||||
permit.authority = *signer_info.key;
|
||||
permit.block_id = block.id;
|
||||
permit.amount = 0;
|
||||
permit
|
||||
} else {
|
||||
permit_info
|
||||
.as_account_mut::<Permit>(&ore_api::ID)?
|
||||
.assert_mut(|p| p.authority == *signer_info.key)?
|
||||
.assert_mut(|p| p.block_id == block.id)?
|
||||
};
|
||||
|
||||
// Transfer hash tokens.
|
||||
transfer(
|
||||
signer_info,
|
||||
sender_info,
|
||||
commitment_info,
|
||||
token_program,
|
||||
amount,
|
||||
)?;
|
||||
|
||||
// Update block.
|
||||
permit.amount += amount;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
64
ore/program/src/decommit.rs
Normal file
64
ore/program/src/decommit.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
use ore_api::prelude::*;
|
||||
use steel::*;
|
||||
|
||||
/// Decommit from a block.
|
||||
pub fn process_decommit(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult {
|
||||
// Parse data.
|
||||
let args = Decommit::try_from_bytes(data)?;
|
||||
let amount = u64::from_le_bytes(args.amount);
|
||||
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, block_info, commitment_info, market_info, miner_info, mint_info, permit_info, recipient_info, system_program, token_program, slot_hashes_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
signer_info.is_signer()?;
|
||||
let block = block_info
|
||||
.as_account::<Block>(&ore_api::ID)?
|
||||
.assert(|b| clock.slot < b.start_slot)?;
|
||||
commitment_info
|
||||
.is_writable()?
|
||||
.as_associated_token_account(block_info.key, mint_info.key)?;
|
||||
let market = market_info
|
||||
.as_account::<Market>(&ore_api::ID)?
|
||||
.assert(|m| m.id == block.id)?;
|
||||
miner_info
|
||||
.as_account::<Miner>(&ore_api::ID)?
|
||||
.assert(|m| m.authority == *signer_info.key)?;
|
||||
mint_info.has_address(&market.base.mint)?.as_mint()?;
|
||||
let permit = permit_info
|
||||
.as_account_mut::<Permit>(&ore_api::ID)?
|
||||
.assert_mut(|p| p.authority == *signer_info.key)?
|
||||
.assert_mut(|p| p.block_id == block.id)?;
|
||||
recipient_info
|
||||
.is_writable()?
|
||||
.as_associated_token_account(signer_info.key, &mint_info.key)?;
|
||||
system_program.is_program(&system_program::ID)?;
|
||||
token_program.is_program(&spl_token::ID)?;
|
||||
slot_hashes_sysvar.is_sysvar(&sysvar::slot_hashes::ID)?;
|
||||
|
||||
// Normalize amount.
|
||||
let amount = permit.amount.min(amount);
|
||||
|
||||
// Transfer hash tokens.
|
||||
transfer_signed(
|
||||
block_info,
|
||||
commitment_info,
|
||||
recipient_info,
|
||||
token_program,
|
||||
amount,
|
||||
&[BLOCK, &block.id.to_le_bytes()],
|
||||
)?;
|
||||
|
||||
// Update block.
|
||||
permit.amount -= amount;
|
||||
|
||||
// Close permit, if empty.
|
||||
if permit.amount == 0 {
|
||||
permit_info.close(signer_info)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
mod close;
|
||||
mod commit;
|
||||
mod decommit;
|
||||
mod mine;
|
||||
mod open;
|
||||
mod swap;
|
||||
|
||||
use core::panic;
|
||||
|
||||
use close::*;
|
||||
use commit::*;
|
||||
use decommit::*;
|
||||
use mine::*;
|
||||
use open::*;
|
||||
use swap::*;
|
||||
@@ -21,6 +27,8 @@ pub fn process_instruction(
|
||||
match ix {
|
||||
OreInstruction::Open => process_open(accounts, data)?,
|
||||
OreInstruction::Close => process_close(accounts, data)?,
|
||||
OreInstruction::Commit => process_commit(accounts, data)?,
|
||||
OreInstruction::Decommit => process_decommit(accounts, data)?,
|
||||
OreInstruction::Mine => process_mine(accounts, data)?,
|
||||
OreInstruction::Swap => process_swap(accounts, data)?,
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ pub fn process_mine(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
|
||||
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, block_info, market_info, miner_info, mint_hash_info, mint_ore_info, recipient_info, sender_info, treasury_info, system_program, token_program, slot_hashes_sysvar] =
|
||||
let [signer_info, block_info, market_info, miner_info, mint_hash_info, mint_ore_info, permit_info, recipient_info, sender_info, treasury_info, system_program, token_program, slot_hashes_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
@@ -26,6 +26,9 @@ pub fn process_mine(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
|
||||
.assert(|m| m.id == block.id)?;
|
||||
mint_hash_info.has_address(&market.base.mint)?.as_mint()?;
|
||||
mint_ore_info.has_address(&MINT_ADDRESS)?.as_mint()?;
|
||||
permit_info
|
||||
.as_account::<Permit>(&ore_api::ID)?
|
||||
.assert(|p| p.authority == *signer_info.key)?;
|
||||
recipient_info
|
||||
.is_writable()?
|
||||
.as_associated_token_account(signer_info.key, &MINT_ADDRESS)?;
|
||||
|
||||
@@ -11,7 +11,7 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
|
||||
|
||||
// Load accounts.
|
||||
let clock = Clock::get()?;
|
||||
let [signer_info, block_info, market_info, mint_base_info, mint_quote_info, vault_base_info, vault_quote_info, system_program, token_program, associated_token_program, rent_sysvar] =
|
||||
let [signer_info, block_info, commitment_info, market_info, mint_base_info, mint_quote_info, vault_base_info, vault_quote_info, system_program, token_program, associated_token_program, rent_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
@@ -116,6 +116,21 @@ pub fn process_open(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult
|
||||
|
||||
// TODO Initialize hash token metadata.
|
||||
|
||||
// Initialize commitment token account.
|
||||
if commitment_info.data_is_empty() {
|
||||
create_associated_token_account(
|
||||
signer_info,
|
||||
block_info,
|
||||
commitment_info,
|
||||
mint_base_info,
|
||||
system_program,
|
||||
token_program,
|
||||
associated_token_program,
|
||||
)?;
|
||||
} else {
|
||||
commitment_info.as_associated_token_account(block_info.key, mint_base_info.key)?;
|
||||
}
|
||||
|
||||
// Initialize vault token accounts.
|
||||
if vault_base_info.data_is_empty() {
|
||||
create_associated_token_account(
|
||||
|
||||
Reference in New Issue
Block a user