@capxul/sdk 4.20.0-beta.33 → 4.20.0-beta.35

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.
@@ -1,6 +1,6 @@
1
1
  import { Cause, Clock, Context, Data, Deferred, Effect, Exit, Fiber, Layer, Option, Predicate, Queue, Ref, Result, Schema, SchemaAST, SchemaGetter, SchemaIssue, SchemaParser } from "effect";
2
2
  import { makeFunctionReference } from "convex/server";
3
- import { bytesToHex, concat, decodeErrorResult, encodeAbiParameters, encodeFunctionData, encodePacked, formatUnits, getContractAddress, hashTypedData, isAddress, isHex, keccak256, pad, padHex, parseAbiParameters, recoverAddress, recoverTypedDataAddress, toBytes, toFunctionSignature, toHex } from "viem";
3
+ import { bytesToHex, concat, decodeErrorResult, encodeAbiParameters, encodeFunctionData, encodePacked, formatUnits, getContractAddress, hashTypedData, isAddress, isHex, keccak256, pad, padHex, parseAbiParameters, recoverAddress, recoverTypedDataAddress, sha256, toBytes, toFunctionSignature, toHex } from "viem";
4
4
  import { getUserOperationHash } from "viem/account-abstraction";
5
5
  //#region src/access/actor-references.ts
