descro resolvers extension
This commit is contained in:
108
programs/descro_ext_resolvers/tests/common/mod.rs
Normal file
108
programs/descro_ext_resolvers/tests/common/mod.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
use {
|
||||
anchor_lang::{
|
||||
solana_program::{instruction::Instruction, system_program},
|
||||
AccountDeserialize, InstructionData, ToAccountMetas,
|
||||
},
|
||||
descro_ext_resolvers::{ResolverEntry, ResolverType},
|
||||
litesvm::LiteSVM,
|
||||
solana_keypair::Keypair,
|
||||
solana_message::{Message, VersionedMessage},
|
||||
solana_signer::Signer,
|
||||
solana_transaction::versioned::VersionedTransaction,
|
||||
};
|
||||
pub use anchor_lang::prelude::Pubkey;
|
||||
|
||||
pub fn setup() -> (LiteSVM, Keypair) {
|
||||
let program_id = descro_ext_resolvers::id();
|
||||
let mut svm = LiteSVM::new();
|
||||
let bytes = include_bytes!("../../../../target/deploy/descro_ext_resolvers.so");
|
||||
svm.add_program(program_id, bytes).unwrap();
|
||||
|
||||
let authority = Keypair::new();
|
||||
svm.airdrop(&authority.pubkey(), 10_000_000_000).unwrap();
|
||||
|
||||
(svm, authority)
|
||||
}
|
||||
|
||||
pub fn resolver_entry_pda(authority: &Pubkey) -> Pubkey {
|
||||
Pubkey::find_program_address(
|
||||
&[b"resolver", authority.as_ref()],
|
||||
&descro_ext_resolvers::id(),
|
||||
)
|
||||
.0
|
||||
}
|
||||
|
||||
pub fn send(svm: &mut LiteSVM, ix: Instruction, payer: &Keypair) {
|
||||
let blockhash = svm.latest_blockhash();
|
||||
let msg = Message::new_with_blockhash(&[ix], Some(&payer.pubkey()), &blockhash);
|
||||
let tx = VersionedTransaction::try_new(VersionedMessage::Legacy(msg), &[payer]).unwrap();
|
||||
svm.send_transaction(tx).expect("transaction failed");
|
||||
}
|
||||
|
||||
pub fn try_send(svm: &mut LiteSVM, ix: Instruction, payer: &Keypair) -> bool {
|
||||
let blockhash = svm.latest_blockhash();
|
||||
let msg = Message::new_with_blockhash(&[ix], Some(&payer.pubkey()), &blockhash);
|
||||
let tx = VersionedTransaction::try_new(VersionedMessage::Legacy(msg), &[payer]).unwrap();
|
||||
svm.send_transaction(tx).is_ok()
|
||||
}
|
||||
|
||||
pub fn ix_register(
|
||||
authority: &Pubkey,
|
||||
resolver_type: ResolverType,
|
||||
name: &str,
|
||||
description: &str,
|
||||
fee_bps: u16,
|
||||
fee_recipient: Pubkey,
|
||||
metadata_uri: &str,
|
||||
) -> Instruction {
|
||||
let entry = resolver_entry_pda(authority);
|
||||
Instruction::new_with_bytes(
|
||||
descro_ext_resolvers::id(),
|
||||
&descro_ext_resolvers::instruction::RegisterResolver {
|
||||
resolver_type,
|
||||
name: name.to_string(),
|
||||
description: description.to_string(),
|
||||
fee_bps,
|
||||
fee_recipient,
|
||||
metadata_uri: metadata_uri.to_string(),
|
||||
}
|
||||
.data(),
|
||||
descro_ext_resolvers::accounts::RegisterResolver {
|
||||
authority: *authority,
|
||||
resolver_entry: entry,
|
||||
system_program: system_program::ID,
|
||||
}
|
||||
.to_account_metas(None),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn ix_update(
|
||||
authority: &Pubkey,
|
||||
name: &str,
|
||||
description: &str,
|
||||
fee_bps: u16,
|
||||
metadata_uri: &str,
|
||||
) -> Instruction {
|
||||
let entry = resolver_entry_pda(authority);
|
||||
Instruction::new_with_bytes(
|
||||
descro_ext_resolvers::id(),
|
||||
&descro_ext_resolvers::instruction::UpdateResolver {
|
||||
name: name.to_string(),
|
||||
description: description.to_string(),
|
||||
fee_bps,
|
||||
metadata_uri: metadata_uri.to_string(),
|
||||
}
|
||||
.data(),
|
||||
descro_ext_resolvers::accounts::UpdateResolver {
|
||||
authority: *authority,
|
||||
resolver_entry: entry,
|
||||
}
|
||||
.to_account_metas(None),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn read_entry(svm: &LiteSVM, authority: &Pubkey) -> ResolverEntry {
|
||||
let pda = resolver_entry_pda(authority);
|
||||
let account = svm.get_account(&pda).expect("resolver entry not found");
|
||||
ResolverEntry::try_deserialize(&mut account.data.as_slice()).unwrap()
|
||||
}
|
||||
127
programs/descro_ext_resolvers/tests/test_register.rs
Normal file
127
programs/descro_ext_resolvers/tests/test_register.rs
Normal file
@@ -0,0 +1,127 @@
|
||||
mod common;
|
||||
use common::*;
|
||||
use descro_ext_resolvers::ResolverType;
|
||||
use solana_keypair::Keypair;
|
||||
use solana_signer::Signer;
|
||||
|
||||
#[test]
|
||||
fn registers_entry_with_correct_state() {
|
||||
let (mut svm, authority) = setup();
|
||||
|
||||
send(
|
||||
&mut svm,
|
||||
ix_register(
|
||||
&authority.pubkey(),
|
||||
ResolverType::CentralAuthority,
|
||||
"Acme Resolvers",
|
||||
"Fast and fair dispute resolution",
|
||||
100, // 1%
|
||||
authority.pubkey(),
|
||||
"ipfs://QmTest",
|
||||
),
|
||||
&authority,
|
||||
);
|
||||
|
||||
let entry = read_entry(&svm, &authority.pubkey());
|
||||
assert_eq!(entry.authority, authority.pubkey());
|
||||
assert_eq!(entry.resolver_type, ResolverType::CentralAuthority);
|
||||
assert_eq!(entry.name, "Acme Resolvers");
|
||||
assert_eq!(entry.fee_bps, 100);
|
||||
assert_eq!(entry.total_resolved, 0);
|
||||
assert_eq!(entry.ruled_for_buyer, 0);
|
||||
assert_eq!(entry.ruled_for_seller, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_register_fails() {
|
||||
let (mut svm, authority) = setup();
|
||||
|
||||
send(
|
||||
&mut svm,
|
||||
ix_register(
|
||||
&authority.pubkey(),
|
||||
ResolverType::CentralAuthority,
|
||||
"Acme",
|
||||
"",
|
||||
0,
|
||||
authority.pubkey(),
|
||||
"",
|
||||
),
|
||||
&authority,
|
||||
);
|
||||
assert!(!try_send(
|
||||
&mut svm,
|
||||
ix_register(
|
||||
&authority.pubkey(),
|
||||
ResolverType::CentralAuthority,
|
||||
"Acme Again",
|
||||
"",
|
||||
0,
|
||||
authority.pubkey(),
|
||||
"",
|
||||
),
|
||||
&authority,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn register_empty_name_fails() {
|
||||
let (mut svm, authority) = setup();
|
||||
|
||||
assert!(!try_send(
|
||||
&mut svm,
|
||||
ix_register(
|
||||
&authority.pubkey(),
|
||||
ResolverType::CentralAuthority,
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
authority.pubkey(),
|
||||
"",
|
||||
),
|
||||
&authority,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn register_invalid_fee_bps_fails() {
|
||||
let (mut svm, authority) = setup();
|
||||
|
||||
assert!(!try_send(
|
||||
&mut svm,
|
||||
ix_register(
|
||||
&authority.pubkey(),
|
||||
ResolverType::CentralAuthority,
|
||||
"Acme",
|
||||
"",
|
||||
10_001, // > 100%
|
||||
authority.pubkey(),
|
||||
"",
|
||||
),
|
||||
&authority,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn different_authorities_have_separate_entries() {
|
||||
let (mut svm, auth1) = setup();
|
||||
let auth2 = Keypair::new();
|
||||
svm.airdrop(&auth2.pubkey(), 10_000_000_000).unwrap();
|
||||
|
||||
send(
|
||||
&mut svm,
|
||||
ix_register(&auth1.pubkey(), ResolverType::CentralAuthority, "Auth1", "", 0, auth1.pubkey(), ""),
|
||||
&auth1,
|
||||
);
|
||||
send(
|
||||
&mut svm,
|
||||
ix_register(&auth2.pubkey(), ResolverType::JuryDAO, "Auth2", "", 50, auth2.pubkey(), ""),
|
||||
&auth2,
|
||||
);
|
||||
|
||||
let e1 = read_entry(&svm, &auth1.pubkey());
|
||||
let e2 = read_entry(&svm, &auth2.pubkey());
|
||||
assert_eq!(e1.name, "Auth1");
|
||||
assert_eq!(e2.name, "Auth2");
|
||||
assert_ne!(resolver_entry_pda(&auth1.pubkey()), resolver_entry_pda(&auth2.pubkey()));
|
||||
}
|
||||
83
programs/descro_ext_resolvers/tests/test_update.rs
Normal file
83
programs/descro_ext_resolvers/tests/test_update.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
mod common;
|
||||
use common::*;
|
||||
use descro_ext_resolvers::ResolverType;
|
||||
use solana_keypair::Keypair;
|
||||
use solana_signer::Signer;
|
||||
|
||||
fn register_default(svm: &mut litesvm::LiteSVM, authority: &Keypair) {
|
||||
send(
|
||||
svm,
|
||||
ix_register(
|
||||
&authority.pubkey(),
|
||||
ResolverType::CentralAuthority,
|
||||
"Original Name",
|
||||
"Original description",
|
||||
100,
|
||||
authority.pubkey(),
|
||||
"ipfs://original",
|
||||
),
|
||||
authority,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_changes_metadata() {
|
||||
let (mut svm, authority) = setup();
|
||||
register_default(&mut svm, &authority);
|
||||
|
||||
send(
|
||||
&mut svm,
|
||||
ix_update(&authority.pubkey(), "New Name", "New description", 200, "ipfs://new"),
|
||||
&authority,
|
||||
);
|
||||
|
||||
let entry = read_entry(&svm, &authority.pubkey());
|
||||
assert_eq!(entry.name, "New Name");
|
||||
assert_eq!(entry.description, "New description");
|
||||
assert_eq!(entry.fee_bps, 200);
|
||||
assert_eq!(entry.metadata_uri, "ipfs://new");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_different_authority_cannot_modify_entry() {
|
||||
let (mut svm, authority) = setup();
|
||||
let other = Keypair::new();
|
||||
svm.airdrop(&other.pubkey(), 1_000_000_000).unwrap();
|
||||
register_default(&mut svm, &authority);
|
||||
|
||||
// `other` signs but claims to BE the authority → seeds derive other's (non-existent) PDA
|
||||
// → account has no data → Anchor rejects the uninitialized account
|
||||
assert!(!try_send(
|
||||
&mut svm,
|
||||
ix_update(&other.pubkey(), "Hacked", "", 0, ""),
|
||||
&other,
|
||||
));
|
||||
|
||||
// `authority`'s entry is unchanged
|
||||
let entry = read_entry(&svm, &authority.pubkey());
|
||||
assert_eq!(entry.name, "Original Name");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_empty_name_fails() {
|
||||
let (mut svm, authority) = setup();
|
||||
register_default(&mut svm, &authority);
|
||||
|
||||
assert!(!try_send(
|
||||
&mut svm,
|
||||
ix_update(&authority.pubkey(), "", "", 0, ""),
|
||||
&authority,
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_invalid_fee_bps_fails() {
|
||||
let (mut svm, authority) = setup();
|
||||
register_default(&mut svm, &authority);
|
||||
|
||||
assert!(!try_send(
|
||||
&mut svm,
|
||||
ix_update(&authority.pubkey(), "Name", "", 10_001, ""),
|
||||
&authority,
|
||||
));
|
||||
}
|
||||
Reference in New Issue
Block a user