@seams/wallet 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/.build-inputs.sha256 +1 -1
- package/dist/esm/core/signingEngine/chains/evm/bytes.js +15 -1
- package/dist/esm/core/signingEngine/flows/signEvmFamily/signingFlow.js +1 -1
- package/dist/esm/core/signingEngine/flows/signNear/shared/ed25519YaoNormalSigning.js +84 -38
- package/dist/esm/core/signingEngine/flows/signNear/signTransactions.js +49 -2
- package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/abi/abiDecode.js +315 -0
- package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/abi/enrichDisplayModelWithAbi.js +77 -0
- package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/formatters.js +10 -1
- package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/renderers/fallback.js +52 -0
- package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/renderers/types.js +62 -0
- package/dist/esm/core/signingEngine/uiConfirm/ui/transaction-display/tree.js +249 -0
- package/dist/esm/sdk/{host-B1CdRGoI.js → host-c1__wJwz.js} +1 -1
- package/dist/esm/sdk/{runtime-auth-tgfe70hU.js → runtime-auth-BKFyLISf.js} +1 -1
- package/dist/{public/sdk/runtime-device-link-BUxuQupR.js → esm/sdk/runtime-device-link-ENxdEXQW.js} +1 -1
- package/dist/{public/sdk/runtime-ecdsa-tempo-DOBk_EtI.js → esm/sdk/runtime-ecdsa-tempo-DhGEb9U7.js} +1 -1
- package/dist/esm/sdk/{runtime-email-otp-CsAJKvYC.js → runtime-email-otp-dgsP7XZi.js} +1 -1
- package/dist/esm/sdk/{runtime-export-7REbcnBl.js → runtime-export-D2RCm5Gk.js} +1 -1
- package/dist/esm/sdk/{runtime-near-BA0DQf6H.js → runtime-near-Bf-9MFBQ.js} +1 -1
- package/dist/esm/sdk/{runtime-preferences-cRViPE8a.js → runtime-preferences-LQ8SPE7o.js} +1 -1
- package/dist/esm/sdk/{runtime-recovery-RRc8Yz1y.js → runtime-recovery-BuEzJzuZ.js} +1 -1
- package/dist/esm/sdk/shared-8ffIBYw2.js +6 -0
- package/dist/esm/sdk/signNear-BhTkDm2-.js +1 -0
- package/dist/esm/sdk/wallet-iframe-host-ecdsa.js +1 -1
- package/dist/esm/sdk/wallet-iframe-host-full.js +1 -1
- package/dist/esm/sdk/wallet-iframe-host-near.js +1 -1
- package/dist/esm/sdk/wallet-iframe-host-runtime.js +1 -1
- package/dist/esm/utils/intentDigest.js +59 -1
- package/dist/public/headers.manifest.json +1 -1
- package/dist/public/sdk/{host-B1CdRGoI.js → host-c1__wJwz.js} +1 -1
- package/dist/public/sdk/{runtime-auth-tgfe70hU.js → runtime-auth-BKFyLISf.js} +1 -1
- package/dist/{esm/sdk/runtime-device-link-BUxuQupR.js → public/sdk/runtime-device-link-ENxdEXQW.js} +1 -1
- package/dist/{esm/sdk/runtime-ecdsa-tempo-DOBk_EtI.js → public/sdk/runtime-ecdsa-tempo-DhGEb9U7.js} +1 -1
- package/dist/public/sdk/{runtime-email-otp-CsAJKvYC.js → runtime-email-otp-dgsP7XZi.js} +1 -1
- package/dist/public/sdk/{runtime-export-7REbcnBl.js → runtime-export-D2RCm5Gk.js} +1 -1
- package/dist/public/sdk/{runtime-near-BA0DQf6H.js → runtime-near-Bf-9MFBQ.js} +1 -1
- package/dist/public/sdk/{runtime-preferences-cRViPE8a.js → runtime-preferences-LQ8SPE7o.js} +1 -1
- package/dist/public/sdk/{runtime-recovery-RRc8Yz1y.js → runtime-recovery-BuEzJzuZ.js} +1 -1
- package/dist/public/sdk/shared-8ffIBYw2.js +6 -0
- package/dist/public/sdk/signNear-BhTkDm2-.js +1 -0
- package/dist/public/sdk/wallet-iframe-host-ecdsa.js +1 -1
- package/dist/public/sdk/wallet-iframe-host-full.js +1 -1
- package/dist/public/sdk/wallet-iframe-host-near.js +1 -1
- package/dist/public/sdk/wallet-iframe-host-runtime.js +1 -1
- package/dist/public/wallet-assets.manifest.json +26 -26
- package/dist/public/wallet-service/index.html +4 -4
- package/dist/types/wallet/src/core/signingEngine/flows/signNear/shared/ed25519YaoNormalSigning.d.ts +16 -4
- package/dist/types/wallet/src/core/signingEngine/flows/signNear/shared/signatureOnlySigning.d.ts +3 -3
- package/dist/types/wallet/src/core/signingEngine/nonce/nearTransactionReadiness.d.ts +3 -0
- package/dist/types/wallet/src/core/signingEngine/stepUpConfirmation/confirmOperation.d.ts +3 -1
- package/dist/types/wallet/src/core/signingEngine/uiConfirm/handlers/flows/signing.d.ts +2 -0
- package/dist/types/wallet/src/core/signingEngine/uiConfirm/handlers/handlePromptFromWorker.d.ts +2 -0
- package/dist/types/wallet/src/core/signingEngine/uiConfirm/uiConfirm.types.d.ts +3 -0
- package/package.json +1 -1
- package/dist/esm/sdk/shared-DdfxBUGY.js +0 -6
- package/dist/esm/sdk/signNear-CO5bx24Z.js +0 -1
- package/dist/public/sdk/shared-DdfxBUGY.js +0 -6
- 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.
|
|
3
|
+
`@seams/wallet` **0.9.1** 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.
|
|
9
|
+
pnpm add @seams/wallet@0.9.1
|
|
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.
|
|
15
|
+
`@seams/wallet-server@0.9.1` on the matching release.
|
|
16
16
|
|
|
17
17
|
## Next release migration (unreleased)
|
|
18
18
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
ae160ae14f2523702c4fef83cd460099dc8ebef71ae5079e056f38d97cc5d19d
|
|
@@ -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
|
|
743
|
-
|
|
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
|
-
|
|
776
|
-
|
|
777
|
-
|
|
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");
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { keccak256Bytes } from "../../../../../../shared-ts/src/utils/keccak.js";
|
|
2
|
+
import { bytesToHex, hexToBytes } from "../../../../chains/evm/bytes.js";
|
|
3
|
+
import { deriveSelectorFromHexData, normalizeHexData, normalizeHexSelector } from "../../../../chains/evm/display/normalization.js";
|
|
4
|
+
//#region src/core/signingEngine/uiConfirm/ui/transaction-display/abi/abiDecode.ts
|
|
5
|
+
const WORD_SIZE = 32;
|
|
6
|
+
const MAX_DECODE_ARRAY_LENGTH = 256;
|
|
7
|
+
const ABI_FUNCTION_LOOKUP_CACHE = /* @__PURE__ */ new WeakMap();
|
|
8
|
+
function selectorFromDataHex(dataHex) {
|
|
9
|
+
return deriveSelectorFromHexData(dataHex) || null;
|
|
10
|
+
}
|
|
11
|
+
function buildAbiFunctionEntries(abi) {
|
|
12
|
+
const out = [];
|
|
13
|
+
for (const entry of abi) {
|
|
14
|
+
if (!entry || typeof entry !== "object") continue;
|
|
15
|
+
const type = String(entry.type || "function").trim();
|
|
16
|
+
if (type !== "" && type !== "function") continue;
|
|
17
|
+
const name = String(entry.name || "").trim();
|
|
18
|
+
if (!name) continue;
|
|
19
|
+
const rawInputs = entry.inputs;
|
|
20
|
+
const inputs = Array.isArray(rawInputs) ? rawInputs : [];
|
|
21
|
+
const selector = selectorFromSignature(`${name}(${inputs.map((input) => canonicalAbiTypeFromParameter(input)).join(",")})`);
|
|
22
|
+
if (!selector) continue;
|
|
23
|
+
const normalizedInputs = normalizeAbiComponentNodes(inputs);
|
|
24
|
+
out.push({
|
|
25
|
+
name,
|
|
26
|
+
selector,
|
|
27
|
+
inputs: normalizedInputs
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
32
|
+
function resolveAbiFunctionLookup(abi) {
|
|
33
|
+
if (!Array.isArray(abi) || abi.length === 0) return void 0;
|
|
34
|
+
const cached = ABI_FUNCTION_LOOKUP_CACHE.get(abi);
|
|
35
|
+
if (cached) return cached;
|
|
36
|
+
const entries = buildAbiFunctionEntries(abi);
|
|
37
|
+
if (!entries.length) return void 0;
|
|
38
|
+
const bySelector = /* @__PURE__ */ new Map();
|
|
39
|
+
for (const entry of entries) if (!bySelector.has(entry.selector)) bySelector.set(entry.selector, entry);
|
|
40
|
+
const lookup = { bySelector };
|
|
41
|
+
ABI_FUNCTION_LOOKUP_CACHE.set(abi, lookup);
|
|
42
|
+
return lookup;
|
|
43
|
+
}
|
|
44
|
+
function selectorFromSignature(signature) {
|
|
45
|
+
const normalized = String(signature || "").trim();
|
|
46
|
+
if (!normalized) return null;
|
|
47
|
+
return normalizeHexSelector(bytesToHex(keccak256Bytes(new TextEncoder().encode(normalized)).slice(0, 4))) || null;
|
|
48
|
+
}
|
|
49
|
+
function canonicalAbiTypeFromParameter(input) {
|
|
50
|
+
const type = String(input?.type || "").trim().toLowerCase();
|
|
51
|
+
if (!type) return "";
|
|
52
|
+
const components = Array.isArray(input?.components) ? input.components : [];
|
|
53
|
+
if (type.startsWith("tuple")) {
|
|
54
|
+
const suffix = type.slice(5);
|
|
55
|
+
return `${`(${components.map((component) => canonicalAbiTypeFromParameter(component)).join(",")})`}${suffix}`;
|
|
56
|
+
}
|
|
57
|
+
return type;
|
|
58
|
+
}
|
|
59
|
+
function normalizeAbiComponentNodes(inputs) {
|
|
60
|
+
const out = [];
|
|
61
|
+
for (let index = 0; index < inputs.length; index += 1) {
|
|
62
|
+
const input = inputs[index];
|
|
63
|
+
const typeName = String(input?.type || "").trim().toLowerCase();
|
|
64
|
+
if (!typeName) continue;
|
|
65
|
+
const typeNode = parseAbiTypeNode({
|
|
66
|
+
type: typeName,
|
|
67
|
+
components: input?.components
|
|
68
|
+
});
|
|
69
|
+
if (!typeNode) continue;
|
|
70
|
+
const name = String(input?.name || "").trim();
|
|
71
|
+
out.push({
|
|
72
|
+
name: name || `arg${index}`,
|
|
73
|
+
typeName,
|
|
74
|
+
typeNode
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
function parseAbiTypeNode(args) {
|
|
80
|
+
const baseTypeRaw = String(args.type || "").trim().toLowerCase();
|
|
81
|
+
if (!baseTypeRaw) return null;
|
|
82
|
+
let baseType = baseTypeRaw;
|
|
83
|
+
const arrayDimensions = [];
|
|
84
|
+
while (baseType.endsWith("]")) {
|
|
85
|
+
const openBracket = baseType.lastIndexOf("[");
|
|
86
|
+
if (openBracket < 0) return null;
|
|
87
|
+
const rawLength = baseType.slice(openBracket + 1, -1).trim();
|
|
88
|
+
if (!/^\d*$/.test(rawLength)) return null;
|
|
89
|
+
const length = rawLength === "" ? null : Number.parseInt(rawLength, 10);
|
|
90
|
+
if (length != null && (!Number.isFinite(length) || length < 0)) return null;
|
|
91
|
+
arrayDimensions.push(length);
|
|
92
|
+
baseType = baseType.slice(0, openBracket);
|
|
93
|
+
}
|
|
94
|
+
let node = null;
|
|
95
|
+
if (baseType === "tuple") {
|
|
96
|
+
const normalizedComponents = normalizeAbiComponentNodes(Array.isArray(args.components) ? args.components : []);
|
|
97
|
+
node = {
|
|
98
|
+
kind: "tuple",
|
|
99
|
+
canonicalType: `(${normalizedComponents.map((component) => component.typeNode.canonicalType).join(",")})`,
|
|
100
|
+
dynamic: normalizedComponents.some((component) => component.typeNode.dynamic),
|
|
101
|
+
components: normalizedComponents
|
|
102
|
+
};
|
|
103
|
+
} else node = {
|
|
104
|
+
kind: "scalar",
|
|
105
|
+
typeName: baseType,
|
|
106
|
+
canonicalType: baseType,
|
|
107
|
+
dynamic: baseType === "bytes" || baseType === "string"
|
|
108
|
+
};
|
|
109
|
+
for (let i = arrayDimensions.length - 1; i >= 0; i -= 1) {
|
|
110
|
+
const length = arrayDimensions[i];
|
|
111
|
+
node = {
|
|
112
|
+
kind: "array",
|
|
113
|
+
canonicalType: `${node.canonicalType}[${length == null ? "" : String(length)}]`,
|
|
114
|
+
dynamic: length == null || node.dynamic,
|
|
115
|
+
item: node,
|
|
116
|
+
length
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return node;
|
|
120
|
+
}
|
|
121
|
+
function readWord(bytes, offset) {
|
|
122
|
+
if (!Number.isInteger(offset) || offset < 0) return null;
|
|
123
|
+
if (offset + WORD_SIZE > bytes.length) return null;
|
|
124
|
+
return bytes.slice(offset, offset + WORD_SIZE);
|
|
125
|
+
}
|
|
126
|
+
function readWordBigInt(bytes, offset) {
|
|
127
|
+
const word = readWord(bytes, offset);
|
|
128
|
+
if (!word) return null;
|
|
129
|
+
let out = 0n;
|
|
130
|
+
for (const byte of word) out = (out << 8n) + BigInt(byte);
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
function readWordNumber(bytes, offset) {
|
|
134
|
+
const value = readWordBigInt(bytes, offset);
|
|
135
|
+
if (value == null) return null;
|
|
136
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER) || value < 0n) return null;
|
|
137
|
+
return Number(value);
|
|
138
|
+
}
|
|
139
|
+
function staticWordLength(typeNode) {
|
|
140
|
+
if (typeNode.dynamic) return 1;
|
|
141
|
+
if (typeNode.kind === "scalar") return 1;
|
|
142
|
+
if (typeNode.kind === "tuple") return typeNode.components.reduce((sum, component) => sum + staticWordLength(component.typeNode), 0);
|
|
143
|
+
if (typeNode.length == null) return 1;
|
|
144
|
+
return typeNode.length * staticWordLength(typeNode.item);
|
|
145
|
+
}
|
|
146
|
+
function decodeScalar(typeName, bytes, offset) {
|
|
147
|
+
const normalizedType = String(typeName || "").trim().toLowerCase();
|
|
148
|
+
if (!normalizedType) return null;
|
|
149
|
+
if (normalizedType === "bytes") {
|
|
150
|
+
const length = readWordNumber(bytes, offset);
|
|
151
|
+
if (length == null) return null;
|
|
152
|
+
const start = offset + WORD_SIZE;
|
|
153
|
+
const end = start + length;
|
|
154
|
+
if (end > bytes.length) return null;
|
|
155
|
+
return bytesToHex(bytes.slice(start, end)).toLowerCase();
|
|
156
|
+
}
|
|
157
|
+
if (normalizedType === "string") {
|
|
158
|
+
const length = readWordNumber(bytes, offset);
|
|
159
|
+
if (length == null) return null;
|
|
160
|
+
const start = offset + WORD_SIZE;
|
|
161
|
+
const end = start + length;
|
|
162
|
+
if (end > bytes.length) return null;
|
|
163
|
+
const valueBytes = bytes.slice(start, end);
|
|
164
|
+
try {
|
|
165
|
+
return new TextDecoder().decode(valueBytes);
|
|
166
|
+
} catch {
|
|
167
|
+
return bytesToHex(valueBytes).toLowerCase();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const word = readWord(bytes, offset);
|
|
171
|
+
if (!word) return null;
|
|
172
|
+
const wordValue = readWordBigInt(bytes, offset);
|
|
173
|
+
if (wordValue == null) return null;
|
|
174
|
+
if (normalizedType === "bool") return wordValue !== 0n;
|
|
175
|
+
if (normalizedType === "address") return bytesToHex(word.slice(12)).toLowerCase();
|
|
176
|
+
if (normalizedType === "function") return bytesToHex(word.slice(0, 24)).toLowerCase();
|
|
177
|
+
const fixedBytesMatch = normalizedType.match(/^bytes(\d{1,2})$/);
|
|
178
|
+
if (fixedBytesMatch) {
|
|
179
|
+
const byteLength = Number.parseInt(fixedBytesMatch[1], 10);
|
|
180
|
+
if (!Number.isFinite(byteLength) || byteLength <= 0 || byteLength > 32) return null;
|
|
181
|
+
return bytesToHex(word.slice(0, byteLength)).toLowerCase();
|
|
182
|
+
}
|
|
183
|
+
if (normalizedType.match(/^uint(\d{0,3})$/)) return wordValue.toString(10);
|
|
184
|
+
const intMatch = normalizedType.match(/^int(\d{0,3})$/);
|
|
185
|
+
if (intMatch) {
|
|
186
|
+
const bitsRaw = intMatch[1];
|
|
187
|
+
const bits = bitsRaw ? Number.parseInt(bitsRaw, 10) : 256;
|
|
188
|
+
if (!Number.isFinite(bits) || bits <= 0 || bits > 256 || bits % 8 !== 0) return wordValue.toString(10);
|
|
189
|
+
const bitWidth = BigInt(bits);
|
|
190
|
+
const modulus = 1n << bitWidth;
|
|
191
|
+
return (wordValue >= 1n << bitWidth - 1n ? wordValue - modulus : wordValue).toString(10);
|
|
192
|
+
}
|
|
193
|
+
return bytesToHex(word).toLowerCase();
|
|
194
|
+
}
|
|
195
|
+
function decodeTypeAt(typeNode, bytes, offset) {
|
|
196
|
+
if (typeNode.kind === "scalar") return decodeScalar(typeNode.typeName, bytes, offset);
|
|
197
|
+
if (typeNode.kind === "tuple") {
|
|
198
|
+
const decodedItems = decodeTupleComponents(typeNode.components, bytes, offset);
|
|
199
|
+
if (!decodedItems) return null;
|
|
200
|
+
const out = {};
|
|
201
|
+
for (let i = 0; i < typeNode.components.length; i += 1) {
|
|
202
|
+
const component = typeNode.components[i];
|
|
203
|
+
const baseName = String(component.name || "").trim() || `item${i}`;
|
|
204
|
+
let name = baseName;
|
|
205
|
+
let counter = 1;
|
|
206
|
+
while (Object.prototype.hasOwnProperty.call(out, name)) {
|
|
207
|
+
counter += 1;
|
|
208
|
+
name = `${baseName}_${counter}`;
|
|
209
|
+
}
|
|
210
|
+
out[name] = decodedItems[i];
|
|
211
|
+
}
|
|
212
|
+
return out;
|
|
213
|
+
}
|
|
214
|
+
const expectedLength = typeNode.length;
|
|
215
|
+
const isDynamicArray = expectedLength == null;
|
|
216
|
+
const arrayLength = isDynamicArray ? readWordNumber(bytes, offset) : expectedLength;
|
|
217
|
+
if (arrayLength == null) return null;
|
|
218
|
+
if (arrayLength < 0 || arrayLength > MAX_DECODE_ARRAY_LENGTH) return null;
|
|
219
|
+
const baseOffset = isDynamicArray ? offset + WORD_SIZE : offset;
|
|
220
|
+
const items = [];
|
|
221
|
+
if (typeNode.item.dynamic) {
|
|
222
|
+
for (let i = 0; i < arrayLength; i += 1) {
|
|
223
|
+
const itemRelativeOffset = readWordNumber(bytes, baseOffset + i * WORD_SIZE);
|
|
224
|
+
if (itemRelativeOffset == null) return null;
|
|
225
|
+
const decoded = decodeTypeAt(typeNode.item, bytes, baseOffset + itemRelativeOffset);
|
|
226
|
+
if (decoded == null) return null;
|
|
227
|
+
items.push(decoded);
|
|
228
|
+
}
|
|
229
|
+
return items;
|
|
230
|
+
}
|
|
231
|
+
const itemWords = staticWordLength(typeNode.item);
|
|
232
|
+
for (let i = 0; i < arrayLength; i += 1) {
|
|
233
|
+
const itemOffset = baseOffset + i * itemWords * WORD_SIZE;
|
|
234
|
+
const decoded = decodeTypeAt(typeNode.item, bytes, itemOffset);
|
|
235
|
+
if (decoded == null) return null;
|
|
236
|
+
items.push(decoded);
|
|
237
|
+
}
|
|
238
|
+
return items;
|
|
239
|
+
}
|
|
240
|
+
function decodeTupleComponents(components, bytes, tupleOffset) {
|
|
241
|
+
let cursorWords = 0;
|
|
242
|
+
const headOffsets = [];
|
|
243
|
+
for (const component of components) {
|
|
244
|
+
headOffsets.push(cursorWords * WORD_SIZE);
|
|
245
|
+
cursorWords += component.typeNode.dynamic ? 1 : staticWordLength(component.typeNode);
|
|
246
|
+
}
|
|
247
|
+
const out = [];
|
|
248
|
+
for (let i = 0; i < components.length; i += 1) {
|
|
249
|
+
const component = components[i];
|
|
250
|
+
const headOffset = tupleOffset + headOffsets[i];
|
|
251
|
+
if (component.typeNode.dynamic) {
|
|
252
|
+
const relativeOffset = readWordNumber(bytes, headOffset);
|
|
253
|
+
if (relativeOffset == null) return null;
|
|
254
|
+
const decoded = decodeTypeAt(component.typeNode, bytes, tupleOffset + relativeOffset);
|
|
255
|
+
if (decoded == null) return null;
|
|
256
|
+
out.push(decoded);
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
const decoded = decodeTypeAt(component.typeNode, bytes, headOffset);
|
|
260
|
+
if (decoded == null) return null;
|
|
261
|
+
out.push(decoded);
|
|
262
|
+
}
|
|
263
|
+
return out;
|
|
264
|
+
}
|
|
265
|
+
function formatDecodedArgumentsJsonText(args) {
|
|
266
|
+
if (!args.length) return void 0;
|
|
267
|
+
const payload = {};
|
|
268
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
269
|
+
const arg = args[index];
|
|
270
|
+
const baseKey = String(arg.key || "").trim() || `arg${index}`;
|
|
271
|
+
let nextKey = baseKey;
|
|
272
|
+
let suffix = 2;
|
|
273
|
+
while (Object.prototype.hasOwnProperty.call(payload, nextKey)) {
|
|
274
|
+
nextKey = `${baseKey}_${suffix}`;
|
|
275
|
+
suffix += 1;
|
|
276
|
+
}
|
|
277
|
+
payload[nextKey] = arg.value;
|
|
278
|
+
}
|
|
279
|
+
try {
|
|
280
|
+
return JSON.stringify(payload, null, 2);
|
|
281
|
+
} catch {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function decodeCallDataWithAbi(args) {
|
|
286
|
+
const selector = selectorFromDataHex(args.dataHex);
|
|
287
|
+
if (!selector) return void 0;
|
|
288
|
+
const abiLookup = resolveAbiFunctionLookup(args.abi);
|
|
289
|
+
if (!abiLookup) return void 0;
|
|
290
|
+
const matched = abiLookup.bySelector.get(selector);
|
|
291
|
+
if (!matched) return void 0;
|
|
292
|
+
const normalizedDataHex = normalizeHexData(args.dataHex, { lowercase: true });
|
|
293
|
+
let argsBytes;
|
|
294
|
+
try {
|
|
295
|
+
const bytes = hexToBytes(normalizedDataHex);
|
|
296
|
+
if (bytes.length < 4) return { functionLabel: `${matched.name}()` };
|
|
297
|
+
argsBytes = bytes.slice(4);
|
|
298
|
+
} catch {
|
|
299
|
+
return { functionLabel: `${matched.name}()` };
|
|
300
|
+
}
|
|
301
|
+
const decodedValues = decodeTupleComponents(matched.inputs, argsBytes, 0);
|
|
302
|
+
if (!decodedValues) return { functionLabel: `${matched.name}()` };
|
|
303
|
+
const decodedArguments = matched.inputs.map((input, index) => ({
|
|
304
|
+
key: String(input.name || "").trim() || `arg${index}`,
|
|
305
|
+
value: decodedValues[index]
|
|
306
|
+
}));
|
|
307
|
+
return {
|
|
308
|
+
functionLabel: `${matched.name}()`,
|
|
309
|
+
decodedArgumentsJsonText: formatDecodedArgumentsJsonText(decodedArguments)
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
//#endregion
|
|
313
|
+
export { decodeCallDataWithAbi };
|
|
314
|
+
|
|
315
|
+
//# sourceMappingURL=abiDecode.js.map
|