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
19 changes: 19 additions & 0 deletions config/example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Olas Mech Worker Tool Configuration
tool_id: "polymarket_intelligence"
name: "Polymarket Prediction Market Intelligence x402 Tool"
description: "Retrieves live Polymarket prediction market analysis, implied probabilities, volume/liquidity metrics, and automated risk flags ($0.05 USDC on Base)."
author: "Autonomous Crypto Intelligence Labs"
version: "1.0.0"

gateway:
url: "https://agent-payment-gateway.vercel.app/v1/prediction-market-analysis"
price_usdc: "0.05"
network: "eip155:8453"
asset_contract: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
merchant_recipient: "0x43f9a721B59C247B6258e72A1Bf5A384b64F8A38"

inputs:
schema: "schemas/input.json"

outputs:
schema: "schemas/output.json"
22 changes: 22 additions & 0 deletions schemas/input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PolymarketIntelligenceInput",
"description": "Input schema for Olas Mech Tool: Polymarket Prediction Market Intelligence",
"type": "object",
"properties": {
"prompt": {
"type": "string",
"description": "Natural language request or market query (e.g. 'Analyze Polymarket market 691547')"
},
"market_id": {
"type": "string",
"description": "Polymarket market ID or slug (e.g. '691547', 'kraken-ipo-by-december-31-2026-513')"
},
"analysis_type": {
"type": "string",
"description": "Depth of analysis requested",
"default": "market_intelligence"
}
},
"required": ["market_id"]
}
32 changes: 32 additions & 0 deletions schemas/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PolymarketIntelligenceOutput",
"description": "Output schema for Olas Mech Tool: Polymarket Prediction Market Intelligence",
"type": "object",
"properties": {
"requestId": { "type": "string" },
"result": {
"type": "object",
"properties": {
"market": { "type": "object" },
"outcomes": { "type": "array" },
"market_metrics": { "type": "object" },
"analysis": { "type": "object" },
"data_timestamp": { "type": "string" },
"source": { "type": "string" }
}
},
"x402_settlement": {
"type": "object",
"properties": {
"status": { "type": "string" },
"amount": { "type": "string" },
"currency": { "type": "string" },
"network": { "type": "string" },
"recipient": { "type": "string" },
"tx_hash": { "type": "string" }
}
}
},
"required": ["result", "x402_settlement"]
}
80 changes: 80 additions & 0 deletions tests/test_tool_mocked.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
Unit & Integration Tests for Olas Mech Tool: polymarket_intelligence.py
ALL TESTS ARE 100% MOCKED (NO LIVE PAYMENTS OR REAL BLOCKCHAIN TRANSACTIONS EXECUTED).
"""

import json
import unittest
from unittest.mock import patch, MagicMock

import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../tool')))

from polymarket_intelligence import run

class TestPolymarketIntelligenceOlasTool(unittest.TestCase):

@patch('requests.post')
def test_http_402_challenge_mocked(self, mock_post):
"""MOCKED TEST: Verify tool handles HTTP 402 challenge correctly."""
mock_resp = MagicMock()
mock_resp.status_code = 402
mock_resp.json.return_value = {
"error": "Payment Required",
"status": 402,
"accepts": [
{
"scheme": "exact",
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "0.05",
"payTo": "0x43f9a721B59C247B6258e72A1Bf5A384b64F8A38"
}
]
}
mock_post.return_value = mock_resp

output_str = run({"market_id": "691547"})
data = json.loads(output_str)

self.assertEqual(data["status"], "PAYMENT_REQUIRED")
self.assertEqual(data["http_status"], 402)
self.assertEqual(data["x402_challenge"]["price_usdc"], "0.05")
self.assertEqual(data["x402_challenge"]["recipient"], "0x43f9a721B59C247B6258e72A1Bf5A384b64F8A38")
print("[PASS] MOCKED TEST 1: HTTP 402 Challenge correctly parsed")

@patch('requests.post')
def test_http_200_success_mocked(self, mock_post):
"""MOCKED TEST: Verify tool returns live payload when payment signature attached."""
mock_resp = MagicMock()
mock_resp.status_code = 200
mock_resp.json.return_value = {
"success": True,
"data": {
"market": { "id": "691547", "question": "Kraken IPO by December 31, 2026?" },
"outcomes": [{ "name": "Yes", "price_usd": 0.12 }, { "name": "No", "price_usd": 0.88 }]
},
"payment": {
"amount": "0.05",
"currency": "USDC",
"network": "BASE",
"tx_hash": "0x_mocked_tx_hash_for_unit_testing"
}
}
mock_post.return_value = mock_resp

output_str = run({
"market_id": "691547",
"payment_signature": "0x_mocked_tx_hash_for_unit_testing"
})
data = json.loads(output_str)

self.assertEqual(data["status"], "SUCCESS")
self.assertEqual(data["http_status"], 200)
self.assertEqual(data["result"]["market"]["id"], "691547")
self.assertEqual(data["x402_settlement"]["tx_hash"], "0x_mocked_tx_hash_for_unit_testing")
print("[PASS] MOCKED TEST 2: Paid HTTP 200 payload correctly returned")

if __name__ == '__main__':
unittest.main()
83 changes: 83 additions & 0 deletions tools/polymarket_intelligence.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""
Olas Mech Tool Adapter: Polymarket x402 Intelligence Service
Exposes our production x402 Polymarket Intelligence API to Olas Mech Worker Nodes and Pearl/Polystrat agents.

Architecture:
Pearl Agent ➔ Olas Mech Request ('polymarket_intelligence') ➔ Mech Worker Node ➔ HTTP 402 Challenge ➔ Base Mainnet $0.05 USDC Payment ➔ Production API Data ➔ Mech On-Chain Response
"""

