@lifi/composer-sdk 0.0.1-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +220 -0
- package/dist/authoring/FlowBuilderCore.cjs +115 -0
- package/dist/authoring/FlowBuilderCore.cjs.map +1 -0
- package/dist/authoring/FlowBuilderCore.d.cts +114 -0
- package/dist/authoring/FlowBuilderCore.d.ts +114 -0
- package/dist/authoring/FlowBuilderCore.js +91 -0
- package/dist/authoring/FlowBuilderCore.js.map +1 -0
- package/dist/authoring/handles.cjs +43 -0
- package/dist/authoring/handles.cjs.map +1 -0
- package/dist/authoring/handles.d.cts +61 -0
- package/dist/authoring/handles.d.ts +61 -0
- package/dist/authoring/handles.js +17 -0
- package/dist/authoring/handles.js.map +1 -0
- package/dist/authoring/raw.cjs +41 -0
- package/dist/authoring/raw.cjs.map +1 -0
- package/dist/authoring/raw.d.cts +47 -0
- package/dist/authoring/raw.d.ts +47 -0
- package/dist/authoring/raw.js +16 -0
- package/dist/authoring/raw.js.map +1 -0
- package/dist/authoring/signatureArgs.cjs +114 -0
- package/dist/authoring/signatureArgs.cjs.map +1 -0
- package/dist/authoring/signatureArgs.d.cts +146 -0
- package/dist/authoring/signatureArgs.d.ts +146 -0
- package/dist/authoring/signatureArgs.js +87 -0
- package/dist/authoring/signatureArgs.js.map +1 -0
- package/dist/client.cjs +140 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +67 -0
- package/dist/client.d.ts +67 -0
- package/dist/client.js +116 -0
- package/dist/client.js.map +1 -0
- package/dist/discovery.cjs +17 -0
- package/dist/discovery.cjs.map +1 -0
- package/dist/discovery.d.cts +56 -0
- package/dist/discovery.d.ts +56 -0
- package/dist/discovery.js +1 -0
- package/dist/discovery.js.map +1 -0
- package/dist/errors.cjs +91 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.cts +77 -0
- package/dist/errors.d.ts +77 -0
- package/dist/errors.js +65 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/config.generated.cjs +17 -0
- package/dist/generated/config.generated.cjs.map +1 -0
- package/dist/generated/config.generated.d.cts +144 -0
- package/dist/generated/config.generated.d.ts +144 -0
- package/dist/generated/config.generated.js +1 -0
- package/dist/generated/config.generated.js.map +1 -0
- package/dist/generated/guards.generated.cjs +32 -0
- package/dist/generated/guards.generated.cjs.map +1 -0
- package/dist/generated/guards.generated.d.cts +4 -0
- package/dist/generated/guards.generated.d.ts +4 -0
- package/dist/generated/guards.generated.js +8 -0
- package/dist/generated/guards.generated.js.map +1 -0
- package/dist/generated/materialisers.generated.cjs +44 -0
- package/dist/generated/materialisers.generated.cjs.map +1 -0
- package/dist/generated/materialisers.generated.d.cts +4 -0
- package/dist/generated/materialisers.generated.d.ts +4 -0
- package/dist/generated/materialisers.generated.js +18 -0
- package/dist/generated/materialisers.generated.js.map +1 -0
- package/dist/generated/operations.generated.cjs +110 -0
- package/dist/generated/operations.generated.cjs.map +1 -0
- package/dist/generated/operations.generated.d.cts +337 -0
- package/dist/generated/operations.generated.d.ts +337 -0
- package/dist/generated/operations.generated.js +89 -0
- package/dist/generated/operations.generated.js.map +1 -0
- package/dist/generated/preconditions.generated.cjs +44 -0
- package/dist/generated/preconditions.generated.cjs.map +1 -0
- package/dist/generated/preconditions.generated.d.cts +4 -0
- package/dist/generated/preconditions.generated.d.ts +4 -0
- package/dist/generated/preconditions.generated.js +18 -0
- package/dist/generated/preconditions.generated.js.map +1 -0
- package/dist/guards.generated-DKKDKREA.d.ts +14 -0
- package/dist/guards.generated-hrQ1KPNv.d.cts +14 -0
- package/dist/index.cjs +76 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +99 -0
- package/dist/index.d.ts +99 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/materialisers.generated-BsA1uDW8.d.ts +24 -0
- package/dist/materialisers.generated-nMxTAaVi.d.cts +24 -0
- package/dist/preconditions.generated-DblS13Wq.d.cts +24 -0
- package/dist/preconditions.generated-U7YpVh30.d.ts +24 -0
- package/dist/raw-Dj_2rBSQ.d.cts +19 -0
- package/dist/raw-IxCF_bSS.d.ts +19 -0
- package/dist/raw.cjs +34 -0
- package/dist/raw.cjs.map +1 -0
- package/dist/raw.d.cts +4 -0
- package/dist/raw.d.ts +4 -0
- package/dist/raw.js +8 -0
- package/dist/raw.js.map +1 -0
- package/dist/resources-BKlFxjo8.d.cts +56 -0
- package/dist/resources-CYis1_DS.d.ts +56 -0
- package/dist/resources.cjs +39 -0
- package/dist/resources.cjs.map +1 -0
- package/dist/resources.d.cts +3 -0
- package/dist/resources.d.ts +3 -0
- package/dist/resources.js +14 -0
- package/dist/resources.js.map +1 -0
- package/dist/run/inputs.cjs +51 -0
- package/dist/run/inputs.cjs.map +1 -0
- package/dist/run/inputs.d.cts +91 -0
- package/dist/run/inputs.d.ts +91 -0
- package/dist/run/inputs.js +26 -0
- package/dist/run/inputs.js.map +1 -0
- package/dist/sdk.cjs +60 -0
- package/dist/sdk.cjs.map +1 -0
- package/dist/sdk.d.cts +112 -0
- package/dist/sdk.d.ts +112 -0
- package/dist/sdk.js +40 -0
- package/dist/sdk.js.map +1 -0
- package/dist/types.cjs +17 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +74 -0
- package/dist/types.d.ts +74 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/package.json +81 -0
- package/src/authoring/FlowBuilderCore.ts +270 -0
- package/src/authoring/handles.ts +81 -0
- package/src/authoring/raw.ts +60 -0
- package/src/authoring/signatureArgs.ts +249 -0
- package/src/client.ts +230 -0
- package/src/discovery.ts +51 -0
- package/src/errors.ts +150 -0
- package/src/examples/approveAndDeposit.ts +84 -0
- package/src/examples/callContract.ts +199 -0
- package/src/examples/config.ts +9 -0
- package/src/examples/consolidateToEth.ts +94 -0
- package/src/examples/consolidateToUsdc.ts +95 -0
- package/src/examples/depositFromProxy.ts +87 -0
- package/src/examples/dustSweep.ts +66 -0
- package/src/examples/lifiSwap.ts +56 -0
- package/src/examples/lifiZap.ts +60 -0
- package/src/examples/rawCallWithArithmetic.ts +78 -0
- package/src/examples/readContractState.ts +77 -0
- package/src/examples/run.ts +168 -0
- package/src/examples/splitAndZap.ts +73 -0
- package/src/examples/splitWithArithmetic.ts +93 -0
- package/src/examples/swapAndZap.ts +72 -0
- package/src/examples/swapToRecipient.ts +109 -0
- package/src/examples/swapWithAllowRevert.ts +119 -0
- package/src/examples/swapWithBalanceCheck.ts +73 -0
- package/src/examples/swapWithOutputValidation.ts +125 -0
- package/src/examples/transferTokens.ts +123 -0
- package/src/examples/untypedOpWithTypedRef.ts +77 -0
- package/src/generated/config.generated.ts +174 -0
- package/src/generated/guards.generated.ts +14 -0
- package/src/generated/materialisers.generated.ts +44 -0
- package/src/generated/operations.generated.ts +568 -0
- package/src/generated/preconditions.generated.ts +43 -0
- package/src/index.ts +149 -0
- package/src/raw.ts +10 -0
- package/src/resources.ts +61 -0
- package/src/run/inputs.ts +117 -0
- package/src/sdk.ts +173 -0
- package/src/types.ts +101 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var signatureArgs_exports = {};
|
|
20
|
+
__export(signatureArgs_exports, {
|
|
21
|
+
buildCallWireFormat: () => buildCallWireFormat,
|
|
22
|
+
buildStaticCallWireFormat: () => buildStaticCallWireFormat,
|
|
23
|
+
parseFunctionParams: () => parseFunctionParams,
|
|
24
|
+
toBindRef: () => toBindRef
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(signatureArgs_exports);
|
|
27
|
+
var import_abitype = require("abitype");
|
|
28
|
+
var import_handles = require("./handles.js");
|
|
29
|
+
const parseFunctionParams = (functionSignature) => {
|
|
30
|
+
const parsed = (0, import_abitype.parseAbiItem)(functionSignature);
|
|
31
|
+
if (parsed.type !== "function") {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`core.call: expected a function signature, got "${parsed.type}": "${functionSignature}"`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return parsed.inputs.map((input, index) => {
|
|
37
|
+
if (!input.name) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`core.call: parameter at index ${index} in signature has no name. All parameters must be named for named binds to work.`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return input.name;
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const toBindRef = (bindable) => {
|
|
46
|
+
if ("_tag" in bindable) return (0, import_handles.handleToRef)(bindable);
|
|
47
|
+
return bindable;
|
|
48
|
+
};
|
|
49
|
+
const resolvePositionalArgs = (label, bind, config) => {
|
|
50
|
+
const functionSignature = config.functionSignature;
|
|
51
|
+
if (typeof functionSignature !== "string") {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`${label}: config.functionSignature is required and must be a string`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
const paramNames = parseFunctionParams(functionSignature);
|
|
57
|
+
const paramSet = new Set(paramNames);
|
|
58
|
+
const bindKeys = Object.keys(bind);
|
|
59
|
+
const bindSet = new Set(bindKeys);
|
|
60
|
+
const missing = paramNames.filter((n) => !bindSet.has(n));
|
|
61
|
+
const extra = bindKeys.filter((k) => !paramSet.has(k));
|
|
62
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`${label}: bind keys [${bindKeys.join(
|
|
65
|
+
", "
|
|
66
|
+
)}] do not match signature parameters [${paramNames.join(
|
|
67
|
+
", "
|
|
68
|
+
)}]. Missing: ${missing.join(", ") || "(none)"}. Extra: ${extra.join(", ") || "(none)"}.`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return paramNames.map((name) => {
|
|
72
|
+
const bindable = bind[name];
|
|
73
|
+
if (bindable == null) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`${label}: bind value for parameter "${name}" is undefined`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return toBindRef(bindable);
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
const buildCallWireFormat = (args) => {
|
|
82
|
+
const positionalArgs = resolvePositionalArgs(
|
|
83
|
+
"core.call",
|
|
84
|
+
args.bind,
|
|
85
|
+
args.config
|
|
86
|
+
);
|
|
87
|
+
const hasResource = args.resource != null;
|
|
88
|
+
return {
|
|
89
|
+
op: hasResource ? "core.call" : "core.invoke",
|
|
90
|
+
bind: hasResource ? { input: toBindRef(args.resource) } : {},
|
|
91
|
+
config: { ...args.config, args: positionalArgs },
|
|
92
|
+
...args.guards && args.guards.length > 0 && { guards: args.guards }
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
const buildStaticCallWireFormat = (args) => {
|
|
96
|
+
const positionalArgs = resolvePositionalArgs(
|
|
97
|
+
"core.staticCall",
|
|
98
|
+
args.bind,
|
|
99
|
+
args.config
|
|
100
|
+
);
|
|
101
|
+
return {
|
|
102
|
+
bind: {},
|
|
103
|
+
config: { ...args.config, args: positionalArgs },
|
|
104
|
+
...args.guards && args.guards.length > 0 && { guards: args.guards }
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
108
|
+
0 && (module.exports = {
|
|
109
|
+
buildCallWireFormat,
|
|
110
|
+
buildStaticCallWireFormat,
|
|
111
|
+
parseFunctionParams,
|
|
112
|
+
toBindRef
|
|
113
|
+
});
|
|
114
|
+
//# sourceMappingURL=signatureArgs.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/authoring/signatureArgs.ts"],"sourcesContent":["import type { Ref } from '@lifi/compose-spec';\nimport { type ParseAbiItem, parseAbiItem } from 'abitype';\n\nimport type { AbiTypeToOutputKind, TypedGuard } from '../types.js';\n\nimport type { AnyBindable, CallArgs } from './FlowBuilderCore.js';\nimport type { Bindable, OutputHandle } from './handles.js';\nimport { handleToRef } from './handles.js';\n\n/**\n * Type-level extraction of named bind keys from a function signature string.\n * When `TSig` is a string literal matching a Solidity function signature,\n * resolves to a record whose keys are the parameter names and values are\n * `Bindable<kind>` where the kind is derived from each parameter's Solidity\n * type via `AbiTypeToOutputKind`. For recognised `SolType` parameters\n * (e.g. `uint256`, `address`, `uint128`) the bind slot is precisely typed;\n * for other Solidity types (e.g. tuples) the slot accepts any scalar handle.\n * Falls back to `Record<string, AnyBindable>` for non-literal strings.\n */\nexport type SignatureBind<TSig extends string> = string extends TSig\n ? Record<string, AnyBindable>\n : ParseAbiItem<TSig> extends {\n type: 'function';\n inputs: infer I extends readonly { name: string; type: string }[];\n }\n ? {\n readonly [P in I[number] as P['name']]: Bindable<\n AbiTypeToOutputKind<P['type']>\n >;\n }\n : Record<string, AnyBindable>;\n\n// ---------------------------------------------------------------------------\n// Return-type inference from function signatures\n// ---------------------------------------------------------------------------\n\n/**\n * Describes the output type(s) of a parsed function signature as a\n * human-readable string for inclusion in type-level error messages.\n */\ntype DescribeOutputs<O extends readonly { type: string }[]> =\n O extends readonly [{ type: infer T extends string }] ? T : 'multiple values';\n\n/**\n * A string-literal type that surfaces a clear error when the user provides a\n * function signature whose return type is not supported by core.call.\n * The message is visible in IDE tooltips and compiler diagnostics.\n */\ntype UnsupportedReturnTypeError<TLabel extends string, TSig extends string> =\n ParseAbiItem<TSig> extends {\n type: 'function';\n outputs: infer O extends readonly { type: string }[];\n }\n ? `[TypeError] ${TLabel}: return type '${DescribeOutputs<O>}' is not supported — only 'uint256' or void signatures are allowed`\n : `[TypeError] ${TLabel}: unable to parse return type from signature`;\n\n/**\n * Conditional output type for `core.call` based on the function signature's\n * return type:\n *\n * - `returns (uint256)` → `{ result: OutputHandle }`\n * - No returns clause → `{ result: undefined }`\n * - Anything else → `{ result: \"[TypeError] ...\" }` (compile-time error)\n *\n * When `TSig` is a non-literal `string` (e.g. a variable, not a string\n * constant), the type falls back to `{ result: OutputHandle | undefined }`\n * so that both void and uint256 call sites remain assignable.\n */\nexport type CoreCallResult<TSig extends string> = string extends TSig\n ? { readonly result: OutputHandle<'uint256'> | undefined }\n : ParseAbiItem<TSig> extends { type: 'function'; outputs: readonly [] }\n ? { readonly result: undefined }\n : ParseAbiItem<TSig> extends {\n type: 'function';\n outputs: readonly [{ type: 'uint256' }];\n }\n ? { readonly result: OutputHandle<'uint256'> }\n : { readonly result: UnsupportedReturnTypeError<'core.call', TSig> };\n\n/**\n * Conditional output type for `core.staticCall`. staticCall always reads a\n * value, so void signatures are also rejected:\n *\n * - `returns (uint256)` → `{ result: OutputHandle }`\n * - No returns / other → `{ result: \"[TypeError] ...\" }` (compile-time error)\n */\nexport type StaticCallResult<TSig extends string> = string extends TSig\n ? { readonly result: OutputHandle<'uint256'> }\n : ParseAbiItem<TSig> extends {\n type: 'function';\n outputs: readonly [{ type: 'uint256' }];\n }\n ? { readonly result: OutputHandle<'uint256'> }\n : ParseAbiItem<TSig> extends { type: 'function'; outputs: readonly [] }\n ? {\n readonly result: `[TypeError] core.staticCall: function has no return value — staticCall requires a 'returns (uint256)' signature`;\n }\n : {\n readonly result: UnsupportedReturnTypeError<'core.staticCall', TSig>;\n };\n\n/**\n * Parses a Solidity function signature and returns parameter names in order.\n * Delegates to abitype's runtime `parseAbiItem` — the same parser that powers\n * the compile-time `ParseAbiItem<TSig>` type — so runtime and type-level\n * parsing can never diverge.\n *\n * @throws if the signature is not a valid function signature or a parameter is unnamed\n */\nexport const parseFunctionParams = (functionSignature: string): string[] => {\n const parsed = parseAbiItem(functionSignature);\n if (parsed.type !== 'function') {\n throw new Error(\n `core.call: expected a function signature, got \"${parsed.type}\": \"${functionSignature}\"`,\n );\n }\n\n return parsed.inputs.map((input, index) => {\n if (!input.name) {\n throw new Error(\n `core.call: parameter at index ${index} in signature has no name. All parameters must be named for named binds to work.`,\n );\n }\n return input.name;\n });\n};\n\n/**\n * Converts any `AnyBindable` to a `Ref` (`{ $ref: string }`).\n * Handles carry a `_tag` property and are converted via `handleToRef`;\n * `Ref` objects pass through as-is.\n */\nexport const toBindRef = (bindable: AnyBindable): Ref => {\n if ('_tag' in bindable) return handleToRef(bindable);\n return bindable;\n};\n\nexport interface BuildCallWireFormatInput {\n readonly resource?: AnyBindable;\n readonly bind: Record<string, AnyBindable>;\n readonly config: Record<string, unknown>;\n readonly guards?: readonly TypedGuard[];\n}\n\nexport interface CallWireResult {\n readonly op: 'core.call' | 'core.invoke';\n readonly bind: Record<string, Ref>;\n readonly config: Record<string, unknown>;\n readonly guards?: readonly TypedGuard[];\n}\n\n/**\n * Parses a function signature from `config`, validates bind keys against it,\n * and converts named binds to positional `$ref` args.\n */\nconst resolvePositionalArgs = (\n label: string,\n bind: Record<string, AnyBindable>,\n config: Record<string, unknown>,\n): Ref[] => {\n const functionSignature = config.functionSignature;\n if (typeof functionSignature !== 'string') {\n throw new Error(\n `${label}: config.functionSignature is required and must be a string`,\n );\n }\n\n const paramNames = parseFunctionParams(functionSignature);\n const paramSet = new Set(paramNames);\n const bindKeys = Object.keys(bind);\n const bindSet = new Set(bindKeys);\n\n const missing = paramNames.filter((n) => !bindSet.has(n));\n const extra = bindKeys.filter((k) => !paramSet.has(k));\n\n if (missing.length > 0 || extra.length > 0) {\n throw new Error(\n `${label}: bind keys [${bindKeys.join(\n ', ',\n )}] do not match signature parameters [${paramNames.join(\n ', ',\n )}]. Missing: ${missing.join(', ') || '(none)'}. Extra: ${\n extra.join(', ') || '(none)'\n }.`,\n );\n }\n\n return paramNames.map((name) => {\n const bindable = bind[name];\n if (bindable == null) {\n throw new Error(\n `${label}: bind value for parameter \"${name}\" is undefined`,\n );\n }\n return toBindRef(bindable);\n });\n};\n\n/**\n * Transforms the user-facing `resource` + named `bind` API into the wire\n * format that the backend expects:\n * - With resource: `core.call` with `bind: { input: <resourceRef> }`\n * - Without resource: `core.invoke` with `bind: {}`\n * - `config: { ...userConfig, args: [positional refs...] }`\n */\nexport const buildCallWireFormat = (\n args: BuildCallWireFormatInput,\n): CallWireResult => {\n const positionalArgs = resolvePositionalArgs(\n 'core.call',\n args.bind,\n args.config,\n );\n const hasResource = args.resource != null;\n\n return {\n op: hasResource ? 'core.call' : 'core.invoke',\n bind: hasResource ? { input: toBindRef(args.resource) } : {},\n config: { ...args.config, args: positionalArgs },\n ...(args.guards && args.guards.length > 0 && { guards: args.guards }),\n };\n};\n\nexport interface BuildStaticCallWireFormatInput {\n readonly bind: Record<string, AnyBindable>;\n readonly config: Record<string, unknown>;\n readonly guards?: readonly TypedGuard[];\n}\n\n/**\n * Transforms the user-facing named `bind` API into the wire format that the\n * backend expects for `core.staticCall`. Same as `buildCallWireFormat` but\n * with no `resource` field — staticCall has no resource inputs.\n */\nexport const buildStaticCallWireFormat = (\n args: BuildStaticCallWireFormatInput,\n): CallArgs => {\n const positionalArgs = resolvePositionalArgs(\n 'core.staticCall',\n args.bind,\n args.config,\n );\n\n return {\n bind: {},\n config: { ...args.config, args: positionalArgs },\n ...(args.guards && args.guards.length > 0 && { guards: args.guards }),\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,qBAAgD;AAMhD,qBAA4B;AAsGrB,MAAM,sBAAsB,CAAC,sBAAwC;AAC1E,QAAM,aAAS,6BAAa,iBAAiB;AAC7C,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,IAAI;AAAA,MACR,kDAAkD,OAAO,IAAI,OAAO,iBAAiB;AAAA,IACvF;AAAA,EACF;AAEA,SAAO,OAAO,OAAO,IAAI,CAAC,OAAO,UAAU;AACzC,QAAI,CAAC,MAAM,MAAM;AACf,YAAM,IAAI;AAAA,QACR,iCAAiC,KAAK;AAAA,MACxC;AAAA,IACF;AACA,WAAO,MAAM;AAAA,EACf,CAAC;AACH;AAOO,MAAM,YAAY,CAAC,aAA+B;AACvD,MAAI,UAAU,SAAU,YAAO,4BAAY,QAAQ;AACnD,SAAO;AACT;AAoBA,MAAM,wBAAwB,CAC5B,OACA,MACA,WACU;AACV,QAAM,oBAAoB,OAAO;AACjC,MAAI,OAAO,sBAAsB,UAAU;AACzC,UAAM,IAAI;AAAA,MACR,GAAG,KAAK;AAAA,IACV;AAAA,EACF;AAEA,QAAM,aAAa,oBAAoB,iBAAiB;AACxD,QAAM,WAAW,IAAI,IAAI,UAAU;AACnC,QAAM,WAAW,OAAO,KAAK,IAAI;AACjC,QAAM,UAAU,IAAI,IAAI,QAAQ;AAEhC,QAAM,UAAU,WAAW,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;AACxD,QAAM,QAAQ,SAAS,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;AAErD,MAAI,QAAQ,SAAS,KAAK,MAAM,SAAS,GAAG;AAC1C,UAAM,IAAI;AAAA,MACR,GAAG,KAAK,gBAAgB,SAAS;AAAA,QAC/B;AAAA,MACF,CAAC,wCAAwC,WAAW;AAAA,QAClD;AAAA,MACF,CAAC,eAAe,QAAQ,KAAK,IAAI,KAAK,QAAQ,YAC5C,MAAM,KAAK,IAAI,KAAK,QACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,WAAW,IAAI,CAAC,SAAS;AAC9B,UAAM,WAAW,KAAK,IAAI;AAC1B,QAAI,YAAY,MAAM;AACpB,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,+BAA+B,IAAI;AAAA,MAC7C;AAAA,IACF;AACA,WAAO,UAAU,QAAQ;AAAA,EAC3B,CAAC;AACH;AASO,MAAM,sBAAsB,CACjC,SACmB;AACnB,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AACA,QAAM,cAAc,KAAK,YAAY;AAErC,SAAO;AAAA,IACL,IAAI,cAAc,cAAc;AAAA,IAChC,MAAM,cAAc,EAAE,OAAO,UAAU,KAAK,QAAQ,EAAE,IAAI,CAAC;AAAA,IAC3D,QAAQ,EAAE,GAAG,KAAK,QAAQ,MAAM,eAAe;AAAA,IAC/C,GAAI,KAAK,UAAU,KAAK,OAAO,SAAS,KAAK,EAAE,QAAQ,KAAK,OAAO;AAAA,EACrE;AACF;AAaO,MAAM,4BAA4B,CACvC,SACa;AACb,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AAEA,SAAO;AAAA,IACL,MAAM,CAAC;AAAA,IACP,QAAQ,EAAE,GAAG,KAAK,QAAQ,MAAM,eAAe;AAAA,IAC/C,GAAI,KAAK,UAAU,KAAK,OAAO,SAAS,KAAK,EAAE,QAAQ,KAAK,OAAO;AAAA,EACrE;AACF;","names":[]}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Ref } from '@lifi/compose-spec';
|
|
2
|
+
import { ParseAbiItem } from 'abitype';
|
|
3
|
+
import { AbiTypeToOutputKind, TypedGuard } from '../types.cjs';
|
|
4
|
+
import { AnyBindable, CallArgs } from './FlowBuilderCore.cjs';
|
|
5
|
+
import { Bindable, OutputHandle } from './handles.cjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Type-level extraction of named bind keys from a function signature string.
|
|
9
|
+
* When `TSig` is a string literal matching a Solidity function signature,
|
|
10
|
+
* resolves to a record whose keys are the parameter names and values are
|
|
11
|
+
* `Bindable<kind>` where the kind is derived from each parameter's Solidity
|
|
12
|
+
* type via `AbiTypeToOutputKind`. For recognised `SolType` parameters
|
|
13
|
+
* (e.g. `uint256`, `address`, `uint128`) the bind slot is precisely typed;
|
|
14
|
+
* for other Solidity types (e.g. tuples) the slot accepts any scalar handle.
|
|
15
|
+
* Falls back to `Record<string, AnyBindable>` for non-literal strings.
|
|
16
|
+
*/
|
|
17
|
+
type SignatureBind<TSig extends string> = string extends TSig ? Record<string, AnyBindable> : ParseAbiItem<TSig> extends {
|
|
18
|
+
type: 'function';
|
|
19
|
+
inputs: infer I extends readonly {
|
|
20
|
+
name: string;
|
|
21
|
+
type: string;
|
|
22
|
+
}[];
|
|
23
|
+
} ? {
|
|
24
|
+
readonly [P in I[number] as P['name']]: Bindable<AbiTypeToOutputKind<P['type']>>;
|
|
25
|
+
} : Record<string, AnyBindable>;
|
|
26
|
+
/**
|
|
27
|
+
* Describes the output type(s) of a parsed function signature as a
|
|
28
|
+
* human-readable string for inclusion in type-level error messages.
|
|
29
|
+
*/
|
|
30
|
+
type DescribeOutputs<O extends readonly {
|
|
31
|
+
type: string;
|
|
32
|
+
}[]> = O extends readonly [{
|
|
33
|
+
type: infer T extends string;
|
|
34
|
+
}] ? T : 'multiple values';
|
|
35
|
+
/**
|
|
36
|
+
* A string-literal type that surfaces a clear error when the user provides a
|
|
37
|
+
* function signature whose return type is not supported by core.call.
|
|
38
|
+
* The message is visible in IDE tooltips and compiler diagnostics.
|
|
39
|
+
*/
|
|
40
|
+
type UnsupportedReturnTypeError<TLabel extends string, TSig extends string> = ParseAbiItem<TSig> extends {
|
|
41
|
+
type: 'function';
|
|
42
|
+
outputs: infer O extends readonly {
|
|
43
|
+
type: string;
|
|
44
|
+
}[];
|
|
45
|
+
} ? `[TypeError] ${TLabel}: return type '${DescribeOutputs<O>}' is not supported — only 'uint256' or void signatures are allowed` : `[TypeError] ${TLabel}: unable to parse return type from signature`;
|
|
46
|
+
/**
|
|
47
|
+
* Conditional output type for `core.call` based on the function signature's
|
|
48
|
+
* return type:
|
|
49
|
+
*
|
|
50
|
+
* - `returns (uint256)` → `{ result: OutputHandle }`
|
|
51
|
+
* - No returns clause → `{ result: undefined }`
|
|
52
|
+
* - Anything else → `{ result: "[TypeError] ..." }` (compile-time error)
|
|
53
|
+
*
|
|
54
|
+
* When `TSig` is a non-literal `string` (e.g. a variable, not a string
|
|
55
|
+
* constant), the type falls back to `{ result: OutputHandle | undefined }`
|
|
56
|
+
* so that both void and uint256 call sites remain assignable.
|
|
57
|
+
*/
|
|
58
|
+
type CoreCallResult<TSig extends string> = string extends TSig ? {
|
|
59
|
+
readonly result: OutputHandle<'uint256'> | undefined;
|
|
60
|
+
} : ParseAbiItem<TSig> extends {
|
|
61
|
+
type: 'function';
|
|
62
|
+
outputs: readonly [];
|
|
63
|
+
} ? {
|
|
64
|
+
readonly result: undefined;
|
|
65
|
+
} : ParseAbiItem<TSig> extends {
|
|
66
|
+
type: 'function';
|
|
67
|
+
outputs: readonly [{
|
|
68
|
+
type: 'uint256';
|
|
69
|
+
}];
|
|
70
|
+
} ? {
|
|
71
|
+
readonly result: OutputHandle<'uint256'>;
|
|
72
|
+
} : {
|
|
73
|
+
readonly result: UnsupportedReturnTypeError<'core.call', TSig>;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Conditional output type for `core.staticCall`. staticCall always reads a
|
|
77
|
+
* value, so void signatures are also rejected:
|
|
78
|
+
*
|
|
79
|
+
* - `returns (uint256)` → `{ result: OutputHandle }`
|
|
80
|
+
* - No returns / other → `{ result: "[TypeError] ..." }` (compile-time error)
|
|
81
|
+
*/
|
|
82
|
+
type StaticCallResult<TSig extends string> = string extends TSig ? {
|
|
83
|
+
readonly result: OutputHandle<'uint256'>;
|
|
84
|
+
} : ParseAbiItem<TSig> extends {
|
|
85
|
+
type: 'function';
|
|
86
|
+
outputs: readonly [{
|
|
87
|
+
type: 'uint256';
|
|
88
|
+
}];
|
|
89
|
+
} ? {
|
|
90
|
+
readonly result: OutputHandle<'uint256'>;
|
|
91
|
+
} : ParseAbiItem<TSig> extends {
|
|
92
|
+
type: 'function';
|
|
93
|
+
outputs: readonly [];
|
|
94
|
+
} ? {
|
|
95
|
+
readonly result: `[TypeError] core.staticCall: function has no return value — staticCall requires a 'returns (uint256)' signature`;
|
|
96
|
+
} : {
|
|
97
|
+
readonly result: UnsupportedReturnTypeError<'core.staticCall', TSig>;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Parses a Solidity function signature and returns parameter names in order.
|
|
101
|
+
* Delegates to abitype's runtime `parseAbiItem` — the same parser that powers
|
|
102
|
+
* the compile-time `ParseAbiItem<TSig>` type — so runtime and type-level
|
|
103
|
+
* parsing can never diverge.
|
|
104
|
+
*
|
|
105
|
+
* @throws if the signature is not a valid function signature or a parameter is unnamed
|
|
106
|
+
*/
|
|
107
|
+
declare const parseFunctionParams: (functionSignature: string) => string[];
|
|
108
|
+
/**
|
|
109
|
+
* Converts any `AnyBindable` to a `Ref` (`{ $ref: string }`).
|
|
110
|
+
* Handles carry a `_tag` property and are converted via `handleToRef`;
|
|
111
|
+
* `Ref` objects pass through as-is.
|
|
112
|
+
*/
|
|
113
|
+
declare const toBindRef: (bindable: AnyBindable) => Ref;
|
|
114
|
+
interface BuildCallWireFormatInput {
|
|
115
|
+
readonly resource?: AnyBindable;
|
|
116
|
+
readonly bind: Record<string, AnyBindable>;
|
|
117
|
+
readonly config: Record<string, unknown>;
|
|
118
|
+
readonly guards?: readonly TypedGuard[];
|
|
119
|
+
}
|
|
120
|
+
interface CallWireResult {
|
|
121
|
+
readonly op: 'core.call' | 'core.invoke';
|
|
122
|
+
readonly bind: Record<string, Ref>;
|
|
123
|
+
readonly config: Record<string, unknown>;
|
|
124
|
+
readonly guards?: readonly TypedGuard[];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Transforms the user-facing `resource` + named `bind` API into the wire
|
|
128
|
+
* format that the backend expects:
|
|
129
|
+
* - With resource: `core.call` with `bind: { input: <resourceRef> }`
|
|
130
|
+
* - Without resource: `core.invoke` with `bind: {}`
|
|
131
|
+
* - `config: { ...userConfig, args: [positional refs...] }`
|
|
132
|
+
*/
|
|
133
|
+
declare const buildCallWireFormat: (args: BuildCallWireFormatInput) => CallWireResult;
|
|
134
|
+
interface BuildStaticCallWireFormatInput {
|
|
135
|
+
readonly bind: Record<string, AnyBindable>;
|
|
136
|
+
readonly config: Record<string, unknown>;
|
|
137
|
+
readonly guards?: readonly TypedGuard[];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Transforms the user-facing named `bind` API into the wire format that the
|
|
141
|
+
* backend expects for `core.staticCall`. Same as `buildCallWireFormat` but
|
|
142
|
+
* with no `resource` field — staticCall has no resource inputs.
|
|
143
|
+
*/
|
|
144
|
+
declare const buildStaticCallWireFormat: (args: BuildStaticCallWireFormatInput) => CallArgs;
|
|
145
|
+
|
|
146
|
+
export { type BuildCallWireFormatInput, type BuildStaticCallWireFormatInput, type CallWireResult, type CoreCallResult, type SignatureBind, type StaticCallResult, buildCallWireFormat, buildStaticCallWireFormat, parseFunctionParams, toBindRef };
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Ref } from '@lifi/compose-spec';
|
|
2
|
+
import { ParseAbiItem } from 'abitype';
|
|
3
|
+
import { AbiTypeToOutputKind, TypedGuard } from '../types.js';
|
|
4
|
+
import { AnyBindable, CallArgs } from './FlowBuilderCore.js';
|
|
5
|
+
import { Bindable, OutputHandle } from './handles.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Type-level extraction of named bind keys from a function signature string.
|
|
9
|
+
* When `TSig` is a string literal matching a Solidity function signature,
|
|
10
|
+
* resolves to a record whose keys are the parameter names and values are
|
|
11
|
+
* `Bindable<kind>` where the kind is derived from each parameter's Solidity
|
|
12
|
+
* type via `AbiTypeToOutputKind`. For recognised `SolType` parameters
|
|
13
|
+
* (e.g. `uint256`, `address`, `uint128`) the bind slot is precisely typed;
|
|
14
|
+
* for other Solidity types (e.g. tuples) the slot accepts any scalar handle.
|
|
15
|
+
* Falls back to `Record<string, AnyBindable>` for non-literal strings.
|
|
16
|
+
*/
|
|
17
|
+
type SignatureBind<TSig extends string> = string extends TSig ? Record<string, AnyBindable> : ParseAbiItem<TSig> extends {
|
|
18
|
+
type: 'function';
|
|
19
|
+
inputs: infer I extends readonly {
|
|
20
|
+
name: string;
|
|
21
|
+
type: string;
|
|
22
|
+
}[];
|
|
23
|
+
} ? {
|
|
24
|
+
readonly [P in I[number] as P['name']]: Bindable<AbiTypeToOutputKind<P['type']>>;
|
|
25
|
+
} : Record<string, AnyBindable>;
|
|
26
|
+
/**
|
|
27
|
+
* Describes the output type(s) of a parsed function signature as a
|
|
28
|
+
* human-readable string for inclusion in type-level error messages.
|
|
29
|
+
*/
|
|
30
|
+
type DescribeOutputs<O extends readonly {
|
|
31
|
+
type: string;
|
|
32
|
+
}[]> = O extends readonly [{
|
|
33
|
+
type: infer T extends string;
|
|
34
|
+
}] ? T : 'multiple values';
|
|
35
|
+
/**
|
|
36
|
+
* A string-literal type that surfaces a clear error when the user provides a
|
|
37
|
+
* function signature whose return type is not supported by core.call.
|
|
38
|
+
* The message is visible in IDE tooltips and compiler diagnostics.
|
|
39
|
+
*/
|
|
40
|
+
type UnsupportedReturnTypeError<TLabel extends string, TSig extends string> = ParseAbiItem<TSig> extends {
|
|
41
|
+
type: 'function';
|
|
42
|
+
outputs: infer O extends readonly {
|
|
43
|
+
type: string;
|
|
44
|
+
}[];
|
|
45
|
+
} ? `[TypeError] ${TLabel}: return type '${DescribeOutputs<O>}' is not supported — only 'uint256' or void signatures are allowed` : `[TypeError] ${TLabel}: unable to parse return type from signature`;
|
|
46
|
+
/**
|
|
47
|
+
* Conditional output type for `core.call` based on the function signature's
|
|
48
|
+
* return type:
|
|
49
|
+
*
|
|
50
|
+
* - `returns (uint256)` → `{ result: OutputHandle }`
|
|
51
|
+
* - No returns clause → `{ result: undefined }`
|
|
52
|
+
* - Anything else → `{ result: "[TypeError] ..." }` (compile-time error)
|
|
53
|
+
*
|
|
54
|
+
* When `TSig` is a non-literal `string` (e.g. a variable, not a string
|
|
55
|
+
* constant), the type falls back to `{ result: OutputHandle | undefined }`
|
|
56
|
+
* so that both void and uint256 call sites remain assignable.
|
|
57
|
+
*/
|
|
58
|
+
type CoreCallResult<TSig extends string> = string extends TSig ? {
|
|
59
|
+
readonly result: OutputHandle<'uint256'> | undefined;
|
|
60
|
+
} : ParseAbiItem<TSig> extends {
|
|
61
|
+
type: 'function';
|
|
62
|
+
outputs: readonly [];
|
|
63
|
+
} ? {
|
|
64
|
+
readonly result: undefined;
|
|
65
|
+
} : ParseAbiItem<TSig> extends {
|
|
66
|
+
type: 'function';
|
|
67
|
+
outputs: readonly [{
|
|
68
|
+
type: 'uint256';
|
|
69
|
+
}];
|
|
70
|
+
} ? {
|
|
71
|
+
readonly result: OutputHandle<'uint256'>;
|
|
72
|
+
} : {
|
|
73
|
+
readonly result: UnsupportedReturnTypeError<'core.call', TSig>;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Conditional output type for `core.staticCall`. staticCall always reads a
|
|
77
|
+
* value, so void signatures are also rejected:
|
|
78
|
+
*
|
|
79
|
+
* - `returns (uint256)` → `{ result: OutputHandle }`
|
|
80
|
+
* - No returns / other → `{ result: "[TypeError] ..." }` (compile-time error)
|
|
81
|
+
*/
|
|
82
|
+
type StaticCallResult<TSig extends string> = string extends TSig ? {
|
|
83
|
+
readonly result: OutputHandle<'uint256'>;
|
|
84
|
+
} : ParseAbiItem<TSig> extends {
|
|
85
|
+
type: 'function';
|
|
86
|
+
outputs: readonly [{
|
|
87
|
+
type: 'uint256';
|
|
88
|
+
}];
|
|
89
|
+
} ? {
|
|
90
|
+
readonly result: OutputHandle<'uint256'>;
|
|
91
|
+
} : ParseAbiItem<TSig> extends {
|
|
92
|
+
type: 'function';
|
|
93
|
+
outputs: readonly [];
|
|
94
|
+
} ? {
|
|
95
|
+
readonly result: `[TypeError] core.staticCall: function has no return value — staticCall requires a 'returns (uint256)' signature`;
|
|
96
|
+
} : {
|
|
97
|
+
readonly result: UnsupportedReturnTypeError<'core.staticCall', TSig>;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Parses a Solidity function signature and returns parameter names in order.
|
|
101
|
+
* Delegates to abitype's runtime `parseAbiItem` — the same parser that powers
|
|
102
|
+
* the compile-time `ParseAbiItem<TSig>` type — so runtime and type-level
|
|
103
|
+
* parsing can never diverge.
|
|
104
|
+
*
|
|
105
|
+
* @throws if the signature is not a valid function signature or a parameter is unnamed
|
|
106
|
+
*/
|
|
107
|
+
declare const parseFunctionParams: (functionSignature: string) => string[];
|
|
108
|
+
/**
|
|
109
|
+
* Converts any `AnyBindable` to a `Ref` (`{ $ref: string }`).
|
|
110
|
+
* Handles carry a `_tag` property and are converted via `handleToRef`;
|
|
111
|
+
* `Ref` objects pass through as-is.
|
|
112
|
+
*/
|
|
113
|
+
declare const toBindRef: (bindable: AnyBindable) => Ref;
|
|
114
|
+
interface BuildCallWireFormatInput {
|
|
115
|
+
readonly resource?: AnyBindable;
|
|
116
|
+
readonly bind: Record<string, AnyBindable>;
|
|
117
|
+
readonly config: Record<string, unknown>;
|
|
118
|
+
readonly guards?: readonly TypedGuard[];
|
|
119
|
+
}
|
|
120
|
+
interface CallWireResult {
|
|
121
|
+
readonly op: 'core.call' | 'core.invoke';
|
|
122
|
+
readonly bind: Record<string, Ref>;
|
|
123
|
+
readonly config: Record<string, unknown>;
|
|
124
|
+
readonly guards?: readonly TypedGuard[];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Transforms the user-facing `resource` + named `bind` API into the wire
|
|
128
|
+
* format that the backend expects:
|
|
129
|
+
* - With resource: `core.call` with `bind: { input: <resourceRef> }`
|
|
130
|
+
* - Without resource: `core.invoke` with `bind: {}`
|
|
131
|
+
* - `config: { ...userConfig, args: [positional refs...] }`
|
|
132
|
+
*/
|
|
133
|
+
declare const buildCallWireFormat: (args: BuildCallWireFormatInput) => CallWireResult;
|
|
134
|
+
interface BuildStaticCallWireFormatInput {
|
|
135
|
+
readonly bind: Record<string, AnyBindable>;
|
|
136
|
+
readonly config: Record<string, unknown>;
|
|
137
|
+
readonly guards?: readonly TypedGuard[];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Transforms the user-facing named `bind` API into the wire format that the
|
|
141
|
+
* backend expects for `core.staticCall`. Same as `buildCallWireFormat` but
|
|
142
|
+
* with no `resource` field — staticCall has no resource inputs.
|
|
143
|
+
*/
|
|
144
|
+
declare const buildStaticCallWireFormat: (args: BuildStaticCallWireFormatInput) => CallArgs;
|
|
145
|
+
|
|
146
|
+
export { type BuildCallWireFormatInput, type BuildStaticCallWireFormatInput, type CallWireResult, type CoreCallResult, type SignatureBind, type StaticCallResult, buildCallWireFormat, buildStaticCallWireFormat, parseFunctionParams, toBindRef };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { parseAbiItem } from "abitype";
|
|
2
|
+
import { handleToRef } from "./handles.js";
|
|
3
|
+
const parseFunctionParams = (functionSignature) => {
|
|
4
|
+
const parsed = parseAbiItem(functionSignature);
|
|
5
|
+
if (parsed.type !== "function") {
|
|
6
|
+
throw new Error(
|
|
7
|
+
`core.call: expected a function signature, got "${parsed.type}": "${functionSignature}"`
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
return parsed.inputs.map((input, index) => {
|
|
11
|
+
if (!input.name) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
`core.call: parameter at index ${index} in signature has no name. All parameters must be named for named binds to work.`
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
return input.name;
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
const toBindRef = (bindable) => {
|
|
20
|
+
if ("_tag" in bindable) return handleToRef(bindable);
|
|
21
|
+
return bindable;
|
|
22
|
+
};
|
|
23
|
+
const resolvePositionalArgs = (label, bind, config) => {
|
|
24
|
+
const functionSignature = config.functionSignature;
|
|
25
|
+
if (typeof functionSignature !== "string") {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`${label}: config.functionSignature is required and must be a string`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
const paramNames = parseFunctionParams(functionSignature);
|
|
31
|
+
const paramSet = new Set(paramNames);
|
|
32
|
+
const bindKeys = Object.keys(bind);
|
|
33
|
+
const bindSet = new Set(bindKeys);
|
|
34
|
+
const missing = paramNames.filter((n) => !bindSet.has(n));
|
|
35
|
+
const extra = bindKeys.filter((k) => !paramSet.has(k));
|
|
36
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`${label}: bind keys [${bindKeys.join(
|
|
39
|
+
", "
|
|
40
|
+
)}] do not match signature parameters [${paramNames.join(
|
|
41
|
+
", "
|
|
42
|
+
)}]. Missing: ${missing.join(", ") || "(none)"}. Extra: ${extra.join(", ") || "(none)"}.`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return paramNames.map((name) => {
|
|
46
|
+
const bindable = bind[name];
|
|
47
|
+
if (bindable == null) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`${label}: bind value for parameter "${name}" is undefined`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
return toBindRef(bindable);
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
const buildCallWireFormat = (args) => {
|
|
56
|
+
const positionalArgs = resolvePositionalArgs(
|
|
57
|
+
"core.call",
|
|
58
|
+
args.bind,
|
|
59
|
+
args.config
|
|
60
|
+
);
|
|
61
|
+
const hasResource = args.resource != null;
|
|
62
|
+
return {
|
|
63
|
+
op: hasResource ? "core.call" : "core.invoke",
|
|
64
|
+
bind: hasResource ? { input: toBindRef(args.resource) } : {},
|
|
65
|
+
config: { ...args.config, args: positionalArgs },
|
|
66
|
+
...args.guards && args.guards.length > 0 && { guards: args.guards }
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
const buildStaticCallWireFormat = (args) => {
|
|
70
|
+
const positionalArgs = resolvePositionalArgs(
|
|
71
|
+
"core.staticCall",
|
|
72
|
+
args.bind,
|
|
73
|
+
args.config
|
|
74
|
+
);
|
|
75
|
+
return {
|
|
76
|
+
bind: {},
|
|
77
|
+
config: { ...args.config, args: positionalArgs },
|
|
78
|
+
...args.guards && args.guards.length > 0 && { guards: args.guards }
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
export {
|
|
82
|
+
buildCallWireFormat,
|
|
83
|
+
buildStaticCallWireFormat,
|
|
84
|
+
parseFunctionParams,
|
|
85
|
+
toBindRef
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=signatureArgs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/authoring/signatureArgs.ts"],"sourcesContent":["import type { Ref } from '@lifi/compose-spec';\nimport { type ParseAbiItem, parseAbiItem } from 'abitype';\n\nimport type { AbiTypeToOutputKind, TypedGuard } from '../types.js';\n\nimport type { AnyBindable, CallArgs } from './FlowBuilderCore.js';\nimport type { Bindable, OutputHandle } from './handles.js';\nimport { handleToRef } from './handles.js';\n\n/**\n * Type-level extraction of named bind keys from a function signature string.\n * When `TSig` is a string literal matching a Solidity function signature,\n * resolves to a record whose keys are the parameter names and values are\n * `Bindable<kind>` where the kind is derived from each parameter's Solidity\n * type via `AbiTypeToOutputKind`. For recognised `SolType` parameters\n * (e.g. `uint256`, `address`, `uint128`) the bind slot is precisely typed;\n * for other Solidity types (e.g. tuples) the slot accepts any scalar handle.\n * Falls back to `Record<string, AnyBindable>` for non-literal strings.\n */\nexport type SignatureBind<TSig extends string> = string extends TSig\n ? Record<string, AnyBindable>\n : ParseAbiItem<TSig> extends {\n type: 'function';\n inputs: infer I extends readonly { name: string; type: string }[];\n }\n ? {\n readonly [P in I[number] as P['name']]: Bindable<\n AbiTypeToOutputKind<P['type']>\n >;\n }\n : Record<string, AnyBindable>;\n\n// ---------------------------------------------------------------------------\n// Return-type inference from function signatures\n// ---------------------------------------------------------------------------\n\n/**\n * Describes the output type(s) of a parsed function signature as a\n * human-readable string for inclusion in type-level error messages.\n */\ntype DescribeOutputs<O extends readonly { type: string }[]> =\n O extends readonly [{ type: infer T extends string }] ? T : 'multiple values';\n\n/**\n * A string-literal type that surfaces a clear error when the user provides a\n * function signature whose return type is not supported by core.call.\n * The message is visible in IDE tooltips and compiler diagnostics.\n */\ntype UnsupportedReturnTypeError<TLabel extends string, TSig extends string> =\n ParseAbiItem<TSig> extends {\n type: 'function';\n outputs: infer O extends readonly { type: string }[];\n }\n ? `[TypeError] ${TLabel}: return type '${DescribeOutputs<O>}' is not supported — only 'uint256' or void signatures are allowed`\n : `[TypeError] ${TLabel}: unable to parse return type from signature`;\n\n/**\n * Conditional output type for `core.call` based on the function signature's\n * return type:\n *\n * - `returns (uint256)` → `{ result: OutputHandle }`\n * - No returns clause → `{ result: undefined }`\n * - Anything else → `{ result: \"[TypeError] ...\" }` (compile-time error)\n *\n * When `TSig` is a non-literal `string` (e.g. a variable, not a string\n * constant), the type falls back to `{ result: OutputHandle | undefined }`\n * so that both void and uint256 call sites remain assignable.\n */\nexport type CoreCallResult<TSig extends string> = string extends TSig\n ? { readonly result: OutputHandle<'uint256'> | undefined }\n : ParseAbiItem<TSig> extends { type: 'function'; outputs: readonly [] }\n ? { readonly result: undefined }\n : ParseAbiItem<TSig> extends {\n type: 'function';\n outputs: readonly [{ type: 'uint256' }];\n }\n ? { readonly result: OutputHandle<'uint256'> }\n : { readonly result: UnsupportedReturnTypeError<'core.call', TSig> };\n\n/**\n * Conditional output type for `core.staticCall`. staticCall always reads a\n * value, so void signatures are also rejected:\n *\n * - `returns (uint256)` → `{ result: OutputHandle }`\n * - No returns / other → `{ result: \"[TypeError] ...\" }` (compile-time error)\n */\nexport type StaticCallResult<TSig extends string> = string extends TSig\n ? { readonly result: OutputHandle<'uint256'> }\n : ParseAbiItem<TSig> extends {\n type: 'function';\n outputs: readonly [{ type: 'uint256' }];\n }\n ? { readonly result: OutputHandle<'uint256'> }\n : ParseAbiItem<TSig> extends { type: 'function'; outputs: readonly [] }\n ? {\n readonly result: `[TypeError] core.staticCall: function has no return value — staticCall requires a 'returns (uint256)' signature`;\n }\n : {\n readonly result: UnsupportedReturnTypeError<'core.staticCall', TSig>;\n };\n\n/**\n * Parses a Solidity function signature and returns parameter names in order.\n * Delegates to abitype's runtime `parseAbiItem` — the same parser that powers\n * the compile-time `ParseAbiItem<TSig>` type — so runtime and type-level\n * parsing can never diverge.\n *\n * @throws if the signature is not a valid function signature or a parameter is unnamed\n */\nexport const parseFunctionParams = (functionSignature: string): string[] => {\n const parsed = parseAbiItem(functionSignature);\n if (parsed.type !== 'function') {\n throw new Error(\n `core.call: expected a function signature, got \"${parsed.type}\": \"${functionSignature}\"`,\n );\n }\n\n return parsed.inputs.map((input, index) => {\n if (!input.name) {\n throw new Error(\n `core.call: parameter at index ${index} in signature has no name. All parameters must be named for named binds to work.`,\n );\n }\n return input.name;\n });\n};\n\n/**\n * Converts any `AnyBindable` to a `Ref` (`{ $ref: string }`).\n * Handles carry a `_tag` property and are converted via `handleToRef`;\n * `Ref` objects pass through as-is.\n */\nexport const toBindRef = (bindable: AnyBindable): Ref => {\n if ('_tag' in bindable) return handleToRef(bindable);\n return bindable;\n};\n\nexport interface BuildCallWireFormatInput {\n readonly resource?: AnyBindable;\n readonly bind: Record<string, AnyBindable>;\n readonly config: Record<string, unknown>;\n readonly guards?: readonly TypedGuard[];\n}\n\nexport interface CallWireResult {\n readonly op: 'core.call' | 'core.invoke';\n readonly bind: Record<string, Ref>;\n readonly config: Record<string, unknown>;\n readonly guards?: readonly TypedGuard[];\n}\n\n/**\n * Parses a function signature from `config`, validates bind keys against it,\n * and converts named binds to positional `$ref` args.\n */\nconst resolvePositionalArgs = (\n label: string,\n bind: Record<string, AnyBindable>,\n config: Record<string, unknown>,\n): Ref[] => {\n const functionSignature = config.functionSignature;\n if (typeof functionSignature !== 'string') {\n throw new Error(\n `${label}: config.functionSignature is required and must be a string`,\n );\n }\n\n const paramNames = parseFunctionParams(functionSignature);\n const paramSet = new Set(paramNames);\n const bindKeys = Object.keys(bind);\n const bindSet = new Set(bindKeys);\n\n const missing = paramNames.filter((n) => !bindSet.has(n));\n const extra = bindKeys.filter((k) => !paramSet.has(k));\n\n if (missing.length > 0 || extra.length > 0) {\n throw new Error(\n `${label}: bind keys [${bindKeys.join(\n ', ',\n )}] do not match signature parameters [${paramNames.join(\n ', ',\n )}]. Missing: ${missing.join(', ') || '(none)'}. Extra: ${\n extra.join(', ') || '(none)'\n }.`,\n );\n }\n\n return paramNames.map((name) => {\n const bindable = bind[name];\n if (bindable == null) {\n throw new Error(\n `${label}: bind value for parameter \"${name}\" is undefined`,\n );\n }\n return toBindRef(bindable);\n });\n};\n\n/**\n * Transforms the user-facing `resource` + named `bind` API into the wire\n * format that the backend expects:\n * - With resource: `core.call` with `bind: { input: <resourceRef> }`\n * - Without resource: `core.invoke` with `bind: {}`\n * - `config: { ...userConfig, args: [positional refs...] }`\n */\nexport const buildCallWireFormat = (\n args: BuildCallWireFormatInput,\n): CallWireResult => {\n const positionalArgs = resolvePositionalArgs(\n 'core.call',\n args.bind,\n args.config,\n );\n const hasResource = args.resource != null;\n\n return {\n op: hasResource ? 'core.call' : 'core.invoke',\n bind: hasResource ? { input: toBindRef(args.resource) } : {},\n config: { ...args.config, args: positionalArgs },\n ...(args.guards && args.guards.length > 0 && { guards: args.guards }),\n };\n};\n\nexport interface BuildStaticCallWireFormatInput {\n readonly bind: Record<string, AnyBindable>;\n readonly config: Record<string, unknown>;\n readonly guards?: readonly TypedGuard[];\n}\n\n/**\n * Transforms the user-facing named `bind` API into the wire format that the\n * backend expects for `core.staticCall`. Same as `buildCallWireFormat` but\n * with no `resource` field — staticCall has no resource inputs.\n */\nexport const buildStaticCallWireFormat = (\n args: BuildStaticCallWireFormatInput,\n): CallArgs => {\n const positionalArgs = resolvePositionalArgs(\n 'core.staticCall',\n args.bind,\n args.config,\n );\n\n return {\n bind: {},\n config: { ...args.config, args: positionalArgs },\n ...(args.guards && args.guards.length > 0 && { guards: args.guards }),\n };\n};\n"],"mappings":"AACA,SAA4B,oBAAoB;AAMhD,SAAS,mBAAmB;AAsGrB,MAAM,sBAAsB,CAAC,sBAAwC;AAC1E,QAAM,SAAS,aAAa,iBAAiB;AAC7C,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,IAAI;AAAA,MACR,kDAAkD,OAAO,IAAI,OAAO,iBAAiB;AAAA,IACvF;AAAA,EACF;AAEA,SAAO,OAAO,OAAO,IAAI,CAAC,OAAO,UAAU;AACzC,QAAI,CAAC,MAAM,MAAM;AACf,YAAM,IAAI;AAAA,QACR,iCAAiC,KAAK;AAAA,MACxC;AAAA,IACF;AACA,WAAO,MAAM;AAAA,EACf,CAAC;AACH;AAOO,MAAM,YAAY,CAAC,aAA+B;AACvD,MAAI,UAAU,SAAU,QAAO,YAAY,QAAQ;AACnD,SAAO;AACT;AAoBA,MAAM,wBAAwB,CAC5B,OACA,MACA,WACU;AACV,QAAM,oBAAoB,OAAO;AACjC,MAAI,OAAO,sBAAsB,UAAU;AACzC,UAAM,IAAI;AAAA,MACR,GAAG,KAAK;AAAA,IACV;AAAA,EACF;AAEA,QAAM,aAAa,oBAAoB,iBAAiB;AACxD,QAAM,WAAW,IAAI,IAAI,UAAU;AACnC,QAAM,WAAW,OAAO,KAAK,IAAI;AACjC,QAAM,UAAU,IAAI,IAAI,QAAQ;AAEhC,QAAM,UAAU,WAAW,OAAO,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;AACxD,QAAM,QAAQ,SAAS,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;AAErD,MAAI,QAAQ,SAAS,KAAK,MAAM,SAAS,GAAG;AAC1C,UAAM,IAAI;AAAA,MACR,GAAG,KAAK,gBAAgB,SAAS;AAAA,QAC/B;AAAA,MACF,CAAC,wCAAwC,WAAW;AAAA,QAClD;AAAA,MACF,CAAC,eAAe,QAAQ,KAAK,IAAI,KAAK,QAAQ,YAC5C,MAAM,KAAK,IAAI,KAAK,QACtB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,WAAW,IAAI,CAAC,SAAS;AAC9B,UAAM,WAAW,KAAK,IAAI;AAC1B,QAAI,YAAY,MAAM;AACpB,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,+BAA+B,IAAI;AAAA,MAC7C;AAAA,IACF;AACA,WAAO,UAAU,QAAQ;AAAA,EAC3B,CAAC;AACH;AASO,MAAM,sBAAsB,CACjC,SACmB;AACnB,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AACA,QAAM,cAAc,KAAK,YAAY;AAErC,SAAO;AAAA,IACL,IAAI,cAAc,cAAc;AAAA,IAChC,MAAM,cAAc,EAAE,OAAO,UAAU,KAAK,QAAQ,EAAE,IAAI,CAAC;AAAA,IAC3D,QAAQ,EAAE,GAAG,KAAK,QAAQ,MAAM,eAAe;AAAA,IAC/C,GAAI,KAAK,UAAU,KAAK,OAAO,SAAS,KAAK,EAAE,QAAQ,KAAK,OAAO;AAAA,EACrE;AACF;AAaO,MAAM,4BAA4B,CACvC,SACa;AACb,QAAM,iBAAiB;AAAA,IACrB;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AAEA,SAAO;AAAA,IACL,MAAM,CAAC;AAAA,IACP,QAAQ,EAAE,GAAG,KAAK,QAAQ,MAAM,eAAe;AAAA,IAC/C,GAAI,KAAK,UAAU,KAAK,OAAO,SAAS,KAAK,EAAE,QAAQ,KAAK,OAAO;AAAA,EACrE;AACF;","names":[]}
|