@totalreclaw/totalreclaw 3.3.12-rc.21 → 3.3.12-rc.23
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/SKILL.md +1 -1
- package/billing-cache.ts +49 -5
- package/config.ts +41 -1
- package/dist/billing-cache.js +37 -5
- package/dist/config.js +37 -1
- package/dist/index.js +5 -2
- package/dist/subgraph-store.js +33 -8
- package/dist/tr-cli.js +1 -1
- package/index.ts +5 -2
- package/package.json +2 -2
- package/skill.json +1 -1
- package/subgraph-store.ts +33 -8
- package/tr-cli.ts +1 -1
package/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: totalreclaw
|
|
3
3
|
description: "End-to-end encrypted, decentralized memory for OpenClaw. A native kind:memory provider — recall is automatic via memory_search/memory_get, and facts are captured in the background. Trigger on 'install TotalReclaw', 'set up TotalReclaw', 'restore my recovery phrase', any recall request ('what do you remember about me', 'what's my X'), AND any explicit remember request ('remember X', 'save X')."
|
|
4
|
-
version: 3.3.12-rc.
|
|
4
|
+
version: 3.3.12-rc.23
|
|
5
5
|
author: TotalReclaw Team
|
|
6
6
|
license: MIT
|
|
7
7
|
homepage: https://totalreclaw.xyz
|
package/billing-cache.ts
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
* - keeps the chain-id override in sync with the relay's authoritative
|
|
15
15
|
* `chain_id` (after ops-1 both tiers are on Gnosis 100; the client consumes
|
|
16
16
|
* the relay value verbatim — see `syncChainIdFromBilling`)
|
|
17
|
+
* - keeps the DataEdge-address override in sync with the relay's
|
|
18
|
+
* authoritative `data_edge_address` (staging vs prod contract; consumed
|
|
19
|
+
* verbatim — see `syncDataEdgeAddressFromBilling`, #460)
|
|
17
20
|
* - does NOT import anything that performs outbound I/O
|
|
18
21
|
*
|
|
19
22
|
* Do NOT add any outbound-request call to this file — a single match for
|
|
@@ -24,7 +27,10 @@
|
|
|
24
27
|
|
|
25
28
|
import fs from 'node:fs';
|
|
26
29
|
import path from 'node:path';
|
|
27
|
-
import { CONFIG, setChainIdOverride } from './config.js';
|
|
30
|
+
import { CONFIG, setChainIdOverride, setDataEdgeAddressOverride } from './config.js';
|
|
31
|
+
|
|
32
|
+
/** A plausible EVM address — anything else from billing is ignored (#460). */
|
|
33
|
+
const DATA_EDGE_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
28
34
|
|
|
29
35
|
// ---------------------------------------------------------------------------
|
|
30
36
|
// Constants
|
|
@@ -57,6 +63,13 @@ export interface BillingCache {
|
|
|
57
63
|
* source of truth, so the client consumes this verbatim (#402).
|
|
58
64
|
*/
|
|
59
65
|
chain_id?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Authoritative DataEdge contract address from the relay
|
|
68
|
+
* `/v1/billing/status` response. Staging returns the isolated staging
|
|
69
|
+
* DataEdge, production the prod DataEdge; the client consumes this verbatim
|
|
70
|
+
* so writes and reads land on the same contract (#460).
|
|
71
|
+
*/
|
|
72
|
+
data_edge_address?: string;
|
|
60
73
|
checked_at: number;
|
|
61
74
|
}
|
|
62
75
|
|
|
@@ -82,6 +95,34 @@ export function syncChainIdFromBilling(chainId: number | undefined): void {
|
|
|
82
95
|
setChainIdOverride(typeof chainId === 'number' && Number.isFinite(chainId) ? chainId : 100);
|
|
83
96
|
}
|
|
84
97
|
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// DataEdge-address sync
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Apply the relay's authoritative `data_edge_address` to the runtime DataEdge
|
|
104
|
+
* override. Mirrors `syncChainIdFromBilling`.
|
|
105
|
+
*
|
|
106
|
+
* The relay routes each environment to its own DataEdge (staging is on-chain
|
|
107
|
+
* isolated). If the client ignores this and uses the WASM-baked default (the
|
|
108
|
+
* PROD DataEdge), writes against the staging relay mine on the prod contract
|
|
109
|
+
* while reads come from the staging subgraph → empty recall + phantom
|
|
110
|
+
* "stored=N" success (#460).
|
|
111
|
+
*
|
|
112
|
+
* A missing / malformed `data_edge_address` (older relay, partial payload,
|
|
113
|
+
* junk) clears the override (`null`) so resolution falls through to the WASM
|
|
114
|
+
* default — never a stale value. Only a plausible address
|
|
115
|
+
* (`0x` + 40 hex) is honored. Called from `readBillingCache` and
|
|
116
|
+
* `writeBillingCache` so every cache read or write keeps the override in sync.
|
|
117
|
+
* Idempotent. The explicit env override (`TOTALRECLAW_DATA_EDGE_ADDRESS`)
|
|
118
|
+
* still wins — it is the first term in `getSubgraphConfig`.
|
|
119
|
+
*/
|
|
120
|
+
export function syncDataEdgeAddressFromBilling(address: string | undefined): void {
|
|
121
|
+
setDataEdgeAddressOverride(
|
|
122
|
+
typeof address === 'string' && DATA_EDGE_ADDRESS_RE.test(address) ? address : null,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
85
126
|
// ---------------------------------------------------------------------------
|
|
86
127
|
// Read / write
|
|
87
128
|
// ---------------------------------------------------------------------------
|
|
@@ -99,9 +140,10 @@ export function readBillingCache(): BillingCache | null {
|
|
|
99
140
|
if (!fs.existsSync(BILLING_CACHE_PATH)) return null;
|
|
100
141
|
const raw = JSON.parse(fs.readFileSync(BILLING_CACHE_PATH, 'utf-8')) as BillingCache;
|
|
101
142
|
if (!raw.checked_at || Date.now() - raw.checked_at > BILLING_CACHE_TTL) return null;
|
|
102
|
-
// Keep chain
|
|
103
|
-
// across process restarts.
|
|
143
|
+
// Keep chain + DataEdge overrides in sync with the persisted authoritative
|
|
144
|
+
// values across process restarts.
|
|
104
145
|
syncChainIdFromBilling(raw.chain_id);
|
|
146
|
+
syncDataEdgeAddressFromBilling(raw.data_edge_address);
|
|
105
147
|
return raw;
|
|
106
148
|
} catch {
|
|
107
149
|
return null;
|
|
@@ -121,7 +163,9 @@ export function writeBillingCache(cache: BillingCache): void {
|
|
|
121
163
|
} catch {
|
|
122
164
|
// Best-effort — don't block on cache write failure.
|
|
123
165
|
}
|
|
124
|
-
// Sync chain
|
|
125
|
-
//
|
|
166
|
+
// Sync chain + DataEdge overrides AFTER the write so in-process UserOp
|
|
167
|
+
// signing + subgraph reads pick up the correct chain and contract
|
|
168
|
+
// immediately, even if the disk write failed.
|
|
126
169
|
syncChainIdFromBilling(cache.chain_id);
|
|
170
|
+
syncDataEdgeAddressFromBilling(cache.data_edge_address);
|
|
127
171
|
}
|
package/config.ts
CHANGED
|
@@ -122,6 +122,39 @@ export function __resetChainIdOverrideForTests(): void {
|
|
|
122
122
|
_chainIdOverride = null;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Runtime override for the DataEdge contract address, set after the relay
|
|
127
|
+
* billing response is read. The relay returns an authoritative
|
|
128
|
+
* `data_edge_address` in `/v1/billing/status` (staging routes to the isolated
|
|
129
|
+
* staging DataEdge, production to the prod DataEdge). Chain-aware clients MUST
|
|
130
|
+
* consume it verbatim — otherwise writes mine on the WASM-baked prod DataEdge
|
|
131
|
+
* while reads hit the relay's subgraph, so recall silently returns empty
|
|
132
|
+
* against staging (#460). Mirrors `_chainIdOverride`.
|
|
133
|
+
*
|
|
134
|
+
* `null` means "no billing override" → fall through to the WASM default. The
|
|
135
|
+
* explicit operator env override (`TOTALRECLAW_DATA_EDGE_ADDRESS`, exposed as
|
|
136
|
+
* `CONFIG.dataEdgeAddress`) always wins over this.
|
|
137
|
+
*/
|
|
138
|
+
let _dataEdgeAddressOverride: string | null = null;
|
|
139
|
+
|
|
140
|
+
export function setDataEdgeAddressOverride(address: string | null): void {
|
|
141
|
+
_dataEdgeAddressOverride = address;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Read the billing-sourced DataEdge override (or `''` when unset). Used by
|
|
146
|
+
* `getSubgraphConfig` as the middle term of the env → billing → WASM-default
|
|
147
|
+
* resolution order (#460).
|
|
148
|
+
*/
|
|
149
|
+
export function getDataEdgeAddressOverride(): string {
|
|
150
|
+
return _dataEdgeAddressOverride ?? '';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Reset the DataEdge override — used by tests. */
|
|
154
|
+
export function __resetDataEdgeAddressOverrideForTests(): void {
|
|
155
|
+
_dataEdgeAddressOverride = null;
|
|
156
|
+
}
|
|
157
|
+
|
|
125
158
|
export const CONFIG = {
|
|
126
159
|
// Core — recoveryPhrase reads from override first, then env var.
|
|
127
160
|
// Use getRecoveryPhrase() for dynamic access; this property is for
|
|
@@ -235,7 +268,14 @@ export const CONFIG = {
|
|
|
235
268
|
get chainId(): number {
|
|
236
269
|
return _chainIdOverride ?? 100;
|
|
237
270
|
},
|
|
238
|
-
|
|
271
|
+
// Explicit operator env override for the DataEdge contract. Stays env-only:
|
|
272
|
+
// it is the FIRST term of `getSubgraphConfig`'s env → billing → WASM-default
|
|
273
|
+
// resolution order, so it wins over the relay's authoritative
|
|
274
|
+
// `data_edge_address` (see `getDataEdgeAddressOverride` / #460). Getter, not
|
|
275
|
+
// a literal, so it reflects the live env rather than freezing at module load.
|
|
276
|
+
get dataEdgeAddress(): string {
|
|
277
|
+
return process.env.TOTALRECLAW_DATA_EDGE_ADDRESS || '';
|
|
278
|
+
},
|
|
239
279
|
entryPointAddress: process.env.TOTALRECLAW_ENTRYPOINT_ADDRESS || '',
|
|
240
280
|
rpcUrl: process.env.TOTALRECLAW_RPC_URL || '',
|
|
241
281
|
|
package/dist/billing-cache.js
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
* - keeps the chain-id override in sync with the relay's authoritative
|
|
15
15
|
* `chain_id` (after ops-1 both tiers are on Gnosis 100; the client consumes
|
|
16
16
|
* the relay value verbatim — see `syncChainIdFromBilling`)
|
|
17
|
+
* - keeps the DataEdge-address override in sync with the relay's
|
|
18
|
+
* authoritative `data_edge_address` (staging vs prod contract; consumed
|
|
19
|
+
* verbatim — see `syncDataEdgeAddressFromBilling`, #460)
|
|
17
20
|
* - does NOT import anything that performs outbound I/O
|
|
18
21
|
*
|
|
19
22
|
* Do NOT add any outbound-request call to this file — a single match for
|
|
@@ -23,7 +26,9 @@
|
|
|
23
26
|
*/
|
|
24
27
|
import fs from 'node:fs';
|
|
25
28
|
import path from 'node:path';
|
|
26
|
-
import { CONFIG, setChainIdOverride } from './config.js';
|
|
29
|
+
import { CONFIG, setChainIdOverride, setDataEdgeAddressOverride } from './config.js';
|
|
30
|
+
/** A plausible EVM address — anything else from billing is ignored (#460). */
|
|
31
|
+
const DATA_EDGE_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
27
32
|
// ---------------------------------------------------------------------------
|
|
28
33
|
// Constants
|
|
29
34
|
// ---------------------------------------------------------------------------
|
|
@@ -51,6 +56,30 @@ export function syncChainIdFromBilling(chainId) {
|
|
|
51
56
|
setChainIdOverride(typeof chainId === 'number' && Number.isFinite(chainId) ? chainId : 100);
|
|
52
57
|
}
|
|
53
58
|
// ---------------------------------------------------------------------------
|
|
59
|
+
// DataEdge-address sync
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
/**
|
|
62
|
+
* Apply the relay's authoritative `data_edge_address` to the runtime DataEdge
|
|
63
|
+
* override. Mirrors `syncChainIdFromBilling`.
|
|
64
|
+
*
|
|
65
|
+
* The relay routes each environment to its own DataEdge (staging is on-chain
|
|
66
|
+
* isolated). If the client ignores this and uses the WASM-baked default (the
|
|
67
|
+
* PROD DataEdge), writes against the staging relay mine on the prod contract
|
|
68
|
+
* while reads come from the staging subgraph → empty recall + phantom
|
|
69
|
+
* "stored=N" success (#460).
|
|
70
|
+
*
|
|
71
|
+
* A missing / malformed `data_edge_address` (older relay, partial payload,
|
|
72
|
+
* junk) clears the override (`null`) so resolution falls through to the WASM
|
|
73
|
+
* default — never a stale value. Only a plausible address
|
|
74
|
+
* (`0x` + 40 hex) is honored. Called from `readBillingCache` and
|
|
75
|
+
* `writeBillingCache` so every cache read or write keeps the override in sync.
|
|
76
|
+
* Idempotent. The explicit env override (`TOTALRECLAW_DATA_EDGE_ADDRESS`)
|
|
77
|
+
* still wins — it is the first term in `getSubgraphConfig`.
|
|
78
|
+
*/
|
|
79
|
+
export function syncDataEdgeAddressFromBilling(address) {
|
|
80
|
+
setDataEdgeAddressOverride(typeof address === 'string' && DATA_EDGE_ADDRESS_RE.test(address) ? address : null);
|
|
81
|
+
}
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
54
83
|
// Read / write
|
|
55
84
|
// ---------------------------------------------------------------------------
|
|
56
85
|
/**
|
|
@@ -68,9 +97,10 @@ export function readBillingCache() {
|
|
|
68
97
|
const raw = JSON.parse(fs.readFileSync(BILLING_CACHE_PATH, 'utf-8'));
|
|
69
98
|
if (!raw.checked_at || Date.now() - raw.checked_at > BILLING_CACHE_TTL)
|
|
70
99
|
return null;
|
|
71
|
-
// Keep chain
|
|
72
|
-
// across process restarts.
|
|
100
|
+
// Keep chain + DataEdge overrides in sync with the persisted authoritative
|
|
101
|
+
// values across process restarts.
|
|
73
102
|
syncChainIdFromBilling(raw.chain_id);
|
|
103
|
+
syncDataEdgeAddressFromBilling(raw.data_edge_address);
|
|
74
104
|
return raw;
|
|
75
105
|
}
|
|
76
106
|
catch {
|
|
@@ -92,7 +122,9 @@ export function writeBillingCache(cache) {
|
|
|
92
122
|
catch {
|
|
93
123
|
// Best-effort — don't block on cache write failure.
|
|
94
124
|
}
|
|
95
|
-
// Sync chain
|
|
96
|
-
//
|
|
125
|
+
// Sync chain + DataEdge overrides AFTER the write so in-process UserOp
|
|
126
|
+
// signing + subgraph reads pick up the correct chain and contract
|
|
127
|
+
// immediately, even if the disk write failed.
|
|
97
128
|
syncChainIdFromBilling(cache.chain_id);
|
|
129
|
+
syncDataEdgeAddressFromBilling(cache.data_edge_address);
|
|
98
130
|
}
|
package/dist/config.js
CHANGED
|
@@ -107,6 +107,35 @@ export function setChainIdOverride(chainId) {
|
|
|
107
107
|
export function __resetChainIdOverrideForTests() {
|
|
108
108
|
_chainIdOverride = null;
|
|
109
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Runtime override for the DataEdge contract address, set after the relay
|
|
112
|
+
* billing response is read. The relay returns an authoritative
|
|
113
|
+
* `data_edge_address` in `/v1/billing/status` (staging routes to the isolated
|
|
114
|
+
* staging DataEdge, production to the prod DataEdge). Chain-aware clients MUST
|
|
115
|
+
* consume it verbatim — otherwise writes mine on the WASM-baked prod DataEdge
|
|
116
|
+
* while reads hit the relay's subgraph, so recall silently returns empty
|
|
117
|
+
* against staging (#460). Mirrors `_chainIdOverride`.
|
|
118
|
+
*
|
|
119
|
+
* `null` means "no billing override" → fall through to the WASM default. The
|
|
120
|
+
* explicit operator env override (`TOTALRECLAW_DATA_EDGE_ADDRESS`, exposed as
|
|
121
|
+
* `CONFIG.dataEdgeAddress`) always wins over this.
|
|
122
|
+
*/
|
|
123
|
+
let _dataEdgeAddressOverride = null;
|
|
124
|
+
export function setDataEdgeAddressOverride(address) {
|
|
125
|
+
_dataEdgeAddressOverride = address;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Read the billing-sourced DataEdge override (or `''` when unset). Used by
|
|
129
|
+
* `getSubgraphConfig` as the middle term of the env → billing → WASM-default
|
|
130
|
+
* resolution order (#460).
|
|
131
|
+
*/
|
|
132
|
+
export function getDataEdgeAddressOverride() {
|
|
133
|
+
return _dataEdgeAddressOverride ?? '';
|
|
134
|
+
}
|
|
135
|
+
/** Reset the DataEdge override — used by tests. */
|
|
136
|
+
export function __resetDataEdgeAddressOverrideForTests() {
|
|
137
|
+
_dataEdgeAddressOverride = null;
|
|
138
|
+
}
|
|
110
139
|
export const CONFIG = {
|
|
111
140
|
// Core — recoveryPhrase reads from override first, then env var.
|
|
112
141
|
// Use getRecoveryPhrase() for dynamic access; this property is for
|
|
@@ -216,7 +245,14 @@ export const CONFIG = {
|
|
|
216
245
|
get chainId() {
|
|
217
246
|
return _chainIdOverride ?? 100;
|
|
218
247
|
},
|
|
219
|
-
|
|
248
|
+
// Explicit operator env override for the DataEdge contract. Stays env-only:
|
|
249
|
+
// it is the FIRST term of `getSubgraphConfig`'s env → billing → WASM-default
|
|
250
|
+
// resolution order, so it wins over the relay's authoritative
|
|
251
|
+
// `data_edge_address` (see `getDataEdgeAddressOverride` / #460). Getter, not
|
|
252
|
+
// a literal, so it reflects the live env rather than freezing at module load.
|
|
253
|
+
get dataEdgeAddress() {
|
|
254
|
+
return process.env.TOTALRECLAW_DATA_EDGE_ADDRESS || '';
|
|
255
|
+
},
|
|
220
256
|
entryPointAddress: process.env.TOTALRECLAW_ENTRYPOINT_ADDRESS || '',
|
|
221
257
|
rpcUrl: process.env.TOTALRECLAW_RPC_URL || '',
|
|
222
258
|
// 3.3.3-rc.1 (issue #187 — ONNX decouple): kill switch for the
|
package/dist/index.js
CHANGED
|
@@ -735,14 +735,15 @@ async function initialize(logger) {
|
|
|
735
735
|
const tier = billingData.tier;
|
|
736
736
|
const expiresAt = billingData.expires_at;
|
|
737
737
|
// Populate billing cache for future use. Copy the relay's
|
|
738
|
-
// authoritative chain_id so
|
|
739
|
-
// chain
|
|
738
|
+
// authoritative chain_id + data_edge_address so they land on disk and
|
|
739
|
+
// drive the runtime chain + DataEdge overrides verbatim (#402, #460).
|
|
740
740
|
writeBillingCache({
|
|
741
741
|
tier: tier || 'free',
|
|
742
742
|
free_writes_used: billingData.free_writes_used ?? 0,
|
|
743
743
|
free_writes_limit: billingData.free_writes_limit ?? 0,
|
|
744
744
|
features: billingData.features,
|
|
745
745
|
chain_id: billingData.chain_id,
|
|
746
|
+
data_edge_address: billingData.data_edge_address,
|
|
746
747
|
checked_at: Date.now(),
|
|
747
748
|
});
|
|
748
749
|
if (tier === 'pro' && expiresAt) {
|
|
@@ -4083,6 +4084,8 @@ const plugin = {
|
|
|
4083
4084
|
features: billingData.features,
|
|
4084
4085
|
// Relay's authoritative chain_id → drives the chain override verbatim (#402).
|
|
4085
4086
|
chain_id: billingData.chain_id,
|
|
4087
|
+
// Relay's authoritative data_edge_address → drives the DataEdge override verbatim (#460).
|
|
4088
|
+
data_edge_address: billingData.data_edge_address,
|
|
4086
4089
|
checked_at: Date.now(),
|
|
4087
4090
|
};
|
|
4088
4091
|
writeBillingCache(cache);
|
package/dist/subgraph-store.js
CHANGED
|
@@ -21,7 +21,7 @@ function getWasm() {
|
|
|
21
21
|
_wasm = requireWasm('@totalreclaw/core');
|
|
22
22
|
return _wasm;
|
|
23
23
|
}
|
|
24
|
-
import { CONFIG } from './config.js';
|
|
24
|
+
import { CONFIG, getDataEdgeAddressOverride } from './config.js';
|
|
25
25
|
import { buildRelayHeaders } from './relay-headers.js';
|
|
26
26
|
import { rpcRequest, rpcWithRetry } from './relay.js';
|
|
27
27
|
import { signUserOp } from './vault-crypto.js';
|
|
@@ -359,8 +359,17 @@ async function submitFactOnChainLocked(protobufPayload, config, eoa, sender) {
|
|
|
359
359
|
return rpcWithRetry({ url: bundlerUrl, headers, method, params });
|
|
360
360
|
}
|
|
361
361
|
const entryPoint = config.entryPointAddress || getWasm().getEntryPointAddress();
|
|
362
|
-
// 2. Encode calldata (SimpleAccount.execute → DataEdge
|
|
363
|
-
|
|
362
|
+
// 2. Encode calldata (SimpleAccount.execute → DataEdge).
|
|
363
|
+
// Target the resolved DataEdge address (env → relay billing → WASM default,
|
|
364
|
+
// per getSubgraphConfig / #462) so writes land on the SAME contract the
|
|
365
|
+
// relay reads from. The legacy `encodeSingleCall` bakes the PROD DataEdge,
|
|
366
|
+
// which stranded staging writes on prod (#460). Guard: an empty address
|
|
367
|
+
// (config built without getSubgraphConfig) falls back to the legacy encoder
|
|
368
|
+
// — behavior-identical to before, and avoids `encodeSingleCallTo` throwing
|
|
369
|
+
// on a bad address.
|
|
370
|
+
const calldataBytes = config.dataEdgeAddress
|
|
371
|
+
? getWasm().encodeSingleCallTo(protobufPayload, config.dataEdgeAddress)
|
|
372
|
+
: getWasm().encodeSingleCall(protobufPayload);
|
|
364
373
|
const callData = `0x${Buffer.from(calldataBytes).toString('hex')}`;
|
|
365
374
|
// 3. Get gas prices from Pimlico
|
|
366
375
|
const gasPrices = await rpc('pimlico_getUserOperationGasPrice', []);
|
|
@@ -541,10 +550,18 @@ async function submitFactBatchOnChainLocked(protobufPayloads, config, eoa, sende
|
|
|
541
550
|
return rpcWithRetry({ url: bundlerUrl, headers, method, params });
|
|
542
551
|
}
|
|
543
552
|
const entryPoint = config.entryPointAddress || getWasm().getEntryPointAddress();
|
|
544
|
-
// Encode batch calldata (SimpleAccount.executeBatch)
|
|
545
|
-
// encodeBatchCall
|
|
553
|
+
// Encode batch calldata (SimpleAccount.executeBatch).
|
|
554
|
+
// encodeBatchCall{,To} expect a JSON array of hex-encoded payload strings.
|
|
555
|
+
// Target the resolved DataEdge address (env → relay billing → WASM default,
|
|
556
|
+
// per getSubgraphConfig / #462) so writes land on the SAME contract the
|
|
557
|
+
// relay reads from — the legacy `encodeBatchCall` bakes the PROD DataEdge and
|
|
558
|
+
// stranded staging writes on prod (#460). Guard: empty address → legacy
|
|
559
|
+
// encoder (behavior-identical; avoids `encodeBatchCallTo` throwing).
|
|
546
560
|
const payloadsHex = protobufPayloads.map(p => p.toString('hex'));
|
|
547
|
-
const
|
|
561
|
+
const payloadsJson = JSON.stringify(payloadsHex);
|
|
562
|
+
const calldataBytes = config.dataEdgeAddress
|
|
563
|
+
? getWasm().encodeBatchCallTo(payloadsJson, config.dataEdgeAddress)
|
|
564
|
+
: getWasm().encodeBatchCall(payloadsJson);
|
|
548
565
|
const callData = `0x${Buffer.from(calldataBytes).toString('hex')}`;
|
|
549
566
|
// Get gas prices
|
|
550
567
|
const gasPrices = await rpc('pimlico_getUserOperationGasPrice', []);
|
|
@@ -712,7 +729,10 @@ export function isSubgraphMode() {
|
|
|
712
729
|
* - TOTALRECLAW_SELF_HOSTED -- set "true" to use self-hosted server (default: managed service)
|
|
713
730
|
*
|
|
714
731
|
* Chain ID is no longer configurable via env — it is auto-detected from the
|
|
715
|
-
* relay billing response (
|
|
732
|
+
* relay billing response (post-ops-1 both tiers are on Gnosis mainnet, chain
|
|
733
|
+
* 100). The DataEdge contract address is likewise consumed from the relay's
|
|
734
|
+
* authoritative `data_edge_address` (env override still wins, WASM default is
|
|
735
|
+
* the final fallback — see the `dataEdgeAddress` resolution below, #460).
|
|
716
736
|
*/
|
|
717
737
|
export function getSubgraphConfig() {
|
|
718
738
|
return {
|
|
@@ -721,7 +741,12 @@ export function getSubgraphConfig() {
|
|
|
721
741
|
mnemonic: CONFIG.recoveryPhrase,
|
|
722
742
|
cachePath: CONFIG.cachePath,
|
|
723
743
|
chainId: CONFIG.chainId,
|
|
724
|
-
|
|
744
|
+
// Resolution order (#460): explicit operator env override → relay billing
|
|
745
|
+
// `data_edge_address` (verbatim) → WASM-baked default. The relay routes
|
|
746
|
+
// each environment to its own DataEdge (staging is on-chain isolated), so
|
|
747
|
+
// consuming its value keeps writes + reads on the same contract; without
|
|
748
|
+
// the middle term staging writes mined on the prod default → empty recall.
|
|
749
|
+
dataEdgeAddress: CONFIG.dataEdgeAddress || getDataEdgeAddressOverride() || getWasm().getDataEdgeAddress(),
|
|
725
750
|
entryPointAddress: CONFIG.entryPointAddress || getWasm().getEntryPointAddress(),
|
|
726
751
|
rpcUrl: CONFIG.rpcUrl || undefined,
|
|
727
752
|
};
|
package/dist/tr-cli.js
CHANGED
|
@@ -51,7 +51,7 @@ const STATE_PATH = CONFIG.onboardingStatePath;
|
|
|
51
51
|
// Auto-synced by skill/scripts/sync-version.mjs from skill/plugin/package.json::version.
|
|
52
52
|
// Do not edit by hand — running tests will catch drift but the publish workflow
|
|
53
53
|
// rewrites this constant at the start of every npm/ClawHub publish.
|
|
54
|
-
const PLUGIN_VERSION = '3.3.12-rc.
|
|
54
|
+
const PLUGIN_VERSION = '3.3.12-rc.23';
|
|
55
55
|
function die(msg, code = 1) {
|
|
56
56
|
process.stderr.write(`tr: ${msg}\n`);
|
|
57
57
|
process.exit(code);
|
package/index.ts
CHANGED
|
@@ -1007,14 +1007,15 @@ async function initialize(logger: OpenClawPluginApi['logger']): Promise<void> {
|
|
|
1007
1007
|
const tier = billingData.tier as string;
|
|
1008
1008
|
const expiresAt = billingData.expires_at as string | undefined;
|
|
1009
1009
|
// Populate billing cache for future use. Copy the relay's
|
|
1010
|
-
// authoritative chain_id so
|
|
1011
|
-
// chain
|
|
1010
|
+
// authoritative chain_id + data_edge_address so they land on disk and
|
|
1011
|
+
// drive the runtime chain + DataEdge overrides verbatim (#402, #460).
|
|
1012
1012
|
writeBillingCache({
|
|
1013
1013
|
tier: tier || 'free',
|
|
1014
1014
|
free_writes_used: (billingData.free_writes_used as number) ?? 0,
|
|
1015
1015
|
free_writes_limit: (billingData.free_writes_limit as number) ?? 0,
|
|
1016
1016
|
features: billingData.features as BillingCache['features'] | undefined,
|
|
1017
1017
|
chain_id: billingData.chain_id as number | undefined,
|
|
1018
|
+
data_edge_address: billingData.data_edge_address as string | undefined,
|
|
1018
1019
|
checked_at: Date.now(),
|
|
1019
1020
|
});
|
|
1020
1021
|
if (tier === 'pro' && expiresAt) {
|
|
@@ -4785,6 +4786,8 @@ const plugin = {
|
|
|
4785
4786
|
features: billingData.features as BillingCache['features'] | undefined,
|
|
4786
4787
|
// Relay's authoritative chain_id → drives the chain override verbatim (#402).
|
|
4787
4788
|
chain_id: billingData.chain_id as number | undefined,
|
|
4789
|
+
// Relay's authoritative data_edge_address → drives the DataEdge override verbatim (#460).
|
|
4790
|
+
data_edge_address: billingData.data_edge_address as string | undefined,
|
|
4788
4791
|
checked_at: Date.now(),
|
|
4789
4792
|
};
|
|
4790
4793
|
writeBillingCache(cache);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@totalreclaw/totalreclaw",
|
|
3
|
-
"version": "3.3.12-rc.
|
|
3
|
+
"version": "3.3.12-rc.23",
|
|
4
4
|
"description": "End-to-end encrypted, agent-portable memory for OpenClaw and any LLM-agent runtime. XChaCha20-Poly1305 with protobuf v4 + on-chain Memory Taxonomy v1 (claim / preference / directive / commitment / episode / summary).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"scripts": {
|
|
69
69
|
"build": "rm -rf dist && tsc -p tsconfig.json --noCheck",
|
|
70
70
|
"verify-tarball": "node ../scripts/verify-tarball.mjs",
|
|
71
|
-
"test": "npx tsx batch-gate.test.ts && npx tsx manifest-shape.test.ts && npx tsx config-schema.test.ts && npx tsx config.test.ts && npx tsx relay-headers.test.ts && npx tsx scope-address-visible.test.ts && npx tsx llm-profile-reader.test.ts && npx tsx llm-client.test.ts && npx tsx llm-client-retry.test.ts && npx tsx llm-client-json-mode.test.ts && npx tsx gateway-url.test.ts && npx tsx retype-setscope.test.ts && npx tsx tool-gating.test.ts && npx tsx onboarding-noninteractive.test.ts && npx tsx pair-cli-json.test.ts && npx tsx pair-qr.test.ts && npx tsx pair-remote-client.test.ts && npx tsx pair-http.test.ts && npx tsx pair-http-route-registration.test.ts && npx tsx pair-http-init.test.ts && npx tsx qa-bug-report.test.ts && npx tsx nonce-serialization.test.ts && npx tsx initcode-lifecycle.test.ts && npx tsx phrase-safety-registry.test.ts && npx tsx test_issue_92_onnx_download_ux.test.ts && npx tsx onboard-pair-only.test.ts && npx tsx import-state.test.ts && npx tsx import-time-smoke.test.ts && npx tsx install-staging-cleanup.test.ts && npx tsx partial-install-detection.test.ts && npx tsx install-reload-idempotency.test.ts && npx tsx skill-register.test.ts && npx tsx json-stdout-cleanliness.test.ts && npx tsx url-binding.test.ts && npx tsx fs-helpers.test.ts && npx tsx pair-cli-default-mode.test.ts && npx tsx embedding-fallback-tag.test.ts && npx tsx staging-banner-gate.test.ts && npx tsx restart-auth.test.ts && npx tsx inbound-user-tracker.test.ts && npx tsx register-command-name.test.ts && npx tsx skill-md-native.test.ts &&npx tsx tr-cli-json-output.test.ts && npx tsx import-upgrade-cli.test.ts && npx tsx cli-registercli-scope.test.ts && npx tsx postinstall-validate.test.ts && npx tsx credential-provider.test.ts && npx tsx memory-runtime.test.ts && npx tsx tools.test.ts && npx tsx register-native.test.ts && npx tsx relay.test.ts && npx tsx vault-crypto.test.ts && npx tsx entry-env.test.ts && npx tsx trajectory-poller.test.ts && npx tsx billing-cache.test.ts",
|
|
71
|
+
"test": "npx tsx batch-gate.test.ts && npx tsx manifest-shape.test.ts && npx tsx config-schema.test.ts && npx tsx config.test.ts && npx tsx relay-headers.test.ts && npx tsx scope-address-visible.test.ts && npx tsx llm-profile-reader.test.ts && npx tsx llm-client.test.ts && npx tsx llm-client-retry.test.ts && npx tsx llm-client-json-mode.test.ts && npx tsx gateway-url.test.ts && npx tsx retype-setscope.test.ts && npx tsx tool-gating.test.ts && npx tsx onboarding-noninteractive.test.ts && npx tsx pair-cli-json.test.ts && npx tsx pair-qr.test.ts && npx tsx pair-remote-client.test.ts && npx tsx pair-http.test.ts && npx tsx pair-http-route-registration.test.ts && npx tsx pair-http-init.test.ts && npx tsx qa-bug-report.test.ts && npx tsx nonce-serialization.test.ts && npx tsx initcode-lifecycle.test.ts && npx tsx phrase-safety-registry.test.ts && npx tsx test_issue_92_onnx_download_ux.test.ts && npx tsx onboard-pair-only.test.ts && npx tsx import-state.test.ts && npx tsx import-time-smoke.test.ts && npx tsx install-staging-cleanup.test.ts && npx tsx partial-install-detection.test.ts && npx tsx install-reload-idempotency.test.ts && npx tsx skill-register.test.ts && npx tsx json-stdout-cleanliness.test.ts && npx tsx url-binding.test.ts && npx tsx fs-helpers.test.ts && npx tsx pair-cli-default-mode.test.ts && npx tsx embedding-fallback-tag.test.ts && npx tsx staging-banner-gate.test.ts && npx tsx restart-auth.test.ts && npx tsx inbound-user-tracker.test.ts && npx tsx register-command-name.test.ts && npx tsx skill-md-native.test.ts &&npx tsx tr-cli-json-output.test.ts && npx tsx import-upgrade-cli.test.ts && npx tsx cli-registercli-scope.test.ts && npx tsx postinstall-validate.test.ts && npx tsx credential-provider.test.ts && npx tsx memory-runtime.test.ts && npx tsx tools.test.ts && npx tsx register-native.test.ts && npx tsx relay.test.ts && npx tsx vault-crypto.test.ts && npx tsx entry-env.test.ts && npx tsx trajectory-poller.test.ts && npx tsx billing-cache.test.ts && npx tsx dataedge-write-target.test.ts",
|
|
72
72
|
"smoke:dist": "npx tsx dist-esm-smoke.test.ts",
|
|
73
73
|
"check-scanner": "node ../scripts/check-scanner.mjs",
|
|
74
74
|
"check-version-drift": "node ../scripts/check-version-drift.mjs",
|
package/skill.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "totalreclaw",
|
|
3
|
-
"version": "3.3.12-rc.
|
|
3
|
+
"version": "3.3.12-rc.23",
|
|
4
4
|
"description": "End-to-end encrypted memory for AI agents — portable, yours forever. XChaCha20-Poly1305 E2EE: server never sees plaintext.",
|
|
5
5
|
"author": "TotalReclaw Team",
|
|
6
6
|
"license": "MIT",
|
package/subgraph-store.ts
CHANGED
|
@@ -21,7 +21,7 @@ function getWasm() {
|
|
|
21
21
|
if (!_wasm) _wasm = requireWasm('@totalreclaw/core');
|
|
22
22
|
return _wasm;
|
|
23
23
|
}
|
|
24
|
-
import { CONFIG } from './config.js';
|
|
24
|
+
import { CONFIG, getDataEdgeAddressOverride } from './config.js';
|
|
25
25
|
import { buildRelayHeaders } from './relay-headers.js';
|
|
26
26
|
import { rpcRequest, rpcWithRetry } from './relay.js';
|
|
27
27
|
import { signUserOp } from './vault-crypto.js';
|
|
@@ -447,8 +447,17 @@ async function submitFactOnChainLocked(
|
|
|
447
447
|
|
|
448
448
|
const entryPoint = config.entryPointAddress || getWasm().getEntryPointAddress();
|
|
449
449
|
|
|
450
|
-
// 2. Encode calldata (SimpleAccount.execute → DataEdge
|
|
451
|
-
|
|
450
|
+
// 2. Encode calldata (SimpleAccount.execute → DataEdge).
|
|
451
|
+
// Target the resolved DataEdge address (env → relay billing → WASM default,
|
|
452
|
+
// per getSubgraphConfig / #462) so writes land on the SAME contract the
|
|
453
|
+
// relay reads from. The legacy `encodeSingleCall` bakes the PROD DataEdge,
|
|
454
|
+
// which stranded staging writes on prod (#460). Guard: an empty address
|
|
455
|
+
// (config built without getSubgraphConfig) falls back to the legacy encoder
|
|
456
|
+
// — behavior-identical to before, and avoids `encodeSingleCallTo` throwing
|
|
457
|
+
// on a bad address.
|
|
458
|
+
const calldataBytes = config.dataEdgeAddress
|
|
459
|
+
? getWasm().encodeSingleCallTo(protobufPayload, config.dataEdgeAddress)
|
|
460
|
+
: getWasm().encodeSingleCall(protobufPayload);
|
|
452
461
|
const callData = `0x${Buffer.from(calldataBytes).toString('hex')}`;
|
|
453
462
|
|
|
454
463
|
// 3. Get gas prices from Pimlico
|
|
@@ -659,10 +668,18 @@ async function submitFactBatchOnChainLocked(
|
|
|
659
668
|
}
|
|
660
669
|
const entryPoint = config.entryPointAddress || getWasm().getEntryPointAddress();
|
|
661
670
|
|
|
662
|
-
// Encode batch calldata (SimpleAccount.executeBatch)
|
|
663
|
-
// encodeBatchCall
|
|
671
|
+
// Encode batch calldata (SimpleAccount.executeBatch).
|
|
672
|
+
// encodeBatchCall{,To} expect a JSON array of hex-encoded payload strings.
|
|
673
|
+
// Target the resolved DataEdge address (env → relay billing → WASM default,
|
|
674
|
+
// per getSubgraphConfig / #462) so writes land on the SAME contract the
|
|
675
|
+
// relay reads from — the legacy `encodeBatchCall` bakes the PROD DataEdge and
|
|
676
|
+
// stranded staging writes on prod (#460). Guard: empty address → legacy
|
|
677
|
+
// encoder (behavior-identical; avoids `encodeBatchCallTo` throwing).
|
|
664
678
|
const payloadsHex = protobufPayloads.map(p => p.toString('hex'));
|
|
665
|
-
const
|
|
679
|
+
const payloadsJson = JSON.stringify(payloadsHex);
|
|
680
|
+
const calldataBytes = config.dataEdgeAddress
|
|
681
|
+
? getWasm().encodeBatchCallTo(payloadsJson, config.dataEdgeAddress)
|
|
682
|
+
: getWasm().encodeBatchCall(payloadsJson);
|
|
666
683
|
const callData = `0x${Buffer.from(calldataBytes).toString('hex')}`;
|
|
667
684
|
|
|
668
685
|
// Get gas prices
|
|
@@ -844,7 +861,10 @@ export function isSubgraphMode(): boolean {
|
|
|
844
861
|
* - TOTALRECLAW_SELF_HOSTED -- set "true" to use self-hosted server (default: managed service)
|
|
845
862
|
*
|
|
846
863
|
* Chain ID is no longer configurable via env — it is auto-detected from the
|
|
847
|
-
* relay billing response (
|
|
864
|
+
* relay billing response (post-ops-1 both tiers are on Gnosis mainnet, chain
|
|
865
|
+
* 100). The DataEdge contract address is likewise consumed from the relay's
|
|
866
|
+
* authoritative `data_edge_address` (env override still wins, WASM default is
|
|
867
|
+
* the final fallback — see the `dataEdgeAddress` resolution below, #460).
|
|
848
868
|
*/
|
|
849
869
|
export function getSubgraphConfig(): SubgraphStoreConfig {
|
|
850
870
|
return {
|
|
@@ -853,7 +873,12 @@ export function getSubgraphConfig(): SubgraphStoreConfig {
|
|
|
853
873
|
mnemonic: CONFIG.recoveryPhrase,
|
|
854
874
|
cachePath: CONFIG.cachePath,
|
|
855
875
|
chainId: CONFIG.chainId,
|
|
856
|
-
|
|
876
|
+
// Resolution order (#460): explicit operator env override → relay billing
|
|
877
|
+
// `data_edge_address` (verbatim) → WASM-baked default. The relay routes
|
|
878
|
+
// each environment to its own DataEdge (staging is on-chain isolated), so
|
|
879
|
+
// consuming its value keeps writes + reads on the same contract; without
|
|
880
|
+
// the middle term staging writes mined on the prod default → empty recall.
|
|
881
|
+
dataEdgeAddress: CONFIG.dataEdgeAddress || getDataEdgeAddressOverride() || getWasm().getDataEdgeAddress(),
|
|
857
882
|
entryPointAddress: CONFIG.entryPointAddress || getWasm().getEntryPointAddress(),
|
|
858
883
|
rpcUrl: CONFIG.rpcUrl || undefined,
|
|
859
884
|
};
|
package/tr-cli.ts
CHANGED
|
@@ -68,7 +68,7 @@ const STATE_PATH = CONFIG.onboardingStatePath;
|
|
|
68
68
|
// Auto-synced by skill/scripts/sync-version.mjs from skill/plugin/package.json::version.
|
|
69
69
|
// Do not edit by hand — running tests will catch drift but the publish workflow
|
|
70
70
|
// rewrites this constant at the start of every npm/ClawHub publish.
|
|
71
|
-
const PLUGIN_VERSION = '3.3.12-rc.
|
|
71
|
+
const PLUGIN_VERSION = '3.3.12-rc.23';
|
|
72
72
|
|
|
73
73
|
function die(msg: string, code = 1): never {
|
|
74
74
|
process.stderr.write(`tr: ${msg}\n`);
|