{"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 === undefined) {\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 !== undefined;\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,aAAa,QAAW;AAC1B,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,aAAa;AAEtC,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":[]}