mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-08-25 14:11:09 +00:00
179 lines
6.8 KiB
Rust
179 lines
6.8 KiB
Rust
use nssa_core::{
|
|
account::{Account, AccountId},
|
|
program::ProgramId,
|
|
};
|
|
use serde_json::{json, Value};
|
|
use token_core::{MetadataStandard, TokenDefinition, TokenHolding, TokenMetadata};
|
|
|
|
use super::{
|
|
parse_token_program_id,
|
|
request::{
|
|
DecodeAccountRequest, DecodeDefinitionRequest, DecodeHoldingRequest, DecodeMetadataRequest,
|
|
},
|
|
TokenApiError, TokenResult,
|
|
};
|
|
use crate::account::{account_id_hex, decode_account as decode_wallet_account};
|
|
|
|
pub fn decode_definition(request: DecodeDefinitionRequest) -> TokenResult {
|
|
let token_program_id = parse_token_program_id(&request.token_program_id)?;
|
|
let (account_id, account) = parse_and_validate_account(&request.definition, token_program_id)?;
|
|
let definition = TokenDefinition::try_from(&account.data)
|
|
.map_err(|_| TokenApiError::new("invalid_definition_data"))?;
|
|
Ok(definition_json(account_id, &definition))
|
|
}
|
|
|
|
pub fn decode_holding(request: DecodeHoldingRequest) -> TokenResult {
|
|
let token_program_id = parse_token_program_id(&request.token_program_id)?;
|
|
let (account_id, account) = parse_and_validate_account(&request.holding, token_program_id)?;
|
|
let holding = TokenHolding::try_from(&account.data)
|
|
.map_err(|_| TokenApiError::new("invalid_holding_data"))?;
|
|
Ok(holding_json(account_id, &holding))
|
|
}
|
|
|
|
pub fn decode_metadata(request: DecodeMetadataRequest) -> TokenResult {
|
|
let token_program_id = parse_token_program_id(&request.token_program_id)?;
|
|
let (account_id, account) = parse_and_validate_account(&request.metadata, token_program_id)?;
|
|
let metadata = TokenMetadata::try_from(&account.data)
|
|
.map_err(|_| TokenApiError::new("invalid_metadata_data"))?;
|
|
Ok(metadata_json(account_id, &metadata))
|
|
}
|
|
|
|
pub fn decode_account(request: DecodeAccountRequest) -> TokenResult {
|
|
let token_program_id = parse_token_program_id(&request.token_program_id)?;
|
|
let (account_id, account) = parse_and_validate_account(&request.account, token_program_id)?;
|
|
|
|
let definition = TokenDefinition::try_from(&account.data).ok();
|
|
let holding = TokenHolding::try_from(&account.data).ok();
|
|
let metadata = TokenMetadata::try_from(&account.data).ok();
|
|
let matches = usize::from(definition.is_some())
|
|
+ usize::from(holding.is_some())
|
|
+ usize::from(metadata.is_some());
|
|
|
|
match (matches, definition, holding, metadata) {
|
|
(1, Some(value), None, None) => Ok(definition_json(account_id, &value)),
|
|
(1, None, Some(value), None) => Ok(holding_json(account_id, &value)),
|
|
(1, None, None, Some(value)) => Ok(metadata_json(account_id, &value)),
|
|
(0, None, None, None) => Err(TokenApiError::new("invalid_account_data")),
|
|
_ => Err(TokenApiError::new("ambiguous_account_type")),
|
|
}
|
|
}
|
|
|
|
fn parse_and_validate_account(
|
|
read: &crate::account::AccountRead,
|
|
token_program_id: ProgramId,
|
|
) -> Result<(AccountId, Account), TokenApiError> {
|
|
let (account_id, account) = decode_wallet_account(read).map_err(map_account_read_error)?;
|
|
if account.program_owner != token_program_id {
|
|
return Err(TokenApiError::new("token_program_mismatch"));
|
|
}
|
|
Ok((account_id, account))
|
|
}
|
|
|
|
fn map_account_read_error(error: String) -> TokenApiError {
|
|
if error == "account read failed" {
|
|
TokenApiError::new("account_read_failed")
|
|
} else {
|
|
TokenApiError::new("bad_request")
|
|
}
|
|
}
|
|
|
|
fn definition_json(account_id: AccountId, definition: &TokenDefinition) -> Value {
|
|
let account_hex = account_id_hex(account_id);
|
|
match definition {
|
|
TokenDefinition::Fungible {
|
|
name,
|
|
total_supply,
|
|
metadata_id,
|
|
authority,
|
|
} => json!({
|
|
"accountType": "definition",
|
|
"kind": "fungible",
|
|
"accountId": account_id.to_string(),
|
|
"accountIdHex": account_hex,
|
|
"name": name,
|
|
"totalSupplyRaw": total_supply.to_string(),
|
|
"metadataId": metadata_id.map(|value| value.to_string()),
|
|
"metadataIdHex": metadata_id.map(account_id_hex),
|
|
"mintAuthorityId": authority.map(|value| value.to_string()),
|
|
"mintAuthorityIdHex": authority.map(account_id_hex),
|
|
}),
|
|
TokenDefinition::NonFungible {
|
|
name,
|
|
printable_supply,
|
|
metadata_id,
|
|
} => json!({
|
|
"accountType": "definition",
|
|
"kind": "nonFungible",
|
|
"accountId": account_id.to_string(),
|
|
"accountIdHex": account_hex,
|
|
"name": name,
|
|
"printableSupplyRaw": printable_supply.to_string(),
|
|
"metadataId": metadata_id.to_string(),
|
|
"metadataIdHex": account_id_hex(*metadata_id),
|
|
}),
|
|
}
|
|
}
|
|
|
|
fn holding_json(account_id: AccountId, holding: &TokenHolding) -> Value {
|
|
let account_hex = account_id_hex(account_id);
|
|
match holding {
|
|
TokenHolding::Fungible {
|
|
definition_id,
|
|
balance,
|
|
} => json!({
|
|
"accountType": "holding",
|
|
"kind": "fungible",
|
|
"accountId": account_id.to_string(),
|
|
"accountIdHex": account_hex,
|
|
"definitionId": definition_id.to_string(),
|
|
"definitionIdHex": account_id_hex(*definition_id),
|
|
"balanceRaw": balance.to_string(),
|
|
}),
|
|
TokenHolding::NftMaster {
|
|
definition_id,
|
|
print_balance,
|
|
} => json!({
|
|
"accountType": "holding",
|
|
"kind": "nftMaster",
|
|
"accountId": account_id.to_string(),
|
|
"accountIdHex": account_hex,
|
|
"definitionId": definition_id.to_string(),
|
|
"definitionIdHex": account_id_hex(*definition_id),
|
|
"printBalanceRaw": print_balance.to_string(),
|
|
}),
|
|
TokenHolding::NftPrintedCopy {
|
|
definition_id,
|
|
owned,
|
|
} => json!({
|
|
"accountType": "holding",
|
|
"kind": "nftPrintedCopy",
|
|
"accountId": account_id.to_string(),
|
|
"accountIdHex": account_hex,
|
|
"definitionId": definition_id.to_string(),
|
|
"definitionIdHex": account_id_hex(*definition_id),
|
|
"owned": owned,
|
|
}),
|
|
}
|
|
}
|
|
|
|
fn metadata_json(account_id: AccountId, metadata: &TokenMetadata) -> Value {
|
|
json!({
|
|
"accountType": "metadata",
|
|
"accountId": account_id.to_string(),
|
|
"accountIdHex": account_id_hex(account_id),
|
|
"definitionId": metadata.definition_id.to_string(),
|
|
"definitionIdHex": account_id_hex(metadata.definition_id),
|
|
"standard": metadata_standard_name(&metadata.standard),
|
|
"uri": metadata.uri,
|
|
"creators": metadata.creators,
|
|
"primarySaleDateRaw": metadata.primary_sale_date.to_string(),
|
|
})
|
|
}
|
|
|
|
fn metadata_standard_name(value: &MetadataStandard) -> &'static str {
|
|
match value {
|
|
MetadataStandard::Simple => "simple",
|
|
MetadataStandard::Expanded => "expanded",
|
|
}
|
|
}
|