@reap-protocol/sdk 0.1.0 โ 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 +103 -0
- package/package.json +6 -2
- package/src/README.md +76 -42
- package/src/index.ts +125 -71
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,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reap-protocol/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "tsc"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"axios": "^1.
|
|
10
|
+
"axios": "^1.13.2",
|
|
11
11
|
"ethers": "^6.0.0"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
@@ -15,5 +15,9 @@
|
|
|
15
15
|
},
|
|
16
16
|
"publishConfig": {
|
|
17
17
|
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/Apriloracle/Reap-protocol-sdk.git"
|
|
18
22
|
}
|
|
19
23
|
}
|
package/src/README.md
CHANGED
|
@@ -1,58 +1,83 @@
|
|
|
1
|
-
|
|
1
|
+
# @reap-protocol/sdk
|
|
2
2
|
|
|
3
|
-
The official TypeScript/Node.js SDK for the
|
|
4
|
-
Enable Autonomous Agents to buy and sell on-chain with zero smart contract knowledge.
|
|
3
|
+
**The official TypeScript/Node.js SDK for the Reap Protocol: The Agentic Commerce Grid.**
|
|
5
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
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
## ๐ฆ Installation
|
|
8
|
+
```bash
|
|
10
9
|
npm install @reap-protocol/sdk ethers axios
|
|
10
|
+
```
|
|
11
11
|
|
|
12
|
+
## ๐ Quick Start
|
|
12
13
|
|
|
14
|
+
This example demonstrates the full Agentic Commerce Loop: Identity -> Discovery -> Smart Sync -> Settlement.
|
|
13
15
|
|
|
14
|
-
๐ Quick Start
|
|
15
16
|
|
|
16
|
-
1. Setup
|
|
17
|
-
If using TypeScript, ensure your tsconfig.json targets ES2020 or higher.
|
|
17
|
+
### 1. Setup
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
If using TypeScript, ensure your tsconfig.json targets ES2020 or higher.
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
### 2. The Agent Code (agent.ts)
|
|
22
|
+
```typescript
|
|
22
23
|
import { ReapClient } from "@reap-protocol/sdk";
|
|
23
24
|
|
|
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
|
-
// 1. Initialize
|
|
29
|
-
const client = new ReapClient(PRIVATE_KEY);
|
|
32
|
+
// 1. Initialize the Agent
|
|
33
|
+
const client = new ReapClient(PRIVATE_KEY, CHAIN_RPC);
|
|
34
|
+
|
|
35
|
+
// Wait for Chain ID initialization
|
|
36
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
30
37
|
console.log("๐ค Agent Online");
|
|
31
38
|
|
|
32
39
|
try {
|
|
33
|
-
// 2. Identity
|
|
34
|
-
//
|
|
40
|
+
// 2. Identity (One-time setup)
|
|
41
|
+
// Registers your wallet as an authorized Agent on the Protocol
|
|
42
|
+
console.log("๐ Checking Identity...");
|
|
35
43
|
await client.registerIdentity();
|
|
36
44
|
|
|
37
|
-
// 3. Discovery (
|
|
38
|
-
//
|
|
39
|
-
console.log("๐ฆ
|
|
40
|
-
const result = await client.stockShelf("Tonnino Tuna");
|
|
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'...");
|
|
41
48
|
|
|
42
|
-
|
|
49
|
+
// dryRun = true
|
|
50
|
+
const result = await client.stockShelf("Gaming Laptop", true);
|
|
51
|
+
|
|
52
|
+
const inventory = result.items || [];
|
|
53
|
+
const transactions = result.transactions || [];
|
|
54
|
+
|
|
43
55
|
console.log(` ๐ Found ${inventory.length} items.`);
|
|
44
56
|
|
|
45
57
|
if (inventory.length > 0) {
|
|
46
|
-
// 4. Decision
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
// 4. Decision Logic
|
|
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);
|
|
70
|
+
|
|
71
|
+
// 6. Agentic Cart (Settlement)
|
|
72
|
+
// Automatically approves USDC and executes the atomic purchase
|
|
73
|
+
console.log("๐ธ Buying Item...");
|
|
74
|
+
const receipt = await client.buyProduct(targetItem.id);
|
|
54
75
|
|
|
55
|
-
|
|
76
|
+
if (receipt) {
|
|
77
|
+
console.log(`๐ SUCCESS! Transaction Hash: ${receipt.hash}`);
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
console.log("โ No items found.");
|
|
56
81
|
}
|
|
57
82
|
|
|
58
83
|
} catch (e: any) {
|
|
@@ -61,26 +86,35 @@ async function main() {
|
|
|
61
86
|
}
|
|
62
87
|
|
|
63
88
|
main();
|
|
89
|
+
```
|
|
64
90
|
|
|
91
|
+
### 3. Run It
|
|
92
|
+
```bash
|
|
93
|
+
# Install execution tools if you haven't already
|
|
94
|
+
npm install --save-dev ts-node typescript @types/node
|
|
65
95
|
|
|
96
|
+
# Run
|
|
97
|
+
npx ts-node agent.ts
|
|
98
|
+
```
|
|
66
99
|
|
|
67
|
-
|
|
68
|
-
Typed Interfaces: Full TypeScript support for Product Data and Transactions.
|
|
69
|
-
Agentic Cart: Automatically routes purchases through the Protocol's batch processor.
|
|
70
|
-
Protocol Negotiation: Built-in support for HTTP 402 Payment Negotiation loops.
|
|
71
|
-
Gas Optimized: Checks on-chain state before sending registration transactions.
|
|
100
|
+
## ๐ง Configuration
|
|
72
101
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
code
|
|
76
|
-
TypeScript
|
|
102
|
+
You can override defaults for custom RPCs or self-hosted middleware.
|
|
103
|
+
```typescript
|
|
77
104
|
const client = new ReapClient(
|
|
78
105
|
"YOUR_PRIVATE_KEY",
|
|
79
|
-
"https://
|
|
80
|
-
"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
|
|
81
108
|
);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## โจ Features
|
|
82
112
|
|
|
113
|
+
* **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
|
+
* **Agentic Cart**: Automatically routes purchases through the Protocol's batch processor.
|
|
115
|
+
* **Protocol Negotiation**: Built-in support for HTTP 402 Payment Negotiation loops.
|
|
116
|
+
* **Gas Optimized**: Checks on-chain state before sending registration transactions.
|
|
83
117
|
|
|
118
|
+
## License
|
|
84
119
|
|
|
85
|
-
License
|
|
86
120
|
MIT
|
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
|
-
chainRpc: string = "https://
|
|
12
|
-
builderUrl: string = "https://api.reap.deals"
|
|
27
|
+
chainRpc: string = "https://avalanche-fuji.drpc.org",
|
|
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(/\/$/, "");
|
|
17
|
-
|
|
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
|
-
*
|
|
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
|
|
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,
|
|
67
|
+
gasLimit: 500000,
|
|
39
68
|
nonce: currentNonce,
|
|
40
|
-
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
|
-
|
|
74
|
-
|
|
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
|
-
// ---
|
|
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
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|