Skip to content

Commit

Permalink
Fix asset to hotspot conversion (#373)
Browse files Browse the repository at this point in the history
* Fix asset to hotspot conversion

Asset convertion to a Hotspot was relying on a metadata field that may take over 24 hours to get populated, and is only to be used for non critical purposes.

This PR introduces a KeyToAsset cache that is used to cache asset accounts based on the asset key. The cache is then used for Asset->Hotspot conversion to get the entity key (back)

* Fix onboarding update txn params

The location passed into the onboarding server was not a quoted big number.. This fix removes serde_with as a dependency and fixes the issue in request parameter construction

* kta module, naming cleanup

asset_account renamed to kta, created separate module for kta functionality.

kta module supports get_many to fetch many kta_keys

* use Error::account_not_found convenience
  • Loading branch information
madninja authored Jun 13, 2024
1 parent 5fa6d0d commit 55e926a
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 144 deletions.
9 changes: 0 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion helium-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ solana-program = "*"
solana-transaction-status = "*"
serde = {workspace = true}
serde_json = {workspace = true}
serde_with = "2"
# serde_with = "2"
lazy_static = "1"
rust_decimal = {workspace = true}
helium-proto = {workspace= true}
Expand Down
97 changes: 59 additions & 38 deletions helium-lib/src/asset.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,40 @@
use crate::{
dao::Dao,
entity_key::AsEntityKey,
keypair::{serde_opt_pubkey, serde_pubkey, Keypair, Pubkey},
entity_key::{self, AsEntityKey},
keypair::{serde_opt_pubkey, serde_pubkey, Pubkey},
kta,
result::{DecodeError, Error, Result},
settings::{DasClient, DasSearchAssetsParams, Settings},
};
use helium_anchor_gen::helium_entity_manager;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use solana_sdk::{bs58, signer::Signer};
use std::{collections::HashMap, ops::Deref, result::Result as StdResult, str::FromStr};

pub async fn account_for_entity_key<C: Clone + Deref<Target = impl Signer>, E>(
client: &anchor_client::Client<C>,
entity_key: &E,
) -> Result<helium_entity_manager::KeyToAssetV0>
where
E: AsEntityKey,
{
let program = client.program(helium_entity_manager::id())?;
let asset_key = Dao::Hnt.key_to_asset_key(entity_key);
let asset_account = program
.account::<helium_entity_manager::KeyToAssetV0>(asset_key)
.await?;
Ok(asset_account)
}
use solana_sdk::bs58;
use std::{collections::HashMap, result::Result as StdResult, str::FromStr};

pub async fn for_entity_key<E>(settings: &Settings, entity_key: &E) -> Result<Asset>
where
E: AsEntityKey,
{
let client = settings.mk_anchor_client(Keypair::void())?;
let asset_account = account_for_entity_key(&client, entity_key).await?;
get(settings, &asset_account).await
let kta = kta::for_entity_key(entity_key).await?;
for_kta(settings, &kta).await
}

pub async fn get(
pub async fn for_kta(
settings: &Settings,
asset_account: &helium_entity_manager::KeyToAssetV0,
kta: &helium_entity_manager::KeyToAssetV0,
) -> Result<Asset> {
let jsonrpc = settings.mk_jsonrpc_client()?;
let asset_responase: Asset = jsonrpc.get_asset(&asset_account.asset).await?;
let asset_responase: Asset = jsonrpc.get_asset(&kta.asset).await?;
Ok(asset_responase)
}

pub async fn get_with_proof(
pub async fn for_kta_with_proof(
settings: &Settings,
asset_account: &helium_entity_manager::KeyToAssetV0,
kta: &helium_entity_manager::KeyToAssetV0,
) -> Result<(Asset, AssetProof)> {
let (asset, asset_proof) = futures::try_join!(
get(settings, asset_account),
proof::get(settings, asset_account)
)?;
let (asset, asset_proof) =
futures::try_join!(for_kta(settings, kta), proof::get(settings, kta))?;
Ok((asset, asset_proof))
}

Expand Down Expand Up @@ -80,11 +63,10 @@ pub mod proof {

pub async fn get(
settings: &Settings,
asset_account: &helium_entity_manager::KeyToAssetV0,
kta: &helium_entity_manager::KeyToAssetV0,
) -> Result<AssetProof> {
let jsonrpc = settings.mk_jsonrpc_client()?;
let asset_proof_response: AssetProof =
jsonrpc.get_asset_proof(&asset_account.asset).await?;
let asset_proof_response: AssetProof = jsonrpc.get_asset_proof(&kta.asset).await?;

Ok(asset_proof_response)
}
Expand All @@ -93,9 +75,8 @@ pub mod proof {
where
E: AsEntityKey,
{
let client = settings.mk_anchor_client(Keypair::void())?;
let asset_account = account_for_entity_key(&client, entity_key).await?;
get(settings, &asset_account).await
let kta = kta::for_entity_key(entity_key).await?;
get(settings, &kta).await
}
}

Expand Down Expand Up @@ -136,10 +117,19 @@ pub struct Asset {
#[serde(with = "serde_pubkey")]
pub id: Pubkey,
pub compression: AssetCompression,
pub creators: Vec<AssetCreator>,
pub ownership: AssetOwnership,
pub content: AssetContent,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct AssetCreator {
#[serde(with = "serde_pubkey")]
address: Pubkey,
share: u8,
verified: bool,
}

pub type Hash = [u8; 32];

#[derive(Debug, Deserialize, Serialize, Clone)]
Expand Down Expand Up @@ -176,6 +166,37 @@ pub struct AssetProof {
pub tree_id: Pubkey,
}

impl Asset {
pub fn kta_key(&self) -> Result<Pubkey> {
if let Some(creator) = self.creators.get(1) {
return Ok(creator.address);
}
let entity_key_str = self
.content
.json_uri
.path()
.strip_prefix('/')
.map(ToString::to_string)
.ok_or(DecodeError::other(format!(
"missing entity key in \"{}\"",
self.content.json_uri
)))?;
let key_serialization =
if ["IOT OPS", "CARRIER"].contains(&self.content.metadata.symbol.as_str()) {
helium_entity_manager::KeySerialization::UTF8
} else {
helium_entity_manager::KeySerialization::B58
};
let entity_key = entity_key::from_string(entity_key_str, key_serialization)?;
let kta_key = Dao::Hnt.entity_key_to_kta_key(&entity_key);
Ok(kta_key)
}

pub async fn get_kta(&self) -> Result<helium_entity_manager::KeyToAssetV0> {
kta::get(&self.kta_key()?).await
}
}

impl AssetProof {
pub fn proof(
&self,
Expand Down Expand Up @@ -204,7 +225,7 @@ impl AssetProof {
let canopy_heights = get_canopy_heights().await?;
let height = canopy_heights
.get(tree)
.ok_or_else(|| anchor_client::ClientError::AccountNotFound)?;
.ok_or_else(Error::account_not_found)?;
self.proof(Some(*height))
}
}
Expand Down
17 changes: 7 additions & 10 deletions helium-lib/src/dao.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use crate::{
entity_key::AsEntityKey,
keypair::Pubkey,
programs::{MPL_BUBBLEGUM_PROGRAM_ID, TOKEN_METADATA_PROGRAM_ID},
result::Result,
entity_key::AsEntityKey, keypair::Pubkey, programs::TOKEN_METADATA_PROGRAM_ID, result::Result,
token::Token,
};
use helium_anchor_gen::{data_credits, helium_entity_manager, helium_sub_daos, lazy_distributor};
Expand Down Expand Up @@ -75,13 +72,13 @@ impl Dao {

pub fn merkle_tree_authority(&self, merkle_tree: &Pubkey) -> Pubkey {
let (tree_authority, _ta_bump) =
Pubkey::find_program_address(&[merkle_tree.as_ref()], &MPL_BUBBLEGUM_PROGRAM_ID);
Pubkey::find_program_address(&[merkle_tree.as_ref()], &mpl_bubblegum::ID);
tree_authority
}

pub fn bubblegum_signer(&self) -> Pubkey {
let (bubblegum_signer, _bs_bump) =
Pubkey::find_program_address(&[b"collection_cpi"], &MPL_BUBBLEGUM_PROGRAM_ID);
Pubkey::find_program_address(&[b"collection_cpi"], &mpl_bubblegum::ID);
bubblegum_signer
}

Expand All @@ -93,7 +90,7 @@ impl Dao {
key
}

pub fn key_to_asset_key<E: AsEntityKey + ?Sized>(&self, entity_key: &E) -> Pubkey {
pub fn entity_key_to_kta_key<E: AsEntityKey + ?Sized>(&self, entity_key: &E) -> Pubkey {
let hash = Sha256::digest(entity_key.as_entity_key());
let (key, _) = Pubkey::find_program_address(
&[b"key_to_asset", self.key().as_ref(), hash.as_ref()],
Expand Down Expand Up @@ -170,7 +167,7 @@ impl SubDao {
key
}

pub fn escrow_account_key(&self, delegated_dc_key: &Pubkey) -> Pubkey {
pub fn escrow_key(&self, delegated_dc_key: &Pubkey) -> Pubkey {
let (key, _) = Pubkey::find_program_address(
&[b"escrow_dc_account", delegated_dc_key.as_ref()],
&data_credits::id(),
Expand Down Expand Up @@ -217,12 +214,12 @@ impl SubDao {
key
}

pub fn asset_key_to_receipient_key(&self, asset_key: &Pubkey) -> Pubkey {
pub fn receipient_key_from_kta(&self, kta: &helium_entity_manager::KeyToAssetV0) -> Pubkey {
let (key, _) = Pubkey::find_program_address(
&[
b"recipient",
self.lazy_distributor_key().as_ref(),
asset_key.as_ref(),
kta.asset.as_ref(),
],
&lazy_distributor::id(),
);
Expand Down
2 changes: 1 addition & 1 deletion helium-lib/src/dc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pub async fn delegate<C: Clone + Deref<Target = impl Signer> + GetPubkey>(
sub_dao: subdao.key(),
owner: keypair.pubkey(),
from_account: Token::Dc.associated_token_adress(&keypair.pubkey()),
escrow_account: subdao.escrow_account_key(&delegated_data_credits),
escrow_account: subdao.escrow_key(&delegated_data_credits),
payer: keypair.pubkey(),
associated_token_program: anchor_spl::associated_token::ID,
token_program: anchor_spl::token::ID,
Expand Down
Loading

0 comments on commit 55e926a

Please sign in to comment.