@agirails/sdk 2.5.2 → 2.5.4
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 +67 -22
- package/dist/ACTPClient.js.map +1 -1
- package/dist/adapters/BasicAdapter.d.ts +12 -0
- package/dist/adapters/BasicAdapter.d.ts.map +1 -1
- package/dist/adapters/BasicAdapter.js +30 -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 +45 -11
- 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/cli/utils/client.d.ts.map +1 -1
- package/dist/cli/utils/client.js +1 -0
- package/dist/cli/utils/client.js.map +1 -1
- package/dist/config/networks.d.ts +2 -2
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +27 -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/runtime/MockStateManager.d.ts.map +1 -1
- package/dist/runtime/MockStateManager.js +2 -1
- package/dist/runtime/MockStateManager.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.map +1 -1
- package/dist/wallet/AutoWalletProvider.js +52 -18
- package/dist/wallet/AutoWalletProvider.js.map +1 -1
- package/dist/wallet/SmartWalletRouter.d.ts +116 -0
- package/dist/wallet/SmartWalletRouter.d.ts.map +1 -0
- package/dist/wallet/SmartWalletRouter.js +212 -0
- package/dist/wallet/SmartWalletRouter.js.map +1 -0
- package/dist/wallet/aa/DualNonceManager.d.ts +19 -0
- package/dist/wallet/aa/DualNonceManager.d.ts.map +1 -1
- package/dist/wallet/aa/DualNonceManager.js +100 -5
- 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 -251
- 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 -576
- 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
|
@@ -1,483 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* QuoteBuilder - AIP-2 Price Quote Construction
|
|
3
|
-
* Reference: AIP-2 §6.1
|
|
4
|
-
*
|
|
5
|
-
* Builds price quotes with:
|
|
6
|
-
* - Amount validation (≥ originalAmount, ≤ maxPrice)
|
|
7
|
-
* - EIP-712 signature
|
|
8
|
-
* - Canonical JSON hashing
|
|
9
|
-
* - Optional IPFS upload
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { Signer, keccak256, toUtf8Bytes, verifyTypedData } from 'ethers';
|
|
13
|
-
import { canonicalJsonStringify } from '../utils/canonicalJson';
|
|
14
|
-
import { IPFSClient } from '../utils/IPFSClient';
|
|
15
|
-
import { NonceManager } from '../utils/NonceManager';
|
|
16
|
-
import { EIP712Domain } from '../types/eip712';
|
|
17
|
-
import { SignatureVerificationError } from '../errors';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Quote message interface (AIP-2)
|
|
21
|
-
* Reference: AIP-2 §2.1
|
|
22
|
-
*/
|
|
23
|
-
export interface QuoteMessage {
|
|
24
|
-
type: 'agirails.quote.v1';
|
|
25
|
-
version: '1.0.0';
|
|
26
|
-
txId: string; // bytes32 (0x-prefixed)
|
|
27
|
-
provider: string; // DID (e.g., "did:ethr:84532:0x...")
|
|
28
|
-
consumer: string; // DID
|
|
29
|
-
quotedAmount: string; // Provider's quoted price (base units, string to avoid JS overflow)
|
|
30
|
-
originalAmount: string; // Consumer's original offer
|
|
31
|
-
maxPrice: string; // Consumer's maximum acceptable price
|
|
32
|
-
currency: string; // Currently "USDC" only
|
|
33
|
-
decimals: number; // Token decimals (6 for USDC)
|
|
34
|
-
quotedAt: number; // Unix timestamp (seconds)
|
|
35
|
-
expiresAt: number; // Unix timestamp (seconds)
|
|
36
|
-
justification?: {
|
|
37
|
-
reason?: string;
|
|
38
|
-
estimatedTime?: number;
|
|
39
|
-
computeCost?: number;
|
|
40
|
-
breakdown?: Record<string, any>;
|
|
41
|
-
};
|
|
42
|
-
chainId: number; // 84532 (Base Sepolia) or 8453 (Base Mainnet)
|
|
43
|
-
nonce: number; // Monotonically increasing per provider + message type
|
|
44
|
-
signature: string; // EIP-712 signature (0x-prefixed, 130 chars)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Quote build parameters
|
|
49
|
-
* Reference: AIP-2 §6.1
|
|
50
|
-
*/
|
|
51
|
-
export interface QuoteParams {
|
|
52
|
-
txId: string;
|
|
53
|
-
provider: string; // DID
|
|
54
|
-
consumer: string; // DID
|
|
55
|
-
quotedAmount: string; // Base units (e.g., "7500000" for $7.50 USDC)
|
|
56
|
-
originalAmount: string; // From AIP-1 request
|
|
57
|
-
maxPrice: string; // From AIP-1 request
|
|
58
|
-
currency?: string; // Default: "USDC"
|
|
59
|
-
decimals?: number; // Default: 6
|
|
60
|
-
expiresAt?: number; // Optional, defaults to +1 hour
|
|
61
|
-
justification?: {
|
|
62
|
-
reason?: string;
|
|
63
|
-
estimatedTime?: number;
|
|
64
|
-
computeCost?: number;
|
|
65
|
-
breakdown?: Record<string, any>;
|
|
66
|
-
};
|
|
67
|
-
chainId: number;
|
|
68
|
-
kernelAddress: string; // ACTPKernel contract address for EIP-712 domain
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* EIP-712 types for AIP-2 quote messages
|
|
73
|
-
* Reference: AIP-2 §3.1
|
|
74
|
-
*/
|
|
75
|
-
export const AIP2QuoteTypes = {
|
|
76
|
-
PriceQuote: [
|
|
77
|
-
{ name: 'txId', type: 'bytes32' },
|
|
78
|
-
{ name: 'provider', type: 'string' },
|
|
79
|
-
{ name: 'consumer', type: 'string' },
|
|
80
|
-
{ name: 'quotedAmount', type: 'string' },
|
|
81
|
-
{ name: 'originalAmount', type: 'string' },
|
|
82
|
-
{ name: 'maxPrice', type: 'string' },
|
|
83
|
-
{ name: 'currency', type: 'string' },
|
|
84
|
-
{ name: 'decimals', type: 'uint8' },
|
|
85
|
-
{ name: 'quotedAt', type: 'uint256' },
|
|
86
|
-
{ name: 'expiresAt', type: 'uint256' },
|
|
87
|
-
{ name: 'justificationHash', type: 'bytes32' },
|
|
88
|
-
{ name: 'chainId', type: 'uint256' },
|
|
89
|
-
{ name: 'nonce', type: 'uint256' }
|
|
90
|
-
]
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* QuoteBuilder - Main Builder Class
|
|
95
|
-
* Reference: AIP-2 §6.1
|
|
96
|
-
*/
|
|
97
|
-
export class QuoteBuilder {
|
|
98
|
-
constructor(
|
|
99
|
-
private signer: Signer,
|
|
100
|
-
private nonceManager: NonceManager,
|
|
101
|
-
private ipfs?: IPFSClient
|
|
102
|
-
) {}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Build and sign a quote message
|
|
106
|
-
* Reference: AIP-2 §4.1 (Provider workflow)
|
|
107
|
-
*
|
|
108
|
-
* @param params - Quote parameters
|
|
109
|
-
* @returns Signed quote message
|
|
110
|
-
*/
|
|
111
|
-
async build(params: QuoteParams): Promise<QuoteMessage> {
|
|
112
|
-
// Validate parameters
|
|
113
|
-
this.validateParams(params);
|
|
114
|
-
|
|
115
|
-
const quotedAt = Math.floor(Date.now() / 1000);
|
|
116
|
-
const expiresAt = params.expiresAt || (quotedAt + 3600); // Default 1 hour
|
|
117
|
-
|
|
118
|
-
// Validate expiry
|
|
119
|
-
if (expiresAt <= quotedAt) {
|
|
120
|
-
throw new Error('expiresAt must be after quotedAt');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (expiresAt > quotedAt + 86400) {
|
|
124
|
-
throw new Error('expiresAt cannot exceed 24 hours from quotedAt');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Construct quote message (unsigned)
|
|
128
|
-
const quote: QuoteMessage = {
|
|
129
|
-
type: 'agirails.quote.v1',
|
|
130
|
-
version: '1.0.0',
|
|
131
|
-
txId: params.txId,
|
|
132
|
-
provider: params.provider,
|
|
133
|
-
consumer: params.consumer,
|
|
134
|
-
quotedAmount: params.quotedAmount,
|
|
135
|
-
originalAmount: params.originalAmount,
|
|
136
|
-
maxPrice: params.maxPrice,
|
|
137
|
-
currency: params.currency || 'USDC',
|
|
138
|
-
decimals: params.decimals !== undefined ? params.decimals : 6,
|
|
139
|
-
quotedAt,
|
|
140
|
-
expiresAt,
|
|
141
|
-
justification: params.justification,
|
|
142
|
-
chainId: params.chainId,
|
|
143
|
-
nonce: this.nonceManager.getNextNonce('agirails.quote.v1'),
|
|
144
|
-
signature: '' // Filled in next step
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
// Sign with EIP-712
|
|
148
|
-
const signature = await this.signQuote(quote, params.kernelAddress);
|
|
149
|
-
quote.signature = signature;
|
|
150
|
-
|
|
151
|
-
// Record nonce usage
|
|
152
|
-
this.nonceManager.recordNonce('agirails.quote.v1', quote.nonce);
|
|
153
|
-
|
|
154
|
-
return quote;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Verify quote signature and business rules
|
|
159
|
-
* Reference: AIP-2 §5.2, §5.3
|
|
160
|
-
*
|
|
161
|
-
* @param quote - Quote message to verify
|
|
162
|
-
* @param kernelAddress - ACTPKernel contract address
|
|
163
|
-
* @returns true if valid, throws error otherwise
|
|
164
|
-
*/
|
|
165
|
-
async verify(quote: QuoteMessage, kernelAddress: string): Promise<boolean> {
|
|
166
|
-
// 1. Validate schema
|
|
167
|
-
this.validateQuoteSchema(quote);
|
|
168
|
-
|
|
169
|
-
// 2. Verify signature
|
|
170
|
-
const recoveredAddress = this.recoverQuoteSigner(quote, kernelAddress);
|
|
171
|
-
const expectedAddress = this.extractAddressFromDID(quote.provider);
|
|
172
|
-
|
|
173
|
-
if (recoveredAddress.toLowerCase() !== expectedAddress.toLowerCase()) {
|
|
174
|
-
throw new Error('Invalid signature: recovered address does not match provider');
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// 3. Validate business rules
|
|
178
|
-
const quotedAmount = BigInt(quote.quotedAmount);
|
|
179
|
-
const originalAmount = BigInt(quote.originalAmount);
|
|
180
|
-
const maxPrice = BigInt(quote.maxPrice);
|
|
181
|
-
|
|
182
|
-
if (quotedAmount < originalAmount) {
|
|
183
|
-
throw new Error('Quoted amount below original amount');
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (quotedAmount > maxPrice) {
|
|
187
|
-
throw new Error('Quoted amount exceeds maxPrice');
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Platform minimum: $0.05 = 50000 base units (6 decimals)
|
|
191
|
-
if (quotedAmount < 50000n) {
|
|
192
|
-
throw new Error('Quoted amount below platform minimum ($0.05)');
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// 4. Check expiry
|
|
196
|
-
const now = Math.floor(Date.now() / 1000);
|
|
197
|
-
if (quote.expiresAt < now) {
|
|
198
|
-
throw new Error('Quote expired');
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// 5. Timestamp freshness check
|
|
202
|
-
if (Math.abs(now - quote.quotedAt) > 300) {
|
|
203
|
-
throw new Error('Quote timestamp outside 5-minute tolerance');
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Upload quote to IPFS and return CID
|
|
211
|
-
* Reference: AIP-2 §6 (optional IPFS storage)
|
|
212
|
-
*
|
|
213
|
-
* @param quote - Quote message
|
|
214
|
-
* @returns IPFS CID
|
|
215
|
-
*/
|
|
216
|
-
async uploadToIPFS(quote: QuoteMessage): Promise<string> {
|
|
217
|
-
if (!this.ipfs) {
|
|
218
|
-
throw new Error('IPFS client not configured');
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
const cid = await this.ipfs.add(JSON.stringify(quote));
|
|
222
|
-
await this.ipfs.pin(cid); // Pin for dispute window
|
|
223
|
-
return cid;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Compute quote hash (canonical JSON + keccak256)
|
|
228
|
-
* Used for on-chain storage in transaction metadata
|
|
229
|
-
* Reference: AIP-2 §4.1 (Step 6)
|
|
230
|
-
*
|
|
231
|
-
* @param quote - Quote message
|
|
232
|
-
* @returns Keccak256 hash (0x-prefixed)
|
|
233
|
-
*/
|
|
234
|
-
computeHash(quote: QuoteMessage): string {
|
|
235
|
-
// Remove signature field for hashing
|
|
236
|
-
const { signature: _signature, ...quoteWithoutSig } = quote;
|
|
237
|
-
return keccak256(toUtf8Bytes(canonicalJsonStringify(quoteWithoutSig)));
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Sign quote message with EIP-712
|
|
242
|
-
* Reference: AIP-2 §3.1, §3.2
|
|
243
|
-
*
|
|
244
|
-
* @param quote - Quote message (unsigned)
|
|
245
|
-
* @param kernelAddress - ACTPKernel contract address
|
|
246
|
-
* @returns EIP-712 signature (0x-prefixed, 130 chars)
|
|
247
|
-
*/
|
|
248
|
-
private async signQuote(quote: QuoteMessage, kernelAddress: string): Promise<string> {
|
|
249
|
-
const domain: EIP712Domain = {
|
|
250
|
-
name: 'AGIRAILS',
|
|
251
|
-
version: '1',
|
|
252
|
-
chainId: quote.chainId,
|
|
253
|
-
verifyingContract: kernelAddress
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
// Compute justification hash
|
|
257
|
-
const justificationHash = this.computeJustificationHash(quote.justification);
|
|
258
|
-
|
|
259
|
-
const message = {
|
|
260
|
-
txId: quote.txId,
|
|
261
|
-
provider: quote.provider,
|
|
262
|
-
consumer: quote.consumer,
|
|
263
|
-
quotedAmount: quote.quotedAmount,
|
|
264
|
-
originalAmount: quote.originalAmount,
|
|
265
|
-
maxPrice: quote.maxPrice,
|
|
266
|
-
currency: quote.currency,
|
|
267
|
-
decimals: quote.decimals,
|
|
268
|
-
quotedAt: quote.quotedAt,
|
|
269
|
-
expiresAt: quote.expiresAt,
|
|
270
|
-
justificationHash,
|
|
271
|
-
chainId: quote.chainId,
|
|
272
|
-
nonce: quote.nonce
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
// Sign using ethers.js signTypedData (v6 API)
|
|
276
|
-
if ('signTypedData' in this.signer && typeof (this.signer as any).signTypedData === 'function') {
|
|
277
|
-
const signature = await (this.signer as any).signTypedData(domain, AIP2QuoteTypes, message);
|
|
278
|
-
return signature;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
throw new Error('Signer does not support EIP-712 typed data signing');
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Recover signer address from quote signature
|
|
286
|
-
* Reference: AIP-2 §5.3
|
|
287
|
-
*
|
|
288
|
-
* @param quote - Quote message
|
|
289
|
-
* @param kernelAddress - ACTPKernel contract address
|
|
290
|
-
* @returns Recovered Ethereum address
|
|
291
|
-
*/
|
|
292
|
-
private recoverQuoteSigner(quote: QuoteMessage, kernelAddress: string): string {
|
|
293
|
-
const domain: EIP712Domain = {
|
|
294
|
-
name: 'AGIRAILS',
|
|
295
|
-
version: '1',
|
|
296
|
-
chainId: quote.chainId,
|
|
297
|
-
verifyingContract: kernelAddress
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
const justificationHash = this.computeJustificationHash(quote.justification);
|
|
301
|
-
|
|
302
|
-
const message = {
|
|
303
|
-
txId: quote.txId,
|
|
304
|
-
provider: quote.provider,
|
|
305
|
-
consumer: quote.consumer,
|
|
306
|
-
quotedAmount: quote.quotedAmount,
|
|
307
|
-
originalAmount: quote.originalAmount,
|
|
308
|
-
maxPrice: quote.maxPrice,
|
|
309
|
-
currency: quote.currency,
|
|
310
|
-
decimals: quote.decimals,
|
|
311
|
-
quotedAt: quote.quotedAt,
|
|
312
|
-
expiresAt: quote.expiresAt,
|
|
313
|
-
justificationHash,
|
|
314
|
-
chainId: quote.chainId,
|
|
315
|
-
nonce: quote.nonce
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
// Recover address using ethers.js verifyTypedData
|
|
319
|
-
// Wrap in try-catch to handle low-level cryptographic errors gracefully
|
|
320
|
-
try {
|
|
321
|
-
const recoveredAddress = verifyTypedData(domain, AIP2QuoteTypes, message, quote.signature);
|
|
322
|
-
return recoveredAddress;
|
|
323
|
-
} catch (error: any) {
|
|
324
|
-
// Wrap low-level cryptographic errors in SignatureVerificationError
|
|
325
|
-
throw new SignatureVerificationError(
|
|
326
|
-
quote.provider,
|
|
327
|
-
'unknown',
|
|
328
|
-
);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Compute justification hash for EIP-712 signature
|
|
334
|
-
* Reference: AIP-2 §3.2
|
|
335
|
-
*
|
|
336
|
-
* @param justification - Optional justification object
|
|
337
|
-
* @returns Keccak256 hash (0x-prefixed), or zero hash if omitted
|
|
338
|
-
*/
|
|
339
|
-
private computeJustificationHash(justification: object | undefined): string {
|
|
340
|
-
if (!justification || Object.keys(justification).length === 0) {
|
|
341
|
-
return '0x0000000000000000000000000000000000000000000000000000000000000000';
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
return keccak256(toUtf8Bytes(canonicalJsonStringify(justification)));
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Validate quote parameters
|
|
349
|
-
* Reference: AIP-2 §5.1, §5.2
|
|
350
|
-
*
|
|
351
|
-
* @param params - Quote parameters
|
|
352
|
-
* @throws Error if validation fails
|
|
353
|
-
*/
|
|
354
|
-
private validateParams(params: QuoteParams): void {
|
|
355
|
-
// Amount validation
|
|
356
|
-
const quotedAmount = BigInt(params.quotedAmount);
|
|
357
|
-
const originalAmount = BigInt(params.originalAmount);
|
|
358
|
-
const maxPrice = BigInt(params.maxPrice);
|
|
359
|
-
|
|
360
|
-
if (quotedAmount < originalAmount) {
|
|
361
|
-
throw new Error('quotedAmount must be >= originalAmount');
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
if (quotedAmount > maxPrice) {
|
|
365
|
-
throw new Error('quotedAmount must be <= maxPrice');
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// Platform minimum: $0.05 = 50000 base units (6 decimals)
|
|
369
|
-
if (quotedAmount < 50000n) {
|
|
370
|
-
throw new Error('quotedAmount must be >= $0.05 (50000 base units)');
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// Expiry validation
|
|
374
|
-
if (params.expiresAt) {
|
|
375
|
-
const now = Math.floor(Date.now() / 1000);
|
|
376
|
-
if (params.expiresAt <= now) {
|
|
377
|
-
throw new Error('expiresAt must be in the future');
|
|
378
|
-
}
|
|
379
|
-
if (params.expiresAt > now + 86400) {
|
|
380
|
-
throw new Error('expiresAt cannot be more than 24 hours in future');
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// DID format validation
|
|
385
|
-
if (!params.provider.startsWith('did:ethr:')) {
|
|
386
|
-
throw new Error('provider must be valid did:ethr format');
|
|
387
|
-
}
|
|
388
|
-
if (!params.consumer.startsWith('did:ethr:')) {
|
|
389
|
-
throw new Error('consumer must be valid did:ethr format');
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// Transaction ID format
|
|
393
|
-
if (!/^0x[a-fA-F0-9]{64}$/.test(params.txId)) {
|
|
394
|
-
throw new Error('txId must be valid bytes32 hex string');
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Kernel address format
|
|
398
|
-
if (!/^0x[a-fA-F0-9]{40}$/.test(params.kernelAddress)) {
|
|
399
|
-
throw new Error('kernelAddress must be valid Ethereum address');
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// ChainId validation
|
|
403
|
-
if (params.chainId !== 84532 && params.chainId !== 8453) {
|
|
404
|
-
throw new Error('chainId must be 84532 (Base Sepolia) or 8453 (Base Mainnet)');
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* Validate quote message schema
|
|
410
|
-
* Reference: AIP-2 §2.1, §5.1
|
|
411
|
-
*
|
|
412
|
-
* @param quote - Quote message
|
|
413
|
-
* @throws Error if validation fails
|
|
414
|
-
*/
|
|
415
|
-
private validateQuoteSchema(quote: QuoteMessage): void {
|
|
416
|
-
if (quote.type !== 'agirails.quote.v1') {
|
|
417
|
-
throw new Error('Invalid message type');
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
if (!/^\d+\.\d+\.\d+$/.test(quote.version)) {
|
|
421
|
-
throw new Error('Invalid version format');
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
if (!/^0x[a-fA-F0-9]{64}$/.test(quote.txId)) {
|
|
425
|
-
throw new Error('Invalid txId format');
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
if (!quote.provider.startsWith('did:ethr:')) {
|
|
429
|
-
throw new Error('Invalid provider DID format');
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
if (!quote.consumer.startsWith('did:ethr:')) {
|
|
433
|
-
throw new Error('Invalid consumer DID format');
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
if (!/^\d+$/.test(quote.quotedAmount)) {
|
|
437
|
-
throw new Error('Invalid quotedAmount format (must be numeric string)');
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
if (!/^\d+$/.test(quote.originalAmount)) {
|
|
441
|
-
throw new Error('Invalid originalAmount format (must be numeric string)');
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
if (!/^\d+$/.test(quote.maxPrice)) {
|
|
445
|
-
throw new Error('Invalid maxPrice format (must be numeric string)');
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
if (quote.currency !== 'USDC') {
|
|
449
|
-
throw new Error('Only USDC currency is supported');
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
if (quote.decimals !== 6) {
|
|
453
|
-
throw new Error('USDC must use 6 decimals');
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if (quote.chainId !== 84532 && quote.chainId !== 8453) {
|
|
457
|
-
throw new Error('Invalid chainId');
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
if (!/^0x[a-fA-F0-9]{130}$/.test(quote.signature)) {
|
|
461
|
-
throw new Error('Invalid signature format');
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
/**
|
|
466
|
-
* Extract Ethereum address from DID
|
|
467
|
-
* Supports: did:ethr:0x... and did:ethr:84532:0x...
|
|
468
|
-
* Reference: AIP-0 §2.1 (DID format)
|
|
469
|
-
*
|
|
470
|
-
* @param did - DID string
|
|
471
|
-
* @returns Ethereum address (0x-prefixed)
|
|
472
|
-
*/
|
|
473
|
-
private extractAddressFromDID(did: string): string {
|
|
474
|
-
const parts = did.replace('did:ethr:', '').split(':');
|
|
475
|
-
const address = parts.length === 2 ? parts[1] : parts[0];
|
|
476
|
-
|
|
477
|
-
if (!address.startsWith('0x') || address.length !== 42) {
|
|
478
|
-
throw new Error(`Invalid DID format: ${did}`);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
return address;
|
|
482
|
-
}
|
|
483
|
-
}
|
package/src/builders/index.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ACTP SDK Builders
|
|
3
|
-
* High-level builder classes for constructing ACTP messages
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export {
|
|
7
|
-
DeliveryProofBuilder,
|
|
8
|
-
DeliveryProofParams,
|
|
9
|
-
AGIRAILS_DELIVERY_SCHEMA_UID
|
|
10
|
-
} from './DeliveryProofBuilder';
|
|
11
|
-
|
|
12
|
-
export {
|
|
13
|
-
QuoteBuilder,
|
|
14
|
-
QuoteParams,
|
|
15
|
-
QuoteMessage,
|
|
16
|
-
AIP2QuoteTypes
|
|
17
|
-
} from './QuoteBuilder';
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Balance Command - Check USDC balance
|
|
3
|
-
*
|
|
4
|
-
* Shows the USDC balance for the current user or a specified address.
|
|
5
|
-
*
|
|
6
|
-
* @module cli/commands/balance
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { Command } from 'commander';
|
|
10
|
-
import { Output, ExitCode } from '../utils/output';
|
|
11
|
-
import { createClient, mapError } from '../utils/client';
|
|
12
|
-
import { loadConfig } from '../utils/config';
|
|
13
|
-
|
|
14
|
-
// ============================================================================
|
|
15
|
-
// Command Definition
|
|
16
|
-
// ============================================================================
|
|
17
|
-
|
|
18
|
-
export function createBalanceCommand(): Command {
|
|
19
|
-
const cmd = new Command('balance')
|
|
20
|
-
.description('Check USDC balance')
|
|
21
|
-
.argument('[address]', 'Address to check (defaults to your address)')
|
|
22
|
-
.option('--json', 'Output as JSON')
|
|
23
|
-
.option('-q, --quiet', 'Output only the balance amount')
|
|
24
|
-
.action(async (address, options) => {
|
|
25
|
-
const output = new Output(
|
|
26
|
-
options.json ? 'json' : options.quiet ? 'quiet' : 'human'
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
try {
|
|
30
|
-
await runBalance(address, output);
|
|
31
|
-
} catch (error) {
|
|
32
|
-
const structuredError = mapError(error);
|
|
33
|
-
output.errorResult({
|
|
34
|
-
code: structuredError.code,
|
|
35
|
-
message: structuredError.message,
|
|
36
|
-
details: structuredError.details,
|
|
37
|
-
});
|
|
38
|
-
process.exit(ExitCode.ERROR);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
return cmd;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ============================================================================
|
|
46
|
-
// Implementation
|
|
47
|
-
// ============================================================================
|
|
48
|
-
|
|
49
|
-
async function runBalance(
|
|
50
|
-
address: string | undefined,
|
|
51
|
-
output: Output
|
|
52
|
-
): Promise<void> {
|
|
53
|
-
// Load config to get default address
|
|
54
|
-
const config = loadConfig();
|
|
55
|
-
|
|
56
|
-
// Use specified address or default to config address
|
|
57
|
-
const targetAddress = address || config.address;
|
|
58
|
-
|
|
59
|
-
// Validate address format
|
|
60
|
-
if (!/^0x[a-fA-F0-9]{40}$/.test(targetAddress)) {
|
|
61
|
-
throw new Error(
|
|
62
|
-
`Invalid address format: "${targetAddress}"\n` +
|
|
63
|
-
'Expected 0x-prefixed 40-character hex string.'
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Create client and get balance
|
|
68
|
-
const client = await createClient();
|
|
69
|
-
const balanceWei = await client.getBalance(targetAddress.toLowerCase());
|
|
70
|
-
|
|
71
|
-
// Format balance
|
|
72
|
-
const balanceFormatted = formatUsdc(balanceWei);
|
|
73
|
-
const isOwnAddress = targetAddress.toLowerCase() === config.address.toLowerCase();
|
|
74
|
-
|
|
75
|
-
output.result(
|
|
76
|
-
{
|
|
77
|
-
address: targetAddress,
|
|
78
|
-
balance: `${balanceFormatted} USDC`,
|
|
79
|
-
balanceWei,
|
|
80
|
-
isYou: isOwnAddress,
|
|
81
|
-
},
|
|
82
|
-
{ quietKey: 'balance' }
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
// Additional info in human mode
|
|
86
|
-
if (balanceWei === '0') {
|
|
87
|
-
output.blank();
|
|
88
|
-
output.warning('Balance is zero.');
|
|
89
|
-
if (config.mode === 'mock') {
|
|
90
|
-
output.print(' Mint tokens: actp mint ' + targetAddress + ' 1000');
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Format USDC amount from wei to decimal with commas
|
|
97
|
-
*/
|
|
98
|
-
function formatUsdc(weiAmount: string): string {
|
|
99
|
-
const amount = BigInt(weiAmount);
|
|
100
|
-
const whole = amount / 1_000_000n;
|
|
101
|
-
const decimal = amount % 1_000_000n;
|
|
102
|
-
const decimalStr = decimal.toString().padStart(6, '0').slice(0, 2);
|
|
103
|
-
|
|
104
|
-
// Add thousands separators
|
|
105
|
-
const wholeFormatted = whole.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
106
|
-
|
|
107
|
-
return `${wholeFormatted}.${decimalStr}`;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export { runBalance };
|