Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
IkigaiLabsETH committed Dec 21, 2024
1 parent ef8734e commit 15e1ca0
Show file tree
Hide file tree
Showing 9 changed files with 726 additions and 768 deletions.
17 changes: 17 additions & 0 deletions packages/plugin-nft-collections/src/constants/collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ export const NFTCollectionSchema = z.object({
verified: z.boolean().default(true),
featured: z.boolean().default(false),
createdAt: z.string().optional(),
// Market data
floorPrice: z.number().optional(),
volume24h: z.number().optional(),
marketCap: z.number().optional(),
holders: z.number().optional(),
totalSupply: z.number().optional(),
// Social metrics
twitterFollowers: z.number().optional(),
discordMembers: z.number().optional(),
// Trading features
supportedMarketplaces: z.array(z.string()).optional(),
hasRoyalties: z.boolean().optional(),
royaltyPercentage: z.number().optional(),
// Metadata
traits: z.record(z.string(), z.array(z.string())).optional(),
categories: z.array(z.string()).optional(),
lastUpdate: z.string().optional(),
});

export type NFTCollection = z.infer<typeof NFTCollectionSchema>;
Expand Down
125 changes: 82 additions & 43 deletions packages/plugin-nft-collections/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,34 @@ import {
import { ReservoirService } from "./services/reservoir";
import { MarketIntelligenceService } from "./services/market-intelligence";
import { SocialAnalyticsService } from "./services/social-analytics";
import { CacheManager } from "./services/cache-manager";
import { RateLimiter } from "./services/rate-limiter";
import { SecurityManager } from "./services/security-manager";
import { nftCollectionProvider } from "./providers/nft-collections";
import { sweepFloorAction } from "./actions/sweep-floor";
import { listNFTAction } from "./actions/list-nft";

interface NFTCollectionsPluginConfig {
caching?: {
enabled: boolean;
ttl?: number;
maxSize?: number;
};
security?: {
rateLimit?: {
enabled: boolean;
maxRequests?: number;
windowMs?: number;
};
};
}

interface ExtendedCharacter extends Character {
providers?: any[];
actions?: any[];
runtime?: IAgentRuntime;
}

export class NFTCollectionsPlugin implements Plugin {
public readonly name = "nft-collections";
public readonly description =
Expand All @@ -19,44 +43,54 @@ export class NFTCollectionsPlugin implements Plugin {
private reservoirService?: ReservoirService;
private marketIntelligenceService?: MarketIntelligenceService;
private socialAnalyticsService?: SocialAnalyticsService;
private cacheManager?: CacheManager;
private rateLimiter?: RateLimiter;
private securityManager?: SecurityManager;

constructor() {
// No need for super() since we're implementing, not extending
constructor(private config: NFTCollectionsPluginConfig = {}) {
this.initializeServices();
}

async setup(
character: Character & { runtime?: IAgentRuntime }
): Promise<void> {
private initializeServices(): void {
// Initialize caching if enabled
if (this.config.caching?.enabled) {
this.cacheManager = new CacheManager({
ttl: this.config.caching.ttl || 3600000, // 1 hour default
maxSize: this.config.caching.maxSize || 1000,
});
}

// Initialize rate limiter if enabled
if (this.config.security?.rateLimit?.enabled) {
this.rateLimiter = new RateLimiter({
maxRequests: this.config.security.rateLimit.maxRequests || 100,
windowMs: this.config.security.rateLimit.windowMs || 60000,
});
}
}

async setup(character: ExtendedCharacter): Promise<void> {
if (!character.runtime) {
throw new Error("Runtime not available in character");
}

console.log(
"Character settings:",
JSON.stringify(character.settings, null, 2)
);
console.log(
"Environment RESERVOIR_API_KEY:",
process.env.RESERVOIR_API_KEY
);

// Try to get the API key from character settings or environment variable
const reservoirApiKey =
character.settings?.secrets?.RESERVOIR_API_KEY ||
process.env.RESERVOIR_API_KEY;
console.log("Final reservoirApiKey:", reservoirApiKey);

if (!reservoirApiKey) {
throw new Error(
"RESERVOIR_API_KEY is required in either character settings or environment variables"
);
throw new Error("RESERVOIR_API_KEY is required");
}

this.reservoirService = new ReservoirService(reservoirApiKey);
// Initialize Reservoir service
this.reservoirService = new ReservoirService(reservoirApiKey, {
cacheManager: this.cacheManager,
rateLimiter: this.rateLimiter,
});
await this.reservoirService.initialize(character.runtime);
await character.runtime.registerService(this.reservoirService);

// Optional services
// Initialize optional services
const marketApiKeys = {
nansen: character.settings.secrets?.NANSEN_API_KEY,
dune: character.settings.secrets?.DUNE_API_KEY,
Expand All @@ -65,45 +99,50 @@ export class NFTCollectionsPlugin implements Plugin {
nftscan: character.settings.secrets?.NFTSCAN_API_KEY,
};

const socialApiKeys = {
twitter: character.settings.secrets?.TWITTER_API_KEY,
discord: character.settings.secrets?.DISCORD_API_KEY,
telegram: character.settings.secrets?.TELEGRAM_API_KEY,
alchemy: character.settings.secrets?.ALCHEMY_API_KEY,
nftscan: character.settings.secrets?.NFTSCAN_API_KEY,
};

// Initialize optional services only if API keys are provided
if (Object.values(marketApiKeys).some((key) => key)) {
this.marketIntelligenceService = new MarketIntelligenceService(
marketApiKeys
);
await this.marketIntelligenceService.initialize();
this.marketIntelligenceService = new MarketIntelligenceService({
cacheManager: this.cacheManager,
rateLimiter: this.rateLimiter,
});
await this.marketIntelligenceService.initialize(character.runtime);
await character.runtime.registerService(
this.marketIntelligenceService
);
}

const socialApiKeys = {
twitter: character.settings.secrets?.TWITTER_API_KEY,
discord: character.settings.secrets?.DISCORD_API_KEY,
telegram: character.settings.secrets?.TELEGRAM_API_KEY,
};

if (Object.values(socialApiKeys).some((key) => key)) {
this.socialAnalyticsService = new SocialAnalyticsService(
socialApiKeys
);
await this.socialAnalyticsService.initialize();
this.socialAnalyticsService = new SocialAnalyticsService({
cacheManager: this.cacheManager,
rateLimiter: this.rateLimiter,
});
await this.socialAnalyticsService.initialize(character.runtime);
await character.runtime.registerService(
this.socialAnalyticsService
);
}

// Register providers and actions
(character as any).providers = (character as any).providers || [];
(character as any).providers.push(nftCollectionProvider);
character.providers = character.providers || [];
character.providers.push(nftCollectionProvider);

(character as any).actions = (character as any).actions || [];
(character as any).actions.push(sweepFloorAction, listNFTAction);
character.actions = character.actions || [];
character.actions.push(sweepFloorAction, listNFTAction);
}

async teardown(): Promise<void> {
// Cleanup if needed
// Cleanup resources
if (this.cacheManager) {
await this.cacheManager.clear();
}
if (this.rateLimiter) {
await this.rateLimiter.cleanup();
}
}
}

Expand Down
57 changes: 57 additions & 0 deletions packages/plugin-nft-collections/src/services/cache-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
interface CacheConfig {
ttl: number;
maxSize: number;
}

interface CacheEntry<T> {
data: T;
timestamp: number;
}

export class CacheManager {
private cache: Map<string, CacheEntry<any>>;
private config: CacheConfig;

constructor(config: CacheConfig) {
this.config = config;
this.cache = new Map();
}

async get<T>(key: string): Promise<T | null> {
const entry = this.cache.get(key);
if (!entry) return null;

// Check if entry has expired
if (Date.now() - entry.timestamp > this.config.ttl) {
this.cache.delete(key);
return null;
}

return entry.data;
}

async set<T>(key: string, data: T): Promise<void> {
// Implement LRU eviction if cache is full
if (this.cache.size >= this.config.maxSize) {
const oldestKey = this.cache.keys().next().value;
this.cache.delete(oldestKey);
}

this.cache.set(key, {
data,
timestamp: Date.now(),
});
}

async delete(key: string): Promise<void> {
this.cache.delete(key);
}

async clear(): Promise<void> {
this.cache.clear();
}

async has(key: string): Promise<boolean> {
return this.cache.has(key);
}
}
Loading

0 comments on commit 15e1ca0

Please sign in to comment.