@agirails/sdk 2.0.1-beta → 2.0.2
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/LICENSE +190 -0
- package/README.md +116 -108
- package/bin/actp +10 -0
- package/dist/ACTPClient.d.ts +456 -33
- package/dist/ACTPClient.d.ts.map +1 -1
- package/dist/ACTPClient.js +477 -93
- package/dist/ACTPClient.js.map +1 -1
- package/dist/abi/AgentRegistry.json +782 -0
- package/dist/abi/EscrowVault.json +106 -38
- package/dist/abi/IdentityRegistry.json +316 -0
- package/dist/adapters/BaseAdapter.d.ts +231 -0
- package/dist/adapters/BaseAdapter.d.ts.map +1 -0
- package/dist/adapters/BaseAdapter.js +393 -0
- package/dist/adapters/BaseAdapter.js.map +1 -0
- package/dist/adapters/BeginnerAdapter.d.ts +152 -0
- package/dist/adapters/BeginnerAdapter.d.ts.map +1 -0
- package/dist/adapters/BeginnerAdapter.js +168 -0
- package/dist/adapters/BeginnerAdapter.js.map +1 -0
- package/dist/adapters/IntermediateAdapter.d.ts +211 -0
- package/dist/adapters/IntermediateAdapter.d.ts.map +1 -0
- package/dist/adapters/IntermediateAdapter.js +260 -0
- package/dist/adapters/IntermediateAdapter.js.map +1 -0
- package/dist/adapters/index.d.ts +15 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +26 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/builders/DeliveryProofBuilder.d.ts +60 -1
- package/dist/builders/DeliveryProofBuilder.d.ts.map +1 -1
- package/dist/builders/DeliveryProofBuilder.js +81 -5
- package/dist/builders/DeliveryProofBuilder.js.map +1 -1
- package/dist/builders/QuoteBuilder.d.ts +101 -0
- package/dist/builders/QuoteBuilder.d.ts.map +1 -1
- package/dist/builders/QuoteBuilder.js +120 -3
- package/dist/builders/QuoteBuilder.js.map +1 -1
- package/dist/builders/index.d.ts +4 -0
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +4 -0
- package/dist/builders/index.js.map +1 -1
- package/dist/cli/commands/balance.d.ts +13 -0
- package/dist/cli/commands/balance.d.ts.map +1 -0
- package/dist/cli/commands/balance.js +89 -0
- package/dist/cli/commands/balance.js.map +1 -0
- package/dist/cli/commands/batch.d.ts +24 -0
- package/dist/cli/commands/batch.d.ts.map +1 -0
- package/dist/cli/commands/batch.js +424 -0
- package/dist/cli/commands/batch.js.map +1 -0
- package/dist/cli/commands/config.d.ts +13 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +192 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +143 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/mint.d.ts +13 -0
- package/dist/cli/commands/mint.d.ts.map +1 -0
- package/dist/cli/commands/mint.js +91 -0
- package/dist/cli/commands/mint.js.map +1 -0
- package/dist/cli/commands/pay.d.ts +18 -0
- package/dist/cli/commands/pay.d.ts.map +1 -0
- package/dist/cli/commands/pay.js +87 -0
- package/dist/cli/commands/pay.js.map +1 -0
- package/dist/cli/commands/simulate.d.ts +32 -0
- package/dist/cli/commands/simulate.d.ts.map +1 -0
- package/dist/cli/commands/simulate.js +290 -0
- package/dist/cli/commands/simulate.js.map +1 -0
- package/dist/cli/commands/time.d.ts +29 -0
- package/dist/cli/commands/time.d.ts.map +1 -0
- package/dist/cli/commands/time.js +252 -0
- package/dist/cli/commands/time.js.map +1 -0
- package/dist/cli/commands/tx.d.ts +16 -0
- package/dist/cli/commands/tx.d.ts.map +1 -0
- package/dist/cli/commands/tx.js +379 -0
- package/dist/cli/commands/tx.js.map +1 -0
- package/dist/cli/commands/watch.d.ts +20 -0
- package/dist/cli/commands/watch.d.ts.map +1 -0
- package/dist/cli/commands/watch.js +160 -0
- package/dist/cli/commands/watch.js.map +1 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +104 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/client.d.ts +70 -0
- package/dist/cli/utils/client.d.ts.map +1 -0
- package/dist/cli/utils/client.js +240 -0
- package/dist/cli/utils/client.js.map +1 -0
- package/dist/cli/utils/config.d.ts +91 -0
- package/dist/cli/utils/config.d.ts.map +1 -0
- package/dist/cli/utils/config.js +240 -0
- package/dist/cli/utils/config.js.map +1 -0
- package/dist/cli/utils/output.d.ts +174 -0
- package/dist/cli/utils/output.d.ts.map +1 -0
- package/dist/cli/utils/output.js +380 -0
- package/dist/cli/utils/output.js.map +1 -0
- package/dist/config/networks.d.ts +28 -0
- package/dist/config/networks.d.ts.map +1 -1
- package/dist/config/networks.js +60 -12
- package/dist/config/networks.js.map +1 -1
- package/dist/errors/index.d.ts +165 -2
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +260 -2
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +61 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +141 -36
- package/dist/index.js.map +1 -1
- package/dist/level0/Provider.d.ts +106 -0
- package/dist/level0/Provider.d.ts.map +1 -0
- package/dist/level0/Provider.js +10 -0
- package/dist/level0/Provider.js.map +1 -0
- package/dist/level0/ServiceDirectory.d.ts +74 -0
- package/dist/level0/ServiceDirectory.d.ts.map +1 -0
- package/dist/level0/ServiceDirectory.js +122 -0
- package/dist/level0/ServiceDirectory.js.map +1 -0
- package/dist/level0/index.d.ts +10 -0
- package/dist/level0/index.d.ts.map +1 -0
- package/dist/level0/index.js +15 -0
- package/dist/level0/index.js.map +1 -0
- package/dist/level0/provide.d.ts +51 -0
- package/dist/level0/provide.d.ts.map +1 -0
- package/dist/level0/provide.js +113 -0
- package/dist/level0/provide.js.map +1 -0
- package/dist/level0/request.d.ts +53 -0
- package/dist/level0/request.d.ts.map +1 -0
- package/dist/level0/request.js +462 -0
- package/dist/level0/request.js.map +1 -0
- package/dist/level1/Agent.d.ts +472 -0
- package/dist/level1/Agent.d.ts.map +1 -0
- package/dist/level1/Agent.js +1091 -0
- package/dist/level1/Agent.js.map +1 -0
- package/dist/level1/index.d.ts +10 -0
- package/dist/level1/index.d.ts.map +1 -0
- package/dist/level1/index.js +30 -0
- package/dist/level1/index.js.map +1 -0
- package/dist/level1/pricing/PriceCalculator.d.ts +62 -0
- package/dist/level1/pricing/PriceCalculator.d.ts.map +1 -0
- package/dist/level1/pricing/PriceCalculator.js +237 -0
- package/dist/level1/pricing/PriceCalculator.js.map +1 -0
- package/dist/level1/pricing/PricingStrategy.d.ts +179 -0
- package/dist/level1/pricing/PricingStrategy.d.ts.map +1 -0
- package/dist/level1/pricing/PricingStrategy.js +11 -0
- package/dist/level1/pricing/PricingStrategy.js.map +1 -0
- package/dist/level1/types/Job.d.ts +166 -0
- package/dist/level1/types/Job.d.ts.map +1 -0
- package/dist/level1/types/Job.js +11 -0
- package/dist/level1/types/Job.js.map +1 -0
- package/dist/level1/types/Options.d.ts +258 -0
- package/dist/level1/types/Options.d.ts.map +1 -0
- package/dist/level1/types/Options.js +8 -0
- package/dist/level1/types/Options.js.map +1 -0
- package/dist/level1/types/index.d.ts +8 -0
- package/dist/level1/types/index.d.ts.map +1 -0
- package/dist/level1/types/index.js +8 -0
- package/dist/level1/types/index.js.map +1 -0
- package/dist/protocol/ACTPKernel.d.ts +229 -2
- package/dist/protocol/ACTPKernel.d.ts.map +1 -1
- package/dist/protocol/ACTPKernel.js +367 -33
- package/dist/protocol/ACTPKernel.js.map +1 -1
- package/dist/protocol/AgentRegistry.d.ts +177 -0
- package/dist/protocol/AgentRegistry.d.ts.map +1 -0
- package/dist/protocol/AgentRegistry.js +449 -0
- package/dist/protocol/AgentRegistry.js.map +1 -0
- package/dist/protocol/DIDManager.d.ts +289 -0
- package/dist/protocol/DIDManager.d.ts.map +1 -0
- package/dist/protocol/DIDManager.js +481 -0
- package/dist/protocol/DIDManager.js.map +1 -0
- package/dist/protocol/DIDResolver.d.ts +236 -0
- package/dist/protocol/DIDResolver.d.ts.map +1 -0
- package/dist/protocol/DIDResolver.js +495 -0
- package/dist/protocol/DIDResolver.js.map +1 -0
- package/dist/protocol/EASHelper.d.ts +57 -2
- package/dist/protocol/EASHelper.d.ts.map +1 -1
- package/dist/protocol/EASHelper.js +230 -37
- package/dist/protocol/EASHelper.js.map +1 -1
- package/dist/protocol/EscrowVault.d.ts +93 -2
- package/dist/protocol/EscrowVault.d.ts.map +1 -1
- package/dist/protocol/EscrowVault.js +122 -33
- package/dist/protocol/EscrowVault.js.map +1 -1
- package/dist/protocol/EventMonitor.d.ts +45 -1
- package/dist/protocol/EventMonitor.d.ts.map +1 -1
- package/dist/protocol/EventMonitor.js +64 -8
- package/dist/protocol/EventMonitor.js.map +1 -1
- package/dist/protocol/MessageSigner.d.ts +116 -2
- package/dist/protocol/MessageSigner.d.ts.map +1 -1
- package/dist/protocol/MessageSigner.js +215 -9
- package/dist/protocol/MessageSigner.js.map +1 -1
- package/dist/protocol/ProofGenerator.d.ts +93 -0
- package/dist/protocol/ProofGenerator.d.ts.map +1 -1
- package/dist/protocol/ProofGenerator.js +194 -9
- package/dist/protocol/ProofGenerator.js.map +1 -1
- package/dist/protocol/QuoteBuilder.d.ts +8 -0
- package/dist/protocol/QuoteBuilder.d.ts.map +1 -1
- package/dist/protocol/QuoteBuilder.js +8 -0
- package/dist/protocol/QuoteBuilder.js.map +1 -1
- package/dist/runtime/BlockchainRuntime.d.ts +360 -0
- package/dist/runtime/BlockchainRuntime.d.ts.map +1 -0
- package/dist/runtime/BlockchainRuntime.js +767 -0
- package/dist/runtime/BlockchainRuntime.js.map +1 -0
- package/dist/runtime/IACTPRuntime.d.ts +271 -0
- package/dist/runtime/IACTPRuntime.d.ts.map +1 -0
- package/dist/runtime/IACTPRuntime.js +15 -0
- package/dist/runtime/IACTPRuntime.js.map +1 -0
- package/dist/runtime/MockRuntime.d.ts +445 -0
- package/dist/runtime/MockRuntime.d.ts.map +1 -0
- package/dist/runtime/MockRuntime.js +1065 -0
- package/dist/runtime/MockRuntime.js.map +1 -0
- package/dist/runtime/MockStateManager.d.ts +233 -0
- package/dist/runtime/MockStateManager.d.ts.map +1 -0
- package/dist/runtime/MockStateManager.js +533 -0
- package/dist/runtime/MockStateManager.js.map +1 -0
- package/dist/runtime/index.d.ts +14 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +42 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/types/MockState.d.ts +167 -0
- package/dist/runtime/types/MockState.d.ts.map +1 -0
- package/dist/runtime/types/MockState.js +43 -0
- package/dist/runtime/types/MockState.js.map +1 -0
- package/dist/types/agent.d.ts +76 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +8 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/did.d.ts +192 -0
- package/dist/types/did.d.ts.map +1 -0
- package/dist/types/did.js +38 -0
- package/dist/types/did.js.map +1 -0
- package/dist/types/eip712.d.ts +34 -0
- package/dist/types/eip712.d.ts.map +1 -1
- package/dist/types/eip712.js +31 -5
- package/dist/types/eip712.js.map +1 -1
- package/dist/types/escrow.d.ts +17 -10
- package/dist/types/escrow.d.ts.map +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/message.d.ts +32 -0
- package/dist/types/message.d.ts.map +1 -1
- package/dist/types/message.js +4 -0
- package/dist/types/message.js.map +1 -1
- package/dist/types/state.d.ts +28 -0
- package/dist/types/state.d.ts.map +1 -1
- package/dist/types/state.js +37 -6
- package/dist/types/state.js.map +1 -1
- package/dist/types/transaction.d.ts +17 -0
- package/dist/types/transaction.d.ts.map +1 -1
- package/dist/utils/ErrorRecoveryGuide.d.ts +125 -0
- package/dist/utils/ErrorRecoveryGuide.d.ts.map +1 -0
- package/dist/utils/ErrorRecoveryGuide.js +579 -0
- package/dist/utils/ErrorRecoveryGuide.js.map +1 -0
- package/dist/utils/Helpers.d.ts +453 -0
- package/dist/utils/Helpers.d.ts.map +1 -0
- package/dist/utils/Helpers.js +623 -0
- package/dist/utils/Helpers.js.map +1 -0
- package/dist/utils/IPFSClient.d.ts +113 -0
- package/dist/utils/IPFSClient.d.ts.map +1 -1
- package/dist/utils/IPFSClient.js +128 -7
- package/dist/utils/IPFSClient.js.map +1 -1
- package/dist/utils/Logger.d.ts +195 -0
- package/dist/utils/Logger.d.ts.map +1 -0
- package/dist/utils/Logger.js +382 -0
- package/dist/utils/Logger.js.map +1 -0
- package/dist/utils/NonceManager.d.ts +234 -1
- package/dist/utils/NonceManager.d.ts.map +1 -1
- package/dist/utils/NonceManager.js +372 -7
- package/dist/utils/NonceManager.js.map +1 -1
- package/dist/utils/RateLimiter.d.ts +253 -0
- package/dist/utils/RateLimiter.d.ts.map +1 -0
- package/dist/utils/RateLimiter.js +424 -0
- package/dist/utils/RateLimiter.js.map +1 -0
- package/dist/utils/ReceivedNonceTracker.d.ts +175 -0
- package/dist/utils/ReceivedNonceTracker.d.ts.map +1 -1
- package/dist/utils/ReceivedNonceTracker.js +261 -5
- package/dist/utils/ReceivedNonceTracker.js.map +1 -1
- package/dist/utils/SDKLifecycle.d.ts +156 -0
- package/dist/utils/SDKLifecycle.d.ts.map +1 -0
- package/dist/utils/SDKLifecycle.js +347 -0
- package/dist/utils/SDKLifecycle.js.map +1 -0
- package/dist/utils/SecureNonce.d.ts +57 -0
- package/dist/utils/SecureNonce.d.ts.map +1 -0
- package/dist/utils/SecureNonce.js +80 -0
- package/dist/utils/SecureNonce.js.map +1 -0
- package/dist/utils/Semaphore.d.ts +123 -0
- package/dist/utils/Semaphore.d.ts.map +1 -0
- package/dist/utils/Semaphore.js +247 -0
- package/dist/utils/Semaphore.js.map +1 -0
- package/dist/utils/UsedAttestationTracker.d.ts +167 -0
- package/dist/utils/UsedAttestationTracker.d.ts.map +1 -0
- package/dist/utils/UsedAttestationTracker.js +309 -0
- package/dist/utils/UsedAttestationTracker.js.map +1 -0
- package/dist/utils/canonicalJson.d.ts +22 -0
- package/dist/utils/canonicalJson.d.ts.map +1 -1
- package/dist/utils/canonicalJson.js +26 -3
- package/dist/utils/canonicalJson.js.map +1 -1
- package/dist/utils/computeTypeHash.d.ts +14 -0
- package/dist/utils/computeTypeHash.d.ts.map +1 -1
- package/dist/utils/computeTypeHash.js +19 -2
- package/dist/utils/computeTypeHash.js.map +1 -1
- package/dist/utils/fsSafe.d.ts +14 -0
- package/dist/utils/fsSafe.d.ts.map +1 -0
- package/dist/utils/fsSafe.js +89 -0
- package/dist/utils/fsSafe.js.map +1 -0
- package/dist/utils/index.d.ts +15 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +51 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/security.d.ts +147 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +391 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/validation.d.ts +40 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +184 -7
- package/dist/utils/validation.js.map +1 -1
- package/package.json +54 -37
- package/src/ACTPClient.ts +692 -178
- package/src/abi/AgentRegistry.json +782 -0
- package/src/abi/EscrowVault.json +106 -38
- package/src/abi/IdentityRegistry.json +316 -0
- package/src/adapters/BaseAdapter.ts +473 -0
- package/src/adapters/BeginnerAdapter.ts +232 -0
- package/src/adapters/IntermediateAdapter.ts +316 -0
- package/src/adapters/index.ts +25 -0
- package/src/builders/DeliveryProofBuilder.ts +3 -2
- package/src/cli/commands/balance.ts +110 -0
- package/src/cli/commands/batch.ts +487 -0
- package/src/cli/commands/config.ts +231 -0
- package/src/cli/commands/init.ts +161 -0
- package/src/cli/commands/mint.ts +116 -0
- package/src/cli/commands/pay.ts +113 -0
- package/src/cli/commands/simulate.ts +345 -0
- package/src/cli/commands/time.ts +303 -0
- package/src/cli/commands/tx.ts +448 -0
- package/src/cli/commands/watch.ts +211 -0
- package/src/cli/index.ts +116 -0
- package/src/cli/utils/client.ts +249 -0
- package/src/cli/utils/config.ts +282 -0
- package/src/cli/utils/output.ts +465 -0
- package/src/config/networks.ts +32 -9
- package/src/errors/index.ts +298 -1
- package/src/index.ts +207 -71
- package/src/level0/Provider.ts +117 -0
- package/src/level0/ServiceDirectory.ts +131 -0
- package/src/level0/index.ts +10 -0
- package/src/level0/provide.ts +131 -0
- package/src/level0/request.ts +494 -0
- package/src/level1/Agent.ts +1432 -0
- package/src/level1/index.ts +10 -0
- package/src/level1/pricing/PriceCalculator.ts +255 -0
- package/src/level1/pricing/PricingStrategy.ts +198 -0
- package/src/level1/types/Job.ts +179 -0
- package/src/level1/types/Options.ts +291 -0
- package/src/level1/types/index.ts +8 -0
- package/src/protocol/ACTPKernel.ts +175 -23
- package/src/protocol/AgentRegistry.ts +559 -0
- package/src/protocol/DIDManager.ts +629 -0
- package/src/protocol/DIDResolver.ts +554 -0
- package/src/protocol/EASHelper.ts +230 -46
- package/src/protocol/EscrowVault.ts +68 -50
- package/src/protocol/EventMonitor.ts +44 -15
- package/src/protocol/MessageSigner.ts +193 -13
- package/src/protocol/ProofGenerator.ts +223 -4
- package/src/runtime/BlockchainRuntime.ts +993 -0
- package/src/runtime/IACTPRuntime.ts +284 -0
- package/src/runtime/MockRuntime.ts +1244 -0
- package/src/runtime/MockStateManager.ts +576 -0
- package/src/runtime/index.ts +25 -0
- package/src/runtime/types/MockState.ts +227 -0
- package/src/types/agent.ts +79 -0
- package/src/types/did.ts +223 -0
- package/src/types/escrow.ts +12 -11
- package/src/types/index.ts +5 -1
- package/src/types/state.ts +12 -3
- package/src/types/transaction.ts +4 -1
- package/src/utils/ErrorRecoveryGuide.ts +675 -0
- package/src/utils/Helpers.ts +688 -0
- package/src/utils/IPFSClient.ts +122 -5
- package/src/utils/Logger.ts +484 -0
- package/src/utils/NonceManager.ts +305 -8
- package/src/utils/RateLimiter.ts +534 -0
- package/src/utils/ReceivedNonceTracker.ts +170 -0
- package/src/utils/SDKLifecycle.ts +416 -0
- package/src/utils/SecureNonce.ts +78 -0
- package/src/utils/Semaphore.ts +276 -0
- package/src/utils/UsedAttestationTracker.ts +387 -0
- package/src/utils/fsSafe.ts +75 -0
- package/src/utils/index.ts +80 -0
- package/src/utils/security.ts +418 -0
- package/src/utils/validation.ts +164 -0
- package/src/__tests__/ProofGenerator.test.ts +0 -124
- package/src/__tests__/QuoteBuilder.test.ts +0 -516
- package/src/__tests__/StateMachine.test.ts +0 -82
- package/src/__tests__/builders/DeliveryProofBuilder.test.ts +0 -581
- package/src/__tests__/integration/ACTPClient.test.ts +0 -263
- package/src/__tests__/integration.test.ts +0 -289
- package/src/__tests__/protocol/EASHelper.test.ts +0 -472
- package/src/__tests__/protocol/EventMonitor.test.ts +0 -382
- package/src/__tests__/security/ACTPKernel.security.test.ts +0 -1167
- package/src/__tests__/security/EscrowVault.security.test.ts +0 -570
- package/src/__tests__/security/MessageSigner.security.test.ts +0 -286
- package/src/__tests__/security/NonceReplay.security.test.ts +0 -501
- package/src/__tests__/security/validation.security.test.ts +0 -376
- package/src/__tests__/utils/IPFSClient.test.ts +0 -262
- package/src/__tests__/utils/NonceManager.test.ts +0 -205
- package/src/__tests__/utils/canonicalJson.test.ts +0 -153
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AbiCoder, Signer } from 'ethers';
|
|
2
|
+
import { EAS } from '@ethereum-attestation-service/eas-sdk';
|
|
2
3
|
import { DeliveryProof } from '../types';
|
|
3
4
|
import { deliveryProofDataFromProof } from '../types/eip712';
|
|
5
|
+
import {
|
|
6
|
+
IUsedAttestationTracker,
|
|
7
|
+
InMemoryUsedAttestationTracker
|
|
8
|
+
} from '../utils/UsedAttestationTracker';
|
|
4
9
|
|
|
5
10
|
export interface EASConfig {
|
|
6
11
|
contractAddress: string;
|
|
@@ -15,18 +20,65 @@ export interface AttestationResponse {
|
|
|
15
20
|
/**
|
|
16
21
|
* EASHelper - utility wrapper for Ethereum Attestation Service interactions
|
|
17
22
|
*/
|
|
18
|
-
const EAS_ABI = [
|
|
19
|
-
'event Attested(address indexed attester, bytes32 indexed uid, bytes32 indexed schema)',
|
|
20
|
-
'function attest(tuple(bytes32 schema, tuple(address recipient, uint64 expirationTime, bool revocable, bytes32 refUID, bytes data) data) request) external returns (bytes32)',
|
|
21
|
-
'function revoke(tuple(bytes32 schema, bytes32 uid) request) external returns (bytes32)',
|
|
22
|
-
'function getAttestation(bytes32 uid) external view returns (tuple(bytes32 uid, bytes32 schema, address recipient, address attester, uint64 time, uint64 expirationTime, bool revocable, bytes32 refUID, bytes data, uint32 bump))'
|
|
23
|
-
];
|
|
24
|
-
|
|
25
23
|
export class EASHelper {
|
|
26
|
-
private readonly eas:
|
|
24
|
+
private readonly eas: EAS;
|
|
25
|
+
private readonly attestationTracker: IUsedAttestationTracker;
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Create EASHelper instance
|
|
29
|
+
*
|
|
30
|
+
* @param signer - Ethers signer for signing attestations
|
|
31
|
+
* @param config - EAS configuration
|
|
32
|
+
* @param attestationTracker - Optional tracker for replay attack prevention (C-1 fix)
|
|
33
|
+
*
|
|
34
|
+
* SECURITY FIX (NEW-M-2): Validates schema UID format in constructor
|
|
35
|
+
*/
|
|
36
|
+
constructor(
|
|
37
|
+
signer: Signer,
|
|
38
|
+
private readonly config: EASConfig,
|
|
39
|
+
attestationTracker?: IUsedAttestationTracker
|
|
40
|
+
) {
|
|
41
|
+
// SECURITY FIX (NEW-M-2): Validate schema UID format
|
|
42
|
+
if (!config.deliveryProofSchemaId || !/^0x[a-fA-F0-9]{64}$/.test(config.deliveryProofSchemaId)) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`Invalid deliveryProofSchemaId: must be bytes32 hex string (0x...). ` +
|
|
45
|
+
`Got: ${config.deliveryProofSchemaId}`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (config.deliveryProofSchemaId === '0x0000000000000000000000000000000000000000000000000000000000000000') {
|
|
50
|
+
throw new Error('deliveryProofSchemaId cannot be zero bytes32');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Use official EAS SDK wrapper to ensure ABI correctness across deployments
|
|
54
|
+
// (includes fields like revocationTime that are required for security checks).
|
|
55
|
+
this.eas = new EAS(config.contractAddress);
|
|
56
|
+
this.eas.connect(signer as any);
|
|
57
|
+
// SECURITY FIX (C-1): Use provided tracker or create new in-memory one
|
|
58
|
+
if (!attestationTracker) {
|
|
59
|
+
// SECURITY WARNING (HIGH-5): In-memory tracker does not persist across restarts!
|
|
60
|
+
// For production use, provide a FileBasedUsedAttestationTracker with a stateDirectory:
|
|
61
|
+
//
|
|
62
|
+
// import { FileBasedUsedAttestationTracker } from '../utils/UsedAttestationTracker';
|
|
63
|
+
// const tracker = new FileBasedUsedAttestationTracker('/path/to/state');
|
|
64
|
+
// const easHelper = new EASHelper(signer, config, tracker);
|
|
65
|
+
//
|
|
66
|
+
// Without persistence, attestation replay protection is lost on process restart,
|
|
67
|
+
// allowing potential double-spend attacks.
|
|
68
|
+
console.warn(
|
|
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
|
+
);
|
|
73
|
+
}
|
|
74
|
+
this.attestationTracker = attestationTracker || new InMemoryUsedAttestationTracker();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get the attestation tracker for external use
|
|
79
|
+
*/
|
|
80
|
+
getAttestationTracker(): IUsedAttestationTracker {
|
|
81
|
+
return this.attestationTracker;
|
|
30
82
|
}
|
|
31
83
|
|
|
32
84
|
/**
|
|
@@ -57,31 +109,26 @@ export class EASHelper {
|
|
|
57
109
|
schema: this.config.deliveryProofSchemaId,
|
|
58
110
|
data: {
|
|
59
111
|
recipient,
|
|
60
|
-
expirationTime,
|
|
112
|
+
expirationTime: BigInt(expirationTime),
|
|
61
113
|
revocable,
|
|
62
114
|
refUID: proof.txId,
|
|
63
|
-
data: encodedData
|
|
115
|
+
data: encodedData,
|
|
116
|
+
// For Base EAS, value is typically 0. Keep explicit to avoid ambiguity.
|
|
117
|
+
value: 0n
|
|
64
118
|
}
|
|
65
119
|
});
|
|
66
120
|
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const uid = attestedLog
|
|
79
|
-
? this.eas.interface.parseLog(attestedLog)?.args?.uid
|
|
80
|
-
: zeroPadValue('0x00', 32);
|
|
121
|
+
const uid = await tx.wait();
|
|
122
|
+
if (!uid || !/^0x[a-fA-F0-9]{64}$/.test(uid)) {
|
|
123
|
+
throw new Error(`Failed to obtain attestation UID from EAS transaction. Got: ${String(uid)}`);
|
|
124
|
+
}
|
|
125
|
+
if (uid === '0x0000000000000000000000000000000000000000000000000000000000000000') {
|
|
126
|
+
throw new Error('EAS returned zero UID for attestation (unexpected).');
|
|
127
|
+
}
|
|
81
128
|
|
|
82
129
|
return {
|
|
83
130
|
uid,
|
|
84
|
-
transactionHash:
|
|
131
|
+
transactionHash: tx.tx.hash
|
|
85
132
|
};
|
|
86
133
|
}
|
|
87
134
|
|
|
@@ -89,18 +136,24 @@ export class EASHelper {
|
|
|
89
136
|
* Revoke a previously issued attestation by UID.
|
|
90
137
|
*/
|
|
91
138
|
async revokeAttestation(uid: string): Promise<string> {
|
|
139
|
+
if (!uid || !/^0x[a-fA-F0-9]{64}$/.test(uid)) {
|
|
140
|
+
throw new Error(`Invalid attestation UID format: ${uid}`);
|
|
141
|
+
}
|
|
92
142
|
const tx = await this.eas.revoke({
|
|
93
143
|
schema: this.config.deliveryProofSchemaId,
|
|
94
|
-
uid
|
|
144
|
+
data: { uid }
|
|
95
145
|
});
|
|
96
|
-
|
|
97
|
-
return
|
|
146
|
+
await tx.wait();
|
|
147
|
+
return tx.tx.hash;
|
|
98
148
|
}
|
|
99
149
|
|
|
100
150
|
/**
|
|
101
151
|
* Fetch attestation data from the EAS contract.
|
|
102
152
|
*/
|
|
103
153
|
async getAttestation(uid: string) {
|
|
154
|
+
if (!uid || !/^0x[a-fA-F0-9]{64}$/.test(uid)) {
|
|
155
|
+
throw new Error(`Invalid attestation UID format: ${uid}`);
|
|
156
|
+
}
|
|
104
157
|
return await this.eas.getAttestation(uid);
|
|
105
158
|
}
|
|
106
159
|
|
|
@@ -125,6 +178,13 @@ export class EASHelper {
|
|
|
125
178
|
txId: string,
|
|
126
179
|
attestationUID: string
|
|
127
180
|
): Promise<boolean> {
|
|
181
|
+
if (!txId || !/^0x[a-fA-F0-9]{64}$/.test(txId)) {
|
|
182
|
+
throw new Error(`Invalid txId format (expected bytes32): ${txId}`);
|
|
183
|
+
}
|
|
184
|
+
if (!attestationUID || !/^0x[a-fA-F0-9]{64}$/.test(attestationUID)) {
|
|
185
|
+
throw new Error(`Invalid attestationUID format (expected bytes32): ${attestationUID}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
128
188
|
// 1. Fetch attestation from EAS contract
|
|
129
189
|
const attestation = await this.eas.getAttestation(attestationUID);
|
|
130
190
|
|
|
@@ -145,53 +205,177 @@ export class EASHelper {
|
|
|
145
205
|
// 4. Check revocation - EAS uses revocationTime field (not revoked boolean)
|
|
146
206
|
// revocationTime = 0 means not revoked
|
|
147
207
|
// revocationTime > 0 means revoked at that timestamp
|
|
148
|
-
|
|
149
|
-
const isRevoked =
|
|
208
|
+
const revocationTime = BigInt((attestation as any).revocationTime ?? 0);
|
|
209
|
+
const isRevoked = revocationTime > 0n;
|
|
210
|
+
|
|
150
211
|
if (isRevoked) {
|
|
151
212
|
throw new Error(
|
|
152
|
-
`Attestation has been revoked: ${attestationUID} (revoked at timestamp ${
|
|
213
|
+
`Attestation has been revoked: ${attestationUID} (revoked at timestamp ${revocationTime})`
|
|
153
214
|
);
|
|
154
215
|
}
|
|
155
216
|
|
|
156
217
|
// 5. Check expiration
|
|
157
218
|
// expirationTime = 0 means no expiration
|
|
158
219
|
// expirationTime > 0 means expires at that timestamp
|
|
159
|
-
|
|
220
|
+
const expirationTime = BigInt((attestation as any).expirationTime ?? 0);
|
|
221
|
+
if (expirationTime > 0n) {
|
|
160
222
|
const now = Math.floor(Date.now() / 1000);
|
|
161
|
-
if (Number(
|
|
223
|
+
if (Number(expirationTime) < now) {
|
|
162
224
|
throw new Error(
|
|
163
|
-
`Attestation has expired: ${attestationUID} (expired at ${
|
|
225
|
+
`Attestation has expired: ${attestationUID} (expired at ${expirationTime})`
|
|
164
226
|
);
|
|
165
227
|
}
|
|
166
228
|
}
|
|
167
229
|
|
|
168
230
|
// 6. Decode attestation data to extract txId
|
|
169
|
-
|
|
170
|
-
|
|
231
|
+
let attestedTxId: string = '';
|
|
232
|
+
|
|
171
233
|
try {
|
|
172
234
|
const abiCoder = AbiCoder.defaultAbiCoder();
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
235
|
+
const rawData: string = (attestation as any).data;
|
|
236
|
+
|
|
237
|
+
// Prefer AIP-6 decoding (current DX Playground schema)
|
|
238
|
+
// - Official AIP-6: bytes32 txId,string resultCID,bytes32 resultHash,uint256 deliveredAt
|
|
239
|
+
// - Test schema: + uint256 testTimestamp
|
|
240
|
+
try {
|
|
241
|
+
const decoded = abiCoder.decode(
|
|
242
|
+
['bytes32', 'string', 'bytes32', 'uint256', 'uint256'],
|
|
243
|
+
rawData
|
|
244
|
+
);
|
|
245
|
+
attestedTxId = decoded[0];
|
|
246
|
+
const resultCID: string = decoded[1];
|
|
247
|
+
const resultHash: string = decoded[2];
|
|
248
|
+
const deliveredAt: bigint = decoded[3];
|
|
249
|
+
|
|
250
|
+
if (!attestedTxId || !/^0x[a-fA-F0-9]{64}$/.test(attestedTxId)) {
|
|
251
|
+
throw new Error(`Decoded txId is not valid bytes32: ${attestedTxId}`);
|
|
252
|
+
}
|
|
253
|
+
if (typeof resultCID !== 'string' || resultCID.length === 0 || resultCID.length > 2048) {
|
|
254
|
+
throw new Error(`Decoded resultCID invalid length: ${resultCID?.length}`);
|
|
255
|
+
}
|
|
256
|
+
if (!resultHash || !/^0x[a-fA-F0-9]{64}$/.test(resultHash)) {
|
|
257
|
+
throw new Error(`Decoded resultHash is not valid bytes32: ${resultHash}`);
|
|
258
|
+
}
|
|
259
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
260
|
+
if (deliveredAt > now + 86400n) {
|
|
261
|
+
throw new Error(`Decoded deliveredAt is in far future: ${deliveredAt.toString()}`);
|
|
262
|
+
}
|
|
263
|
+
} catch (_e) {
|
|
264
|
+
// Fallback: official AIP-6 schema without testTimestamp
|
|
265
|
+
try {
|
|
266
|
+
const decoded = abiCoder.decode(
|
|
267
|
+
['bytes32', 'string', 'bytes32', 'uint256'],
|
|
268
|
+
rawData
|
|
269
|
+
);
|
|
270
|
+
attestedTxId = decoded[0];
|
|
271
|
+
const resultCID: string = decoded[1];
|
|
272
|
+
const resultHash: string = decoded[2];
|
|
273
|
+
const deliveredAt: bigint = decoded[3];
|
|
274
|
+
|
|
275
|
+
if (!attestedTxId || !/^0x[a-fA-F0-9]{64}$/.test(attestedTxId)) {
|
|
276
|
+
throw new Error(`Decoded txId is not valid bytes32: ${attestedTxId}`);
|
|
277
|
+
}
|
|
278
|
+
if (typeof resultCID !== 'string' || resultCID.length === 0 || resultCID.length > 2048) {
|
|
279
|
+
throw new Error(`Decoded resultCID invalid length: ${resultCID?.length}`);
|
|
280
|
+
}
|
|
281
|
+
if (!resultHash || !/^0x[a-fA-F0-9]{64}$/.test(resultHash)) {
|
|
282
|
+
throw new Error(`Decoded resultHash is not valid bytes32: ${resultHash}`);
|
|
283
|
+
}
|
|
284
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
285
|
+
if (deliveredAt > now + 86400n) {
|
|
286
|
+
throw new Error(`Decoded deliveredAt is in far future: ${deliveredAt.toString()}`);
|
|
287
|
+
}
|
|
288
|
+
} catch (__e) {
|
|
289
|
+
// Final fallback: legacy AIP-4 schema
|
|
290
|
+
// Schema: bytes32 txId, bytes32 contentHash, uint256 timestamp, string deliveryUrl, uint256 size, string mimeType
|
|
291
|
+
const decoded = abiCoder.decode(
|
|
292
|
+
['bytes32', 'bytes32', 'uint256', 'string', 'uint256', 'string'],
|
|
293
|
+
rawData
|
|
294
|
+
);
|
|
295
|
+
attestedTxId = decoded[0];
|
|
296
|
+
const contentHash: string = decoded[1];
|
|
297
|
+
const timestamp: bigint = decoded[2];
|
|
298
|
+
const deliveryUrl: string = decoded[3];
|
|
299
|
+
const size: bigint = decoded[4];
|
|
300
|
+
const mimeType: string = decoded[5];
|
|
301
|
+
|
|
302
|
+
if (!attestedTxId || !/^0x[a-fA-F0-9]{64}$/.test(attestedTxId)) {
|
|
303
|
+
throw new Error(`Decoded txId is not valid bytes32: ${attestedTxId}`);
|
|
304
|
+
}
|
|
305
|
+
if (!contentHash || !/^0x[a-fA-F0-9]{64}$/.test(contentHash)) {
|
|
306
|
+
throw new Error(`Decoded contentHash is not valid bytes32: ${contentHash}`);
|
|
307
|
+
}
|
|
308
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
309
|
+
if (timestamp > now + 86400n) {
|
|
310
|
+
throw new Error(`Decoded timestamp is in far future: ${timestamp.toString()}`);
|
|
311
|
+
}
|
|
312
|
+
if (typeof deliveryUrl !== 'string' || deliveryUrl.length > 2048) {
|
|
313
|
+
throw new Error('Decoded deliveryUrl too long');
|
|
314
|
+
}
|
|
315
|
+
if (size < 0n) {
|
|
316
|
+
throw new Error(`Decoded size is negative: ${size}`);
|
|
317
|
+
}
|
|
318
|
+
if (typeof mimeType !== 'string' || mimeType.length > 256) {
|
|
319
|
+
throw new Error('Decoded mimeType too long');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
178
324
|
} catch (error: any) {
|
|
179
325
|
throw new Error(
|
|
180
326
|
`Attestation data format mismatch: cannot decode attestation ${attestationUID}. ` +
|
|
181
|
-
`Expected AIP-4 delivery proof schema format. ` +
|
|
327
|
+
`Expected AIP-6 (preferred) or AIP-4 (legacy) delivery proof schema format. ` +
|
|
182
328
|
`Original error: ${error.message}`
|
|
183
329
|
);
|
|
184
330
|
}
|
|
185
331
|
|
|
186
332
|
// 7. Verify attestation txId matches expected transaction ID
|
|
187
|
-
if (attestedTxId !== txId) {
|
|
333
|
+
if (attestedTxId.toLowerCase() !== txId.toLowerCase()) {
|
|
188
334
|
throw new Error(
|
|
189
335
|
`Attestation txId mismatch: expected ${txId}, got ${attestedTxId}. ` +
|
|
190
336
|
`Provider may be attempting to use attestation from different transaction!`
|
|
191
337
|
);
|
|
192
338
|
}
|
|
193
339
|
|
|
340
|
+
// SECURITY FIX (C-1): Check if attestation has been used for a different transaction
|
|
341
|
+
if (!this.attestationTracker.isValidForTransaction(attestationUID, txId)) {
|
|
342
|
+
const usedFor = this.attestationTracker.getUsageForAttestation(attestationUID);
|
|
343
|
+
throw new Error(
|
|
344
|
+
`Attestation replay attack detected: attestation ${attestationUID} ` +
|
|
345
|
+
`was already used for transaction ${usedFor}. ` +
|
|
346
|
+
`Cannot reuse for transaction ${txId}.`
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Record this attestation as used for this transaction
|
|
351
|
+
const recorded = await this.attestationTracker.recordUsage(attestationUID, txId);
|
|
352
|
+
if (!recorded) {
|
|
353
|
+
const usedFor = this.attestationTracker.getUsageForAttestation(attestationUID);
|
|
354
|
+
throw new Error(
|
|
355
|
+
`Attestation replay attack detected: attestation ${attestationUID} ` +
|
|
356
|
+
`was already used for transaction ${usedFor}. Cannot reuse for ${txId}.`
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
194
360
|
// All checks passed
|
|
195
361
|
return true;
|
|
196
362
|
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Verify attestation for escrow release with mandatory replay protection
|
|
366
|
+
*
|
|
367
|
+
* SECURITY FIX (C-4): This method MUST be called before releaseEscrow()
|
|
368
|
+
* to prevent attestation replay attacks.
|
|
369
|
+
*
|
|
370
|
+
* @param txId - Expected transaction ID (bytes32)
|
|
371
|
+
* @param attestationUID - Attestation UID to verify (bytes32)
|
|
372
|
+
* @throws Error if verification fails or replay attack detected
|
|
373
|
+
*/
|
|
374
|
+
async verifyAndRecordForRelease(
|
|
375
|
+
txId: string,
|
|
376
|
+
attestationUID: string
|
|
377
|
+
): Promise<void> {
|
|
378
|
+
// Verify the attestation
|
|
379
|
+
await this.verifyDeliveryAttestation(txId, attestationUID);
|
|
380
|
+
}
|
|
197
381
|
}
|
|
@@ -20,15 +20,19 @@ interface GasOptions {
|
|
|
20
20
|
/**
|
|
21
21
|
* EscrowVault - Escrow contract wrapper
|
|
22
22
|
*
|
|
23
|
-
* IMPORTANT:
|
|
24
|
-
* inside ACTPKernel.linkEscrow()
|
|
25
|
-
*
|
|
23
|
+
* IMPORTANT:
|
|
24
|
+
* - Escrow creation happens atomically inside `ACTPKernel.linkEscrow()`.
|
|
25
|
+
* - Payout/refund functions are `onlyKernel` on-chain and MUST NOT be called by users.
|
|
26
|
+
*
|
|
27
|
+
* This module provides:
|
|
28
|
+
* - Helper methods for USDC approvals (requester → EscrowVault allowance)
|
|
29
|
+
* - Read-only access to escrow state (`escrows()` / `remaining()`)
|
|
26
30
|
*
|
|
27
31
|
* Workflow (per AIP-3):
|
|
28
32
|
* 1. Consumer approves USDC to EscrowVault address (use approveToken)
|
|
29
33
|
* 2. Consumer calls ACTPKernel.linkEscrow(txId, escrowVault, escrowId)
|
|
30
|
-
* 3. Kernel internally calls
|
|
31
|
-
* 4. Escrow pulls USDC from
|
|
34
|
+
* 3. Kernel internally calls IEscrowValidator.createEscrow(escrowId, requester, provider, amount)
|
|
35
|
+
* 4. Escrow pulls USDC from requester
|
|
32
36
|
*
|
|
33
37
|
* Reference: AIP-3 §3.2 (Escrow Linking Workflow), lines 258-336
|
|
34
38
|
*/
|
|
@@ -52,7 +56,6 @@ export class EscrowVault {
|
|
|
52
56
|
*/
|
|
53
57
|
private getGasBufferMultiplier(operation: string): number {
|
|
54
58
|
const buffers: Record<string, number> = {
|
|
55
|
-
'releaseEscrow': 1.30, // 30% - Multi-recipient disbursement
|
|
56
59
|
'approveToken': 1.20 // 20% - Standard ERC20 approval
|
|
57
60
|
};
|
|
58
61
|
|
|
@@ -62,12 +65,35 @@ export class EscrowVault {
|
|
|
62
65
|
/**
|
|
63
66
|
* Build transaction options with gas settings and estimated gas
|
|
64
67
|
* V6 Enhancement: Dynamic buffer based on operation type
|
|
68
|
+
*
|
|
69
|
+
* SECURITY FIX (NEW-C-1): Gas estimation manipulation attack protection
|
|
70
|
+
* - Enforces minimum gas floor regardless of estimate
|
|
71
|
+
* - Uses safe BigInt arithmetic with overflow detection
|
|
65
72
|
*/
|
|
66
73
|
private buildTxOptions(estimatedGas: bigint, operation: string = 'default'): any {
|
|
74
|
+
// SECURITY FIX (NEW-C-1): Minimum gas floor to prevent manipulation
|
|
75
|
+
// Malicious contracts could return artificially low gas estimates
|
|
76
|
+
const MIN_GAS_FLOOR = 100000n;
|
|
77
|
+
const safeEstimate = estimatedGas > MIN_GAS_FLOOR ? estimatedGas : MIN_GAS_FLOOR;
|
|
78
|
+
|
|
67
79
|
const bufferMultiplier = this.getGasBufferMultiplier(operation);
|
|
68
80
|
|
|
81
|
+
// SECURITY FIX (NEW-H-1): Safe BigInt arithmetic with overflow check
|
|
82
|
+
// Use 10000 denominator to avoid floating point precision issues
|
|
83
|
+
const bufferNumerator = BigInt(Math.floor(bufferMultiplier * 10000));
|
|
84
|
+
const bufferDenominator = 10000n;
|
|
85
|
+
const gasLimit = (safeEstimate * bufferNumerator) / bufferDenominator;
|
|
86
|
+
|
|
87
|
+
// Overflow detection: result should always be >= original estimate
|
|
88
|
+
if (gasLimit < safeEstimate) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`Gas calculation overflow detected for operation ${operation}. ` +
|
|
91
|
+
`Estimate: ${safeEstimate}, Buffer: ${bufferMultiplier}x, Result: ${gasLimit}`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
69
95
|
const options: any = {
|
|
70
|
-
gasLimit
|
|
96
|
+
gasLimit
|
|
71
97
|
};
|
|
72
98
|
|
|
73
99
|
if (this.gasSettings?.maxFeePerGas) {
|
|
@@ -87,6 +113,18 @@ export class EscrowVault {
|
|
|
87
113
|
return this.address;
|
|
88
114
|
}
|
|
89
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Get the underlying ethers Contract instance.
|
|
118
|
+
*
|
|
119
|
+
* SECURITY FIX (C-3): Provides public access to contract for EventMonitor
|
|
120
|
+
* instead of accessing private field via bracket notation.
|
|
121
|
+
*
|
|
122
|
+
* @returns ethers Contract instance
|
|
123
|
+
*/
|
|
124
|
+
getContract(): Contract {
|
|
125
|
+
return this.contract;
|
|
126
|
+
}
|
|
127
|
+
|
|
90
128
|
/**
|
|
91
129
|
* Approve USDC token for escrow creation
|
|
92
130
|
*
|
|
@@ -151,68 +189,48 @@ export class EscrowVault {
|
|
|
151
189
|
* Get escrow details
|
|
152
190
|
*/
|
|
153
191
|
async getEscrow(escrowId: string): Promise<Escrow> {
|
|
192
|
+
validateTxId(escrowId, 'escrowId');
|
|
154
193
|
const escrowData = await this.contract.escrows(escrowId);
|
|
155
194
|
|
|
156
195
|
return {
|
|
157
196
|
escrowId,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
token: escrowData.token,
|
|
197
|
+
requester: escrowData.requester,
|
|
198
|
+
provider: escrowData.provider,
|
|
161
199
|
amount: escrowData.amount,
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
released: escrowData.released
|
|
200
|
+
releasedAmount: escrowData.releasedAmount,
|
|
201
|
+
active: escrowData.active
|
|
165
202
|
};
|
|
166
203
|
}
|
|
167
204
|
|
|
168
205
|
/**
|
|
169
|
-
* Get escrow balance
|
|
206
|
+
* Get escrow remaining balance (amount - releasedAmount)
|
|
170
207
|
*/
|
|
171
208
|
async getEscrowBalance(escrowId: string): Promise<bigint> {
|
|
172
|
-
|
|
173
|
-
return
|
|
209
|
+
validateTxId(escrowId, 'escrowId');
|
|
210
|
+
return await this.contract.remaining(escrowId);
|
|
174
211
|
}
|
|
175
212
|
|
|
176
213
|
/**
|
|
177
|
-
*
|
|
178
|
-
*
|
|
214
|
+
* @deprecated
|
|
215
|
+
*
|
|
216
|
+
* Payouts/refunds are executed by ACTPKernel (on-chain) as part of state transitions.
|
|
217
|
+
* EscrowVault disbursement methods are `onlyKernel` and cannot be called by EOAs.
|
|
218
|
+
*
|
|
219
|
+
* Use:
|
|
220
|
+
* - `BlockchainRuntime.releaseEscrow(txId, attestationUID?)` (recommended)
|
|
221
|
+
* - or `ACTPKernel.transitionState(txId, State.SETTLED, proof)` (advanced)
|
|
179
222
|
*/
|
|
180
223
|
async releaseEscrow(
|
|
181
224
|
escrowId: string,
|
|
182
|
-
|
|
183
|
-
|
|
225
|
+
_recipients: string[],
|
|
226
|
+
_amounts: bigint[]
|
|
184
227
|
): Promise<void> {
|
|
185
|
-
// Input validation
|
|
186
228
|
validateTxId(escrowId, 'escrowId');
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (recipients.length === 0) {
|
|
193
|
-
throw new ValidationError('recipients', 'Must provide at least one recipient');
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Validate each recipient and amount
|
|
197
|
-
recipients.forEach((recipient, i) => {
|
|
198
|
-
validateAddress(recipient, `recipients[${i}]`);
|
|
199
|
-
validateAmount(amounts[i], `amounts[${i}]`);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
try {
|
|
203
|
-
// ethers v6: use getFunction()
|
|
204
|
-
const disburseFunc = this.contract.getFunction('disburse');
|
|
205
|
-
|
|
206
|
-
// Estimate gas with safety buffer (30% for multi-recipient disbursement)
|
|
207
|
-
const estimatedGas = await disburseFunc.estimateGas(escrowId, recipients, amounts);
|
|
208
|
-
const txOptions = this.buildTxOptions(estimatedGas, 'releaseEscrow');
|
|
209
|
-
|
|
210
|
-
const tx = await disburseFunc(escrowId, recipients, amounts, txOptions);
|
|
211
|
-
|
|
212
|
-
await tx.wait();
|
|
213
|
-
} catch (error: any) {
|
|
214
|
-
throw new TransactionRevertedError(error.transactionHash, error.reason || error.message);
|
|
215
|
-
}
|
|
229
|
+
throw new ValidationError(
|
|
230
|
+
'EscrowVault.releaseEscrow',
|
|
231
|
+
'Escrow payouts are performed by ACTPKernel (onlyKernel). ' +
|
|
232
|
+
'Use BlockchainRuntime.releaseEscrow(txId, attestationUID?) or ACTPKernel.transitionState(txId, SETTLED).'
|
|
233
|
+
);
|
|
216
234
|
}
|
|
217
235
|
|
|
218
236
|
/**
|
|
@@ -3,6 +3,12 @@ import { State, Transaction } from '../types';
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* EventMonitor - Listen to blockchain events
|
|
6
|
+
*
|
|
7
|
+
* SECURITY FIX (EVENT-MONITOR): Corrected event parameter order to match ABI.
|
|
8
|
+
* Per ACTPKernel.json, TransactionCreated signature is:
|
|
9
|
+
* (bytes32 indexed transactionId, address indexed requester, address indexed provider, uint256 amount, bytes32 serviceHash)
|
|
10
|
+
*
|
|
11
|
+
* Previous code had requester/provider swapped which caused wrong filter results.
|
|
6
12
|
*/
|
|
7
13
|
export class EventMonitor {
|
|
8
14
|
constructor(
|
|
@@ -55,18 +61,29 @@ export class EventMonitor {
|
|
|
55
61
|
|
|
56
62
|
/**
|
|
57
63
|
* Get all transactions for an address
|
|
58
|
-
*
|
|
64
|
+
*
|
|
65
|
+
* SECURITY FIX (EVENT-MONITOR): Corrected filter parameter order.
|
|
66
|
+
* Per ACTPKernel.json ABI, TransactionCreated event signature is:
|
|
67
|
+
* (bytes32 indexed transactionId, address indexed requester, address indexed provider, uint256 amount, bytes32 serviceHash)
|
|
68
|
+
*
|
|
69
|
+
* Filter order: TransactionCreated(txId, requester, provider)
|
|
70
|
+
* - To filter by requester: (null, address, null)
|
|
71
|
+
* - To filter by provider: (null, null, address)
|
|
72
|
+
*
|
|
73
|
+
* SECURITY FIX (EVENT-MONITOR): Use getTransaction() instead of transactions()
|
|
74
|
+
* The kernel contract exposes getTransaction(bytes32) not transactions(bytes32).
|
|
59
75
|
*/
|
|
60
76
|
async getTransactionHistory(
|
|
61
77
|
address: string,
|
|
62
78
|
role: 'requester' | 'provider' = 'requester'
|
|
63
79
|
): Promise<Transaction[]> {
|
|
64
|
-
// TransactionCreated event signature
|
|
65
|
-
//
|
|
80
|
+
// TransactionCreated event signature per ABI:
|
|
81
|
+
// (bytes32 indexed transactionId, address indexed requester, address indexed provider, uint256 amount, bytes32 serviceHash)
|
|
82
|
+
// Filter format: TransactionCreated(txId, requester, provider)
|
|
66
83
|
const filter =
|
|
67
84
|
role === 'requester'
|
|
68
|
-
? this.kernelContract.filters.TransactionCreated(null,
|
|
69
|
-
: this.kernelContract.filters.TransactionCreated(null,
|
|
85
|
+
? this.kernelContract.filters.TransactionCreated(null, address, null) // Match requester (2nd indexed param)
|
|
86
|
+
: this.kernelContract.filters.TransactionCreated(null, null, address); // Match provider (3rd indexed param)
|
|
70
87
|
|
|
71
88
|
const events = await this.kernelContract.queryFilter(filter);
|
|
72
89
|
|
|
@@ -77,20 +94,28 @@ export class EventMonitor {
|
|
|
77
94
|
throw new Error('Event does not contain args (not an EventLog)');
|
|
78
95
|
}
|
|
79
96
|
const txId = (event as EventLog).args?.transactionId;
|
|
80
|
-
|
|
97
|
+
|
|
98
|
+
// SECURITY FIX: Use getTransaction() - the actual ABI function
|
|
99
|
+
// Previous code called transactions(txId) which doesn't exist in ABI
|
|
100
|
+
const txData = await this.kernelContract.getTransaction(txId);
|
|
81
101
|
|
|
82
102
|
return {
|
|
83
|
-
txId: txData.transactionId,
|
|
103
|
+
txId: txData.transactionId || txId,
|
|
84
104
|
requester: txData.requester,
|
|
85
105
|
provider: txData.provider,
|
|
86
106
|
amount: txData.amount,
|
|
87
|
-
state: txData.state as State,
|
|
107
|
+
state: (typeof txData.state === 'bigint' ? Number(txData.state) : txData.state) as State,
|
|
88
108
|
createdAt: Number(txData.createdAt),
|
|
109
|
+
updatedAt: Number(txData.updatedAt),
|
|
89
110
|
deadline: Number(txData.deadline),
|
|
90
111
|
disputeWindow: Number(txData.disputeWindow),
|
|
91
112
|
escrowContract: txData.escrowContract,
|
|
92
113
|
escrowId: txData.escrowId,
|
|
93
|
-
|
|
114
|
+
serviceHash: txData.serviceHash,
|
|
115
|
+
attestationUID: txData.attestationUID,
|
|
116
|
+
// Use metadata field (quote hash for QUOTED state) if available, fallback to serviceHash
|
|
117
|
+
metadata: txData.metadata || txData.serviceHash,
|
|
118
|
+
platformFeeBpsLocked: Number(txData.platformFeeBpsLocked)
|
|
94
119
|
};
|
|
95
120
|
})
|
|
96
121
|
);
|
|
@@ -98,21 +123,25 @@ export class EventMonitor {
|
|
|
98
123
|
|
|
99
124
|
/**
|
|
100
125
|
* Subscribe to transaction creation events
|
|
101
|
-
*
|
|
126
|
+
*
|
|
127
|
+
* SECURITY FIX (EVENT-MONITOR): Corrected event parameter order.
|
|
128
|
+
* Per ACTPKernel.json ABI:
|
|
129
|
+
* TransactionCreated(bytes32 indexed transactionId, address indexed requester, address indexed provider, uint256 amount, bytes32 serviceHash)
|
|
102
130
|
*/
|
|
103
131
|
onTransactionCreated(
|
|
104
|
-
callback: (tx: { txId: string;
|
|
132
|
+
callback: (tx: { txId: string; requester: string; provider: string; amount: bigint; serviceHash?: string }) => void
|
|
105
133
|
): () => void {
|
|
106
134
|
const filter = this.kernelContract.filters.TransactionCreated();
|
|
107
135
|
|
|
108
|
-
// Event signature:
|
|
136
|
+
// Event signature per ABI: (txId, requester, provider, amount, serviceHash)
|
|
109
137
|
const listener = async (
|
|
110
138
|
txId: string,
|
|
111
|
-
provider: string,
|
|
112
139
|
requester: string,
|
|
113
|
-
|
|
140
|
+
provider: string,
|
|
141
|
+
amount: bigint,
|
|
142
|
+
serviceHash?: string
|
|
114
143
|
) => {
|
|
115
|
-
callback({ txId,
|
|
144
|
+
callback({ txId, requester, provider, amount, serviceHash });
|
|
116
145
|
};
|
|
117
146
|
|
|
118
147
|
this.kernelContract.on(filter, listener);
|