@agirails/sdk 2.2.2 → 2.3.0
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 +20 -23
- package/dist/ACTPClient.d.ts +7 -0
- package/dist/ACTPClient.d.ts.map +1 -1
- package/dist/ACTPClient.js +56 -1
- package/dist/ACTPClient.js.map +1 -1
- package/dist/abi/AgentRegistry.json +133 -0
- package/dist/adapters/X402Adapter.d.ts +34 -7
- package/dist/adapters/X402Adapter.d.ts.map +1 -1
- package/dist/adapters/X402Adapter.js +36 -8
- package/dist/adapters/X402Adapter.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/cli/commands/diff.d.ts +11 -0
- package/dist/cli/commands/diff.d.ts.map +1 -0
- package/dist/cli/commands/diff.js +115 -0
- package/dist/cli/commands/diff.js.map +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +51 -2
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/publish.d.ts +11 -0
- package/dist/cli/commands/publish.d.ts.map +1 -0
- package/dist/cli/commands/publish.js +170 -0
- package/dist/cli/commands/publish.js.map +1 -0
- package/dist/cli/commands/pull.d.ts +12 -0
- package/dist/cli/commands/pull.d.ts.map +1 -0
- package/dist/cli/commands/pull.js +99 -0
- package/dist/cli/commands/pull.js.map +1 -0
- package/dist/cli/index.js +7 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/config/agirailsmd.d.ts +94 -0
- package/dist/config/agirailsmd.d.ts.map +1 -0
- package/dist/config/agirailsmd.js +209 -0
- package/dist/config/agirailsmd.js.map +1 -0
- package/dist/config/networks.d.ts +2 -0
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +10 -4
- package/dist/config/networks.js.map +1 -1
- package/dist/config/publishPipeline.d.ts +61 -0
- package/dist/config/publishPipeline.d.ts.map +1 -0
- package/dist/config/publishPipeline.js +192 -0
- package/dist/config/publishPipeline.js.map +1 -0
- package/dist/config/syncOperations.d.ts +67 -0
- package/dist/config/syncOperations.d.ts.map +1 -0
- package/dist/config/syncOperations.js +208 -0
- package/dist/config/syncOperations.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/level0/request.d.ts.map +1 -1
- package/dist/level0/request.js +23 -86
- package/dist/level0/request.js.map +1 -1
- package/dist/level1/Agent.d.ts +0 -11
- package/dist/level1/Agent.d.ts.map +1 -1
- package/dist/level1/Agent.js +15 -32
- package/dist/level1/Agent.js.map +1 -1
- package/dist/registry/AgentRegistryClient.d.ts +75 -0
- package/dist/registry/AgentRegistryClient.d.ts.map +1 -0
- package/dist/registry/AgentRegistryClient.js +160 -0
- package/dist/registry/AgentRegistryClient.js.map +1 -0
- package/dist/runtime/MockRuntime.d.ts.map +1 -1
- package/dist/runtime/MockRuntime.js +3 -1
- package/dist/runtime/MockRuntime.js.map +1 -1
- package/dist/types/adapter.d.ts +39 -0
- package/dist/types/adapter.d.ts.map +1 -1
- package/dist/types/adapter.js +7 -0
- package/dist/types/adapter.js.map +1 -1
- package/dist/types/x402.d.ts +23 -0
- package/dist/types/x402.d.ts.map +1 -1
- package/dist/types/x402.js.map +1 -1
- package/dist/wallet/keystore.d.ts +16 -0
- package/dist/wallet/keystore.d.ts.map +1 -0
- package/dist/wallet/keystore.js +132 -0
- package/dist/wallet/keystore.js.map +1 -0
- package/package.json +2 -1
- package/src/ACTPClient.ts +63 -1
- package/src/abi/AgentRegistry.json +133 -0
- package/src/adapters/X402Adapter.ts +94 -16
- package/src/adapters/index.ts +9 -1
- package/src/cli/commands/diff.ts +141 -0
- package/src/cli/commands/init.ts +65 -4
- package/src/cli/commands/publish.ts +209 -0
- package/src/cli/commands/pull.ts +124 -0
- package/src/cli/index.ts +8 -0
- package/src/config/agirailsmd.ts +262 -0
- package/src/config/networks.ts +12 -4
- package/src/config/publishPipeline.ts +276 -0
- package/src/config/syncOperations.ts +279 -0
- package/src/index.ts +3 -0
- package/src/level0/request.ts +27 -88
- package/src/level1/Agent.ts +16 -32
- package/src/registry/AgentRegistryClient.ts +202 -0
- package/src/runtime/MockRuntime.ts +3 -1
- package/src/types/adapter.ts +14 -0
- package/src/types/x402.ts +32 -0
- package/src/wallet/keystore.ts +119 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports._clearCache = exports.getCachedAddress = exports.resolvePrivateKey = void 0;
|
|
27
|
+
/**
|
|
28
|
+
* Keystore auto-resolution for ACTP wallets.
|
|
29
|
+
*
|
|
30
|
+
* Resolution order:
|
|
31
|
+
* 1. ACTP_PRIVATE_KEY env var (backward compat, highest priority)
|
|
32
|
+
* 2. .actp/keystore.json decrypted with ACTP_KEY_PASSWORD
|
|
33
|
+
* 3. undefined (caller decides what to do)
|
|
34
|
+
*/
|
|
35
|
+
const fs = __importStar(require("fs"));
|
|
36
|
+
const path = __importStar(require("path"));
|
|
37
|
+
const ethers_1 = require("ethers");
|
|
38
|
+
// Cache keyed by resolved keystorePath to support multiple stateDirectories
|
|
39
|
+
const _cache = new Map();
|
|
40
|
+
// Separate cache for env-var-resolved key (no path dependency)
|
|
41
|
+
let _envCache = null;
|
|
42
|
+
/**
|
|
43
|
+
* Validate that stateDirectory doesn't escape expected boundaries.
|
|
44
|
+
* Guards against path traversal when stateDirectory comes from user input.
|
|
45
|
+
*/
|
|
46
|
+
function validateStateDirectory(stateDirectory) {
|
|
47
|
+
if (stateDirectory.includes('\0')) {
|
|
48
|
+
throw new Error('Invalid stateDirectory: null byte detected');
|
|
49
|
+
}
|
|
50
|
+
// Reject raw '..' in the input (before normalization resolves it)
|
|
51
|
+
// Catches both relative traversal (../../etc) and embedded traversal (/tmp/../../etc)
|
|
52
|
+
if (stateDirectory.includes('..')) {
|
|
53
|
+
throw new Error('Invalid stateDirectory: path traversal detected (..)');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Validate and normalize a raw private key string.
|
|
58
|
+
* Trims whitespace and verifies 0x-prefixed 64-char hex format.
|
|
59
|
+
*/
|
|
60
|
+
function validateRawKey(raw, source) {
|
|
61
|
+
const trimmed = raw.trim();
|
|
62
|
+
if (!/^0x[0-9a-fA-F]{64}$/.test(trimmed)) {
|
|
63
|
+
throw new Error(`Invalid private key from ${source}: expected 0x-prefixed 64-char hex string`);
|
|
64
|
+
}
|
|
65
|
+
return trimmed;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Auto-resolve private key: env var → keystore → undefined.
|
|
69
|
+
* Never logs or prints the key itself.
|
|
70
|
+
*/
|
|
71
|
+
async function resolvePrivateKey(stateDirectory) {
|
|
72
|
+
// 1. Env var (highest priority, backward compat)
|
|
73
|
+
if (process.env.ACTP_PRIVATE_KEY) {
|
|
74
|
+
if (_envCache)
|
|
75
|
+
return _envCache.key;
|
|
76
|
+
const key = validateRawKey(process.env.ACTP_PRIVATE_KEY, 'ACTP_PRIVATE_KEY env var');
|
|
77
|
+
const address = new ethers_1.Wallet(key).address;
|
|
78
|
+
_envCache = { key, address };
|
|
79
|
+
return key;
|
|
80
|
+
}
|
|
81
|
+
// 2. Resolve keystore path
|
|
82
|
+
if (stateDirectory) {
|
|
83
|
+
validateStateDirectory(stateDirectory);
|
|
84
|
+
}
|
|
85
|
+
const actpDir = stateDirectory
|
|
86
|
+
? path.join(stateDirectory, '.actp')
|
|
87
|
+
: path.join(process.cwd(), '.actp');
|
|
88
|
+
const keystorePath = path.resolve(actpDir, 'keystore.json');
|
|
89
|
+
// 3. Cache hit (keyed by resolved path)
|
|
90
|
+
const cached = _cache.get(keystorePath);
|
|
91
|
+
if (cached)
|
|
92
|
+
return cached.key;
|
|
93
|
+
// 4. Keystore file
|
|
94
|
+
if (!fs.existsSync(keystorePath))
|
|
95
|
+
return undefined;
|
|
96
|
+
const password = process.env.ACTP_KEY_PASSWORD;
|
|
97
|
+
if (!password) {
|
|
98
|
+
throw new Error('Keystore found at ' + keystorePath + ' but ACTP_KEY_PASSWORD is not set.\n' +
|
|
99
|
+
'Set it: export ACTP_KEY_PASSWORD="your-password"');
|
|
100
|
+
}
|
|
101
|
+
const keystore = fs.readFileSync(keystorePath, 'utf-8');
|
|
102
|
+
const wallet = await ethers_1.Wallet.fromEncryptedJson(keystore, password);
|
|
103
|
+
_cache.set(keystorePath, { key: wallet.privateKey, address: wallet.address });
|
|
104
|
+
return wallet.privateKey;
|
|
105
|
+
}
|
|
106
|
+
exports.resolvePrivateKey = resolvePrivateKey;
|
|
107
|
+
/**
|
|
108
|
+
* Get cached address from last resolvePrivateKey() call.
|
|
109
|
+
* Works for both env-var and keystore resolution paths.
|
|
110
|
+
*/
|
|
111
|
+
function getCachedAddress(stateDirectory) {
|
|
112
|
+
// Env var path
|
|
113
|
+
if (_envCache)
|
|
114
|
+
return _envCache.address;
|
|
115
|
+
// Keystore path — look up by resolved path
|
|
116
|
+
const actpDir = stateDirectory
|
|
117
|
+
? path.join(stateDirectory, '.actp')
|
|
118
|
+
: path.join(process.cwd(), '.actp');
|
|
119
|
+
const keystorePath = path.resolve(actpDir, 'keystore.json');
|
|
120
|
+
return _cache.get(keystorePath)?.address;
|
|
121
|
+
}
|
|
122
|
+
exports.getCachedAddress = getCachedAddress;
|
|
123
|
+
/**
|
|
124
|
+
* Clear all cached keys and addresses (for testing).
|
|
125
|
+
* @internal
|
|
126
|
+
*/
|
|
127
|
+
function _clearCache() {
|
|
128
|
+
_cache.clear();
|
|
129
|
+
_envCache = null;
|
|
130
|
+
}
|
|
131
|
+
exports._clearCache = _clearCache;
|
|
132
|
+
//# sourceMappingURL=keystore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keystore.js","sourceRoot":"","sources":["../../src/wallet/keystore.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agirails/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "AGIRAILS SDK for the ACTP (Agent Commerce Transaction Protocol) - Unified mock + blockchain support",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
"fast-json-stable-stringify": "2.1.0",
|
|
81
81
|
"kubo-rpc-client": "3.0.1",
|
|
82
82
|
"proper-lockfile": "4.1.2",
|
|
83
|
+
"yaml": "^2.8.2",
|
|
83
84
|
"zod": "^3.22.4"
|
|
84
85
|
},
|
|
85
86
|
"devDependencies": {
|
package/src/ACTPClient.ts
CHANGED
|
@@ -655,7 +655,16 @@ export class ACTPClient {
|
|
|
655
655
|
|
|
656
656
|
// SECURITY FIX (C-4): Pass EASHelper to adapters for attestation verification
|
|
657
657
|
// ERC-8004: Pass bridge for agent ID resolution, reporter for settlement outcomes
|
|
658
|
-
|
|
658
|
+
const client = new ACTPClient(runtime, normalizedAddress, info, easHelper, erc8004Bridge, reputationReporter);
|
|
659
|
+
|
|
660
|
+
// Drift detection: non-blocking check for AGIRAILS.md sync status
|
|
661
|
+
if (config.mode !== 'mock') {
|
|
662
|
+
client.checkConfigDrift(config).catch(() => {
|
|
663
|
+
// Silently ignore drift check errors — non-critical
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
return client;
|
|
659
668
|
}
|
|
660
669
|
|
|
661
670
|
// ==========================================================================
|
|
@@ -1103,4 +1112,57 @@ export class ACTPClient {
|
|
|
1103
1112
|
getReputationReporter(): ReputationReporter | undefined {
|
|
1104
1113
|
return this.reputationReporter;
|
|
1105
1114
|
}
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Non-blocking drift detection for AGIRAILS.md config.
|
|
1118
|
+
* Checks if local AGIRAILS.md matches on-chain config hash.
|
|
1119
|
+
* Logs warnings but never blocks agent operation.
|
|
1120
|
+
* @internal
|
|
1121
|
+
*/
|
|
1122
|
+
private async checkConfigDrift(config: ACTPClientConfig): Promise<void> {
|
|
1123
|
+
try {
|
|
1124
|
+
const { existsSync, readFileSync } = await import('fs');
|
|
1125
|
+
const { join } = await import('path');
|
|
1126
|
+
|
|
1127
|
+
// Look for AGIRAILS.md in cwd
|
|
1128
|
+
const agirailsMdPath = join(process.cwd(), 'AGIRAILS.md');
|
|
1129
|
+
if (!existsSync(agirailsMdPath)) {
|
|
1130
|
+
return; // No local file — nothing to check
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
const network = config.mode === 'testnet' ? 'base-sepolia' : 'base-mainnet';
|
|
1134
|
+
const networkConfig = getNetwork(network);
|
|
1135
|
+
if (!networkConfig.contracts.agentRegistry) {
|
|
1136
|
+
return; // No registry on this network
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
const content = readFileSync(agirailsMdPath, 'utf-8');
|
|
1140
|
+
const { computeConfigHash } = await import('./config/agirailsmd');
|
|
1141
|
+
const { configHash: localHash } = computeConfigHash(content);
|
|
1142
|
+
|
|
1143
|
+
const { AgentRegistryClient } = await import('./registry/AgentRegistryClient');
|
|
1144
|
+
const provider = new ethers.JsonRpcProvider(networkConfig.rpcUrl);
|
|
1145
|
+
const registryClient = AgentRegistryClient.readOnly(networkConfig.contracts.agentRegistry, provider);
|
|
1146
|
+
|
|
1147
|
+
// Detect template vs published state from frontmatter
|
|
1148
|
+
const { parseAgirailsMd: parseMd } = await import('./config/agirailsmd');
|
|
1149
|
+
const { frontmatter } = parseMd(content);
|
|
1150
|
+
const isTemplate = !frontmatter.config_hash;
|
|
1151
|
+
|
|
1152
|
+
const onChainState = await registryClient.getConfig(config.requesterAddress);
|
|
1153
|
+
const ZERO_HASH = '0x' + '0'.repeat(64);
|
|
1154
|
+
|
|
1155
|
+
if (onChainState.configHash === ZERO_HASH) {
|
|
1156
|
+
if (isTemplate) {
|
|
1157
|
+
console.info('[AGIRAILS] AGIRAILS.md loaded (template mode). Run "actp publish" to register and sync on-chain.');
|
|
1158
|
+
} else {
|
|
1159
|
+
console.warn('[AGIRAILS] Config not published on-chain. Run: actp publish');
|
|
1160
|
+
}
|
|
1161
|
+
} else if (onChainState.configHash !== localHash) {
|
|
1162
|
+
console.warn('[AGIRAILS] Local AGIRAILS.md differs from on-chain. Run: actp diff');
|
|
1163
|
+
}
|
|
1164
|
+
} catch {
|
|
1165
|
+
// Silently ignore — drift detection is best-effort
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1106
1168
|
}
|
|
@@ -10,6 +10,19 @@
|
|
|
10
10
|
],
|
|
11
11
|
"stateMutability": "nonpayable"
|
|
12
12
|
},
|
|
13
|
+
{
|
|
14
|
+
"type": "function",
|
|
15
|
+
"name": "MAX_CID_LENGTH",
|
|
16
|
+
"inputs": [],
|
|
17
|
+
"outputs": [
|
|
18
|
+
{
|
|
19
|
+
"name": "",
|
|
20
|
+
"type": "uint256",
|
|
21
|
+
"internalType": "uint256"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"stateMutability": "view"
|
|
25
|
+
},
|
|
13
26
|
{
|
|
14
27
|
"type": "function",
|
|
15
28
|
"name": "MAX_ENDPOINT_LENGTH",
|
|
@@ -166,6 +179,21 @@
|
|
|
166
179
|
"name": "isActive",
|
|
167
180
|
"type": "bool",
|
|
168
181
|
"internalType": "bool"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"name": "configHash",
|
|
185
|
+
"type": "bytes32",
|
|
186
|
+
"internalType": "bytes32"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"name": "configCID",
|
|
190
|
+
"type": "string",
|
|
191
|
+
"internalType": "string"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"name": "listed",
|
|
195
|
+
"type": "bool",
|
|
196
|
+
"internalType": "bool"
|
|
169
197
|
}
|
|
170
198
|
],
|
|
171
199
|
"stateMutability": "view"
|
|
@@ -277,6 +305,21 @@
|
|
|
277
305
|
"name": "isActive",
|
|
278
306
|
"type": "bool",
|
|
279
307
|
"internalType": "bool"
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"name": "configHash",
|
|
311
|
+
"type": "bytes32",
|
|
312
|
+
"internalType": "bytes32"
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
"name": "configCID",
|
|
316
|
+
"type": "string",
|
|
317
|
+
"internalType": "string"
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
"name": "listed",
|
|
321
|
+
"type": "bool",
|
|
322
|
+
"internalType": "bool"
|
|
280
323
|
}
|
|
281
324
|
]
|
|
282
325
|
}
|
|
@@ -358,6 +401,21 @@
|
|
|
358
401
|
"name": "isActive",
|
|
359
402
|
"type": "bool",
|
|
360
403
|
"internalType": "bool"
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
"name": "configHash",
|
|
407
|
+
"type": "bytes32",
|
|
408
|
+
"internalType": "bytes32"
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"name": "configCID",
|
|
412
|
+
"type": "string",
|
|
413
|
+
"internalType": "string"
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
"name": "listed",
|
|
417
|
+
"type": "bool",
|
|
418
|
+
"internalType": "bool"
|
|
361
419
|
}
|
|
362
420
|
]
|
|
363
421
|
}
|
|
@@ -420,6 +478,24 @@
|
|
|
420
478
|
],
|
|
421
479
|
"stateMutability": "view"
|
|
422
480
|
},
|
|
481
|
+
{
|
|
482
|
+
"type": "function",
|
|
483
|
+
"name": "publishConfig",
|
|
484
|
+
"inputs": [
|
|
485
|
+
{
|
|
486
|
+
"name": "cid",
|
|
487
|
+
"type": "string",
|
|
488
|
+
"internalType": "string"
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
"name": "hash",
|
|
492
|
+
"type": "bytes32",
|
|
493
|
+
"internalType": "bytes32"
|
|
494
|
+
}
|
|
495
|
+
],
|
|
496
|
+
"outputs": [],
|
|
497
|
+
"stateMutability": "nonpayable"
|
|
498
|
+
},
|
|
423
499
|
{
|
|
424
500
|
"type": "function",
|
|
425
501
|
"name": "queryAgentsByService",
|
|
@@ -535,6 +611,19 @@
|
|
|
535
611
|
"outputs": [],
|
|
536
612
|
"stateMutability": "nonpayable"
|
|
537
613
|
},
|
|
614
|
+
{
|
|
615
|
+
"type": "function",
|
|
616
|
+
"name": "setListed",
|
|
617
|
+
"inputs": [
|
|
618
|
+
{
|
|
619
|
+
"name": "_listed",
|
|
620
|
+
"type": "bool",
|
|
621
|
+
"internalType": "bool"
|
|
622
|
+
}
|
|
623
|
+
],
|
|
624
|
+
"outputs": [],
|
|
625
|
+
"stateMutability": "nonpayable"
|
|
626
|
+
},
|
|
538
627
|
{
|
|
539
628
|
"type": "function",
|
|
540
629
|
"name": "supportsService",
|
|
@@ -656,6 +745,31 @@
|
|
|
656
745
|
],
|
|
657
746
|
"anonymous": false
|
|
658
747
|
},
|
|
748
|
+
{
|
|
749
|
+
"type": "event",
|
|
750
|
+
"name": "ConfigPublished",
|
|
751
|
+
"inputs": [
|
|
752
|
+
{
|
|
753
|
+
"name": "agent",
|
|
754
|
+
"type": "address",
|
|
755
|
+
"indexed": true,
|
|
756
|
+
"internalType": "address"
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
"name": "configCID",
|
|
760
|
+
"type": "string",
|
|
761
|
+
"indexed": false,
|
|
762
|
+
"internalType": "string"
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
"name": "configHash",
|
|
766
|
+
"type": "bytes32",
|
|
767
|
+
"indexed": false,
|
|
768
|
+
"internalType": "bytes32"
|
|
769
|
+
}
|
|
770
|
+
],
|
|
771
|
+
"anonymous": false
|
|
772
|
+
},
|
|
659
773
|
{
|
|
660
774
|
"type": "event",
|
|
661
775
|
"name": "EndpointUpdated",
|
|
@@ -687,6 +801,25 @@
|
|
|
687
801
|
],
|
|
688
802
|
"anonymous": false
|
|
689
803
|
},
|
|
804
|
+
{
|
|
805
|
+
"type": "event",
|
|
806
|
+
"name": "ListingChanged",
|
|
807
|
+
"inputs": [
|
|
808
|
+
{
|
|
809
|
+
"name": "agent",
|
|
810
|
+
"type": "address",
|
|
811
|
+
"indexed": true,
|
|
812
|
+
"internalType": "address"
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
"name": "listed",
|
|
816
|
+
"type": "bool",
|
|
817
|
+
"indexed": false,
|
|
818
|
+
"internalType": "bool"
|
|
819
|
+
}
|
|
820
|
+
],
|
|
821
|
+
"anonymous": false
|
|
822
|
+
},
|
|
690
823
|
{
|
|
691
824
|
"type": "event",
|
|
692
825
|
"name": "ReputationUpdated",
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
X402Error,
|
|
36
36
|
X402ErrorCode,
|
|
37
37
|
X402Network,
|
|
38
|
+
X402FeeBreakdown,
|
|
38
39
|
isValidX402Network,
|
|
39
40
|
} from '../types/x402';
|
|
40
41
|
|
|
@@ -46,14 +47,33 @@ import {
|
|
|
46
47
|
export type FetchFunction = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
47
48
|
|
|
48
49
|
/**
|
|
49
|
-
* Transfer function for atomic payments.
|
|
50
|
-
*
|
|
50
|
+
* Transfer function for atomic payments (legacy direct transfer).
|
|
51
|
+
*
|
|
51
52
|
* @param to - Recipient address
|
|
52
53
|
* @param amount - Amount in USDC wei (string)
|
|
53
54
|
* @returns Transaction hash as proof
|
|
54
55
|
*/
|
|
55
56
|
export type TransferFunction = (to: string, amount: string) => Promise<string>;
|
|
56
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Approve function for USDC allowance (used with X402Relay).
|
|
60
|
+
*
|
|
61
|
+
* @param spender - Spender address (relay contract)
|
|
62
|
+
* @param amount - Amount in USDC wei (string)
|
|
63
|
+
* @returns Transaction hash
|
|
64
|
+
*/
|
|
65
|
+
export type ApproveFunction = (spender: string, amount: string) => Promise<string>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Relay pay function — calls X402Relay.payWithFee().
|
|
69
|
+
*
|
|
70
|
+
* @param provider - Provider address
|
|
71
|
+
* @param grossAmount - Gross USDC amount (string)
|
|
72
|
+
* @param serviceId - Service identifier (bytes32 hex)
|
|
73
|
+
* @returns Transaction hash
|
|
74
|
+
*/
|
|
75
|
+
export type RelayPayFunction = (provider: string, grossAmount: string, serviceId: string) => Promise<string>;
|
|
76
|
+
|
|
57
77
|
/** Supported HTTP methods for x402 requests */
|
|
58
78
|
export type X402HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
59
79
|
|
|
@@ -76,12 +96,15 @@ export interface X402PayParams extends UnifiedPayParams {
|
|
|
76
96
|
|
|
77
97
|
/**
|
|
78
98
|
* Configuration options for X402Adapter.
|
|
99
|
+
*
|
|
100
|
+
* For fee-enabled payments via X402Relay, provide relayAddress + approveFn + relayPayFn.
|
|
101
|
+
* Without relay config, falls back to legacy direct transfer (no platform fee).
|
|
79
102
|
*/
|
|
80
103
|
export interface X402AdapterConfig {
|
|
81
104
|
/** Expected network for validation (must match server's X-Payment-Network) */
|
|
82
105
|
expectedNetwork: X402Network;
|
|
83
106
|
|
|
84
|
-
/** Transfer function for atomic payments (
|
|
107
|
+
/** Transfer function for direct atomic payments (legacy fallback) */
|
|
85
108
|
transferFn: TransferFunction;
|
|
86
109
|
|
|
87
110
|
/** Request timeout in milliseconds (default: 30000) */
|
|
@@ -92,6 +115,20 @@ export interface X402AdapterConfig {
|
|
|
92
115
|
|
|
93
116
|
/** Default headers to include in all requests */
|
|
94
117
|
defaultHeaders?: Record<string, string>;
|
|
118
|
+
|
|
119
|
+
// --- X402Relay fee-splitting (optional, recommended) ---
|
|
120
|
+
|
|
121
|
+
/** X402Relay contract address for on-chain fee splitting */
|
|
122
|
+
relayAddress?: string;
|
|
123
|
+
|
|
124
|
+
/** USDC approve function — required when relayAddress is set */
|
|
125
|
+
approveFn?: ApproveFunction;
|
|
126
|
+
|
|
127
|
+
/** Relay payWithFee function — required when relayAddress is set */
|
|
128
|
+
relayPayFn?: RelayPayFunction;
|
|
129
|
+
|
|
130
|
+
/** Platform fee in basis points (default: 100 = 1%). Read-only display hint. */
|
|
131
|
+
platformFeeBps?: number;
|
|
95
132
|
}
|
|
96
133
|
|
|
97
134
|
/**
|
|
@@ -104,6 +141,7 @@ interface AtomicPaymentRecord {
|
|
|
104
141
|
amount: string;
|
|
105
142
|
timestamp: number;
|
|
106
143
|
endpoint: string;
|
|
144
|
+
feeBreakdown?: X402FeeBreakdown;
|
|
107
145
|
}
|
|
108
146
|
|
|
109
147
|
// ============================================================================
|
|
@@ -287,15 +325,15 @@ export class X402Adapter extends BaseAdapter implements IAdapter {
|
|
|
287
325
|
);
|
|
288
326
|
}
|
|
289
327
|
|
|
290
|
-
// Step 6: ATOMIC PAYMENT - direct transfer
|
|
291
|
-
const txHash = await this.executeAtomicPayment(paymentHeaders);
|
|
328
|
+
// Step 6: ATOMIC PAYMENT - via relay (with fee) or direct transfer (legacy)
|
|
329
|
+
const { txHash, feeBreakdown } = await this.executeAtomicPayment(paymentHeaders);
|
|
292
330
|
|
|
293
331
|
// Step 7: Retry with proof (same method/headers/body + payment proof)
|
|
294
332
|
const serviceResponse = await this.retryWithProof(
|
|
295
|
-
endpoint,
|
|
296
|
-
txHash,
|
|
297
|
-
method,
|
|
298
|
-
requestHeaders,
|
|
333
|
+
endpoint,
|
|
334
|
+
txHash,
|
|
335
|
+
method,
|
|
336
|
+
requestHeaders,
|
|
299
337
|
requestBody,
|
|
300
338
|
contentType
|
|
301
339
|
);
|
|
@@ -308,6 +346,7 @@ export class X402Adapter extends BaseAdapter implements IAdapter {
|
|
|
308
346
|
amount: paymentHeaders.amount,
|
|
309
347
|
timestamp: now,
|
|
310
348
|
endpoint,
|
|
349
|
+
feeBreakdown,
|
|
311
350
|
});
|
|
312
351
|
|
|
313
352
|
// Step 9: Return result - DONE! No release needed.
|
|
@@ -323,6 +362,7 @@ export class X402Adapter extends BaseAdapter implements IAdapter {
|
|
|
323
362
|
provider: paymentHeaders.paymentAddress.toLowerCase(),
|
|
324
363
|
requester: this.requesterAddress.toLowerCase(),
|
|
325
364
|
deadline: new Date(paymentHeaders.deadline * 1000).toISOString(),
|
|
365
|
+
feeBreakdown,
|
|
326
366
|
};
|
|
327
367
|
}
|
|
328
368
|
|
|
@@ -562,20 +602,58 @@ export class X402Adapter extends BaseAdapter implements IAdapter {
|
|
|
562
602
|
}
|
|
563
603
|
|
|
564
604
|
/**
|
|
565
|
-
* Execute atomic payment
|
|
605
|
+
* Execute atomic payment with fee splitting via X402Relay (if configured),
|
|
606
|
+
* or direct transfer as legacy fallback.
|
|
566
607
|
*
|
|
567
|
-
*
|
|
568
|
-
*
|
|
569
|
-
* - No state machine
|
|
570
|
-
* - Just transfer and done
|
|
608
|
+
* Relay flow: approve relay → relay.payWithFee(provider, gross, serviceId)
|
|
609
|
+
* Legacy flow: transferFn(provider, amount) — no fee extraction
|
|
571
610
|
*/
|
|
572
|
-
private async executeAtomicPayment(headers: X402PaymentHeaders): Promise<
|
|
611
|
+
private async executeAtomicPayment(headers: X402PaymentHeaders): Promise<{
|
|
612
|
+
txHash: string;
|
|
613
|
+
feeBreakdown?: X402FeeBreakdown;
|
|
614
|
+
}> {
|
|
573
615
|
try {
|
|
616
|
+
// Relay path: on-chain fee splitting
|
|
617
|
+
if (this.config.relayAddress && this.config.approveFn && this.config.relayPayFn) {
|
|
618
|
+
const grossAmount = headers.amount;
|
|
619
|
+
const feeBps = this.config.platformFeeBps ?? 100;
|
|
620
|
+
const MIN_FEE = 50_000n; // $0.05 USDC
|
|
621
|
+
|
|
622
|
+
// Calculate fee: max(gross * bps / 10000, MIN_FEE)
|
|
623
|
+
const grossBig = BigInt(grossAmount);
|
|
624
|
+
const bpsFee = (grossBig * BigInt(feeBps)) / 10_000n;
|
|
625
|
+
const fee = bpsFee > MIN_FEE ? bpsFee : MIN_FEE;
|
|
626
|
+
const providerNet = grossBig - fee;
|
|
627
|
+
|
|
628
|
+
// 1. Approve relay for gross amount
|
|
629
|
+
await this.config.approveFn(this.config.relayAddress, grossAmount);
|
|
630
|
+
|
|
631
|
+
// 2. Call relay.payWithFee
|
|
632
|
+
const serviceId = headers.serviceId ?? '0x' + '0'.repeat(64);
|
|
633
|
+
const txHash = await this.config.relayPayFn(
|
|
634
|
+
headers.paymentAddress,
|
|
635
|
+
grossAmount,
|
|
636
|
+
serviceId
|
|
637
|
+
);
|
|
638
|
+
|
|
639
|
+
return {
|
|
640
|
+
txHash,
|
|
641
|
+
feeBreakdown: {
|
|
642
|
+
grossAmount,
|
|
643
|
+
providerNet: providerNet.toString(),
|
|
644
|
+
platformFee: fee.toString(),
|
|
645
|
+
feeBps,
|
|
646
|
+
estimated: true,
|
|
647
|
+
},
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// Legacy path: direct transfer, no fee
|
|
574
652
|
const txHash = await this.transferFn(
|
|
575
653
|
headers.paymentAddress,
|
|
576
654
|
headers.amount
|
|
577
655
|
);
|
|
578
|
-
return txHash;
|
|
656
|
+
return { txHash };
|
|
579
657
|
} catch (error) {
|
|
580
658
|
throw new X402Error(
|
|
581
659
|
`Atomic payment failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
package/src/adapters/index.ts
CHANGED
|
@@ -23,7 +23,15 @@ export {
|
|
|
23
23
|
} from './BaseAdapter';
|
|
24
24
|
export { BasicAdapter, BasicPayParams, BasicPayResult } from './BasicAdapter';
|
|
25
25
|
export { StandardAdapter, StandardTransactionParams } from './StandardAdapter';
|
|
26
|
-
export {
|
|
26
|
+
export {
|
|
27
|
+
X402Adapter,
|
|
28
|
+
X402AdapterConfig,
|
|
29
|
+
X402PayParams,
|
|
30
|
+
X402HttpMethod,
|
|
31
|
+
FetchFunction,
|
|
32
|
+
ApproveFunction,
|
|
33
|
+
RelayPayFunction,
|
|
34
|
+
} from './X402Adapter';
|
|
27
35
|
export { AdapterRegistry } from './AdapterRegistry';
|
|
28
36
|
export { AdapterRouter, AdapterSelectionResult } from './AdapterRouter';
|
|
29
37
|
export {
|