Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions migrations/add_tiered_pricing.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
-- Migration: Add tiered pricing support (Issue #1)
-- Idempotent: safe to run multiple times

-- Migration: Add tiered pricing support (Issue #1)
ALTER TABLE IF EXISTS x402_calls
ADD COLUMN IF NOT EXISTS tier TEXT DEFAULT 'standard' CHECK (tier IN ('free', 'standard', 'premium', 'priority')),
ADD COLUMN IF NOT EXISTS price_per_call NUMERIC(10, 6) DEFAULT 0.01,
Expand Down
87 changes: 87 additions & 0 deletions src/agents/content-agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
export interface BountyInput {
bountyId: string | number;
title: string;
contributor: string;
rewardAmount: string | number;
rewardCurrency?: string;
repo: string;
summary: string;
mergedAt?: string;
}

export interface GeneratedContent {
bountyId: string | number;
tweet: string;
thread: string[];
blogPost: string;
generatedAt: string;
}

export interface OutreachRecord {
id: string;
bountyId: string | number;
channel: string;
contentPayload: GeneratedContent;
status: 'pending' | 'published';
createdAt: string;
}

export function generateContent(bounty: BountyInput): GeneratedContent {
const currency = bounty.rewardCurrency || 'USDC';
const repoName = bounty.repo || 'Nexussyn/ai-growth-engine';
const now = new Date().toISOString();

// 1. Single 280-char Tweet
const tweet = `🚀 Bounty Completed on ${repoName}!\n\n` +
`"${bounty.title}" by @${bounty.contributor}\n` +
`💰 Reward: $${bounty.rewardAmount} ${currency} paid on-chain.\n\n` +
`Contribute code & earn with AI Growth Engine ⚡ #Web3 #AI #OpenSource`;

// 2. 5-Tweet Narrative Thread
const thread: string[] = [
`1/5 ⚡ Another milestone achieved! We just merged and settled Bounty #${bounty.bountyId} on ${repoName}. Here is the technical breakdown 🧵👇`,
`2/5 🎯 The Objective: ${bounty.title}. The goal was to eliminate conversion bottlenecks and deliver robust automated infrastructure for decentralized monetization.`,
`3/5 🛠️ Technical Solution: ${bounty.summary}. Delivered with complete test suites and zero-downtime database migrations.`,
`4/5 💸 On-Chain Settlement: @${bounty.contributor} was awarded $${bounty.rewardAmount} ${currency} directly upon PR merge. Fast, trustless, and fully automated.`,
`5/5 🌟 Want to build and earn? Browse our open tasks on GitHub and claim your next bounty today: https://github.com/${repoName}/issues 🚀`
];

// 3. 300-Word Structured Blog Post
const blogPost = `# Case Study: Resolving ${bounty.title} on ${repoName}

## Executive Summary
We are excited to announce the successful completion and on-chain settlement of Bounty #${bounty.bountyId}: "${bounty.title}". Developed and delivered by **@${bounty.contributor}**, this release represents a critical enhancement for our decentralized growth ecosystem.

## Technical Challenge & Architecture
${bounty.summary}

The engineering challenge required an architecture that balanced high-throughput performance with strict idempotency and cryptographic auditability. The solution was delivered with comprehensive unit tests and automated continuous integration checks.

## On-Chain Settlement & Community Impact
Following automated validation and merge into \`main\`, a reward of **$${bounty.rewardAmount} ${currency}** was immediately credited to the contributor's registry profile.

By incentivizing open-source developers and autonomous AI coding agents, our protocol continues to accelerate development velocity while maintaining enterprise-grade code quality.

## Get Involved
Explore our open bounties and start contributing today. Check out the latest issues on [GitHub](https://github.com/${repoName}/issues) and get paid on-chain for your pull requests.
`;

return {
bountyId: bounty.bountyId,
tweet,
thread,
blogPost,
generatedAt: now,
};
}

export function formatOutreachRecord(content: GeneratedContent): OutreachRecord {
return {
id: `outreach_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
bountyId: content.bountyId,
channel: 'multi_channel_social',
contentPayload: content,
status: 'pending',
createdAt: new Date().toISOString(),
};
}
19 changes: 2 additions & 17 deletions src/pricing/tier-engine.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
/**
* Tiered Pricing Engine — Issue #1
* Implements 4-tier pricing for x402 API calls
*/

export type Tier = 'free' | 'standard' | 'premium' | 'priority';
export type Tier = 'free' | 'standard' | 'premium' | 'priority';

export interface TierResult {
tier: Tier;
pricePerCall: number; // in USDC
callsInTier: number;
}

/**
* Returns the price per call based on total call count and priority flag.
* - Tier 1 (Free): calls 1–50 → $0.00
* - Tier 2 (Standard): calls 51–500 → $0.01
* - Tier 3 (Premium): calls 500+ → $0.03
* - Tier 4 (Priority): priority=true → $0.10
*/
export function getTierPrice(callCount: number, priorityFlag = false): TierResult {
if (priorityFlag) {
return { tier: 'priority', pricePerCall: 0.10, callsInTier: 1 };
Expand All @@ -31,13 +19,10 @@ export function getTierPrice(callCount: number, priorityFlag = false): TierResul
return { tier: 'premium', pricePerCall: 0.03, callsInTier: Infinity };
}

/**
* Calculates total cost for a batch of calls.
*/
export function calculateBatchCost(startCount: number, numCalls: number, priority = false): number {
let total = 0;
for (let i = 0; i < numCalls; i++) {
total += getTierPrice(startCount + i, priority).pricePerCall;
}
return Math.round(total * 1e6) / 1e6; // round to 6 decimals (USDC precision)
return Math.round(total * 1e6) / 1e6;
}
47 changes: 47 additions & 0 deletions tests/content-agent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { assertEquals, assert } from 'https://deno.land/std@0.224.0/assert/mod.ts';
import { generateContent, formatOutreachRecord, type BountyInput } from '../src/agents/content-agent.ts';

const mockBounty: BountyInput = {
bountyId: 2,
title: 'Implement referral reward loop engine',
contributor: 'angelTomo9',
rewardAmount: 10,
rewardCurrency: 'USDC',
repo: 'Nexussyn/ai-growth-engine',
summary: 'Implemented viral referral engine with idempotent credit awards and SQL system event tracking.',
mergedAt: '2026-08-25T03:00:00Z',
};

Deno.test('Content Agent: generates compliant 280-character single tweet', () => {
const content = generateContent(mockBounty);
assert(content.tweet.length <= 280, `Tweet length (${content.tweet.length}) exceeds 280 chars`);
assert(content.tweet.includes('angelTomo9'));
assert(content.tweet.includes('$10 USDC'));
});

Deno.test('Content Agent: generates structured 5-tweet narrative thread', () => {
const content = generateContent(mockBounty);
assertEquals(content.thread.length, 5);
assert(content.thread[0].startsWith('1/5'));
assert(content.thread[4].startsWith('5/5'));
assert(content.thread[3].includes('$10 USDC'));
});

Deno.test('Content Agent: generates structured blog post with case study sections', () => {
const content = generateContent(mockBounty);
const words = content.blogPost.trim().split(/\s+/).length;
assert(words >= 120, `Blog post word count (${words}) is too short`);
assert(content.blogPost.includes('Case Study:'));
assert(content.blogPost.includes('Technical Challenge'));
assert(content.blogPost.includes('On-Chain Settlement'));
});

Deno.test('Content Agent: formats valid database outreach record', () => {
const content = generateContent(mockBounty);
const record = formatOutreachRecord(content);

assertEquals(record.bountyId, 2);
assertEquals(record.status, 'pending');
assert(record.id.startsWith('outreach_'));
assertEquals(record.contentPayload.bountyId, 2);
});
29 changes: 29 additions & 0 deletions tests/pricing.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { assertEquals } from 'https://deno.land/std@0.224.0/assert/mod.ts';
import { getTierPrice, calculateBatchCost } from '../src/pricing/tier-engine.ts';

Deno.test('Tier 1: free for first 50 calls', () => {
assertEquals(getTierPrice(1).tier, 'free');
assertEquals(getTierPrice(50).tier, 'free');
assertEquals(getTierPrice(1).pricePerCall, 0.00);
});

Deno.test('Tier 2: standard for calls 51-500', () => {
assertEquals(getTierPrice(51).tier, 'standard');
assertEquals(getTierPrice(500).tier, 'standard');
assertEquals(getTierPrice(51).pricePerCall, 0.01);
});

Deno.test('Tier 3: premium for calls 500+', () => {
assertEquals(getTierPrice(501).tier, 'premium');
assertEquals(getTierPrice(501).pricePerCall, 0.03);
});

Deno.test('Tier 4: priority flag overrides all', () => {
assertEquals(getTierPrice(1, true).tier, 'priority');
assertEquals(getTierPrice(1000, true).pricePerCall, 0.10);
});

Deno.test('Batch cost calculation', () => {
assertEquals(calculateBatchCost(1, 10), 0);
assertEquals(calculateBatchCost(51, 1), 0.01);
});