@seams/wallet 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +3 -3
  2. package/dist/.build-inputs.sha256 +1 -1
  3. package/dist/esm/core/signingEngine/chains/evm/bytes.js +15 -1
  4. package/dist/esm/core/signingEngine/flows/signEvmFamily/signingFlow.js +1 -1
  5. package/dist/esm/core/signingEngine/flows/signNear/shared/ed25519YaoNormalSigning.js +84 -38
  6. package/dist/esm/core/signingEngine/flows/signNear/signTransactions.js +49 -2
  7. package/dist/esm/core/signingEngine/uiConfirm/ui/confirm-surface-resize.js +173 -2
  8. package/dist/esm/core/signingEngine/uiConfirm/ui/surface-resize-events.js +6 -1
  9. package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/abi/abiDecode.js +315 -0
  10. package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/abi/enrichDisplayModelWithAbi.js +77 -0
  11. package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/formatters.js +10 -1
  12. package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/renderers/fallback.js +52 -0
  13. package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/renderers/types.js +62 -0
  14. package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/tree.js +249 -0
  15. package/dist/esm/sdk/{host-B1CdRGoI.js → host-c1__wJwz.js} +1 -1
  16. package/dist/esm/sdk/{runtime-auth-tgfe70hU.js → runtime-auth-BKFyLISf.js} +1 -1
  17. package/dist/{public/sdk/runtime-device-link-BUxuQupR.js → esm/sdk/runtime-device-link-ENxdEXQW.js} +1 -1
  18. package/dist/{public/sdk/runtime-ecdsa-tempo-DOBk_EtI.js → esm/sdk/runtime-ecdsa-tempo-DhGEb9U7.js} +1 -1
  19. package/dist/esm/sdk/{runtime-email-otp-CsAJKvYC.js → runtime-email-otp-dgsP7XZi.js} +1 -1
  20. package/dist/esm/sdk/{runtime-export-7REbcnBl.js → runtime-export-D2RCm5Gk.js} +1 -1
  21. package/dist/esm/sdk/{runtime-near-BA0DQf6H.js → runtime-near-Bf-9MFBQ.js} +1 -1
  22. package/dist/esm/sdk/{runtime-preferences-cRViPE8a.js → runtime-preferences-LQ8SPE7o.js} +1 -1
  23. package/dist/esm/sdk/{runtime-recovery-RRc8Yz1y.js → runtime-recovery-BuEzJzuZ.js} +1 -1
  24. package/dist/esm/sdk/shared-8ffIBYw2.js +6 -0
  25. package/dist/esm/sdk/signNear-BhTkDm2-.js +1 -0
  26. package/dist/esm/sdk/wallet-iframe-host-ecdsa.js +1 -1
  27. package/dist/esm/sdk/wallet-iframe-host-full.js +1 -1
  28. package/dist/esm/sdk/wallet-iframe-host-near.js +1 -1
  29. package/dist/esm/sdk/wallet-iframe-host-runtime.js +1 -1
  30. package/dist/esm/utils/intentDigest.js +59 -1
  31. package/dist/public/headers.manifest.json +1 -1
  32. package/dist/public/sdk/{host-B1CdRGoI.js → host-c1__wJwz.js} +1 -1
  33. package/dist/public/sdk/{runtime-auth-tgfe70hU.js → runtime-auth-BKFyLISf.js} +1 -1
  34. package/dist/{esm/sdk/runtime-device-link-BUxuQupR.js → public/sdk/runtime-device-link-ENxdEXQW.js} +1 -1
  35. package/dist/{esm/sdk/runtime-ecdsa-tempo-DOBk_EtI.js → public/sdk/runtime-ecdsa-tempo-DhGEb9U7.js} +1 -1
  36. package/dist/public/sdk/{runtime-email-otp-CsAJKvYC.js → runtime-email-otp-dgsP7XZi.js} +1 -1
  37. package/dist/public/sdk/{runtime-export-7REbcnBl.js → runtime-export-D2RCm5Gk.js} +1 -1
  38. package/dist/public/sdk/{runtime-near-BA0DQf6H.js → runtime-near-Bf-9MFBQ.js} +1 -1
  39. package/dist/public/sdk/{runtime-preferences-cRViPE8a.js → runtime-preferences-LQ8SPE7o.js} +1 -1
  40. package/dist/public/sdk/{runtime-recovery-RRc8Yz1y.js → runtime-recovery-BuEzJzuZ.js} +1 -1
  41. package/dist/public/sdk/shared-8ffIBYw2.js +6 -0
  42. package/dist/public/sdk/signNear-BhTkDm2-.js +1 -0
  43. package/dist/public/sdk/wallet-iframe-host-ecdsa.js +1 -1
  44. package/dist/public/sdk/wallet-iframe-host-full.js +1 -1
  45. package/dist/public/sdk/wallet-iframe-host-near.js +1 -1
  46. package/dist/public/sdk/wallet-iframe-host-runtime.js +1 -1
  47. package/dist/public/wallet-assets.manifest.json +26 -26
  48. package/dist/public/wallet-service/index.html +4 -4
  49. package/dist/types/wallet/src/core/signingEngine/flows/signNear/shared/ed25519YaoNormalSigning.d.ts +16 -4
  50. package/dist/types/wallet/src/core/signingEngine/flows/signNear/shared/signatureOnlySigning.d.ts +3 -3
  51. package/dist/types/wallet/src/core/signingEngine/nonce/nearTransactionReadiness.d.ts +3 -0
  52. package/dist/types/wallet/src/core/signingEngine/stepUpConfirmation/confirmOperation.d.ts +3 -1
  53. package/dist/types/wallet/src/core/signingEngine/uiConfirm/handlers/flows/signing.d.ts +2 -0
  54. package/dist/types/wallet/src/core/signingEngine/uiConfirm/handlers/handlePromptFromWorker.d.ts +2 -0
  55. package/dist/types/wallet/src/core/signingEngine/uiConfirm/uiConfirm.types.d.ts +3 -0
  56. package/package.json +1 -1
  57. package/dist/esm/sdk/shared-DdfxBUGY.js +0 -6
  58. package/dist/esm/sdk/signNear-CO5bx24Z.js +0 -1
  59. package/dist/public/sdk/shared-DdfxBUGY.js +0 -6
  60. package/dist/public/sdk/signNear-CO5bx24Z.js +0 -1
