@agirails/sdk 2.0.3 → 2.2.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 +536 -87
- package/dist/adapters/BaseAdapter.js +2 -2
- package/dist/adapters/BaseAdapter.js.map +1 -1
- package/dist/adapters/BasicAdapter.d.ts.map +1 -1
- package/dist/adapters/BasicAdapter.js +8 -0
- package/dist/adapters/BasicAdapter.js.map +1 -1
- package/dist/adapters/StandardAdapter.d.ts +10 -5
- package/dist/adapters/StandardAdapter.d.ts.map +1 -1
- package/dist/adapters/StandardAdapter.js +19 -6
- package/dist/adapters/StandardAdapter.js.map +1 -1
- package/dist/builders/QuoteBuilder.js +1 -1
- package/dist/builders/QuoteBuilder.js.map +1 -1
- package/dist/cli/commands/config.js +1 -1
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/simulate.js.map +1 -1
- package/dist/cli/commands/time.d.ts.map +1 -1
- package/dist/cli/commands/time.js.map +1 -1
- package/dist/config/networks.d.ts +9 -0
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +25 -10
- package/dist/config/networks.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -1
- package/dist/index.js.map +1 -1
- package/dist/level0/provide.d.ts.map +1 -1
- package/dist/level0/provide.js +2 -1
- package/dist/level0/provide.js.map +1 -1
- package/dist/level0/request.d.ts.map +1 -1
- package/dist/level0/request.js +1 -2
- package/dist/level0/request.js.map +1 -1
- package/dist/level1/Agent.d.ts.map +1 -1
- package/dist/level1/Agent.js +11 -3
- package/dist/level1/Agent.js.map +1 -1
- package/dist/level1/pricing/PriceCalculator.js +1 -1
- package/dist/level1/pricing/PriceCalculator.js.map +1 -1
- package/dist/level1/types/Options.d.ts.map +1 -1
- package/dist/protocol/ACTPKernel.d.ts.map +1 -1
- package/dist/protocol/ACTPKernel.js +7 -5
- package/dist/protocol/ACTPKernel.js.map +1 -1
- package/dist/protocol/DIDResolver.js +1 -1
- package/dist/protocol/DIDResolver.js.map +1 -1
- package/dist/protocol/EASHelper.d.ts.map +1 -1
- package/dist/protocol/EASHelper.js +2 -3
- package/dist/protocol/EASHelper.js.map +1 -1
- package/dist/protocol/MessageSigner.d.ts.map +1 -1
- package/dist/protocol/MessageSigner.js +9 -9
- package/dist/protocol/MessageSigner.js.map +1 -1
- package/dist/protocol/ProofGenerator.d.ts.map +1 -1
- package/dist/protocol/ProofGenerator.js +1 -0
- package/dist/protocol/ProofGenerator.js.map +1 -1
- package/dist/runtime/BlockchainRuntime.d.ts +10 -3
- package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
- package/dist/runtime/BlockchainRuntime.js +41 -25
- package/dist/runtime/BlockchainRuntime.js.map +1 -1
- package/dist/runtime/IACTPRuntime.d.ts +15 -0
- package/dist/runtime/IACTPRuntime.d.ts.map +1 -1
- package/dist/runtime/MockRuntime.d.ts +7 -0
- package/dist/runtime/MockRuntime.d.ts.map +1 -1
- package/dist/runtime/MockRuntime.js +15 -4
- package/dist/runtime/MockRuntime.js.map +1 -1
- package/dist/runtime/types/MockState.d.ts +5 -2
- package/dist/runtime/types/MockState.d.ts.map +1 -1
- package/dist/runtime/types/MockState.js.map +1 -1
- package/dist/storage/ArchiveBundleBuilder.d.ts +150 -0
- package/dist/storage/ArchiveBundleBuilder.d.ts.map +1 -0
- package/dist/storage/ArchiveBundleBuilder.js +468 -0
- package/dist/storage/ArchiveBundleBuilder.js.map +1 -0
- package/dist/storage/ArweaveClient.d.ts +271 -0
- package/dist/storage/ArweaveClient.d.ts.map +1 -0
- package/dist/storage/ArweaveClient.js +761 -0
- package/dist/storage/ArweaveClient.js.map +1 -0
- package/dist/storage/FilebaseClient.d.ts +193 -0
- package/dist/storage/FilebaseClient.d.ts.map +1 -0
- package/dist/storage/FilebaseClient.js +643 -0
- package/dist/storage/FilebaseClient.js.map +1 -0
- package/dist/storage/index.d.ts +47 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +64 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/types.d.ts +291 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +18 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/types/state.d.ts +5 -4
- package/dist/types/state.d.ts.map +1 -1
- package/dist/types/state.js +10 -9
- package/dist/types/state.js.map +1 -1
- package/dist/utils/ErrorRecoveryGuide.d.ts.map +1 -1
- package/dist/utils/ErrorRecoveryGuide.js +1 -2
- package/dist/utils/ErrorRecoveryGuide.js.map +1 -1
- package/dist/utils/IPFSClient.d.ts.map +1 -1
- package/dist/utils/IPFSClient.js +5 -2
- package/dist/utils/IPFSClient.js.map +1 -1
- package/dist/utils/NonceManager.d.ts.map +1 -1
- package/dist/utils/NonceManager.js +3 -2
- package/dist/utils/NonceManager.js.map +1 -1
- package/dist/utils/UsedAttestationTracker.d.ts +1 -1
- package/dist/utils/UsedAttestationTracker.d.ts.map +1 -1
- package/dist/utils/UsedAttestationTracker.js +4 -4
- package/dist/utils/UsedAttestationTracker.js.map +1 -1
- package/dist/utils/circuitBreaker.d.ts +136 -0
- package/dist/utils/circuitBreaker.d.ts.map +1 -0
- package/dist/utils/circuitBreaker.js +253 -0
- package/dist/utils/circuitBreaker.js.map +1 -0
- package/dist/utils/retry.d.ts +120 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +260 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/validation.d.ts +100 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +248 -1
- package/dist/utils/validation.js.map +1 -1
- package/package.json +14 -2
- package/src/adapters/BaseAdapter.ts +2 -2
- package/src/adapters/BasicAdapter.ts +12 -2
- package/src/adapters/StandardAdapter.ts +27 -7
- package/src/builders/QuoteBuilder.ts +1 -1
- package/src/cli/commands/config.ts +1 -1
- package/src/cli/commands/simulate.ts +1 -1
- package/src/cli/commands/time.ts +1 -2
- package/src/config/networks.ts +34 -10
- package/src/index.ts +54 -0
- package/src/level0/provide.ts +2 -1
- package/src/level0/request.ts +1 -2
- package/src/level1/Agent.ts +15 -5
- package/src/level1/pricing/PriceCalculator.ts +1 -1
- package/src/level1/types/Options.ts +1 -1
- package/src/protocol/ACTPKernel.ts +7 -5
- package/src/protocol/DIDResolver.ts +1 -1
- package/src/protocol/EASHelper.ts +2 -5
- package/src/protocol/MessageSigner.ts +9 -15
- package/src/protocol/ProofGenerator.ts +1 -0
- package/src/runtime/BlockchainRuntime.ts +42 -48
- package/src/runtime/IACTPRuntime.ts +16 -0
- package/src/runtime/MockRuntime.ts +16 -6
- package/src/runtime/types/MockState.ts +5 -2
- package/src/storage/ArchiveBundleBuilder.ts +563 -0
- package/src/storage/ArweaveClient.ts +945 -0
- package/src/storage/FilebaseClient.ts +790 -0
- package/src/storage/index.ts +96 -0
- package/src/storage/types.ts +348 -0
- package/src/types/state.ts +10 -9
- package/src/utils/ErrorRecoveryGuide.ts +1 -2
- package/src/utils/IPFSClient.ts +5 -4
- package/src/utils/NonceManager.ts +3 -2
- package/src/utils/UsedAttestationTracker.ts +4 -6
- package/src/utils/circuitBreaker.ts +324 -0
- package/src/utils/fsSafe.ts +5 -0
- package/src/utils/retry.ts +365 -0
- package/src/utils/validation.ts +295 -1
package/src/level0/provide.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { JobHandler } from '../level1/types/Job';
|
|
|
12
12
|
import { ProvideOptions } from '../level1/types/Options';
|
|
13
13
|
import { Provider } from './Provider';
|
|
14
14
|
import { serviceDirectory } from './ServiceDirectory';
|
|
15
|
+
import { sdkLogger } from '../utils/Logger';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Provide a service
|
|
@@ -83,7 +84,7 @@ export function provide(
|
|
|
83
84
|
// Register in service directory after agent has started and has an address
|
|
84
85
|
serviceDirectory.register(service, agent.address);
|
|
85
86
|
}).catch((error) => {
|
|
86
|
-
|
|
87
|
+
sdkLogger.error(`Failed to start provider for ${service}`, { error: error instanceof Error ? error.message : String(error) });
|
|
87
88
|
});
|
|
88
89
|
|
|
89
90
|
// Return Provider interface (adapter over Agent)
|
package/src/level0/request.ts
CHANGED
|
@@ -164,7 +164,6 @@ export async function request(
|
|
|
164
164
|
|
|
165
165
|
let tx = await client.runtime.getTransaction(txId);
|
|
166
166
|
let attempts = 0;
|
|
167
|
-
let timedOut = false;
|
|
168
167
|
|
|
169
168
|
while (tx && tx.state !== 'DELIVERED' && tx.state !== 'SETTLED' && attempts < maxAttempts) {
|
|
170
169
|
// Check for terminal states that indicate failure
|
|
@@ -190,7 +189,7 @@ export async function request(
|
|
|
190
189
|
|
|
191
190
|
// Check if we got a result
|
|
192
191
|
if (!tx || (tx.state !== 'DELIVERED' && tx.state !== 'SETTLED')) {
|
|
193
|
-
|
|
192
|
+
const _timedOut = true; // Flag for potential future use
|
|
194
193
|
|
|
195
194
|
// SECURITY FIX (H-3): Auto-cancel transaction on timeout if still in early state
|
|
196
195
|
// This prevents funds from being locked indefinitely if provider never responds
|
package/src/level1/Agent.ts
CHANGED
|
@@ -14,10 +14,10 @@ import * as fs from 'fs';
|
|
|
14
14
|
import { ethers } from 'ethers';
|
|
15
15
|
import { ACTPClient } from '../ACTPClient';
|
|
16
16
|
import { Job, JobHandler, JobContext } from './types/Job';
|
|
17
|
-
import {
|
|
17
|
+
import { RequestOptions, RequestResult, NetworkOption } from './types/Options';
|
|
18
18
|
import { PricingStrategy } from './pricing/PricingStrategy';
|
|
19
19
|
import { AgentLifecycleError, ServiceConfigError, ValidationError } from '../errors';
|
|
20
|
-
import { validateServiceName, validatePath,
|
|
20
|
+
import { validateServiceName, validatePath, LRUCache } from '../utils/security';
|
|
21
21
|
import { Logger } from '../utils/Logger';
|
|
22
22
|
import { ServiceHash } from '../utils/Helpers';
|
|
23
23
|
import { Semaphore } from '../utils/Semaphore';
|
|
@@ -1232,7 +1232,7 @@ export class Agent extends EventEmitter {
|
|
|
1232
1232
|
result, // Include original result for convenience
|
|
1233
1233
|
});
|
|
1234
1234
|
|
|
1235
|
-
// Transition transaction
|
|
1235
|
+
// Transition transaction through IN_PROGRESS → DELIVERED states
|
|
1236
1236
|
if (this._client) {
|
|
1237
1237
|
// Store delivery proof by directly accessing MockRuntime's state
|
|
1238
1238
|
// This is a workaround - in production, we'd use a proper method
|
|
@@ -1246,8 +1246,18 @@ export class Agent extends EventEmitter {
|
|
|
1246
1246
|
});
|
|
1247
1247
|
}
|
|
1248
1248
|
|
|
1249
|
-
//
|
|
1250
|
-
|
|
1249
|
+
// AUDIT FIX (2026-02): Must transition through IN_PROGRESS before DELIVERED
|
|
1250
|
+
// Contract rejects COMMITTED → DELIVERED direct transition
|
|
1251
|
+
await this._client.runtime.transitionState(job.id, 'IN_PROGRESS');
|
|
1252
|
+
|
|
1253
|
+
// Encode dispute window proof for DELIVERED transition
|
|
1254
|
+
// Use transaction's disputeWindow from metadata, fallback to 2 days (172800s) per Options.ts default
|
|
1255
|
+
const disputeWindowSeconds = job.metadata?.disputeWindow || 172800;
|
|
1256
|
+
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
|
1257
|
+
const disputeWindowProof = abiCoder.encode(['uint256'], [disputeWindowSeconds]);
|
|
1258
|
+
|
|
1259
|
+
// Transition to DELIVERED with dispute window proof
|
|
1260
|
+
await this._client.runtime.transitionState(job.id, 'DELIVERED', disputeWindowProof);
|
|
1251
1261
|
}
|
|
1252
1262
|
|
|
1253
1263
|
// SECURITY FIX (C-2): Remove from active jobs on SUCCESS
|
|
@@ -214,7 +214,7 @@ function estimateUnits(job: Job, unit: string): number {
|
|
|
214
214
|
*
|
|
215
215
|
* @internal
|
|
216
216
|
*/
|
|
217
|
-
function estimateApiCost(
|
|
217
|
+
function estimateApiCost(_api: string, _job: Job): number {
|
|
218
218
|
// MVP: Returns 0 (API costs tracked externally by agent)
|
|
219
219
|
// V2: Integrate with OpenAI/Anthropic pricing APIs
|
|
220
220
|
|
|
@@ -681,16 +681,18 @@ export class ACTPKernel {
|
|
|
681
681
|
validateAddress(mediator, 'mediator');
|
|
682
682
|
}
|
|
683
683
|
|
|
684
|
-
// Encode resolution proof (128 bytes:
|
|
685
|
-
//
|
|
684
|
+
// Encode resolution proof (128 bytes: 2x uint256 + address + uint256)
|
|
685
|
+
// AUDIT FIX (2026-02): Contract expects: (uint256, uint256, address, uint256)
|
|
686
|
+
// = [requesterAmount, providerAmount, mediator, mediatorAmount]
|
|
687
|
+
// See ACTPKernel.sol _decodeResolutionProof() line 654-655
|
|
686
688
|
const abiCoder = AbiCoder.defaultAbiCoder();
|
|
687
689
|
const proofData = abiCoder.encode(
|
|
688
|
-
['uint256', 'uint256', '
|
|
690
|
+
['uint256', 'uint256', 'address', 'uint256'],
|
|
689
691
|
[
|
|
690
692
|
requesterAmount,
|
|
691
693
|
providerAmount,
|
|
692
|
-
|
|
693
|
-
|
|
694
|
+
mediator || ethers.getAddress('0x0000000000000000000000000000000000000000'),
|
|
695
|
+
mediatorAmount
|
|
694
696
|
]
|
|
695
697
|
);
|
|
696
698
|
|
|
@@ -115,7 +115,7 @@ export class DIDResolver {
|
|
|
115
115
|
network: config.network,
|
|
116
116
|
chainId: config.chainId || networkConfig.chainId,
|
|
117
117
|
rpcUrl: config.rpcUrl || networkConfig.rpcUrl,
|
|
118
|
-
registryAddress: config.registryAddress || networkConfig.contracts.
|
|
118
|
+
registryAddress: config.registryAddress || networkConfig.contracts.identityRegistry || ''
|
|
119
119
|
};
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
IUsedAttestationTracker,
|
|
7
7
|
InMemoryUsedAttestationTracker
|
|
8
8
|
} from '../utils/UsedAttestationTracker';
|
|
9
|
+
import { sdkLogger } from '../utils/Logger';
|
|
9
10
|
|
|
10
11
|
export interface EASConfig {
|
|
11
12
|
contractAddress: string;
|
|
@@ -65,11 +66,7 @@ export class EASHelper {
|
|
|
65
66
|
//
|
|
66
67
|
// Without persistence, attestation replay protection is lost on process restart,
|
|
67
68
|
// allowing potential double-spend attacks.
|
|
68
|
-
|
|
69
|
-
'[SECURITY WARNING] EASHelper: Using in-memory attestation tracker. ' +
|
|
70
|
-
'Replay protection will be lost on process restart. ' +
|
|
71
|
-
'For production, provide FileBasedUsedAttestationTracker for persistence.'
|
|
72
|
-
);
|
|
69
|
+
sdkLogger.warn('Using in-memory attestation tracker - replay protection lost on restart (use FileBasedUsedAttestationTracker for production)');
|
|
73
70
|
}
|
|
74
71
|
this.attestationTracker = attestationTracker || new InMemoryUsedAttestationTracker();
|
|
75
72
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
deliveryProofDataFromProof
|
|
11
11
|
} from '../types/eip712';
|
|
12
12
|
import { IReceivedNonceTracker } from '../utils/ReceivedNonceTracker';
|
|
13
|
+
import { sdkLogger } from '../utils/Logger';
|
|
13
14
|
|
|
14
15
|
// Legacy generic ACTP message types moved to types/eip712.ts
|
|
15
16
|
|
|
@@ -157,7 +158,7 @@ export class MessageSigner {
|
|
|
157
158
|
);
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
const { type, version, from, to, timestamp, nonce, signature, ...payload } = message;
|
|
161
|
+
const { type, version, from, to, timestamp, nonce, signature: _sig, ...payload } = message;
|
|
161
162
|
|
|
162
163
|
// SECURITY FIX (H-3): Validate nonce format (must be bytes32)
|
|
163
164
|
if (!nonce || !/^0x[a-fA-F0-9]{64}$/.test(nonce)) {
|
|
@@ -175,22 +176,14 @@ export class MessageSigner {
|
|
|
175
176
|
const nonceValue = BigInt(nonce);
|
|
176
177
|
if (nonceValue < 0xFFFFFFFFn) {
|
|
177
178
|
// Nonce is suspiciously small (< 4 billion = likely sequential)
|
|
178
|
-
|
|
179
|
-
`[SECURITY WARNING] Nonce ${nonce} appears to be sequential (value < 2^32). ` +
|
|
180
|
-
`This makes replay attacks easier. ` +
|
|
181
|
-
`Use SecureNonce.generateSecureNonce() for cryptographically secure random nonces.`
|
|
182
|
-
);
|
|
179
|
+
sdkLogger.warn('Nonce appears sequential - use SecureNonce.generateSecureNonce()', { nonce });
|
|
183
180
|
}
|
|
184
181
|
|
|
185
182
|
// Check if nonce has all same digits (e.g., 0x111...111 or 0x000...000)
|
|
186
183
|
const hexDigits = nonce.slice(2); // Remove '0x'
|
|
187
184
|
const firstDigit = hexDigits[0];
|
|
188
185
|
if (hexDigits.split('').every(d => d === firstDigit)) {
|
|
189
|
-
|
|
190
|
-
`[SECURITY WARNING] Nonce ${nonce} has low entropy (all digits are '${firstDigit}'). ` +
|
|
191
|
-
`This is NOT cryptographically secure. ` +
|
|
192
|
-
`Use SecureNonce.generateSecureNonce() instead.`
|
|
193
|
-
);
|
|
186
|
+
sdkLogger.warn('Nonce has low entropy - use SecureNonce.generateSecureNonce()', { nonce, repeatedDigit: firstDigit });
|
|
194
187
|
}
|
|
195
188
|
|
|
196
189
|
// Generic ACTPMessage with payload encoding (backward compatible)
|
|
@@ -463,10 +456,11 @@ export class MessageSigner {
|
|
|
463
456
|
// This prevents cross-chain replay attacks where a message signed for one chain
|
|
464
457
|
// is replayed on another. For now, we just extract the address but log a warning.
|
|
465
458
|
if (this.domain && this.domain.chainId !== chainId) {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
459
|
+
sdkLogger.warn('DID chainId mismatch - potential cross-chain replay attempt', {
|
|
460
|
+
didChainId: chainId,
|
|
461
|
+
domainChainId: this.domain.chainId,
|
|
462
|
+
did,
|
|
463
|
+
});
|
|
470
464
|
}
|
|
471
465
|
|
|
472
466
|
return address;
|
|
@@ -28,6 +28,7 @@ import { ValidationError } from '../errors';
|
|
|
28
28
|
import { ServiceHash, DisputeWindow } from '../utils/Helpers';
|
|
29
29
|
import { IUsedAttestationTracker, createUsedAttestationTracker } from '../utils/UsedAttestationTracker';
|
|
30
30
|
import { IReceivedNonceTracker, createReceivedNonceTracker } from '../utils/ReceivedNonceTracker';
|
|
31
|
+
import { sdkLogger } from '../utils/Logger';
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* Configuration for BlockchainRuntime
|
|
@@ -217,20 +218,17 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
217
218
|
);
|
|
218
219
|
}
|
|
219
220
|
|
|
220
|
-
|
|
221
|
-
`BlockchainRuntime: Connected to ${this.networkConfig.name} (chainId: ${connectedChainId})`
|
|
222
|
-
);
|
|
221
|
+
sdkLogger.info(`Connected to ${this.networkConfig.name}`, { chainId: connectedChainId });
|
|
223
222
|
} catch (error) {
|
|
224
223
|
if (error instanceof Error && error.message.includes('Network mismatch')) {
|
|
225
224
|
throw error; // Re-throw our validation error
|
|
226
225
|
}
|
|
227
226
|
// For other errors (e.g., network issues), log warning but continue
|
|
228
227
|
// This allows initialization to proceed even if network check fails temporarily
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
);
|
|
228
|
+
sdkLogger.warn('Could not verify network chainId, proceeding with expected value', {
|
|
229
|
+
error: error instanceof Error ? error.message : String(error),
|
|
230
|
+
expectedChainId: this.networkConfig.chainId,
|
|
231
|
+
});
|
|
234
232
|
}
|
|
235
233
|
|
|
236
234
|
// SECURITY FIX (H-4): Use factory pattern to guarantee domain initialization
|
|
@@ -254,10 +252,7 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
254
252
|
this.attestationTracker
|
|
255
253
|
);
|
|
256
254
|
} else if (this.requireAttestation) {
|
|
257
|
-
|
|
258
|
-
'[SECURITY WARNING] BlockchainRuntime: requireAttestation is true but no EAS config provided. ' +
|
|
259
|
-
'Attestation verification will fail. Please provide easConfig in BlockchainRuntimeConfig.'
|
|
260
|
-
);
|
|
255
|
+
sdkLogger.warn('requireAttestation is true but no EAS config provided - attestation verification will fail');
|
|
261
256
|
}
|
|
262
257
|
}
|
|
263
258
|
|
|
@@ -319,11 +314,12 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
319
314
|
this.reconnectAttempts = attempt + 1;
|
|
320
315
|
const delay = this.baseReconnectDelay * Math.pow(2, attempt);
|
|
321
316
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
317
|
+
sdkLogger.warn('Provider connection lost, attempting reconnection', {
|
|
318
|
+
attempt: attempt + 1,
|
|
319
|
+
maxAttempts: this.maxReconnectAttempts,
|
|
320
|
+
delayMs: delay,
|
|
321
|
+
error: error instanceof Error ? error.message : String(error),
|
|
322
|
+
});
|
|
327
323
|
|
|
328
324
|
// Wait before next attempt
|
|
329
325
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
@@ -543,7 +539,11 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
543
539
|
escrowId: tx.escrowId,
|
|
544
540
|
createdAt: Number(tx.createdAt),
|
|
545
541
|
updatedAt: Number(tx.updatedAt),
|
|
546
|
-
|
|
542
|
+
// LIMITATION (V2): completedAt requires event indexing to fetch DELIVERED event timestamp.
|
|
543
|
+
// Currently 0, which means SDK-side dispute window check in releaseEscrow() is bypassed.
|
|
544
|
+
// On-chain contract still enforces dispute window correctly via _validateSettlementConditions().
|
|
545
|
+
// V2 will implement EventMonitor to track this properly.
|
|
546
|
+
completedAt: 0,
|
|
547
547
|
serviceDescription: '', // V2: Decode from on-chain serviceHash
|
|
548
548
|
deliveryProof: '', // V2: Fetch from EAS attestation
|
|
549
549
|
events: [], // V2: Populate via EventMonitor.getTransactionEvents()
|
|
@@ -562,9 +562,7 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
562
562
|
async getAllTransactions(): Promise<MockTransaction[]> {
|
|
563
563
|
// V2: Implement event-based transaction indexing via EventMonitor
|
|
564
564
|
// For now, return empty array as this requires off-chain indexer
|
|
565
|
-
|
|
566
|
-
'getAllTransactions() not fully implemented for BlockchainRuntime. Use EventMonitor for event-based queries.'
|
|
567
|
-
);
|
|
565
|
+
sdkLogger.warn('getAllTransactions() not implemented - use EventMonitor for event-based queries');
|
|
568
566
|
return [];
|
|
569
567
|
}
|
|
570
568
|
|
|
@@ -604,10 +602,7 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
604
602
|
if (legacyMatch) {
|
|
605
603
|
// Legacy SDK format - extract txId
|
|
606
604
|
txId = legacyMatch[1];
|
|
607
|
-
|
|
608
|
-
`BlockchainRuntime.releaseEscrow: Using legacy escrowId format. ` +
|
|
609
|
-
`Please update to use txId directly as escrowId.`
|
|
610
|
-
);
|
|
605
|
+
sdkLogger.warn('Using legacy escrowId format - please update to use txId directly as escrowId');
|
|
611
606
|
} else {
|
|
612
607
|
// Standard: escrowId = txId
|
|
613
608
|
txId = escrowId;
|
|
@@ -658,9 +653,7 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
658
653
|
// Verify attestation is valid for this transaction
|
|
659
654
|
try {
|
|
660
655
|
await this.easHelper.verifyAndRecordForRelease(txId, attestationUID);
|
|
661
|
-
|
|
662
|
-
`BlockchainRuntime.releaseEscrow: Attestation ${attestationUID} verified for transaction ${txId}.`
|
|
663
|
-
);
|
|
656
|
+
sdkLogger.info('Attestation verified for release', { txId, attestationUID });
|
|
664
657
|
} catch (error) {
|
|
665
658
|
throw new Error(
|
|
666
659
|
`Cannot release escrow: attestation verification failed for transaction ${txId}. ` +
|
|
@@ -671,21 +664,16 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
671
664
|
// Even if not required, verify attestation if provided (best effort)
|
|
672
665
|
try {
|
|
673
666
|
await this.easHelper.verifyAndRecordForRelease(txId, attestationUID);
|
|
674
|
-
|
|
675
|
-
`BlockchainRuntime.releaseEscrow: Attestation ${attestationUID} verified (optional) for transaction ${txId}.`
|
|
676
|
-
);
|
|
667
|
+
sdkLogger.info('Attestation verified (optional)', { txId, attestationUID });
|
|
677
668
|
} catch (error) {
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
);
|
|
669
|
+
sdkLogger.warn('Attestation verification failed but not required, proceeding', {
|
|
670
|
+
txId,
|
|
671
|
+
error: error instanceof Error ? error.message : String(error),
|
|
672
|
+
});
|
|
682
673
|
}
|
|
683
674
|
} else {
|
|
684
675
|
// No attestation verification
|
|
685
|
-
|
|
686
|
-
`BlockchainRuntime.releaseEscrow: Settling transaction ${txId}. ` +
|
|
687
|
-
`Note: Set requireAttestation=true and provide easConfig for additional security.`
|
|
688
|
-
);
|
|
676
|
+
sdkLogger.info('Settling transaction without attestation verification', { txId });
|
|
689
677
|
}
|
|
690
678
|
|
|
691
679
|
// SECURITY FIX (SETTLEMENT-FLOW): Use transitionState(SETTLED) instead of releaseEscrow()
|
|
@@ -731,7 +719,7 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
731
719
|
return '0';
|
|
732
720
|
} catch (error) {
|
|
733
721
|
// If query fails, return 0
|
|
734
|
-
|
|
722
|
+
sdkLogger.warn('getEscrowBalance query failed', { error: error instanceof Error ? error.message : String(error) });
|
|
735
723
|
return '0';
|
|
736
724
|
}
|
|
737
725
|
}
|
|
@@ -773,6 +761,16 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
773
761
|
return this.networkConfig;
|
|
774
762
|
}
|
|
775
763
|
|
|
764
|
+
/**
|
|
765
|
+
* Maximum transaction amount in USDC (human-readable).
|
|
766
|
+
*
|
|
767
|
+
* SECURITY: Limits exposure on unaudited mainnet contracts.
|
|
768
|
+
* Returns undefined if no limit (testnet).
|
|
769
|
+
*/
|
|
770
|
+
get maxTransactionAmount(): number | undefined {
|
|
771
|
+
return this.networkConfig.maxTransactionAmount;
|
|
772
|
+
}
|
|
773
|
+
|
|
776
774
|
/**
|
|
777
775
|
* Get ACTPKernel instance (for advanced usage)
|
|
778
776
|
*/
|
|
@@ -869,11 +867,7 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
869
867
|
|
|
870
868
|
// SECURITY FIX (CRITICAL): If it's a raw string (legacy format), hash it
|
|
871
869
|
// This ensures on-chain compatibility with the contract's bytes32 expectation
|
|
872
|
-
|
|
873
|
-
'BlockchainRuntime: serviceDescription is not a valid bytes32 hash. ' +
|
|
874
|
-
'Hashing it now. For best practice, use ServiceHash.hash() before calling createTransaction.'
|
|
875
|
-
);
|
|
876
|
-
|
|
870
|
+
sdkLogger.warn('serviceDescription is not a valid bytes32 hash - hashing now (use ServiceHash.hash() for best practice)');
|
|
877
871
|
return keccak256(toUtf8Bytes(serviceDescription));
|
|
878
872
|
}
|
|
879
873
|
|
|
@@ -892,7 +886,7 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
892
886
|
* @param params - Transaction parameters
|
|
893
887
|
* @returns Estimated gas limit and cost in wei
|
|
894
888
|
*/
|
|
895
|
-
async estimateCreateTransactionGas(
|
|
889
|
+
async estimateCreateTransactionGas(_params: CreateTransactionParams): Promise<{
|
|
896
890
|
gasLimit: bigint;
|
|
897
891
|
gasCostWei: bigint;
|
|
898
892
|
gasCostGwei: string;
|
|
@@ -921,7 +915,7 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
921
915
|
* @param txId - Transaction ID
|
|
922
916
|
* @returns Estimated gas limit and cost
|
|
923
917
|
*/
|
|
924
|
-
async estimateLinkEscrowGas(
|
|
918
|
+
async estimateLinkEscrowGas(_txId: string): Promise<{
|
|
925
919
|
gasLimit: bigint;
|
|
926
920
|
gasCostWei: bigint;
|
|
927
921
|
gasCostGwei: string;
|
|
@@ -949,7 +943,7 @@ export class BlockchainRuntime implements IACTPRuntime {
|
|
|
949
943
|
* @param newState - Target state
|
|
950
944
|
* @returns Estimated gas limit and cost
|
|
951
945
|
*/
|
|
952
|
-
async estimateTransitionGas(
|
|
946
|
+
async estimateTransitionGas(_txId: string, _newState: string): Promise<{
|
|
953
947
|
gasLimit: bigint;
|
|
954
948
|
gasCostWei: bigint;
|
|
955
949
|
gasCostGwei: string;
|
|
@@ -199,6 +199,22 @@ export interface IACTPRuntime {
|
|
|
199
199
|
/** Get current timestamp in seconds */
|
|
200
200
|
now(): number;
|
|
201
201
|
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Maximum transaction amount in USDC (human-readable, e.g., 100 = $100).
|
|
205
|
+
*
|
|
206
|
+
* SECURITY: Limits exposure on unaudited contracts.
|
|
207
|
+
* Returns undefined if no limit is enforced (testnet/mock mode).
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* const limit = runtime.maxTransactionAmount;
|
|
212
|
+
* if (limit && amount > limit) {
|
|
213
|
+
* throw new Error(`Amount exceeds limit of $${limit}`);
|
|
214
|
+
* }
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
maxTransactionAmount?: number;
|
|
202
218
|
}
|
|
203
219
|
|
|
204
220
|
/**
|
|
@@ -25,8 +25,6 @@ import {
|
|
|
25
25
|
MockEscrow,
|
|
26
26
|
MockEvent,
|
|
27
27
|
TransactionState,
|
|
28
|
-
TransactionStateValue,
|
|
29
|
-
MOCK_STATE_DEFAULTS,
|
|
30
28
|
} from './types/MockState';
|
|
31
29
|
import { IACTPRuntime, CreateTransactionParams } from './IACTPRuntime';
|
|
32
30
|
|
|
@@ -201,23 +199,27 @@ export class DisputeWindowActiveError extends Error {
|
|
|
201
199
|
/**
|
|
202
200
|
* Valid state transitions for the ACTP 8-state machine.
|
|
203
201
|
*
|
|
202
|
+
* AUDIT FIX (2026-02): Synced with on-chain ACTPKernel contract.
|
|
203
|
+
*
|
|
204
204
|
* State machine:
|
|
205
205
|
* - INITIATED -> QUOTED (optional), COMMITTED, CANCELLED
|
|
206
206
|
* - QUOTED -> COMMITTED, CANCELLED
|
|
207
|
-
* - COMMITTED -> IN_PROGRESS (
|
|
207
|
+
* - COMMITTED -> IN_PROGRESS, CANCELLED (cannot skip to DELIVERED)
|
|
208
208
|
* - IN_PROGRESS -> DELIVERED, CANCELLED
|
|
209
209
|
* - DELIVERED -> SETTLED, DISPUTED
|
|
210
|
-
* - DISPUTED -> SETTLED
|
|
210
|
+
* - DISPUTED -> SETTLED, CANCELLED (admin/pauser emergency)
|
|
211
211
|
* - SETTLED (terminal)
|
|
212
212
|
* - CANCELLED (terminal)
|
|
213
213
|
*/
|
|
214
214
|
const VALID_TRANSITIONS: Record<TransactionState, TransactionState[]> = {
|
|
215
215
|
INITIATED: ['QUOTED', 'COMMITTED', 'CANCELLED'],
|
|
216
216
|
QUOTED: ['COMMITTED', 'CANCELLED'],
|
|
217
|
-
|
|
217
|
+
// AUDIT FIX: Cannot skip IN_PROGRESS - must transition through it
|
|
218
|
+
COMMITTED: ['IN_PROGRESS', 'CANCELLED'],
|
|
218
219
|
IN_PROGRESS: ['DELIVERED', 'CANCELLED'],
|
|
219
220
|
DELIVERED: ['SETTLED', 'DISPUTED'],
|
|
220
|
-
|
|
221
|
+
// AUDIT FIX: DISPUTED can also be CANCELLED by admin/pauser
|
|
222
|
+
DISPUTED: ['SETTLED', 'CANCELLED'],
|
|
221
223
|
SETTLED: [], // Terminal state
|
|
222
224
|
CANCELLED: [], // Terminal state
|
|
223
225
|
};
|
|
@@ -339,6 +341,14 @@ export class MockRuntime implements IACTPRuntime {
|
|
|
339
341
|
};
|
|
340
342
|
}
|
|
341
343
|
|
|
344
|
+
/**
|
|
345
|
+
* Maximum transaction amount - no limit in mock mode.
|
|
346
|
+
*
|
|
347
|
+
* Mock mode is for testing, so we don't enforce limits.
|
|
348
|
+
* Real blockchain runtimes may have limits for security.
|
|
349
|
+
*/
|
|
350
|
+
readonly maxTransactionAmount: number | undefined = undefined;
|
|
351
|
+
|
|
342
352
|
/**
|
|
343
353
|
* Load events from persisted state file.
|
|
344
354
|
*
|
|
@@ -14,10 +14,13 @@
|
|
|
14
14
|
* ACTP Transaction State enum matching the smart contract states.
|
|
15
15
|
*
|
|
16
16
|
* State machine:
|
|
17
|
-
* - INITIATED (0) -> QUOTED (1, optional) -> COMMITTED (2) -> IN_PROGRESS (3,
|
|
17
|
+
* - INITIATED (0) -> QUOTED (1, optional) -> COMMITTED (2) -> IN_PROGRESS (3, mandatory)
|
|
18
18
|
* -> DELIVERED (4) -> SETTLED (5)
|
|
19
|
-
* - Dispute path: DELIVERED -> DISPUTED (6) -> SETTLED
|
|
19
|
+
* - Dispute path: DELIVERED -> DISPUTED (6) -> SETTLED or CANCELLED (admin)
|
|
20
20
|
* - Cancel path: Any pre-DELIVERED state -> CANCELLED (7)
|
|
21
|
+
*
|
|
22
|
+
* AUDIT FIX (2026-02): IN_PROGRESS is now mandatory per contract. Direct
|
|
23
|
+
* COMMITTED -> DELIVERED transitions are rejected on-chain.
|
|
21
24
|
*/
|
|
22
25
|
export type TransactionState =
|
|
23
26
|
| 'INITIATED'
|