@bananapus/nana-sdk-core 2.12.2 → 2.13.0
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/cjs/bendystrawOperations.d.ts +38 -0
- package/dist/cjs/bendystrawOperations.d.ts.map +1 -0
- package/dist/cjs/bendystrawOperations.js +212 -0
- package/dist/cjs/bendystrawOperations.js.map +1 -0
- package/dist/cjs/review/contractWrite.d.ts +38 -0
- package/dist/cjs/review/contractWrite.d.ts.map +1 -0
- package/dist/cjs/review/contractWrite.js +57 -0
- package/dist/cjs/review/contractWrite.js.map +1 -0
- package/dist/cjs/review/gas.d.ts +28 -0
- package/dist/cjs/review/gas.d.ts.map +1 -0
- package/dist/cjs/review/gas.js +40 -0
- package/dist/cjs/review/gas.js.map +1 -0
- package/dist/cjs/review/index.d.ts +4 -0
- package/dist/cjs/review/index.d.ts.map +1 -0
- package/dist/cjs/review/index.js +20 -0
- package/dist/cjs/review/index.js.map +1 -0
- package/dist/cjs/review/transactionReview.d.ts +81 -0
- package/dist/cjs/review/transactionReview.d.ts.map +1 -0
- package/dist/cjs/review/transactionReview.js +203 -0
- package/dist/cjs/review/transactionReview.js.map +1 -0
- package/dist/cjs/safeService.d.ts +36 -0
- package/dist/cjs/safeService.d.ts.map +1 -0
- package/dist/cjs/safeService.js +142 -0
- package/dist/cjs/safeService.js.map +1 -0
- package/dist/cjs/utils/bendystraw.d.ts +15 -0
- package/dist/cjs/utils/bendystraw.d.ts.map +1 -1
- package/dist/cjs/utils/bendystraw.js +54 -0
- package/dist/cjs/utils/bendystraw.js.map +1 -1
- package/dist/cjs/v6/feeBuyback.d.ts +43 -0
- package/dist/cjs/v6/feeBuyback.d.ts.map +1 -0
- package/dist/cjs/v6/feeBuyback.js +306 -0
- package/dist/cjs/v6/feeBuyback.js.map +1 -0
- package/dist/esm/bendystrawOperations.d.ts +38 -0
- package/dist/esm/bendystrawOperations.d.ts.map +1 -0
- package/dist/esm/bendystrawOperations.js +206 -0
- package/dist/esm/bendystrawOperations.js.map +1 -0
- package/dist/esm/review/contractWrite.d.ts +38 -0
- package/dist/esm/review/contractWrite.d.ts.map +1 -0
- package/dist/esm/review/contractWrite.js +54 -0
- package/dist/esm/review/contractWrite.js.map +1 -0
- package/dist/esm/review/gas.d.ts +28 -0
- package/dist/esm/review/gas.d.ts.map +1 -0
- package/dist/esm/review/gas.js +36 -0
- package/dist/esm/review/gas.js.map +1 -0
- package/dist/esm/review/index.d.ts +4 -0
- package/dist/esm/review/index.d.ts.map +1 -0
- package/dist/esm/review/index.js +4 -0
- package/dist/esm/review/index.js.map +1 -0
- package/dist/esm/review/transactionReview.d.ts +81 -0
- package/dist/esm/review/transactionReview.d.ts.map +1 -0
- package/dist/esm/review/transactionReview.js +192 -0
- package/dist/esm/review/transactionReview.js.map +1 -0
- package/dist/esm/safeService.d.ts +36 -0
- package/dist/esm/safeService.d.ts.map +1 -0
- package/dist/esm/safeService.js +135 -0
- package/dist/esm/safeService.js.map +1 -0
- package/dist/esm/utils/bendystraw.d.ts +15 -0
- package/dist/esm/utils/bendystraw.d.ts.map +1 -1
- package/dist/esm/utils/bendystraw.js +53 -0
- package/dist/esm/utils/bendystraw.js.map +1 -1
- package/dist/esm/v6/feeBuyback.d.ts +43 -0
- package/dist/esm/v6/feeBuyback.d.ts.map +1 -0
- package/dist/esm/v6/feeBuyback.js +299 -0
- package/dist/esm/v6/feeBuyback.js.map +1 -0
- package/package.json +30 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type BendystrawNetwork } from "./utils/bendystraw.js";
|
|
2
|
+
export type BendystrawOperationContract = {
|
|
3
|
+
operationName?: string;
|
|
4
|
+
validateData: (value: unknown) => value is Record<string, unknown>;
|
|
5
|
+
validateVariables: (value: unknown) => value is Record<string, unknown>;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Compile one static GraphQL document into the same runtime operation contract
|
|
9
|
+
* used by every Bendystraw transport: operation name, bounded variables, and
|
|
10
|
+
* recursive response-shape validation.
|
|
11
|
+
*/
|
|
12
|
+
export declare function compileBendystrawOperation(query: string): BendystrawOperationContract;
|
|
13
|
+
/** The persisted-operation id a same-origin Bendystraw proxy accepts: the SHA-256 of the exact document. */
|
|
14
|
+
export declare function bendystrawOperationId(query: string): Promise<string>;
|
|
15
|
+
export type PersistedBendystrawRequest = {
|
|
16
|
+
query: string;
|
|
17
|
+
variables: Record<string, unknown>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a proxy request body (`{ operation, variables }`) against the app's
|
|
21
|
+
* registry of persisted documents. Anything else, including an unknown id, is
|
|
22
|
+
* refused with null, so the proxy never forwards arbitrary GraphQL.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolvePersistedBendystrawRequest(value: unknown, registry: Readonly<Record<string, string>>): PersistedBendystrawRequest | null;
|
|
25
|
+
/**
|
|
26
|
+
* Send one persisted operation through the app's same-origin proxy
|
|
27
|
+
* (`/api/bendystraw/{network}/query` unless `endpoint` says otherwise). Only
|
|
28
|
+
* the operation id and variables leave the browser; the response is validated
|
|
29
|
+
* against the document's contract.
|
|
30
|
+
*/
|
|
31
|
+
export declare function requestPersistedBendystraw<T>(args: {
|
|
32
|
+
contract: BendystrawOperationContract;
|
|
33
|
+
network: BendystrawNetwork;
|
|
34
|
+
query: string;
|
|
35
|
+
variables: Record<string, unknown>;
|
|
36
|
+
endpoint?: string;
|
|
37
|
+
}): Promise<T>;
|
|
38
|
+
//# sourceMappingURL=bendystrawOperations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bendystrawOperations.d.ts","sourceRoot":"","sources":["../../src/bendystrawOperations.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,MAAM,2BAA2B,GAAG;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnE,iBAAiB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzE,CAAC;AAwJF;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,GACZ,2BAA2B,CAiD7B;AAED,4GAA4G;AAC5G,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAS1E;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACzC,0BAA0B,GAAG,IAAI,CAcnC;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAAC,CAAC,EAAE,IAAI,EAAE;IACxD,QAAQ,EAAE,2BAA2B,CAAC;IACtC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,CAAC,CAAC,CAkBb"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compileBendystrawOperation = compileBendystrawOperation;
|
|
4
|
+
exports.bendystrawOperationId = bendystrawOperationId;
|
|
5
|
+
exports.resolvePersistedBendystrawRequest = resolvePersistedBendystrawRequest;
|
|
6
|
+
exports.requestPersistedBendystraw = requestPersistedBendystraw;
|
|
7
|
+
const graphql_1 = require("graphql");
|
|
8
|
+
const bendystraw_js_1 = require("./utils/bendystraw.js");
|
|
9
|
+
const contracts = new Map();
|
|
10
|
+
function isRecord(value) {
|
|
11
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
12
|
+
}
|
|
13
|
+
function isSafeInput(value, depth = 0) {
|
|
14
|
+
if (depth > 12)
|
|
15
|
+
return false;
|
|
16
|
+
if (value === undefined ||
|
|
17
|
+
value === null ||
|
|
18
|
+
typeof value === "boolean" ||
|
|
19
|
+
(typeof value === "number" && Number.isFinite(value))) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
if (typeof value === "string")
|
|
23
|
+
return value.length <= 16_384;
|
|
24
|
+
if (Array.isArray(value)) {
|
|
25
|
+
return (value.length <= 1_000 &&
|
|
26
|
+
value.every((item) => isSafeInput(item, depth + 1)));
|
|
27
|
+
}
|
|
28
|
+
return (isRecord(value) &&
|
|
29
|
+
Object.keys(value).length <= 250 &&
|
|
30
|
+
Object.values(value).every((item) => isSafeInput(item, depth + 1)));
|
|
31
|
+
}
|
|
32
|
+
function validateNamedInput(name, value) {
|
|
33
|
+
if (!isSafeInput(value))
|
|
34
|
+
return false;
|
|
35
|
+
switch (name) {
|
|
36
|
+
case "Boolean":
|
|
37
|
+
return typeof value === "boolean";
|
|
38
|
+
case "Float":
|
|
39
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
40
|
+
case "Int":
|
|
41
|
+
return typeof value === "number" && Number.isSafeInteger(value);
|
|
42
|
+
case "ID":
|
|
43
|
+
return typeof value === "string" || Number.isSafeInteger(value);
|
|
44
|
+
case "String":
|
|
45
|
+
return typeof value === "string";
|
|
46
|
+
default:
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function validateInput(type, value) {
|
|
51
|
+
if (type.kind === graphql_1.Kind.NON_NULL_TYPE) {
|
|
52
|
+
return (value !== null && value !== undefined && validateInput(type.type, value));
|
|
53
|
+
}
|
|
54
|
+
if (value === null || value === undefined)
|
|
55
|
+
return true;
|
|
56
|
+
if (type.kind === graphql_1.Kind.LIST_TYPE) {
|
|
57
|
+
const values = Array.isArray(value) ? value : [value];
|
|
58
|
+
return values.every((item) => validateInput(type.type, item));
|
|
59
|
+
}
|
|
60
|
+
return validateNamedInput(type.name.value, value);
|
|
61
|
+
}
|
|
62
|
+
// Defaults are constant values: the parser rejects a variable inside one.
|
|
63
|
+
function defaultValueOf(value) {
|
|
64
|
+
if (!value)
|
|
65
|
+
return undefined;
|
|
66
|
+
switch (value.kind) {
|
|
67
|
+
case graphql_1.Kind.BOOLEAN:
|
|
68
|
+
return value.value;
|
|
69
|
+
case graphql_1.Kind.ENUM:
|
|
70
|
+
case graphql_1.Kind.STRING:
|
|
71
|
+
return value.value;
|
|
72
|
+
case graphql_1.Kind.FLOAT:
|
|
73
|
+
case graphql_1.Kind.INT:
|
|
74
|
+
return Number(value.value);
|
|
75
|
+
case graphql_1.Kind.LIST:
|
|
76
|
+
return value.values.map(defaultValueOf);
|
|
77
|
+
case graphql_1.Kind.NULL:
|
|
78
|
+
return null;
|
|
79
|
+
case graphql_1.Kind.OBJECT:
|
|
80
|
+
return Object.fromEntries(value.fields.map((field) => [
|
|
81
|
+
field.name.value,
|
|
82
|
+
defaultValueOf(field.value),
|
|
83
|
+
]));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function validateSelectedValue(value, selectionSet, fragments) {
|
|
87
|
+
if (value === null)
|
|
88
|
+
return true;
|
|
89
|
+
if (Array.isArray(value)) {
|
|
90
|
+
return value.every((item) => validateSelectedValue(item, selectionSet, fragments));
|
|
91
|
+
}
|
|
92
|
+
if (!isRecord(value))
|
|
93
|
+
return false;
|
|
94
|
+
return validateSelectionSet(value, selectionSet, fragments, true);
|
|
95
|
+
}
|
|
96
|
+
function validateSelectionSet(value, selectionSet, fragments, requireFields) {
|
|
97
|
+
for (const selection of selectionSet.selections) {
|
|
98
|
+
if (selection.kind === graphql_1.Kind.FIELD) {
|
|
99
|
+
const responseKey = selection.alias?.value ?? selection.name.value;
|
|
100
|
+
if (!Object.prototype.hasOwnProperty.call(value, responseKey)) {
|
|
101
|
+
if (requireFields)
|
|
102
|
+
return false;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (selection.selectionSet &&
|
|
106
|
+
!validateSelectedValue(value[responseKey], selection.selectionSet, fragments)) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (selection.kind === graphql_1.Kind.INLINE_FRAGMENT) {
|
|
111
|
+
if (!validateSelectionSet(value, selection.selectionSet, fragments, requireFields && !selection.typeCondition)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
const fragment = fragments.get(selection.name.value);
|
|
117
|
+
if (!fragment)
|
|
118
|
+
return false;
|
|
119
|
+
if (!validateSelectionSet(value, fragment.selectionSet, fragments, false)) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Compile one static GraphQL document into the same runtime operation contract
|
|
128
|
+
* used by every Bendystraw transport: operation name, bounded variables, and
|
|
129
|
+
* recursive response-shape validation.
|
|
130
|
+
*/
|
|
131
|
+
function compileBendystrawOperation(query) {
|
|
132
|
+
const cached = contracts.get(query);
|
|
133
|
+
if (cached)
|
|
134
|
+
return cached;
|
|
135
|
+
const document = (0, graphql_1.parse)(query);
|
|
136
|
+
const operations = document.definitions.filter((definition) => definition.kind === graphql_1.Kind.OPERATION_DEFINITION);
|
|
137
|
+
if (operations.length !== 1) {
|
|
138
|
+
throw new TypeError("A Bendystraw document must contain exactly one operation");
|
|
139
|
+
}
|
|
140
|
+
const operation = operations[0];
|
|
141
|
+
const fragments = new Map(document.definitions
|
|
142
|
+
.filter((definition) => definition.kind === graphql_1.Kind.FRAGMENT_DEFINITION)
|
|
143
|
+
.map((fragment) => [fragment.name.value, fragment]));
|
|
144
|
+
const variableNames = new Set(operation.variableDefinitions?.map((definition) => definition.variable.name.value) ?? []);
|
|
145
|
+
const contract = {
|
|
146
|
+
operationName: operation.name?.value,
|
|
147
|
+
validateData: (value) => isRecord(value) &&
|
|
148
|
+
validateSelectionSet(value, operation.selectionSet, fragments, true),
|
|
149
|
+
validateVariables: (value) => {
|
|
150
|
+
if (!isRecord(value) || !isSafeInput(value))
|
|
151
|
+
return false;
|
|
152
|
+
if (Object.keys(value).some((name) => !variableNames.has(name)))
|
|
153
|
+
return false;
|
|
154
|
+
return (operation.variableDefinitions ?? []).every((definition) => {
|
|
155
|
+
const name = definition.variable.name.value;
|
|
156
|
+
const input = value[name] === undefined
|
|
157
|
+
? defaultValueOf(definition.defaultValue)
|
|
158
|
+
: value[name];
|
|
159
|
+
return validateInput(definition.type, input);
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
contracts.set(query, contract);
|
|
164
|
+
return contract;
|
|
165
|
+
}
|
|
166
|
+
/** The persisted-operation id a same-origin Bendystraw proxy accepts: the SHA-256 of the exact document. */
|
|
167
|
+
async function bendystrawOperationId(query) {
|
|
168
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(query));
|
|
169
|
+
let id = "";
|
|
170
|
+
for (const byte of new Uint8Array(digest))
|
|
171
|
+
id += byte.toString(16).padStart(2, "0");
|
|
172
|
+
return id;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Resolve a proxy request body (`{ operation, variables }`) against the app's
|
|
176
|
+
* registry of persisted documents. Anything else, including an unknown id, is
|
|
177
|
+
* refused with null, so the proxy never forwards arbitrary GraphQL.
|
|
178
|
+
*/
|
|
179
|
+
function resolvePersistedBendystrawRequest(value, registry) {
|
|
180
|
+
if (!isRecord(value))
|
|
181
|
+
return null;
|
|
182
|
+
const keys = Object.keys(value);
|
|
183
|
+
if (keys.some((key) => key !== "operation" && key !== "variables") ||
|
|
184
|
+
typeof value.operation !== "string" ||
|
|
185
|
+
!/^[a-f0-9]{64}$/u.test(value.operation) ||
|
|
186
|
+
!isRecord(value.variables)) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
// The 64-hex id check above rules out inherited keys such as `__proto__`.
|
|
190
|
+
const query = registry[value.operation];
|
|
191
|
+
return query ? { query, variables: value.variables } : null;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Send one persisted operation through the app's same-origin proxy
|
|
195
|
+
* (`/api/bendystraw/{network}/query` unless `endpoint` says otherwise). Only
|
|
196
|
+
* the operation id and variables leave the browser; the response is validated
|
|
197
|
+
* against the document's contract.
|
|
198
|
+
*/
|
|
199
|
+
async function requestPersistedBendystraw(args) {
|
|
200
|
+
const operation = await bendystrawOperationId(args.query);
|
|
201
|
+
return (0, bendystraw_js_1.requestBendystraw)(args.endpoint ?? `/api/bendystraw/${args.network}/query`, args.query, args.variables, {
|
|
202
|
+
fetch: (input, init) => fetch(input, {
|
|
203
|
+
...init,
|
|
204
|
+
body: JSON.stringify({ operation, variables: args.variables }),
|
|
205
|
+
cache: "no-store",
|
|
206
|
+
}),
|
|
207
|
+
operationName: args.contract.operationName,
|
|
208
|
+
validateData: (value) => args.contract.validateData(value),
|
|
209
|
+
validateVariables: args.contract.validateVariables,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=bendystrawOperations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bendystrawOperations.js","sourceRoot":"","sources":["../../src/bendystrawOperations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type Address } from "viem";
|
|
2
|
+
export type ReviewedWritePhase = "review" | "simulating" | "signing";
|
|
3
|
+
export type ReviewedContractWriteOptions<TRequest extends {
|
|
4
|
+
chainId: number;
|
|
5
|
+
}, TSimulated, THash> = {
|
|
6
|
+
request: TRequest;
|
|
7
|
+
expectedAccount: Address | undefined;
|
|
8
|
+
review: (request: TRequest) => Promise<unknown>;
|
|
9
|
+
switchChain: (chainId: number) => Promise<unknown>;
|
|
10
|
+
currentAccount: () => Address | undefined;
|
|
11
|
+
simulate: (request: TRequest) => Promise<TSimulated>;
|
|
12
|
+
reverify?: (request: TRequest) => Promise<unknown>;
|
|
13
|
+
/** Persist recovery intent after simulation, before a wallet can broadcast. */
|
|
14
|
+
beforeWrite?: () => unknown | Promise<unknown>;
|
|
15
|
+
/** The persisted intent was rejected by a final gate before write was invoked. */
|
|
16
|
+
onBeforeWriteAborted?: () => unknown | Promise<unknown>;
|
|
17
|
+
/** Clear that intent only when the wallet explicitly rejects the write. */
|
|
18
|
+
onWriteRejected?: () => unknown | Promise<unknown>;
|
|
19
|
+
write: (simulated: TSimulated) => Promise<THash>;
|
|
20
|
+
onPhase?: (phase: ReviewedWritePhase) => void;
|
|
21
|
+
accountChangedError?: string;
|
|
22
|
+
/**
|
|
23
|
+
* An app-specific gate run before anything else, such as refusing writes while
|
|
24
|
+
* the app is impersonating another account. It throws to stop the write.
|
|
25
|
+
*/
|
|
26
|
+
guard?: () => void;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Shared review-to-wallet boundary for direct contract writes.
|
|
30
|
+
*
|
|
31
|
+
* The exact request object accepted by review is also handed to simulation,
|
|
32
|
+
* and only the simulation result reaches the wallet writer. Account identity
|
|
33
|
+
* is checked after a chain switch and again immediately before signing.
|
|
34
|
+
*/
|
|
35
|
+
export declare function submitReviewedContractWrite<TRequest extends {
|
|
36
|
+
chainId: number;
|
|
37
|
+
}, TSimulated, THash>({ request, expectedAccount, review, switchChain, currentAccount, simulate, reverify, beforeWrite, onBeforeWriteAborted, onWriteRejected, write, onPhase, accountChangedError, guard, }: ReviewedContractWriteOptions<TRequest, TSimulated, THash>): Promise<THash>;
|
|
38
|
+
//# sourceMappingURL=contractWrite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contractWrite.d.ts","sourceRoot":"","sources":["../../../src/review/contractWrite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AAEzE,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;AAErE,MAAM,MAAM,4BAA4B,CACtC,QAAQ,SAAS;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,EACpC,UAAU,EACV,KAAK,IACH;IACF,OAAO,EAAE,QAAQ,CAAC;IAClB,eAAe,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAChD,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,cAAc,EAAE,MAAM,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/C,kFAAkF;IAClF,oBAAoB,CAAC,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxD,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,KAAK,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;CACpB,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,2BAA2B,CAC/C,QAAQ,SAAS;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,EACpC,UAAU,EACV,KAAK,EACL,EACA,OAAO,EACP,eAAe,EACf,MAAM,EACN,WAAW,EACX,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,oBAAoB,EACpB,eAAe,EACf,KAAK,EACL,OAAO,EACP,mBAAgF,EAChF,KAAK,GACN,EAAE,4BAA4B,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CA+C5E"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.submitReviewedContractWrite = submitReviewedContractWrite;
|
|
4
|
+
const viem_1 = require("viem");
|
|
5
|
+
/**
|
|
6
|
+
* Shared review-to-wallet boundary for direct contract writes.
|
|
7
|
+
*
|
|
8
|
+
* The exact request object accepted by review is also handed to simulation,
|
|
9
|
+
* and only the simulation result reaches the wallet writer. Account identity
|
|
10
|
+
* is checked after a chain switch and again immediately before signing.
|
|
11
|
+
*/
|
|
12
|
+
async function submitReviewedContractWrite({ request, expectedAccount, review, switchChain, currentAccount, simulate, reverify, beforeWrite, onBeforeWriteAborted, onWriteRejected, write, onPhase, accountChangedError = "Connected account changed. Review the transaction again.", guard, }) {
|
|
13
|
+
guard?.();
|
|
14
|
+
if (!expectedAccount)
|
|
15
|
+
throw new Error("Connect a wallet first.");
|
|
16
|
+
onPhase?.("review");
|
|
17
|
+
await review(request);
|
|
18
|
+
onPhase?.("simulating");
|
|
19
|
+
await switchChain(request.chainId);
|
|
20
|
+
assertExpectedAccount(currentAccount(), expectedAccount, accountChangedError);
|
|
21
|
+
await reverify?.(request);
|
|
22
|
+
assertExpectedAccount(currentAccount(), expectedAccount, accountChangedError);
|
|
23
|
+
const simulated = await simulate(request);
|
|
24
|
+
assertExpectedAccount(currentAccount(), expectedAccount, accountChangedError);
|
|
25
|
+
if (beforeWrite) {
|
|
26
|
+
await beforeWrite();
|
|
27
|
+
try {
|
|
28
|
+
assertExpectedAccount(currentAccount(), expectedAccount, accountChangedError);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
// This is strictly before the wallet writer is invoked. An ambiguous
|
|
32
|
+
// write error must never reach this cleanup path.
|
|
33
|
+
await onBeforeWriteAborted?.();
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
onPhase?.("signing");
|
|
38
|
+
try {
|
|
39
|
+
return await write(simulated);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
// The same-looking error from review/simulation never reaches this catch.
|
|
43
|
+
// An RPC timeout or ambiguous submission must preserve the recovery lock.
|
|
44
|
+
const rejected = error instanceof viem_1.UserRejectedRequestError ||
|
|
45
|
+
(error instanceof viem_1.BaseError &&
|
|
46
|
+
error.walk((cause) => cause instanceof viem_1.UserRejectedRequestError) instanceof viem_1.UserRejectedRequestError);
|
|
47
|
+
if (rejected)
|
|
48
|
+
await onWriteRejected?.();
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function assertExpectedAccount(current, expected, message) {
|
|
53
|
+
if (!current || current.toLowerCase() !== expected.toLowerCase()) {
|
|
54
|
+
throw new Error(message);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=contractWrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contractWrite.js","sourceRoot":"","sources":["../../../src/review/contractWrite.ts"],"names":[],"mappings":";;AAuCA,kEAkEC;AAzGD,+BAAyE;AAgCzE;;;;;;GAMG;AACI,KAAK,UAAU,2BAA2B,CAI/C,EACA,OAAO,EACP,eAAe,EACf,MAAM,EACN,WAAW,EACX,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,oBAAoB,EACpB,eAAe,EACf,KAAK,EACL,OAAO,EACP,mBAAmB,GAAG,0DAA0D,EAChF,KAAK,GACqD;IAC1D,KAAK,EAAE,EAAE,CAAC;IACV,IAAI,CAAC,eAAe;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAEjE,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC;IACpB,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;IAEtB,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC;IACxB,MAAM,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,qBAAqB,CAAC,cAAc,EAAE,EAAE,eAAe,EAAE,mBAAmB,CAAC,CAAC;IAC9E,MAAM,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC;IAC1B,qBAAqB,CAAC,cAAc,EAAE,EAAE,eAAe,EAAE,mBAAmB,CAAC,CAAC;IAE9E,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1C,qBAAqB,CAAC,cAAc,EAAE,EAAE,eAAe,EAAE,mBAAmB,CAAC,CAAC;IAE9E,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,WAAW,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,qBAAqB,CACnB,cAAc,EAAE,EAChB,eAAe,EACf,mBAAmB,CACpB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,qEAAqE;YACrE,kDAAkD;YAClD,MAAM,oBAAoB,EAAE,EAAE,CAAC;YAC/B,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0EAA0E;QAC1E,0EAA0E;QAC1E,MAAM,QAAQ,GACZ,KAAK,YAAY,+BAAwB;YACzC,CAAC,KAAK,YAAY,gBAAS;gBACzB,KAAK,CAAC,IAAI,CACR,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,YAAY,+BAAwB,CACrD,YAAY,+BAAwB,CAAC,CAAC;QAC3C,IAAI,QAAQ;YAAE,MAAM,eAAe,EAAE,EAAE,CAAC;QACxC,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAC5B,OAA4B,EAC5B,QAAiB,EACjB,OAAe;IAEf,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Address, Hex, PublicClient } from "viem";
|
|
2
|
+
/**
|
|
3
|
+
* Wallet gas limits are deliberately twice the latest RPC estimate.
|
|
4
|
+
*
|
|
5
|
+
* Some Juicebox terminal calls catch a failed internal fee payment and keep
|
|
6
|
+
* going. An RPC can therefore return an estimate for that cheaper recovery
|
|
7
|
+
* path even though the intended fee route needs more gas. Unused gas is not
|
|
8
|
+
* spent, so a 2x limit is a cheap guard against that under-estimation.
|
|
9
|
+
*/
|
|
10
|
+
export declare function gasWithHeadroom(estimate: bigint): bigint;
|
|
11
|
+
/**
|
|
12
|
+
* The gas limit to send for a call that carries a reviewed cap.
|
|
13
|
+
*
|
|
14
|
+
* A cap bounds an `eth_call` against a target-controlled contract; it is not
|
|
15
|
+
* what the call costs. Wallets reject a transaction whose `gas * maxFeePerGas`
|
|
16
|
+
* exceeds the balance, so sending the cap itself turns a 1M-gas mainnet cap
|
|
17
|
+
* into a ~0.003 ETH balance requirement for a call that burns a tenth of that.
|
|
18
|
+
*
|
|
19
|
+
* Measurement stays bounded by the cap, and the cap survives when the node
|
|
20
|
+
* cannot measure.
|
|
21
|
+
*/
|
|
22
|
+
export declare function gasWithinCap(client: PublicClient, tx: {
|
|
23
|
+
account: Address;
|
|
24
|
+
to: Address;
|
|
25
|
+
data: Hex;
|
|
26
|
+
value?: bigint;
|
|
27
|
+
}, cap?: bigint): Promise<bigint | undefined>;
|
|
28
|
+
//# sourceMappingURL=gas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gas.d.ts","sourceRoot":"","sources":["../../../src/review/gas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAEvD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,YAAY,EACpB,EAAE,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,GAAG,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAChE,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAW7B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.gasWithHeadroom = gasWithHeadroom;
|
|
4
|
+
exports.gasWithinCap = gasWithinCap;
|
|
5
|
+
/**
|
|
6
|
+
* Wallet gas limits are deliberately twice the latest RPC estimate.
|
|
7
|
+
*
|
|
8
|
+
* Some Juicebox terminal calls catch a failed internal fee payment and keep
|
|
9
|
+
* going. An RPC can therefore return an estimate for that cheaper recovery
|
|
10
|
+
* path even though the intended fee route needs more gas. Unused gas is not
|
|
11
|
+
* spent, so a 2x limit is a cheap guard against that under-estimation.
|
|
12
|
+
*/
|
|
13
|
+
function gasWithHeadroom(estimate) {
|
|
14
|
+
return estimate * 2n;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The gas limit to send for a call that carries a reviewed cap.
|
|
18
|
+
*
|
|
19
|
+
* A cap bounds an `eth_call` against a target-controlled contract; it is not
|
|
20
|
+
* what the call costs. Wallets reject a transaction whose `gas * maxFeePerGas`
|
|
21
|
+
* exceeds the balance, so sending the cap itself turns a 1M-gas mainnet cap
|
|
22
|
+
* into a ~0.003 ETH balance requirement for a call that burns a tenth of that.
|
|
23
|
+
*
|
|
24
|
+
* Measurement stays bounded by the cap, and the cap survives when the node
|
|
25
|
+
* cannot measure.
|
|
26
|
+
*/
|
|
27
|
+
async function gasWithinCap(client, tx, cap) {
|
|
28
|
+
try {
|
|
29
|
+
const estimate = await client.estimateGas({
|
|
30
|
+
...tx,
|
|
31
|
+
...(cap === undefined ? {} : { gas: cap }),
|
|
32
|
+
});
|
|
33
|
+
const measured = gasWithHeadroom(estimate);
|
|
34
|
+
return cap !== undefined && cap < measured ? cap : measured;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return cap;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=gas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gas.js","sourceRoot":"","sources":["../../../src/review/gas.ts"],"names":[],"mappings":";;AAUA,0CAEC;AAaD,oCAeC;AAtCD;;;;;;;GAOG;AACH,SAAgB,eAAe,CAAC,QAAgB;IAC9C,OAAO,QAAQ,GAAG,EAAE,CAAC;AACvB,CAAC;AAED;;;;;;;;;;GAUG;AACI,KAAK,UAAU,YAAY,CAChC,MAAoB,EACpB,EAAgE,EAChE,GAAY;IAEZ,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC;YACxC,GAAG,EAAE;YACL,GAAG,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;SAC3C,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC3C,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/review/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC;AACzB,cAAc,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./contractWrite.js"), exports);
|
|
18
|
+
__exportStar(require("./gas.js"), exports);
|
|
19
|
+
__exportStar(require("./transactionReview.js"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/review/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,2CAAyB;AACzB,yDAAuC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type Abi, type Address, type Hex } from "viem";
|
|
2
|
+
/**
|
|
3
|
+
* How review prompts name a chain and link its explorer. Apps pass their own
|
|
4
|
+
* chain display, which also keeps a chain table out of the review bundle.
|
|
5
|
+
*/
|
|
6
|
+
export type TransactionReviewDisplay = {
|
|
7
|
+
chainName: (chainId: number) => string;
|
|
8
|
+
explorerOrigin: (chainId: number) => string | null;
|
|
9
|
+
};
|
|
10
|
+
export type TransactionReviewCall = {
|
|
11
|
+
chainId: number;
|
|
12
|
+
to: Address;
|
|
13
|
+
data: Hex;
|
|
14
|
+
value?: bigint;
|
|
15
|
+
from?: Address;
|
|
16
|
+
abi?: Abi;
|
|
17
|
+
functionName?: string;
|
|
18
|
+
args?: readonly unknown[];
|
|
19
|
+
/** Plain-language action shown above the decoded call. */
|
|
20
|
+
label?: string;
|
|
21
|
+
/** Optional known contract name. The full address is always shown too. */
|
|
22
|
+
contractName?: string;
|
|
23
|
+
/** The calls a batching destination (MultiSend) makes in order, decoded by the caller. */
|
|
24
|
+
calls?: readonly TransactionReviewCall[];
|
|
25
|
+
};
|
|
26
|
+
export type TransactionReviewRequest = {
|
|
27
|
+
calls: readonly TransactionReviewCall[];
|
|
28
|
+
title?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
confirmLabel?: string;
|
|
31
|
+
/** Distinguishes a wallet transaction from an authorization which a relayer/Safe will submit. */
|
|
32
|
+
kind?: "transaction" | "authorization";
|
|
33
|
+
/** Exact typed data committed by a Safe/relayer signature, when applicable. */
|
|
34
|
+
authorization?: unknown;
|
|
35
|
+
};
|
|
36
|
+
export type ContractTransactionReviewCall = {
|
|
37
|
+
chainId: number;
|
|
38
|
+
address: Address;
|
|
39
|
+
abi: Abi;
|
|
40
|
+
functionName: string;
|
|
41
|
+
args?: readonly unknown[];
|
|
42
|
+
value?: bigint;
|
|
43
|
+
account?: Address;
|
|
44
|
+
};
|
|
45
|
+
export type TransactionReviewOptions = Omit<TransactionReviewRequest, "calls"> & {
|
|
46
|
+
label?: string;
|
|
47
|
+
contractName?: string;
|
|
48
|
+
};
|
|
49
|
+
type TransactionReviewHandler = (request: TransactionReviewRequest) => Promise<boolean>;
|
|
50
|
+
export type FundingChainOption = {
|
|
51
|
+
chainId: number;
|
|
52
|
+
/** The chain name and quoted funding cost shown to the user. */
|
|
53
|
+
label: string;
|
|
54
|
+
};
|
|
55
|
+
type FundingChainSelectionHandler = (options: readonly FundingChainOption[]) => Promise<number | null>;
|
|
56
|
+
export declare function registerFundingChainSelectionHandler(handler: FundingChainSelectionHandler): () => void;
|
|
57
|
+
/** Funding always requires an explicit choice, even with one quoted option. */
|
|
58
|
+
export declare function requireFundingChainSelection(options: readonly FundingChainOption[]): Promise<number>;
|
|
59
|
+
/**
|
|
60
|
+
* The provider registers the only UI capable of approving a transaction.
|
|
61
|
+
* Keeping the entry point in a small client module lets non-React wallet
|
|
62
|
+
* helpers (Safe and Relayr) use the same mandatory review queue.
|
|
63
|
+
*/
|
|
64
|
+
export declare function registerTransactionReviewHandler(handler: TransactionReviewHandler): () => void;
|
|
65
|
+
export declare function requestContractTransactionReview(call: ContractTransactionReviewCall, options?: TransactionReviewOptions): Promise<boolean>;
|
|
66
|
+
export declare function requireTransactionReview(request: TransactionReviewRequest): Promise<void>;
|
|
67
|
+
export declare function requireContractTransactionReview(call: ContractTransactionReviewCall, options?: TransactionReviewOptions): Promise<void>;
|
|
68
|
+
export declare function transactionReviewJson(request: TransactionReviewRequest): string;
|
|
69
|
+
/**
|
|
70
|
+
* The post-transaction counterpart of the review prompt: a mined tx the user
|
|
71
|
+
* wants explained (or diagnosed) from explorer evidence. Points at Etherscan's
|
|
72
|
+
* transaction-debugger skill when the reader's agent has it, and degrades to
|
|
73
|
+
* the explorer page when it doesn't.
|
|
74
|
+
*/
|
|
75
|
+
export declare function buildTransactionDebugPrompt(calls: {
|
|
76
|
+
chainId: number;
|
|
77
|
+
txHash: string;
|
|
78
|
+
}[], { chainName: displayChainName, explorerOrigin }: TransactionReviewDisplay): string;
|
|
79
|
+
export declare function buildTransactionReviewPrompt(request: TransactionReviewRequest, { explorerOrigin }: Pick<TransactionReviewDisplay, "explorerOrigin">): string;
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=transactionReview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transactionReview.d.ts","sourceRoot":"","sources":["../../../src/review/transactionReview.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,GAAG,EAAE,KAAK,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAE5E;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;IACvC,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CACpD,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,GAAG,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0FAA0F;IAC1F,KAAK,CAAC,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iGAAiG;IACjG,IAAI,CAAC,EAAE,aAAa,GAAG,eAAe,CAAC;IACvC,+EAA+E;IAC/E,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACzC,wBAAwB,EACxB,OAAO,CACR,GAAG;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,KAAK,wBAAwB,GAAG,CAC9B,OAAO,EAAE,wBAAwB,KAC9B,OAAO,CAAC,OAAO,CAAC,CAAC;AAItB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,KAAK,4BAA4B,GAAG,CAClC,OAAO,EAAE,SAAS,kBAAkB,EAAE,KACnC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAI5B,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,4BAA4B,GACpC,MAAM,IAAI,CAMZ;AAED,+EAA+E;AAC/E,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,SAAS,kBAAkB,EAAE,GACrC,OAAO,CAAC,MAAM,CAAC,CAkCjB;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,wBAAwB,GAChC,MAAM,IAAI,CAMZ;AA0CD,wBAAgB,gCAAgC,CAC9C,IAAI,EAAE,6BAA6B,EACnC,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,OAAO,CAAC,CAqBlB;AASD,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,gCAAgC,CACpD,IAAI,EAAE,6BAA6B,EACnC,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,wBAAwB,GAChC,MAAM,CAmBR;AAMD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,EAC5C,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,EAAE,wBAAwB,GACxE,MAAM,CAoBR;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,wBAAwB,EACjC,EAAE,cAAc,EAAE,EAAE,IAAI,CAAC,wBAAwB,EAAE,gBAAgB,CAAC,GACnE,MAAM,CAiER"}
|