@pod-protocol/cli
Version:
Official CLI for the PoD Protocol
258 lines • 9.41 kB
JavaScript
/**
* Digital Asset Standard (DAS) API Integration
* Provides interface for querying compressed NFTs and Merkle trees
*/
import { Connection } from '@solana/web3.js';
export class DASAPI {
connection;
endpoint;
developmentMode;
constructor(endpoint, developmentMode = false) {
this.endpoint = endpoint;
this.developmentMode = developmentMode;
this.connection = new Connection(endpoint);
}
async testConnection() {
if (this.developmentMode) {
const start = Date.now();
await new Promise(resolve => setTimeout(resolve, 10)); // Simulate latency
return {
healthy: true,
version: 'development-mock',
latency: Date.now() - start
};
}
try {
const start = Date.now();
await this.connection.getVersion();
return {
healthy: true,
version: 'production',
latency: Date.now() - start
};
}
catch (error) {
return {
healthy: false,
version: 'unknown',
latency: -1
};
}
}
async getAsset(assetId) {
if (this.developmentMode) {
return this.createMockAsset(assetId);
}
try {
const response = await fetch(`${this.endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'get-asset',
method: 'getAsset',
params: { id: assetId }
})
});
const data = await response.json();
return data.result;
}
catch (error) {
throw new Error(`Failed to fetch asset ${assetId}: ${error}`);
}
}
async getAssetsByOwner(owner, options = {}) {
if (this.developmentMode) {
const limit = options.limit || 20;
const page = options.page || 1;
const items = Array.from({ length: Math.min(limit, 5) }, (_, i) => this.createMockAsset(`${owner}_asset_${page}_${i}`));
return {
items,
total: 25,
limit,
page
};
}
try {
const response = await fetch(`${this.endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'get-assets-by-owner',
method: 'getAssetsByOwner',
params: {
ownerAddress: owner,
limit: options.limit || 20,
page: options.page || 1
}
})
});
const data = await response.json();
return data.result;
}
catch (error) {
throw new Error(`Failed to fetch assets for owner ${owner}: ${error}`);
}
}
async getAssetProof(assetId) {
if (this.developmentMode) {
return {
root: `root_${Math.random().toString(36).substring(7)}`,
proof: Array.from({ length: 14 }, (_, i) => `proof_${i}_${Math.random().toString(36).substring(7)}`),
node_index: Math.floor(Math.random() * 1000),
leaf: `leaf_${Math.random().toString(36).substring(7)}`,
tree_id: `tree_${Math.random().toString(36).substring(7)}`
};
}
try {
const response = await fetch(`${this.endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'get-asset-proof',
method: 'getAssetProof',
params: { id: assetId }
})
});
const data = await response.json();
return data.result;
}
catch (error) {
throw new Error(`Failed to fetch proof for asset ${assetId}: ${error}`);
}
}
async searchAssets(options = {}) {
if (this.developmentMode) {
const limit = options.limit || 20;
const page = options.page || 1;
const items = Array.from({ length: Math.min(limit, 8) }, (_, i) => this.createMockAsset(`search_result_${page}_${i}`, options.compressed !== false));
return {
items,
total: 50,
limit,
page
};
}
try {
const response = await fetch(`${this.endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'search-assets',
method: 'searchAssets',
params: options
})
});
const data = await response.json();
return data.result;
}
catch (error) {
throw new Error(`Failed to search assets: ${error}`);
}
}
async getAssetBatch(assetIds) {
if (this.developmentMode) {
return assetIds.map(id => this.createMockAsset(id));
}
try {
const response = await fetch(`${this.endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 'get-asset-batch',
method: 'getAssetBatch',
params: { ids: assetIds }
})
});
const data = await response.json();
return data.result;
}
catch (error) {
throw new Error(`Failed to fetch asset batch: ${error}`);
}
}
createMockAsset(id, compressed = true) {
return {
id,
content: {
metadata: {
name: `Mock NFT ${id}`,
symbol: 'MOCK',
description: `A mock compressed NFT for testing purposes`
},
files: [{
uri: `https://example.com/${id}.png`,
mime: 'image/png'
}],
json_uri: `https://example.com/${id}.json`
},
compression: compressed ? {
compressed: true,
tree: `tree_${Math.random().toString(36).substring(7)}`,
leaf_id: Math.floor(Math.random() * 1000),
data_hash: `data_${Math.random().toString(36).substring(7)}`,
creator_hash: `creator_${Math.random().toString(36).substring(7)}`,
asset_hash: `asset_${Math.random().toString(36).substring(7)}`,
seq: Math.floor(Math.random() * 100)
} : undefined,
ownership: {
owner: `owner_${Math.random().toString(36).substring(7)}`,
ownership_model: 'single'
},
royalty: {
royalty_model: 'creators',
percent: 5,
basis_points: 500
}
};
}
}
export class DASUtils {
static filterCompressedAssets(assets) {
return assets.filter(asset => asset.compression?.compressed === true);
}
static groupAssetsByTree(assets) {
const grouped = {};
assets.forEach(asset => {
if (asset.compression?.tree) {
if (!grouped[asset.compression.tree]) {
grouped[asset.compression.tree] = [];
}
grouped[asset.compression.tree].push(asset);
}
});
return grouped;
}
static calculateStorageSavings(nftCount) {
// Regular NFT cost: ~0.012 SOL per NFT (account rent)
const regularCostPerNFT = 0.012;
const regularCost = nftCount * regularCostPerNFT;
// Compressed NFT cost: ~0.000001 SOL per NFT (tree space)
const compressedCostPerNFT = 0.000001;
const compressedCost = nftCount * compressedCostPerNFT;
const savings = regularCost - compressedCost;
const multiplier = regularCost > 0 ? Math.round(regularCost / compressedCost) : 0;
return {
regular_cost: `${regularCost.toFixed(4)} SOL`,
compressed_cost: `${compressedCost.toFixed(6)} SOL`,
savings: `${savings.toFixed(4)} SOL`,
multiplier: `${multiplier}x`
};
}
static extractCollections(assets) {
const collections = {};
assets.forEach(asset => {
const collectionKey = asset.content.metadata.symbol || 'Unknown';
collections[collectionKey] = (collections[collectionKey] || 0) + 1;
});
return Object.entries(collections).map(([key, count]) => ({ key, count }));
}
}
export function createDASAPI(endpoint, developmentMode = false) {
return new DASAPI(endpoint, developmentMode);
}
//# sourceMappingURL=das-api.js.map