package/README.md CHANGED
@@ -1,18 +1,18 @@
1
1
  # Seams Wallet SDK
2
2
 
3
- `@seams/wallet` **0.9.0** provides browser wallet lifecycle, NEAR and EVM-family
3
+ `@seams/wallet` **0.9.2** provides browser wallet lifecycle, NEAR and EVM-family
4
4
  threshold signing, React components, and hosted wallet runtime assets.
5
5
 
6
6
  ## Install
7
7
 
8
8
  ```sh
9
- pnpm add @seams/wallet@0.9.0
9
+ pnpm add @seams/wallet@0.9.2
10
10
  ```
11
11
 
12
12
  React integrations support React 18 and 19. Import the provider and UI from
13
13
  `@seams/wallet/react` and its stylesheet from `@seams/wallet/react/styles`.
14
14
  Keep the application package, wallet-origin assets, and
15
- `@seams/wallet-server@0.9.0` on the matching release.
15
+ `@seams/wallet-server@0.9.2` on the matching release.
16
16
 
17
17
  ## Next release migration (unreleased)
18
18
 
@@ -1 +1 @@
1
- b17394151f88cd47fcc785945c545b600a58769c4ccb3ce56aa76fc6fcd46cef
1
+ 392dfb0f192f2256956e72a6ec24a6d93a8c39e38b83581ad6c62f1dd73df7a5
@@ -1,8 +1,22 @@
1
1
  //#region src/core/signingEngine/chains/evm/bytes.ts
2
+ function hexToBytes(hex) {
3
+ const raw = String(hex || "");
4
+ const normalized = raw.startsWith("0x") ? raw.slice(2) : raw;
5
+ if (normalized.length === 0) return new Uint8Array();
6
+ if (normalized.length % 2 !== 0) throw new Error(`Invalid hex (odd length): ${hex}`);
7
+ const bytes = new Uint8Array(normalized.length / 2);
8
+ for (let i = 0; i < bytes.length; i++) {
9
+ const byte = normalized.slice(i * 2, i * 2 + 2);
10
+ const value = Number.parseInt(byte, 16);
11
+ if (!Number.isFinite(value)) throw new Error(`Invalid hex: ${hex}`);
12
+ bytes[i] = value;
13
+ }
14
+ return bytes;
15
+ }
2
16
  function bytesToHex(bytes) {
3
17
  return `0x${Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")}`;
4
18
  }
5
19
  //#endregion
6
- export { bytesToHex };
20
+ export { bytesToHex, hexToBytes };
7
21
 
8
22
  //# sourceMappingURL=bytes.js.map
@@ -4,9 +4,9 @@ import { parseDigestB64u, sha256Utf8DigestB64u } from "../../../../shared-ts/src
4
4
  import { SigningEventPhase, createSigningFlowEvent } from "../../../types/sdkSentEvents.js";
5
5
  import { SigningSessionIds } from "../../session/operationState/types.js";
6
6
  import { normalizeAuthenticationCredential } from "../../webauthnAuth/credentials/helpers.js";
7
+ import { bytesToHex } from "../../chains/evm/bytes.js";
7
8
  import { isActiveWalletAuthoritySigningAuthPlan, isWarmSessionSigningAuthPlan } from "../../stepUpConfirmation/types.js";
8
9
  import { toManagedNonceReservationSnapshot } from "../../../rpcClients/evm/nonceBackend.js";
9
- import { bytesToHex } from "../../chains/evm/bytes.js";
10
10
  import { emitEcdsaSigningTiming } from "../../session/operationState/trace.js";
11
11
  import { parseSigningOperationFingerprintDigest } from "../../../../shared-ts/src/authorization/operationFingerprint.js";
