mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-08-27 07:01:14 +00:00
feat(token): add Logos token API module
This commit is contained in:
committed by
r4bbit
parent
72a3e741a0
commit
741e72add9
@@ -0,0 +1,178 @@
|
||||
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",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user