@reap-protocol/sdk 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/README.md +18 -3
- package/src/index.ts +96 -20
package/package.json
CHANGED
package/src/README.md
CHANGED
|
@@ -24,8 +24,6 @@ import { ReapClient } from "@reap-protocol/sdk";
|
|
|
24
24
|
|
|
25
25
|
// Load your private key securely
|
|
26
26
|
const PRIVATE_KEY = process.env.MY_WALLET_KEY || "";
|
|
27
|
-
|
|
28
|
-
// Optional: Use a specific RPC (e.g., Celo Alfajores or Avalanche Fuji)
|
|
29
27
|
const CHAIN_RPC = "https://api.avax-test.network/ext/bc/C/rpc";
|
|
30
28
|
|
|
31
29
|
async function main() {
|
|
@@ -97,6 +95,21 @@ npm install --save-dev ts-node typescript @types/node
|
|
|
97
95
|
npx ts-node agent.ts
|
|
98
96
|
```
|
|
99
97
|
|
|
98
|
+
## 🕵️ Agent Discovery (New)
|
|
99
|
+
|
|
100
|
+
You can now search for other AI Agents (MCP, x402, A2A).
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// 1. Search for Agents
|
|
104
|
+
// Registries: 'mcp' (AI Models), 'x402' (Payment Agents), 'a2a' (Autonomous)
|
|
105
|
+
const agents = await client.searchAgents("ecommerce", "x402");
|
|
106
|
+
|
|
107
|
+
if (agents.length > 0) {
|
|
108
|
+
const targetAgent = agents[0];
|
|
109
|
+
console.log(`Found: ${targetAgent.name}`);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
100
113
|
## 🔧 Configuration
|
|
101
114
|
|
|
102
115
|
You can override defaults for custom RPCs or self-hosted middleware.
|
|
@@ -110,10 +123,12 @@ const client = new ReapClient(
|
|
|
110
123
|
|
|
111
124
|
## ✨ Features
|
|
112
125
|
|
|
126
|
+
* **Agent Discovery**: Search thousands of AI Agents from MCP, x402, and A2A registries.
|
|
113
127
|
* **JIT Stocking**: "Just-In-Time" inventory system. If an agent searches for an item not yet on the blockchain, the Protocol indexes it in real-time.
|
|
114
128
|
* **Agentic Cart**: Automatically routes purchases through the Protocol's batch processor.
|
|
115
129
|
* **Protocol Negotiation**: Built-in support for HTTP 402 Payment Negotiation loops.
|
|
116
|
-
|
|
130
|
+
|
|
131
|
+
|
|
117
132
|
|
|
118
133
|
## License
|
|
119
134
|
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { ethers } from "ethers";
|
|
2
|
-
import axios
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
|
|
4
|
+
// ==========================================
|
|
5
|
+
// CONSTANTS & CONFIGURATION
|
|
6
|
+
// ==========================================
|
|
3
7
|
|
|
4
8
|
const HOLOCRON_ROUTER_ADDRESS = "0x2cEC5Bf3a0D3fEe4E13e8f2267176BdD579F4fd8";
|
|
5
9
|
|
|
@@ -9,12 +13,26 @@ const NETWORKS: Record<string, string> = {
|
|
|
9
13
|
"CELO": "https://forno.celo-sepolia.celo-testnet.org"
|
|
10
14
|
};
|
|
11
15
|
|
|
12
|
-
|
|
13
16
|
const HOLOCRON_ABI = [
|
|
14
17
|
"function checkExistence(uint256 _c) view returns (bool)",
|
|
15
18
|
"function stock(uint256 _c) external"
|
|
16
19
|
];
|
|
17
20
|
|
|
21
|
+
// --- Agent Registry Configuration ---
|
|
22
|
+
export type AgentRegistry = 'mcp' | 'x402' | 'a2a';
|
|
23
|
+
|
|
24
|
+
const REGISTRY_MAP: Record<AgentRegistry, string> = {
|
|
25
|
+
"mcp": "pulsemcp",
|
|
26
|
+
"x402": "coinbase-x402-bazaar",
|
|
27
|
+
"a2a": "a2a-registry"
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const SEARCH_API_URL = "https://www.reap.deals/api/search-agents";
|
|
31
|
+
|
|
32
|
+
// ==========================================
|
|
33
|
+
// REAP CLIENT CLASS
|
|
34
|
+
// ==========================================
|
|
35
|
+
|
|
18
36
|
export class ReapClient {
|
|
19
37
|
private wallet: ethers.Wallet;
|
|
20
38
|
private builderUrl: string;
|
|
@@ -37,22 +55,34 @@ export class ReapClient {
|
|
|
37
55
|
this.init();
|
|
38
56
|
}
|
|
39
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Async initialization to fetch Chain ID
|
|
60
|
+
*/
|
|
40
61
|
private async init() {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
try {
|
|
63
|
+
const net = await this.provider.getNetwork();
|
|
64
|
+
this.chainId = Number(net.chainId);
|
|
65
|
+
console.log(`🤖 Reap Agent Online: ${this.wallet.address} (Chain: ${this.chainId})`);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
console.error("⚠️ Failed to fetch chain ID. Defaulting to 43113.");
|
|
68
|
+
}
|
|
44
69
|
}
|
|
45
70
|
|
|
71
|
+
// ==========================================
|
|
72
|
+
// CORE TRANSACTION LOGIC
|
|
73
|
+
// ==========================================
|
|
74
|
+
|
|
46
75
|
/**
|
|
47
|
-
* Execute Transactions with Nonce & Gas Fixes
|
|
76
|
+
* Execute Transactions with Nonce & Gas Fixes.
|
|
77
|
+
* Handles sequential nonce increments locally to prevent RPC lag.
|
|
48
78
|
*/
|
|
49
79
|
private async executeTransactions(txList: any[]) {
|
|
50
80
|
let lastReceipt;
|
|
51
81
|
|
|
52
|
-
//
|
|
82
|
+
// 1. Fetch Nonce ONCE
|
|
53
83
|
let currentNonce = await this.provider.getTransactionCount(this.wallet.address, "pending");
|
|
54
84
|
|
|
55
|
-
//
|
|
85
|
+
// 2. Gas Price Buffer (1.1x) for fast propagation
|
|
56
86
|
const feeData = await this.provider.getFeeData();
|
|
57
87
|
const gasPrice = feeData.gasPrice ? (feeData.gasPrice * 110n) / 100n : undefined;
|
|
58
88
|
|
|
@@ -64,10 +94,10 @@ export class ReapClient {
|
|
|
64
94
|
to: txData.to,
|
|
65
95
|
data: txData.data,
|
|
66
96
|
value: BigInt(txData.value),
|
|
67
|
-
gasLimit: 500000,
|
|
97
|
+
gasLimit: 500000, // Safe default limit
|
|
68
98
|
nonce: currentNonce,
|
|
69
99
|
chainId: this.chainId,
|
|
70
|
-
gasPrice: gasPrice
|
|
100
|
+
gasPrice: gasPrice
|
|
71
101
|
};
|
|
72
102
|
|
|
73
103
|
try {
|
|
@@ -86,6 +116,7 @@ export class ReapClient {
|
|
|
86
116
|
|
|
87
117
|
} catch (e: any) {
|
|
88
118
|
console.error(` ❌ Tx Failed: ${e.message}`);
|
|
119
|
+
// Stop execution if payment or approval fails. Continue for others if needed.
|
|
89
120
|
if (label.includes("Approve") || label.includes("Payment")) throw e;
|
|
90
121
|
}
|
|
91
122
|
}
|
|
@@ -94,7 +125,7 @@ export class ReapClient {
|
|
|
94
125
|
|
|
95
126
|
private async callBuilder(endpoint: string, payload: any) {
|
|
96
127
|
try {
|
|
97
|
-
// Inject Chain ID
|
|
128
|
+
// Inject Chain ID for Middleware routing
|
|
98
129
|
payload.chain_id = this.chainId;
|
|
99
130
|
const { data } = await axios.post(`${this.builderUrl}${endpoint}`, payload);
|
|
100
131
|
return data;
|
|
@@ -104,8 +135,13 @@ export class ReapClient {
|
|
|
104
135
|
}
|
|
105
136
|
}
|
|
106
137
|
|
|
107
|
-
//
|
|
138
|
+
// ==========================================
|
|
139
|
+
// HOLOCRON & SMART SYNC
|
|
140
|
+
// ==========================================
|
|
108
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Check if a coordinate exists in the Holocron Registry.
|
|
144
|
+
*/
|
|
109
145
|
async checkHolocron(coordinate: string) {
|
|
110
146
|
console.log(`🔎 Scanning Holocron for ${coordinate}...`);
|
|
111
147
|
|
|
@@ -118,10 +154,12 @@ export class ReapClient {
|
|
|
118
154
|
return exists;
|
|
119
155
|
}
|
|
120
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Internal method to execute the 'stock' function on the Holocron.
|
|
159
|
+
*/
|
|
121
160
|
private async indexToHolocron(coordinate: string) {
|
|
122
161
|
console.log(` 📝 Indexing Coordinate ${coordinate} to Holocron...`);
|
|
123
162
|
|
|
124
|
-
// Re-fetch nonce/gas
|
|
125
163
|
const nonce = await this.provider.getTransactionCount(this.wallet.address, "pending");
|
|
126
164
|
const feeData = await this.provider.getFeeData();
|
|
127
165
|
const gasPrice = feeData.gasPrice ? (feeData.gasPrice * 110n) / 100n : undefined;
|
|
@@ -140,8 +178,11 @@ export class ReapClient {
|
|
|
140
178
|
await new Promise(r => setTimeout(r, 2000));
|
|
141
179
|
}
|
|
142
180
|
|
|
143
|
-
|
|
144
|
-
|
|
181
|
+
/**
|
|
182
|
+
* Smart Sync: Checks Holocron first.
|
|
183
|
+
* If item exists -> Skip registration (Save Gas).
|
|
184
|
+
* If missing -> Execute registration TX -> Index to Holocron.
|
|
185
|
+
*/
|
|
145
186
|
async smartSync(item: any, transaction: any) {
|
|
146
187
|
const coordinate = item.id;
|
|
147
188
|
|
|
@@ -158,11 +199,8 @@ export class ReapClient {
|
|
|
158
199
|
// 2. Register Data (if transaction exists)
|
|
159
200
|
if (transaction) {
|
|
160
201
|
console.log(" 🔸 Registering Data on-chain...");
|
|
161
|
-
|
|
162
|
-
// ⚠️ THE FIX: Wrap the single 'transaction' object in brackets [ ]
|
|
163
|
-
// to make it a list, because executeTransactions expects a list.
|
|
202
|
+
// Wrap single transaction in array
|
|
164
203
|
await this.executeTransactions([transaction]);
|
|
165
|
-
|
|
166
204
|
} else {
|
|
167
205
|
console.log(" ⚠️ No registration transaction provided. Skipping to index.");
|
|
168
206
|
}
|
|
@@ -171,7 +209,41 @@ export class ReapClient {
|
|
|
171
209
|
await this.indexToHolocron(coordinate);
|
|
172
210
|
}
|
|
173
211
|
|
|
174
|
-
//
|
|
212
|
+
// ==========================================
|
|
213
|
+
// AGENT DISCOVERY (NEW)
|
|
214
|
+
// ==========================================
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Search for AI Agents across different registries (MCP, x402, A2A).
|
|
218
|
+
* @param query Keywords to search for (e.g. "customer support", "ecommerce")
|
|
219
|
+
* @param registry 'mcp' | 'x402' | 'a2a'
|
|
220
|
+
* @param limit Max results (default 40)
|
|
221
|
+
*/
|
|
222
|
+
async searchAgents(query: string, registry: AgentRegistry = 'mcp', limit: number = 40) {
|
|
223
|
+
console.log(`🔎 Searching Registry [${REGISTRY_MAP[registry]}] for: "${query}"...`);
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
const payload = {
|
|
227
|
+
limit: limit,
|
|
228
|
+
query: query,
|
|
229
|
+
registry: REGISTRY_MAP[registry] // Maps 'mcp' -> 'pulsemcp', etc.
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const response = await axios.post(SEARCH_API_URL, payload);
|
|
233
|
+
const hits = response.data.hits || [];
|
|
234
|
+
|
|
235
|
+
console.log(` ✅ Found ${hits.length} agents.`);
|
|
236
|
+
return hits;
|
|
237
|
+
|
|
238
|
+
} catch (error: any) {
|
|
239
|
+
console.error(" ❌ Search Failed:", error.message);
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ==========================================
|
|
245
|
+
// PUBLIC API (Commerce & Identity)
|
|
246
|
+
// ==========================================
|
|
175
247
|
|
|
176
248
|
async registerIdentity(profileUri: string = "ipfs://default") {
|
|
177
249
|
console.log("🆔 Registering Protocol Identity...");
|
|
@@ -187,6 +259,10 @@ export class ReapClient {
|
|
|
187
259
|
return this.executeTransactions(res.transactions);
|
|
188
260
|
}
|
|
189
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Search for Products/Inventory.
|
|
264
|
+
* Use dryRun=true to get items without executing on-chain registration immediately.
|
|
265
|
+
*/
|
|
190
266
|
async stockShelf(productQuery: string, dryRun: boolean = false) {
|
|
191
267
|
console.log(`📦 Stocking Shelf: '${productQuery}' (Dry Run: ${dryRun})`);
|
|
192
268
|
|