@jinn-network/client 0.1.3-canary.2d6b2676 → 0.1.3-canary.8e61ba74
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/adapters/adapter.d.ts +15 -4
- package/dist/adapters/local/adapter.d.ts +9 -8
- package/dist/adapters/local/adapter.js +47 -74
- package/dist/adapters/local/adapter.js.map +1 -1
- package/dist/adapters/mech/adapter.d.ts +29 -13
- package/dist/adapters/mech/adapter.js +316 -311
- package/dist/adapters/mech/adapter.js.map +1 -1
- package/dist/adapters/mech/contracts.d.ts +62 -16
- package/dist/adapters/mech/contracts.js +226 -92
- package/dist/adapters/mech/contracts.js.map +1 -1
- package/dist/adapters/mech/safe-revert.js +0 -6
- package/dist/adapters/mech/safe-revert.js.map +1 -1
- package/dist/adapters/mech/types.d.ts +237 -84
- package/dist/adapters/mech/types.js +125 -50
- package/dist/adapters/mech/types.js.map +1 -1
- package/dist/agent/agent-ws.d.ts +1 -0
- package/dist/agent/agent-ws.js +13 -1
- package/dist/agent/agent-ws.js.map +1 -1
- package/dist/agent/operator-claude.js +4 -0
- package/dist/agent/operator-claude.js.map +1 -1
- package/dist/api/gather-status.d.ts +0 -1
- package/dist/api/gather-status.js +0 -1
- package/dist/api/gather-status.js.map +1 -1
- package/dist/api/setup-endpoints.d.ts +20 -0
- package/dist/api/setup-endpoints.js +110 -3
- package/dist/api/setup-endpoints.js.map +1 -1
- package/dist/build-info.json +4 -4
- package/dist/build-meta.json +1 -1
- package/dist/cli/commands/auth.js +6 -3
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/bootstrap.js +0 -1
- package/dist/cli/commands/bootstrap.js.map +1 -1
- package/dist/cli/commands/create.js +3 -3
- package/dist/cli/commands/doctor.js +4 -12
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/fleet-scale.js +0 -1
- package/dist/cli/commands/fleet-scale.js.map +1 -1
- package/dist/cli/commands/fund-requirements.js +0 -1
- package/dist/cli/commands/fund-requirements.js.map +1 -1
- package/dist/cli/commands/migrate-agent-id.js +0 -1
- package/dist/cli/commands/migrate-agent-id.js.map +1 -1
- package/dist/cli/commands/solver-nets.js +1 -1
- package/dist/cli/commands/solver-plugins.js +3 -1
- package/dist/cli/commands/solver-plugins.js.map +1 -1
- package/dist/cli/commands/tasks.js +20 -11
- package/dist/cli/commands/tasks.js.map +1 -1
- package/dist/cli/commands/version.js +0 -1
- package/dist/cli/commands/version.js.map +1 -1
- package/dist/cli/deployment-digest.js +0 -5
- package/dist/cli/deployment-digest.js.map +1 -1
- package/dist/cli/execution-context.js +0 -1
- package/dist/cli/execution-context.js.map +1 -1
- package/dist/cli/introspection-context.js +0 -1
- package/dist/cli/introspection-context.js.map +1 -1
- package/dist/config.d.ts +410 -22
- package/dist/config.js +41 -30
- package/dist/config.js.map +1 -1
- package/dist/daemon/creator.d.ts +3 -3
- package/dist/daemon/creator.js +3 -3
- package/dist/daemon/creator.js.map +1 -1
- package/dist/daemon/daemon.d.ts +3 -6
- package/dist/daemon/daemon.js +30 -9
- package/dist/daemon/daemon.js.map +1 -1
- package/dist/daemon/jinn-claim-loop-canonical.d.ts +11 -11
- package/dist/daemon/jinn-claim-loop-canonical.js +17 -17
- package/dist/daemon/jinn-claim-loop-canonical.js.map +1 -1
- package/dist/daemon/jinn-claim-loop-mock.d.ts +4 -4
- package/dist/daemon/jinn-claim-loop-mock.js +7 -7
- package/dist/daemon/jinn-claim-loop-mock.js.map +1 -1
- package/dist/daemon/jinn-claim-loop.d.ts +4 -4
- package/dist/daemon/jinn-claim-loop.js +3 -3
- package/dist/dashboard/assets/{index-Bxlk5qpa.js → index-CaUOdCs6.js} +6 -6
- package/dist/dashboard/index.html +1 -1
- package/dist/earning/bootstrap.d.ts +0 -1
- package/dist/earning/bootstrap.js +0 -1
- package/dist/earning/bootstrap.js.map +1 -1
- package/dist/earning/contracts.d.ts +18 -20
- package/dist/earning/contracts.js +18 -29
- package/dist/earning/contracts.js.map +1 -1
- package/dist/earning/funding-plan.d.ts +0 -1
- package/dist/earning/funding-plan.js +0 -1
- package/dist/earning/funding-plan.js.map +1 -1
- package/dist/earning/migrate-agent-id.d.ts +0 -1
- package/dist/earning/migrate-agent-id.js +0 -1
- package/dist/earning/migrate-agent-id.js.map +1 -1
- package/dist/erc8004/reputation.d.ts +2 -2
- package/dist/erc8004/reputation.js +2 -2
- package/dist/events/types.d.ts +2 -2
- package/dist/harnesses/engine/delivery.d.ts +10 -6
- package/dist/harnesses/engine/delivery.js +10 -6
- package/dist/harnesses/engine/delivery.js.map +1 -1
- package/dist/harnesses/engine/engine.d.ts +16 -29
- package/dist/harnesses/engine/engine.js +67 -106
- package/dist/harnesses/engine/engine.js.map +1 -1
- package/dist/harnesses/engine/persistence.d.ts +5 -1
- package/dist/harnesses/engine/persistence.js +10 -2
- package/dist/harnesses/engine/persistence.js.map +1 -1
- package/dist/harnesses/external-impls/loader.d.ts +1 -1
- package/dist/harnesses/impls/claude-code-learner/types.d.ts +1 -1
- package/dist/harnesses/impls/claude-mcp-prediction/index.d.ts +1 -1
- package/dist/harnesses/impls/claude-mcp-prediction/index.js +6 -6
- package/dist/harnesses/impls/claude-mcp-prediction/types.d.ts +1 -1
- package/dist/harnesses/impls/claude-mcp-prediction/types.js +1 -1
- package/dist/harnesses/impls/index.js +5 -5
- package/dist/harnesses/impls/portfolio-v0-evaluator/index.js +1 -1
- package/dist/harnesses/impls/portfolio-v0-evaluator/index.js.map +1 -1
- package/dist/harnesses/impls/prediction-v0-baseline/index.d.ts +4 -4
- package/dist/harnesses/impls/prediction-v0-baseline/index.js +10 -10
- package/dist/harnesses/impls/prediction-v0-evaluator/canonical-metrics.d.ts +3 -3
- package/dist/harnesses/impls/prediction-v0-evaluator/checks/availability.d.ts +1 -1
- package/dist/harnesses/impls/prediction-v0-evaluator/index.d.ts +4 -4
- package/dist/harnesses/impls/prediction-v0-evaluator/index.js +11 -11
- package/dist/harnesses/impls/prediction-v1-baseline/index.d.ts +31 -0
- package/dist/harnesses/impls/prediction-v1-baseline/index.js +79 -0
- package/dist/harnesses/impls/prediction-v1-baseline/index.js.map +1 -0
- package/dist/harnesses/impls/prediction-v1-evaluator/index.d.ts +32 -0
- package/dist/harnesses/impls/prediction-v1-evaluator/index.js +198 -0
- package/dist/harnesses/impls/prediction-v1-evaluator/index.js.map +1 -0
- package/dist/harnesses/manifest/types.d.ts +1 -1
- package/dist/harnesses/manifest/types.js +1 -1
- package/dist/harnesses/types.d.ts +2 -1
- package/dist/harnesses/types.js.map +1 -1
- package/dist/main.js +2 -26
- package/dist/main.js.map +1 -1
- package/dist/mcp/operator-server.js +1 -1
- package/dist/mcp/operator-server.js.map +1 -1
- package/dist/mcp/server.js +2 -2
- package/dist/plugins/manifest.d.ts +1 -1
- package/dist/plugins/manifest.js +1 -1
- package/dist/plugins/manifest.js.map +1 -1
- package/dist/plugins/registry.js +1 -1
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/resolvers.js +2 -1
- package/dist/plugins/resolvers.js.map +1 -1
- package/dist/plugins/types.d.ts +4 -8
- package/dist/plugins/validator.js +5 -7
- package/dist/plugins/validator.js.map +1 -1
- package/dist/preflight/claude-auth.d.ts +3 -1
- package/dist/preflight/claude-auth.js +5 -5
- package/dist/preflight/claude-auth.js.map +1 -1
- package/dist/setup/claude-code-install.d.ts +19 -0
- package/dist/setup/claude-code-install.js +51 -0
- package/dist/setup/claude-code-install.js.map +1 -0
- package/dist/solver-nets/contracts.d.ts +2 -0
- package/dist/solver-nets/contracts.js +2 -0
- package/dist/solver-nets/contracts.js.map +1 -0
- package/dist/solver-nets/registry.d.ts +2 -0
- package/dist/solver-nets/registry.js +13 -5
- package/dist/solver-nets/registry.js.map +1 -1
- package/dist/solver-types/constants.d.ts +1 -1
- package/dist/solver-types/constants.js +1 -1
- package/dist/solver-types/index.d.ts +5 -5
- package/dist/solver-types/index.js +5 -5
- package/dist/solver-types/prediction-apy-v0-auto.js +12 -0
- package/dist/solver-types/prediction-apy-v0-auto.js.map +1 -1
- package/dist/solver-types/prediction-v0-auto.d.ts +4 -4
- package/dist/solver-types/prediction-v0-auto.js +22 -10
- package/dist/solver-types/prediction-v0-auto.js.map +1 -1
- package/dist/solver-types/prediction-v0-template.d.ts +10 -10
- package/dist/solver-types/prediction-v0-template.js +16 -16
- package/dist/solver-types/prediction-v0-template.js.map +1 -1
- package/dist/solver-types/prediction-v0.d.ts +2 -2
- package/dist/solver-types/prediction-v0.js +11 -11
- package/dist/solver-types/prediction-v1-auto.d.ts +22 -0
- package/dist/solver-types/prediction-v1-auto.js +211 -0
- package/dist/solver-types/prediction-v1-auto.js.map +1 -0
- package/dist/solver-types/prediction-v1.d.ts +3 -0
- package/dist/solver-types/prediction-v1.js +29 -0
- package/dist/solver-types/prediction-v1.js.map +1 -0
- package/dist/solver-types/solver-type.d.ts +5 -4
- package/dist/store/store.d.ts +4 -0
- package/dist/store/store.js +28 -4
- package/dist/store/store.js.map +1 -1
- package/dist/tasks/posting-service.d.ts +5 -2
- package/dist/tasks/posting-service.js +12 -6
- package/dist/tasks/posting-service.js.map +1 -1
- package/dist/tasks/sources.d.ts +2 -2
- package/dist/tasks/sources.js +10 -7
- package/dist/tasks/sources.js.map +1 -1
- package/dist/templates/harnesses/alternative-harness/package.json.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/src/coordinator.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/src/index.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/src/mock-harness.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/src/phases/debrief.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/src/phases/execute.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/src/phases/improve.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/src/phases/memory.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/src/phases/orient.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/src/phases/plan.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/src/phases/strategize.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/test/coordinator.test.ts.tmpl +1 -1
- package/dist/templates/harnesses/alternative-harness/test/unit.test.ts.tmpl +1 -1
- package/dist/templates/harnesses/evaluator/package.json.tmpl +1 -1
- package/dist/templates/harnesses/evaluator/src/index.ts.tmpl +1 -1
- package/dist/templates/harnesses/evaluator/test/unit.test.ts.tmpl +1 -1
- package/dist/templates/harnesses/forecaster/package.json.tmpl +1 -1
- package/dist/templates/harnesses/forecaster/src/index.ts.tmpl +1 -1
- package/dist/templates/harnesses/forecaster/test/unit.test.ts.tmpl +1 -1
- package/dist/trajectory/schema.d.ts +10 -10
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/payloads/index.d.ts +1 -0
- package/dist/types/payloads/index.js +6 -0
- package/dist/types/payloads/index.js.map +1 -1
- package/dist/types/payloads/prediction-v1.d.ts +2 -0
- package/dist/types/payloads/prediction-v1.js +2 -0
- package/dist/types/payloads/prediction-v1.js.map +1 -0
- package/dist/types/prediction-v1.d.ts +2 -0
- package/dist/types/prediction-v1.js +2 -0
- package/dist/types/prediction-v1.js.map +1 -0
- package/dist/types/prediction.d.ts +559 -19
- package/dist/types/prediction.js +12 -9
- package/dist/types/prediction.js.map +1 -1
- package/dist/types/task-document.d.ts +389 -0
- package/dist/types/task-document.js +11 -0
- package/dist/types/task-document.js.map +1 -1
- package/dist/types/task.d.ts +285 -1
- package/dist/types/task.js +6 -1
- package/dist/types/task.js.map +1 -1
- package/dist/vendor/@jinn-network/sdk/README.md +61 -0
- package/dist/vendor/@jinn-network/sdk/dist/capabilities.d.ts +52 -0
- package/dist/vendor/@jinn-network/sdk/dist/capabilities.js +1 -0
- package/dist/vendor/@jinn-network/sdk/dist/contracts.d.ts +105 -0
- package/dist/vendor/@jinn-network/sdk/dist/contracts.js +147 -0
- package/dist/vendor/@jinn-network/sdk/dist/harness.d.ts +69 -0
- package/dist/vendor/@jinn-network/sdk/dist/harness.js +1 -0
- package/dist/vendor/@jinn-network/sdk/dist/index.d.ts +2 -0
- package/dist/vendor/@jinn-network/sdk/dist/index.js +5 -0
- package/dist/vendor/@jinn-network/sdk/dist/manifest.d.ts +69 -0
- package/dist/vendor/@jinn-network/sdk/dist/manifest.js +3 -0
- package/dist/vendor/@jinn-network/sdk/dist/payloads/prediction-v1.d.ts +223 -0
- package/dist/vendor/@jinn-network/sdk/dist/payloads/prediction-v1.js +64 -0
- package/dist/vendor/@jinn-network/sdk/dist/plugins.d.ts +36 -0
- package/dist/vendor/@jinn-network/sdk/dist/plugins.js +54 -0
- package/dist/vendor/@jinn-network/sdk/dist/prediction-v1.d.ts +870 -0
- package/dist/vendor/@jinn-network/sdk/dist/prediction-v1.js +80 -0
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/index.d.ts +2 -0
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/index.js +1 -0
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/prediction-v1.d.ts +6 -0
- package/dist/vendor/@jinn-network/sdk/dist/solvernets/prediction-v1.js +3 -0
- package/dist/vendor/@jinn-network/sdk/dist/types.d.ts +116 -0
- package/dist/vendor/@jinn-network/sdk/dist/types.js +21 -0
- package/dist/vendor/@jinn-network/sdk/package.json +34 -0
- package/dist/venues/polymarket/client.d.ts +77 -0
- package/dist/venues/polymarket/client.js +309 -0
- package/dist/venues/polymarket/client.js.map +1 -0
- package/dist/withdraw/run-withdraw-plan.js +0 -2
- package/dist/withdraw/run-withdraw-plan.js.map +1 -1
- package/package.json +8 -6
- package/plugins/jinn-prediction-plugin/.claude-plugin/plugin.json +13 -86
- package/plugins/jinn-prediction-plugin/.mcp.json +8 -0
- package/plugins/jinn-prediction-plugin/GEMINI.md +3 -0
- package/plugins/jinn-prediction-plugin/gemini-extension.json +13 -0
- package/plugins/jinn-prediction-plugin/jinn.plugin.json +23 -0
- package/plugins/jinn-prediction-plugin/schemas/prediction-v1-solution.schema.json +34 -0
- package/plugins/jinn-prediction-plugin/schemas/prediction-v1-task.schema.json +118 -0
- package/plugins/jinn-prediction-plugin/schemas/prediction-v1-verdict.schema.json +84 -0
- package/templates/harnesses/alternative-harness/package.json.tmpl +1 -1
- package/templates/harnesses/alternative-harness/src/coordinator.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/src/index.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/src/mock-harness.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/src/phases/debrief.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/src/phases/execute.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/src/phases/improve.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/src/phases/memory.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/src/phases/orient.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/src/phases/plan.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/src/phases/strategize.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/test/coordinator.test.ts.tmpl +1 -1
- package/templates/harnesses/alternative-harness/test/unit.test.ts.tmpl +1 -1
- package/templates/harnesses/evaluator/package.json.tmpl +1 -1
- package/templates/harnesses/evaluator/src/index.ts.tmpl +1 -1
- package/templates/harnesses/evaluator/test/unit.test.ts.tmpl +1 -1
- package/templates/harnesses/forecaster/package.json.tmpl +1 -1
- package/templates/harnesses/forecaster/src/index.ts.tmpl +1 -1
- package/templates/harnesses/forecaster/test/unit.test.ts.tmpl +1 -1
- package/dist/adapters/claim-registry/abi.d.ts +0 -127
- package/dist/adapters/claim-registry/abi.js +0 -93
- package/dist/adapters/claim-registry/abi.js.map +0 -1
- package/dist/adapters/claim-registry/client.d.ts +0 -98
- package/dist/adapters/claim-registry/client.js +0 -225
- package/dist/adapters/claim-registry/client.js.map +0 -1
- package/dist/adapters/mech/claim-policy.d.ts +0 -40
- package/dist/adapters/mech/claim-policy.js +0 -104
- package/dist/adapters/mech/claim-policy.js.map +0 -1
- package/dist/harnesses/engine/claim.d.ts +0 -69
- package/dist/harnesses/engine/claim.js +0 -111
- package/dist/harnesses/engine/claim.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getAddress } from 'viem';
|
|
2
|
-
import { keccak256 } from 'viem';
|
|
1
|
+
import { getAddress, zeroAddress } from 'viem';
|
|
2
|
+
import { keccak256, toBytes } from 'viem';
|
|
3
3
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
4
4
|
import { base, baseSepolia } from 'viem/chains';
|
|
5
5
|
import { PermanentError, parseTask } from '../../types/index.js';
|
|
@@ -7,13 +7,19 @@ import { createClients } from './safe.js';
|
|
|
7
7
|
import { buildResultPayload, uploadToIpfs, cidToDigestHex, fetchFromIpfs, fetchSignedTaskFromIpfs, fetchSignedEnvelopeFromIpfs, } from './ipfs.js';
|
|
8
8
|
import { canonicalJson } from '../../harnesses/engine/canonical-json.js';
|
|
9
9
|
import { SignedEnvelopeSchema } from '../../types/envelope.js';
|
|
10
|
-
import { submitTask,
|
|
11
|
-
import { MECH_MARKETPLACE_ABI } from './types.js';
|
|
12
|
-
import { AcceptAllPolicy } from './claim-policy.js';
|
|
10
|
+
import { submitTask, claimTask as claimTaskOnchain, claimEvaluation as claimEvaluationOnchain, claimDelivery, getMechDeliveryRate, getTimeoutBounds, decodeTaskCreatedLogs, decodeSolutionDeliveryClaimedLogs, decodeDeliverLogs, findLatestDeliveryDataHexForRequest, getMarketplaceRequestDeliveryMech, getTaskCidDigest, callDeliverToMarketplace, } from './contracts.js';
|
|
13
11
|
import { withRecoverableRetry } from '../../tx-retry.js';
|
|
14
12
|
import { formatRpcError } from '../../rpc-error-context.js';
|
|
15
|
-
import { RESTORATION_TASK_CID_CONTEXT_KEY,
|
|
13
|
+
import { RESTORATION_ENVELOPE_CID_CONTEXT_KEY, RESTORATION_TASK_CID_CONTEXT_KEY, } from '../../harnesses/impls/evaluation-context.js';
|
|
16
14
|
import { signTaskV1 } from '../../tasks/signing.js';
|
|
15
|
+
const ROUTER_REQUEST_CURSOR_CONFIG_KEY = 'mech_router_request_block_cursor_v1';
|
|
16
|
+
const PENDING_EVALUATION_SOLUTIONS_CONFIG_KEY = 'mech_pending_evaluation_solutions_v1';
|
|
17
|
+
const DEFAULT_MECH_CLAIM_POLICY = {
|
|
18
|
+
mode: 'exclusive',
|
|
19
|
+
maxClaims: 1,
|
|
20
|
+
maxClaimsPerOperator: 1,
|
|
21
|
+
claimLeaseTtlSeconds: 30 * 60,
|
|
22
|
+
};
|
|
17
23
|
export class MechAdapter {
|
|
18
24
|
name = 'mech';
|
|
19
25
|
publicClient;
|
|
@@ -23,27 +29,17 @@ export class MechAdapter {
|
|
|
23
29
|
requestBlockCursor = 0n;
|
|
24
30
|
deliveryBlockCursor = 0n;
|
|
25
31
|
pendingEvaluations = new Map();
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// Restoration result content cached across evaluation-job retries so a transient
|
|
31
|
-
// Safe/router failure does not silently strip evaluator context on the next poll.
|
|
32
|
-
pendingEvaluationResults = new Map();
|
|
33
|
-
// IPFS CID of the restoration envelope — threaded into evaluation context so
|
|
34
|
-
// evaluators can populate restorationEnvelope.cid without a synchronous IPFS fetch.
|
|
35
|
-
pendingEvaluationResultCids = new Map();
|
|
36
|
-
// RIDs with no delivery found in backfill window; avoids repeated 500k-block rescans.
|
|
37
|
-
backfillMissRids = new Set();
|
|
32
|
+
observedTasks = new Map();
|
|
33
|
+
requestKinds = new Map();
|
|
34
|
+
evaluationOpportunities = new Map();
|
|
35
|
+
pendingEvaluationSolutions = new Map();
|
|
38
36
|
// Original Tasks keyed by request ID (restoration and evaluation)
|
|
39
37
|
// so we can yield accurate Task in DeliveredResult
|
|
40
38
|
originalStates = new Map();
|
|
41
39
|
store;
|
|
42
|
-
claimPolicy;
|
|
43
40
|
constructor(config, store) {
|
|
44
41
|
this.config = config;
|
|
45
42
|
this.store = store;
|
|
46
|
-
this.claimPolicy = config.claimPolicy ?? new AcceptAllPolicy();
|
|
47
43
|
}
|
|
48
44
|
async initialize() {
|
|
49
45
|
const chain = this.config.chainId === 84532 ? baseSepolia : base;
|
|
@@ -64,102 +60,74 @@ export class MechAdapter {
|
|
|
64
60
|
this.deliveryBlockCursor = blockNumber;
|
|
65
61
|
// Recover pending state from on-chain events
|
|
66
62
|
if (this.store) {
|
|
63
|
+
this.loadPendingEvaluationSolutions();
|
|
67
64
|
await this.recoverPendingState(blockNumber);
|
|
68
65
|
}
|
|
69
66
|
}
|
|
70
67
|
async recoverPendingState(currentBlock) {
|
|
71
68
|
const fromBlock = this.store?.getLastProcessedBlock() ?? currentBlock;
|
|
72
|
-
if (fromBlock
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const restorations = await scanTasks(this.publicClient, this.config.routerAddress, this.config.safeAddress, fromBlock, currentBlock);
|
|
77
|
-
// Scan for evaluation jobs this creator posted
|
|
78
|
-
const evaluations = await scanEvaluationJobs(this.publicClient, this.config.routerAddress, this.config.safeAddress, fromBlock, currentBlock);
|
|
79
|
-
// Build set of restoration IDs that already have evaluation jobs
|
|
80
|
-
const hasEvaluation = new Set(evaluations.map(e => e.restorationRequestId));
|
|
81
|
-
// Check each restoration's delivery status
|
|
82
|
-
for (const restoration of restorations) {
|
|
83
|
-
if (hasEvaluation.has(restoration.requestId)) {
|
|
84
|
-
// Evaluation already created — check if eval delivery needs claiming
|
|
85
|
-
const evalJob = evaluations.find(e => e.restorationRequestId === restoration.requestId);
|
|
86
|
-
if (evalJob) {
|
|
87
|
-
const evalInfo = await this.publicClient.readContract({
|
|
88
|
-
address: this.config.mechMarketplaceAddress,
|
|
89
|
-
abi: MECH_MARKETPLACE_ABI,
|
|
90
|
-
functionName: 'mapRequestIdInfos',
|
|
91
|
-
args: [evalJob.requestId],
|
|
92
|
-
});
|
|
93
|
-
if (evalInfo[1] === '0x0000000000000000000000000000000000000000') {
|
|
94
|
-
// Evaluation not yet delivered — track it
|
|
95
|
-
this.pendingEvaluationClaims.add(evalJob.requestId);
|
|
96
|
-
}
|
|
97
|
-
// If delivered, fully complete — nothing to track
|
|
98
|
-
}
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
// No evaluation job yet — check delivery status
|
|
102
|
-
const info = await this.publicClient.readContract({
|
|
103
|
-
address: this.config.mechMarketplaceAddress,
|
|
104
|
-
abi: MECH_MARKETPLACE_ABI,
|
|
105
|
-
functionName: 'mapRequestIdInfos',
|
|
106
|
-
args: [restoration.requestId],
|
|
107
|
-
});
|
|
108
|
-
const deliveryMech = info[1];
|
|
109
|
-
if (deliveryMech === '0x0000000000000000000000000000000000000000') {
|
|
110
|
-
// Not delivered yet — track for evaluation after delivery
|
|
111
|
-
this.pendingEvaluations.set(restoration.requestId, {
|
|
112
|
-
id: restoration.requestId,
|
|
113
|
-
description: '', // Original description not available from events, but not needed for evaluation creation
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
// Delivered but no evaluation — needs claim + evaluation creation
|
|
118
|
-
this.pendingEvaluations.set(restoration.requestId, {
|
|
119
|
-
id: restoration.requestId,
|
|
120
|
-
description: '',
|
|
121
|
-
});
|
|
122
|
-
this.claimedButNotEvaluated.add(restoration.requestId);
|
|
123
|
-
}
|
|
69
|
+
if (fromBlock < currentBlock) {
|
|
70
|
+
console.error(`[mech] TaskCoordinator clean-break recovery starts at block ${fromBlock}; ` +
|
|
71
|
+
'old request-first recovery is intentionally disabled');
|
|
72
|
+
this.deliveryBlockCursor = fromBlock;
|
|
124
73
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
this.pendingEvaluationResultCids.set(requestId, envelopeCid);
|
|
151
|
-
this.backfillMissRids.delete(requestId);
|
|
152
|
-
}
|
|
153
|
-
catch (err) {
|
|
154
|
-
console.error(`[mech] recovery: could not load restoration result IPFS for ${requestId}:`, err);
|
|
74
|
+
const routerCursorRaw = this.store?.getConfigValue(ROUTER_REQUEST_CURSOR_CONFIG_KEY);
|
|
75
|
+
const routerFromBlock = routerCursorRaw != null
|
|
76
|
+
? BigInt(routerCursorRaw)
|
|
77
|
+
: fromBlock;
|
|
78
|
+
if (routerFromBlock < currentBlock) {
|
|
79
|
+
this.requestBlockCursor = routerFromBlock;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
loadPendingEvaluationSolutions() {
|
|
83
|
+
const raw = this.store?.getConfigValue(PENDING_EVALUATION_SOLUTIONS_CONFIG_KEY);
|
|
84
|
+
if (!raw)
|
|
85
|
+
return;
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(raw);
|
|
88
|
+
if (!Array.isArray(parsed))
|
|
89
|
+
return;
|
|
90
|
+
for (const value of parsed) {
|
|
91
|
+
if (value == null || typeof value !== 'object')
|
|
92
|
+
continue;
|
|
93
|
+
const item = value;
|
|
94
|
+
if (typeof item.taskId !== 'string' ||
|
|
95
|
+
typeof item.requestId !== 'string' ||
|
|
96
|
+
typeof item.operator !== 'string' ||
|
|
97
|
+
typeof item.attemptIndex !== 'number') {
|
|
98
|
+
continue;
|
|
155
99
|
}
|
|
100
|
+
const solution = {
|
|
101
|
+
taskId: item.taskId,
|
|
102
|
+
attemptIndex: item.attemptIndex,
|
|
103
|
+
requestId: item.requestId,
|
|
104
|
+
operator: item.operator,
|
|
105
|
+
transactionHash: typeof item.transactionHash === 'string'
|
|
106
|
+
? item.transactionHash
|
|
107
|
+
: undefined,
|
|
108
|
+
blockNumber: typeof item.blockNumber === 'number' ? item.blockNumber : undefined,
|
|
109
|
+
};
|
|
110
|
+
this.pendingEvaluationSolutions.set(solution.requestId, solution);
|
|
156
111
|
}
|
|
157
112
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
console.error(`[mech] Recovered: ${this.pendingEvaluations.size} pending evaluations, ${this.pendingEvaluationClaims.size} pending eval claims, ${this.claimedButNotEvaluated.size} claimed but not evaluated`);
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.error('[mech] Failed to load pending evaluation solutions:', err);
|
|
161
115
|
}
|
|
162
116
|
}
|
|
117
|
+
persistPendingEvaluationSolutions() {
|
|
118
|
+
if (!this.store)
|
|
119
|
+
return;
|
|
120
|
+
this.store.setConfigValue(PENDING_EVALUATION_SOLUTIONS_CONFIG_KEY, JSON.stringify(Array.from(this.pendingEvaluationSolutions.values())));
|
|
121
|
+
}
|
|
122
|
+
rememberPendingEvaluationSolution(solution) {
|
|
123
|
+
this.pendingEvaluationSolutions.set(solution.requestId, solution);
|
|
124
|
+
this.persistPendingEvaluationSolutions();
|
|
125
|
+
}
|
|
126
|
+
forgetPendingEvaluationSolution(requestId) {
|
|
127
|
+
if (!this.pendingEvaluationSolutions.delete(requestId))
|
|
128
|
+
return;
|
|
129
|
+
this.persistPendingEvaluationSolutions();
|
|
130
|
+
}
|
|
163
131
|
async postTask(state) {
|
|
164
132
|
const restorationState = {
|
|
165
133
|
...state,
|
|
@@ -177,25 +145,27 @@ export class MechAdapter {
|
|
|
177
145
|
const restorationTaskCid = `f01551220${digestNo0x}`;
|
|
178
146
|
const deliveryRate = await getMechDeliveryRate(this.publicClient, this.config.mechContractAddress);
|
|
179
147
|
const { max: maxTimeout } = await getTimeoutBounds(this.publicClient, this.config.mechMarketplaceAddress);
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
148
|
+
const solverTypeDigest = keccak256(toBytes(signedTask.solverType));
|
|
149
|
+
const policy = this.contractPolicyForTask(restorationState);
|
|
150
|
+
const taskSubmission = await submitTask(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, restorationDataHex, solverTypeDigest, policy, deliveryRate, deliveryRate, maxTimeout, this.config.evictionRecovery);
|
|
151
|
+
const announcement = {
|
|
152
|
+
taskId: taskSubmission.taskId,
|
|
153
|
+
task: {
|
|
154
|
+
...restorationState,
|
|
155
|
+
signedTask,
|
|
156
|
+
context: { ...(restorationState.context ?? {}), [RESTORATION_TASK_CID_CONTEXT_KEY]: restorationTaskCid },
|
|
157
|
+
},
|
|
158
|
+
taskCid: restorationTaskCid,
|
|
159
|
+
onchainCreationTx: taskSubmission.txHash,
|
|
160
|
+
onchainCreationBlock: taskSubmission.blockNumber,
|
|
161
|
+
};
|
|
162
|
+
this.observedTasks.set(taskSubmission.taskId, announcement);
|
|
163
|
+
return {
|
|
164
|
+
taskId: taskSubmission.taskId,
|
|
165
|
+
taskCid: restorationTaskCid,
|
|
166
|
+
txHash: taskSubmission.txHash,
|
|
167
|
+
blockNumber: taskSubmission.blockNumber,
|
|
195
168
|
};
|
|
196
|
-
this.pendingEvaluations.set(restorationRequestId, stateForEval);
|
|
197
|
-
this.originalStates.set(restorationRequestId, { ...stateForEval, role: 'restoration' });
|
|
198
|
-
return restorationRequestId;
|
|
199
169
|
}
|
|
200
170
|
async signTaskDocument(state) {
|
|
201
171
|
const now = Date.now();
|
|
@@ -218,6 +188,7 @@ export class MechAdapter {
|
|
|
218
188
|
window: state.window ?? { startTs: now, endTs: now + 86_400_000 },
|
|
219
189
|
spec: state.spec ?? {},
|
|
220
190
|
eligibility: state.eligibility ?? {},
|
|
191
|
+
claimPolicy: state.claimPolicy ?? DEFAULT_MECH_CLAIM_POLICY,
|
|
221
192
|
creator: {
|
|
222
193
|
safeAddress: getAddress(this.config.safeAddress),
|
|
223
194
|
agentEoa: account.address,
|
|
@@ -227,24 +198,159 @@ export class MechAdapter {
|
|
|
227
198
|
};
|
|
228
199
|
return signTaskV1(taskDoc, this.config.agentEoaPrivateKey);
|
|
229
200
|
}
|
|
230
|
-
|
|
201
|
+
contractPolicyForTask(state) {
|
|
202
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
203
|
+
const claimPolicy = state.claimPolicy ?? DEFAULT_MECH_CLAIM_POLICY;
|
|
204
|
+
const normalizeTs = (value, fallback) => {
|
|
205
|
+
const raw = value ?? fallback;
|
|
206
|
+
return BigInt(raw > 10_000_000_000 ? Math.floor(raw / 1000) : raw);
|
|
207
|
+
};
|
|
208
|
+
const claimWindowStart = normalizeTs(claimPolicy.claimWindowStartTs ?? state.window?.startTs, nowSeconds);
|
|
209
|
+
const claimWindowEnd = normalizeTs(claimPolicy.claimWindowEndTs ?? state.window?.endTs, nowSeconds + 30 * 60);
|
|
210
|
+
const submissionDeadline = normalizeTs(claimPolicy.submissionDeadlineTs, Number(claimWindowEnd) + claimPolicy.claimLeaseTtlSeconds);
|
|
211
|
+
return {
|
|
212
|
+
claimWindowStart,
|
|
213
|
+
claimWindowEnd,
|
|
214
|
+
submissionDeadline,
|
|
215
|
+
claimLeaseTtlSeconds: claimPolicy.claimLeaseTtlSeconds,
|
|
216
|
+
maxClaims: claimPolicy.maxClaims,
|
|
217
|
+
maxClaimsPerOperator: claimPolicy.maxClaimsPerOperator,
|
|
218
|
+
policyHook: (claimPolicy.policyHook ?? zeroAddress),
|
|
219
|
+
evaluationPolicy: {
|
|
220
|
+
requiredVerdicts: 1,
|
|
221
|
+
passThreshold: 1,
|
|
222
|
+
evaluationDeadline: submissionDeadline + BigInt(claimPolicy.claimLeaseTtlSeconds),
|
|
223
|
+
maxVerdictsPerEvaluator: 1,
|
|
224
|
+
disallowSolverSelfEvaluation: true,
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
buildEvaluationTask(params) {
|
|
229
|
+
return {
|
|
230
|
+
...params.task,
|
|
231
|
+
id: `${params.task.id}:evaluation:${params.attemptIndex}`,
|
|
232
|
+
role: 'evaluation',
|
|
233
|
+
restorationRequestId: params.solutionRequestId,
|
|
234
|
+
attemptId: params.solutionRequestId,
|
|
235
|
+
attemptNumber: params.attemptIndex,
|
|
236
|
+
context: {
|
|
237
|
+
...(params.task.context ?? {}),
|
|
238
|
+
restorationResult: params.resultData,
|
|
239
|
+
[RESTORATION_TASK_CID_CONTEXT_KEY]: params.task.context?.[RESTORATION_TASK_CID_CONTEXT_KEY] ?? params.taskCid,
|
|
240
|
+
[RESTORATION_ENVELOPE_CID_CONTEXT_KEY]: params.restorationEnvelopeCid,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
async restorationAnnouncementForTaskId(taskId) {
|
|
245
|
+
const cached = this.observedTasks.get(taskId);
|
|
246
|
+
if (cached)
|
|
247
|
+
return cached;
|
|
248
|
+
const taskCidDigest = await getTaskCidDigest(this.publicClient, this.config.routerAddress, taskId);
|
|
249
|
+
const digest = taskCidDigest.startsWith('0x') ? taskCidDigest.slice(2) : taskCidDigest;
|
|
250
|
+
const taskCid = `f01551220${digest}`;
|
|
251
|
+
const signed = await fetchSignedTaskFromIpfs(this.config.ipfsGatewayUrl, taskCid);
|
|
252
|
+
const task = parseTask({ signedTask: signed });
|
|
253
|
+
const announcement = {
|
|
254
|
+
taskId,
|
|
255
|
+
task,
|
|
256
|
+
taskCid,
|
|
257
|
+
};
|
|
258
|
+
this.observedTasks.set(taskId, announcement);
|
|
259
|
+
return announcement;
|
|
260
|
+
}
|
|
261
|
+
async deliveryEnvelopeCidForSolution(solution) {
|
|
262
|
+
const deliveryMech = await getMarketplaceRequestDeliveryMech(this.publicClient, this.config.mechMarketplaceAddress, solution.requestId);
|
|
263
|
+
const toBlock = solution.blockNumber != null
|
|
264
|
+
? BigInt(solution.blockNumber)
|
|
265
|
+
: await this.publicClient.getBlockNumber();
|
|
266
|
+
const configuredLookback = this.config.mechDeliverBackfillLookbackBlocks;
|
|
267
|
+
const fromBlock = configuredLookback == null
|
|
268
|
+
? 0n
|
|
269
|
+
: toBlock > configuredLookback
|
|
270
|
+
? toBlock - configuredLookback
|
|
271
|
+
: 0n;
|
|
272
|
+
const deliveryDataHex = await findLatestDeliveryDataHexForRequest(this.publicClient, deliveryMech, solution.requestId, fromBlock, toBlock);
|
|
273
|
+
if (!deliveryDataHex) {
|
|
274
|
+
throw new Error(`No Deliver event data found for solution ${solution.requestId} on mech ${deliveryMech} ` +
|
|
275
|
+
`between blocks ${fromBlock} and ${toBlock}`);
|
|
276
|
+
}
|
|
277
|
+
const digest = deliveryDataHex.startsWith('0x') ? deliveryDataHex.slice(2) : deliveryDataHex;
|
|
278
|
+
return `f01551220${digest}`;
|
|
279
|
+
}
|
|
280
|
+
async evaluationAnnouncementForSolution(solution) {
|
|
281
|
+
if (solution.operator.toLowerCase() === this.config.safeAddress.toLowerCase()) {
|
|
282
|
+
return undefined;
|
|
283
|
+
}
|
|
284
|
+
const restoration = await this.restorationAnnouncementForTaskId(solution.taskId);
|
|
285
|
+
const restorationEnvelopeCid = await this.deliveryEnvelopeCidForSolution(solution);
|
|
286
|
+
const resultPayload = await fetchFromIpfs(this.config.ipfsGatewayUrl, restorationEnvelopeCid);
|
|
287
|
+
const resultData = resultPayload.data ?? JSON.stringify(resultPayload);
|
|
288
|
+
const evaluationTask = this.buildEvaluationTask({
|
|
289
|
+
task: restoration.task,
|
|
290
|
+
solutionRequestId: solution.requestId,
|
|
291
|
+
attemptIndex: solution.attemptIndex,
|
|
292
|
+
resultData,
|
|
293
|
+
restorationEnvelopeCid,
|
|
294
|
+
taskCid: restoration.taskCid,
|
|
295
|
+
});
|
|
296
|
+
const opportunityId = `evaluation:${solution.taskId}:${solution.attemptIndex}:${solution.requestId}`;
|
|
297
|
+
const announcement = {
|
|
298
|
+
taskId: opportunityId,
|
|
299
|
+
task: evaluationTask,
|
|
300
|
+
taskCid: restoration.taskCid,
|
|
301
|
+
onchainCreationTx: solution.transactionHash,
|
|
302
|
+
onchainCreationBlock: solution.blockNumber,
|
|
303
|
+
};
|
|
304
|
+
this.evaluationOpportunities.set(opportunityId, {
|
|
305
|
+
taskId: solution.taskId,
|
|
306
|
+
attemptIndex: solution.attemptIndex,
|
|
307
|
+
task: evaluationTask,
|
|
308
|
+
});
|
|
309
|
+
this.observedTasks.set(opportunityId, announcement);
|
|
310
|
+
return announcement;
|
|
311
|
+
}
|
|
312
|
+
async *retryPendingEvaluationSolutions() {
|
|
313
|
+
for (const [requestId, solution] of Array.from(this.pendingEvaluationSolutions)) {
|
|
314
|
+
try {
|
|
315
|
+
const announcement = await this.evaluationAnnouncementForSolution(solution);
|
|
316
|
+
if (announcement) {
|
|
317
|
+
yield announcement;
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
this.forgetPendingEvaluationSolution(requestId);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
catch (err) {
|
|
324
|
+
console.error(`[mech] evaluation opportunity retry failed for ${requestId}:`, err);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async *watchForTasks() {
|
|
231
329
|
while (!this.stopped) {
|
|
232
330
|
try {
|
|
331
|
+
for await (const announcement of this.retryPendingEvaluationSolutions()) {
|
|
332
|
+
yield announcement;
|
|
333
|
+
}
|
|
233
334
|
const currentBlock = await this.publicClient.getBlockNumber();
|
|
234
335
|
if (currentBlock > this.requestBlockCursor) {
|
|
336
|
+
const fromBlock = this.requestBlockCursor + 1n;
|
|
235
337
|
const logs = await this.publicClient.getLogs({
|
|
236
|
-
address: this.config.
|
|
237
|
-
fromBlock
|
|
338
|
+
address: this.config.routerAddress,
|
|
339
|
+
fromBlock,
|
|
238
340
|
toBlock: currentBlock,
|
|
239
341
|
});
|
|
342
|
+
const submittedSolutions = decodeSolutionDeliveryClaimedLogs(logs);
|
|
343
|
+
for (const solution of submittedSolutions) {
|
|
344
|
+
this.rememberPendingEvaluationSolution(solution);
|
|
345
|
+
}
|
|
240
346
|
this.requestBlockCursor = currentBlock;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
347
|
+
if (this.store) {
|
|
348
|
+
this.store.setConfigValue(ROUTER_REQUEST_CURSOR_CONFIG_KEY, currentBlock.toString());
|
|
349
|
+
}
|
|
350
|
+
const createdTasks = decodeTaskCreatedLogs(logs);
|
|
351
|
+
for (const { taskId, taskCidDigest, transactionHash, blockNumber } of createdTasks) {
|
|
246
352
|
try {
|
|
247
|
-
const digest =
|
|
353
|
+
const digest = taskCidDigest.startsWith('0x') ? taskCidDigest.slice(2) : taskCidDigest;
|
|
248
354
|
// CIDv1 hex with raw codec (0x55) + sha2-256 (0x12) + 32-byte length (0x20).
|
|
249
355
|
// The Autonolas registry returns raw-codec CIDs when uploading files with
|
|
250
356
|
// cid-version=1 (Kubo default for files). This is confirmed by the existing
|
|
@@ -253,37 +359,80 @@ export class MechAdapter {
|
|
|
253
359
|
const taskCid = `f01551220${digest}`;
|
|
254
360
|
const signed = await fetchSignedTaskFromIpfs(this.config.ipfsGatewayUrl, taskCid);
|
|
255
361
|
const task = parseTask({ signedTask: signed });
|
|
256
|
-
|
|
257
|
-
|
|
362
|
+
const announcement = {
|
|
363
|
+
taskId,
|
|
258
364
|
task,
|
|
259
365
|
taskCid,
|
|
260
366
|
onchainCreationTx: transactionHash,
|
|
261
367
|
onchainCreationBlock: blockNumber,
|
|
262
368
|
};
|
|
369
|
+
this.observedTasks.set(taskId, announcement);
|
|
370
|
+
yield announcement;
|
|
263
371
|
}
|
|
264
372
|
catch (err) {
|
|
265
|
-
console.error(`[mech] Failed to parse
|
|
373
|
+
console.error(`[mech] Failed to parse task ${taskId}:`, err);
|
|
266
374
|
}
|
|
267
375
|
}
|
|
376
|
+
for await (const announcement of this.retryPendingEvaluationSolutions()) {
|
|
377
|
+
yield announcement;
|
|
378
|
+
}
|
|
268
379
|
}
|
|
269
380
|
}
|
|
270
381
|
catch (err) {
|
|
271
|
-
console.error('[mech] Error polling for
|
|
272
|
-
operation: '
|
|
382
|
+
console.error('[mech] Error polling for tasks:', formatRpcError(err, {
|
|
383
|
+
operation: 'pollTaskCreated',
|
|
273
384
|
chain: this.config.chainId === 84532 ? 'base-sepolia' : 'base',
|
|
274
385
|
rpcUrl: this.config.rpcUrl,
|
|
275
|
-
contract: this.config.
|
|
386
|
+
contract: this.config.routerAddress,
|
|
276
387
|
fromBlock: this.requestBlockCursor + 1n,
|
|
277
388
|
}));
|
|
278
389
|
}
|
|
279
390
|
await new Promise(r => setTimeout(r, this.config.pollIntervalMs));
|
|
280
391
|
}
|
|
281
392
|
}
|
|
282
|
-
async
|
|
283
|
-
const
|
|
284
|
-
if (
|
|
285
|
-
|
|
393
|
+
async claimTask(taskId) {
|
|
394
|
+
const evaluationOpportunity = this.evaluationOpportunities.get(taskId);
|
|
395
|
+
if (evaluationOpportunity) {
|
|
396
|
+
const signedEvaluationTask = await this.signTaskDocument(evaluationOpportunity.task);
|
|
397
|
+
const evaluationCid = await uploadToIpfs(this.config.ipfsRegistryUrl, signedEvaluationTask);
|
|
398
|
+
const evaluationTaskCidDigest = cidToDigestHex(evaluationCid);
|
|
399
|
+
const claimed = await this.claimEvaluation(evaluationOpportunity.taskId, evaluationOpportunity.attemptIndex, evaluationTaskCidDigest);
|
|
400
|
+
this.pendingEvaluations.set(claimed.requestId, evaluationOpportunity.task);
|
|
401
|
+
this.originalStates.set(claimed.requestId, evaluationOpportunity.task);
|
|
402
|
+
this.requestKinds.set(claimed.requestId, 'verdict');
|
|
403
|
+
this.evaluationOpportunities.delete(taskId);
|
|
404
|
+
const solutionRequestId = evaluationOpportunity.task.restorationRequestId;
|
|
405
|
+
if (solutionRequestId) {
|
|
406
|
+
this.forgetPendingEvaluationSolution(solutionRequestId);
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
requestId: claimed.requestId,
|
|
410
|
+
taskId: claimed.taskId,
|
|
411
|
+
attemptIndex: claimed.attemptIndex,
|
|
412
|
+
task: evaluationOpportunity.task,
|
|
413
|
+
taskCid: evaluationCid,
|
|
414
|
+
onchainCreationTx: claimed.txHash,
|
|
415
|
+
onchainCreationBlock: claimed.blockNumber,
|
|
416
|
+
};
|
|
286
417
|
}
|
|
418
|
+
const announcement = this.observedTasks.get(taskId);
|
|
419
|
+
if (!announcement) {
|
|
420
|
+
throw new PermanentError(`Cannot claim unknown task ${taskId}`);
|
|
421
|
+
}
|
|
422
|
+
const claimed = await claimTaskOnchain(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, taskId, this.config.mechContractAddress, this.config.evictionRecovery);
|
|
423
|
+
const task = announcement.task;
|
|
424
|
+
this.pendingEvaluations.set(claimed.requestId, task);
|
|
425
|
+
this.originalStates.set(claimed.requestId, { ...task, role: task.role ?? 'restoration' });
|
|
426
|
+
this.requestKinds.set(claimed.requestId, 'solution');
|
|
427
|
+
return {
|
|
428
|
+
requestId: claimed.requestId,
|
|
429
|
+
taskId: claimed.taskId,
|
|
430
|
+
attemptIndex: claimed.attemptIndex,
|
|
431
|
+
task,
|
|
432
|
+
taskCid: announcement.taskCid,
|
|
433
|
+
onchainCreationTx: claimed.txHash,
|
|
434
|
+
onchainCreationBlock: claimed.blockNumber,
|
|
435
|
+
};
|
|
287
436
|
}
|
|
288
437
|
async submitResult(requestId, result) {
|
|
289
438
|
const payload = buildResultPayload(requestId, result);
|
|
@@ -292,9 +441,21 @@ export class MechAdapter {
|
|
|
292
441
|
// Safe → AgentMech.deliverToMarketplace() → Marketplace.deliverMarketplace()
|
|
293
442
|
await callDeliverToMarketplace(this.publicClient, this.walletClient, this.config.safeAddress, this.config.mechContractAddress, [requestId], [deliveryDigest], this.config.evictionRecovery);
|
|
294
443
|
}
|
|
444
|
+
async claimEvaluation(taskId, attemptIndex, evaluationTaskCidDigest) {
|
|
445
|
+
const claimed = await claimEvaluationOnchain(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, taskId, attemptIndex, this.config.mechContractAddress, evaluationTaskCidDigest, this.config.evictionRecovery);
|
|
446
|
+
this.requestKinds.set(claimed.requestId, 'verdict');
|
|
447
|
+
return claimed;
|
|
448
|
+
}
|
|
449
|
+
async submitSolutionDelivery(requestId, solutionDigest) {
|
|
450
|
+
await claimDelivery(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, requestId, { variant: 'v3', kind: 'solution', evidenceHash: solutionDigest }, this.config.evictionRecovery);
|
|
451
|
+
}
|
|
452
|
+
async submitVerdictDelivery(requestId, verdictDigest, verdictCode = 1) {
|
|
453
|
+
await claimDelivery(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, requestId, { variant: 'v3', kind: 'verdict', evidenceHash: verdictDigest, verdictCode }, this.config.evictionRecovery);
|
|
454
|
+
}
|
|
295
455
|
async evidenceHashForDelivery(requestId, deliveryDataHex) {
|
|
296
|
-
if (this.config.routerClaimDeliveryVariant !== 'v2')
|
|
456
|
+
if (this.config.routerClaimDeliveryVariant !== 'v2' && this.config.routerClaimDeliveryVariant !== 'v3') {
|
|
297
457
|
return undefined;
|
|
458
|
+
}
|
|
298
459
|
const deliveryDigest = deliveryDataHex.startsWith('0x')
|
|
299
460
|
? deliveryDataHex.slice(2)
|
|
300
461
|
: deliveryDataHex;
|
|
@@ -320,7 +481,11 @@ export class MechAdapter {
|
|
|
320
481
|
return 'retry';
|
|
321
482
|
}
|
|
322
483
|
try {
|
|
323
|
-
await claimDelivery(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, requestId, {
|
|
484
|
+
await claimDelivery(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, requestId, {
|
|
485
|
+
variant: this.config.routerClaimDeliveryVariant,
|
|
486
|
+
kind: this.requestKinds.get(requestId) ?? 'solution',
|
|
487
|
+
evidenceHash,
|
|
488
|
+
}, this.config.evictionRecovery);
|
|
324
489
|
return 'claimed';
|
|
325
490
|
}
|
|
326
491
|
catch (err) {
|
|
@@ -353,12 +518,10 @@ export class MechAdapter {
|
|
|
353
518
|
// (a) Did this Safe DELIVER this? → claim it (counter credit goes to msg.sender)
|
|
354
519
|
// The Deliver event's mechAddress is mechServiceMultisig (the Safe that owns
|
|
355
520
|
// the mech), so we compare against this.config.safeAddress.
|
|
356
|
-
// (b) Did this Safe
|
|
357
|
-
// (trigger eval creation for restoration deliveries; clean up for eval deliveries)
|
|
521
|
+
// (b) Did this Safe claim the underlying Task? → act on the delivery.
|
|
358
522
|
const iDelivered = mechAddress.toLowerCase() === this.config.safeAddress.toLowerCase();
|
|
359
523
|
const iCreatedRestoration = this.pendingEvaluations.has(requestId);
|
|
360
|
-
|
|
361
|
-
if (!iDelivered && !iCreatedRestoration && !iCreatedEvaluation)
|
|
524
|
+
if (!iDelivered && !iCreatedRestoration)
|
|
362
525
|
continue;
|
|
363
526
|
// (a) Deliverer-side claim path: if this Safe delivered the request,
|
|
364
527
|
// claim it first so router counters credit the deliverer.
|
|
@@ -368,40 +531,14 @@ export class MechAdapter {
|
|
|
368
531
|
if (deliveryClaimStatus === 'retry')
|
|
369
532
|
continue;
|
|
370
533
|
}
|
|
371
|
-
// (b)
|
|
372
|
-
//
|
|
373
|
-
// `createEvaluationJob` can fire. Production engine deliveries
|
|
374
|
-
// usually claim atomically; this call is idempotent and also
|
|
375
|
-
// covers legacy/test adapter deliveries that only wrote to the
|
|
376
|
-
// marketplace.
|
|
534
|
+
// (b) Task-side claim path: if this request came from our Task
|
|
535
|
+
// claim, make sure JinnRouterV3 records the Solution submission.
|
|
377
536
|
if (iCreatedRestoration && deliveryClaimStatus !== 'claimed' && deliveryClaimStatus !== 'already-claimed') {
|
|
378
537
|
const creatorClaimStatus = await this.ensureDeliveryClaimed(requestId, deliveryDataHex);
|
|
379
538
|
if (creatorClaimStatus === 'retry')
|
|
380
539
|
continue;
|
|
381
540
|
}
|
|
382
|
-
// (c)
|
|
383
|
-
// The deliverer (someone else, or us if we also delivered) must have claimed first.
|
|
384
|
-
// tryCreateEvaluationJob calls verifyRestorationClaimed() which polls for the claim.
|
|
385
|
-
if (iCreatedRestoration) {
|
|
386
|
-
let restorationResultData;
|
|
387
|
-
let restorationEnvelopeCid;
|
|
388
|
-
try {
|
|
389
|
-
const digest = deliveryDataHex.startsWith('0x') ? deliveryDataHex.slice(2) : deliveryDataHex;
|
|
390
|
-
restorationEnvelopeCid = `f01551220${digest}`;
|
|
391
|
-
const payload = await fetchFromIpfs(this.config.ipfsGatewayUrl, restorationEnvelopeCid);
|
|
392
|
-
restorationResultData = payload.data ?? JSON.stringify(payload);
|
|
393
|
-
this.backfillMissRids.delete(requestId);
|
|
394
|
-
}
|
|
395
|
-
catch (err) {
|
|
396
|
-
console.error(`[mech] Failed to fetch restoration result for evaluation: ${requestId}`, err);
|
|
397
|
-
}
|
|
398
|
-
await this.tryCreateEvaluationJob(requestId, restorationResultData, restorationEnvelopeCid);
|
|
399
|
-
}
|
|
400
|
-
// (d) If I created the evaluation, clean up tracking once delivered.
|
|
401
|
-
if (iCreatedEvaluation) {
|
|
402
|
-
this.pendingEvaluationClaims.delete(requestId);
|
|
403
|
-
}
|
|
404
|
-
// (e) Yield the delivery result.
|
|
541
|
+
// (c) Yield the delivery result.
|
|
405
542
|
try {
|
|
406
543
|
const deliveryDigest = deliveryDataHex.startsWith('0x') ? deliveryDataHex.slice(2) : deliveryDataHex;
|
|
407
544
|
const resultPayload = await fetchFromIpfs(this.config.ipfsGatewayUrl, `f01551220${deliveryDigest}`);
|
|
@@ -422,18 +559,14 @@ export class MechAdapter {
|
|
|
422
559
|
};
|
|
423
560
|
// Clean up after yielding
|
|
424
561
|
this.originalStates.delete(requestId);
|
|
562
|
+
this.pendingEvaluations.delete(requestId);
|
|
563
|
+
this.requestKinds.delete(requestId);
|
|
425
564
|
}
|
|
426
565
|
catch (err) {
|
|
427
566
|
console.error(`[mech] Failed to parse delivery ${requestId}:`, err);
|
|
428
567
|
}
|
|
429
568
|
}
|
|
430
569
|
}
|
|
431
|
-
// After new Deliver events are processed (and `pendingEvaluationResults` may be warm),
|
|
432
|
-
// retry evaluation creation. Doing this *before* deliver processing can upload an
|
|
433
|
-
// evaluation Task without `restorationResult` in context.
|
|
434
|
-
for (const rid of [...this.claimedButNotEvaluated]) {
|
|
435
|
-
await this.tryCreateEvaluationJob(rid);
|
|
436
|
-
}
|
|
437
570
|
}
|
|
438
571
|
catch (err) {
|
|
439
572
|
console.error('[mech] Error polling for deliveries:', formatRpcError(err, {
|
|
@@ -451,134 +584,6 @@ export class MechAdapter {
|
|
|
451
584
|
await new Promise(r => setTimeout(r, this.config.pollIntervalMs));
|
|
452
585
|
}
|
|
453
586
|
}
|
|
454
|
-
async backfillRestorationResultFromChain(requestId) {
|
|
455
|
-
if (this.pendingEvaluationResults.has(requestId)) {
|
|
456
|
-
return this.pendingEvaluationResults.get(requestId);
|
|
457
|
-
}
|
|
458
|
-
if (this.backfillMissRids.has(requestId)) {
|
|
459
|
-
return undefined;
|
|
460
|
-
}
|
|
461
|
-
const currentBlock = await this.publicClient.getBlockNumber();
|
|
462
|
-
const lookbackBlocks = this.config.mechDeliverBackfillLookbackBlocks ?? 500000n;
|
|
463
|
-
const from = currentBlock > lookbackBlocks
|
|
464
|
-
? currentBlock - lookbackBlocks
|
|
465
|
-
: 1n;
|
|
466
|
-
const dhex = await findLatestDeliveryDataHexForRequest(this.publicClient, this.config.mechContractAddress, requestId, from, currentBlock);
|
|
467
|
-
if (!dhex) {
|
|
468
|
-
this.backfillMissRids.add(requestId);
|
|
469
|
-
return undefined;
|
|
470
|
-
}
|
|
471
|
-
try {
|
|
472
|
-
const d = String(dhex);
|
|
473
|
-
const dig = d.startsWith('0x') ? d.slice(2) : d;
|
|
474
|
-
const envelopeCid = `f01551220${dig}`;
|
|
475
|
-
const payload = (await fetchFromIpfs(this.config.ipfsGatewayUrl, envelopeCid));
|
|
476
|
-
const data = payload.data ?? JSON.stringify(payload);
|
|
477
|
-
this.pendingEvaluationResults.set(requestId, data);
|
|
478
|
-
this.pendingEvaluationResultCids.set(requestId, envelopeCid);
|
|
479
|
-
this.backfillMissRids.delete(requestId);
|
|
480
|
-
return data;
|
|
481
|
-
}
|
|
482
|
-
catch (err) {
|
|
483
|
-
console.error(`[mech] backfill: failed to load restoration result for ${requestId}:`, err);
|
|
484
|
-
return undefined;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
async tryCreateEvaluationJob(requestId, restorationResultData, restorationEnvelopeCid) {
|
|
488
|
-
if (!this.pendingEvaluations.has(requestId))
|
|
489
|
-
return;
|
|
490
|
-
const originalState = this.pendingEvaluations.get(requestId);
|
|
491
|
-
if (restorationResultData) {
|
|
492
|
-
this.pendingEvaluationResults.set(requestId, restorationResultData);
|
|
493
|
-
this.backfillMissRids.delete(requestId);
|
|
494
|
-
}
|
|
495
|
-
if (restorationEnvelopeCid) {
|
|
496
|
-
this.pendingEvaluationResultCids.set(requestId, restorationEnvelopeCid);
|
|
497
|
-
}
|
|
498
|
-
let cachedRestorationResultData = restorationResultData ?? this.pendingEvaluationResults.get(requestId);
|
|
499
|
-
if (cachedRestorationResultData == null) {
|
|
500
|
-
cachedRestorationResultData = await this.backfillRestorationResultFromChain(requestId);
|
|
501
|
-
}
|
|
502
|
-
if (cachedRestorationResultData == null) {
|
|
503
|
-
this.claimedButNotEvaluated.add(requestId);
|
|
504
|
-
console.error(`[mech] no restoration result yet for ${requestId} (evaluation job and IPFS upload deferred until Deliver or backfill)`);
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
const cachedEnvelopeCid = restorationEnvelopeCid ?? this.pendingEvaluationResultCids.get(requestId);
|
|
508
|
-
try {
|
|
509
|
-
const evaluationState = {
|
|
510
|
-
...originalState,
|
|
511
|
-
role: 'evaluation',
|
|
512
|
-
restorationRequestId: requestId,
|
|
513
|
-
context: {
|
|
514
|
-
...originalState.context,
|
|
515
|
-
restorationResult: cachedRestorationResultData,
|
|
516
|
-
...(cachedEnvelopeCid ? { [RESTORATION_ENVELOPE_CID_CONTEXT_KEY]: cachedEnvelopeCid } : {}),
|
|
517
|
-
},
|
|
518
|
-
};
|
|
519
|
-
const evaluationPayload = await this.signTaskDocument(evaluationState);
|
|
520
|
-
const evaluationCid = await uploadToIpfs(this.config.ipfsRegistryUrl, evaluationPayload);
|
|
521
|
-
const evaluationDataHex = cidToDigestHex(evaluationCid);
|
|
522
|
-
// Verify the restoration claim landed on-chain before submitting.
|
|
523
|
-
// RPC load balancers can serve stale state right after a write,
|
|
524
|
-
// causing the router's restorationDeliveryClaimed check to fail
|
|
525
|
-
// with RestorationNotClaimed (surfaces as Safe GS013).
|
|
526
|
-
const isClaimed = await this.verifyRestorationClaimed(requestId);
|
|
527
|
-
if (!isClaimed) {
|
|
528
|
-
console.error(`[mech] restorationDeliveryClaimed not yet visible for ${requestId} — will retry`);
|
|
529
|
-
this.claimedButNotEvaluated.add(requestId);
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
const deliveryRate = await getMechDeliveryRate(this.publicClient, this.config.mechContractAddress);
|
|
533
|
-
const { max: maxTimeout } = await getTimeoutBounds(this.publicClient, this.config.mechMarketplaceAddress);
|
|
534
|
-
const evalRequestIds = await submitEvaluationJob(this.publicClient, this.walletClient, this.config.safeAddress, this.config.routerAddress, requestId, this.config.mechContractAddress, evaluationDataHex, deliveryRate, maxTimeout, this.config.evictionRecovery);
|
|
535
|
-
if (evalRequestIds.length > 0) {
|
|
536
|
-
this.pendingEvaluationClaims.add(evalRequestIds[0]);
|
|
537
|
-
// Copy original state to evaluation request ID so delivery can use it
|
|
538
|
-
const origState = this.originalStates.get(requestId);
|
|
539
|
-
if (origState) {
|
|
540
|
-
this.originalStates.set(evalRequestIds[0], { ...origState, role: 'evaluation' });
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
// Success — clean up both tracking sets
|
|
544
|
-
this.pendingEvaluations.delete(requestId);
|
|
545
|
-
this.claimedButNotEvaluated.delete(requestId);
|
|
546
|
-
this.pendingEvaluationResults.delete(requestId);
|
|
547
|
-
this.pendingEvaluationResultCids.delete(requestId);
|
|
548
|
-
}
|
|
549
|
-
catch (err) {
|
|
550
|
-
console.error(`[mech] Failed to create evaluation job for ${requestId}:`, err);
|
|
551
|
-
// Track for retry on next poll cycle (doesn't require a new Deliver event)
|
|
552
|
-
this.claimedButNotEvaluated.add(requestId);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
async verifyRestorationClaimed(requestId) {
|
|
556
|
-
// RPC / fork can lag right after claimDelivery; give more room than 5×2s so
|
|
557
|
-
// tryCreateEvaluationJob succeeds on the first watchForDeliveries pass when possible.
|
|
558
|
-
const MAX_POLLS = 12;
|
|
559
|
-
const POLL_DELAY_MS = 1_500;
|
|
560
|
-
const abi = [{
|
|
561
|
-
type: 'function',
|
|
562
|
-
name: 'restorationDeliveryClaimed',
|
|
563
|
-
inputs: [{ name: 'requestId', type: 'bytes32' }],
|
|
564
|
-
outputs: [{ name: '', type: 'bool' }],
|
|
565
|
-
stateMutability: 'view',
|
|
566
|
-
}];
|
|
567
|
-
for (let i = 0; i < MAX_POLLS; i++) {
|
|
568
|
-
const claimed = await this.publicClient.readContract({
|
|
569
|
-
address: this.config.routerAddress,
|
|
570
|
-
abi,
|
|
571
|
-
functionName: 'restorationDeliveryClaimed',
|
|
572
|
-
args: [requestId],
|
|
573
|
-
});
|
|
574
|
-
if (claimed)
|
|
575
|
-
return true;
|
|
576
|
-
if (i < MAX_POLLS - 1) {
|
|
577
|
-
await new Promise(r => setTimeout(r, POLL_DELAY_MS));
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
return false;
|
|
581
|
-
}
|
|
582
587
|
async stop() {
|
|
583
588
|
this.stopped = true;
|
|
584
589
|
}
|