6
6
  function actorReferenceToBackend(actor) {
@@ -1966,6 +1966,15 @@ const CAPXUL_ERROR_CODES = [
1966
1966
  "WORK_DIED",
1967
1967
  "ACTOR_STOPPED"
1968
1968
  ];
1969
+ /** The existing Organization authority refusal vocabulary. */
1970
+ const ROLE_PERMISSION_DENIED_REASONS = [
1971
+ "over_cap",
1972
+ "daily_cap",
1973
+ "not_member",
1974
+ "disallowed_recipient",
1975
+ "condition_violation",
1976
+ "budget_exhausted"
1977
+ ];
1969
1978
  /**
1970
1979
  * The error codes that represent an expected product outcome rather than a
1971
1980
  * defect. The SDK and backend observation boundaries both classify failures
@@ -4307,7 +4316,7 @@ function isQuantityHex(value) {
4307
4316
  function isBytes32(value) {
4308
4317
  return typeof value === "string" && BYTES32_HEX.test(value);
4309
4318
  }
4310
- function refused(field, shape, value) {
4319
+ function refused$1(field, shape, value) {
4311
4320
  throw Errors.invalidInput(field, invalidValueReason(`must be ${shape}`, value));
4312
4321
  }
4313
4322
  /** Rebuilding the `0x` prefix keeps the result a `Hex`; lowercasing never changes the bytes. */
@@ -4316,19 +4325,19 @@ function lowered(value) {
4316
4325
  }
4317
4326
  /** Hex data exactly as given: case kept, for text another party compares or hashes as is. */
4318
4327
  function toExactHex(value, field = "value") {
4319
- return isHex$1(value) ? value : refused(field, "0x-prefixed hex", value);
4328
+ return isHex$1(value) ? value : refused$1(field, "0x-prefixed hex", value);
4320
4329
  }
4321
4330
  /** Hex data, lowercased. */
4322
4331
  function toLowerHex(value, field = "value") {
4323
- return isHex$1(value) ? lowered(value) : refused(field, "0x-prefixed hex", value);
4332
+ return isHex$1(value) ? lowered(value) : refused$1(field, "0x-prefixed hex", value);
4324
4333
  }
4325
4334
  /** A bytes32 value, lowercased. */
4326
4335
  function toLowerBytes32(value, field = "value") {
4327
- return isBytes32(value) ? lowered(value) : refused(field, "a 0x-prefixed bytes32 value", value);
4336
+ return isBytes32(value) ? lowered(value) : refused$1(field, "a 0x-prefixed bytes32 value", value);
4328
4337
  }
4329
4338
  /** An address, lowercased: the form stored rows and digests compare. */
4330
4339
  function toLowerAddress(value, field = "address") {
4331
- return isAddress$1(value) ? lowered(value) : refused(field, "an EVM address", value);
4340
+ return isAddress$1(value) ? lowered(value) : refused$1(field, "an EVM address", value);
4332
4341
  }
4333
4342
  //#endregion
4334
4343
  //#region ../protocol/src/evm/schema.ts
@@ -4881,16 +4890,19 @@ const PaymentCommandSchema = Schema.Union([
4881
4890
  PaymentBirthCommandSchema,
4882
4891
  Schema.Struct({
4883
4892
  kind: Schema.Literal("claim_commitment"),
4893
+ requestKey: Schema.optional(nonEmpty("requestKey")),
4884
4894
  actor: AccountActorRefSchema,
4885
4895
  paymentId: PaymentIdSchema
4886
4896
  }),
4887
4897
  Schema.Struct({
4888
4898
  kind: Schema.Literal("cancel_commitment"),
4899
+ requestKey: Schema.optional(nonEmpty("requestKey")),
4889
4900
  actor: ActorRefSchema,
4890
4901
  paymentId: PaymentIdSchema
4891
4902
  }),
4892
4903
  Schema.Struct({
4893
4904
  kind: Schema.Literal("redirect_commitment"),
4905
+ requestKey: Schema.optional(nonEmpty("requestKey")),
4894
4906
  actor: ActorRefSchema,
4895
4907
  paymentId: PaymentIdSchema,
4896
4908
  recipient: ActorOrDestinationRefSchema
@@ -4915,8 +4927,10 @@ const PreparedMoneyItemSchema = Schema.Union([
4915
4927
  tokenAddress: AddressSchema$1,
4916
4928
  rawAmount: WeiAmountSchema$1,
4917
4929
  kind: Uint16Schema,
4918
- documentHash: NonzeroDocumentHashSchema
4919
- }),
4930
+ documentHash: NonzeroDocumentHashSchema,
4931
+ jobNonce: Schema.optional(Bytes32Schema),
4932
+ executor: Schema.optional(AddressSchema$1)
4933
+ }).pipe(Schema.refine((item) => item.jobNonce === void 0 === (item.executor === void 0), { message: "Prepared V3 identity requires both jobNonce and executor" })),
4920
4934
  Schema.Struct({
4921
4935
  operation: Schema.Literal("create_commitment"),
4922
4936
  paymentId: PaymentIdSchema,
@@ -5018,6 +5032,12 @@ const PersonalUnsignedUserOperationSchema = Schema.Struct({
5018
5032
  entryPoint: Schema.optional(Schema.Never),
5019
5033
  safe4337ModuleAddress: Schema.optional(Schema.Never)
5020
5034
  });
5035
+ const SubmittedPaymentExecutionSchema = Schema.Struct({
5036
+ executionId: MoneyExecutionIdSchema,
5037
+ commandId: PaymentCommandIdSchema,
5038
+ userOpHash: Bytes32Schema,
5039
+ payment: Payment
5040
+ });
5021
5041
  const PreparedPaymentExecutionSchema = Schema.Struct({
5022
5042
  actorAccountId: AccountIdSchema$1,
5023
5043
  item: PreparedMoneyItemSchema,
@@ -5035,7 +5055,8 @@ const PreparedPaymentExecutionSchema = Schema.Struct({
5035
5055
  chainId: BaseSepoliaChainIdSchema,
5036
5056
  signerAddress: AddressSchema$1,
5037
5057
  userOpSenderSafe: SafeAddressSchema,
5038
- digest: Bytes32Schema
5058
+ digest: Bytes32Schema,
5059
+ settled: Schema.optional(SubmittedPaymentExecutionSchema)
5039
5060
  });
5040
5061
  const SubmitPaymentExecutionInputSchema = Schema.Struct({
5041
5062
  executionId: MoneyExecutionIdSchema,
@@ -5049,12 +5070,6 @@ const AbandonPaymentExecutionInputSchema = Schema.Struct({
5049
5070
  "prepared_mismatch"
5050
5071
  ])
5051
5072
  });
5052
- const SubmittedPaymentExecutionSchema = Schema.Struct({
5053
- executionId: MoneyExecutionIdSchema,
5054
- commandId: PaymentCommandIdSchema,
5055
- userOpHash: Bytes32Schema,
5056
- payment: Payment
5057
- });
5058
5073
  const SubmittedPaymentCommandExecutionSchema = Schema.Struct({
5059
5074
  executionId: MoneyExecutionIdSchema,
5060
5075
  commandId: PaymentCommandIdSchema,
@@ -5069,14 +5084,17 @@ const PaymentLifecycleExecutionIntentSchema = Schema.Union([
5069
5084
  }),
5070
5085
  Schema.Struct({
5071
5086
  kind: Schema.Literal("claim"),
5072
- paymentId: PaymentIdSchema
5087
+ paymentId: PaymentIdSchema,
5088
+ requestKey: Schema.optional(nonEmpty("requestKey"))
5073
5089
  }),
5074
5090
  Schema.Struct({
5075
5091
  kind: Schema.Literal("cancel"),
5076
- paymentId: PaymentIdSchema
5092
+ paymentId: PaymentIdSchema,
5093
+ requestKey: Schema.optional(nonEmpty("requestKey"))
5077
5094
  }),
5078
5095
  Schema.Struct({
5079
5096
  kind: Schema.Literal("redirect"),
5097
+ requestKey: Schema.optional(nonEmpty("requestKey")),
5080
5098
  paymentId: PaymentIdSchema,
5081
5099
  recipient: RedirectPaymentRef
5082
5100
  })
@@ -5135,10 +5153,12 @@ const RequestPaymentConfirmationFields = {
5135
5153
  const RequestPaymentTermsSchema = Schema.Struct(RequestPaymentConfirmationFields);
5136
5154
  const RequestPaymentConfirmationSchema = Schema.Union([Schema.Struct({
5137
5155
  ...RequestPaymentConfirmationFields,
5156
+ requestKey: Schema.optional(nonEmpty("requestKey")),
5138
5157
  payer: Schema.Struct({ kind: Schema.Literal("account") }),
5139
5158
  permissionId: Schema.optional(Schema.Never)
5140
5159
  }), Schema.Struct({
5141
5160
  ...RequestPaymentConfirmationFields,
5161
+ requestKey: Schema.optional(nonEmpty("requestKey")),
5142
5162
  payer: OrganizationActorRefSchema,
5143
5163
  permissionId: PermissionIdSchema
5144
5164
  })]);
@@ -5198,13 +5218,14 @@ const PreparedPaymentCommandExecutionSchema = Schema.Struct({
5198
5218
  commitmentId: Uint256StringSchema,
5199
5219
  documentHash: NonzeroDocumentHashSchema
5200
5220
  })),
5201
- documentBundles: Schema.optional(Schema.Array(PaymentDocumentBundleV3Schema))
5221
+ documentBundles: Schema.optional(Schema.Array(PaymentDocumentBundleV3Schema)),
5222
+ settled: Schema.optional(SubmittedPaymentCommandExecutionSchema)
5202
5223
  }).check(Schema.makeFilter((execution) => {
5203
5224
  if (!("kind" in execution.request) || execution.request.kind !== "payment_request") return true;
5204
5225
  const source = execution.sourceCommand;
5205
5226
  const prepared = execution.preparedCommand;
5206
5227
  if (source?.kind !== "birth" || prepared === void 0 || source.lineage?.kind !== "payment_request") return false;
5207
- if (source.lineage.requestId !== execution.request.confirmation.requestId || source.requestKey !== execution.request.requestKey || source.requestKey !== execution.request.confirmation.requestId || execution.userOperation === void 0) return false;
5228
+ if (source.lineage.requestId !== execution.request.confirmation.requestId || source.requestKey !== execution.request.requestKey || source.requestKey !== (execution.request.confirmation.requestKey ?? execution.request.confirmation.requestId) || execution.userOperation === void 0) return false;
5208
5229
  if ([
5209
5230
  source.items.length,
5210
5231
  execution.request.items.length,
@@ -5217,7 +5238,7 @@ const PreparedPaymentCommandExecutionSchema = Schema.Struct({
5217
5238
  prepared.instructionDocuments?.length
5218
5239
  ].some((length) => length !== 1)) return false;
5219
5240
  const item = prepared.items[0];
5220
- return "recipientSafe" in item && item.operation === source.items[0].operation && item.operation === execution.request.items[0].operation && item.paymentId === execution.paymentIds[0] && item.paymentId === execution.sourcePaymentIds?.[0] && item.recipientSafe === execution.sourceRecipientSafes?.[0];
5241
+ return "recipientSafe" in item && item.operation === source.items[0].operation && item.operation === execution.request.items[0].operation && [item.paymentId, execution.sourcePaymentIds?.[0]].every((id) => id === execution.paymentIds[0]) && item.recipientSafe === execution.sourceRecipientSafes?.[0];
5221
5242
  }));
5222
5243
  //#endregion
5223
5244
  //#region ../protocol/src/accounts/approval-schema.ts
@@ -5285,6 +5306,7 @@ const ApprovalSummarySchema = Schema.Struct({
5285
5306
  /** The exact operation the signature covers: the digest is the one thing the key signs. */
5286
5307
  const ApprovalOperationSchema = Schema.Struct({
5287
5308
  executionId: MoneyExecutionIdSchema,
5309
+ commandId: Schema.optional(nonEmpty("commandId")),
5288
5310
  digest: Bytes32Schema,
5289
5311
  userOperation: PersonalUnsignedUserOperationSchema,
5290
5312
  paymentIds: Schema.Array(PaymentIdSchema)
@@ -5477,6 +5499,21 @@ const approvals = {
5477
5499
  ...APPROVAL
5478
5500
  ]
5479
5501
  }),
5502
+ /** Read the signed operation's progress. Consumption alone does not prove completion. */
5503
+ observe: Operation.query("accounts.approvals.observe", {
5504
+ input: Schema.Struct({ approvalId: ApprovalIdSchema }),
5505
+ output: Schema.Struct({
5506
+ approval: ApprovalSchema,
5507
+ completed: Schema.Boolean
5508
+ }),
5509
+ errors: [
5510
+ ...CALL$10,
5511
+ ...DEFECTS,
5512
+ ...APPROVAL,
5513
+ "SUPERSEDED",
5514
+ "TRANSACTION_FAILED"
5515
+ ]
5516
+ }),
5480
5517
  /** The person opened the approval page: stamp the first review of a pending approval. */
5481
5518
  review: Operation.mutation("accounts.approvals.review", {
5482
5519
  input: Schema.Struct({ approvalId: ApprovalIdSchema }),
@@ -6819,6 +6856,12 @@ function failureFingerprint(code, mode, operation) {
6819
6856
  //#endregion
6820
6857
  //#region ../protocol/src/errors/schema.ts
6821
6858
  const FailureModeSchema$1 = Schema.Literals(FAILURE_MODES$1);
6859
+ Schema.Struct({
6860
+ reason: Schema.Literals(ROLE_PERMISSION_DENIED_REASONS),
6861
+ operation: Schema.optionalKey(Schema.String),
6862
+ remaining: Schema.optionalKey(AssetAmountSchema),
6863
+ required: Schema.optionalKey(AssetAmountSchema)
6864
+ });
6822
6865
  const ChainUpstreamSchema$1 = Schema.Literals(CHAIN_UPSTREAMS);
6823
6866
  const ChainCauseSchema = Schema.Struct({
6824
6867
  mode: FailureModeSchema$1,
@@ -9440,6 +9483,7 @@ const inboxes = {
9440
9483
  input: Schema.Struct({
9441
9484
  actor,
9442
9485
  paymentRequestId: Schema.String,
9486
+ requestKey: Schema.optionalKey(nonEmpty("requestKey")),
9443
9487
  timing: Schema.optionalKey(PaymentTiming),
9444
9488
  permissionId: Schema.optionalKey(Schema.String)
9445
9489
  }),
@@ -9816,7 +9860,8 @@ const PEOPLE_OPERATIONS = {
9816
9860
  expire: "accounts.approvals.expire",
9817
9861
  recordApproval: "accounts.approvals.recordApproval",
9818
9862
  recordExpiry: "accounts.approvals.recordExpiry",
9819
- sendApproved: "accounts.approvals.sendApproved"
9863
+ sendApproved: "accounts.approvals.sendApproved",
9864
+ rescheduleApproved: "accounts.approvals.rescheduleApproved"
9820
9865
  },
9821
9866
  balances: { readBinding: "accounts.balances.readBinding" },
9822
9867
  claims: {
@@ -13703,7 +13748,7 @@ function mapAccountLifecycle(input) {
13703
13748
  }
13704
13749
  //#endregion
13705
13750
  //#region package.json
13706
- var version = "4.20.0-beta.33";
13751
+ var version = "4.20.0-beta.35";
13707
13752
  //#endregion
13708
13753
  //#region src/observability/telemetry/exception-projection.ts
13709
13754
  /** Fixed fallback for failures that have no safe message. */
@@ -14476,6 +14521,127 @@ function mapOk(result, f) {
14476
14521
  }
14477
14522
  }
14478
14523
  //#endregion
14524
+ //#region ../protocol/src/evm/test-assets.ts
14525
+ const SYNTHETIC_TEST_ASSET_SOURCE = "synthetic-test-liquidity";
14526
+ /**
14527
+ * Owned test assets, with metadata read from each creation receipt and contract.
14528
+ * Settlement admission lives in assets.ts. The fixed test exchange uses the
14529
+ * original five assets; bank EURC has its own deployment.
14530
+ *
14531
+ * `symbol` is the display string the owned contract returns. A
14532
+ * provider-supported USDC would be a different contract at a different
14533
+ * address returning the same symbol, which is why the resolvers below key on
14534
+ * `assetId`, or on chain plus address, and never on a symbol.
14535
+ */
14536
+ const SYNTHETIC_TEST_ASSET_FIXTURES = {
14537
+ usdc: {
14538
+ assetId: assetIdFor(84532, "0x06ba8b863ca77490b0e7008427562bdbfcff730e"),
14539
+ chainId: toChainId(84532),
14540
+ tokenAddress: "0x06ba8b863ca77490b0e7008427562bdbfcff730e",
14541
+ symbol: "USDC",
14542
+ decimals: 6,
14543
+ peg: toCurrencyCode("USD"),
14544
+ deploymentStartBlock: 46690061,
14545
+ deploymentTransaction: "0x2661b7af5f62b9e31c707a59746cda65b90ba4448852317ac1968162fb94ff52",
14546
+ source: SYNTHETIC_TEST_ASSET_SOURCE
14547
+ },
14548
+ usdt: {
14549
+ assetId: assetIdFor(84532, "0xcb5f361ae070e75d573941b8cd54995fa3876d75"),
14550
+ chainId: toChainId(84532),
14551
+ tokenAddress: "0xcb5f361ae070e75d573941b8cd54995fa3876d75",
14552
+ symbol: "USDT",
14553
+ decimals: 6,
14554
+ peg: toCurrencyCode("USD"),
14555
+ deploymentStartBlock: 46690061,
14556
+ deploymentTransaction: "0x98e5303f97974a31eddb61ad030072d900ce7283ce8080bfe0b9e5ea6f297749",
14557
+ source: SYNTHETIC_TEST_ASSET_SOURCE
14558
+ },
14559
+ weth: {
14560
+ assetId: assetIdFor(84532, "0x85b7bd39ce3df9a85135e1e307225dd435f67e47"),
14561
+ chainId: toChainId(84532),
14562
+ tokenAddress: "0x85b7bd39ce3df9a85135e1e307225dd435f67e47",
14563
+ symbol: "WETH",
14564
+ decimals: 18,
14565
+ peg: null,
14566
+ deploymentStartBlock: 46690061,
14567
+ deploymentTransaction: "0x48dfacc01c15adc34f6c629aec5c9ff7bb84176d448017da0d0d4fdaf8b5a68a",
14568
+ source: SYNTHETIC_TEST_ASSET_SOURCE
14569
+ },
14570
+ wbtc: {
14571
+ assetId: assetIdFor(84532, "0xcf433a81f507dcc88c2c404650ffafb40750b451"),
14572
+ chainId: toChainId(84532),
14573
+ tokenAddress: "0xcf433a81f507dcc88c2c404650ffafb40750b451",
14574
+ symbol: "WBTC",
14575
+ decimals: 8,
14576
+ peg: null,
14577
+ deploymentStartBlock: 46690061,
14578
+ deploymentTransaction: "0xa975fcda0a67509742243bbfc386032d2e0d6ca78404c255fae2e4ffae1c7f4d",
14579
+ source: SYNTHETIC_TEST_ASSET_SOURCE
14580
+ },
14581
+ cngn: {
14582
+ assetId: assetIdFor(84532, "0xda515a7267e190710f0003f951c62bcfd70d6b2a"),
14583
+ chainId: toChainId(84532),
14584
+ tokenAddress: "0xda515a7267e190710f0003f951c62bcfd70d6b2a",
14585
+ symbol: "cNGN",
14586
+ decimals: 6,
14587
+ peg: toCurrencyCode("NGN"),
14588
+ deploymentStartBlock: 46690061,
14589
+ deploymentTransaction: "0x6f6b0302448c7cd7db5c118a8250e548c6e72821df373e5a27550e5cdfa635a1",
14590
+ source: SYNTHETIC_TEST_ASSET_SOURCE
14591
+ },
14592
+ eurc: {
14593
+ assetId: assetIdFor(84532, "0x15055b4ed1d248c169b92705757cd9c3d985ad5f"),
14594
+ chainId: toChainId(84532),
14595
+ tokenAddress: "0x15055b4ed1d248c169b92705757cd9c3d985ad5f",
14596
+ symbol: "EURC",
14597
+ decimals: 6,
14598
+ peg: toCurrencyCode("EUR"),
14599
+ deploymentStartBlock: 47893251,
14600
+ deploymentTransaction: "0x4e0ab412d980a672336487afd10da007d51f34f17876b19b13732c8125be90ca",
14601
+ source: SYNTHETIC_TEST_ASSET_SOURCE
14602
+ }
14603
+ };
14604
+ /** EURC is minted for bank deposits and has no admission to the fixed test exchange. */
14605
+ const SYNTHETIC_TEST_ASSETS = [...[
14606
+ SYNTHETIC_TEST_ASSET_FIXTURES.usdc,
14607
+ SYNTHETIC_TEST_ASSET_FIXTURES.usdt,
14608
+ SYNTHETIC_TEST_ASSET_FIXTURES.weth,
14609
+ SYNTHETIC_TEST_ASSET_FIXTURES.wbtc,
14610
+ SYNTHETIC_TEST_ASSET_FIXTURES.cngn
14611
+ ], SYNTHETIC_TEST_ASSET_FIXTURES.eurc];
14612
+ toChainId(84532);
14613
+ /**
14614
+ * The settlement tier: the owned test assets admitted to the exact-transfer
14615
+ * path and to the treasury reads. USDC, USDT, WETH and EURC are admitted assets.
14616
+ * There is no default token.
14617
+ */
14618
+ const SETTLEMENT_ASSETS_BASE_SEPOLIA = Object.freeze({
14619
+ CAPXUL_TEST_USDC: SYNTHETIC_TEST_ASSET_FIXTURES.usdc,
14620
+ CAPXUL_TEST_USDT: SYNTHETIC_TEST_ASSET_FIXTURES.usdt,
14621
+ CAPXUL_TEST_WETH: SYNTHETIC_TEST_ASSET_FIXTURES.weth,
14622
+ CAPXUL_TEST_EURC: SYNTHETIC_TEST_ASSET_FIXTURES.eurc
14623
+ });
14624
+ const CONFIGURED_MONEY_ASSETS = Object.freeze(Object.values(SETTLEMENT_ASSETS_BASE_SEPOLIA));
14625
+ /** Public AssetIds for the admitted Base Sepolia test assets. */
14626
+ const TOKENS = Object.freeze({ BASE_SEPOLIA: Object.freeze({
14627
+ CAPXUL_TEST_USDC: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_USDC.assetId,
14628
+ CAPXUL_TEST_USDT: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_USDT.assetId,
14629
+ CAPXUL_TEST_WETH: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_WETH.assetId,
14630
+ CAPXUL_TEST_EURC: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_EURC.assetId
14631
+ }) });
14632
+ /**
14633
+ * Every known asset in ONE identity space. The tiers above declare admission;
14634
+ * this is the only list an identity resolves against, so an asset is never
14635
+ * two different things depending on which list a caller happened to read.
14636
+ */
14637
+ const MONEY_ASSET_REGISTRY = [...SYNTHETIC_TEST_ASSETS];
14638
+ CONFIGURED_MONEY_ASSETS.map((asset) => asset.tokenAddress.toLowerCase());
14639
+ /** The registry row for `assetId` across every tier, or `null`. */
14640
+ function configuredMoneyAssetById(assetId) {
14641
+ const canonical = toAssetId(assetId);
14642
+ return MONEY_ASSET_REGISTRY.find((asset) => asset.assetId === canonical) ?? null;
14643
+ }
14644
+ //#endregion
14479
14645
  //#region src/platform/transport/call-operation.ts
14480
14646
  function callOperation(port, row, args, options) {
14481
14647
  const op = row;
@@ -15649,6 +15815,23 @@ async function verifyPaymentDocumentSignatureV3(input) {
15649
15815
  })).toLowerCase() === envelope.signature.signer;
15650
15816
  }
15651
15817
  //#endregion
15818
+ //#region ../protocol/src/documents/identities.ts
15819
+ /** A caller handed this module a value its own types rule out: a defect, named. */
15820
+ function defect$1(step, message) {
15821
+ return new CapxulError("UNKNOWN", message, { details: { step } });
15822
+ }
15823
+ function hashDocumentOriginIdV3(input) {
15824
+ if (!Number.isSafeInteger(input.chainId) || input.chainId <= 0 || !Number.isSafeInteger(input.itemIndex) || input.itemIndex < 0 || input.actorKind !== "account" && input.actorKind !== "organization" || input.actorId.length === 0 || input.requestKey.length === 0) throw defect$1("hashDocumentOriginIdV3", "Invalid document origin input");
15825
+ return keccak256(encodeAbiParameters(parseAbiParameters("string namespace, uint256 chainId, string actorKind, string actorId, string requestKey, uint256 itemIndex"), [
15826
+ "capxul.document-origin.v3",
15827
+ BigInt(input.chainId),
15828
+ input.actorKind,
15829
+ input.actorId,
15830
+ input.requestKey,
15831
+ BigInt(input.itemIndex)
15832
+ ]));
15833
+ }
15834
+ //#endregion
15652
15835
  //#region src/documents/birth-context.ts
15653
15836
  function sourcePurpose(source) {
15654
15837
  if ("purposeKind" in source) return source.purposeKind;
@@ -15663,13 +15846,20 @@ function isBirthItem(item) {
15663
15846
  function requestRetryInstruction(input) {
15664
15847
  const request = input.evidence.request;
15665
15848
  const original = input.evidence.sourceCommand;
15666
- if (!("kind" in request) || request.kind !== "retry" || original?.kind !== "birth" || original.lineage?.kind !== "payment_request" && original.lineage?.kind !== "invoice_checkout" || original.lineage.requestId !== original.requestKey || !input.evidence.sourcePaymentIds?.includes(request.paymentId)) return void 0;
15849
+ if (!("kind" in request) || request.kind !== "retry" || original?.kind !== "birth" || original.lineage?.kind !== "payment_request" && original.lineage?.kind !== "invoice_checkout" || !input.evidence.sourcePaymentIds?.includes(request.paymentId)) return void 0;
15667
15850
  const document = original.items[input.index]?.document;
15668
15851
  if (document?.kind !== "envelope") return void 0;
15669
15852
  const bytes = decodeCanonicalBase64V3(document.bytesBase64);
15670
15853
  const envelope = decodeSupportedPaymentDocumentEnvelope(bytes);
15671
15854
  if (envelope.primaryType !== "Memo" && envelope.primaryType !== "Invoice") return void 0;
15672
15855
  if (envelope.version === 5) return void 0;
15856
+ if (original.lineage.requestId !== original.requestKey && (original.lineage.kind !== "payment_request" || envelope.primaryType !== "Invoice" || envelope.message.originId !== hashDocumentOriginIdV3({
15857
+ chainId: input.evidence.chainId,
15858
+ actorKind: original.actor.kind,
15859
+ actorId: original.actor.kind === "account" ? original.actor.accountId : original.actor.orgId,
15860
+ requestKey: original.lineage.requestId,
15861
+ itemIndex: input.index
15862
+ }))) return void 0;
15673
15863
  return {
15674
15864
  documentHash: hashSupportedPaymentDocument(envelope),
15675
15865
  contentHash: hashPaymentDocumentContentV3(bytes),
@@ -15698,11 +15888,7 @@ function requestBirthContext(evidence) {
15698
15888
  ].some((items) => items?.length !== 1)) return null;
15699
15889
  const item = command.items[0];
15700
15890
  const instruction = command.instructionDocuments?.[0];
15701
- if (!isBirthItem(item) || instruction === void 0 || source.lineage?.kind !== "payment_request" || [
15702
- source.lineage.requestId,
15703
- source.requestKey,
15704
- request.requestKey
15705
- ].some((key) => key !== request.confirmation.requestId) || documentJson(request.actor) !== documentJson(source.actor) || documentJson(request.items) !== documentJson(source.items) || evidence.sourcePaymentIds?.[0] !== evidence.paymentIds[0] || evidence.sourceRecipientSafes?.[0]?.toLowerCase() !== request.confirmation.issuerSafe.toLowerCase() || documentJson(evidence.documentBundles) !== documentJson(command.documentBundles) || !confirmedRequestFactsMatch(request.confirmation, source, item, instruction)) return null;
15891
+ if (!isBirthItem(item) || instruction === void 0 || source.lineage?.kind !== "payment_request" || source.lineage.requestId !== request.confirmation.requestId || [source.requestKey, request.requestKey].some((key) => key !== (request.confirmation.requestKey ?? request.confirmation.requestId)) || documentJson(request.actor) !== documentJson(source.actor) || documentJson(request.items) !== documentJson(source.items) || evidence.sourcePaymentIds?.[0] !== evidence.paymentIds[0] || evidence.sourceRecipientSafes?.[0]?.toLowerCase() !== request.confirmation.issuerSafe.toLowerCase() || documentJson(evidence.documentBundles) !== documentJson(command.documentBundles) || !confirmedRequestFactsMatch(request.confirmation, source, item, instruction)) return null;
15706
15892
  return {
15707
15893
  source: source.items,
15708
15894
  actorKind: source.actor.kind,
@@ -15728,127 +15914,6 @@ function retryBirthContext(evidence) {
15728
15914
  };
15729
15915
  }
15730
15916
  //#endregion
15731
- //#region ../protocol/src/evm/test-assets.ts
15732
- const SYNTHETIC_TEST_ASSET_SOURCE = "synthetic-test-liquidity";
15733
- /**
15734
- * Owned test assets, with metadata read from each creation receipt and contract.
15735
- * Settlement admission lives in assets.ts. The fixed test exchange uses the
15736
- * original five assets; bank EURC has its own deployment.
15737
- *
15738
- * `symbol` is the display string the owned contract returns. A
15739
- * provider-supported USDC would be a different contract at a different
15740
- * address returning the same symbol, which is why the resolvers below key on
15741
- * `assetId`, or on chain plus address, and never on a symbol.
15742
- */
15743
- const SYNTHETIC_TEST_ASSET_FIXTURES = {
15744
- usdc: {
15745
- assetId: assetIdFor(84532, "0x06ba8b863ca77490b0e7008427562bdbfcff730e"),
15746
- chainId: toChainId(84532),
15747
- tokenAddress: "0x06ba8b863ca77490b0e7008427562bdbfcff730e",
15748
- symbol: "USDC",
15749
- decimals: 6,
15750
- peg: toCurrencyCode("USD"),
15751
- deploymentStartBlock: 46690061,
15752
- deploymentTransaction: "0x2661b7af5f62b9e31c707a59746cda65b90ba4448852317ac1968162fb94ff52",
15753
- source: SYNTHETIC_TEST_ASSET_SOURCE
15754
- },
15755
- usdt: {
15756
- assetId: assetIdFor(84532, "0xcb5f361ae070e75d573941b8cd54995fa3876d75"),
15757
- chainId: toChainId(84532),
15758
- tokenAddress: "0xcb5f361ae070e75d573941b8cd54995fa3876d75",
15759
- symbol: "USDT",
15760
- decimals: 6,
15761
- peg: toCurrencyCode("USD"),
15762
- deploymentStartBlock: 46690061,
15763
- deploymentTransaction: "0x98e5303f97974a31eddb61ad030072d900ce7283ce8080bfe0b9e5ea6f297749",
15764
- source: SYNTHETIC_TEST_ASSET_SOURCE
15765
- },
15766
- weth: {
15767
- assetId: assetIdFor(84532, "0x85b7bd39ce3df9a85135e1e307225dd435f67e47"),
15768
- chainId: toChainId(84532),
15769
- tokenAddress: "0x85b7bd39ce3df9a85135e1e307225dd435f67e47",
15770
- symbol: "WETH",
15771
- decimals: 18,
15772
- peg: null,
15773
- deploymentStartBlock: 46690061,
15774
- deploymentTransaction: "0x48dfacc01c15adc34f6c629aec5c9ff7bb84176d448017da0d0d4fdaf8b5a68a",
15775
- source: SYNTHETIC_TEST_ASSET_SOURCE
15776
- },
15777
- wbtc: {
15778
- assetId: assetIdFor(84532, "0xcf433a81f507dcc88c2c404650ffafb40750b451"),
15779
- chainId: toChainId(84532),
15780
- tokenAddress: "0xcf433a81f507dcc88c2c404650ffafb40750b451",
15781
- symbol: "WBTC",
15782
- decimals: 8,
15783
- peg: null,
15784
- deploymentStartBlock: 46690061,
15785
- deploymentTransaction: "0xa975fcda0a67509742243bbfc386032d2e0d6ca78404c255fae2e4ffae1c7f4d",
15786
- source: SYNTHETIC_TEST_ASSET_SOURCE
15787
- },
15788
- cngn: {
15789
- assetId: assetIdFor(84532, "0xda515a7267e190710f0003f951c62bcfd70d6b2a"),
15790
- chainId: toChainId(84532),
15791
- tokenAddress: "0xda515a7267e190710f0003f951c62bcfd70d6b2a",
15792
- symbol: "cNGN",
15793
- decimals: 6,
15794
- peg: toCurrencyCode("NGN"),
15795
- deploymentStartBlock: 46690061,
15796
- deploymentTransaction: "0x6f6b0302448c7cd7db5c118a8250e548c6e72821df373e5a27550e5cdfa635a1",
15797
- source: SYNTHETIC_TEST_ASSET_SOURCE
15798
- },
15799
- eurc: {
15800
- assetId: assetIdFor(84532, "0x15055b4ed1d248c169b92705757cd9c3d985ad5f"),
15801
- chainId: toChainId(84532),
15802
- tokenAddress: "0x15055b4ed1d248c169b92705757cd9c3d985ad5f",
15803
- symbol: "EURC",
15804
- decimals: 6,
15805
- peg: toCurrencyCode("EUR"),
15806
- deploymentStartBlock: 47893251,
15807
- deploymentTransaction: "0x4e0ab412d980a672336487afd10da007d51f34f17876b19b13732c8125be90ca",
15808
- source: SYNTHETIC_TEST_ASSET_SOURCE
15809
- }
15810
- };
15811
- /** EURC is minted for bank deposits and has no admission to the fixed test exchange. */
15812
- const SYNTHETIC_TEST_ASSETS = [...[
15813
- SYNTHETIC_TEST_ASSET_FIXTURES.usdc,
15814
- SYNTHETIC_TEST_ASSET_FIXTURES.usdt,
15815
- SYNTHETIC_TEST_ASSET_FIXTURES.weth,
15816
- SYNTHETIC_TEST_ASSET_FIXTURES.wbtc,
15817
- SYNTHETIC_TEST_ASSET_FIXTURES.cngn
15818
- ], SYNTHETIC_TEST_ASSET_FIXTURES.eurc];
15819
- toChainId(84532);
15820
- /**
15821
- * The settlement tier: the owned test assets admitted to the exact-transfer
15822
- * path and to the treasury reads. USDC, USDT, WETH and EURC are admitted assets.
15823
- * There is no default token.
15824
- */
15825
- const SETTLEMENT_ASSETS_BASE_SEPOLIA = Object.freeze({
15826
- CAPXUL_TEST_USDC: SYNTHETIC_TEST_ASSET_FIXTURES.usdc,
15827
- CAPXUL_TEST_USDT: SYNTHETIC_TEST_ASSET_FIXTURES.usdt,
15828
- CAPXUL_TEST_WETH: SYNTHETIC_TEST_ASSET_FIXTURES.weth,
15829
- CAPXUL_TEST_EURC: SYNTHETIC_TEST_ASSET_FIXTURES.eurc
15830
- });
15831
- const CONFIGURED_MONEY_ASSETS = Object.freeze(Object.values(SETTLEMENT_ASSETS_BASE_SEPOLIA));
15832
- /** Public AssetIds for the admitted Base Sepolia test assets. */
15833
- const TOKENS = Object.freeze({ BASE_SEPOLIA: Object.freeze({
15834
- CAPXUL_TEST_USDC: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_USDC.assetId,
15835
- CAPXUL_TEST_USDT: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_USDT.assetId,
15836
- CAPXUL_TEST_WETH: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_WETH.assetId,
15837
- CAPXUL_TEST_EURC: SETTLEMENT_ASSETS_BASE_SEPOLIA.CAPXUL_TEST_EURC.assetId
15838
- }) });
15839
- /**
15840
- * Every known asset in ONE identity space. The tiers above declare admission;
15841
- * this is the only list an identity resolves against, so an asset is never
15842
- * two different things depending on which list a caller happened to read.
15843
- */
15844
- const MONEY_ASSET_REGISTRY = [...SYNTHETIC_TEST_ASSETS];
15845
- CONFIGURED_MONEY_ASSETS.map((asset) => asset.tokenAddress.toLowerCase());
15846
- /** The registry row for `assetId` across every tier, or `null`. */
15847
- function configuredMoneyAssetById(assetId) {
15848
- const canonical = toAssetId(assetId);
15849
- return MONEY_ASSET_REGISTRY.find((asset) => asset.assetId === canonical) ?? null;
15850
- }
15851
- //#endregion
15852
15917
  //#region ../protocol/src/documents/receipts.ts
15853
15918
  async function parseSupportingReceiptV3(input) {
15854
15919
  const supporting = SchemaParser.decodeUnknownSync(SupportingReceiptInputSchema, { onExcessProperty: "error" })(input);
@@ -15879,23 +15944,6 @@ async function parseSupportingReceiptV3(input) {
15879
15944
  };
15880
15945
  }
15881
15946
  //#endregion
15882
- //#region ../protocol/src/documents/identities.ts
15883
- /** A caller handed this module a value its own types rule out: a defect, named. */
15884
- function defect$1(step, message) {
15885
- return new CapxulError("UNKNOWN", message, { details: { step } });
15886
- }
15887
- function hashDocumentOriginIdV3(input) {
15888
- if (!Number.isSafeInteger(input.chainId) || input.chainId <= 0 || !Number.isSafeInteger(input.itemIndex) || input.itemIndex < 0 || input.actorKind !== "account" && input.actorKind !== "organization" || input.actorId.length === 0 || input.requestKey.length === 0) throw defect$1("hashDocumentOriginIdV3", "Invalid document origin input");
15889
- return keccak256(encodeAbiParameters(parseAbiParameters("string namespace, uint256 chainId, string actorKind, string actorId, string requestKey, uint256 itemIndex"), [
15890
- "capxul.document-origin.v3",
15891
- BigInt(input.chainId),
15892
- input.actorKind,
15893
- input.actorId,
15894
- input.requestKey,
15895
- BigInt(input.itemIndex)
15896
- ]));
15897
- }
15898
- //#endregion
15899
15947
  //#region ../protocol/src/documents/context.ts
15900
15948
  function sameAmount(left, right) {
15901
15949
  return left.asset === right.asset && left.minorUnits === right.minorUnits && left.decimals === right.decimals;
@@ -16176,6 +16224,25 @@ function verifiesInvoiceCheckoutBirthEvidence(evidence, invoice, chainId, source
16176
16224
  return "kind" in evidence.request && evidence.request.kind === "invoice_checkout" && evidence.request.linkToken === invoice.linkToken && evidence.preparedCommand?.items.length === 1 && item?.operation === "send" && evidence.preparedCommand.senderSafe.toLowerCase() === sourceWallet.toLowerCase() && evidence.preparedCommand.contractAddress.toLowerCase() === invoice.contractAddress.toLowerCase() && item.settlementId === invoice.settlementId && item.documentHash === invoice.documentHash && item.recipientSafe.toLowerCase() === invoice.recipientSafe.toLowerCase() && item.tokenAddress.toLowerCase() === invoice.tokenAddress.toLowerCase() && item.rawAmount === invoice.rawAmount && item.kind === (invoice.documentKind === "memo" ? 0 : 1) && invoice.chainId === chainId;
16177
16225
  }
16178
16226
  //#endregion
16227
+ //#region ../protocol/src/payments/execution-identity.ts
16228
+ /** A command and its exact signed operation have one durable execution identity. */
16229
+ function moneyExecutionId(commandId, digest) {
16230
+ return `money_execution_${keccak256(encodeAbiParameters([
16231
+ { type: "string" },
16232
+ { type: "string" },
16233
+ { type: "bytes32" }
16234
+ ], [
16235
+ "capxul.money-execution.v1",
16236
+ commandId,
16237
+ toLowerBytes32(digest)
16238
+ ])).slice(2)}`;
16239
+ }
16240
+ /** Existing stored executions keep their digest-derived identity. */
16241
+ function matchesMoneyExecutionId(executionId, digest, commandId) {
16242
+ const exactDigest = toLowerBytes32(digest);
16243
+ return executionId === `money_execution_${exactDigest.slice(2)}` || commandId !== void 0 && executionId === moneyExecutionId(commandId, exactDigest);
16244
+ }
16245
+ //#endregion
16179
16246
  //#region ../protocol/src/evm/payments-abi.ts
16180
16247
  /** The exact compiled CapxulPaymentsV2 ABI. */
16181
16248
  const CAPXUL_PAYMENTS_V2_ABI = [
@@ -16822,6 +16889,313 @@ const CAPXUL_PAYMENTS_V2_ABI = [
16822
16889
  /** Immutable CapxulPaymentsV2 deployment on Base Sepolia. */
16823
16890
  const CAPXUL_PAYMENTS_V2_ADDRESS = "0x7a5c25aB7ce91d7a475B71cd1ec33E230291f8a4";
16824
16891
  //#endregion
16892
+ //#region ../protocol/src/evm/payments-v3.ts
16893
+ const PAYMENT_ITEM_COMPONENTS = [
16894
+ {
16895
+ name: "settlementId",
16896
+ type: "bytes32",
16897
+ internalType: "bytes32"
16898
+ },
16899
+ {
16900
+ name: "recipient",
16901
+ type: "address",
16902
+ internalType: "address"
16903
+ },
16904
+ {
16905
+ name: "token",
16906
+ type: "address",
16907
+ internalType: "address"
16908
+ },
16909
+ {
16910
+ name: "amount",
16911
+ type: "uint256",
16912
+ internalType: "uint256"
16913
+ },
16914
+ {
16915
+ name: "kind",
16916
+ type: "uint16",
16917
+ internalType: "uint16"
16918
+ },
16919
+ {
16920
+ name: "documentHash",
16921
+ type: "bytes32",
16922
+ internalType: "bytes32"
16923
+ },
16924
+ {
16925
+ name: "jobNonce",
16926
+ type: "bytes32",
16927
+ internalType: "bytes32"
16928
+ },
16929
+ {
16930
+ name: "executor",
16931
+ type: "address",
16932
+ internalType: "address"
16933
+ }
16934
+ ];
16935
+ const PAYMENT_ITEM_INPUT = {
16936
+ name: "item",
16937
+ type: "tuple",
16938
+ internalType: "struct CapxulPaymentsV3.PaymentItem",
16939
+ components: PAYMENT_ITEM_COMPONENTS
16940
+ };
16941
+ /** The exact compiled CapxulPaymentsV3 ABI. */
16942
+ const CAPXUL_PAYMENTS_V3_ABI = [
16943
+ {
16944
+ type: "function",
16945
+ name: "paymentId",
16946
+ inputs: [PAYMENT_ITEM_INPUT],
16947
+ outputs: [{
16948
+ name: "",
16949
+ type: "bytes32",
16950
+ internalType: "bytes32"
16951
+ }],
16952
+ stateMutability: "view"
16953
+ },
16954
+ {
16955
+ type: "function",
16956
+ name: "send",
16957
+ inputs: [PAYMENT_ITEM_INPUT],
16958
+ outputs: [],
16959
+ stateMutability: "nonpayable"
16960
+ },
16961
+ {
16962
+ type: "function",
16963
+ name: "sendBatch",
16964
+ inputs: [{
16965
+ name: "items",
16966
+ type: "tuple[]",
16967
+ internalType: "struct CapxulPaymentsV3.PaymentItem[]",
16968
+ components: PAYMENT_ITEM_COMPONENTS
16969
+ }],
16970
+ outputs: [],
16971
+ stateMutability: "nonpayable"
16972
+ },
16973
+ {
16974
+ type: "function",
16975
+ name: "settled",
16976
+ inputs: [{
16977
+ name: "",
16978
+ type: "bytes32",
16979
+ internalType: "bytes32"
16980
+ }],
16981
+ outputs: [{
16982
+ name: "",
16983
+ type: "bool",
16984
+ internalType: "bool"
16985
+ }],
16986
+ stateMutability: "view"
16987
+ },
16988
+ {
16989
+ type: "event",
16990
+ name: "PaymentSent",
16991
+ inputs: [
16992
+ {
16993
+ name: "settlementId",
16994
+ type: "bytes32",
16995
+ indexed: true,
16996
+ internalType: "bytes32"
16997
+ },
16998
+ {
16999
+ name: "sender",
17000
+ type: "address",
17001
+ indexed: true,
17002
+ internalType: "address"
17003
+ },
17004
+ {
17005
+ name: "recipient",
17006
+ type: "address",
17007
+ indexed: true,
17008
+ internalType: "address"
17009
+ },
17010
+ {
17011
+ name: "token",
17012
+ type: "address",
17013
+ indexed: false,
17014
+ internalType: "address"
17015
+ },
17016
+ {
17017
+ name: "amount",
17018
+ type: "uint256",
17019
+ indexed: false,
17020
+ internalType: "uint256"
17021
+ },
17022
+ {
17023
+ name: "kind",
17024
+ type: "uint16",
17025
+ indexed: false,
17026
+ internalType: "uint16"
17027
+ },
17028
+ {
17029
+ name: "documentHash",
17030
+ type: "bytes32",
17031
+ indexed: false,
17032
+ internalType: "bytes32"
17033
+ }
17034
+ ],
17035
+ anonymous: false
17036
+ },
17037
+ {
17038
+ type: "error",
17039
+ name: "InexactTransfer",
17040
+ inputs: [
17041
+ {
17042
+ name: "token",
17043
+ type: "address",
17044
+ internalType: "address"
17045
+ },
17046
+ {
17047
+ name: "expected",
17048
+ type: "uint256",
17049
+ internalType: "uint256"
17050
+ },
17051
+ {
17052
+ name: "received",
17053
+ type: "uint256",
17054
+ internalType: "uint256"
17055
+ }
17056
+ ]
17057
+ },
17058
+ {
17059
+ type: "error",
17060
+ name: "InvalidExecutor",
17061
+ inputs: [{
17062
+ name: "expected",
17063
+ type: "address",
17064
+ internalType: "address"
17065
+ }, {
17066
+ name: "supplied",
17067
+ type: "address",
17068
+ internalType: "address"
17069
+ }]
17070
+ },
17071
+ {
17072
+ type: "error",
17073
+ name: "PaymentIdMismatch",
17074
+ inputs: [{
17075
+ name: "expected",
17076
+ type: "bytes32",
17077
+ internalType: "bytes32"
17078
+ }, {
17079
+ name: "supplied",
17080
+ type: "bytes32",
17081
+ internalType: "bytes32"
17082
+ }]
17083
+ },
17084
+ {
17085
+ type: "error",
17086
+ name: "ReentrantCall",
17087
+ inputs: []
17088
+ },
17089
+ {
17090
+ type: "error",
17091
+ name: "SettlementIdConsumed",
17092
+ inputs: [{
17093
+ name: "settlementId",
17094
+ type: "bytes32",
17095
+ internalType: "bytes32"
17096
+ }]
17097
+ },
17098
+ {
17099
+ type: "error",
17100
+ name: "TokenCallReturnedFalse",
17101
+ inputs: [{
17102
+ name: "token",
17103
+ type: "address",
17104
+ internalType: "address"
17105
+ }]
17106
+ },
17107
+ {
17108
+ type: "error",
17109
+ name: "TokenHasNoCode",
17110
+ inputs: [{
17111
+ name: "token",
17112
+ type: "address",
17113
+ internalType: "address"
17114
+ }]
17115
+ },
17116
+ {
17117
+ type: "error",
17118
+ name: "ZeroAddress",
17119
+ inputs: []
17120
+ },
17121
+ {
17122
+ type: "error",
17123
+ name: "ZeroAmount",
17124
+ inputs: []
17125
+ },
17126
+ {
17127
+ type: "error",
17128
+ name: "ZeroDocumentHash",
17129
+ inputs: []
17130
+ },
17131
+ {
17132
+ type: "error",
17133
+ name: "ZeroJobNonce",
17134
+ inputs: []
17135
+ },
17136
+ {
17137
+ type: "error",
17138
+ name: "ZeroSettlementId",
17139
+ inputs: []
17140
+ }
17141
+ ];
17142
+ /** The fixed CREATE2 deployment on every admitted chain. */
17143
+ const CAPXUL_PAYMENTS_V3_ADDRESS = "0x46b28f455c8de7c1505e3185A3f8f87B07eaE1aE";
17144
+ //#endregion
17145
+ //#region ../protocol/src/evm/payments/encoding.ts
17146
+ const CAPXUL_PAYMENT_V3_TYPEHASH = keccak256(toBytes("CapxulPayment(uint256 chainId,address router,bytes32 jobNonce,address executor,address recipient,address token,uint256 amount,uint16 kind,bytes32 documentHash)"));
17147
+ function paymentJobNonce(commandId, itemIndex) {
17148
+ if (!Number.isSafeInteger(itemIndex) || itemIndex < 0) throw Errors.invalidInput("itemIndex", "must be a non-negative safe integer");
17149
+ return sha256(toBytes(`{"commandId":${JSON.stringify(commandId)},"index":${itemIndex},"version":1}`));
17150
+ }
17151
+ function capxulPaymentsV3PaymentId(chainId, router, item) {
17152
+ return keccak256(encodeAbiParameters(parseAbiParameters("bytes32,uint256,address,bytes32,address,address,address,uint256,uint16,bytes32"), [
17153
+ CAPXUL_PAYMENT_V3_TYPEHASH,
17154
+ BigInt(chainId),
17155
+ router,
17156
+ item.jobNonce,
17157
+ item.executor,
17158
+ item.recipient,
17159
+ item.token,
17160
+ item.amount,
17161
+ item.kind,
17162
+ item.documentHash
17163
+ ]));
17164
+ }
17165
+ function encodeCapxulPaymentsV3Send(item) {
17166
+ return encodeFunctionData({
17167
+ abi: CAPXUL_PAYMENTS_V3_ABI,
17168
+ functionName: "send",
17169
+ args: [item]
17170
+ });
17171
+ }
17172
+ function encodeCapxulPaymentsV3SendBatch(items) {
17173
+ return encodeFunctionData({
17174
+ abi: CAPXUL_PAYMENTS_V3_ABI,
17175
+ functionName: "sendBatch",
17176
+ args: [items]
17177
+ });
17178
+ }
17179
+ function v3Item(command, item, itemIndex) {
17180
+ const { commandId, chainId, senderSafe } = command;
17181
+ if (commandId === void 0 || chainId === void 0 || senderSafe === void 0) throw Errors.invalidInput("command", "CapxulPaymentsV3 requires its command identity");
17182
+ const terms = {
17183
+ recipient: item.recipientSafe,
17184
+ token: item.tokenAddress,
17185
+ amount: BigInt(item.rawAmount),
17186
+ kind: item.kind,
17187
+ documentHash: item.documentHash,
17188
+ jobNonce: item.jobNonce ?? paymentJobNonce(commandId, itemIndex),
17189
+ executor: item.executor ?? senderSafe
17190
+ };
17191
+ const settlementId = capxulPaymentsV3PaymentId(chainId, command.contractAddress, terms);
17192
+ if (settlementId.toLowerCase() !== item.settlementId.toLowerCase()) throw Errors.invalidInput("settlementId", "does not match CapxulPaymentsV3 terms");
17193
+ return {
17194
+ settlementId,
17195
+ ...terms
17196
+ };
17197
+ }
17198
+ //#endregion
16825
17199
  //#region ../protocol/src/evm/zodiac-abi.ts
16826
17200
  const MODULE_PROXY_FACTORY_ABI = [{
16827
17201
  type: "function",
@@ -17185,7 +17559,8 @@ function requiredByPaymentToken(items) {
17185
17559
  }
17186
17560
  return totals;
17187
17561
  }
17188
- function birthCall(contract, item) {
17562
+ function birthCall(command, item, itemIndex) {
17563
+ const contract = command.contractAddress;
17189
17564
  const common = {
17190
17565
  settlementId: item.settlementId,
17191
17566
  recipient: item.recipientSafe,
@@ -17196,7 +17571,7 @@ function birthCall(contract, item) {
17196
17571
  return {
17197
17572
  to: contract,
17198
17573
  value: 0n,
17199
- data: item.operation === "send" ? encodeCapxulPaymentsV2Send({
17574
+ data: item.operation === "send" ? contract.toLowerCase() === "0x46b28f455c8de7c1505e3185A3f8f87B07eaE1aE".toLowerCase() ? encodeCapxulPaymentsV3Send(v3Item(command, item, itemIndex)) : encodeCapxulPaymentsV2Send({
17200
17575
  ...common,
17201
17576
  amount: BigInt(item.rawAmount)
17202
17577
  }) : encodeCapxulPaymentsV2CreateCommitment({
@@ -17208,7 +17583,8 @@ function birthCall(contract, item) {
17208
17583
  })
17209
17584
  };
17210
17585
  }
17211
- function birthCalls(contract, items) {
17586
+ function birthCalls(command, items) {
17587
+ const contract = command.contractAddress;
17212
17588
  const approvals = [...requiredByPaymentToken(items).values()].map(({ token, total }) => ({
17213
17589
  to: token,
17214
17590
  value: 0n,
@@ -17222,7 +17598,7 @@ function birthCalls(contract, items) {
17222
17598
  if (items.length > 1 && sends.length === items.length) return [...approvals, {
17223
17599
  to: contract,
17224
17600
  value: 0n,
17225
- data: encodeCapxulPaymentsV2SendBatch(sends.map((item) => ({
17601
+ data: contract.toLowerCase() === "0x46b28f455c8de7c1505e3185A3f8f87B07eaE1aE".toLowerCase() ? encodeCapxulPaymentsV3SendBatch(sends.map((item, index) => v3Item(command, item, index))) : encodeCapxulPaymentsV2SendBatch(sends.map((item) => ({
17226
17602
  settlementId: item.settlementId,
17227
17603
  recipient: item.recipientSafe,
17228
17604
  token: item.tokenAddress,
@@ -17231,7 +17607,7 @@ function birthCalls(contract, items) {
17231
17607
  documentHash: item.documentHash
17232
17608
  })))
17233
17609
  }];
17234
- return [...approvals, ...items.map((item) => birthCall(contract, item))];
17610
+ return [...approvals, ...items.map((item, index) => birthCall(command, item, index))];
17235
17611
  }
17236
17612
  function lifecycleData(item) {
17237
17613
  switch (item.operation) {
@@ -17246,7 +17622,7 @@ function encodePreparedPaymentCallData(command) {
17246
17622
  if (command.items.length === 0) throw Errors.invalidInput("items", "must not be empty");
17247
17623
  const births = command.items.filter(isBirth);
17248
17624
  if (births.length === command.items.length) {
17249
- const calls = birthCalls(command.contractAddress, births);
17625
+ const calls = birthCalls(command, births);
17250
17626
  return command.executionRoute.kind === "direct" ? safe4337MultiSendUserOpCallData({ calls }) : buildOrgRoleSpendPersonalCallData(buildOrgRoleMultiCall({
17251
17627
  rolesModuleAddress: command.executionRoute.rolesModule,
17252
17628
  roleKey: command.executionRoute.roleKey,
@@ -17309,15 +17685,16 @@ function verifiesMoneyOperation(evidence, expectedSafe, chainId, permissionId) {
17309
17685
  try {
17310
17686
  const command = evidence.preparedCommand;
17311
17687
  const operation = evidence.userOperation;
17312
- if (command === void 0 || operation === void 0 || false) return false;
17313
- if (command.commandId !== evidence.commandId || command.chainId !== chainId || evidence.chainId !== chainId || command.contractAddress.toLowerCase() !== "0x7a5c25aB7ce91d7a475B71cd1ec33E230291f8a4".toLowerCase() || command.items.length !== evidence.paymentIds.length || command.items.some((item, index) => item.paymentId !== evidence.paymentIds[index]) || evidence.userOpSenderSafe.toLowerCase() !== expectedSafe.toLowerCase() || command.executionRoute.userOpSenderSafe.toLowerCase() !== expectedSafe.toLowerCase() || operation.sender.toLowerCase() !== expectedSafe.toLowerCase()) return false;
17688
+ if (command === void 0 || operation === void 0) return false;
17689
+ const knownRouter = command.contractAddress.toLowerCase() === "0x7a5c25aB7ce91d7a475B71cd1ec33E230291f8a4".toLowerCase() || command.contractAddress.toLowerCase() === "0x46b28f455c8de7c1505e3185A3f8f87B07eaE1aE".toLowerCase();
17690
+ if (command.commandId !== evidence.commandId || command.chainId !== chainId || evidence.chainId !== chainId || !knownRouter || command.items.length !== evidence.paymentIds.length || command.items.some((item, index) => item.paymentId !== evidence.paymentIds[index]) || evidence.userOpSenderSafe.toLowerCase() !== expectedSafe.toLowerCase() || command.executionRoute.userOpSenderSafe.toLowerCase() !== expectedSafe.toLowerCase() || operation.sender.toLowerCase() !== expectedSafe.toLowerCase()) return false;
17314
17691
  const route = command.executionRoute;
17315
17692
  if (route.kind === "direct") {
17316
17693
  if (permissionId !== void 0 || command.senderSafe.toLowerCase() !== expectedSafe.toLowerCase()) return false;
17317
17694
  } else if ((permissionId === void 0 ? !isOwnerLifecycle(command) : route.roleKey.toLowerCase() !== roleKeyForPermission(permissionId).toLowerCase()) || command.senderSafe.toLowerCase() !== route.organizationSafe.toLowerCase()) return false;
17318
17695
  if (operation.callData.toLowerCase() !== encodePreparedPaymentCallData(command).toLowerCase()) return false;
17319
17696
  const digest = moneySafeOpDigest(operation, chainId);
17320
- return evidence.digest.toLowerCase() === digest.toLowerCase() && evidence.executionId === `money_execution_${digest.slice(2).toLowerCase()}`;
17697
+ return evidence.digest.toLowerCase() === digest.toLowerCase() && matchesMoneyExecutionId(evidence.executionId, digest, evidence.commandId);
17321
17698
  } catch {
17322
17699
  return false;
17323
17700
  }
@@ -17524,6 +17901,29 @@ function reportMoneyTelemetryFailure(kind, name, cause) {
17524
17901
  }));
17525
17902
  }
17526
17903
  //#endregion
17904
+ //#region ../protocol/src/payments/request-finality.ts
17905
+ /** Add a proved request outcome without changing the original failure. */
17906
+ function withPaymentRequestFinality(error, paymentRequestFinality) {
17907
+ const marked = new CapxulError(error.code, error.message, {
17908
+ cause: error.cause,
17909
+ details: {
17910
+ ...error.details,
17911
+ paymentRequestFinality
17912
+ },
17913
+ ...error.correlationId === void 0 ? {} : { correlationId: error.correlationId },
17914
+ ...error.layer === void 0 ? {} : { layer: error.layer },
17915
+ ...error.mode === void 0 ? {} : { mode: error.mode },
17916
+ ...error.chain === void 0 ? {} : { chain: error.chain }
17917
+ });
17918
+ marked.name = error.name;
17919
+ if (error.stack !== void 0) marked.stack = error.stack;
17920
+ return marked;
17921
+ }
17922
+ /** Only an authoritative failed-key response or confirmed durable closure resolves a key. */
17923
+ function isFinalPaymentRequestError(error) {
17924
+ return error.details?.paymentRequestFinality === "closed" || error.code === "INVALID_INPUT" && error.details?.field === "requestKey" && error.details.paymentRequestFinality === "failed";
17925
+ }
17926
+ //#endregion
17527
17927
  //#region src/payments/prepared-execution.ts
17528
17928
  async function abandonPrepared(deps, executionId, reason, result, onPreparedClosed) {
17529
17929
  const abandoned = await runIfActive(void 0, executions.abandon.name, () => callOperation(deps.convexCall, executions.abandon, {
@@ -17531,8 +17931,12 @@ async function abandonPrepared(deps, executionId, reason, result, onPreparedClos
17531
17931
  reason
17532
17932
  }).pipe(Effect.mapError((publicError) => ({ publicError }))), deps.runPromise);
17533
17933
  if (!abandoned.ok) return abandoned;
17534
- if (abandoned.value) onPreparedClosed?.();
17535
- return result;
17934
+ if (!abandoned.value) return result;
17935
+ onPreparedClosed?.();
17936
+ return result.ok ? result : {
17937
+ ok: false,
17938
+ error: withPaymentRequestFinality(result.error, "closed")
17939
+ };
17536
17940
  }
17537
17941
  async function notifyVerifiedPaymentPrepared(onPrepared, paymentId) {
17538
17942
  if (onPrepared === void 0) return {
@@ -17576,14 +17980,31 @@ async function abandonPreparedCommand(deps, executionId, closePayment, reason, r
17576
17980
  reason
17577
17981
  })).pipe(Effect.mapError((publicError) => ({ publicError })))), controls), deps.runPromise);
17578
17982
  if (!abandoned.ok) return abandoned;
17579
- if (abandoned.value) onPreparedClosed?.();
17580
- return result;
17983
+ if (!abandoned.value) return result;
17984
+ onPreparedClosed?.();
17985
+ return result.ok ? result : {
17986
+ ok: false,
17987
+ error: withPaymentRequestFinality(result.error, "closed")
17988
+ };
17581
17989
  }
17582
17990
  //#endregion
17583
17991
  //#region src/payments/command-execution.ts
17584
17992
  function isAborted$1(signal) {
17585
17993
  return signal?.aborted === true;
17586
17994
  }
17995
+ function settledPaymentsMatch(evidence) {
17996
+ try {
17997
+ return evidence.settled?.payments.every((payment, index) => {
17998
+ const item = evidence.preparedCommand?.items[index];
17999
+ const instructions = payment.documents.filter((document) => document.role === "instruction");
18000
+ const amount = toExactAssetAmount(payment.amount, CONFIGURED_MONEY_ASSETS);
18001
+ const asset = CONFIGURED_MONEY_ASSETS.find((row) => row.assetId === amount.asset);
18002
+ return item?.operation === "send" && payment.status === "settled" && payment.direction === "out" && payment.receipt?.chainId === evidence.chainId && item.tokenAddress.toLowerCase() === asset?.tokenAddress.toLowerCase() && item.rawAmount === amount.minorUnits && instructions.length === 1 && canonicalJson(instructions[0]) === canonicalJson(evidence.preparedCommand?.instructionDocuments?.[index]);
18003
+ }) === true;
18004
+ } catch {
18005
+ return false;
18006
+ }
18007
+ }
17587
18008
  async function executePrepared(deps, prepare, isExpectedRequest, closePaymentOnExit, onPreparedClosed, signal, controls, onPrepared, readAcceptedReplay, checkout, sourceWallet) {
17588
18009
  if (isAborted$1(signal)) return {
17589
18010
  ok: false,
@@ -17616,7 +18037,7 @@ async function executePrepared(deps, prepare, isExpectedRequest, closePaymentOnE
17616
18037
  const prepared = await prepare(signerAddress);
17617
18038
  if (!current()) return cancelled;
17618
18039
  if (!prepared.ok) return prepared;
17619
- const accepted = readAcceptedReplay?.();
18040
+ const accepted = readAcceptedReplay?.() ?? prepared.value.settled;
17620
18041
  const closePrepared = closePaymentOnExit && accepted === void 0;
17621
18042
  const executionId = Schema.decodeUnknownResult(MoneyExecutionIdSchema)(readField(prepared.value, "executionId"));
17622
18043
  if (executionId._tag === "Failure") return {
@@ -17642,12 +18063,12 @@ async function executePrepared(deps, prepare, isExpectedRequest, closePaymentOnE
17642
18063
  if (!verified) return abandon("prepared_mismatch", Errors.invalidInput("execution", "prepared Money operation mismatch"));
17643
18064
  if (accepted !== void 0) {
17644
18065
  const decodedSubmission = Schema.decodeResult(SubmittedPaymentCommandExecutionSchema, { onExcessProperty: "error" })(accepted);
17645
- if (decodedSubmission._tag === "Failure" || !acceptedSubmissionMatches(evidence, decodedSubmission.success)) return {
18066
+ if (decodedSubmission._tag === "Failure" || !acceptedSubmissionMatches(evidence, decodedSubmission.success) || evidence.settled !== void 0 && !settledPaymentsMatch(evidence)) return {
17646
18067
  ok: false,
17647
- error: Errors.invalidInput("execution", "accepted Payroll replay evidence mismatch")
18068
+ error: Errors.invalidInput("execution", "accepted Money replay evidence mismatch")
17648
18069
  };
17649
18070
  if (!current() || isAborted$1(signal)) return cancelled;
17650
- return {
18071
+ if (evidence.settled === void 0) return {
17651
18072
  ok: true,
17652
18073
  value: decodedSubmission.success
17653
18074
  };
@@ -17664,6 +18085,10 @@ async function executePrepared(deps, prepare, isExpectedRequest, closePaymentOnE
17664
18085
  }
17665
18086
  if (!current()) return cancelled;
17666
18087
  if (isAborted$1(signal)) return abandon("cancelled", Errors.cancelled({ operation: "payments" }));
18088
+ if (evidence.settled !== void 0) return {
18089
+ ok: true,
18090
+ value: evidence.settled
18091
+ };
17667
18092
  await emitPreparedInitiation(deps, evidence);
17668
18093
  if (!current()) return cancelled;
17669
18094
  if (isAborted$1(signal)) return abandon("cancelled", Errors.cancelled({ operation: "payments" }));
@@ -17714,10 +18139,10 @@ function itemMatches(prepared, amount) {
17714
18139
  return item.paymentId === prepared.paymentId && Object.entries(PAYMENT_PURPOSE_KIND_CODES).some(([name, code]) => name === prepared.purposeKind && code === item.kind) && expectedPurpose === prepared.purposeKind && documentKind === "invoice" === (purpose === "invoice") && purpose !== "payroll" && item.tokenAddress.toLowerCase() === asset?.tokenAddress.toLowerCase() && (item.operation === "send" ? item.rawAmount : item.totalAmount) === amount.minorUnits && plannedCommitmentMatches(prepared) && recipientMatches(prepared, item.recipientSafe.toLowerCase());
17715
18140
  }
17716
18141
  /** The callData a personal Payment birth item must carry: approve, then send or commit. */
17717
- function expectedPersonalCallData(prepared) {
18142
+ function expectedPersonalCallData(prepared, expectedSafe, chainId) {
17718
18143
  const item = prepared.item;
17719
18144
  if (item.operation !== "send" && item.operation !== "create_commitment") throw new Error("Expected personal Payment birth item");
17720
- const contract = CAPXUL_PAYMENTS_V2_ADDRESS;
18145
+ const contract = toAddress(CAPXUL_PAYMENTS_V2_ADDRESS);
17721
18146
  const { settlementId, recipientSafe, tokenAddress, documentHash } = item;
17722
18147
  const amount = BigInt(item.operation === "send" ? item.rawAmount : item.totalAmount);
17723
18148
  const paymentData = item.operation === "send" ? encodeCapxulPaymentsV2Send({
@@ -17738,26 +18163,61 @@ function expectedPersonalCallData(prepared) {
17738
18163
  kind: item.kind,
17739
18164
  documentHash
17740
18165
  });
17741
- return safe4337MultiSendUserOpCallData({ calls: [{
18166
+ const calls = (router, encodedPaymentData) => safe4337MultiSendUserOpCallData({ calls: [{
17742
18167
  to: tokenAddress,
17743
18168
  value: 0n,
17744
18169
  data: encodeFunctionData({
17745
18170
  abi: ERC20_APPROVE_ABI,
17746
18171
  functionName: "approve",
17747
- args: [contract, amount]
18172
+ args: [router, amount]
17748
18173
  })
17749
18174
  }, {
17750
- to: contract,
18175
+ to: router,
17751
18176
  value: 0n,
17752
- data: paymentData
18177
+ data: encodedPaymentData
17753
18178
  }] });
18179
+ const v2 = calls(contract, paymentData);
18180
+ if (item.operation !== "send") return [v2];
18181
+ const terms = {
18182
+ recipient: item.recipientSafe,
18183
+ token: item.tokenAddress,
18184
+ amount,
18185
+ kind: item.kind,
18186
+ documentHash,
18187
+ jobNonce: paymentJobNonce(prepared.commandId, 0),
18188
+ executor: toAddress(expectedSafe)
18189
+ };
18190
+ const v3Contract = toAddress(CAPXUL_PAYMENTS_V3_ADDRESS);
18191
+ const v3SettlementId = capxulPaymentsV3PaymentId(chainId, v3Contract, terms);
18192
+ if (v3SettlementId.toLowerCase() !== settlementId.toLowerCase()) return [v2];
18193
+ return [calls(v3Contract, encodeCapxulPaymentsV3Send({
18194
+ settlementId: v3SettlementId,
18195
+ ...terms
18196
+ }))];
17754
18197
  }
17755
18198
  function verifiesPersonalOperation(prepared, expectedSafe, chainId) {
17756
18199
  try {
17757
18200
  const operation = prepared.userOperation;
17758
- if (operation.sender.toLowerCase() !== expectedSafe.toLowerCase() || operation.callData.toLowerCase() !== expectedPersonalCallData(prepared).toLowerCase()) return false;
18201
+ if (operation.sender.toLowerCase() !== expectedSafe.toLowerCase() || !expectedPersonalCallData(prepared, expectedSafe, chainId).some((callData) => operation.callData.toLowerCase() === callData.toLowerCase())) return false;
17759
18202
  const digest = moneySafeOpDigest(operation, chainId);
17760
- return prepared.digest.toLowerCase() === digest.toLowerCase() && prepared.executionId === `money_execution_${digest.slice(2).toLowerCase()}`;
18203
+ return prepared.digest.toLowerCase() === digest.toLowerCase() && matchesMoneyExecutionId(prepared.executionId, digest, prepared.commandId);
18204
+ } catch {
18205
+ return false;
18206
+ }
18207
+ }
18208
+ /** A settled reply retains the verified operation, quantity, instruction and receipt. */
18209
+ function verifiesSettledPersonalReplay(evidence) {
18210
+ const settled = evidence.settled;
18211
+ if (settled === void 0) return true;
18212
+ try {
18213
+ const instructions = settled.payment.documents.filter((document) => document.role === "instruction");
18214
+ return acceptedSubmissionMatches({
18215
+ ...evidence,
18216
+ paymentIds: [evidence.paymentId]
18217
+ }, {
18218
+ ...settled,
18219
+ payments: [settled.payment]
18220
+ }) && settled.payment.status === "settled" && settled.payment.direction === "out" && settled.payment.receipt?.chainId === evidence.chainId && itemMatches(evidence, toExactAssetAmount(settled.payment.amount, CONFIGURED_MONEY_ASSETS)) && instructions.length === 1 && canonicalJson(instructions[0]) === canonicalJson(evidence.instructionDocument);
17761
18221
  } catch {
17762
18222
  return false;
17763
18223
  }
@@ -17871,6 +18331,7 @@ async function preparedMismatch(chainId, evidence, payment, expected) {
17871
18331
  if (evidence.userOpSenderSafe.toLowerCase() !== expected.expectedSafe.toLowerCase()) return mismatch("userOpSenderSafe", "prepared Payment execution uses another Account Safe");
17872
18332
  if (!await verifiesPersonalDocument(evidence)) return mismatch("document", "prepared Payment document does not match the request");
17873
18333
  if (!verifiesPersonalOperation(evidence, expected.expectedSafe, chainId)) return mismatch("execution", "prepared Payment operation does not match the request");
18334
+ if (!verifiesSettledPersonalReplay(evidence)) return mismatch("execution", "settled Payment replay evidence mismatch");
17874
18335
  }
17875
18336
  /**
17876
18337
  * Prepare one personal Payment for this signer and check what the backend
@@ -17921,19 +18382,27 @@ async function emitPreparedPaymentInitiated(deps, evidence) {
17921
18382
  async function executePersonalPayment(deps, payment, signal, requestKey, onPreparedClosed, onPrepared) {
17922
18383
  if (isAborted(signal)) return cancelled(CAPXUL_OPERATIONS.payments.pay);
17923
18384
  if (deps.signer === void 0) return mismatch("signer", "payments.pay requires a configured CapxulSigner");
17924
- if (deps.actor.authSession() === null) return {
18385
+ const session = deps.actor.authSession();
18386
+ if (session === null) return {
17925
18387
  ok: false,
17926
18388
  error: Errors.notAuthenticated()
17927
18389
  };
18390
+ const lifetime = deps.actor.authLifetime();
18391
+ const current = () => deps.actor.matchesAuthLifetime(lifetime, session.authUserId);
17928
18392
  const signerAddress = await signerCall(deps.signer.source, "getAddress", () => deps.signer.getAddress());
17929
18393
  if (!signerAddress.ok) return signerAddress;
17930
18394
  const prepared = await prepareVerifiedPersonalPayment(deps, payment, signerAddress.value, requestKey ?? `pay_${crypto.randomUUID()}`, signal, onPreparedClosed);
17931
18395
  if (!prepared.ok) return prepared;
17932
18396
  const evidence = prepared.value;
18397
+ if (evidence.settled !== void 0 && !current()) return cancelled(CAPXUL_OPERATIONS.payments.pay);
17933
18398
  const digest = evidence.digest;
17934
18399
  if (isAborted(signal)) return abandonPrepared(deps, evidence.executionId, "cancelled", cancelled(CAPXUL_OPERATIONS.payments.pay), onPreparedClosed);
17935
18400
  const delivered = await notifyVerifiedPaymentPrepared(onPrepared, evidence.paymentId);
17936
18401
  if (!delivered.ok) return delivered;
18402
+ if (evidence.settled !== void 0) return current() ? {
18403
+ ok: true,
18404
+ value: evidence.settled
18405
+ } : cancelled(CAPXUL_OPERATIONS.payments.pay);
17937
18406
  if (isAborted(signal)) return abandonPrepared(deps, evidence.executionId, "cancelled", cancelled(CAPXUL_OPERATIONS.payments.pay), onPreparedClosed);
17938
18407
  await emitPreparedPaymentInitiated(deps, evidence);
17939
18408
  if (isAborted(signal)) return abandonPrepared(deps, evidence.executionId, "cancelled", cancelled(CAPXUL_OPERATIONS.payments.pay), onPreparedClosed);
@@ -18467,6 +18936,41 @@ function isCheckoutSettlementConsumed(error, settlementId) {
18467
18936
  return false;
18468
18937
  }
18469
18938
  //#endregion
18939
+ //#region src/requests/request-keys.ts
18940
+ /** Keep an Invoice attempt through uncertainty; renew an old failed default only before preparation. */
18941
+ async function withInvoiceRequestKey(actorId, intent, provided, run) {
18942
+ let key;
18943
+ let prepared = false;
18944
+ try {
18945
+ key = await paymentRequestKeyLifecycle(`invoice-request:${actorId}`, intent, provided);
18946
+ let result = await run(key.key, () => {
18947
+ prepared = true;
18948
+ });
18949
+ const renew = provided === void 0 && !prepared && !result.ok && isFinalPaymentRequestError(result.error) && result.error.details?.paymentRequestFinality === "failed";
18950
+ let finished = true;
18951
+ try {
18952
+ await key.finish(!result.ok && isFinalPaymentRequestError(result.error));
18953
+ } catch {
18954
+ finished = false;
18955
+ }
18956
+ if (renew && finished) {
18957
+ key = await paymentRequestKeyLifecycle(`invoice-request:${actorId}`, intent);
18958
+ result = await run(key.key, () => {
18959
+ prepared = true;
18960
+ });
18961
+ await key.finish(!result.ok && isFinalPaymentRequestError(result.error)).catch(() => void 0);
18962
+ }
18963
+ return result;
18964
+ } catch (cause) {
18965
+ return {
18966
+ ok: false,
18967
+ error: asCapxulError(cause)
18968
+ };
18969
+ } finally {
18970
+ await key?.finish(false).catch(() => void 0);
18971
+ }
18972
+ }
18973
+ //#endregion
18470
18974
  //#region src/requests/checkout-payments.ts
18471
18975
  const missing$1 = async () => ({
18472
18976
  ok: false,
@@ -18656,72 +19160,96 @@ function makeCheckoutMethods(deps) {
18656
19160
  }
18657
19161
  //#endregion
18658
19162
  //#region src/requests/inbox-payments.ts
18659
- function mapApprovedInboxPayment(command, input) {
19163
+ const refused = () => ({
19164
+ ok: false,
19165
+ error: Errors.providerError("convex", inboxes.approve.name, "approved Payment read does not match its command")
19166
+ });
19167
+ /** Read the approved command's actual Payment under the payer's existing scope. */
19168
+ async function readApprovedInboxPayment(calls, command, controls, current) {
18660
19169
  const item = command.items[0];
18661
- if (item === void 0 || item.operation !== "send" && item.operation !== "create_commitment") return {
19170
+ const cancelled = {
18662
19171
  ok: false,
18663
- error: Errors.providerError("convex", inboxes.approve.name, "reply has no payment birth item")
19172
+ error: Errors.cancelled({ operation: inboxes.approve.name })
18664
19173
  };
18665
- try {
18666
- const asset = CONFIGURED_MONEY_ASSETS.find((candidate) => candidate.tokenAddress.toLowerCase() === item.tokenAddress.toLowerCase());
18667
- if (asset === void 0) return {
18668
- ok: false,
18669
- error: Errors.providerError("convex", inboxes.approve.name, "prepared payment asset is not configured")
18670
- };
18671
- const amount = {
18672
- asset: asset.assetId,
18673
- value: formatUnits(BigInt(item.operation === "send" ? item.rawAmount : item.totalAmount), asset.decimals)
18674
- };
18675
- const zero = {
18676
- ...amount,
18677
- value: "0"
18678
- };
18679
- const timing = input.timing ?? { kind: "instant" };
18680
- return {
18681
- ok: true,
18682
- value: {
18683
- id: item.paymentId,
18684
- status: timing.kind === "instant" ? "pending" : timing.kind === "scheduled" ? "scheduled" : "streaming",
18685
- amount,
18686
- paymentType: "invoice",
18687
- direction: "out",
18688
- counterpartyLabel: item.recipientSafe,
18689
- receipt: null,
18690
- recipient: {
18691
- kind: "external_address",
18692
- label: item.recipientSafe
18693
- },
18694
- documents: [],
18695
- timing,
18696
- released: zero,
18697
- availableToClaim: zero,
18698
- createdAt: 0,
18699
- updatedAt: 0
18700
- }
18701
- };
18702
- } catch (cause) {
18703
- return {
18704
- ok: false,
18705
- error: Errors.unknown(cause)
18706
- };
18707
- }
19174
+ if (command.items.length !== 1 || item === void 0 || item.operation !== "send" && item.operation !== "create_commitment") return refused();
19175
+ if (!current()) return cancelled;
19176
+ const check = (payment) => {
19177
+ if (!current()) return cancelled;
19178
+ if (payment === null || payment.id !== item.paymentId || payment.direction !== "out") return refused();
19179
+ try {
19180
+ const amount = toExactAssetAmount(payment.amount, CONFIGURED_MONEY_ASSETS);
19181
+ const asset = CONFIGURED_MONEY_ASSETS.find((row) => row.assetId === amount.asset);
19182
+ const instruction = payment.documents.find((document) => document.role === "instruction");
19183
+ const expected = command.instructionDocuments?.[0];
19184
+ if (asset?.tokenAddress.toLowerCase() !== item.tokenAddress.toLowerCase() || amount.minorUnits !== (item.operation === "send" ? item.rawAmount : item.totalAmount) || instruction?.documentHash !== item.documentHash || expected !== void 0 && (instruction.contentHash !== expected.contentHash || instruction.format !== expected.format) || payment.status === "settled" && payment.receipt?.chainId !== command.chainId) return refused();
19185
+ return {
19186
+ ok: true,
19187
+ value: normalizePaymentTiming(payment)
19188
+ };
19189
+ } catch (cause) {
19190
+ return {
19191
+ ok: false,
19192
+ error: Errors.unknown(cause)
19193
+ };
19194
+ }
19195
+ };
19196
+ const actor = calls.actor;
19197
+ const result = actor.kind === "account" ? await calls.bookChecked(records.get, { paymentId: item.paymentId }, controls, check) : await calls.bookChecked(records.getForOrganization, {
19198
+ orgId: actor.orgId,
19199
+ paymentId: item.paymentId
19200
+ }, controls, (response) => response.orgId === actor.orgId ? check(response.payment) : refused());
19201
+ return current() ? result : cancelled;
18708
19202
  }
18709
19203
  //#endregion
18710
19204
  //#region src/requests/inboxes.ts
18711
19205
  function makeInboxMethods(calls) {
18712
- const { actor, convexCall, deps, observeContactScope, book, bookChecked } = calls;
19206
+ const { actor, convexCall, deps, observeContactScope, book } = calls;
18713
19207
  return {
18714
19208
  paymentTerms: (requestId, options) => book(inboxes.paymentTerms, {
18715
19209
  actor,
18716
19210
  paymentRequestId: requestId
18717
19211
  }, options, (terms) => terms),
18718
19212
  list: (options) => book(inboxes.listCurrent, { actor }, options, (items) => mapPage(items, mapInboxItem)),
18719
- approve: (input, options) => bookChecked(inboxes.approve, {
18720
- actor,
18721
- paymentRequestId: input.requestId,
18722
- ...input.timing === void 0 ? {} : { timing: input.timing },
18723
- ...input.permissionId === void 0 ? {} : { permissionId: input.permissionId }
18724
- }, options, (prepared) => mapApprovedInboxPayment(prepared, input)),
19213
+ approve: async (providedInput, options) => {
19214
+ const input = structuredClone(providedInput);
19215
+ const identity = deps.identityActor;
19216
+ const lifetime = identity?.authLifetime();
19217
+ const current = () => identity === void 0 || lifetime !== void 0 && identity.matchesAuthLifetime(lifetime, lifetime.authUserId);
19218
+ const cancelled = {
19219
+ ok: false,
19220
+ error: Errors.cancelled({ operation: inboxes.approve.name })
19221
+ };
19222
+ const controls = deps.invocationControls?.(options) ?? options;
19223
+ const approve = async (requestKey) => {
19224
+ if (!current()) return cancelled;
19225
+ const prepared = await book(inboxes.approve, {
19226
+ actor,
19227
+ paymentRequestId: input.requestId,
19228
+ ...requestKey === void 0 ? {} : { requestKey },
19229
+ ...input.timing === void 0 ? {} : { timing: input.timing },
19230
+ ...input.permissionId === void 0 ? {} : { permissionId: input.permissionId }
19231
+ }, controls, (value) => value);
19232
+ if (!current()) return cancelled;
19233
+ if (!prepared.ok) return prepared;
19234
+ return readApprovedInboxPayment(calls, prepared.value, controls, current);
19235
+ };
19236
+ const terms = await book(inboxes.paymentTerms, {
19237
+ actor,
19238
+ paymentRequestId: input.requestId
19239
+ }, controls, (value) => value);
19240
+ if (!current()) return cancelled;
19241
+ if (!terms.ok) return terms;
19242
+ if (terms.value.instruction.kind !== "invoice") return approve(input.requestKey);
19243
+ return withInvoiceRequestKey(lifetime?.authUserId ?? "signed-out", {
19244
+ ...terms.value,
19245
+ payer: actor.kind === "account" ? { kind: "account" } : {
19246
+ kind: "organization",
19247
+ orgId: actor.orgId
19248
+ },
19249
+ permissionId: input.permissionId,
19250
+ release: input.timing ?? { kind: "instant" }
19251
+ }, input.requestKey, (key) => approve(key));
19252
+ },
18725
19253
  fulfill: (input, options) => {
18726
19254
  const onPrepared = options?.onPrepared;
18727
19255
  const decoded = Schema.decodeResult(RequestPaymentConfirmationSchema, { onExcessProperty: "error" })(input);
@@ -18744,20 +19272,26 @@ function makeInboxMethods(calls) {
18744
19272
  const controls = deps.invocationControls?.(options) ?? options;
18745
19273
  return runCapxulEffect(Effect.gen(function* () {
18746
19274
  const parent = yield* Effect.currentSpan.pipe(Effect.orDie);
18747
- return yield* awaitCapxulResult(() => executeRequestPayment({
19275
+ const run = (named, prepared) => executeRequestPayment({
18748
19276
  actor: identityActor,
18749
19277
  chainId,
18750
19278
  signer,
18751
19279
  convexCall,
18752
19280
  runPromise: deps.runPromise,
18753
19281
  ...deps.telemetry === void 0 ? {} : { telemetry: deps.telemetry }
18754
- }, confirmation, carryInvocationParentSpan(controls, parent), onPrepared === void 0 ? void 0 : async (paymentIds) => {
18755
- await onPrepared({ paymentIds });
19282
+ }, named, carryInvocationParentSpan(controls, parent), async (paymentIds) => {
19283
+ prepared();
19284
+ await onPrepared?.({ paymentIds });
18756
19285
  return {
18757
19286
  ok: true,
18758
19287
  value: void 0
18759
19288
  };
18760
- }));
19289
+ });
19290
+ const { requestKey, ...intent } = confirmation;
19291
+ return yield* awaitCapxulResult(() => confirmation.instruction.kind !== "invoice" ? run(confirmation, () => void 0) : withInvoiceRequestKey(identityActor.authSession()?.authUserId ?? "signed-out", intent, requestKey, (key, prepared) => run({
19292
+ ...confirmation,
19293
+ requestKey: key
19294
+ }, prepared)));
18761
19295
  }).pipe(Effect.tap(() => observeContactScope)), controls, CAPXUL_OPERATIONS.inbox.fulfill, deps.runPromise);
18762
19296
  },
18763
19297
  decline: (requestId, options) => book(inboxes.decline, {
@@ -19683,7 +20217,7 @@ function makePersonalPay(deps) {
19683
20217
  };
19684
20218
  }
19685
20219
  release(false);
19686
- await finishQuietly(requestKey, submitted.ok || flight.requestState.resolved);
20220
+ await finishQuietly(requestKey, submitted.ok || flight.requestState.resolved || isFinalPaymentRequestError(submitted.error));
19687
20221
  return mapOk(submitted, (value) => normalizePaymentTiming(value.payment));
19688
20222
  };
19689
20223
  }
@@ -19760,6 +20294,7 @@ function makePaymentsMethods(deps) {
19760
20294
  createCommitment: (input, options) => pay(input, options),
19761
20295
  claim: (paymentId, options) => runLifecycle({
19762
20296
  kind: "claim",
20297
+ requestKey: options?.requestKey ?? `pay_${crypto.randomUUID()}`,
19763
20298
  paymentId
19764
20299
  }, deps.invocationControls?.(options) ?? options, CAPXUL_OPERATIONS.payments.claim),
19765
20300
  list: (options) => {
@@ -19772,6 +20307,7 @@ function makePaymentsMethods(deps) {
19772
20307
  },
19773
20308
  cancel: (paymentId, options) => runLifecycle({
19774
20309
  kind: "cancel",
20310
+ requestKey: options?.requestKey ?? `pay_${crypto.randomUUID()}`,
19775
20311
  paymentId
19776
20312
  }, deps.invocationControls?.(options) ?? options, CAPXUL_OPERATIONS.payments.cancel),
19777
20313
  redirect: async (input, options) => {
@@ -19780,6 +20316,7 @@ function makePaymentsMethods(deps) {
19780
20316
  if (!recipient.ok) return runCapxulEffect(Effect.fail(recipient.error), observationOnlyControls(controls), CAPXUL_OPERATIONS.payments.redirect, deps.runPromise);
19781
20317
  return runLifecycle({
19782
20318
  kind: "redirect",
20319
+ requestKey: options?.requestKey ?? `pay_${crypto.randomUUID()}`,
19783
20320
  paymentId: input.paymentId,
19784
20321
  recipient: recipient.value
19785
20322
  }, controls, CAPXUL_OPERATIONS.payments.redirect);
@@ -20033,7 +20570,7 @@ async function executeOrganizationBatch(scope, input, signal, operation, control
20033
20570
  }
20034
20571
  release(false);
20035
20572
  try {
20036
- await requestKey.finish(result.ok || flight.requestState.resolved);
20573
+ await requestKey.finish(result.ok || flight.requestState.resolved || isFinalPaymentRequestError(result.error));
20037
20574
  } catch {}
20038
20575
  const normalized = mapOk(result, (value) => value.payments.map((payment) => normalizePaymentTiming(payment)));
20039
20576
  if (!normalized.ok) return normalized;
@@ -20134,7 +20671,8 @@ function makeOrganizationPaymentsMethods(deps, orgId) {
20134
20671
  },
20135
20672
  cancel: (paymentId, options) => ownerLifecycle({
20136
20673
  kind: "cancel",
20137
- paymentId
20674
+ paymentId,
20675
+ requestKey: options?.requestKey ?? `pay_${crypto.randomUUID()}`
20138
20676
  }, deps.invocationControls?.(options) ?? options, CAPXUL_OPERATIONS.organizationPayments.cancel),
20139
20677
  redirect: (input, options) => {
20140
20678
  const controls = deps.invocationControls?.(options) ?? options;
@@ -20142,7 +20680,8 @@ function makeOrganizationPaymentsMethods(deps, orgId) {
20142
20680
  return recipient.ok ? ownerLifecycle({
20143
20681
  kind: "redirect",
20144
20682
  paymentId: input.paymentId,
20145
- recipient: recipient.value
20683
+ recipient: recipient.value,
20684
+ requestKey: options?.requestKey ?? `pay_${crypto.randomUUID()}`
20146
20685
  }, controls, CAPXUL_OPERATIONS.organizationPayments.redirect) : runCapxulEffect(Effect.fail(recipient.error), observationOnlyControls(controls), CAPXUL_OPERATIONS.organizationPayments.redirect, deps.runPromise);
20147
20686
  },
20148
20687
  payBatch: (input, options) => {
@@ -20762,6 +21301,46 @@ function makeAccountMethods(deps) {
20762
21301
  };
20763
21302
  }
20764
21303
  //#endregion
21304
+ //#region src/accounts/approval-rules.ts
21305
+ const IN_FLIGHT = /* @__PURE__ */ new Set([
21306
+ "pending",
21307
+ "settling",
21308
+ "in_transit"
21309
+ ]);
21310
+ /** A Payment the chain has not decided yet. */
21311
+ function inFlight(payment) {
21312
+ return IN_FLIGHT.has(payment.status);
21313
+ }
21314
+ /**
21315
+ * The operation the approval describes is the one its digest signs: the
21316
+ * SafeOp digest of its UserOperation on this client's chain, and the
21317
+ * execution that digest names. Anything else is refused before the key signs.
21318
+ */
21319
+ function describedOperation(approval, chainId) {
21320
+ const { operation, summary } = approval;
21321
+ if (chainId !== void 0 && summary.network.chainId !== chainId) return Errors.invalidInput("approval", "the approval is for another chain");
21322
+ try {
21323
+ const digest = moneySafeOpDigest(operation.userOperation, summary.network.chainId);
21324
+ if (digest.toLowerCase() === operation.digest.toLowerCase() && matchesMoneyExecutionId(operation.executionId, digest, operation.commandId)) return void 0;
21325
+ } catch {}
21326
+ return Errors.invalidInput("approval", "the operation does not match the digest it asks to sign");
21327
+ }
21328
+ /** Wait, unless the caller gives up first. False when aborted. */
21329
+ function sleep(ms, signal) {
21330
+ if (signal?.aborted === true) return Promise.resolve(false);
21331
+ return new Promise((resolve) => {
21332
+ const timer = setTimeout(() => {
21333
+ signal?.removeEventListener("abort", onAbort);
21334
+ resolve(true);
21335
+ }, ms);
21336
+ const onAbort = () => {
21337
+ clearTimeout(timer);
21338
+ resolve(false);
21339
+ };
21340
+ signal?.addEventListener("abort", onAbort, { once: true });
21341
+ });
21342
+ }
21343
+ //#endregion
20765
21344
  //#region src/accounts/organization-approvals.ts
20766
21345
  /** The Organization Payment prepared for `signerAddress` and checked, before any approval. */
20767
21346
  async function prepareVerifiedOrganizationPayment(deps, input, signerAddress, signal) {
@@ -20854,58 +21433,6 @@ async function checkedBankApproval(deps, input, opened) {
20854
21433
  });
20855
21434
  }
20856
21435
  //#endregion
20857
- //#region src/accounts/approval-rules.ts
20858
- const IN_FLIGHT = /* @__PURE__ */ new Set([
20859
- "pending",
20860
- "settling",
20861
- "in_transit"
20862
- ]);
20863
- /** A Payment the chain has not decided yet. */
20864
- function inFlight(payment) {
20865
- return IN_FLIGHT.has(payment.status);
20866
- }
20867
- /**
20868
- * The approved operation is not sent yet: the approval is approved, or it was
20869
- * consumed but a Payment is still `pending` (a recorded send moves it to
20870
- * `settling`), so the send did not land.
20871
- */
20872
- function unsent(approval, payments) {
20873
- return approval.state === "approved" || approval.state === "consumed" && payments.some((payment) => payment.status === "pending");
20874
- }
20875
- /** The send was refused because another send of the same operation holds its claim. */
20876
- function anotherSendInFlight(error) {
20877
- return error.code === "SUPERSEDED" && error.details?.reason === "unobservable-claim";
20878
- }
20879
- /**
20880
- * The operation the approval describes is the one its digest signs: the
20881
- * SafeOp digest of its UserOperation on this client's chain, and the
20882
- * execution that digest names. Anything else is refused before the key signs.
20883
- */
20884
- function describedOperation(approval, chainId) {
20885
- const { operation, summary } = approval;
20886
- if (chainId !== void 0 && summary.network.chainId !== chainId) return Errors.invalidInput("approval", "the approval is for another chain");
20887
- try {
20888
- const digest = moneySafeOpDigest(operation.userOperation, summary.network.chainId);
20889
- if (digest.toLowerCase() === operation.digest.toLowerCase() && operation.executionId === `money_execution_${digest.slice(2).toLowerCase()}`) return void 0;
20890
- } catch {}
20891
- return Errors.invalidInput("approval", "the operation does not match the digest it asks to sign");
20892
- }
20893
- /** Wait, unless the caller gives up first. False when aborted. */
20894
- function sleep(ms, signal) {
20895
- if (signal?.aborted === true) return Promise.resolve(false);
20896
- return new Promise((resolve) => {
20897
- const timer = setTimeout(() => {
20898
- signal?.removeEventListener("abort", onAbort);
20899
- resolve(true);
20900
- }, ms);
20901
- const onAbort = () => {
20902
- clearTimeout(timer);
20903
- resolve(false);
20904
- };
20905
- signal?.addEventListener("abort", onAbort, { once: true });
20906
- });
20907
- }
20908
- //#endregion
20909
21436
  //#region ../protocol/src/payroll/model.ts
20910
21437
  function toPayrollRunId(raw) {
20911
21438
  return toNonEmptyStringBrand(raw, "payrollRunId", (value) => isNonEmptyString(value));
@@ -21367,7 +21894,8 @@ function lifecycleIntent(input) {
21367
21894
  ok: true,
21368
21895
  value: {
21369
21896
  kind: "cancel",
21370
- paymentId: input.cancel
21897
+ paymentId: input.cancel,
21898
+ requestKey: input.requestKey ?? `pay_${crypto.randomUUID()}`
21371
21899
  }
21372
21900
  };
21373
21901
  const recipient = normalizeTargetForBackend(input.to, "to");
@@ -21376,7 +21904,8 @@ function lifecycleIntent(input) {
21376
21904
  value: {
21377
21905
  kind: "redirect",
21378
21906
  paymentId: input.redirect,
21379
- recipient: recipient.value
21907
+ recipient: recipient.value,
21908
+ requestKey: input.requestKey ?? `pay_${crypto.randomUUID()}`
21380
21909
  }
21381
21910
  } : recipient;
21382
21911
  }
@@ -21408,10 +21937,19 @@ async function prepareVerifiedRequestPayment(deps, input, signerAddress, signal)
21408
21937
  error: Errors.invalidInput("confirmation", "invalid request confirmation")
21409
21938
  };
21410
21939
  const confirmation = decoded.success;
21411
- return checked(deps, signerAddress, await runIfActive(signal, commands$1.prepareRequest.name, () => callOperation(deps.convexCall, commands$1.prepareRequest, {
21412
- confirmation,
21413
- signerAddress
21414
- }).pipe(Effect.mapError((publicError) => ({ publicError }))), deps.runPromise), requestPaymentCheck(confirmation), false);
21940
+ const run = async (named, prepared) => {
21941
+ const result = await runIfActive(signal, commands$1.prepareRequest.name, () => callOperation(deps.convexCall, commands$1.prepareRequest, {
21942
+ confirmation: named,
21943
+ signerAddress
21944
+ }).pipe(Effect.mapError((publicError) => ({ publicError }))), deps.runPromise);
21945
+ if (result.ok) prepared();
21946
+ return checked(deps, signerAddress, result, requestPaymentCheck(named), false);
21947
+ };
21948
+ const { requestKey, ...intent } = confirmation;
21949
+ return confirmation.instruction.kind !== "invoice" ? run(confirmation, () => void 0) : withInvoiceRequestKey(deps.actor?.authSession()?.authUserId ?? "signed-out", intent, requestKey, (key, prepared) => run({
21950
+ ...confirmation,
21951
+ requestKey: key
21952
+ }, prepared));
21415
21953
  }
21416
21954
  /** One payroll run: the run the backend writes and the batch that pays it, checked together. */
21417
21955
  async function prepareVerifiedPayrollRun(deps, input, signerAddress, signal) {
@@ -21506,7 +22044,7 @@ function makeApprovalsMethods(deps) {
21506
22044
  const signal = options?.signal;
21507
22045
  if (isCommandApproval(input)) return openApproval(signal, (signerAddress) => prepareVerifiedCommand(deps, input, signerAddress, signal));
21508
22046
  if (isPermissionChange(input)) return openApproval(signal, async (signerAddress) => {
21509
- const { prepareVerifiedPermissionChange } = await import("./permission-approvals-vDZJpy8H.mjs");
22047
+ const { prepareVerifiedPermissionChange } = await import("./permission-approvals-Bw9VaKay.mjs");
21510
22048
  return prepareVerifiedPermissionChange(deps, input, signerAddress, signal);
21511
22049
  });
21512
22050
  if ("organizationId" in input) return checkedBankApproval(deps, input, await openApproval(signal, (signerAddress) => prepareVerifiedOrganizationPayment(deps, input, signerAddress, signal)));
@@ -21603,43 +22141,33 @@ function makeApprovalsMethods(deps) {
21603
22141
  };
21604
22142
  /**
21605
22143
  * One read of the approval: its outcome when it has ended, or null to read
21606
- * again. The Payments are read before anything is sent, so a send is never
21607
- * made for Payments this caller cannot follow.
22144
+ * again. This path only reads. The backend owns submission and recovery.
21608
22145
  */
21609
22146
  const step = async (approvalId, signal, organizationId) => {
21610
- const read = await call(approvals.get.name, approvals.get, { approvalId }, signal);
22147
+ const read = await call(approvals.observe.name, approvals.observe, { approvalId }, signal);
21611
22148
  if (!read.ok) return read;
21612
- const approval = read.value;
22149
+ const { approval, completed } = read.value;
21613
22150
  if (approval.state === "pending") return {
21614
22151
  ok: true,
21615
22152
  value: null
21616
22153
  };
21617
- if (endsOnceSent(approval)) {
21618
- if (approval.state !== "approved" && approval.state !== "consumed") return {
21619
- ok: true,
21620
- value: {
21621
- approval,
21622
- payments: []
21623
- }
21624
- };
21625
- const sent = await submit(approvalId);
21626
- return sent.ok || !anotherSendInFlight(sent.error) ? sent : {
21627
- ok: true,
21628
- value: null
21629
- };
21630
- }
22154
+ const closed = approval.state === "rejected" || approval.state === "expired";
22155
+ if (!closed && !completed) return {
22156
+ ok: true,
22157
+ value: null
22158
+ };
22159
+ if (!movesMoney(approval)) return {
22160
+ ok: true,
22161
+ value: {
22162
+ approval,
22163
+ payments: []
22164
+ }
22165
+ };
21631
22166
  const payments = await readApprovalPayments(deps, approval.operation.paymentIds, organizationId ?? (approval.actor.kind === "organization" ? approval.actor.orgId : void 0), signal);
21632
22167
  if (!payments.ok) return payments;
21633
- if (unsent(approval, payments.value)) {
21634
- const sent = await submit(approvalId);
21635
- return sent.ok || anotherSendInFlight(sent.error) ? {
21636
- ok: true,
21637
- value: null
21638
- } : sent;
21639
- }
21640
22168
  return {
21641
22169
  ok: true,
21642
- value: approval.state !== "consumed" || !payments.value.some(inFlight) ? {
22170
+ value: closed || endsOnceSent(approval) || !payments.value.some(inFlight) ? {
21643
22171
  approval,
21644
22172
  payments: payments.value
21645
22173
  } : null
@@ -22317,7 +22845,7 @@ function decodeStatus(body) {
22317
22845
  */
22318
22846
  const HEADS = {
22319
22847
  transfer: "select \"id\", \"chain_id\", \"tx_hash\", \"transaction_log_ordinal\", \"log_index\", \"block_number\", \"block_hash\", \"timestamp\", \"asset_id\", \"token\", \"from\", \"to\", \"amount\" from \"transfer\" where (\"transfer\".\"from\" = $1 or \"transfer\".\"to\" = $2) order by \"transfer\".\"block_number\" desc, \"transfer\".\"id\" desc",
22320
- payment: "select \"id\", \"chain_id\", \"tx_hash\", \"transaction_log_ordinal\", \"log_index\", \"block_number\", \"block_hash\", \"timestamp\", \"contract\", \"settlement_id\", \"sender\", \"recipient\", \"asset_id\", \"token\", \"amount\", \"kind\", \"document_hash\" from \"payment\" where (\"payment\".\"sender\" = $1 or \"payment\".\"recipient\" = $2) order by \"payment\".\"block_number\" desc, \"payment\".\"id\" desc",
22848
+ payment: "select \"id\", \"chain_id\", \"tx_hash\", \"transaction_log_ordinal\", \"log_index\", \"block_number\", \"block_hash\", \"timestamp\", \"contract\", \"settlement_id\", \"sender\", \"recipient\", \"asset_id\", \"token\", \"amount\", \"kind\", \"document_hash\", \"job_nonce\", \"executor\" from \"payment\" where (\"payment\".\"sender\" = $1 or \"payment\".\"recipient\" = $2) order by \"payment\".\"block_number\" desc, \"payment\".\"id\" desc",
22321
22849
  balance: "select \"chain_id\", \"asset_id\", \"to\", \"amount\" from \"balance\" where \"balance\".\"to\" = $1"
22322
22850
  };
22323
22851
  /** How many times the statement binds the Safe address. */
@@ -22360,7 +22888,7 @@ function ponderQuery(table, input) {
22360
22888
  input.limit
22361
22889
  ];
22362
22890
  return {
22363
- sql: `${HEADS.payment.slice(0, HEADS.payment.indexOf("where "))}where (("payment"."sender" = $1 or "payment"."recipient" = $2) and "payment"."settlement_id" in (${input.settlements.map((_, i) => `$${i + 3}`).join(", ")})) limit $${params.length}`,
22891
+ sql: `${HEADS.payment.slice(0, HEADS.payment.indexOf("where ")).replace(" from \"payment\"", ", \"contract\" as \"router\" from \"payment\"")}where (("payment"."sender" = $1 or "payment"."recipient" = $2) and "payment"."settlement_id" in (${input.settlements.map((_, i) => `$${i + 3}`).join(", ")})) limit $${params.length}`,
22364
22892
  params,
22365
22893
  typings: params.map(() => "none")
22366
22894
  };
@@ -24558,4 +25086,4 @@ function executeIdentityProductObservation(telemetry, record, state) {
24558
25086
  return ignoreTransportFailure(() => invocationTelemetry.emit(mapped), "emit", mapped.name).pipe(Effect.andThen(ignoreTransportFailure(after, mapped.name === "auth_signed_out" ? "reset" : "identify", mapped.name)));
24559
25087
  }
24560
25088
  //#endregion
24561
- export { parseAssetAmount as $, hashPermissionReplacementPreview as $n, EXPECTED_OPERATION_OUTCOMES as $r, isSettingUpLifecycle as $t, registerProductTelemetryInvocation as A, toDurationMs as Ai, onboardings as An, toExactAssetAmount as Ar, safe4337MultiSendUserOpCallData as At, makePaymentsMethods as B, FAILURE_MODES$1 as Bi, invitations as Bn, publicIdentityFailure as Br, CAPXUL_SDK_EXPECTED_OUTCOME_EVENT as Bt, AccountReadPortTag as C, AuthClientPortTag as Ci, EXCEPTION_EVENT_NAME as Cn, toPermissionAssignmentId as Cr, SEND_SIGNATURE as Ct, convexCallErrorFromCapxul as D, BrowserAuthCacheAdapter as Di, normalizeCapxulOperation as Dn, currencySymbolFor as Dr, deriveCapxulSafeAddress as Dt, ConvexCallPortTag as E, InMemoryAuthCacheAdapter as Ei, isCapxulOperation as En, ChainIdSchema$1 as Er, TOKENS as Et, decodePayrollRunInput as F, toJwtToken as Fi, PreparedPermissionExecutionSchema as Fn, toWeiAmount as Fr, callOperation as Ft, isCheckoutSettlementConsumed as G, AuthCachePortTag as Gi, workspaces as Gn, runCapxulEffect as Gr, withCapturedAttemptContext as Gt, makeDestinationsMethods as H, isRecord as Hi, roles as Hn, runPortEffect as Hr, observeFailedResult as Ht, toPayrollGroupId as I, toSessionToken as Ii, PermissionCommandViewSchema as In, absurd as Ir, asCapxulError as It, subscribeFreshQuery as J, ORGANIZATION_SETUP_STATUSES as Jn, defectAsCapxulError as Jr, normalizeExceptionErrorKind as Jt, makeTargetsMethods as K, OrganizationSetupSchema as Kn, withVerifiedOrganizationScope as Kr, EXCEPTION_MESSAGE as Kt, makeAccountMethods as L, Errors as Li, PayrollGroupIdSchema as Ln, reference as Lr, toPublicError$1 as Lt, makeApprovalsMethods as M, toEpochSeconds as Mi, commands as Mn, isEvmAddress as Mr, BASE_SEPOLIA_CHAIN_ID as Mt, makePayrollMethods as N, toAuthUserId as Ni, configurations as Nn, toAddress as Nr, MULTI_SEND_CALL_ONLY as Nt, retryIdempotentRead as O, parseAuthSession as Oi, OPERATIONS as On, toAssetId as Or, normalizeSafeSaltEmail as Ot, makeUnavailablePayrollMethods as P, toEmail as Pi, replacements as Pn, toChainId as Pr, SAFE_SENTINEL_OWNERS as Pt, formatAssetAmount as Q, InvitationViewSchema as Qn, CAPXUL_ERROR_CODES as Qr, version as Qt, annotateDepositInstructions as R, CapxulError as Ri, PayrollGroupInputSchema as Rn, makeAuthMethods as Rr, failureDetail as Rt, valueIn as S, AuthClientError as Si, CLI_INVOCATION_KINDS as Sn, toBudgetId as Sr, SEND_BATCH_SIGNATURE as St, TelemetryPortTag as T, globalLocalStorage as Ti, CAPXUL_OPERATIONS as Tn, toRoleKey as Tr, CONFIGURED_MONEY_ASSETS as Tt, makeActorRelationshipMethods as U, readField as Ui, setups as Un, sessionFromActor as Ur, observeSdkClient as Ut, waitForPaymentSubmission as V, isFailureMode as Vi, members as Vn, runIdentityFacade as Vr, postHogFailureObservation as Vt, makeCheckoutMethods as W, AuthCacheError as Wi, treasuries as Wn, observationOnlyControls as Wr, observationContextProps as Wt, assetAmountFromRaw as X, decodeChainCause as Xn, toCapxulResult as Xr, projectSdkException as Xt, abandonPrepared as Y, CHAIN_UPSTREAMS as Yn, runIfActive as Yr, normalizeExceptionOperation as Yt, assetSymbolFor as Z, toOrgId as Zn, formatTraceparent as Zr, safeExceptionLabel as Zt, accountFromAccountPositions as _, isCredentialField as _i, validateHandle as _n, toLowerHex as _r, ROLES_SET_ALLOWANCE_ABI as _t, paymentPhase as a, ClockError as ai, openfortSignerNotReadyCode as an, roleKeyForPermission as ar, fingerprintPaymentIntent as at, MONEY_READ_RATES as b, toPublishableKey as bi, CLI_CAPABILITIES as bn, DurationMsSchema$1 as br, ROLE_MANAGEMENT_SIGNATURES as bt, makePaymentDocumentsMethods as c, BetterAuthNodeLayer as ci, resolveFailureMode as cn, images as cr, resolveOrgPermissionIdentity as ct, SmartAccountPortTag as d, attachInvocationObservation as di, toCountryCode as dn, toAccountId as dr, MULTI_SEND_SELECTOR as dt, ActorFailure as ei, UNOBSERVABLE_SIGNER_STATUS as en, decodePermissionIntent as er, requireAsset as et, smartAccountErrorFromCapxul as f, copyInvocationObservation as fi, toKycTier as fn, PaymentDocumentOptionsSchema as fr, OPERATOR as ft, ConvexAccountLayer as g, redactUrlSecrets as gi, toPartyId as gn, toLowerBytes32 as gr, ROLES_EXEC_TRANSACTION_WITH_ROLE_ABI as gt, makeAccountsMethods as h, redactSecrets as hi, toHandle as hn, toLowerAddress as hr, ROLES_ASSIGN_ROLES_ABI as ht, inboxPhase as i, SystemClockLayer as ii, isSignerNotReadySignal as in, ORG_BUDGET_ACTIONS as ir, canonicalJson as it, wireChainId as j, toEpochMs as ji, authorities as jn, EVM_ADDRESS_RE$1 as jr, buildSafeMultiSendExecTransactionCall as jt, bindProductTelemetryInvocation as k, parseCachedJwt as ki, details as kn, toCurrencyCode as kr, safe4337ExecuteUserOpCallData as kt, makeSmartAccountMethods as l, BetterAuthBrowserLayer as li, makeCurrentUserMethods as ln, bankDetails as lr, CREATE_COMMITMENT_SIGNATURE as lt, PonderIndexerAdapter as m, sanitizeObservationContext as mi, HANDLE_RE as mn, toExactHex as mr, PARAMETER_TYPE as mt, bootIdentityFlow as n, withInvocationParentSpan as ni, injectedWalletSigner as nn, CurrentPolicySchema as nr, isMoneyParseError as nt, requestPhase as o, ClockPortTag as oi, recoverRawDigestSigner as on, diagnostics as or, moneySafeOpDigest as ot, makeHoldingsMethods as p, readInvocationObservation as pi, toTesterKind as pn, isBytes32 as pr, OWNER_COMMITMENT_SIGNATURES as pt, makeVerificationMethods as q, ORGANIZATION_SETUP_REASONS as qn, awaitCapxulResult as qr, SDK_VERSION as qt, makeMeMethods as r, oauthBearerAuthClient as ri, isEcdsaSignatureHex as rn, MONTHLY_REFILL_PERIOD_SECONDS as rr, parseMoney as rt, makeActivityMethods as s, readClockNow as si, signerFailure as sn, AppIdSchema$1 as sr, ZODIAC_MODULE_PROXY_FACTORY as st, executeIdentityProductObservation as t, carryInvocationParentSpan as ti, causeChain as tn, keepRefillOnChange as tr, toRaw as tt, ConvexSmartAccountLayer as u, observationRequestHeaders as ui, makeClientRequestMethods as un, deposits as ur, MODULE_PROXY_FACTORY_ABI as ut, accountPositionsFromWire as v, toAllowedOrigin as vi, redactTelemetryEvent as vn, PAYMENT_DIRECTIONS as vr, ROLES_SET_TRANSACTION_UNWRAPPER_ABI as vt, accountReadErrorFromCapxul as w, detectAuthCacheAdapter as wi, stampTelemetryEnvelope as wn, toPermissionId as wr, CAPXUL_PAYMENTS_V2_ADDRESS as wt, valueActivitySummary as x, authClientPortFromPromiseAdapter as xi, CLI_COMMAND_NAMES as xn, EpochMsSchema$1 as xr, SAFE_ENABLE_MODULE_ABI as xt, positionPeg as y, toAppId as yi, redactTelemetryProps as yn, PAYMENT_STATUSES as yr, ROLES_SET_UP_ABI as yt, makeOrganizationPaymentsMethods as z, isCapxulError as zi, FixedOfferDraftSchema as zn, askIdentity as zr, failureEvidenceProps as zt };
25089
+ export { parseAssetAmount as $, InvitationViewSchema as $n, CAPXUL_ERROR_CODES as $r, version as $t, registerProductTelemetryInvocation as A, parseCachedJwt as Ai, details as An, toCurrencyCode as Ar, buildSafeMultiSendExecTransactionCall as At, makePaymentsMethods as B, isCapxulError as Bi, FixedOfferDraftSchema as Bn, askIdentity as Br, failureEvidenceProps as Bt, AccountReadPortTag as C, AuthClientError as Ci, CLI_INVOCATION_KINDS as Cn, toBudgetId as Cr, SEND_SIGNATURE as Ct, convexCallErrorFromCapxul as D, InMemoryAuthCacheAdapter as Di, isCapxulOperation as Dn, ChainIdSchema$1 as Dr, normalizeSafeSaltEmail as Dt, ConvexCallPortTag as E, globalLocalStorage as Ei, CAPXUL_OPERATIONS as En, toRoleKey as Er, deriveCapxulSafeAddress as Et, decodePayrollRunInput as F, toEmail as Fi, replacements as Fn, toChainId as Fr, CONFIGURED_MONEY_ASSETS as Ft, isCheckoutSettlementConsumed as G, AuthCacheError as Gi, treasuries as Gn, observationOnlyControls as Gr, observationContextProps as Gt, makeDestinationsMethods as H, isFailureMode as Hi, members as Hn, runIdentityFacade as Hr, postHogFailureObservation as Ht, toPayrollGroupId as I, toJwtToken as Ii, PreparedPermissionExecutionSchema as In, toWeiAmount as Ir, TOKENS as It, subscribeFreshQuery as J, ORGANIZATION_SETUP_REASONS as Jn, awaitCapxulResult as Jr, SDK_VERSION as Jt, makeTargetsMethods as K, AuthCachePortTag as Ki, workspaces as Kn, runCapxulEffect as Kr, withCapturedAttemptContext as Kt, makeAccountMethods as L, toSessionToken as Li, PermissionCommandViewSchema as Ln, absurd as Lr, asCapxulError as Lt, makeApprovalsMethods as M, toEpochMs as Mi, authorities as Mn, EVM_ADDRESS_RE$1 as Mr, MULTI_SEND_CALL_ONLY as Mt, makePayrollMethods as N, toEpochSeconds as Ni, commands as Nn, isEvmAddress as Nr, SAFE_SENTINEL_OWNERS as Nt, retryIdempotentRead as O, BrowserAuthCacheAdapter as Oi, normalizeCapxulOperation as On, currencySymbolFor as Or, safe4337ExecuteUserOpCallData as Ot, makeUnavailablePayrollMethods as P, toAuthUserId as Pi, configurations as Pn, toAddress as Pr, callOperation as Pt, formatAssetAmount as Q, toOrgId as Qn, formatTraceparent as Qr, safeExceptionLabel as Qt, annotateDepositInstructions as R, Errors as Ri, PayrollGroupIdSchema as Rn, reference as Rr, toPublicError$1 as Rt, valueIn as S, authClientPortFromPromiseAdapter as Si, CLI_COMMAND_NAMES as Sn, EpochMsSchema$1 as Sr, SEND_BATCH_SIGNATURE as St, TelemetryPortTag as T, detectAuthCacheAdapter as Ti, stampTelemetryEnvelope as Tn, toPermissionId as Tr, matchesMoneyExecutionId as Tt, makeActorRelationshipMethods as U, isRecord as Ui, roles as Un, runPortEffect as Ur, observeFailedResult as Ut, waitForPaymentSubmission as V, FAILURE_MODES$1 as Vi, invitations as Vn, publicIdentityFailure as Vr, CAPXUL_SDK_EXPECTED_OUTCOME_EVENT as Vt, makeCheckoutMethods as W, readField as Wi, setups as Wn, sessionFromActor as Wr, observeSdkClient as Wt, assetAmountFromRaw as X, CHAIN_UPSTREAMS as Xn, runIfActive as Xr, normalizeExceptionOperation as Xt, abandonPrepared as Y, ORGANIZATION_SETUP_STATUSES as Yn, defectAsCapxulError as Yr, normalizeExceptionErrorKind as Yt, assetSymbolFor as Z, decodeChainCause as Zn, toCapxulResult as Zr, projectSdkException as Zt, accountFromAccountPositions as _, redactUrlSecrets as _i, toPartyId as _n, toLowerBytes32 as _r, ROLES_SET_ALLOWANCE_ABI as _t, paymentPhase as a, SystemClockLayer as ai, isSignerNotReadySignal as an, ORG_BUDGET_ACTIONS as ar, fingerprintPaymentIntent as at, MONEY_READ_RATES as b, toAppId as bi, redactTelemetryProps as bn, PAYMENT_STATUSES as br, ROLE_MANAGEMENT_SIGNATURES as bt, makePaymentDocumentsMethods as c, readClockNow as ci, signerFailure as cn, AppIdSchema$1 as cr, resolveOrgPermissionIdentity as ct, SmartAccountPortTag as d, observationRequestHeaders as di, makeClientRequestMethods as dn, deposits as dr, MULTI_SEND_SELECTOR as dt, EXPECTED_OPERATION_OUTCOMES as ei, isSettingUpLifecycle as en, hashPermissionReplacementPreview as er, requireAsset as et, smartAccountErrorFromCapxul as f, attachInvocationObservation as fi, toCountryCode as fn, toAccountId as fr, OPERATOR as ft, ConvexAccountLayer as g, redactSecrets as gi, toHandle as gn, toLowerAddress as gr, ROLES_EXEC_TRANSACTION_WITH_ROLE_ABI as gt, makeAccountsMethods as h, sanitizeObservationContext as hi, HANDLE_RE as hn, toExactHex as hr, ROLES_ASSIGN_ROLES_ABI as ht, inboxPhase as i, oauthBearerAuthClient as ii, isEcdsaSignatureHex as in, MONTHLY_REFILL_PERIOD_SECONDS as ir, canonicalJson as it, wireChainId as j, toDurationMs as ji, onboardings as jn, toExactAssetAmount as jr, BASE_SEPOLIA_CHAIN_ID as jt, bindProductTelemetryInvocation as k, parseAuthSession as ki, OPERATIONS as kn, toAssetId as kr, safe4337MultiSendUserOpCallData as kt, makeSmartAccountMethods as l, BetterAuthNodeLayer as li, resolveFailureMode as ln, images as lr, CREATE_COMMITMENT_SIGNATURE as lt, PonderIndexerAdapter as m, readInvocationObservation as mi, toTesterKind as mn, isBytes32 as mr, PARAMETER_TYPE as mt, bootIdentityFlow as n, carryInvocationParentSpan as ni, causeChain as nn, keepRefillOnChange as nr, isMoneyParseError as nt, requestPhase as o, ClockError as oi, openfortSignerNotReadyCode as on, roleKeyForPermission as or, moneySafeOpDigest as ot, makeHoldingsMethods as p, copyInvocationObservation as pi, toKycTier as pn, PaymentDocumentOptionsSchema as pr, OWNER_COMMITMENT_SIGNATURES as pt, makeVerificationMethods as q, OrganizationSetupSchema as qn, withVerifiedOrganizationScope as qr, EXCEPTION_MESSAGE as qt, makeMeMethods as r, withInvocationParentSpan as ri, injectedWalletSigner as rn, CurrentPolicySchema as rr, parseMoney as rt, makeActivityMethods as s, ClockPortTag as si, recoverRawDigestSigner as sn, diagnostics as sr, ZODIAC_MODULE_PROXY_FACTORY as st, executeIdentityProductObservation as t, ActorFailure as ti, UNOBSERVABLE_SIGNER_STATUS as tn, decodePermissionIntent as tr, toRaw as tt, ConvexSmartAccountLayer as u, BetterAuthBrowserLayer as ui, makeCurrentUserMethods as un, bankDetails as ur, MODULE_PROXY_FACTORY_ABI as ut, accountPositionsFromWire as v, isCredentialField as vi, validateHandle as vn, toLowerHex as vr, ROLES_SET_TRANSACTION_UNWRAPPER_ABI as vt, accountReadErrorFromCapxul as w, AuthClientPortTag as wi, EXCEPTION_EVENT_NAME as wn, toPermissionAssignmentId as wr, CAPXUL_PAYMENTS_V2_ADDRESS as wt, valueActivitySummary as x, toPublishableKey as xi, CLI_CAPABILITIES as xn, DurationMsSchema$1 as xr, SAFE_ENABLE_MODULE_ABI as xt, positionPeg as y, toAllowedOrigin as yi, redactTelemetryEvent as yn, PAYMENT_DIRECTIONS as yr, ROLES_SET_UP_ABI as yt, makeOrganizationPaymentsMethods as z, CapxulError as zi, PayrollGroupInputSchema as zn, makeAuthMethods as zr, failureDetail as zt };