@crediolabs/policy-synth 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/install/authority-overlap.js +1 -1
- package/dist/install/build-add-context-rule.js +16 -5
- package/dist/predicate/from-json.js +7 -0
- package/dist/run/index.d.ts +2 -2
- package/dist/run/index.js +1 -1
- package/dist/run/schemas.d.ts +19 -0
- package/dist/run/schemas.js +27 -0
- package/dist-cjs/install/authority-overlap.js +1 -1
- package/dist-cjs/install/build-add-context-rule.js +16 -5
- package/dist-cjs/predicate/from-json.js +7 -0
- package/dist-cjs/run/index.d.ts +2 -2
- package/dist-cjs/run/index.js +3 -1
- package/dist-cjs/run/schemas.d.ts +19 -0
- package/dist-cjs/run/schemas.js +28 -1
- package/package.json +1 -1
- package/src/install/authority-overlap.ts +1 -1
- package/src/install/build-add-context-rule.ts +20 -6
- package/src/predicate/from-json.ts +7 -0
- package/src/run/index.ts +3 -0
- package/src/run/schemas.ts +40 -0
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// rather than by tooling - which is why the tooling now exists.
|
|
19
19
|
//
|
|
20
20
|
// Adapted to grammar 3 from the version published in `@crediolabs/policy-synth`
|
|
21
|
-
// 0.2.0, which came from
|
|
21
|
+
// 0.2.0, which came from a different repository and was lost when the npm
|
|
22
22
|
// lineage moved here. `or` and `not` are gone from the grammar, so the cases
|
|
23
23
|
// handling them are gone too; oracle bounds are gone from the stored document.
|
|
24
24
|
//
|
|
@@ -121,12 +121,23 @@ function encodeSigner(s) {
|
|
|
121
121
|
function encodePoliciesMap(args) {
|
|
122
122
|
const entries = [];
|
|
123
123
|
for (const ref of args.policies) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
// Refuse anything that is not an interpreter policy rather than skipping
|
|
125
|
+
// it. This loop used to `if (kind === 'interpreter')` and drop everything
|
|
126
|
+
// else in silence, so a caller attaching an OZ `spending_limit` beside the
|
|
127
|
+
// interpreter got a rule WITHOUT the cap and no indication of it - the
|
|
128
|
+
// policy the user asked for was simply absent from the install they signed.
|
|
129
|
+
// `PolicyRef` has one shape today, so TypeScript narrows this branch to
|
|
130
|
+
// `never`; the guard is for callers reaching the built JS untyped, and for
|
|
131
|
+
// the next kind added to `PolicyRef` without a case here. Failing loudly is
|
|
132
|
+
// the only safe direction: a dropped policy is a missing restriction.
|
|
133
|
+
if (ref.kind !== 'interpreter') {
|
|
134
|
+
const kind = JSON.stringify(ref.kind ?? null);
|
|
135
|
+
throw limitError('INSTALL_BUILD_FAILED', `policy kind ${kind} is not supported; this builder attaches interpreter policies only. Attach an OpenZeppelin built-in through the account layer instead - dropping it here would install a rule missing the restriction you asked for.`);
|
|
129
136
|
}
|
|
137
|
+
entries.push(new xdr.ScMapEntry({
|
|
138
|
+
key: Address.fromString(ref.interpreterAddress).toScVal(),
|
|
139
|
+
val: encodePolicyInstallParams(args),
|
|
140
|
+
}));
|
|
130
141
|
}
|
|
131
142
|
entries.sort(sortByScValSymbolString);
|
|
132
143
|
return xdr.ScVal.scvMap(entries);
|
|
@@ -48,6 +48,13 @@ function jsonToLeaf(value) {
|
|
|
48
48
|
return { kind: 'call_arg', index: numberField(v, 'index') };
|
|
49
49
|
case 'call_arg_len':
|
|
50
50
|
return { kind: 'call_arg_len', index: numberField(v, 'index') };
|
|
51
|
+
case 'call_arg_field':
|
|
52
|
+
return {
|
|
53
|
+
kind: 'call_arg_field',
|
|
54
|
+
index: numberField(v, 'index'),
|
|
55
|
+
element: numberField(v, 'element'),
|
|
56
|
+
field: stringField(v, 'field'),
|
|
57
|
+
};
|
|
51
58
|
case 'call_arg_scaled':
|
|
52
59
|
// num/den stay decimal STRINGS: an i128 ratio does not survive a JS
|
|
53
60
|
// number, and silently rounding one would change the floor.
|
package/dist/run/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { type AuthorityOverlap } from '../install/authority-overlap.ts';
|
|
|
3
3
|
import { type BuildInstallPolicyResult, type BuildRevokePolicyResult } from '../install/build-install-policy.ts';
|
|
4
4
|
import { getInterpreterInfo } from '../install/get-interpreter-info.ts';
|
|
5
5
|
import { type RecordTransactionInput, type SimulatePolicyInput, type SynthesizePolicyInput, type VerifyPolicyInput } from './schemas.ts';
|
|
6
|
-
export type { DeclarePolicyInput, GetInterpreterInfoInput, InstallPolicyInput, RecordTransactionInput, RevokePolicyInput, SimulatePolicyInput, SynthesizePolicyInput, VerifyPolicyInput, } from './schemas.ts';
|
|
7
|
-
export { ComposeUserResponsesSchema, DeclarePolicyInputSchema, GetInterpreterInfoInputSchema, InstallPolicyInputSchema, InterpreterOptionsSchema, MAINNET_RPC_URL, NetworkSchema, PINNED_INTERPRETER_ADDRESS_BY_NETWORK, PINNED_INTERPRETER_GRAMMAR_VERSION, PINNED_INTERPRETER_MAINNET_ADDRESS, PINNED_INTERPRETER_TESTNET_ADDRESS, PINNED_INTERPRETER_WASM_SHA256, PredicateLeafSchema, PredicateNodeSchema, RecordedTransactionSchema, RecordTransactionInputSchema, RevokePolicyInputSchema, RPC_URL_BY_NETWORK, SynthesizePolicyInputSchema, TESTNET_RPC_URL, ToolErrorSchema, } from './schemas.ts';
|
|
6
|
+
export type { DeclarePolicyInput, GetInterpreterInfoInput, InstallPolicyInput, OzBuiltinPolicy, RecordTransactionInput, RevokePolicyInput, SimulatePolicyInput, SynthesizePolicyInput, VerifyPolicyInput, } from './schemas.ts';
|
|
7
|
+
export { ComposeUserResponsesSchema, DeclarePolicyInputSchema, GetInterpreterInfoInputSchema, InstallPolicyInputSchema, InterpreterOptionsSchema, MAINNET_RPC_URL, NetworkSchema, PINNED_INTERPRETER_ADDRESS_BY_NETWORK, PINNED_INTERPRETER_GRAMMAR_VERSION, PINNED_INTERPRETER_MAINNET_ADDRESS, PINNED_INTERPRETER_TESTNET_ADDRESS, PINNED_INTERPRETER_WASM_SHA256, PINNED_OZ_POLICY_ADDRESS_BY_NETWORK, PINNED_OZ_POLICY_WASM_SHA256, PredicateLeafSchema, PredicateNodeSchema, RecordedTransactionSchema, RecordTransactionInputSchema, RevokePolicyInputSchema, RPC_URL_BY_NETWORK, SynthesizePolicyInputSchema, TESTNET_RPC_URL, ToolErrorSchema, } from './schemas.ts';
|
|
8
8
|
export type RunRecordTransactionInput = RecordTransactionInput;
|
|
9
9
|
export type RunSynthesizePolicyInput = SynthesizePolicyInput;
|
|
10
10
|
export type RunSimulatePolicyInput = SimulatePolicyInput;
|
package/dist/run/index.js
CHANGED
|
@@ -30,7 +30,7 @@ import { DeclarePolicyInputSchema, GetInterpreterInfoInputSchema, InstallPolicyI
|
|
|
30
30
|
// downstream consumer) can import the canonical input shapes from the same
|
|
31
31
|
// module that owns the tool-body glue. The strict schemas are the source of
|
|
32
32
|
// truth - MCP tool shapes are derived from them.
|
|
33
|
-
export { ComposeUserResponsesSchema, DeclarePolicyInputSchema, GetInterpreterInfoInputSchema, InstallPolicyInputSchema, InterpreterOptionsSchema, MAINNET_RPC_URL, NetworkSchema, PINNED_INTERPRETER_ADDRESS_BY_NETWORK, PINNED_INTERPRETER_GRAMMAR_VERSION, PINNED_INTERPRETER_MAINNET_ADDRESS, PINNED_INTERPRETER_TESTNET_ADDRESS, PINNED_INTERPRETER_WASM_SHA256, PredicateLeafSchema, PredicateNodeSchema, RecordedTransactionSchema, RecordTransactionInputSchema, RevokePolicyInputSchema, RPC_URL_BY_NETWORK, SynthesizePolicyInputSchema, TESTNET_RPC_URL, ToolErrorSchema, } from "./schemas.js";
|
|
33
|
+
export { ComposeUserResponsesSchema, DeclarePolicyInputSchema, GetInterpreterInfoInputSchema, InstallPolicyInputSchema, InterpreterOptionsSchema, MAINNET_RPC_URL, NetworkSchema, PINNED_INTERPRETER_ADDRESS_BY_NETWORK, PINNED_INTERPRETER_GRAMMAR_VERSION, PINNED_INTERPRETER_MAINNET_ADDRESS, PINNED_INTERPRETER_TESTNET_ADDRESS, PINNED_INTERPRETER_WASM_SHA256, PINNED_OZ_POLICY_ADDRESS_BY_NETWORK, PINNED_OZ_POLICY_WASM_SHA256, PredicateLeafSchema, PredicateNodeSchema, RecordedTransactionSchema, RecordTransactionInputSchema, RevokePolicyInputSchema, RPC_URL_BY_NETWORK, SynthesizePolicyInputSchema, TESTNET_RPC_URL, ToolErrorSchema, } from "./schemas.js";
|
|
34
34
|
/** Map every tool name to its canonical domain error code. Replaces a 7-way
|
|
35
35
|
* if/else so adding a tool adds one line here rather than a new branch in
|
|
36
36
|
* each envelope call. */
|
package/dist/run/schemas.d.ts
CHANGED
|
@@ -1627,6 +1627,25 @@ export declare const MAINNET_RPC_URL = "https://mainnet.sorobanrpc.com";
|
|
|
1627
1627
|
* a single constant - only the addresses and RPCs are network-scoped. */
|
|
1628
1628
|
export declare const PINNED_INTERPRETER_ADDRESS_BY_NETWORK: Record<Network, string>;
|
|
1629
1629
|
export declare const RPC_URL_BY_NETWORK: Record<Network, string>;
|
|
1630
|
+
/** The OpenZeppelin built-in policies we deployed instances of. These are OZ
|
|
1631
|
+
* EXAMPLE contracts, built by us from `OpenZeppelin/stellar-contracts` at tag
|
|
1632
|
+
* v0.7.2 and deployed by us. We have NOT audited them and upstream ships an
|
|
1633
|
+
* "experimental software ... as is" disclaimer; anything surfacing one of
|
|
1634
|
+
* these to a user must say so rather than implying we vouch for the code.
|
|
1635
|
+
* Provenance detail in `docs/audit/README.md` finding 7. */
|
|
1636
|
+
export type OzBuiltinPolicy = 'spending_limit' | 'simple_threshold' | 'weighted_threshold';
|
|
1637
|
+
/** Instance addresses per network. Exported so consumers import the pin
|
|
1638
|
+
* instead of copying a literal - a copied address is how a testnet id ends up
|
|
1639
|
+
* being queried against mainnet, which returns `Error(Storage, MissingValue)`
|
|
1640
|
+
* and reads exactly like "nothing is deployed there".
|
|
1641
|
+
*
|
|
1642
|
+
* Instance ids are network-scoped, so the addresses differ while the wasm
|
|
1643
|
+
* hash does not: each pair below was created from the same uploaded wasm (see
|
|
1644
|
+
* `PINNED_OZ_POLICY_WASM_SHA256`), verified by fetching the deployed bytes
|
|
1645
|
+
* back from both networks. */
|
|
1646
|
+
export declare const PINNED_OZ_POLICY_ADDRESS_BY_NETWORK: Record<Network, Record<OzBuiltinPolicy, string>>;
|
|
1647
|
+
/** sha256 of each deployed policy wasm, identical across both networks. */
|
|
1648
|
+
export declare const PINNED_OZ_POLICY_WASM_SHA256: Record<OzBuiltinPolicy, string>;
|
|
1630
1649
|
/** Stellar network passphrases. Pinned here so the XDR envelope uses the
|
|
1631
1650
|
* matching passphrase when the wallet signs (a mismatch yields invalid
|
|
1632
1651
|
* hashes). */
|
package/dist/run/schemas.js
CHANGED
|
@@ -364,6 +364,33 @@ export const RPC_URL_BY_NETWORK = {
|
|
|
364
364
|
testnet: TESTNET_RPC_URL,
|
|
365
365
|
mainnet: MAINNET_RPC_URL,
|
|
366
366
|
};
|
|
367
|
+
/** Instance addresses per network. Exported so consumers import the pin
|
|
368
|
+
* instead of copying a literal - a copied address is how a testnet id ends up
|
|
369
|
+
* being queried against mainnet, which returns `Error(Storage, MissingValue)`
|
|
370
|
+
* and reads exactly like "nothing is deployed there".
|
|
371
|
+
*
|
|
372
|
+
* Instance ids are network-scoped, so the addresses differ while the wasm
|
|
373
|
+
* hash does not: each pair below was created from the same uploaded wasm (see
|
|
374
|
+
* `PINNED_OZ_POLICY_WASM_SHA256`), verified by fetching the deployed bytes
|
|
375
|
+
* back from both networks. */
|
|
376
|
+
export const PINNED_OZ_POLICY_ADDRESS_BY_NETWORK = {
|
|
377
|
+
testnet: {
|
|
378
|
+
spending_limit: 'CDH4KOBRUEZI6TTZ72YXR5YUIODB6RH3AF75KX56Z73DELRCA5TWFISP',
|
|
379
|
+
simple_threshold: 'CAYTIVQOEZDOQI4GC3XBXEEYHQUANQQJHPJVMXVRBREGSAP6TCN3DID6',
|
|
380
|
+
weighted_threshold: 'CCTNRFZCL45GTJICA3Z2KFQO3VEGBHGCVBLHQ3GLJKAGACQIJMYJS7T2',
|
|
381
|
+
},
|
|
382
|
+
mainnet: {
|
|
383
|
+
spending_limit: 'CA7IBD266HIHFDUIBZLPIAITJUA3DVY4JAG6K3QMGBKLZCXXLP5E2F7A',
|
|
384
|
+
simple_threshold: 'CDOGPGUFGGUDG25P3TG6XIXJKRRYOZ3PXUZIEPVH74KXRZIDKZ5HYEOS',
|
|
385
|
+
weighted_threshold: 'CDWPZ4YZ3YIJ64XSHRMERRF2L2H7XD6SPUZDP3KI56T7QXQCICC25V3J',
|
|
386
|
+
},
|
|
387
|
+
};
|
|
388
|
+
/** sha256 of each deployed policy wasm, identical across both networks. */
|
|
389
|
+
export const PINNED_OZ_POLICY_WASM_SHA256 = {
|
|
390
|
+
spending_limit: '9ce30ea1fe5c2dc5c9c49cf3462adb32e2c11d7dfadb15ef43a51ba56568de2b',
|
|
391
|
+
simple_threshold: '01c0be09eb6fb288cab2e878b4e890f7a38f75afab99aeb197861f44e2e2dfe6',
|
|
392
|
+
weighted_threshold: '78030272b06afb09d2949ab8877c9a8ae1ab9025b48f4edafd5816cc44f76eaa',
|
|
393
|
+
};
|
|
367
394
|
/** Stellar network passphrases. Pinned here so the XDR envelope uses the
|
|
368
395
|
* matching passphrase when the wallet signs (a mismatch yields invalid
|
|
369
396
|
* hashes). */
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// rather than by tooling - which is why the tooling now exists.
|
|
20
20
|
//
|
|
21
21
|
// Adapted to grammar 3 from the version published in `@crediolabs/policy-synth`
|
|
22
|
-
// 0.2.0, which came from
|
|
22
|
+
// 0.2.0, which came from a different repository and was lost when the npm
|
|
23
23
|
// lineage moved here. `or` and `not` are gone from the grammar, so the cases
|
|
24
24
|
// handling them are gone too; oracle bounds are gone from the stored document.
|
|
25
25
|
//
|
|
@@ -125,12 +125,23 @@ function encodeSigner(s) {
|
|
|
125
125
|
function encodePoliciesMap(args) {
|
|
126
126
|
const entries = [];
|
|
127
127
|
for (const ref of args.policies) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
// Refuse anything that is not an interpreter policy rather than skipping
|
|
129
|
+
// it. This loop used to `if (kind === 'interpreter')` and drop everything
|
|
130
|
+
// else in silence, so a caller attaching an OZ `spending_limit` beside the
|
|
131
|
+
// interpreter got a rule WITHOUT the cap and no indication of it - the
|
|
132
|
+
// policy the user asked for was simply absent from the install they signed.
|
|
133
|
+
// `PolicyRef` has one shape today, so TypeScript narrows this branch to
|
|
134
|
+
// `never`; the guard is for callers reaching the built JS untyped, and for
|
|
135
|
+
// the next kind added to `PolicyRef` without a case here. Failing loudly is
|
|
136
|
+
// the only safe direction: a dropped policy is a missing restriction.
|
|
137
|
+
if (ref.kind !== 'interpreter') {
|
|
138
|
+
const kind = JSON.stringify(ref.kind ?? null);
|
|
139
|
+
throw limitError('INSTALL_BUILD_FAILED', `policy kind ${kind} is not supported; this builder attaches interpreter policies only. Attach an OpenZeppelin built-in through the account layer instead - dropping it here would install a rule missing the restriction you asked for.`);
|
|
133
140
|
}
|
|
141
|
+
entries.push(new stellar_sdk_1.xdr.ScMapEntry({
|
|
142
|
+
key: stellar_sdk_1.Address.fromString(ref.interpreterAddress).toScVal(),
|
|
143
|
+
val: encodePolicyInstallParams(args),
|
|
144
|
+
}));
|
|
134
145
|
}
|
|
135
146
|
entries.sort(sortByScValSymbolString);
|
|
136
147
|
return stellar_sdk_1.xdr.ScVal.scvMap(entries);
|
|
@@ -51,6 +51,13 @@ function jsonToLeaf(value) {
|
|
|
51
51
|
return { kind: 'call_arg', index: numberField(v, 'index') };
|
|
52
52
|
case 'call_arg_len':
|
|
53
53
|
return { kind: 'call_arg_len', index: numberField(v, 'index') };
|
|
54
|
+
case 'call_arg_field':
|
|
55
|
+
return {
|
|
56
|
+
kind: 'call_arg_field',
|
|
57
|
+
index: numberField(v, 'index'),
|
|
58
|
+
element: numberField(v, 'element'),
|
|
59
|
+
field: stringField(v, 'field'),
|
|
60
|
+
};
|
|
54
61
|
case 'call_arg_scaled':
|
|
55
62
|
// num/den stay decimal STRINGS: an i128 ratio does not survive a JS
|
|
56
63
|
// number, and silently rounding one would change the floor.
|
package/dist-cjs/run/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { type AuthorityOverlap } from '../install/authority-overlap.ts';
|
|
|
3
3
|
import { type BuildInstallPolicyResult, type BuildRevokePolicyResult } from '../install/build-install-policy.ts';
|
|
4
4
|
import { getInterpreterInfo } from '../install/get-interpreter-info.ts';
|
|
5
5
|
import { type RecordTransactionInput, type SimulatePolicyInput, type SynthesizePolicyInput, type VerifyPolicyInput } from './schemas.ts';
|
|
6
|
-
export type { DeclarePolicyInput, GetInterpreterInfoInput, InstallPolicyInput, RecordTransactionInput, RevokePolicyInput, SimulatePolicyInput, SynthesizePolicyInput, VerifyPolicyInput, } from './schemas.ts';
|
|
7
|
-
export { ComposeUserResponsesSchema, DeclarePolicyInputSchema, GetInterpreterInfoInputSchema, InstallPolicyInputSchema, InterpreterOptionsSchema, MAINNET_RPC_URL, NetworkSchema, PINNED_INTERPRETER_ADDRESS_BY_NETWORK, PINNED_INTERPRETER_GRAMMAR_VERSION, PINNED_INTERPRETER_MAINNET_ADDRESS, PINNED_INTERPRETER_TESTNET_ADDRESS, PINNED_INTERPRETER_WASM_SHA256, PredicateLeafSchema, PredicateNodeSchema, RecordedTransactionSchema, RecordTransactionInputSchema, RevokePolicyInputSchema, RPC_URL_BY_NETWORK, SynthesizePolicyInputSchema, TESTNET_RPC_URL, ToolErrorSchema, } from './schemas.ts';
|
|
6
|
+
export type { DeclarePolicyInput, GetInterpreterInfoInput, InstallPolicyInput, OzBuiltinPolicy, RecordTransactionInput, RevokePolicyInput, SimulatePolicyInput, SynthesizePolicyInput, VerifyPolicyInput, } from './schemas.ts';
|
|
7
|
+
export { ComposeUserResponsesSchema, DeclarePolicyInputSchema, GetInterpreterInfoInputSchema, InstallPolicyInputSchema, InterpreterOptionsSchema, MAINNET_RPC_URL, NetworkSchema, PINNED_INTERPRETER_ADDRESS_BY_NETWORK, PINNED_INTERPRETER_GRAMMAR_VERSION, PINNED_INTERPRETER_MAINNET_ADDRESS, PINNED_INTERPRETER_TESTNET_ADDRESS, PINNED_INTERPRETER_WASM_SHA256, PINNED_OZ_POLICY_ADDRESS_BY_NETWORK, PINNED_OZ_POLICY_WASM_SHA256, PredicateLeafSchema, PredicateNodeSchema, RecordedTransactionSchema, RecordTransactionInputSchema, RevokePolicyInputSchema, RPC_URL_BY_NETWORK, SynthesizePolicyInputSchema, TESTNET_RPC_URL, ToolErrorSchema, } from './schemas.ts';
|
|
8
8
|
export type RunRecordTransactionInput = RecordTransactionInput;
|
|
9
9
|
export type RunSynthesizePolicyInput = SynthesizePolicyInput;
|
|
10
10
|
export type RunSimulatePolicyInput = SimulatePolicyInput;
|
package/dist-cjs/run/index.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// No business logic. No retries. No session state. The same call shape can
|
|
19
19
|
// drive the CLI (which calls into the same core directly without MCP).
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.ToolErrorSchema = exports.TESTNET_RPC_URL = exports.SynthesizePolicyInputSchema = exports.RPC_URL_BY_NETWORK = exports.RevokePolicyInputSchema = exports.RecordTransactionInputSchema = exports.RecordedTransactionSchema = exports.PredicateNodeSchema = exports.PredicateLeafSchema = exports.PINNED_INTERPRETER_WASM_SHA256 = exports.PINNED_INTERPRETER_TESTNET_ADDRESS = exports.PINNED_INTERPRETER_MAINNET_ADDRESS = exports.PINNED_INTERPRETER_GRAMMAR_VERSION = exports.PINNED_INTERPRETER_ADDRESS_BY_NETWORK = exports.NetworkSchema = exports.MAINNET_RPC_URL = exports.InterpreterOptionsSchema = exports.InstallPolicyInputSchema = exports.GetInterpreterInfoInputSchema = exports.DeclarePolicyInputSchema = exports.ComposeUserResponsesSchema = void 0;
|
|
21
|
+
exports.ToolErrorSchema = exports.TESTNET_RPC_URL = exports.SynthesizePolicyInputSchema = exports.RPC_URL_BY_NETWORK = exports.RevokePolicyInputSchema = exports.RecordTransactionInputSchema = exports.RecordedTransactionSchema = exports.PredicateNodeSchema = exports.PredicateLeafSchema = exports.PINNED_OZ_POLICY_WASM_SHA256 = exports.PINNED_OZ_POLICY_ADDRESS_BY_NETWORK = exports.PINNED_INTERPRETER_WASM_SHA256 = exports.PINNED_INTERPRETER_TESTNET_ADDRESS = exports.PINNED_INTERPRETER_MAINNET_ADDRESS = exports.PINNED_INTERPRETER_GRAMMAR_VERSION = exports.PINNED_INTERPRETER_ADDRESS_BY_NETWORK = exports.NetworkSchema = exports.MAINNET_RPC_URL = exports.InterpreterOptionsSchema = exports.InstallPolicyInputSchema = exports.GetInterpreterInfoInputSchema = exports.DeclarePolicyInputSchema = exports.ComposeUserResponsesSchema = void 0;
|
|
22
22
|
exports.runRecordTransaction = runRecordTransaction;
|
|
23
23
|
exports.runSynthesizePolicy = runSynthesizePolicy;
|
|
24
24
|
exports.runInstallPolicy = runInstallPolicy;
|
|
@@ -55,6 +55,8 @@ Object.defineProperty(exports, "PINNED_INTERPRETER_GRAMMAR_VERSION", { enumerabl
|
|
|
55
55
|
Object.defineProperty(exports, "PINNED_INTERPRETER_MAINNET_ADDRESS", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_MAINNET_ADDRESS; } });
|
|
56
56
|
Object.defineProperty(exports, "PINNED_INTERPRETER_TESTNET_ADDRESS", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_TESTNET_ADDRESS; } });
|
|
57
57
|
Object.defineProperty(exports, "PINNED_INTERPRETER_WASM_SHA256", { enumerable: true, get: function () { return schemas_ts_2.PINNED_INTERPRETER_WASM_SHA256; } });
|
|
58
|
+
Object.defineProperty(exports, "PINNED_OZ_POLICY_ADDRESS_BY_NETWORK", { enumerable: true, get: function () { return schemas_ts_2.PINNED_OZ_POLICY_ADDRESS_BY_NETWORK; } });
|
|
59
|
+
Object.defineProperty(exports, "PINNED_OZ_POLICY_WASM_SHA256", { enumerable: true, get: function () { return schemas_ts_2.PINNED_OZ_POLICY_WASM_SHA256; } });
|
|
58
60
|
Object.defineProperty(exports, "PredicateLeafSchema", { enumerable: true, get: function () { return schemas_ts_2.PredicateLeafSchema; } });
|
|
59
61
|
Object.defineProperty(exports, "PredicateNodeSchema", { enumerable: true, get: function () { return schemas_ts_2.PredicateNodeSchema; } });
|
|
60
62
|
Object.defineProperty(exports, "RecordedTransactionSchema", { enumerable: true, get: function () { return schemas_ts_2.RecordedTransactionSchema; } });
|
|
@@ -1627,6 +1627,25 @@ export declare const MAINNET_RPC_URL = "https://mainnet.sorobanrpc.com";
|
|
|
1627
1627
|
* a single constant - only the addresses and RPCs are network-scoped. */
|
|
1628
1628
|
export declare const PINNED_INTERPRETER_ADDRESS_BY_NETWORK: Record<Network, string>;
|
|
1629
1629
|
export declare const RPC_URL_BY_NETWORK: Record<Network, string>;
|
|
1630
|
+
/** The OpenZeppelin built-in policies we deployed instances of. These are OZ
|
|
1631
|
+
* EXAMPLE contracts, built by us from `OpenZeppelin/stellar-contracts` at tag
|
|
1632
|
+
* v0.7.2 and deployed by us. We have NOT audited them and upstream ships an
|
|
1633
|
+
* "experimental software ... as is" disclaimer; anything surfacing one of
|
|
1634
|
+
* these to a user must say so rather than implying we vouch for the code.
|
|
1635
|
+
* Provenance detail in `docs/audit/README.md` finding 7. */
|
|
1636
|
+
export type OzBuiltinPolicy = 'spending_limit' | 'simple_threshold' | 'weighted_threshold';
|
|
1637
|
+
/** Instance addresses per network. Exported so consumers import the pin
|
|
1638
|
+
* instead of copying a literal - a copied address is how a testnet id ends up
|
|
1639
|
+
* being queried against mainnet, which returns `Error(Storage, MissingValue)`
|
|
1640
|
+
* and reads exactly like "nothing is deployed there".
|
|
1641
|
+
*
|
|
1642
|
+
* Instance ids are network-scoped, so the addresses differ while the wasm
|
|
1643
|
+
* hash does not: each pair below was created from the same uploaded wasm (see
|
|
1644
|
+
* `PINNED_OZ_POLICY_WASM_SHA256`), verified by fetching the deployed bytes
|
|
1645
|
+
* back from both networks. */
|
|
1646
|
+
export declare const PINNED_OZ_POLICY_ADDRESS_BY_NETWORK: Record<Network, Record<OzBuiltinPolicy, string>>;
|
|
1647
|
+
/** sha256 of each deployed policy wasm, identical across both networks. */
|
|
1648
|
+
export declare const PINNED_OZ_POLICY_WASM_SHA256: Record<OzBuiltinPolicy, string>;
|
|
1630
1649
|
/** Stellar network passphrases. Pinned here so the XDR envelope uses the
|
|
1631
1650
|
* matching passphrase when the wallet signs (a mismatch yields invalid
|
|
1632
1651
|
* hashes). */
|
package/dist-cjs/run/schemas.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// imports them here so its tool-shape bindings stay in step; the CLI imports
|
|
17
17
|
// them here so it can build the same args envelope the MCP transport builds.
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.ToolErrorSchema = exports.GetInterpreterInfoInputSchema = exports.RevokePolicyInputSchema = exports.InstallPolicyInputSchema = exports.DeclarePolicyInputSchema = exports.NETWORK_PASSPHRASES = exports.RPC_URL_BY_NETWORK = exports.PINNED_INTERPRETER_ADDRESS_BY_NETWORK = exports.MAINNET_RPC_URL = exports.TESTNET_RPC_URL = exports.PINNED_INTERPRETER_GRAMMAR_VERSION = exports.PINNED_INTERPRETER_WASM_SHA256 = exports.PINNED_INTERPRETER_MAINNET_ADDRESS = exports.PINNED_INTERPRETER_TESTNET_ADDRESS = exports.ObservedRuleSchema = exports.VerifyPolicyInputSchema = exports.SimulatePolicyInputSchema = exports.PredicateNodeSchema = exports.PredicateLeafSchema = exports.SynthesizePolicyInputSchema = exports.InterpreterOptionsSchema = exports.RecordTransactionInputSchema = exports.ComposeUserResponsesSchema = exports.RecordedTransactionSchema = exports.ParseConfidenceSchema = exports.OnChainEventSchema = exports.TokenMovementSchema = exports.ContractInvocationSchema = exports.ScValSchema = exports.NetworkSchema = void 0;
|
|
19
|
+
exports.ToolErrorSchema = exports.GetInterpreterInfoInputSchema = exports.RevokePolicyInputSchema = exports.InstallPolicyInputSchema = exports.DeclarePolicyInputSchema = exports.NETWORK_PASSPHRASES = exports.PINNED_OZ_POLICY_WASM_SHA256 = exports.PINNED_OZ_POLICY_ADDRESS_BY_NETWORK = exports.RPC_URL_BY_NETWORK = exports.PINNED_INTERPRETER_ADDRESS_BY_NETWORK = exports.MAINNET_RPC_URL = exports.TESTNET_RPC_URL = exports.PINNED_INTERPRETER_GRAMMAR_VERSION = exports.PINNED_INTERPRETER_WASM_SHA256 = exports.PINNED_INTERPRETER_MAINNET_ADDRESS = exports.PINNED_INTERPRETER_TESTNET_ADDRESS = exports.ObservedRuleSchema = exports.VerifyPolicyInputSchema = exports.SimulatePolicyInputSchema = exports.PredicateNodeSchema = exports.PredicateLeafSchema = exports.SynthesizePolicyInputSchema = exports.InterpreterOptionsSchema = exports.RecordTransactionInputSchema = exports.ComposeUserResponsesSchema = exports.RecordedTransactionSchema = exports.ParseConfidenceSchema = exports.OnChainEventSchema = exports.TokenMovementSchema = exports.ContractInvocationSchema = exports.ScValSchema = exports.NetworkSchema = void 0;
|
|
20
20
|
const zod_1 = require("zod");
|
|
21
21
|
const address_ts_1 = require("../synth/address.js");
|
|
22
22
|
/** Soroban `valid_until` is a u32 ledger sequence; a value above this cannot be
|
|
@@ -367,6 +367,33 @@ exports.RPC_URL_BY_NETWORK = {
|
|
|
367
367
|
testnet: exports.TESTNET_RPC_URL,
|
|
368
368
|
mainnet: exports.MAINNET_RPC_URL,
|
|
369
369
|
};
|
|
370
|
+
/** Instance addresses per network. Exported so consumers import the pin
|
|
371
|
+
* instead of copying a literal - a copied address is how a testnet id ends up
|
|
372
|
+
* being queried against mainnet, which returns `Error(Storage, MissingValue)`
|
|
373
|
+
* and reads exactly like "nothing is deployed there".
|
|
374
|
+
*
|
|
375
|
+
* Instance ids are network-scoped, so the addresses differ while the wasm
|
|
376
|
+
* hash does not: each pair below was created from the same uploaded wasm (see
|
|
377
|
+
* `PINNED_OZ_POLICY_WASM_SHA256`), verified by fetching the deployed bytes
|
|
378
|
+
* back from both networks. */
|
|
379
|
+
exports.PINNED_OZ_POLICY_ADDRESS_BY_NETWORK = {
|
|
380
|
+
testnet: {
|
|
381
|
+
spending_limit: 'CDH4KOBRUEZI6TTZ72YXR5YUIODB6RH3AF75KX56Z73DELRCA5TWFISP',
|
|
382
|
+
simple_threshold: 'CAYTIVQOEZDOQI4GC3XBXEEYHQUANQQJHPJVMXVRBREGSAP6TCN3DID6',
|
|
383
|
+
weighted_threshold: 'CCTNRFZCL45GTJICA3Z2KFQO3VEGBHGCVBLHQ3GLJKAGACQIJMYJS7T2',
|
|
384
|
+
},
|
|
385
|
+
mainnet: {
|
|
386
|
+
spending_limit: 'CA7IBD266HIHFDUIBZLPIAITJUA3DVY4JAG6K3QMGBKLZCXXLP5E2F7A',
|
|
387
|
+
simple_threshold: 'CDOGPGUFGGUDG25P3TG6XIXJKRRYOZ3PXUZIEPVH74KXRZIDKZ5HYEOS',
|
|
388
|
+
weighted_threshold: 'CDWPZ4YZ3YIJ64XSHRMERRF2L2H7XD6SPUZDP3KI56T7QXQCICC25V3J',
|
|
389
|
+
},
|
|
390
|
+
};
|
|
391
|
+
/** sha256 of each deployed policy wasm, identical across both networks. */
|
|
392
|
+
exports.PINNED_OZ_POLICY_WASM_SHA256 = {
|
|
393
|
+
spending_limit: '9ce30ea1fe5c2dc5c9c49cf3462adb32e2c11d7dfadb15ef43a51ba56568de2b',
|
|
394
|
+
simple_threshold: '01c0be09eb6fb288cab2e878b4e890f7a38f75afab99aeb197861f44e2e2dfe6',
|
|
395
|
+
weighted_threshold: '78030272b06afb09d2949ab8877c9a8ae1ab9025b48f4edafd5816cc44f76eaa',
|
|
396
|
+
};
|
|
370
397
|
/** Stellar network passphrases. Pinned here so the XDR envelope uses the
|
|
371
398
|
* matching passphrase when the wallet signs (a mismatch yields invalid
|
|
372
399
|
* hashes). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crediolabs/policy-synth",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Off-chain TypeScript synthesis core for the OZ Accounts Policy Builder. Records Soroban transactions, synthesises the minimal policy that permits exactly that flow, verifies it, and returns an unsigned install transaction.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// rather than by tooling - which is why the tooling now exists.
|
|
19
19
|
//
|
|
20
20
|
// Adapted to grammar 3 from the version published in `@crediolabs/policy-synth`
|
|
21
|
-
// 0.2.0, which came from
|
|
21
|
+
// 0.2.0, which came from a different repository and was lost when the npm
|
|
22
22
|
// lineage moved here. `or` and `not` are gone from the grammar, so the cases
|
|
23
23
|
// handling them are gone too; oracle bounds are gone from the stored document.
|
|
24
24
|
//
|
|
@@ -194,14 +194,28 @@ function encodeSigner(s: SignerDraft): xdr.ScVal {
|
|
|
194
194
|
function encodePoliciesMap(args: BuildAddContextRuleArgs): xdr.ScVal {
|
|
195
195
|
const entries: xdr.ScMapEntry[] = []
|
|
196
196
|
for (const ref of args.policies) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
197
|
+
// Refuse anything that is not an interpreter policy rather than skipping
|
|
198
|
+
// it. This loop used to `if (kind === 'interpreter')` and drop everything
|
|
199
|
+
// else in silence, so a caller attaching an OZ `spending_limit` beside the
|
|
200
|
+
// interpreter got a rule WITHOUT the cap and no indication of it - the
|
|
201
|
+
// policy the user asked for was simply absent from the install they signed.
|
|
202
|
+
// `PolicyRef` has one shape today, so TypeScript narrows this branch to
|
|
203
|
+
// `never`; the guard is for callers reaching the built JS untyped, and for
|
|
204
|
+
// the next kind added to `PolicyRef` without a case here. Failing loudly is
|
|
205
|
+
// the only safe direction: a dropped policy is a missing restriction.
|
|
206
|
+
if (ref.kind !== 'interpreter') {
|
|
207
|
+
const kind = JSON.stringify((ref as { kind?: unknown }).kind ?? null)
|
|
208
|
+
throw limitError(
|
|
209
|
+
'INSTALL_BUILD_FAILED',
|
|
210
|
+
`policy kind ${kind} is not supported; this builder attaches interpreter policies only. Attach an OpenZeppelin built-in through the account layer instead - dropping it here would install a rule missing the restriction you asked for.`
|
|
203
211
|
)
|
|
204
212
|
}
|
|
213
|
+
entries.push(
|
|
214
|
+
new xdr.ScMapEntry({
|
|
215
|
+
key: Address.fromString(ref.interpreterAddress).toScVal(),
|
|
216
|
+
val: encodePolicyInstallParams(args),
|
|
217
|
+
})
|
|
218
|
+
)
|
|
205
219
|
}
|
|
206
220
|
entries.sort(sortByScValSymbolString)
|
|
207
221
|
return xdr.ScVal.scvMap(entries)
|
|
@@ -57,6 +57,13 @@ function jsonToLeaf(value: unknown): PredicateLeaf {
|
|
|
57
57
|
return { kind: 'call_arg', index: numberField(v, 'index') }
|
|
58
58
|
case 'call_arg_len':
|
|
59
59
|
return { kind: 'call_arg_len', index: numberField(v, 'index') }
|
|
60
|
+
case 'call_arg_field':
|
|
61
|
+
return {
|
|
62
|
+
kind: 'call_arg_field',
|
|
63
|
+
index: numberField(v, 'index'),
|
|
64
|
+
element: numberField(v, 'element'),
|
|
65
|
+
field: stringField(v, 'field'),
|
|
66
|
+
}
|
|
60
67
|
case 'call_arg_scaled':
|
|
61
68
|
// num/den stay decimal STRINGS: an i128 ratio does not survive a JS
|
|
62
69
|
// number, and silently rounding one would change the floor.
|
package/src/run/index.ts
CHANGED
|
@@ -77,6 +77,7 @@ export type {
|
|
|
77
77
|
DeclarePolicyInput,
|
|
78
78
|
GetInterpreterInfoInput,
|
|
79
79
|
InstallPolicyInput,
|
|
80
|
+
OzBuiltinPolicy,
|
|
80
81
|
RecordTransactionInput,
|
|
81
82
|
RevokePolicyInput,
|
|
82
83
|
SimulatePolicyInput,
|
|
@@ -100,6 +101,8 @@ export {
|
|
|
100
101
|
PINNED_INTERPRETER_MAINNET_ADDRESS,
|
|
101
102
|
PINNED_INTERPRETER_TESTNET_ADDRESS,
|
|
102
103
|
PINNED_INTERPRETER_WASM_SHA256,
|
|
104
|
+
PINNED_OZ_POLICY_ADDRESS_BY_NETWORK,
|
|
105
|
+
PINNED_OZ_POLICY_WASM_SHA256,
|
|
103
106
|
PredicateLeafSchema,
|
|
104
107
|
PredicateNodeSchema,
|
|
105
108
|
RecordedTransactionSchema,
|
package/src/run/schemas.ts
CHANGED
|
@@ -421,6 +421,46 @@ export const RPC_URL_BY_NETWORK: Record<Network, string> = {
|
|
|
421
421
|
mainnet: MAINNET_RPC_URL,
|
|
422
422
|
}
|
|
423
423
|
|
|
424
|
+
/** The OpenZeppelin built-in policies we deployed instances of. These are OZ
|
|
425
|
+
* EXAMPLE contracts, built by us from `OpenZeppelin/stellar-contracts` at tag
|
|
426
|
+
* v0.7.2 and deployed by us. We have NOT audited them and upstream ships an
|
|
427
|
+
* "experimental software ... as is" disclaimer; anything surfacing one of
|
|
428
|
+
* these to a user must say so rather than implying we vouch for the code.
|
|
429
|
+
* Provenance detail in `docs/audit/README.md` finding 7. */
|
|
430
|
+
export type OzBuiltinPolicy = 'spending_limit' | 'simple_threshold' | 'weighted_threshold'
|
|
431
|
+
|
|
432
|
+
/** Instance addresses per network. Exported so consumers import the pin
|
|
433
|
+
* instead of copying a literal - a copied address is how a testnet id ends up
|
|
434
|
+
* being queried against mainnet, which returns `Error(Storage, MissingValue)`
|
|
435
|
+
* and reads exactly like "nothing is deployed there".
|
|
436
|
+
*
|
|
437
|
+
* Instance ids are network-scoped, so the addresses differ while the wasm
|
|
438
|
+
* hash does not: each pair below was created from the same uploaded wasm (see
|
|
439
|
+
* `PINNED_OZ_POLICY_WASM_SHA256`), verified by fetching the deployed bytes
|
|
440
|
+
* back from both networks. */
|
|
441
|
+
export const PINNED_OZ_POLICY_ADDRESS_BY_NETWORK: Record<
|
|
442
|
+
Network,
|
|
443
|
+
Record<OzBuiltinPolicy, string>
|
|
444
|
+
> = {
|
|
445
|
+
testnet: {
|
|
446
|
+
spending_limit: 'CDH4KOBRUEZI6TTZ72YXR5YUIODB6RH3AF75KX56Z73DELRCA5TWFISP',
|
|
447
|
+
simple_threshold: 'CAYTIVQOEZDOQI4GC3XBXEEYHQUANQQJHPJVMXVRBREGSAP6TCN3DID6',
|
|
448
|
+
weighted_threshold: 'CCTNRFZCL45GTJICA3Z2KFQO3VEGBHGCVBLHQ3GLJKAGACQIJMYJS7T2',
|
|
449
|
+
},
|
|
450
|
+
mainnet: {
|
|
451
|
+
spending_limit: 'CA7IBD266HIHFDUIBZLPIAITJUA3DVY4JAG6K3QMGBKLZCXXLP5E2F7A',
|
|
452
|
+
simple_threshold: 'CDOGPGUFGGUDG25P3TG6XIXJKRRYOZ3PXUZIEPVH74KXRZIDKZ5HYEOS',
|
|
453
|
+
weighted_threshold: 'CDWPZ4YZ3YIJ64XSHRMERRF2L2H7XD6SPUZDP3KI56T7QXQCICC25V3J',
|
|
454
|
+
},
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/** sha256 of each deployed policy wasm, identical across both networks. */
|
|
458
|
+
export const PINNED_OZ_POLICY_WASM_SHA256: Record<OzBuiltinPolicy, string> = {
|
|
459
|
+
spending_limit: '9ce30ea1fe5c2dc5c9c49cf3462adb32e2c11d7dfadb15ef43a51ba56568de2b',
|
|
460
|
+
simple_threshold: '01c0be09eb6fb288cab2e878b4e890f7a38f75afab99aeb197861f44e2e2dfe6',
|
|
461
|
+
weighted_threshold: '78030272b06afb09d2949ab8877c9a8ae1ab9025b48f4edafd5816cc44f76eaa',
|
|
462
|
+
}
|
|
463
|
+
|
|
424
464
|
/** Stellar network passphrases. Pinned here so the XDR envelope uses the
|
|
425
465
|
* matching passphrase when the wallet signs (a mismatch yields invalid
|
|
426
466
|
* hashes). */
|