mirror of
https://github.com/d0zingcat/ore.git
synced 2026-05-15 23:16:46 +00:00
metaplex integration
This commit is contained in:
14
Cargo.lock
generated
14
Cargo.lock
generated
@@ -2105,6 +2105,19 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mpl-token-metadata"
|
||||
version = "4.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf0f61b553e424a6234af1268456972ee66c2222e1da89079242251fa7479e5"
|
||||
dependencies = [
|
||||
"borsh 0.10.3",
|
||||
"num-derive 0.3.3",
|
||||
"num-traits",
|
||||
"solana-program",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.26.4"
|
||||
@@ -2358,6 +2371,7 @@ dependencies = [
|
||||
"bs58 0.5.0",
|
||||
"bs64",
|
||||
"bytemuck",
|
||||
"mpl-token-metadata",
|
||||
"num_enum 0.7.2",
|
||||
"rand 0.8.5",
|
||||
"shank",
|
||||
|
||||
@@ -21,6 +21,7 @@ default = []
|
||||
[dependencies]
|
||||
bs58 = "0.5.0"
|
||||
bytemuck = "1.14.3"
|
||||
mpl-token-metadata = "4.1.2"
|
||||
num_enum = "0.7.2"
|
||||
shank = "0.3.0"
|
||||
solana-program = "^1.16"
|
||||
|
||||
@@ -3,7 +3,7 @@ use solana_program::{keccak::Hash, pubkey, pubkey::Pubkey};
|
||||
/// The unix timestamp after which mining is allowed.
|
||||
pub const START_AT: i64 = 0;
|
||||
|
||||
/// Bus pubkeys
|
||||
/// The addresses of the bus accounts.
|
||||
pub const BUS_ADDRESSES: [Pubkey; BUS_COUNT] = [
|
||||
pubkey!("85JC7qU7pkjYdvvXewfzgjCBZvugtrnPKYE9mzPD2ajJ"),
|
||||
pubkey!("FXCPt8PPwNQF8NVFDvdnHRENpkWexGMr5t8EnSoBsbns"),
|
||||
@@ -15,10 +15,13 @@ pub const BUS_ADDRESSES: [Pubkey; BUS_COUNT] = [
|
||||
pubkey!("72GSzz967ePb6mDrZYzmwyFFrfNUgH2PUwwocfeyjxLB"),
|
||||
];
|
||||
|
||||
/// The mint address of the ORE token.
|
||||
/// The address of the Ore mint metadata account.
|
||||
pub const METADATA_ADDRESS: Pubkey = pubkey!("4nbf4yufkBjJbZjZrz5D6L4nRyRbiw9rvKLTesCVpqnB");
|
||||
|
||||
/// The address of the Ore mint account.
|
||||
pub const MINT_ADDRESS: Pubkey = pubkey!("tmResQt9qPVRhAh74fMxginQqHBG74Ls3Nou1rkvCg7");
|
||||
|
||||
/// Treasury address
|
||||
/// The address of the treasury account.
|
||||
pub const TREASURY_ADDRESS: Pubkey = pubkey!("nLCGcWmqqLC2UVBb3neVQWhzzJd8GAJshvasczmVm94");
|
||||
|
||||
/// The initial reward rate to payout in the first epoch.
|
||||
@@ -66,6 +69,9 @@ static_assertions::const_assert!(
|
||||
/// The seed of the bus account PDA.
|
||||
pub const BUS: &[u8] = b"bus";
|
||||
|
||||
/// The seed of the mint account PDA.
|
||||
pub const METADATA: &[u8] = b"metadata";
|
||||
|
||||
/// The seed of the mint account PDA.
|
||||
pub const MINT: &[u8] = b"mint";
|
||||
|
||||
@@ -74,3 +80,12 @@ pub const PROOF: &[u8] = b"proof";
|
||||
|
||||
/// The seed of the treasury account PDA.
|
||||
pub const TREASURY: &[u8] = b"treasury";
|
||||
|
||||
/// The name for token metadata.
|
||||
pub const METADATA_NAME: &str = "Ore";
|
||||
|
||||
/// The ticker symbol for token metadata.
|
||||
pub const METADATA_SYMBOL: &str = "ORE";
|
||||
|
||||
/// The uri for token metdata.
|
||||
pub const METADATA_URI: &str = "https://ore.supply/public/metadata.json";
|
||||
|
||||
@@ -8,8 +8,8 @@ use solana_program::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
impl_instruction_from_bytes, impl_to_bytes, state::Hash, BUS, MINT, MINT_ADDRESS, PROOF,
|
||||
TREASURY, TREASURY_ADDRESS,
|
||||
impl_instruction_from_bytes, impl_to_bytes, state::Hash, BUS, METADATA, MINT, MINT_ADDRESS,
|
||||
PROOF, TREASURY, TREASURY_ADDRESS,
|
||||
};
|
||||
|
||||
#[repr(u8)]
|
||||
@@ -66,13 +66,15 @@ pub enum OreInstruction {
|
||||
#[account(7, name = "bus_5", desc = "Ore bus account 5", writable)]
|
||||
#[account(8, name = "bus_6", desc = "Ore bus account 6", writable)]
|
||||
#[account(9, name = "bus_7", desc = "Ore bus account 7", writable)]
|
||||
#[account(10, name = "mint", desc = "Ore token mint account")]
|
||||
#[account(11, name = "treasury", desc = "Ore treasury account")]
|
||||
#[account(12, name = "treasury_tokens", desc = "Ore treasury token account", writable)]
|
||||
#[account(13, name = "system_program", desc = "Solana system program")]
|
||||
#[account(14, name = "token_program", desc = "SPL token program")]
|
||||
#[account(15, name = "associated_token_program", desc = "SPL associated token program")]
|
||||
#[account(16, name = "rent", desc = "Solana rent sysvar")]
|
||||
#[account(10, name = "metadata", desc = "Ore mint metadata account", writable)]
|
||||
#[account(11, name = "mint", desc = "Ore mint account", writable)]
|
||||
#[account(12, name = "treasury", desc = "Ore treasury account", writable)]
|
||||
#[account(13, name = "treasury_tokens", desc = "Ore treasury token account", writable)]
|
||||
#[account(14, name = "system_program", desc = "Solana system program")]
|
||||
#[account(15, name = "token_program", desc = "SPL token program")]
|
||||
#[account(16, name = "associated_token_program", desc = "SPL associated token program")]
|
||||
#[account(17, name = "mpl_token_metadata", desc = "MPL token metadata program")]
|
||||
#[account(18, name = "rent", desc = "Solana rent sysvar")]
|
||||
Initialize = 100,
|
||||
|
||||
#[account(0, name = "ore_program", desc = "Ore program")]
|
||||
@@ -101,6 +103,7 @@ pub struct InitializeArgs {
|
||||
pub bus_5_bump: u8,
|
||||
pub bus_6_bump: u8,
|
||||
pub bus_7_bump: u8,
|
||||
pub metadata_bump: u8,
|
||||
pub mint_bump: u8,
|
||||
pub treasury_bump: u8,
|
||||
}
|
||||
@@ -168,6 +171,14 @@ pub fn initialize(signer: Pubkey) -> Instruction {
|
||||
];
|
||||
let mint_pda = Pubkey::find_program_address(&[MINT], &crate::id());
|
||||
let treasury_pda = Pubkey::find_program_address(&[TREASURY], &crate::id());
|
||||
let metadata_pda = Pubkey::find_program_address(
|
||||
&[
|
||||
METADATA,
|
||||
mpl_token_metadata::ID.as_ref(),
|
||||
mint_pda.0.as_ref(),
|
||||
],
|
||||
&mpl_token_metadata::ID,
|
||||
);
|
||||
Instruction {
|
||||
program_id: crate::id(),
|
||||
accounts: vec![
|
||||
@@ -180,12 +191,14 @@ pub fn initialize(signer: Pubkey) -> Instruction {
|
||||
AccountMeta::new(bus_pdas[5].0, false),
|
||||
AccountMeta::new(bus_pdas[6].0, false),
|
||||
AccountMeta::new(bus_pdas[7].0, false),
|
||||
AccountMeta::new(metadata_pda.0, false),
|
||||
AccountMeta::new(mint_pda.0, false),
|
||||
AccountMeta::new(treasury_pda.0, false),
|
||||
AccountMeta::new(treasury_tokens, false),
|
||||
AccountMeta::new_readonly(system_program::id(), false),
|
||||
AccountMeta::new_readonly(spl_token::id(), false),
|
||||
AccountMeta::new_readonly(spl_associated_token_account::id(), false),
|
||||
AccountMeta::new_readonly(mpl_token_metadata::ID, false),
|
||||
AccountMeta::new_readonly(sysvar::rent::id(), false),
|
||||
],
|
||||
data: [
|
||||
@@ -199,6 +212,7 @@ pub fn initialize(signer: Pubkey) -> Instruction {
|
||||
bus_5_bump: bus_pdas[5].1,
|
||||
bus_6_bump: bus_pdas[6].1,
|
||||
bus_7_bump: bus_pdas[7].1,
|
||||
metadata_bump: metadata_pda.1,
|
||||
mint_bump: mint_pda.1,
|
||||
treasury_bump: treasury_pda.1,
|
||||
}
|
||||
|
||||
@@ -201,8 +201,9 @@ pub fn load_token_account<'a, 'info>(
|
||||
pub fn load_uninitialized_pda<'a, 'info>(
|
||||
info: &'a AccountInfo<'info>,
|
||||
seeds: &[&[u8]],
|
||||
program_id: &Pubkey,
|
||||
) -> Result<(), ProgramError> {
|
||||
let key = Pubkey::create_program_address(seeds, &crate::id())?;
|
||||
let key = Pubkey::create_program_address(seeds, program_id)?;
|
||||
if info.key.ne(&key) {
|
||||
return Err(ProgramError::InvalidSeeds);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ use crate::{
|
||||
utils::create_pda,
|
||||
utils::AccountDeserialize,
|
||||
utils::Discriminator,
|
||||
BUS, BUS_ADDRESSES, BUS_COUNT, INITIAL_DIFFICULTY, INITIAL_REWARD_RATE, MINT, MINT_ADDRESS,
|
||||
BUS, BUS_ADDRESSES, BUS_COUNT, INITIAL_DIFFICULTY, INITIAL_REWARD_RATE, METADATA,
|
||||
METADATA_ADDRESS, METADATA_NAME, METADATA_SYMBOL, METADATA_URI, MINT, MINT_ADDRESS,
|
||||
TOKEN_DECIMALS, TREASURY, TREASURY_ADDRESS,
|
||||
};
|
||||
|
||||
@@ -45,29 +46,47 @@ pub fn process_initialize<'a, 'info>(
|
||||
let args = InitializeArgs::try_from_bytes(data)?;
|
||||
|
||||
// Load accounts
|
||||
let [signer, bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info, bus_7_info, mint_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program, rent_sysvar] =
|
||||
let [signer, bus_0_info, bus_1_info, bus_2_info, bus_3_info, bus_4_info, bus_5_info, bus_6_info, bus_7_info, metadata_info, mint_info, treasury_info, treasury_tokens_info, system_program, token_program, associated_token_program, metadata_program, rent_sysvar] =
|
||||
accounts
|
||||
else {
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
load_signer(signer)?;
|
||||
load_uninitialized_pda(bus_0_info, &[BUS, &[0], &[args.bus_0_bump]])?;
|
||||
load_uninitialized_pda(bus_1_info, &[BUS, &[1], &[args.bus_1_bump]])?;
|
||||
load_uninitialized_pda(bus_2_info, &[BUS, &[2], &[args.bus_2_bump]])?;
|
||||
load_uninitialized_pda(bus_3_info, &[BUS, &[3], &[args.bus_3_bump]])?;
|
||||
load_uninitialized_pda(bus_4_info, &[BUS, &[4], &[args.bus_4_bump]])?;
|
||||
load_uninitialized_pda(bus_5_info, &[BUS, &[5], &[args.bus_5_bump]])?;
|
||||
load_uninitialized_pda(bus_6_info, &[BUS, &[6], &[args.bus_6_bump]])?;
|
||||
load_uninitialized_pda(bus_7_info, &[BUS, &[7], &[args.bus_7_bump]])?;
|
||||
load_uninitialized_pda(mint_info, &[MINT, &[args.mint_bump]])?;
|
||||
load_uninitialized_pda(treasury_info, &[TREASURY, &[args.treasury_bump]])?;
|
||||
load_uninitialized_pda(bus_0_info, &[BUS, &[0], &[args.bus_0_bump]], &crate::id())?;
|
||||
load_uninitialized_pda(bus_1_info, &[BUS, &[1], &[args.bus_1_bump]], &crate::id())?;
|
||||
load_uninitialized_pda(bus_2_info, &[BUS, &[2], &[args.bus_2_bump]], &crate::id())?;
|
||||
load_uninitialized_pda(bus_3_info, &[BUS, &[3], &[args.bus_3_bump]], &crate::id())?;
|
||||
load_uninitialized_pda(bus_4_info, &[BUS, &[4], &[args.bus_4_bump]], &crate::id())?;
|
||||
load_uninitialized_pda(bus_5_info, &[BUS, &[5], &[args.bus_5_bump]], &crate::id())?;
|
||||
load_uninitialized_pda(bus_6_info, &[BUS, &[6], &[args.bus_6_bump]], &crate::id())?;
|
||||
load_uninitialized_pda(bus_7_info, &[BUS, &[7], &[args.bus_7_bump]], &crate::id())?;
|
||||
load_uninitialized_pda(
|
||||
metadata_info,
|
||||
&[
|
||||
METADATA,
|
||||
mpl_token_metadata::ID.as_ref(),
|
||||
MINT_ADDRESS.as_ref(),
|
||||
&[args.metadata_bump],
|
||||
],
|
||||
&mpl_token_metadata::ID,
|
||||
)?;
|
||||
load_uninitialized_pda(mint_info, &[MINT, &[args.mint_bump]], &crate::id())?;
|
||||
load_uninitialized_pda(
|
||||
treasury_info,
|
||||
&[TREASURY, &[args.treasury_bump]],
|
||||
&crate::id(),
|
||||
)?;
|
||||
load_uninitialized_account(treasury_tokens_info)?;
|
||||
load_program(system_program, system_program::id())?;
|
||||
load_program(token_program, spl_token::id())?;
|
||||
load_program(associated_token_program, spl_associated_token_account::id())?;
|
||||
load_program(metadata_program, mpl_token_metadata::ID)?;
|
||||
load_sysvar(rent_sysvar, sysvar::rent::id())?;
|
||||
|
||||
// Verify keys
|
||||
if metadata_info.key.ne(&METADATA_ADDRESS) {
|
||||
return Err(ProgramError::InvalidSeeds);
|
||||
}
|
||||
if mint_info.key.ne(&MINT_ADDRESS) {
|
||||
return Err(ProgramError::InvalidSeeds);
|
||||
}
|
||||
@@ -155,6 +174,32 @@ pub fn process_initialize<'a, 'info>(
|
||||
&[&[MINT, &[args.mint_bump]]],
|
||||
)?;
|
||||
|
||||
// Initialize mint metadata
|
||||
mpl_token_metadata::instructions::CreateMetadataAccountV3Cpi {
|
||||
__program: metadata_program,
|
||||
metadata: metadata_info,
|
||||
mint: mint_info,
|
||||
mint_authority: treasury_info,
|
||||
payer: signer,
|
||||
update_authority: (signer, true),
|
||||
system_program,
|
||||
rent: Some(rent_sysvar),
|
||||
__args: mpl_token_metadata::instructions::CreateMetadataAccountV3InstructionArgs {
|
||||
data: mpl_token_metadata::types::DataV2 {
|
||||
name: METADATA_NAME.to_string(),
|
||||
symbol: METADATA_SYMBOL.to_string(),
|
||||
uri: METADATA_URI.to_string(),
|
||||
seller_fee_basis_points: 0,
|
||||
creators: None,
|
||||
collection: None,
|
||||
uses: None,
|
||||
},
|
||||
is_mutable: true,
|
||||
collection_details: None,
|
||||
},
|
||||
}
|
||||
.invoke_signed(&[&[TREASURY, &[args.treasury_bump]]])?;
|
||||
|
||||
// Initialize treasury token account
|
||||
solana_program::program::invoke(
|
||||
&spl_associated_token_account::instruction::create_associated_token_account(
|
||||
|
||||
@@ -36,7 +36,11 @@ pub fn process_register<'a, 'info>(
|
||||
return Err(ProgramError::NotEnoughAccountKeys);
|
||||
};
|
||||
load_signer(signer)?;
|
||||
load_uninitialized_pda(proof_info, &[PROOF, signer.key.as_ref(), &[args.bump]])?;
|
||||
load_uninitialized_pda(
|
||||
proof_info,
|
||||
&[PROOF, signer.key.as_ref(), &[args.bump]],
|
||||
&crate::id(),
|
||||
)?;
|
||||
load_program(system_program, system_program::id())?;
|
||||
|
||||
// Initialize proof
|
||||
|
||||
BIN
tests/buffers/metadata_program.bpf
Normal file
BIN
tests/buffers/metadata_program.bpf
Normal file
Binary file not shown.
@@ -1,11 +1,19 @@
|
||||
use mpl_token_metadata::{
|
||||
accounts::Metadata,
|
||||
types::{Key, TokenStandard},
|
||||
};
|
||||
use ore::{
|
||||
state::{Bus, Treasury},
|
||||
utils::AccountDeserialize,
|
||||
BUS_ADDRESSES, BUS_COUNT, INITIAL_DIFFICULTY, INITIAL_REWARD_RATE, MINT_ADDRESS, TREASURY,
|
||||
BUS_ADDRESSES, BUS_COUNT, INITIAL_DIFFICULTY, INITIAL_REWARD_RATE, METADATA_ADDRESS,
|
||||
METADATA_NAME, METADATA_SYMBOL, METADATA_URI, MINT_ADDRESS, TREASURY,
|
||||
};
|
||||
use solana_program::{hash::Hash, program_option::COption, program_pack::Pack, pubkey::Pubkey};
|
||||
use solana_program_test::{processor, BanksClient, ProgramTest};
|
||||
use solana_program::{
|
||||
hash::Hash, program_option::COption, program_pack::Pack, pubkey::Pubkey, rent::Rent,
|
||||
};
|
||||
use solana_program_test::{processor, read_file, BanksClient, ProgramTest};
|
||||
use solana_sdk::{
|
||||
account::Account,
|
||||
signature::{Keypair, Signer},
|
||||
transaction::Transaction,
|
||||
};
|
||||
@@ -57,6 +65,27 @@ async fn test_initialize() {
|
||||
assert_eq!(mint.is_initialized, true);
|
||||
assert_eq!(mint.freeze_authority, COption::None);
|
||||
|
||||
// Test metadata state
|
||||
let metadata_account = banks.get_account(METADATA_ADDRESS).await.unwrap().unwrap();
|
||||
assert_eq!(metadata_account.owner, mpl_token_metadata::ID);
|
||||
let metadata = Metadata::from_bytes(&metadata_account.data).unwrap();
|
||||
assert_eq!(metadata.key, Key::MetadataV1);
|
||||
assert_eq!(metadata.update_authority, payer.pubkey());
|
||||
assert_eq!(metadata.mint, MINT_ADDRESS);
|
||||
assert_eq!(metadata.name.trim_end_matches('\0'), METADATA_NAME);
|
||||
assert_eq!(metadata.symbol.trim_end_matches('\0'), METADATA_SYMBOL);
|
||||
assert_eq!(metadata.uri.trim_end_matches('\0'), METADATA_URI);
|
||||
assert_eq!(metadata.seller_fee_basis_points, 0);
|
||||
assert_eq!(metadata.creators, None);
|
||||
assert_eq!(metadata.primary_sale_happened, false);
|
||||
assert_eq!(metadata.is_mutable, true);
|
||||
assert_eq!(metadata.edition_nonce, Some(u8::MAX));
|
||||
assert_eq!(metadata.token_standard, Some(TokenStandard::Fungible));
|
||||
assert_eq!(metadata.collection, None);
|
||||
assert_eq!(metadata.uses, None);
|
||||
assert_eq!(metadata.collection_details, None);
|
||||
assert_eq!(metadata.programmable_config, None);
|
||||
|
||||
// Test treasury token state
|
||||
let treasury_tokens_account = banks
|
||||
.get_account(treasury_tokens_address)
|
||||
@@ -78,5 +107,19 @@ async fn test_initialize() {
|
||||
async fn setup_program_test_env() -> (BanksClient, Keypair, Hash) {
|
||||
let mut program_test = ProgramTest::new("ore", ore::ID, processor!(ore::process_instruction));
|
||||
program_test.prefer_bpf(true);
|
||||
|
||||
// Setup metadata program
|
||||
let data = read_file(&"tests/buffers/metadata_program.bpf");
|
||||
program_test.add_account(
|
||||
mpl_token_metadata::ID,
|
||||
Account {
|
||||
lamports: Rent::default().minimum_balance(data.len()).max(1),
|
||||
data,
|
||||
owner: solana_sdk::bpf_loader::id(),
|
||||
executable: true,
|
||||
rent_epoch: 0,
|
||||
},
|
||||
);
|
||||
|
||||
program_test.start().await
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{mem::size_of, str::FromStr};
|
||||
|
||||
use ore::{
|
||||
instruction::{MineArgs, OreInstruction, RegisterArgs},
|
||||
instruction::{MineArgs, OreInstruction},
|
||||
state::{Bus, Proof, Treasury},
|
||||
utils::{AccountDeserialize, Discriminator},
|
||||
BUS_ADDRESSES, BUS_COUNT, INITIAL_REWARD_RATE, MINT_ADDRESS, PROOF, TOKEN_DECIMALS, TREASURY,
|
||||
|
||||
Reference in New Issue
Block a user