12
12
  import { SigningOperationCommandKind, buildSigningOperationCommandSteps, createSigningOperationPlan, runSigningOperationCommandSteps, runUnplannedSigningOperationCommandSequence } from "../shared/signingStateMachine.js";
@@ -725,6 +725,82 @@ function routerAbEd25519NormalSigningMaterialFacts(args) {
725
725
  relayerUrl: args.walletSessionState.relayerUrl
726
726
  };
727
727
  }
728
+ async function nearTransactionPrepareInputs(args, unsigned) {
729
+ const nearNetworkId = normalizeNearNetworkId(args.ctx);
730
+ const parsedTransaction = parseThresholdEd25519NearTransaction(args.txSigningRequest, "txSigningRequest");
731
+ return {
732
+ nearNetworkId,
733
+ parsedTransaction,
734
+ operationFingerprint: SigningSessionIds.signingOperationFingerprint(await thresholdEd25519NearTransactionOperationFingerprint({
735
+ nearAccountId: args.nearAccountId,
736
+ nearNetworkId,
737
+ relayerKeyId: args.thresholdKeyMaterial.relayerKeyId,
738
+ signerPublicKey: args.thresholdKeyMaterial.publicKey,
739
+ transactions: [parsedTransaction],
740
+ unsignedTransactionBorshB64u: unsigned.unsignedTransactionBorshB64u,
741
+ signingDigestB64u: unsigned.signingDigestB64u
742
+ }))
743
+ };
744
+ }
745
+ async function buildRouterAbEd25519NearTransactionWarmPrepare(args, unsigned, inputs) {
746
+ const scope = buildRouterAbNormalSigningScope({
747
+ activeClient: args.activeClient,
748
+ walletSessionState: args.walletSessionState,
749
+ walletId: args.walletId,
750
+ operationId: args.operationId
751
+ });
752
+ if (!scope) throw new Error("[SigningEngine][near] Router A/B Ed25519 signing scope is missing");
753
+ return await buildRouterAbEd25519NearTransactionPrepareRequestV2({
754
+ scope,
755
+ expiresAtMs: routerAbNormalSigningExpiresAtMs({
756
+ walletSessionExpiresAtMs: args.walletSessionState.signingWalletSession.expiresAtMs,
757
+ requestedTtlMs: ROUTER_AB_NORMAL_SIGNING_REQUEST_TTL_MS
758
+ }),
759
+ operationId: args.operationId,
760
+ operationFingerprint: inputs.operationFingerprint,
761
+ displayDigestB64u: args.displayDigest,
762
+ nearAccountId: args.nearAccountId,
763
+ nearNetworkId: inputs.nearNetworkId,
764
+ transactions: [{
765
+ receiverId: inputs.parsedTransaction.receiverId,
766
+ actionFingerprint: await routerAbNormalSigningActionFingerprint(inputs.parsedTransaction.actions)
767
+ }],
768
+ unsignedTransactionBorshB64u: unsigned.unsignedTransactionBorshB64u,
769
+ expectedSigningDigestB64u: unsigned.signingDigestB64u
770
+ });
771
+ }
772
+ /**
773
+ * Sends the prepare of a warm-session transaction while the confirmation
774
+ * dialog is open. The transaction context is the one the dialog reserved.
775
+ */
776
+ async function startRouterAbEd25519NearTransactionPrepare(args) {
777
+ const unsigned = await buildThresholdEd25519NearTxUnsignedBorshWasm({
778
+ txSigningRequest: args.txSigningRequest,
779
+ transactionContext: args.transactionContext,
780
+ workerCtx: args.ctx
781
+ });
782
+ const prepare = await buildRouterAbEd25519NearTransactionWarmPrepare(args, unsigned, await nearTransactionPrepareInputs(args, unsigned));
783
+ const ready = requireRouterAbEd25519NormalSigningReadyState({
784
+ state: args.walletSessionState,
785
+ thresholdSessionId: args.thresholdSessionId,
786
+ nearAccountId: args.nearAccountId,
787
+ thresholdKeyMaterial: args.thresholdKeyMaterial
788
+ });
789
+ const sentAt = performance.now();
790
+ const response = prepareRouterAbNormalSigningV2({
791
+ relayServerUrl: args.walletSessionState.relayerUrl,
792
+ credential: ready.credential,
793
+ request: prepare.request
794
+ });
795
+ response.catch(() => {});
796
+ emitEd25519SigningTiming(String(args.operationId), "prepare_sent", sentAt);
797
+ return {
798
+ prepare,
799
+ displayDigest: args.displayDigest,
800
+ signingDigestB64u: unsigned.signingDigestB64u,
801
+ response
802
+ };
803
+ }
728
804
  async function tryFinalizeRouterAbEd25519NearTransactionNormalSigning(args) {
729
805
  const materialFacts = routerAbEd25519NormalSigningMaterialFacts(args);
730
806
  if (!materialFacts.routerAbNormalSigning) throw new Error("[SigningEngine][near] Router A/B Ed25519 normal-signing state is missing");
@@ -739,17 +815,8 @@ async function tryFinalizeRouterAbEd25519NearTransactionNormalSigning(args) {
739
815
  workerCtx: args.ctx
740
816
  });
