@reap-protocol/sdk 0.1.1 โ†’ 0.1.2

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/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # @reap-protocol/sdk
2
+
3
+ **The official TypeScript/Node.js SDK for the Reap Protocol: The Agentic Commerce Grid.**
4
+
5
+ The Reap Protocol enables AI Agents to search for products, register them on-chain, and execute atomic purchases without needing to understand smart contract ABIs. It acts as the bridge between Web2 products data and Web3 commerce settlement.
6
+
7
+ ## ๐Ÿ“ฆ Installation
8
+ ```bash
9
+ npm install @reap-protocol/sdk ethers axios
10
+ ```
11
+
12
+ ## ๐Ÿš€ Quick Start
13
+
14
+ This example demonstrates the full Agentic Commerce Loop: Identity -> Discovery -> Settlement.
15
+
16
+ ### 1. Setup
17
+
18
+ If using TypeScript, ensure your tsconfig.json targets ES2020 or higher.
19
+
20
+ ### 2. The Agent Code (agent.ts)
21
+ ```typescript
22
+ import { ReapClient } from "@reap-protocol/sdk";
23
+
24
+ // Load your private key securely
25
+ const PRIVATE_KEY = process.env.MY_WALLET_KEY || "";
26
+
27
+ async function main() {
28
+ // 1. Initialize the Agent
29
+ // (Points to official middleware by default)
30
+ const client = new ReapClient(PRIVATE_KEY);
31
+ console.log("๐Ÿค– Agent Online");
32
+
33
+ try {
34
+ // 2. Identity (One-time setup)
35
+ // Registers your wallet as an authorized Agent on the Protocol
36
+ console.log("๐Ÿ†” Checking Identity...");
37
+ await client.registerIdentity();
38
+
39
+ // 3. JIT Stocking (Discovery)
40
+ // Searches Web2 (Reap Deals), registers items on-chain, and returns inventory
41
+ console.log("๐Ÿ“ฆ Stocking Shelf with 'Gaming Laptop'...");
42
+ const result = await client.stockShelf("Gaming Laptop");
43
+
44
+ const inventory = result.items;
45
+ console.log(` ๐Ÿ” Found ${inventory.length} items on-chain.`);
46
+
47
+ if (inventory.length > 0) {
48
+ // 4. Decision Logic
49
+ // Example: Pick the first available item
50
+ const target = inventory[0];
51
+ console.log(` ๐ŸŽฏ Selected: ${target.name} ($${target.price})`);
52
+ console.log(` ID: ${target.id}`);
53
+
54
+ // 5. Agentic Cart (Settlement)
55
+ // Automatically approves USDC and executes the atomic purchase
56
+ console.log("๐Ÿ’ธ Buying Item...");
57
+ const receipt = await client.buyProduct(target.id);
58
+
59
+ if (receipt) {
60
+ console.log(`๐ŸŽ‰ SUCCESS! Transaction Hash: ${receipt.hash}`);
61
+ }
62
+ } else {
63
+ console.log("โŒ No items found.");
64
+ }
65
+
66
+ } catch (e: any) {
67
+ console.error("โŒ Error:", e.message);
68
+ }
69
+ }
70
+
71
+ main();
72
+ ```
73
+
74
+ ### 3. Run It
75
+ ```bash
76
+ # Install execution tools if you haven't already
77
+ npm install --save-dev ts-node typescript @types/node
78
+
79
+ # Run
80
+ npx ts-node agent.ts
81
+ ```
82
+
83
+ ## ๐Ÿ”ง Configuration
84
+
85
+ You can override defaults for custom RPCs or self-hosted middleware.
86
+ ```typescript
87
+ const client = new ReapClient(
88
+ "YOUR_PRIVATE_KEY",
89
+ "https://base-sepolia.g.alchemy.com/v2/YOUR_KEY", // Custom RPC
90
+ "https://api.reap.deals" // Middleware URL
91
+ );
92
+ ```
93
+
94
+ ## โœจ Features
95
+
96
+ * **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.
97
+ * **Agentic Cart**: Automatically routes purchases through the Protocol's batch processor.
98
+ * **Protocol Negotiation**: Built-in support for HTTP 402 Payment Negotiation loops.
99
+ * **Gas Optimized**: Checks on-chain state before sending registration transactions.
100
+
101
+ ## License
102
+
103
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reap-protocol/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
package/src/README.md CHANGED
@@ -11,7 +11,8 @@ npm install @reap-protocol/sdk ethers axios
11
11
 