import json
import os
import requests
from typing import Any, Dict, Optional

GATEWAY_URL = os.getenv("GATEWAY_BASE_URL", "https://agent-payment-gateway.vercel.app")
MERCHANT_WALLET = "0x43f9a721B59C247B6258e72A1Bf5A384b64F8A38"
PRICE_USDC = "0.05"
BASE_NETWORK = "eip155:8453"

def run(kwargs: Dict[str, Any]) -> str:
"""
Main entrypoint for Olas Mech Worker execution.
kwargs contains 'prompt', 'market_id', and optional 'payment_signature'.
"""
market_id = kwargs.get("market_id") or "691547"
payment_sig = kwargs.get("payment_signature") or os.getenv("X402_PAYMENT_SIGNATURE")

endpoint = f"{GATEWAY_URL}/v1/prediction-market-analysis"
payload = {
"market_id": market_id,
"analysis_type": kwargs.get("analysis_type", "market_intelligence")
}

headers = {
"Content-Type": "application/json"
}

if payment_sig:
headers["PAYMENT-SIGNATURE"] = payment_sig

try:
response = requests.post(endpoint, json=payload, headers=headers, timeout=10)

# HTTP 402 Payment Required Handling
if response.status_code == 402:
challenge_data = response.json()
accepts = challenge_data.get("accepts", [{}])[0]

return json.dumps({
"status": "PAYMENT_REQUIRED",
"http_status": 402,
"message": "x402 Payment Authorization required to unlock live Polymarket analysis",
"x402_challenge": {
"price_usdc": accepts.get("amount", PRICE_USDC),
"network": accepts.get("network", BASE_NETWORK),
"asset": accepts.get("asset", "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"),
"recipient": accepts.get("payTo", MERCHANT_WALLET)
}
})

response.raise_for_status()
api_data = response.json()

return json.dumps({
"status": "SUCCESS",
"http_status": 200,
"result": api_data.get("data", {}),
"x402_settlement": api_data.get("payment", {
"amount": PRICE_USDC,
"currency": "USDC",
"network": "BASE",
"recipient": MERCHANT_WALLET
})
})

except Exception as e:
return json.dumps({
"status": "ERROR",
"error": str(e)
})

if __name__ == "__main__":
test_res = run({"market_id": "691547"})
print(test_res)