@buildersgarden/siwa 0.0.1
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 +75 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/keystore.d.ts +126 -0
- package/dist/keystore.js +355 -0
- package/dist/memory.d.ts +37 -0
- package/dist/memory.js +134 -0
- package/dist/proxy-auth.d.ts +27 -0
- package/dist/proxy-auth.js +58 -0
- package/dist/registry.d.ts +74 -0
- package/dist/registry.js +89 -0
- package/dist/siwa.d.ts +99 -0
- package/dist/siwa.js +284 -0
- package/package.json +27 -0
package/dist/memory.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memory.ts
|
|
3
|
+
*
|
|
4
|
+
* Read/write helpers for the agent's MEMORY.md public identity file.
|
|
5
|
+
* MEMORY.md uses the pattern: - **Key**: `value`
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: This file stores ONLY public data (address, agentId, etc.).
|
|
8
|
+
* Private keys are managed exclusively by keystore.ts.
|
|
9
|
+
*
|
|
10
|
+
* Dependencies: fs (Node built-in)
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
const DEFAULT_MEMORY_PATH = './MEMORY.md';
|
|
14
|
+
/**
|
|
15
|
+
* Ensure MEMORY.md exists. If not, copy from template or create minimal.
|
|
16
|
+
*/
|
|
17
|
+
export function ensureMemoryExists(memoryPath = DEFAULT_MEMORY_PATH, templatePath) {
|
|
18
|
+
if (fs.existsSync(memoryPath))
|
|
19
|
+
return;
|
|
20
|
+
if (templatePath && fs.existsSync(templatePath)) {
|
|
21
|
+
fs.copyFileSync(templatePath, memoryPath);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
const minimal = `# Agent Identity Memory
|
|
25
|
+
|
|
26
|
+
> This file contains **public** agent identity data only. The private key is stored
|
|
27
|
+
> securely in the keystore backend (OS keychain or encrypted file) — never here.
|
|
28
|
+
|
|
29
|
+
## Wallet
|
|
30
|
+
|
|
31
|
+
- **Address**: \`<NOT SET>\`
|
|
32
|
+
- **Keystore Backend**: \`<NOT SET>\`
|
|
33
|
+
- **Keystore Path**: \`<NOT SET>\`
|
|
34
|
+
- **Created At**: \`<NOT SET>\`
|
|
35
|
+
|
|
36
|
+
## Registration
|
|
37
|
+
|
|
38
|
+
- **Status**: \`unregistered\`
|
|
39
|
+
- **Agent ID**: \`<NOT SET>\`
|
|
40
|
+
- **Agent Registry**: \`<NOT SET>\`
|
|
41
|
+
- **Agent URI**: \`<NOT SET>\`
|
|
42
|
+
- **Chain ID**: \`<NOT SET>\`
|
|
43
|
+
- **Registered At**: \`<NOT SET>\`
|
|
44
|
+
|
|
45
|
+
## Agent Profile
|
|
46
|
+
|
|
47
|
+
- **Name**: \`<NOT SET>\`
|
|
48
|
+
- **Description**: \`<NOT SET>\`
|
|
49
|
+
- **Image**: \`<NOT SET>\`
|
|
50
|
+
|
|
51
|
+
## Services
|
|
52
|
+
|
|
53
|
+
## Sessions
|
|
54
|
+
|
|
55
|
+
## Notes
|
|
56
|
+
`;
|
|
57
|
+
fs.writeFileSync(memoryPath, minimal);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Read all populated fields from MEMORY.md.
|
|
62
|
+
* Returns a map of Key → value (skips <NOT SET> fields).
|
|
63
|
+
*/
|
|
64
|
+
export function readMemory(memoryPath = DEFAULT_MEMORY_PATH) {
|
|
65
|
+
if (!fs.existsSync(memoryPath))
|
|
66
|
+
return {};
|
|
67
|
+
const content = fs.readFileSync(memoryPath, 'utf-8');
|
|
68
|
+
const fields = {};
|
|
69
|
+
for (const line of content.split('\n')) {
|
|
70
|
+
const match = line.match(/^- \*\*(.+?)\*\*:\s*`(.+?)`/);
|
|
71
|
+
if (match && match[2] !== '<NOT SET>') {
|
|
72
|
+
fields[match[1]] = match[2];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return fields;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Write a single field value in MEMORY.md.
|
|
79
|
+
*/
|
|
80
|
+
export function writeMemoryField(key, value, memoryPath = DEFAULT_MEMORY_PATH) {
|
|
81
|
+
let content = fs.readFileSync(memoryPath, 'utf-8');
|
|
82
|
+
const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
83
|
+
const pattern = new RegExp(`(- \\*\\*${escaped}\\*\\*:\\s*)\`.+?\``);
|
|
84
|
+
if (pattern.test(content)) {
|
|
85
|
+
content = content.replace(pattern, `$1\`${value}\``);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
content += `\n- **${key}**: \`${value}\`\n`;
|
|
89
|
+
}
|
|
90
|
+
fs.writeFileSync(memoryPath, content);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Append a line under a ## Section header in MEMORY.md.
|
|
94
|
+
*/
|
|
95
|
+
export function appendToMemorySection(section, line, memoryPath = DEFAULT_MEMORY_PATH) {
|
|
96
|
+
let content = fs.readFileSync(memoryPath, 'utf-8');
|
|
97
|
+
const marker = `## ${section}`;
|
|
98
|
+
const idx = content.indexOf(marker);
|
|
99
|
+
if (idx === -1) {
|
|
100
|
+
content += `\n## ${section}\n\n${line}\n`;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const headerEnd = content.indexOf('\n', idx);
|
|
104
|
+
if (headerEnd === -1) {
|
|
105
|
+
content += `\n${line}\n`;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
let insertPos = headerEnd + 1;
|
|
109
|
+
const afterHeader = content.slice(insertPos);
|
|
110
|
+
const commentMatch = afterHeader.match(/^<!--.*?-->\n/);
|
|
111
|
+
if (commentMatch)
|
|
112
|
+
insertPos += commentMatch[0].length;
|
|
113
|
+
if (content[insertPos] === '\n')
|
|
114
|
+
insertPos += 1;
|
|
115
|
+
content = content.slice(0, insertPos) + line + '\n' + content.slice(insertPos);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
fs.writeFileSync(memoryPath, content);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Check if the agent has a wallet address recorded.
|
|
122
|
+
* Note: This only checks MEMORY.md — the actual key is in the keystore.
|
|
123
|
+
*/
|
|
124
|
+
export function hasWalletRecord(memoryPath = DEFAULT_MEMORY_PATH) {
|
|
125
|
+
const mem = readMemory(memoryPath);
|
|
126
|
+
return !!mem['Address'];
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Check if the agent is registered onchain.
|
|
130
|
+
*/
|
|
131
|
+
export function isRegistered(memoryPath = DEFAULT_MEMORY_PATH) {
|
|
132
|
+
const mem = readMemory(memoryPath);
|
|
133
|
+
return mem['Status'] === 'registered' && !!mem['Agent ID'];
|
|
134
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* proxy-auth.ts
|
|
3
|
+
*
|
|
4
|
+
* Shared HMAC-SHA256 authentication utility for the keyring proxy.
|
|
5
|
+
* Used by both the proxy client (keystore.ts) and server (test/proxy/index.ts).
|
|
6
|
+
*
|
|
7
|
+
* Security features:
|
|
8
|
+
* - HMAC-SHA256 over method + path + body + timestamp
|
|
9
|
+
* - 30-second timestamp drift limit for replay protection
|
|
10
|
+
* - Constant-time comparison via crypto.timingSafeEqual
|
|
11
|
+
*/
|
|
12
|
+
export interface HmacHeaders {
|
|
13
|
+
'X-Proxy-Timestamp': string;
|
|
14
|
+
'X-Proxy-Signature': string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Compute HMAC-SHA256 headers for an outgoing request.
|
|
18
|
+
*/
|
|
19
|
+
export declare function computeHmac(secret: string, method: string, path: string, body: string): HmacHeaders;
|
|
20
|
+
/**
|
|
21
|
+
* Verify an incoming HMAC-SHA256 signature.
|
|
22
|
+
* Returns { valid: true } or { valid: false, error: string }.
|
|
23
|
+
*/
|
|
24
|
+
export declare function verifyHmac(secret: string, method: string, path: string, body: string, timestamp: string, signature: string): {
|
|
25
|
+
valid: boolean;
|
|
26
|
+
error?: string;
|
|
27
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* proxy-auth.ts
|
|
3
|
+
*
|
|
4
|
+
* Shared HMAC-SHA256 authentication utility for the keyring proxy.
|
|
5
|
+
* Used by both the proxy client (keystore.ts) and server (test/proxy/index.ts).
|
|
6
|
+
*
|
|
7
|
+
* Security features:
|
|
8
|
+
* - HMAC-SHA256 over method + path + body + timestamp
|
|
9
|
+
* - 30-second timestamp drift limit for replay protection
|
|
10
|
+
* - Constant-time comparison via crypto.timingSafeEqual
|
|
11
|
+
*/
|
|
12
|
+
import * as crypto from 'crypto';
|
|
13
|
+
const MAX_DRIFT_MS = 30_000; // 30 seconds
|
|
14
|
+
/**
|
|
15
|
+
* Compute HMAC-SHA256 headers for an outgoing request.
|
|
16
|
+
*/
|
|
17
|
+
export function computeHmac(secret, method, path, body) {
|
|
18
|
+
const timestamp = Date.now().toString();
|
|
19
|
+
const payload = `${method.toUpperCase()}\n${path}\n${timestamp}\n${body}`;
|
|
20
|
+
const signature = crypto
|
|
21
|
+
.createHmac('sha256', secret)
|
|
22
|
+
.update(payload)
|
|
23
|
+
.digest('hex');
|
|
24
|
+
return {
|
|
25
|
+
'X-Proxy-Timestamp': timestamp,
|
|
26
|
+
'X-Proxy-Signature': signature,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Verify an incoming HMAC-SHA256 signature.
|
|
31
|
+
* Returns { valid: true } or { valid: false, error: string }.
|
|
32
|
+
*/
|
|
33
|
+
export function verifyHmac(secret, method, path, body, timestamp, signature) {
|
|
34
|
+
// Check timestamp drift
|
|
35
|
+
const ts = parseInt(timestamp, 10);
|
|
36
|
+
if (isNaN(ts))
|
|
37
|
+
return { valid: false, error: 'Invalid timestamp' };
|
|
38
|
+
const drift = Math.abs(Date.now() - ts);
|
|
39
|
+
if (drift > MAX_DRIFT_MS) {
|
|
40
|
+
return { valid: false, error: `Timestamp drift ${drift}ms exceeds ${MAX_DRIFT_MS}ms limit` };
|
|
41
|
+
}
|
|
42
|
+
// Recompute expected signature
|
|
43
|
+
const payload = `${method.toUpperCase()}\n${path}\n${timestamp}\n${body}`;
|
|
44
|
+
const expected = crypto
|
|
45
|
+
.createHmac('sha256', secret)
|
|
46
|
+
.update(payload)
|
|
47
|
+
.digest('hex');
|
|
48
|
+
// Constant-time comparison
|
|
49
|
+
const sigBuf = Buffer.from(signature, 'utf-8');
|
|
50
|
+
const expBuf = Buffer.from(expected, 'utf-8');
|
|
51
|
+
if (sigBuf.length !== expBuf.length) {
|
|
52
|
+
return { valid: false, error: 'Signature mismatch' };
|
|
53
|
+
}
|
|
54
|
+
if (!crypto.timingSafeEqual(sigBuf, expBuf)) {
|
|
55
|
+
return { valid: false, error: 'Signature mismatch' };
|
|
56
|
+
}
|
|
57
|
+
return { valid: true };
|
|
58
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* registry.ts
|
|
3
|
+
*
|
|
4
|
+
* Agent Identity Registry reader.
|
|
5
|
+
* Provides functions to read agent profiles and reputation from on-chain registries.
|
|
6
|
+
*
|
|
7
|
+
* Dependencies:
|
|
8
|
+
* npm install ethers
|
|
9
|
+
*/
|
|
10
|
+
import { ethers } from 'ethers';
|
|
11
|
+
/** Service endpoint types defined in ERC-8004 */
|
|
12
|
+
export type ServiceType = 'web' | 'A2A' | 'MCP' | 'OASF' | 'ENS' | 'DID' | 'email';
|
|
13
|
+
/** Trust models defined in ERC-8004 */
|
|
14
|
+
export type TrustModel = 'reputation' | 'crypto-economic' | 'tee-attestation';
|
|
15
|
+
/** Predefined reputation feedback tags defined in ERC-8004 */
|
|
16
|
+
export type ReputationTag = 'starred' | 'reachable' | 'ownerVerified' | 'uptime' | 'successRate' | 'responseTime' | 'blocktimeFreshness' | 'revenues' | 'tradingYield';
|
|
17
|
+
export interface AgentService {
|
|
18
|
+
name: ServiceType | (string & {});
|
|
19
|
+
endpoint: string;
|
|
20
|
+
version?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface AgentRegistration {
|
|
23
|
+
agentId: number;
|
|
24
|
+
agentRegistry: string;
|
|
25
|
+
}
|
|
26
|
+
export interface AgentMetadata {
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
image: string;
|
|
30
|
+
services: AgentService[];
|
|
31
|
+
active: boolean;
|
|
32
|
+
x402Support?: boolean;
|
|
33
|
+
supportedTrust?: (TrustModel | (string & {}))[];
|
|
34
|
+
registrations?: AgentRegistration[];
|
|
35
|
+
}
|
|
36
|
+
export interface AgentProfile {
|
|
37
|
+
agentId: number;
|
|
38
|
+
owner: string;
|
|
39
|
+
uri: string;
|
|
40
|
+
agentWallet: string | null;
|
|
41
|
+
metadata: AgentMetadata | null;
|
|
42
|
+
}
|
|
43
|
+
export interface GetAgentOptions {
|
|
44
|
+
registryAddress: string;
|
|
45
|
+
provider: ethers.Provider;
|
|
46
|
+
fetchMetadata?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export interface ReputationSummary {
|
|
49
|
+
count: number;
|
|
50
|
+
score: number;
|
|
51
|
+
rawValue: bigint;
|
|
52
|
+
decimals: number;
|
|
53
|
+
}
|
|
54
|
+
export interface GetReputationOptions {
|
|
55
|
+
reputationRegistryAddress: string;
|
|
56
|
+
provider: ethers.Provider;
|
|
57
|
+
clients?: string[];
|
|
58
|
+
tag1?: ReputationTag | (string & {});
|
|
59
|
+
tag2?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Read an agent from the Identity Registry and parse its profile.
|
|
63
|
+
*
|
|
64
|
+
* @param agentId The on-chain agent token ID
|
|
65
|
+
* @param options Registry address, provider, and optional fetchMetadata flag
|
|
66
|
+
*/
|
|
67
|
+
export declare function getAgent(agentId: number, options: GetAgentOptions): Promise<AgentProfile>;
|
|
68
|
+
/**
|
|
69
|
+
* Read an agent's reputation summary from the Reputation Registry.
|
|
70
|
+
*
|
|
71
|
+
* @param agentId The on-chain agent token ID
|
|
72
|
+
* @param options Reputation registry address, provider, and optional filters
|
|
73
|
+
*/
|
|
74
|
+
export declare function getReputation(agentId: number, options: GetReputationOptions): Promise<ReputationSummary>;
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* registry.ts
|
|
3
|
+
*
|
|
4
|
+
* Agent Identity Registry reader.
|
|
5
|
+
* Provides functions to read agent profiles and reputation from on-chain registries.
|
|
6
|
+
*
|
|
7
|
+
* Dependencies:
|
|
8
|
+
* npm install ethers
|
|
9
|
+
*/
|
|
10
|
+
import { ethers } from 'ethers';
|
|
11
|
+
// ─── ABI Fragments ──────────────────────────────────────────────────
|
|
12
|
+
const IDENTITY_REGISTRY_ABI = [
|
|
13
|
+
'function ownerOf(uint256 tokenId) view returns (address)',
|
|
14
|
+
'function tokenURI(uint256 tokenId) view returns (string)',
|
|
15
|
+
'function getAgentWallet(uint256 agentId) view returns (address)',
|
|
16
|
+
];
|
|
17
|
+
const REPUTATION_REGISTRY_ABI = [
|
|
18
|
+
'function getSummary(uint256 agentId, address[] clients, string tag1, string tag2) view returns (uint64 count, int128 summaryValue, uint8 valueDecimals)',
|
|
19
|
+
];
|
|
20
|
+
// ─── Internal Helpers ───────────────────────────────────────────────
|
|
21
|
+
const IPFS_GATEWAY = 'https://gateway.pinata.cloud/ipfs/';
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a URI to its JSON content.
|
|
24
|
+
* Supports ipfs://, data:application/json;base64, and http(s):// schemes.
|
|
25
|
+
*/
|
|
26
|
+
async function resolveURI(uri) {
|
|
27
|
+
if (uri.startsWith('ipfs://')) {
|
|
28
|
+
const cid = uri.slice('ipfs://'.length);
|
|
29
|
+
const response = await fetch(`${IPFS_GATEWAY}${cid}`);
|
|
30
|
+
if (!response.ok)
|
|
31
|
+
throw new Error(`IPFS fetch failed: ${response.status}`);
|
|
32
|
+
return response.json();
|
|
33
|
+
}
|
|
34
|
+
if (uri.startsWith('data:application/json;base64,')) {
|
|
35
|
+
const base64 = uri.slice('data:application/json;base64,'.length);
|
|
36
|
+
const json = Buffer.from(base64, 'base64').toString('utf-8');
|
|
37
|
+
return JSON.parse(json);
|
|
38
|
+
}
|
|
39
|
+
if (uri.startsWith('http://') || uri.startsWith('https://')) {
|
|
40
|
+
const response = await fetch(uri);
|
|
41
|
+
if (!response.ok)
|
|
42
|
+
throw new Error(`HTTP fetch failed: ${response.status}`);
|
|
43
|
+
return response.json();
|
|
44
|
+
}
|
|
45
|
+
throw new Error(`Unsupported URI scheme: ${uri}`);
|
|
46
|
+
}
|
|
47
|
+
// ─── Public API ─────────────────────────────────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* Read an agent from the Identity Registry and parse its profile.
|
|
50
|
+
*
|
|
51
|
+
* @param agentId The on-chain agent token ID
|
|
52
|
+
* @param options Registry address, provider, and optional fetchMetadata flag
|
|
53
|
+
*/
|
|
54
|
+
export async function getAgent(agentId, options) {
|
|
55
|
+
const { registryAddress, provider, fetchMetadata = true } = options;
|
|
56
|
+
const registry = new ethers.Contract(registryAddress, IDENTITY_REGISTRY_ABI, provider);
|
|
57
|
+
const [owner, uri, walletAddr] = await Promise.all([
|
|
58
|
+
registry.ownerOf(agentId),
|
|
59
|
+
registry.tokenURI(agentId),
|
|
60
|
+
registry.getAgentWallet(agentId),
|
|
61
|
+
]);
|
|
62
|
+
const agentWallet = walletAddr === ethers.ZeroAddress ? null : walletAddr;
|
|
63
|
+
let metadata = null;
|
|
64
|
+
if (fetchMetadata) {
|
|
65
|
+
try {
|
|
66
|
+
const raw = await resolveURI(uri);
|
|
67
|
+
metadata = raw;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
metadata = null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { agentId, owner, uri, agentWallet, metadata };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Read an agent's reputation summary from the Reputation Registry.
|
|
77
|
+
*
|
|
78
|
+
* @param agentId The on-chain agent token ID
|
|
79
|
+
* @param options Reputation registry address, provider, and optional filters
|
|
80
|
+
*/
|
|
81
|
+
export async function getReputation(agentId, options) {
|
|
82
|
+
const { reputationRegistryAddress, provider, clients = [], tag1 = '', tag2 = '', } = options;
|
|
83
|
+
const reputation = new ethers.Contract(reputationRegistryAddress, REPUTATION_REGISTRY_ABI, provider);
|
|
84
|
+
const [count, summaryValue, valueDecimals] = await reputation.getSummary(agentId, clients, tag1, tag2);
|
|
85
|
+
const decimals = Number(valueDecimals);
|
|
86
|
+
const rawValue = BigInt(summaryValue);
|
|
87
|
+
const score = Number(rawValue) / 10 ** decimals;
|
|
88
|
+
return { count: Number(count), score, rawValue, decimals };
|
|
89
|
+
}
|
package/dist/siwa.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* siwa.ts
|
|
3
|
+
*
|
|
4
|
+
* SIWA (Sign In With Agent) utility functions.
|
|
5
|
+
* Provides message building, signing (agent-side), and verification (server-side).
|
|
6
|
+
*
|
|
7
|
+
* Dependencies:
|
|
8
|
+
* npm install ethers
|
|
9
|
+
*/
|
|
10
|
+
import { ethers } from 'ethers';
|
|
11
|
+
import { AgentProfile, ServiceType, TrustModel } from './registry.js';
|
|
12
|
+
export interface SIWAMessageFields {
|
|
13
|
+
domain: string;
|
|
14
|
+
address: string;
|
|
15
|
+
statement?: string;
|
|
16
|
+
uri: string;
|
|
17
|
+
version?: string;
|
|
18
|
+
agentId: number;
|
|
19
|
+
agentRegistry: string;
|
|
20
|
+
chainId: number;
|
|
21
|
+
nonce: string;
|
|
22
|
+
issuedAt: string;
|
|
23
|
+
expirationTime?: string;
|
|
24
|
+
notBefore?: string;
|
|
25
|
+
requestId?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface SIWAVerificationResult {
|
|
28
|
+
valid: boolean;
|
|
29
|
+
address: string;
|
|
30
|
+
agentId: number;
|
|
31
|
+
agentRegistry: string;
|
|
32
|
+
chainId: number;
|
|
33
|
+
error?: string;
|
|
34
|
+
agent?: AgentProfile;
|
|
35
|
+
}
|
|
36
|
+
export interface SIWAVerifyCriteria {
|
|
37
|
+
minScore?: number;
|
|
38
|
+
minFeedbackCount?: number;
|
|
39
|
+
reputationRegistryAddress?: string;
|
|
40
|
+
requiredServices?: (ServiceType | (string & {}))[];
|
|
41
|
+
mustBeActive?: boolean;
|
|
42
|
+
requiredTrust?: (TrustModel | (string & {}))[];
|
|
43
|
+
custom?: (agent: AgentProfile) => boolean | Promise<boolean>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build a SIWA plaintext message string from structured fields.
|
|
47
|
+
*/
|
|
48
|
+
export declare function buildSIWAMessage(fields: SIWAMessageFields): string;
|
|
49
|
+
/**
|
|
50
|
+
* Parse a SIWA message string back into structured fields.
|
|
51
|
+
*/
|
|
52
|
+
export declare function parseSIWAMessage(message: string): SIWAMessageFields;
|
|
53
|
+
/**
|
|
54
|
+
* Generate a cryptographically secure nonce (≥ 8 alphanumeric characters).
|
|
55
|
+
*/
|
|
56
|
+
export declare function generateNonce(length?: number): string;
|
|
57
|
+
/**
|
|
58
|
+
* Sign a SIWA message using the secure keystore.
|
|
59
|
+
*
|
|
60
|
+
* The private key is loaded from the keystore, used to sign, and discarded.
|
|
61
|
+
* It is NEVER returned or exposed to the caller.
|
|
62
|
+
*
|
|
63
|
+
* @param fields — SIWA message fields (domain, agentId, etc.)
|
|
64
|
+
* @param keystoreConfig — Optional keystore configuration override
|
|
65
|
+
* @returns { message, signature } — only the plaintext message and EIP-191 signature
|
|
66
|
+
*/
|
|
67
|
+
export declare function signSIWAMessage(fields: SIWAMessageFields, keystoreConfig?: import('./keystore').KeystoreConfig): Promise<{
|
|
68
|
+
message: string;
|
|
69
|
+
signature: string;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* Sign a SIWA message using a raw private key.
|
|
73
|
+
* ⚠️ DEPRECATED: Use signSIWAMessage() with keystore instead.
|
|
74
|
+
* Kept only for server-side testing or environments without keystore.
|
|
75
|
+
*/
|
|
76
|
+
export declare function signSIWAMessageUnsafe(privateKey: string, fields: SIWAMessageFields): Promise<{
|
|
77
|
+
message: string;
|
|
78
|
+
signature: string;
|
|
79
|
+
}>;
|
|
80
|
+
/**
|
|
81
|
+
* Verify a SIWA message + signature.
|
|
82
|
+
*
|
|
83
|
+
* Checks:
|
|
84
|
+
* 1. Message format validity
|
|
85
|
+
* 2. Signature → address recovery
|
|
86
|
+
* 3. Address matches message
|
|
87
|
+
* 4. Domain matches expected domain
|
|
88
|
+
* 5. Nonce matches (caller must validate against their nonce store)
|
|
89
|
+
* 6. Time window (expirationTime / notBefore)
|
|
90
|
+
* 7. Onchain: ownerOf(agentId) === recovered address
|
|
91
|
+
*
|
|
92
|
+
* @param message Full SIWA message string
|
|
93
|
+
* @param signature EIP-191 signature hex string
|
|
94
|
+
* @param expectedDomain The server's domain (for domain binding)
|
|
95
|
+
* @param nonceValid Callback that returns true if the nonce is valid and unconsumed
|
|
96
|
+
* @param provider ethers Provider for onchain verification
|
|
97
|
+
* @param criteria Optional criteria to validate agent profile/reputation after ownership check
|
|
98
|
+
*/
|
|
99
|
+
export declare function verifySIWA(message: string, signature: string, expectedDomain: string, nonceValid: (nonce: string) => boolean | Promise<boolean>, provider: ethers.Provider, criteria?: SIWAVerifyCriteria): Promise<SIWAVerificationResult>;
|