741
817
  if (base64UrlDecode(unsigned.signingDigestB64u).length !== 32) throw new Error("Router A/B normal-signing NEAR payload digest must be 32 bytes");
742
- const nearNetworkId = normalizeNearNetworkId(args.ctx);
743
- const parsedTransaction = parseThresholdEd25519NearTransaction(args.txSigningRequest, "txSigningRequest");
744
- const operationFingerprint = SigningSessionIds.signingOperationFingerprint(await thresholdEd25519NearTransactionOperationFingerprint({
745
- nearAccountId: args.nearAccountId,
746
- nearNetworkId,
747
- relayerKeyId: args.thresholdKeyMaterial.relayerKeyId,
748
- signerPublicKey: args.thresholdKeyMaterial.publicKey,
749
- transactions: [parsedTransaction],
750
- unsignedTransactionBorshB64u: unsigned.unsignedTransactionBorshB64u,
751
- signingDigestB64u: unsigned.signingDigestB64u
752
- }));
818
+ const prepareInputs = await nearTransactionPrepareInputs(args, unsigned);
819
+ let started = null;
753
820
  let prepare;
754
821
  let credential;
755
822
  let issuedAuthorization;
@@ -772,31 +839,9 @@ async function tryFinalizeRouterAbEd25519NearTransactionNormalSigning(args) {
772
839
  if (prepare.request.scope.authorization.kind !== "operation_step_up" || issued.kind !== "verified_step_up") throw new Error("[SigningEngine][near] issued operation step-up evidence changed identity");
773
840
  issuedAuthorization = issued;
774
841
  } else {
775
- const scope = buildRouterAbNormalSigningScope({
776
- activeClient: args.activeClient,
777
- walletSessionState: args.walletSessionState,
778
- walletId: args.walletId,
779
- operationId: args.operationId
780
- });
781
- if (!scope) throw new Error("[SigningEngine][near] Router A/B Ed25519 signing scope is missing");
782
- prepare = await buildRouterAbEd25519NearTransactionPrepareRequestV2({
783
- scope,
784
- expiresAtMs: routerAbNormalSigningExpiresAtMs({
785
- walletSessionExpiresAtMs: args.walletSessionState.signingWalletSession.expiresAtMs,
786
- requestedTtlMs: ROUTER_AB_NORMAL_SIGNING_REQUEST_TTL_MS
787
- }),
788
- operationId: args.operationId,
789
- operationFingerprint,
790
- displayDigestB64u: args.displayDigest,
791
- nearAccountId: args.nearAccountId,
792
- nearNetworkId,
793
- transactions: [{
794
- receiverId: parsedTransaction.receiverId,
795
- actionFingerprint: await routerAbNormalSigningActionFingerprint(parsedTransaction.actions)
796
- }],
797
- unsignedTransactionBorshB64u: unsigned.unsignedTransactionBorshB64u,
798
- expectedSigningDigestB64u: unsigned.signingDigestB64u
799
- });
842
+ started = args.startedPrepare && args.startedPrepare.displayDigest === args.displayDigest && args.startedPrepare.signingDigestB64u === unsigned.signingDigestB64u ? args.startedPrepare : null;
843
+ if (args.startedPrepare && !started) abandonRouterAbEd25519StartedPrepare(args.startedPrepare);
844
+ prepare = started ? started.prepare : await buildRouterAbEd25519NearTransactionWarmPrepare(args, unsigned, prepareInputs);
800
845
  credential = requireRouterAbEd25519NormalSigningReadyState({
801
846
  state: args.walletSessionState,
802
847
  thresholdSessionId: args.thresholdSessionId,
@@ -829,7 +874,8 @@ async function tryFinalizeRouterAbEd25519NearTransactionNormalSigning(args) {
829
874
  signingPayloadLabel: "NEAR payload digest",
830
875
  prepare,
831
876
  credential,
832
- authorization: "reusable_wallet_session"
877
+ authorization: "reusable_wallet_session",
878
+ startedResponse: started?.response
833
879
  });
834
880
  const finalized = await finalizeThresholdEd25519NearTxFromSignatureWasm({
835
881
  unsignedTransactionBorshB64u: unsigned.unsignedTransactionBorshB64u,
@@ -871,6 +917,6 @@ async function tryFinalizeRouterAbEd25519NearTransactionNormalSigning(args) {
871
917
  };
872
918
  }
873
919
  //#endregion
874
- export { abandonRouterAbEd25519StartedPrepare, buildNearEd25519OperationStepUpProof, buildNearEmailOtpEd25519OperationStepUpProof, finalizeThresholdEd25519DelegateSignatureResult, prepareRouterAbEd25519NearTransactionOperationStepUp, prepareRouterAbEd25519SignatureOnlyOperationStepUp, requireIssuedNearEd25519OperationStepUpAuthorization, requireNearEd25519OperationStepUpProof, startRouterAbEd25519SignatureOnlyPrepare, tryFinalizeRouterAbEd25519NearTransactionNormalSigning, tryFinalizeRouterAbEd25519SignatureOnlyNormalSigning };
920
+ export { abandonRouterAbEd25519StartedPrepare, buildNearEd25519OperationStepUpProof, buildNearEmailOtpEd25519OperationStepUpProof, finalizeThresholdEd25519DelegateSignatureResult, prepareRouterAbEd25519NearTransactionOperationStepUp, prepareRouterAbEd25519SignatureOnlyOperationStepUp, requireIssuedNearEd25519OperationStepUpAuthorization, requireNearEd25519OperationStepUpProof, startRouterAbEd25519NearTransactionPrepare, startRouterAbEd25519SignatureOnlyPrepare, tryFinalizeRouterAbEd25519NearTransactionNormalSigning, tryFinalizeRouterAbEd25519SignatureOnlyNormalSigning };
875
921
 
876
922
  //# sourceMappingURL=ed25519YaoNormalSigning.js.map
@@ -6,6 +6,7 @@ import { toAccountId } from "../../../types/accountIds.js";
6
6
  import { SigningEventPhase, createSigningFlowEvent } from "../../../types/sdkSentEvents.js";
7
7
  import { SigningOperationIntent, SigningSessionIds, SigningSessionPlanKind } from "../../session/operationState/types.js";
8
8
  import { nearEd25519SignerBindingFromBoundaryFields } from "../../session/identity/exactSigningLaneIdentity.js";
9
+ import { computeUiIntentDigestFromTxs, orderActionForDigest } from "../../../../utils/intentDigest.js";
9
10
  import { isWarmSessionSigningAuthPlan } from "../../stepUpConfirmation/types.js";
10
11
  import { createSigningBoundaryTraceEvent, emitEd25519SigningTiming, emitSigningBoundaryTrace } from "../../session/operationState/trace.js";
11
12
  import { parseSigningOperationFingerprintDigest } from "../../../../shared-ts/src/authorization/operationFingerprint.js";
@@ -20,7 +21,7 @@ import { emitNearSigningConfirmationProgress } from "./shared/confirmationProgre
20
21
  import { buildNearEd25519StepUpAuthorization } from "./stepUpAuthorization.js";
21
22
  import { requiredNearTransactionSignatureUses } from "./signatureUses.js";
22
23
  import { clearNearOperationStepUpBuilder, consumePreparedNearOperationStepUp, registerNearOperationStepUpBuilder } from "./shared/operationStepUpPreparation.js";
23
- import { buildNearEd25519OperationStepUpProof, buildNearEmailOtpEd25519OperationStepUpProof, prepareRouterAbEd25519NearTransactionOperationStepUp, requireIssuedNearEd25519OperationStepUpAuthorization, requireNearEd25519OperationStepUpProof, tryFinalizeRouterAbEd25519NearTransactionNormalSigning } from "./shared/ed25519YaoNormalSigning.js";
24
+ import { buildNearEd25519OperationStepUpProof, buildNearEmailOtpEd25519OperationStepUpProof, prepareRouterAbEd25519NearTransactionOperationStepUp, requireIssuedNearEd25519OperationStepUpAuthorization, requireNearEd25519OperationStepUpProof, startRouterAbEd25519NearTransactionPrepare, tryFinalizeRouterAbEd25519NearTransactionNormalSigning } from "./shared/ed25519YaoNormalSigning.js";
24
25
  import { fundNearImplicitAccountForOperationStepUp, resolveConfirmedNearTransactionContext } from "./implicitAccountFunding.js";
25
26
  import { clearNearImplicitAccountFunder, registerNearImplicitAccountFunder } from "./shared/implicitAccountFundingPort.js";
26
27
  import { nearOperationStepUpMaterialFacts, prepareNearOperationStepUpMaterial, resolveNearOperationStepUpMaterial, resolvePreparedNearEd25519YaoMaterial } from "./shared/ed25519YaoCapabilityResolution.js";
@@ -55,6 +56,34 @@ function requireWarmNearSigningMaterialTask(task) {
55
56
  if (!task) throw new Error("[SigningEngine][near] warm signing material was not prepared");
56
57
  return task;
57
58
  }
59
+ async function startWarmNearTransactionPrepare(args) {
60
+ const resolved = await args.warmMaterial;
61
+ const walletSessionState = await args.sessionCoordinator.resolveActiveAuthorizedRouterAbEd25519WalletSessionState({
62
+ state: resolved.walletSessionState,
63
+ nowMs: Date.now()
64
+ });
65
+ if (!walletSessionState) return null;
66
+ const displayDigest = await computeUiIntentDigestFromTxs([{
67
+ receiverId: args.confirmationTransaction.receiverId,
68
+ actions: args.confirmationTransaction.actions.map(orderActionForDigest)
69
+ }]);
70
+ return await startRouterAbEd25519NearTransactionPrepare({
71
+ ctx: args.ctx,
72
+ thresholdSessionId: resolved.material.facts.thresholdSessionId,
73
+ thresholdKeyMaterial: args.thresholdKeyMaterial,
74
+ walletId: args.walletId,
75
+ nearAccountId: args.nearAccountId,
76
+ activeClient: resolved.material.activeClient,
77
+ walletSessionState,
78
+ operationId: args.operationId,
79
+ displayDigest,
80
+ txSigningRequest: args.txSigningRequest,
81
+ transactionContext: args.readiness.transactionContext
82
+ });
83
+ }
84
+ function ignoreStartedPrepareFailure() {
85
+ return null;
86
+ }
58
87
  async function resolveNearTransactionOperationStepUpMaterial(args) {
59
88
  if (args.authorization.kind === "passkey") {
60
89
  if (args.material.kind !== "passkey_live" && args.material.kind !== "passkey_sealed") throw new Error("[SigningEngine][near] passkey transaction material changed factor");
@@ -553,6 +582,22 @@ async function runAuthorizedNearTransactionWithActionsSigning({ ctx, commandSubj
553
582
  }
554
583
  });
555
584
  emitEd25519SigningTiming(String(signingOperationId), "pre_confirmation", preConfirmationStartedAt);
585
+ let startedPrepareTask = null;
586
+ const startTransactionPrepare = (readiness) => {
587
+ if (startedPrepareTask || !warmSigningMaterialTask) return;
588
+ startedPrepareTask = startWarmNearTransactionPrepare({
589
+ ctx,
590
+ warmMaterial: warmSigningMaterialTask,
591
+ sessionCoordinator,
592
+ thresholdKeyMaterial: signingContext.threshold.thresholdKeyMaterial,
593
+ walletId: commandSubject.walletSession.walletId,
594
+ nearAccountId,
595
+ operationId: signingOperation.operationId,
596
+ txSigningRequest,
597
+ confirmationTransaction,
598
+ readiness
599
+ }).catch(ignoreStartedPrepareFailure);
600
+ };
556
601
  const confirmationStartedAt = performance.now();
557
602
  let confirmation;
558
603
  try {
@@ -567,6 +612,7 @@ async function runAuthorizedNearTransactionWithActionsSigning({ ctx, commandSubj
567
612
  chain: "near",
568
613
  kind: "transaction",
569
614
  ...buildSigningConfirmationAuthParams({ signingAuthPlan: confirmationAuthPayload.signingAuthPlan }),
615
+ ...warmSigningMaterialTask ? { onNearTransactionContextReady: startTransactionPrepare } : {},
570
616
  walletId: String(signingLane.identity.signer.account.wallet.walletId),
571
617
  txSigningRequests: [confirmationTransaction],
572
618
  rpcCall: resolvedRpcCall,
@@ -785,7 +831,8 @@ async function runAuthorizedNearTransactionWithActionsSigning({ ctx, commandSubj
785
831
  displayDigest: confirmation.intentDigest,
786
832
  txSigningRequest,
787
833
  transactionContext,
788
- authorization: { kind: "reusable_wallet_session" }
834
+ authorization: { kind: "reusable_wallet_session" },
835
+ startedPrepare: startedPrepareTask ? await startedPrepareTask : null
789
836
  });
790
837
  if (routerAbNormalSigningResult) return routerAbNormalSigningResult.okResponse;
791
838
  throw new Error("[SigningEngine][near] Router A/B Ed25519 signing is unavailable");
@@ -1,4 +1,4 @@
1
- import { dispatchSurfaceResizeBegin } from "./surface-resize-events.js";
1
+ import { addSurfaceResizeBeginListener, dispatchSurfaceResizeBegin } from "./surface-resize-events.js";
2
2
  //#region src/core/signingEngine/uiConfirm/ui/confirm-surface-resize.ts
3
3
  /**
4
4
  * Host-driven height changes for wallet-iframe confirmations.
@@ -25,6 +25,10 @@ import { dispatchSurfaceResizeBegin } from "./surface-resize-events.js";
25
25
  *
26
26
  * The module owns the rules for iframe-hosted confirmation reflow.
27
27
  */
28
+ const CONFIRM_SURFACE_MODE_ATTR = "data-seams-confirm-surface";
29
+ const CONFIRM_SURFACE_MODE_WALLET_IFRAME = "wallet-iframe";
30
+ /** Marks the confirmer host while its height is held at a motion's target. */
31
+ const CONFIRM_SURFACE_PINNED_CLASS = "seams-confirm-surface-pinned";
28
32
  /**
29
33
  * Marks the document root for the same span. It is a second class rather than
30
34
  * the one above because the host rule must match any element that hosts a
@@ -37,6 +41,24 @@ const CONFIRM_SURFACE_PINNED_ROOT_CLASS = "seams-confirm-surface-pinned-root";
37
41
  const CONFIRM_SURFACE_HEIGHT_DRIVEN_CLASS = "seams-surface-height-driven";
38
42
  /** The CSS variable the class above reads. Components own the write (CSP). */
39
43
  const CONFIRM_SURFACE_HEIGHT_DRIVEN_VAR = "--seams-surface-height-driven-target";
44
+ /** Frames the box may sit still, after it has moved, before its motion counts as over. */
45
+ const SETTLED_FRAMES_AFTER_MOTION = 8;
46
+ /** Frames to wait for the parent to react at all before giving up on it. */
47
+ const SETTLED_FRAMES_WITHOUT_MOTION = 20;
48
+ /**
49
+ * The parent writes the destination box and forces a layout BEFORE it starts
50
+ * its ease, and a cross-origin iframe can receive that destination size for one
51
+ * frame before the animation snaps it back to the origin. Landing on that
52
+ * frame finishes the interior instantly and leaves the box to ease on its
53
+ * own — the exact jank this module exists to remove. A box that jumps straight
54
+ * to the target therefore has to stay there this many frames before the
55
+ * content lands on it; a box that eased through intermediate sizes lands at
56
+ * once. The parent pins the iframe to the origin for that read
57
+ * (`overlay-styles.ts pinDialogIframe`), so this is the second of two guards.
58
+ */
59
+ const LANDING_CONFIRM_FRAMES = 3;
60
+ /** The parent rounds the measured size; allow that much slack when asking whether the box hugs the host. */
61
+ const HUG_TOLERANCE_CSS_PX = 1;
40
62
  /** A host that claims a motion and never lands it must not leave content clamped. */
41
63
  const ANNOUNCE_SAFETY_MS = 1500;
42
64
  /** Height changes below this are not worth a motion, and round to nothing. */
@@ -169,7 +191,156 @@ function announceClampedSurfaceResize(args) {
169
191
  if (!claimed) element.classList.remove(...addedClasses);
170
192
  return claimed;
171
193
  }
194
+ let diagnosticHost = null;
195
+ const surfaceMotionDiagnostics = {
196
+ blipFrames: 0,
197
+ trace(durationMs = 2e3) {
198
+ return new Promise((resolve) => {
199
+ const lines = [];
200
+ const startedAt = performance.now();
201
+ const tick = () => {
202
+ const host = diagnosticHost;
203
+ const pinned = host?.classList.contains(CONFIRM_SURFACE_PINNED_CLASS) ? "*" : "";
204
+ lines.push(`${Math.round(performance.now() - startedAt)}: box=${document.documentElement.clientHeight} content=${host ? Math.round(host.getBoundingClientRect().height) : "-"}${pinned}`);
205
+ if (performance.now() - startedAt < durationMs) requestAnimationFrame(tick);
206
+ else resolve(lines);
207
+ };
208
+ requestAnimationFrame(tick);
209
+ });
210
+ }
211
+ };
212
+ function publishDiagnostics(element) {
213
+ diagnosticHost = element;
214
+ try {
215
+ window.__seamsSurfaceMotion = surfaceMotionDiagnostics;
216
+ } catch {}
217
+ }
218
+ function defaultViewportHeightCssPx() {
219
+ const height = document.documentElement?.clientHeight ?? 0;
220
+ return height > 0 ? height : window.innerHeight;
221
+ }
222
+ function clamp(value, min, max) {
223
+ return Math.min(Math.max(value, min), max);
224
+ }
225
+ function isWalletIframeConfirmSurface(element) {
226
+ return element.getAttribute(CONFIRM_SURFACE_MODE_ATTR) === CONFIRM_SURFACE_MODE_WALLET_IFRAME;
227
+ }
228
+ function createHostHeightPin(element) {
229
+ if (typeof CSSStyleSheet !== "function" || !("adoptedStyleSheets" in document)) return null;
230
+ let sheet = null;
231
+ const release = () => {
232
+ element.classList.remove(CONFIRM_SURFACE_PINNED_CLASS);
233
+ document.documentElement.classList.remove(CONFIRM_SURFACE_PINNED_ROOT_CLASS);
234
+ };
235
+ return {
236
+ set(px) {
237
+ try {
238
+ if (!sheet) sheet = new CSSStyleSheet();
239
+ sheet.replaceSync(`.${CONFIRM_SURFACE_PINNED_CLASS}{height:${Math.max(0, Math.round(px))}px}.${CONFIRM_SURFACE_PINNED_ROOT_CLASS}{overflow:hidden}`);
240
+ if (!document.adoptedStyleSheets.includes(sheet)) document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
241
+ } catch {
242
+ return false;
243
+ }
244
+ element.classList.add(CONFIRM_SURFACE_PINNED_CLASS);
245
+ document.documentElement.classList.add(CONFIRM_SURFACE_PINNED_ROOT_CLASS);
246
+ return true;
247
+ },
248
+ release,
249
+ dispose() {
250
+ release();
251
+ if (!sheet) return;
252
+ const retired = sheet;
253
+ sheet = null;
254
+ try {
255
+ document.adoptedStyleSheets = document.adoptedStyleSheets.filter((s) => s !== retired);
256
+ } catch {}
257
+ }
258
+ };
259
+ }
260
+ function attachConfirmSurfaceResizeChoreographer(element, options = {}) {
261
+ const readViewportHeightCssPx = options.viewportHeightCssPx ?? defaultViewportHeightCssPx;
262
+ const pin = createHostHeightPin(element);
263
+ publishDiagnostics(element);
264
+ let active = null;
265
+ const settle = () => {
266
+ const current = active;
267
+ if (!current) return;
268
+ active = null;
269
+ if (current.frame !== null) cancelAnimationFrame(current.frame);
270
+ current.driver.setProgress(1);
271
+ current.driver.finish();
272
+ pin?.release();
273
+ };
274
+ const step = () => {
275
+ const current = active;
276
+ if (!current) return;
277
+ current.frame = null;
278
+ const viewportPx = readViewportHeightCssPx();
279
+ if (viewportPx !== current.lastViewportPx) {
280
+ current.lastViewportPx = viewportPx;
281
+ current.framesSinceChange = 0;
282
+ current.moved = true;
283
+ } else current.framesSinceChange += 1;
284
+ const progress = clamp((viewportPx - current.originHostPx) / current.deltaCssPx, 0, 1);
285
+ if (progress >= 1) {
286
+ current.framesAtTarget += 1;
287
+ if (current.sawIntermediate || current.framesAtTarget >= LANDING_CONFIRM_FRAMES) {
288
+ settle();
289
+ return;
290
+ }
291
+ current.frame = requestAnimationFrame(step);
292
+ return;
293
+ }
294
+ if (current.framesAtTarget > 0) surfaceMotionDiagnostics.blipFrames += 1;
295
+ current.framesAtTarget = 0;
296
+ if (progress > 0) current.sawIntermediate = true;
297
+ current.driver.setProgress(progress);
298
+ const settledFrames = current.moved ? SETTLED_FRAMES_AFTER_MOTION : SETTLED_FRAMES_WITHOUT_MOTION;
299
+ if (current.framesSinceChange >= settledFrames) {
300
+ settle();
301
+ return;
302
+ }
303
+ current.frame = requestAnimationFrame(step);
304
+ };
305
+ const onSurfaceResizeBegin = (event) => {
306
+ const detail = event.detail;
307
+ if (!pin || !detail || !isWalletIframeConfirmSurface(element)) return;
308
+ const deltaCssPx = detail.deltaCssPx;
309
+ if (!Number.isFinite(deltaCssPx) || Math.abs(deltaCssPx) < MIN_ANNOUNCED_DELTA_CSS_PX) return;
310
+ settle();
311
+ const viewportPx = readViewportHeightCssPx();
312
+ const hostPx = element.getBoundingClientRect().height;
313
+ if (!(viewportPx > 0) || !(hostPx > 0) || Math.abs(viewportPx - hostPx) > HUG_TOLERANCE_CSS_PX) return;
314
+ const originHostPx = Math.round(hostPx);
315
+ const targetHostPx = originHostPx + deltaCssPx;
316
+ if (!(targetHostPx > 0)) return;
317
+ if (!pin.set(targetHostPx)) return;
318
+ const driver = detail.claim();
319
+ if (!driver) {
320
+ pin.release();
321
+ return;
322
+ }
323
+ active = {
324
+ driver,
325
+ originHostPx,
326
+ deltaCssPx,
327
+ lastViewportPx: viewportPx,
328
+ framesSinceChange: 0,
329
+ moved: false,
330
+ sawIntermediate: false,
331
+ framesAtTarget: 0,
332
+ frame: null
333
+ };
334
+ active.frame = requestAnimationFrame(step);
335
+ };
336
+ const removeListener = addSurfaceResizeBeginListener(element, onSurfaceResizeBegin);
337
+ return { dispose() {
338
+ removeListener();
339
+ settle();
340
+ pin?.dispose();
341
+ } };
342
+ }
172
343
  //#endregion
173
- export { CONFIRM_SURFACE_HEIGHT_DRIVEN_VAR, announceClampedSurfaceResize, createSurfaceHeightReflow };
344
+ export { CONFIRM_SURFACE_HEIGHT_DRIVEN_VAR, CONFIRM_SURFACE_MODE_ATTR, announceClampedSurfaceResize, announceSurfaceResize, attachConfirmSurfaceResizeChoreographer, createSurfaceHeightReflow };
174
345
 
175
346
  //# sourceMappingURL=confirm-surface-resize.js.map
@@ -7,7 +7,12 @@ function dispatchSurfaceResizeBegin(target, detail) {
7
7
  detail
8
8
  }));
9
9
  }
10
+ function addSurfaceResizeBeginListener(target, listener, options) {
11
+ const handler = listener;
12
+ target.addEventListener(SURFACE_RESIZE_BEGIN_EVENT, handler, options);
13
+ return () => target.removeEventListener(SURFACE_RESIZE_BEGIN_EVENT, handler, options);
14
+ }
10
15
  //#endregion
11
- export { dispatchSurfaceResizeBegin };
16
+ export { addSurfaceResizeBeginListener, dispatchSurfaceResizeBegin };
12
17
 
13
18
  //# sourceMappingURL=surface-resize-events.js.map