12
12
  ## ๐Ÿš€ Quick Start
13
13
 
14
- This example demonstrates the full Agentic Commerce Loop: Identity -> Discovery -> Settlement.
14
+ This example demonstrates the full Agentic Commerce Loop: Identity -> Discovery -> Smart Sync -> Settlement.
15
+
15
16
 
16
17
  ### 1. Setup
17
18
 
@@ -24,10 +25,15 @@ import { ReapClient } from "@reap-protocol/sdk";
24
25
  // Load your private key securely
25
26
  const PRIVATE_KEY = process.env.MY_WALLET_KEY || "";
26
27
 
28
+ // Optional: Use a specific RPC (e.g., Celo Alfajores or Avalanche Fuji)
29
+ const CHAIN_RPC = "https://api.avax-test.network/ext/bc/C/rpc";
30
+
27
31
  async function main() {
28
32
  // 1. Initialize the Agent
29
- // (Points to official middleware by default)
30
- const client = new ReapClient(PRIVATE_KEY);
33
+ const client = new ReapClient(PRIVATE_KEY, CHAIN_RPC);
34
+
35
+ // Wait for Chain ID initialization
36
+ await new Promise(r => setTimeout(r, 1000));
31
37
  console.log("๐Ÿค– Agent Online");
32
38
 
33
39
  try {
@@ -36,25 +42,36 @@ async function main() {
36
42
  console.log("๐Ÿ†” Checking Identity...");
37
43
  await client.registerIdentity();
38
44
 
39
- // 3. JIT Stocking (Discovery)
40
- // Searches Web2 (Reap Deals), registers items on-chain, and returns inventory
41
- console.log("๐Ÿ“ฆ Stocking Shelf with 'Gaming Laptop'...");
42
- const result = await client.stockShelf("Gaming Laptop");
45
+ // 3. Discovery (Dry Run Mode)
46
+ // Pass 'true' to get the items AND the transactions without executing them yet.
47
+ console.log("๐Ÿ“ฆ Browsing for 'Gaming Laptop'...");
48
+
49
+ // dryRun = true
50
+ const result = await client.stockShelf("Gaming Laptop", true);
43
51
 
44
- const inventory = result.items;
45
- console.log(` ๐Ÿ” Found ${inventory.length} items on-chain.`);
52
+ const inventory = result.items || [];
53
+ const transactions = result.transactions || [];
54
+
55
+ console.log(` ๐Ÿ” Found ${inventory.length} items.`);
46
56
 
47
57
  if (inventory.length > 0) {
48
58
  // 4. Decision Logic
49
- // Example: Pick the first available item
50
- const target = inventory[0];
51
- console.log(` ๐ŸŽฏ Selected: ${target.name} ($${target.price})`);
52
- console.log(` ID: ${target.id}`);
59
+ // Pick the first item and its corresponding registration transaction
60
+ const targetItem = inventory[0];
61
+ const targetTx = transactions[0];
62
+
63
+ console.log(` ๐ŸŽฏ Selected: ${targetItem.name} ($${targetItem.price})`);
64
+
65
+ // 5. Smart Sync (The "Gas Saver")
66
+ // Checks the Holocron (Index) first.
67
+ // If the item exists, it skips registration.
68
+ // If not, it executes the targetTx and indexes it.
69
+ await client.smartSync(targetItem, targetTx);
53
70
 
54
- // 5. Agentic Cart (Settlement)
71
+ // 6. Agentic Cart (Settlement)
55
72
  // Automatically approves USDC and executes the atomic purchase
56
73
  console.log("๐Ÿ’ธ Buying Item...");
57
- const receipt = await client.buyProduct(target.id);
74
+ const receipt = await client.buyProduct(targetItem.id);
58
75
 
59
76
  if (receipt) {
60
77
  console.log(`๐ŸŽ‰ SUCCESS! Transaction Hash: ${receipt.hash}`);
@@ -86,8 +103,8 @@ You can override defaults for custom RPCs or self-hosted middleware.
86
103
  ```typescript
87
104
  const client = new ReapClient(
88
105
  "YOUR_PRIVATE_KEY",
89
- "https://base-sepolia.g.alchemy.com/v2/YOUR_KEY", // Custom RPC
90
- "https://api.reap.deals" // Middleware URL
106
+ "https://avax-fuji.g.alchemy.com/v2/YOUR_KEY", // Custom RPC
107
+ "https://avax2.api.reap.deals" // Middleware URL
91
108
  );
92
109
  ```
93
110
 
package/src/index.ts CHANGED
@@ -1,31 +1,60 @@
1
1
  import { ethers } from "ethers";
2
2
  import axios, { AxiosRequestConfig } from "axios";
3
3
 
4
+ const HOLOCRON_ROUTER_ADDRESS = "0x2cEC5Bf3a0D3fEe4E13e8f2267176BdD579F4fd8";
5
+
6
+ const NETWORKS: Record<string, string> = {
7
+ "BASE": "https://sepolia.base.org",
8
+ "AVAX": "https://api.avax-test.network/ext/bc/C/rpc",
9
+ "CELO": "https://forno.celo-sepolia.celo-testnet.org"
10
+ };
11
+
12
+
13
+ const HOLOCRON_ABI = [
14
+ "function checkExistence(uint256 _c) view returns (bool)",
15
+ "function stock(uint256 _c) external"
16
+ ];
17
+
4
18
  export class ReapClient {
5
19
  private wallet: ethers.Wallet;
6
20
  private builderUrl: string;
7
21
  private provider: ethers.JsonRpcProvider;
22
+ private holocron: ethers.Contract;
23
+ private chainId: number = 43113;
8
24
 
9
25
  constructor(
10
26
  privateKey: string,
11
27
  chainRpc: string = "https://avalanche-fuji.drpc.org",
12
- builderUrl: string = "https://api.reap.deals"
28
+ builderUrl: string = "https://avax2.api.reap.deals"
13
29
  ) {
14
30
  this.provider = new ethers.JsonRpcProvider(chainRpc);
15
31
  this.wallet = new ethers.Wallet(privateKey, this.provider);
16
- this.builderUrl = builderUrl.replace(/\/$/, ""); // Remove trailing slash
17
- console.log(`๐Ÿค– Reap Agent Online: ${this.wallet.address}`);
32
+ this.builderUrl = builderUrl.replace(/\/$/, "");
33
+
34
+ // Initialize Holocron Contract
35
+ this.holocron = new ethers.Contract(HOLOCRON_ROUTER_ADDRESS, HOLOCRON_ABI, this.wallet);
36
+
37
+ this.init();
38
+ }
39
+
40
+ private async init() {
41
+ const net = await this.provider.getNetwork();
42
+ this.chainId = Number(net.chainId);
43
+ console.log(`๐Ÿค– Reap Agent Online: ${this.wallet.address} (Chain: ${this.chainId})`);
18
44
  }
19
45
 
20
46
  /**
21
- * Core Logic: Signs and Broadcasts transactions sequentially.
22
- * Uses manual nonce management to prevent RPC lag errors.
47
+ * Execute Transactions with Nonce & Gas Fixes
23
48
  */
24
49
  private async executeTransactions(txList: any[]) {
25
50
  let lastReceipt;
26
51
 
27
- // 1. Fetch Nonce ONCE
52
+ // FIX 1: Use pending nonce
28
53
  let currentNonce = await this.provider.getTransactionCount(this.wallet.address, "pending");
54
+
55
+ // FIX 2: Gas Price Buffer (1.1x)
56
+ const feeData = await this.provider.getFeeData();
57
+ const gasPrice = feeData.gasPrice ? (feeData.gasPrice * 110n) / 100n : undefined;
29
58
 
30
59
  for (const txData of txList) {
31
60
  const label = txData.label || "Transaction";
@@ -35,33 +64,28 @@ export class ReapClient {
35
64
  to: txData.to,
36
65
  data: txData.data,
37
66
  value: BigInt(txData.value),
38
- gasLimit: 500000, // Safety limit
67
+ gasLimit: 500000,
39
68
  nonce: currentNonce,
40
- chainId: (await this.provider.getNetwork()).chainId
69
+ chainId: this.chainId,
70
+ gasPrice: gasPrice // Apply buffered gas price
41
71
  };
42
72
 
43
73
  try {
44
- // 2. Sign & Send
45
74
  const response = await this.wallet.sendTransaction(tx);
46
75
  console.log(` ๐Ÿš€ Broadcasting: ${response.hash}`);
47
76
 
48
- // 3. Wait
49
77
  const receipt = await response.wait();
50
78
 
51
- // 4. Check Status (1 = Success, 0 = Revert)
52
79
  if (receipt && receipt.status === 0) {
53
80
  throw new Error(`Transaction Reverted! Hash: ${receipt.hash}`);
54
81
  }
55
82
 
56
83
  console.log(` โœ… Settled on-chain.`);
57
84
  lastReceipt = receipt;
58
-
59
- // 5. Increment Nonce
60
85
  currentNonce++;
61
86
 
62
87
  } catch (e: any) {
63
88
  console.error(` โŒ Tx Failed: ${e.message}`);
64
-
65
89
  if (label.includes("Approve") || label.includes("Payment")) throw e;
66
90
  }
67
91
  }
@@ -70,23 +94,84 @@ export class ReapClient {
70
94
 
71
95
  private async callBuilder(endpoint: string, payload: any) {
72
96
  try {
73
- const { data } = await axios.post(`${this.builderUrl}${endpoint}`, payload);
74
- return data;
97
+ // Inject Chain ID
98
+ payload.chain_id = this.chainId;
99
+ const { data } = await axios.post(`${this.builderUrl}${endpoint}`, payload);
100
+ return data;
75
101
  } catch (error: any) {
76
102
  const msg = error.response?.data?.detail || error.message;
77
103
  throw new Error(`Reap Protocol Error: ${msg}`);
78
104
  }
79
105
  }
80
106
 
81
- // --- PUBLIC API ---
107
+ // --- SMART AVAILABILITY (Holocron Only) ---
108
+
109
+ async checkHolocron(coordinate: string) {
110
+ console.log(`๐Ÿ”Ž Scanning Holocron for ${coordinate}...`);
111
+
112
+ let exists = false;
113
+ try {
114
+ exists = await this.holocron.checkExistence(BigInt(coordinate));
115
+ } catch (e) { exists = false; }
116
+
117
+ console.log(` โ€ข Holocron Index: ${exists ? 'โœ… FOUND' : 'โŒ EMPTY'}`);
118
+ return exists;
119
+ }
120
+
121
+ private async indexToHolocron(coordinate: string) {
122
+ console.log(` ๐Ÿ“ Indexing Coordinate ${coordinate} to Holocron...`);
123
+
124
+ // Re-fetch nonce/gas
125
+ const nonce = await this.provider.getTransactionCount(this.wallet.address, "pending");
126
+ const feeData = await this.provider.getFeeData();
127
+ const gasPrice = feeData.gasPrice ? (feeData.gasPrice * 110n) / 100n : undefined;
128
+
129
+ const tx = await this.holocron.stock(BigInt(coordinate), {
130
+ gasLimit: 150000,
131
+ nonce,
132
+ gasPrice
133
+ });
134
+
135
+ console.log(` ๐Ÿš€ Broadcast Holocron TX: ${tx.hash}`);
136
+ await tx.wait();
137
+ console.log(" โœ… Index Updated.");
138
+
139
+ // Small sleep to let RPC sync
140
+ await new Promise(r => setTimeout(r, 2000));
141
+ }
142
+
143
+ // --- src/index.ts ---
82
144
 
83
- async getProduct(productId: string) {
84
- const safeId = encodeURIComponent(productId);
85
- const { data } = await axios.get(`${this.builderUrl}/read/product/${safeId}`);
86
- return data;
145
+ async smartSync(item: any, transaction: any) {
146
+ const coordinate = item.id;
147
+
148
+ // 1. Check Status
149
+ const onHolocron = await this.checkHolocron(coordinate);
150
+
151
+ if (onHolocron) {
152
+ console.log("โšก๏ธ Fast Path: Item is indexed. Skipping registration.");
153
+ return;
154
+ }
155
+
156
+ console.log("\n๐Ÿข Syncing to Chain (Full Path)...");
157
+
158
+ // 2. Register Data (if transaction exists)
159
+ if (transaction) {
160
+ 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.
164
+ await this.executeTransactions([transaction]);
165
+
166
+ } else {
167
+ console.log(" โš ๏ธ No registration transaction provided. Skipping to index.");
168
+ }
169
+
170
+ // 3. Index on Holocron
171
+ await this.indexToHolocron(coordinate);
87
172
  }
88
173
 
89
- // ... inside ReapClient class ...
174
+ // --- PUBLIC API ---
90
175
 
91
176
  async registerIdentity(profileUri: string = "ipfs://default") {
92
177
  console.log("๐Ÿ†” Registering Protocol Identity...");
@@ -96,40 +181,41 @@ export class ReapClient {
96
181
  });
97
182
 
98
183
  if (res.status === "already_registered") {
99
- console.log(` โœ… Already Registered (Agent #${res.agent_id}). Skipping transaction.`);
184
+ console.log(` โœ… Already Registered (Agent #${res.agent_id}). Skipping.`);
100
185
  return null;
101
186
  }
102
-
103
187
  return this.executeTransactions(res.transactions);
104
188
  }
105
189
 
106
- async stockShelf(productQuery: string) {
107
- console.log(`๐Ÿ“ฆ Stocking Shelf: '${productQuery}'`);
190
+ async stockShelf(productQuery: string, dryRun: boolean = false) {
191
+ console.log(`๐Ÿ“ฆ Stocking Shelf: '${productQuery}' (Dry Run: ${dryRun})`);
192
+
108
193
  const res = await this.callBuilder("/build/inventory/stock", {
109
194
  product_query: productQuery,
110
195
  provider_address: this.wallet.address
111
196
  });
112
197
 
198
+ const items = res.meta?.items || [];
199
+ const transactions = res.transactions || [];
200
+
113
201
  if (res.status === "payment_required") {
114
- console.log("๐Ÿ›‘ 402 Payment Required via JSON Spec.");
115
- console.log(` ๐Ÿงพ Invoice: ${res.meta.description}`);
116
- } else {
117
- console.log(` ๐Ÿ” Found ${res.meta.count || 0} items.`);
202
+ console.log("๐Ÿ›‘ 402 Payment Required.");
203
+ if (dryRun) return { receipt: null, items: [] };
204
+ const receipt = await this.executeTransactions(transactions);
205
+ return { receipt, items: [] };
118
206
  }
119
207
 
120
- const receipt = await this.executeTransactions(res.transactions);
208
+ if (dryRun) {
209
+ console.log(` ๐Ÿ‘€ Preview: Found ${items.length} items. Cached ${transactions.length} TXs.`);
210
+ return { receipt: null, items, transactions };
211
+ }
121
212
 
122
- // --- THE FIX: Return both Receipt AND Items ---
123
- return {
124
- receipt,
125
- items: res.meta?.items || []
126
- };
127
- // ----------------------------------------------
213
+ const receipt = await this.executeTransactions(transactions);
214
+ return { receipt, items };
128
215
  }
129
216
 
130
217
  async buyProduct(productId: string) {
131
218
  console.log(`๐Ÿ’ธ Initiating Agentic Cart (Single Item): ${productId}`);
132
- // Route to batch endpoint
133
219
  const res = await this.callBuilder("/build/commerce/batch", {
134
220
  product_ids: [productId]
135
221
  });
@@ -143,36 +229,4 @@ async stockShelf(productQuery: string) {
143
229
  });
144
230
  return this.executeTransactions(res.transactions);
145
231
  }
146
-
147
- async fetch(url: string, config: AxiosRequestConfig = {}) {
148
- console.log(`๐ŸŒ Accessing ${url}...`);
149
- try {
150
- return await axios.get(url, config);
151
- } catch (error: any) {
152
- if (error.response && error.response.status === 402) {
153
- console.log("๐Ÿ›‘ x402 Payment Required. Engaging Protocol...");
154
- const header = error.response.headers["www-authenticate"];
155
-
156
- if (header && header.includes("X402")) {
157
- const match = header.match(/resource_id="([^"]+)"/);
158
- if (match && match[1]) {
159
- const rid = match[1];
160
-
161
- // Pay Protocol
162
- const receipt = await this.buyProduct(rid);
163
-
164
- if (!receipt) throw new Error("Payment Transaction failed");
165
- const proof = receipt.hash;
166
-
167
- console.log(` ๐Ÿ”„ Submitting Proof for Reactive Release: ${proof}`);
168
-
169
- // Release Data
170
- const newConfig = { ...config, headers: { ...config.headers, "Authorization": `X402-Proof ${proof}` } };
171
- return await axios.get(url, newConfig);
172
- }
173
- }
174
- }
175
- throw error;
176
- }
177
- }
178
232
  }