@agirails/sdk 2.5.3 → 2.5.5
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/dist/ACTPClient.d.ts +18 -0
- package/dist/ACTPClient.d.ts.map +1 -1
- package/dist/ACTPClient.js +72 -23
- package/dist/ACTPClient.js.map +1 -1
- package/dist/adapters/BasicAdapter.d.ts +15 -0
- package/dist/adapters/BasicAdapter.d.ts.map +1 -1
- package/dist/adapters/BasicAdapter.js +33 -4
- package/dist/adapters/BasicAdapter.js.map +1 -1
- package/dist/adapters/StandardAdapter.d.ts +20 -3
- package/dist/adapters/StandardAdapter.d.ts.map +1 -1
- package/dist/adapters/StandardAdapter.js +90 -12
- package/dist/adapters/StandardAdapter.js.map +1 -1
- package/dist/cli/commands/publish.js +16 -4
- package/dist/cli/commands/publish.js.map +1 -1
- package/dist/cli/commands/register.js +16 -4
- package/dist/cli/commands/register.js.map +1 -1
- package/dist/cli/commands/tx.js +31 -3
- package/dist/cli/commands/tx.js.map +1 -1
- package/dist/config/networks.d.ts +10 -2
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +31 -22
- package/dist/config/networks.js.map +1 -1
- package/dist/level0/request.d.ts.map +1 -1
- package/dist/level0/request.js +2 -1
- package/dist/level0/request.js.map +1 -1
- package/dist/runtime/BlockchainRuntime.d.ts.map +1 -1
- package/dist/runtime/BlockchainRuntime.js +11 -5
- package/dist/runtime/BlockchainRuntime.js.map +1 -1
- package/dist/utils/IPFSClient.d.ts +3 -1
- package/dist/utils/IPFSClient.d.ts.map +1 -1
- package/dist/utils/IPFSClient.js +27 -7
- package/dist/utils/IPFSClient.js.map +1 -1
- package/dist/wallet/AutoWalletProvider.d.ts +11 -1
- package/dist/wallet/AutoWalletProvider.d.ts.map +1 -1
- package/dist/wallet/AutoWalletProvider.js +84 -19
- package/dist/wallet/AutoWalletProvider.js.map +1 -1
- package/dist/wallet/IWalletProvider.d.ts +34 -0
- package/dist/wallet/IWalletProvider.d.ts.map +1 -1
- package/dist/wallet/SmartWalletRouter.d.ts +128 -0
- package/dist/wallet/SmartWalletRouter.d.ts.map +1 -0
- package/dist/wallet/SmartWalletRouter.js +248 -0
- package/dist/wallet/SmartWalletRouter.js.map +1 -0
- package/dist/wallet/aa/DualNonceManager.d.ts +26 -1
- package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -1
- package/dist/wallet/aa/DualNonceManager.js +140 -6
- package/dist/wallet/aa/DualNonceManager.js.map +1 -1
- package/package.json +3 -6
- package/src/ACTPClient.ts +0 -1579
- package/src/abi/ACTPKernel.json +0 -1356
- package/src/abi/AgentRegistry.json +0 -915
- package/src/abi/ERC20.json +0 -40
- package/src/abi/EscrowVault.json +0 -134
- package/src/abi/IdentityRegistry.json +0 -316
- package/src/adapters/AdapterRegistry.ts +0 -173
- package/src/adapters/AdapterRouter.ts +0 -416
- package/src/adapters/BaseAdapter.ts +0 -498
- package/src/adapters/BasicAdapter.ts +0 -514
- package/src/adapters/IAdapter.ts +0 -292
- package/src/adapters/StandardAdapter.ts +0 -555
- package/src/adapters/X402Adapter.ts +0 -731
- package/src/adapters/index.ts +0 -60
- package/src/builders/DeliveryProofBuilder.ts +0 -327
- package/src/builders/QuoteBuilder.ts +0 -483
- package/src/builders/index.ts +0 -17
- package/src/cli/commands/balance.ts +0 -110
- package/src/cli/commands/batch.ts +0 -487
- package/src/cli/commands/config.ts +0 -231
- package/src/cli/commands/deploy-check.ts +0 -364
- package/src/cli/commands/deploy-env.ts +0 -120
- package/src/cli/commands/diff.ts +0 -141
- package/src/cli/commands/init.ts +0 -469
- package/src/cli/commands/mint.ts +0 -116
- package/src/cli/commands/pay.ts +0 -113
- package/src/cli/commands/publish.ts +0 -475
- package/src/cli/commands/pull.ts +0 -124
- package/src/cli/commands/register.ts +0 -247
- package/src/cli/commands/simulate.ts +0 -345
- package/src/cli/commands/time.ts +0 -302
- package/src/cli/commands/tx.ts +0 -448
- package/src/cli/commands/watch.ts +0 -211
- package/src/cli/index.ts +0 -134
- package/src/cli/utils/client.ts +0 -252
- package/src/cli/utils/config.ts +0 -389
- package/src/cli/utils/output.ts +0 -465
- package/src/cli/utils/wallet.ts +0 -109
- package/src/config/agirailsmd.ts +0 -262
- package/src/config/networks.ts +0 -275
- package/src/config/pendingPublish.ts +0 -237
- package/src/config/publishPipeline.ts +0 -359
- package/src/config/syncOperations.ts +0 -279
- package/src/erc8004/ERC8004Bridge.ts +0 -462
- package/src/erc8004/ReputationReporter.ts +0 -468
- package/src/erc8004/index.ts +0 -61
- package/src/errors/index.ts +0 -427
- package/src/index.ts +0 -364
- package/src/level0/Provider.ts +0 -117
- package/src/level0/ServiceDirectory.ts +0 -131
- package/src/level0/index.ts +0 -10
- package/src/level0/provide.ts +0 -132
- package/src/level0/request.ts +0 -432
- package/src/level1/Agent.ts +0 -1426
- package/src/level1/index.ts +0 -10
- package/src/level1/pricing/PriceCalculator.ts +0 -255
- package/src/level1/pricing/PricingStrategy.ts +0 -198
- package/src/level1/types/Job.ts +0 -179
- package/src/level1/types/Options.ts +0 -291
- package/src/level1/types/index.ts +0 -8
- package/src/protocol/ACTPKernel.ts +0 -808
- package/src/protocol/AgentRegistry.ts +0 -559
- package/src/protocol/DIDManager.ts +0 -629
- package/src/protocol/DIDResolver.ts +0 -554
- package/src/protocol/EASHelper.ts +0 -378
- package/src/protocol/EscrowVault.ts +0 -255
- package/src/protocol/EventMonitor.ts +0 -204
- package/src/protocol/MessageSigner.ts +0 -510
- package/src/protocol/ProofGenerator.ts +0 -339
- package/src/protocol/QuoteBuilder.ts +0 -15
- package/src/registry/AgentRegistryClient.ts +0 -202
- package/src/runtime/BlockchainRuntime.ts +0 -1015
- package/src/runtime/IACTPRuntime.ts +0 -306
- package/src/runtime/MockRuntime.ts +0 -1298
- package/src/runtime/MockStateManager.ts +0 -577
- package/src/runtime/index.ts +0 -25
- package/src/runtime/types/MockState.ts +0 -237
- package/src/storage/ArchiveBundleBuilder.ts +0 -561
- package/src/storage/ArweaveClient.ts +0 -946
- package/src/storage/FilebaseClient.ts +0 -790
- package/src/storage/index.ts +0 -96
- package/src/storage/types.ts +0 -348
- package/src/types/adapter.ts +0 -310
- package/src/types/agent.ts +0 -79
- package/src/types/did.ts +0 -223
- package/src/types/eip712.ts +0 -175
- package/src/types/erc8004.ts +0 -293
- package/src/types/escrow.ts +0 -27
- package/src/types/index.ts +0 -17
- package/src/types/message.ts +0 -145
- package/src/types/state.ts +0 -87
- package/src/types/transaction.ts +0 -69
- package/src/types/x402.ts +0 -251
- package/src/utils/ErrorRecoveryGuide.ts +0 -676
- package/src/utils/Helpers.ts +0 -688
- package/src/utils/IPFSClient.ts +0 -368
- package/src/utils/Logger.ts +0 -484
- package/src/utils/NonceManager.ts +0 -591
- package/src/utils/RateLimiter.ts +0 -534
- package/src/utils/ReceivedNonceTracker.ts +0 -567
- package/src/utils/SDKLifecycle.ts +0 -416
- package/src/utils/SecureNonce.ts +0 -78
- package/src/utils/Semaphore.ts +0 -276
- package/src/utils/UsedAttestationTracker.ts +0 -385
- package/src/utils/canonicalJson.ts +0 -38
- package/src/utils/circuitBreaker.ts +0 -324
- package/src/utils/computeTypeHash.ts +0 -48
- package/src/utils/fsSafe.ts +0 -80
- package/src/utils/index.ts +0 -80
- package/src/utils/retry.ts +0 -364
- package/src/utils/security.ts +0 -418
- package/src/utils/validation.ts +0 -540
- package/src/wallet/AutoWalletProvider.ts +0 -299
- package/src/wallet/EOAWalletProvider.ts +0 -69
- package/src/wallet/IWalletProvider.ts +0 -135
- package/src/wallet/aa/BundlerClient.ts +0 -274
- package/src/wallet/aa/DualNonceManager.ts +0 -173
- package/src/wallet/aa/PaymasterClient.ts +0 -174
- package/src/wallet/aa/TransactionBatcher.ts +0 -353
- package/src/wallet/aa/UserOpBuilder.ts +0 -246
- package/src/wallet/aa/constants.ts +0 -60
- package/src/wallet/keystore.ts +0 -240
package/src/level0/provide.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* provide() - Basic API for service providers
|
|
3
|
-
*
|
|
4
|
-
* The simplest way to provide a service on AGIRAILS.
|
|
5
|
-
* Just write a function, and AGIRAILS handles the rest.
|
|
6
|
-
*
|
|
7
|
-
* @packageDocumentation
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { Agent } from '../level1/Agent';
|
|
11
|
-
import { JobHandler } from '../level1/types/Job';
|
|
12
|
-
import { ProvideOptions } from '../level1/types/Options';
|
|
13
|
-
import { Provider } from './Provider';
|
|
14
|
-
import { serviceDirectory } from './ServiceDirectory';
|
|
15
|
-
import { sdkLogger } from '../utils/Logger';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Provide a service
|
|
19
|
-
*
|
|
20
|
-
* This is the simplest way to provide a service on AGIRAILS.
|
|
21
|
-
* You provide a service name and a handler function, and AGIRAILS
|
|
22
|
-
* takes care of wallet management, transactions, and payments.
|
|
23
|
-
*
|
|
24
|
-
* @param service - Service name (e.g., 'translation', 'echo')
|
|
25
|
-
* @param handler - Job handler function
|
|
26
|
-
* @param options - Optional configuration
|
|
27
|
-
* @returns Provider interface for lifecycle control
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```typescript
|
|
31
|
-
* // Simplest example
|
|
32
|
-
* provide('echo', async (job) => {
|
|
33
|
-
* return job.input;
|
|
34
|
-
* });
|
|
35
|
-
*
|
|
36
|
-
* // With filtering
|
|
37
|
-
* provide('translation', async (job) => {
|
|
38
|
-
* const { text, from, to } = job.input;
|
|
39
|
-
* return { translated: await translate(text, from, to) };
|
|
40
|
-
* }, {
|
|
41
|
-
* filter: { minBudget: 5 },
|
|
42
|
-
* network: 'testnet'
|
|
43
|
-
* });
|
|
44
|
-
*
|
|
45
|
-
* // With events
|
|
46
|
-
* const provider = provide('image-gen', async (job) => {
|
|
47
|
-
* return { imageUrl: await generateImage(job.input.prompt) };
|
|
48
|
-
* });
|
|
49
|
-
*
|
|
50
|
-
* provider.on('payment:received', (amount) => {
|
|
51
|
-
* console.log(`Earned ${amount} USDC!`);
|
|
52
|
-
* });
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
export function provide(
|
|
56
|
-
service: string,
|
|
57
|
-
handler: JobHandler,
|
|
58
|
-
options?: ProvideOptions
|
|
59
|
-
): Provider {
|
|
60
|
-
// Create an Agent instance under the hood
|
|
61
|
-
const agent = new Agent({
|
|
62
|
-
name: `Provider:${service}`,
|
|
63
|
-
description: `Auto-generated provider for ${service}`,
|
|
64
|
-
network: options?.network || 'mock',
|
|
65
|
-
wallet: options?.wallet,
|
|
66
|
-
stateDirectory: options?.stateDirectory,
|
|
67
|
-
rpcUrl: options?.rpcUrl,
|
|
68
|
-
behavior: {
|
|
69
|
-
autoAccept: options?.autoAccept ?? true,
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Register the service with filter options
|
|
74
|
-
agent.provide(
|
|
75
|
-
{
|
|
76
|
-
name: service,
|
|
77
|
-
filter: options?.filter,
|
|
78
|
-
},
|
|
79
|
-
handler
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
// Start the agent immediately (async)
|
|
83
|
-
agent.start().then(() => {
|
|
84
|
-
// Register in service directory after agent has started and has an address
|
|
85
|
-
serviceDirectory.register(service, agent.address);
|
|
86
|
-
}).catch((error) => {
|
|
87
|
-
sdkLogger.error(`Failed to start provider for ${service}`, { error: error instanceof Error ? error.message : String(error) });
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// Return Provider interface (adapter over Agent)
|
|
91
|
-
const provider: Provider = {
|
|
92
|
-
get status() {
|
|
93
|
-
return agent.status as any;
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
get address() {
|
|
97
|
-
return agent.address;
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
get balance() {
|
|
101
|
-
return agent.balance;
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
pause() {
|
|
105
|
-
agent.pause();
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
resume() {
|
|
109
|
-
agent.resume();
|
|
110
|
-
},
|
|
111
|
-
|
|
112
|
-
async stop() {
|
|
113
|
-
await agent.stop();
|
|
114
|
-
serviceDirectory.unregister(service, agent.address);
|
|
115
|
-
},
|
|
116
|
-
|
|
117
|
-
on(event: any, handler: any) {
|
|
118
|
-
agent.on(event, handler);
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
get stats() {
|
|
122
|
-
return {
|
|
123
|
-
jobsCompleted: agent.stats.jobsCompleted,
|
|
124
|
-
jobsFailed: agent.stats.jobsFailed,
|
|
125
|
-
totalEarned: agent.stats.totalEarned,
|
|
126
|
-
averageJobTime: agent.stats.averageJobTime,
|
|
127
|
-
};
|
|
128
|
-
},
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
return provider;
|
|
132
|
-
}
|
package/src/level0/request.ts
DELETED
|
@@ -1,432 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* request() - Basic API for service requesters
|
|
3
|
-
*
|
|
4
|
-
* The simplest way to request a service from AGIRAILS.
|
|
5
|
-
* Specify what you need and your budget, and AGIRAILS finds a provider.
|
|
6
|
-
*
|
|
7
|
-
* @packageDocumentation
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { ACTPClient } from '../ACTPClient';
|
|
11
|
-
import { RequestOptions, RequestResult } from '../level1/types/Options';
|
|
12
|
-
import { serviceDirectory } from './ServiceDirectory';
|
|
13
|
-
import { NoProviderFoundError, TimeoutError, ValidationError } from '../errors';
|
|
14
|
-
import { safeJSONParse, validateServiceName, isValidAddress } from '../utils/security';
|
|
15
|
-
import { Logger } from '../utils/Logger';
|
|
16
|
-
import { ethers } from 'ethers';
|
|
17
|
-
import { resolvePrivateKey } from '../wallet/keystore';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Request a service
|
|
21
|
-
*
|
|
22
|
-
* This is the simplest way to request a service on AGIRAILS.
|
|
23
|
-
* Specify the service name, input data, and budget, and AGIRAILS
|
|
24
|
-
* handles finding a provider, creating the transaction, and delivering the result.
|
|
25
|
-
*
|
|
26
|
-
* @param service - Service name (e.g., 'translation', 'echo')
|
|
27
|
-
* @param options - Request options (input, budget, etc.)
|
|
28
|
-
* @returns Promise resolving to request result
|
|
29
|
-
*
|
|
30
|
-
* @throws {NoProviderFoundError} If no provider is found for the service
|
|
31
|
-
* @throws {TimeoutError} If provider doesn't respond within timeout
|
|
32
|
-
* @throws {ProviderRejectedError} If provider rejects the job
|
|
33
|
-
* @throws {DeliveryFailedError} If provider fails to deliver result
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```typescript
|
|
37
|
-
* // Simplest example
|
|
38
|
-
* const { result } = await request('echo', {
|
|
39
|
-
* input: 'Hello, AGIRAILS!',
|
|
40
|
-
* budget: 1
|
|
41
|
-
* });
|
|
42
|
-
* console.log(result); // 'Hello, AGIRAILS!'
|
|
43
|
-
*
|
|
44
|
-
* // With progress callback
|
|
45
|
-
* const { result } = await request('translation', {
|
|
46
|
-
* input: { text: 'Hello', from: 'en', to: 'de' },
|
|
47
|
-
* budget: 5,
|
|
48
|
-
* onProgress: (status) => {
|
|
49
|
-
* console.log(`${status.state}: ${status.progress}%`);
|
|
50
|
-
* }
|
|
51
|
-
* });
|
|
52
|
-
*
|
|
53
|
-
* // With specific provider
|
|
54
|
-
* const { result } = await request('image-gen', {
|
|
55
|
-
* input: { prompt: 'A beautiful sunset' },
|
|
56
|
-
* budget: 10,
|
|
57
|
-
* provider: '0x1234...abcd'
|
|
58
|
-
* });
|
|
59
|
-
* ```
|
|
60
|
-
*/
|
|
61
|
-
export async function request(
|
|
62
|
-
service: string,
|
|
63
|
-
options: RequestOptions
|
|
64
|
-
): Promise<RequestResult> {
|
|
65
|
-
const validatedService = validateServiceName(service);
|
|
66
|
-
|
|
67
|
-
const logger = new Logger({ source: 'request' });
|
|
68
|
-
|
|
69
|
-
// Find provider
|
|
70
|
-
const provider = findProvider(validatedService, options.provider);
|
|
71
|
-
|
|
72
|
-
if (!provider) {
|
|
73
|
-
throw new NoProviderFoundError(validatedService, {
|
|
74
|
-
availableProviders: serviceDirectory.findProviders(validatedService),
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
let rpcUrl = options.rpcUrl;
|
|
79
|
-
if (!rpcUrl && (options.network === 'testnet' || options.network === 'mainnet')) {
|
|
80
|
-
const { getNetwork } = await import('../config/networks');
|
|
81
|
-
const networkName = options.network === 'testnet' ? 'base-sepolia' : 'base-mainnet';
|
|
82
|
-
const networkConfig = getNetwork(networkName);
|
|
83
|
-
rpcUrl = networkConfig.rpcUrl;
|
|
84
|
-
logger.info(`Using default RPC URL for ${networkName}: ${rpcUrl}`);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const resolvedKey = await resolveKeyIfNeeded(options.wallet, options.network, options.stateDirectory);
|
|
88
|
-
const resolvedAddress = resolvedKey
|
|
89
|
-
? new ethers.Wallet(resolvedKey).address.toLowerCase()
|
|
90
|
-
: undefined;
|
|
91
|
-
|
|
92
|
-
const client = await ACTPClient.create({
|
|
93
|
-
mode: options.network === 'testnet' ? 'testnet' : options.network === 'mainnet' ? 'mainnet' : 'mock',
|
|
94
|
-
requesterAddress: resolvedAddress || getRequesterAddress(options.wallet),
|
|
95
|
-
stateDirectory: options.stateDirectory,
|
|
96
|
-
privateKey: resolvedKey || getPrivateKey(options.wallet),
|
|
97
|
-
rpcUrl,
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
const deadline = calculateDeadline(options.deadline, options.timeout);
|
|
101
|
-
const startTime = Date.now();
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
const requesterAddress = resolvedAddress || getRequesterAddress(options.wallet);
|
|
105
|
-
const amountWei = (options.budget * 1_000_000).toString(); // Convert to USDC wei (6 decimals)
|
|
106
|
-
|
|
107
|
-
// In mock mode, ensure requester has enough funds
|
|
108
|
-
if (client.runtime && 'mintTokens' in client.runtime) {
|
|
109
|
-
const mockRuntime = client.runtime as any;
|
|
110
|
-
const balance = await mockRuntime.getBalance(requesterAddress);
|
|
111
|
-
const balanceBigInt = BigInt(balance);
|
|
112
|
-
const amountBigInt = BigInt(amountWei);
|
|
113
|
-
|
|
114
|
-
if (balanceBigInt < amountBigInt) {
|
|
115
|
-
// Mint enough tokens (with some buffer)
|
|
116
|
-
const toMint = (amountBigInt - balanceBigInt + BigInt(10_000_000)).toString(); // +10 USDC buffer
|
|
117
|
-
await mockRuntime.mintTokens(requesterAddress, toMint);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const serviceMetadata = JSON.stringify({
|
|
122
|
-
service: validatedService,
|
|
123
|
-
input: options.input,
|
|
124
|
-
timestamp: Date.now(),
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
const txId = await client.runtime.createTransaction({
|
|
128
|
-
provider,
|
|
129
|
-
requester: requesterAddress,
|
|
130
|
-
amount: amountWei,
|
|
131
|
-
deadline,
|
|
132
|
-
disputeWindow: options.disputeWindow ?? 172800,
|
|
133
|
-
serviceDescription: serviceMetadata,
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// Call onProgress if provided
|
|
137
|
-
if (options.onProgress) {
|
|
138
|
-
options.onProgress({
|
|
139
|
-
state: 'initiated',
|
|
140
|
-
progress: 10,
|
|
141
|
-
message: 'Transaction created, waiting for provider...',
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Poll for DELIVERED state (provider completes the job)
|
|
146
|
-
const maxWaitTime = options.timeout ?? 300000; // 5 minutes default
|
|
147
|
-
const pollInterval = 2000; // 2 seconds
|
|
148
|
-
const maxAttempts = Math.floor(maxWaitTime / pollInterval);
|
|
149
|
-
|
|
150
|
-
let tx = await client.runtime.getTransaction(txId);
|
|
151
|
-
let attempts = 0;
|
|
152
|
-
|
|
153
|
-
while (tx && tx.state !== 'DELIVERED' && tx.state !== 'SETTLED' && attempts < maxAttempts) {
|
|
154
|
-
// Check for terminal states that indicate failure
|
|
155
|
-
if (tx.state === 'CANCELLED' || tx.state === 'DISPUTED') {
|
|
156
|
-
throw new Error(`Transaction ${tx.state.toLowerCase()}`);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Update progress
|
|
160
|
-
if (options.onProgress) {
|
|
161
|
-
const progress = 10 + Math.min(80, (attempts / maxAttempts) * 80);
|
|
162
|
-
options.onProgress({
|
|
163
|
-
state: tx.state.toLowerCase() as any,
|
|
164
|
-
progress,
|
|
165
|
-
message: `Waiting for delivery (${tx.state})...`,
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Wait and poll again
|
|
170
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
171
|
-
tx = await client.runtime.getTransaction(txId);
|
|
172
|
-
attempts++;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (!tx || (tx.state !== 'DELIVERED' && tx.state !== 'SETTLED')) {
|
|
176
|
-
// Auto-cancel on timeout if still in early state
|
|
177
|
-
if (tx && (tx.state === 'INITIATED' || tx.state === 'COMMITTED')) {
|
|
178
|
-
try {
|
|
179
|
-
logger.warn('Transaction timed out, cancelling to release funds', {
|
|
180
|
-
txId,
|
|
181
|
-
state: tx.state,
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
if ('cancelTransaction' in client.runtime) {
|
|
185
|
-
await (client.runtime as any).cancelTransaction(txId);
|
|
186
|
-
logger.info('Transaction cancelled successfully', { txId });
|
|
187
|
-
|
|
188
|
-
const error = new TimeoutError(maxWaitTime, `Transaction cancelled after timeout`);
|
|
189
|
-
(error as any).txId = txId;
|
|
190
|
-
(error as any).wasCancelled = true;
|
|
191
|
-
throw error;
|
|
192
|
-
} else {
|
|
193
|
-
await client.runtime.transitionState(txId, 'CANCELLED');
|
|
194
|
-
logger.info('Transaction cancelled successfully (via transitionState)', { txId });
|
|
195
|
-
|
|
196
|
-
const error = new TimeoutError(maxWaitTime, `Transaction cancelled after timeout`);
|
|
197
|
-
(error as any).txId = txId;
|
|
198
|
-
(error as any).wasCancelled = true;
|
|
199
|
-
throw error;
|
|
200
|
-
}
|
|
201
|
-
} catch (cancelError) {
|
|
202
|
-
logger.error('Failed to cancel timed-out transaction', { txId }, cancelError as Error);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const error = new TimeoutError(maxWaitTime, `waiting for service '${validatedService}' delivery`);
|
|
207
|
-
(error as any).txId = txId;
|
|
208
|
-
(error as any).currentState = tx?.state || 'UNKNOWN';
|
|
209
|
-
throw error;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
let deliveredResult: any = {};
|
|
213
|
-
if (tx.deliveryProof) {
|
|
214
|
-
const DELIVERY_PROOF_SCHEMA: Record<string, string> = {
|
|
215
|
-
result: 'any',
|
|
216
|
-
data: 'any',
|
|
217
|
-
metadata: 'object',
|
|
218
|
-
proof: 'string',
|
|
219
|
-
timestamp: 'number',
|
|
220
|
-
contentHash: 'string',
|
|
221
|
-
txId: 'string',
|
|
222
|
-
type: 'string',
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
const parsed = safeJSONParse(tx.deliveryProof, DELIVERY_PROOF_SCHEMA);
|
|
226
|
-
|
|
227
|
-
if (parsed !== null) {
|
|
228
|
-
deliveredResult = parsed;
|
|
229
|
-
} else {
|
|
230
|
-
deliveredResult = { data: tx.deliveryProof };
|
|
231
|
-
logger.warn('Failed to parse delivery proof as JSON', { txId });
|
|
232
|
-
}
|
|
233
|
-
} else if (options.network === 'testnet' || options.network === 'mainnet') {
|
|
234
|
-
logger.warn(
|
|
235
|
-
'Delivery proof retrieval not yet implemented for testnet/mainnet. ' +
|
|
236
|
-
'Result may be empty. Use ACTPClient with manual proof handling for production.',
|
|
237
|
-
{ txId, network: options.network }
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (tx.state === 'DELIVERED' && tx.escrowId) {
|
|
242
|
-
const disputeWindowEnd = (tx.completedAt ?? 0) + tx.disputeWindow;
|
|
243
|
-
const currentTime = client.runtime.time.now();
|
|
244
|
-
|
|
245
|
-
if (currentTime >= disputeWindowEnd) {
|
|
246
|
-
const isMockMode = options.network !== 'testnet' && options.network !== 'mainnet';
|
|
247
|
-
|
|
248
|
-
if (isMockMode) {
|
|
249
|
-
try {
|
|
250
|
-
await client.runtime.releaseEscrow(tx.escrowId);
|
|
251
|
-
} catch (error) {
|
|
252
|
-
// Ignore if already released or dispute window still active
|
|
253
|
-
// This is non-critical for result delivery
|
|
254
|
-
}
|
|
255
|
-
} else {
|
|
256
|
-
// For testnet/mainnet, log a warning about manual verification
|
|
257
|
-
logger.warn(
|
|
258
|
-
'Auto-release disabled for non-mock networks. ' +
|
|
259
|
-
'Verify delivery proof and call releaseEscrow() manually, ' +
|
|
260
|
-
'or enable attestation verification in BlockchainRuntime.',
|
|
261
|
-
{ txId, escrowId: tx.escrowId, network: options.network }
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (options.onProgress) {
|
|
268
|
-
options.onProgress({
|
|
269
|
-
state: 'settled',
|
|
270
|
-
progress: 100,
|
|
271
|
-
message: 'Transaction completed!',
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// Extract raw handler result from delivery proof wrapper
|
|
276
|
-
// The delivery proof structure is: { type: 'delivery.proof', result: <handler_output>, ... }
|
|
277
|
-
// We return the raw handler output as `result` for better DX
|
|
278
|
-
//
|
|
279
|
-
// IMPORTANT: We check for type === 'delivery.proof' which is the unique marker
|
|
280
|
-
// set by ProofGenerator. This avoids false positives from handlers that happen
|
|
281
|
-
// to return objects with result/contentHash/timestamp fields.
|
|
282
|
-
const isDeliveryProofWrapper = deliveredResult !== null &&
|
|
283
|
-
typeof deliveredResult === 'object' &&
|
|
284
|
-
deliveredResult.type === 'delivery.proof' &&
|
|
285
|
-
'result' in deliveredResult;
|
|
286
|
-
const rawResult = isDeliveryProofWrapper ? deliveredResult.result : deliveredResult;
|
|
287
|
-
|
|
288
|
-
const result: RequestResult = {
|
|
289
|
-
result: rawResult,
|
|
290
|
-
transaction: {
|
|
291
|
-
id: txId,
|
|
292
|
-
provider,
|
|
293
|
-
amount: options.budget,
|
|
294
|
-
fee: options.budget * 0.01, // 1% ACTP fee
|
|
295
|
-
duration: Date.now() - startTime,
|
|
296
|
-
proof: tx.deliveryProof ?? '',
|
|
297
|
-
},
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
return result;
|
|
301
|
-
} catch (error) {
|
|
302
|
-
// Better error handling
|
|
303
|
-
if (error instanceof TimeoutError) {
|
|
304
|
-
throw error;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Wrap unknown errors
|
|
308
|
-
throw new Error(`Request failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Resolve private key from keystore if wallet is auto/undefined and network is testnet/mainnet.
|
|
314
|
-
* Returns undefined if wallet is explicitly set (caller should use getPrivateKey instead).
|
|
315
|
-
*/
|
|
316
|
-
async function resolveKeyIfNeeded(
|
|
317
|
-
wallet?: 'auto' | 'connect' | string | { privateKey: string },
|
|
318
|
-
network?: string,
|
|
319
|
-
stateDirectory?: string
|
|
320
|
-
): Promise<string | undefined> {
|
|
321
|
-
if (wallet && wallet !== 'auto') return undefined; // explicit wallet, skip auto-detect
|
|
322
|
-
if (network !== 'testnet' && network !== 'mainnet') return undefined;
|
|
323
|
-
return resolvePrivateKey(stateDirectory, { network });
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Find provider for service
|
|
328
|
-
*
|
|
329
|
-
* @param service - Service name
|
|
330
|
-
* @param providerOption - Provider selection strategy
|
|
331
|
-
* @returns Provider address or undefined
|
|
332
|
-
*/
|
|
333
|
-
function findProvider(
|
|
334
|
-
service: string,
|
|
335
|
-
providerOption?: string | 'any' | 'best' | 'cheapest'
|
|
336
|
-
): string | undefined {
|
|
337
|
-
// If specific provider specified, use it
|
|
338
|
-
if (providerOption && providerOption !== 'any' && providerOption !== 'best' && providerOption !== 'cheapest') {
|
|
339
|
-
return providerOption;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Otherwise, find from service directory
|
|
343
|
-
const providers = serviceDirectory.findProviders(service);
|
|
344
|
-
|
|
345
|
-
if (providers.length === 0) {
|
|
346
|
-
return undefined;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// For MVP, just return the first provider
|
|
350
|
-
// In V2, implement 'best' and 'cheapest' strategies
|
|
351
|
-
return providers[0];
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
function getRequesterAddress(
|
|
355
|
-
wallet?: 'auto' | 'connect' | string | { privateKey: string }
|
|
356
|
-
): string {
|
|
357
|
-
if (!wallet || wallet === 'auto') {
|
|
358
|
-
const hex = Buffer.from('requester').toString('hex');
|
|
359
|
-
return '0x' + hex.padEnd(40, '0');
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (wallet === 'connect') {
|
|
363
|
-
throw new Error('Browser wallet connection not yet implemented');
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (typeof wallet === 'string') {
|
|
367
|
-
if (!isValidAddress(wallet)) {
|
|
368
|
-
throw new ValidationError('wallet', `Invalid Ethereum address format: ${wallet}`);
|
|
369
|
-
}
|
|
370
|
-
return wallet.toLowerCase();
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
try {
|
|
374
|
-
const walletInstance = new ethers.Wallet(wallet.privateKey);
|
|
375
|
-
return walletInstance.address.toLowerCase();
|
|
376
|
-
} catch (error) {
|
|
377
|
-
throw new ValidationError('wallet.privateKey', 'Invalid private key format');
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
function getPrivateKey(
|
|
382
|
-
wallet?: 'auto' | 'connect' | string | { privateKey: string }
|
|
383
|
-
): string | undefined {
|
|
384
|
-
if (!wallet || wallet === 'auto' || wallet === 'connect') {
|
|
385
|
-
return undefined;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (typeof wallet === 'string') {
|
|
389
|
-
if (/^0x[0-9a-fA-F]{64}$/.test(wallet)) {
|
|
390
|
-
try {
|
|
391
|
-
new ethers.Wallet(wallet);
|
|
392
|
-
return wallet;
|
|
393
|
-
} catch {
|
|
394
|
-
throw new ValidationError('wallet', 'Invalid private key format');
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
return undefined;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (wallet.privateKey) {
|
|
401
|
-
try {
|
|
402
|
-
new ethers.Wallet(wallet.privateKey);
|
|
403
|
-
return wallet.privateKey;
|
|
404
|
-
} catch {
|
|
405
|
-
throw new ValidationError('wallet.privateKey', 'Invalid private key format');
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
return undefined;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Calculate deadline timestamp
|
|
414
|
-
*
|
|
415
|
-
* @param deadline - Deadline option (timestamp or Date)
|
|
416
|
-
* @param timeout - Timeout in milliseconds
|
|
417
|
-
* @returns Deadline timestamp (seconds)
|
|
418
|
-
*/
|
|
419
|
-
function calculateDeadline(
|
|
420
|
-
deadline?: number | Date,
|
|
421
|
-
timeout: number = 300000 // 5 minutes default
|
|
422
|
-
): number {
|
|
423
|
-
if (deadline) {
|
|
424
|
-
if (deadline instanceof Date) {
|
|
425
|
-
return Math.floor(deadline.getTime() / 1000);
|
|
426
|
-
}
|
|
427
|
-
return deadline;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
// Default: now + timeout
|
|
431
|
-
return Math.floor(Date.now() / 1000) + Math.floor(timeout / 1000);
|
|
432
|
-
}
|