@naculus/connect-appkit-core 0.2.8 → 0.4.0
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/dist/index.cjs +289 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +113 -2
- package/dist/index.d.ts +113 -2
- package/dist/index.js +293 -27
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -793,8 +793,112 @@ function assertHexSignature(value) {
|
|
|
793
793
|
return value;
|
|
794
794
|
}
|
|
795
795
|
|
|
796
|
+
// src/delegation-framework-adapter.ts
|
|
797
|
+
import {
|
|
798
|
+
DELEGATION_FRAMEWORK,
|
|
799
|
+
sessionKeyAddress,
|
|
800
|
+
WalletError as WalletError7
|
|
801
|
+
} from "@naculus/connect-core";
|
|
802
|
+
function createDelegationFrameworkAdapter(options) {
|
|
803
|
+
const { manager, rpc, codec } = options;
|
|
804
|
+
return {
|
|
805
|
+
route: "eip7702",
|
|
806
|
+
async check({ policy }) {
|
|
807
|
+
const ready = policy.scope.mode === "eip7702" && policy.status === "active" && Boolean(policy.authorized);
|
|
808
|
+
return {
|
|
809
|
+
ready,
|
|
810
|
+
authorizationInstalled: ready,
|
|
811
|
+
sponsored: false,
|
|
812
|
+
promptless: true,
|
|
813
|
+
executorAddress: DELEGATION_FRAMEWORK.eip7702StatelessDeleGator,
|
|
814
|
+
reason: ready ? "The session key redeems its delegation; the chain enforces the caveats." : "This policy has no attached EIP-7702 delegation."
|
|
815
|
+
};
|
|
816
|
+
},
|
|
817
|
+
async prepare({ policy, transaction }) {
|
|
818
|
+
if (!transaction.to) {
|
|
819
|
+
throw new WalletError7(
|
|
820
|
+
"invalid_input",
|
|
821
|
+
"A delegated execution needs a target."
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
let value;
|
|
825
|
+
try {
|
|
826
|
+
value = BigInt(transaction.value ?? "0");
|
|
827
|
+
} catch {
|
|
828
|
+
throw new WalletError7(
|
|
829
|
+
"invalid_input",
|
|
830
|
+
"Transaction value is not a quantity."
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
const execution = {
|
|
834
|
+
target: transaction.to,
|
|
835
|
+
value,
|
|
836
|
+
callData: transaction.data ?? "0x"
|
|
837
|
+
};
|
|
838
|
+
const call = await manager.buildDelegationRedemption(
|
|
839
|
+
policy.id,
|
|
840
|
+
execution
|
|
841
|
+
);
|
|
842
|
+
const chainId = options.chainId();
|
|
843
|
+
if (chainId !== call.chainId) {
|
|
844
|
+
throw new WalletError7(
|
|
845
|
+
"chain_mismatch",
|
|
846
|
+
`The delegation is for chain ${call.chainId}, not ${String(chainId)}.`
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
const from = sessionKeyAddress(policy.publicKey);
|
|
850
|
+
const [nonce, gas, fees] = await Promise.all([
|
|
851
|
+
rpc.getTransactionCount(from),
|
|
852
|
+
rpc.estimateGas({ from, to: call.to, data: call.data }),
|
|
853
|
+
rpc.fees()
|
|
854
|
+
]);
|
|
855
|
+
const unsigned = {
|
|
856
|
+
type: "eip1559",
|
|
857
|
+
chainId,
|
|
858
|
+
nonce,
|
|
859
|
+
to: call.to,
|
|
860
|
+
value: 0n,
|
|
861
|
+
data: call.data,
|
|
862
|
+
gas,
|
|
863
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
864
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas
|
|
865
|
+
};
|
|
866
|
+
const payload = {
|
|
867
|
+
outerTx: {
|
|
868
|
+
to: call.to,
|
|
869
|
+
value: "0x0",
|
|
870
|
+
data: call.data,
|
|
871
|
+
chainId,
|
|
872
|
+
gas: `0x${gas.toString(16)}`
|
|
873
|
+
},
|
|
874
|
+
execution,
|
|
875
|
+
unsigned
|
|
876
|
+
};
|
|
877
|
+
return {
|
|
878
|
+
digest: codec.signingHash(unsigned),
|
|
879
|
+
transaction,
|
|
880
|
+
payload
|
|
881
|
+
};
|
|
882
|
+
},
|
|
883
|
+
async broadcast({ prepared, signature }) {
|
|
884
|
+
const { unsigned } = prepared.payload;
|
|
885
|
+
const hash = await rpc.sendRawTransaction(
|
|
886
|
+
codec.serialize(unsigned, signature)
|
|
887
|
+
);
|
|
888
|
+
return { route: "eip7702", hash, status: "submitted" };
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
|
|
796
893
|
// src/delegation-policy.ts
|
|
797
|
-
import {
|
|
894
|
+
import {
|
|
895
|
+
DELEGATION_FRAMEWORK as DELEGATION_FRAMEWORK2,
|
|
896
|
+
delegationTypedData,
|
|
897
|
+
WalletError as WalletError8
|
|
898
|
+
} from "@naculus/connect-core";
|
|
899
|
+
function delegatesToStatelessDeleGator(delegation) {
|
|
900
|
+
return delegation.delegated === true && delegation.delegate?.toLowerCase() === DELEGATION_FRAMEWORK2.eip7702StatelessDeleGator.toLowerCase();
|
|
901
|
+
}
|
|
798
902
|
function sorted(values) {
|
|
799
903
|
return values ? [...values].map((value) => value.toLowerCase()).sort() : null;
|
|
800
904
|
}
|
|
@@ -841,12 +945,13 @@ function buildDelegationPolicyMessage(policy, origin) {
|
|
|
841
945
|
${JSON.stringify(payload)}`;
|
|
842
946
|
}
|
|
843
947
|
function isVerifiablePolicy(policy) {
|
|
844
|
-
return policy.status === "active" && Boolean(policy.authorized) && policy.scope.mode === "offchain";
|
|
948
|
+
return policy.status === "active" && Boolean(policy.authorized) && (policy.scope.mode === "offchain" || policy.scope.mode === "eip7702");
|
|
845
949
|
}
|
|
846
950
|
function createDelegationPolicyFlow(deps) {
|
|
847
951
|
const { manager, origin } = deps;
|
|
848
952
|
const verifyStoredPolicy = async (policy) => {
|
|
849
953
|
if (!isVerifiablePolicy(policy)) return false;
|
|
954
|
+
if (policy.scope.mode === "eip7702") return true;
|
|
850
955
|
return manager.verifyOffchainAuthorization(
|
|
851
956
|
policy.id,
|
|
852
957
|
buildDelegationPolicyMessage(policy, origin),
|
|
@@ -856,28 +961,29 @@ function createDelegationPolicyFlow(deps) {
|
|
|
856
961
|
const createPolicy = async (scope) => {
|
|
857
962
|
const signer = deps.signer();
|
|
858
963
|
if (!signer) {
|
|
859
|
-
throw new
|
|
964
|
+
throw new WalletError8("wallet_unavailable", "No active EVM account");
|
|
860
965
|
}
|
|
966
|
+
if (scope.mode === "eip7702") return createDelegatedPolicy(scope, signer);
|
|
861
967
|
if (scope.mode && scope.mode !== "offchain") {
|
|
862
|
-
throw new
|
|
968
|
+
throw new WalletError8(
|
|
863
969
|
"method_not_allowed",
|
|
864
|
-
"This flow creates
|
|
970
|
+
"This flow creates off-chain and EIP-7702 policies only; AA-module policies need an on-chain module."
|
|
865
971
|
);
|
|
866
972
|
}
|
|
867
973
|
if (scope.allowedRecipients && scope.allowedRecipients.length > 0) {
|
|
868
|
-
throw new
|
|
974
|
+
throw new WalletError8(
|
|
869
975
|
"method_not_allowed",
|
|
870
976
|
"Recipient-limited policies are not supported by this flow: its executions sign raw digests, which connect-core refuses while allowedRecipients is set."
|
|
871
977
|
);
|
|
872
978
|
}
|
|
873
979
|
if (!deps.encryptionKeyConfigured) {
|
|
874
|
-
throw new
|
|
980
|
+
throw new WalletError8(
|
|
875
981
|
"method_not_allowed",
|
|
876
982
|
"Persistent delegation policies require a host-provided encryptionKey. The deterministic compatibility fallback is not a production key boundary."
|
|
877
983
|
);
|
|
878
984
|
}
|
|
879
985
|
if (!deps.storageAvailable()) {
|
|
880
|
-
throw new
|
|
986
|
+
throw new WalletError8(
|
|
881
987
|
"storage_unavailable",
|
|
882
988
|
"Persistent delegation policy storage is unavailable in this browser"
|
|
883
989
|
);
|
|
@@ -891,7 +997,7 @@ function createDelegationPolicyFlow(deps) {
|
|
|
891
997
|
const message = buildDelegationPolicyMessage(draft, origin);
|
|
892
998
|
const signature = await deps.signMessage(message);
|
|
893
999
|
if (!/^0x[0-9a-fA-F]{130}$/.test(signature)) {
|
|
894
|
-
throw new
|
|
1000
|
+
throw new WalletError8(
|
|
895
1001
|
"invalid_input",
|
|
896
1002
|
"Wallet did not return a valid 65-byte EVM policy signature"
|
|
897
1003
|
);
|
|
@@ -902,7 +1008,7 @@ function createDelegationPolicyFlow(deps) {
|
|
|
902
1008
|
signerAddress: signer
|
|
903
1009
|
});
|
|
904
1010
|
if (!recovers) {
|
|
905
|
-
throw new
|
|
1011
|
+
throw new WalletError8(
|
|
906
1012
|
"invalid_input",
|
|
907
1013
|
"Policy signature does not recover to the connected EVM account"
|
|
908
1014
|
);
|
|
@@ -917,13 +1023,13 @@ function createDelegationPolicyFlow(deps) {
|
|
|
917
1023
|
(policy) => policy.id === draft?.id
|
|
918
1024
|
);
|
|
919
1025
|
if (!authorized?.authorized) {
|
|
920
|
-
throw new
|
|
1026
|
+
throw new WalletError8(
|
|
921
1027
|
"invalid_input",
|
|
922
1028
|
"Policy authorization was not persisted"
|
|
923
1029
|
);
|
|
924
1030
|
}
|
|
925
1031
|
if (!await verifyStoredPolicy(authorized)) {
|
|
926
|
-
throw new
|
|
1032
|
+
throw new WalletError8(
|
|
927
1033
|
"invalid_input",
|
|
928
1034
|
"Persisted policy signature did not verify against its stored scope and origin"
|
|
929
1035
|
);
|
|
@@ -940,6 +1046,66 @@ function createDelegationPolicyFlow(deps) {
|
|
|
940
1046
|
throw cause instanceof Error ? cause : new Error("Policy creation failed");
|
|
941
1047
|
}
|
|
942
1048
|
};
|
|
1049
|
+
const createDelegatedPolicy = async (scope, signer) => {
|
|
1050
|
+
if (!deps.signTypedData || !deps.chainId) {
|
|
1051
|
+
throw new WalletError8(
|
|
1052
|
+
"method_not_allowed",
|
|
1053
|
+
"EIP-7702 policies need the wallet's signTypedData and the current chain."
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
if (!deps.encryptionKeyConfigured) {
|
|
1057
|
+
throw new WalletError8(
|
|
1058
|
+
"method_not_allowed",
|
|
1059
|
+
"Persistent delegation policies require a host-provided encryptionKey. The deterministic compatibility fallback is not a production key boundary."
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1062
|
+
if (!deps.storageAvailable()) {
|
|
1063
|
+
throw new WalletError8(
|
|
1064
|
+
"storage_unavailable",
|
|
1065
|
+
"Persistent delegation policy storage is unavailable in this browser"
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
if (!delegatesToStatelessDeleGator(deps.delegation())) {
|
|
1069
|
+
throw new WalletError8(
|
|
1070
|
+
"method_not_allowed",
|
|
1071
|
+
`The account must first delegate to EIP7702StatelessDeleGatorImpl (${DELEGATION_FRAMEWORK2.eip7702StatelessDeleGator}).`
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
const chainId = deps.chainId();
|
|
1075
|
+
if (chainId === null || !Number.isSafeInteger(chainId)) {
|
|
1076
|
+
throw new WalletError8("wallet_unavailable", "No connected EVM chain");
|
|
1077
|
+
}
|
|
1078
|
+
let draft = null;
|
|
1079
|
+
try {
|
|
1080
|
+
draft = await manager.createSessionKey(
|
|
1081
|
+
{ ...scope, mode: "eip7702" },
|
|
1082
|
+
signer
|
|
1083
|
+
);
|
|
1084
|
+
const delegation = await manager.prepareDelegation(draft.id, chainId);
|
|
1085
|
+
const signature = await deps.signTypedData(
|
|
1086
|
+
delegationTypedData(delegation)
|
|
1087
|
+
);
|
|
1088
|
+
if (!/^0x[0-9a-fA-F]{130}$/.test(signature)) {
|
|
1089
|
+
throw new WalletError8(
|
|
1090
|
+
"invalid_input",
|
|
1091
|
+
"Wallet did not return a valid 65-byte EVM signature"
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
await manager.attachDelegation(
|
|
1095
|
+
draft.id,
|
|
1096
|
+
delegation,
|
|
1097
|
+
signature
|
|
1098
|
+
);
|
|
1099
|
+
await deps.refresh();
|
|
1100
|
+
return (await manager.listSessions()).find((s) => s.id === draft?.id) ?? draft;
|
|
1101
|
+
} catch (cause) {
|
|
1102
|
+
if (draft) await manager.revokeSession(draft.id).catch(() => {
|
|
1103
|
+
});
|
|
1104
|
+
await deps.refresh().catch(() => {
|
|
1105
|
+
});
|
|
1106
|
+
throw cause;
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
943
1109
|
const revokePolicy = async (policyId) => {
|
|
944
1110
|
await manager.revokeSession(policyId);
|
|
945
1111
|
await deps.refresh();
|
|
@@ -972,16 +1138,21 @@ function createDelegationPolicyFlow(deps) {
|
|
|
972
1138
|
const delegationMatches = Boolean(
|
|
973
1139
|
adapter?.route !== "eip7702" || delegation.delegated === true && adapterCheck?.executorAddress && delegation.delegate?.toLowerCase() === adapterCheck.executorAddress.toLowerCase()
|
|
974
1140
|
);
|
|
1141
|
+
const delegatedPolicy = policy?.scope.mode === "eip7702";
|
|
975
1142
|
const policyReady = Boolean(
|
|
976
|
-
policy?.status === "active" && policy.authorized && authorizationVerified && policy.scope.mode === "offchain" && signerMatches && scope.valid
|
|
1143
|
+
policy?.status === "active" && policy.authorized && authorizationVerified && (policy.scope.mode === "offchain" || delegatedPolicy) && signerMatches && scope.valid
|
|
977
1144
|
);
|
|
978
1145
|
const adapterSponsorshipReady = Boolean(
|
|
979
1146
|
deps.sponsorship !== "required" || adapterCheck?.sponsored
|
|
980
1147
|
);
|
|
981
1148
|
const broadcastReady = Boolean(
|
|
982
|
-
policyReady && callCount === 1 && adapterCheck?.ready && adapterCheck.authorizationInstalled && adapterCheck.promptless && adapterSponsorshipReady && delegationMatches
|
|
1149
|
+
policyReady && callCount === 1 && adapterCheck?.ready && adapterCheck.authorizationInstalled && adapterCheck.promptless && adapterSponsorshipReady && delegationMatches && // An eip7702 policy executes only through a redemption: the key
|
|
1150
|
+
// signs nothing else, so only an eip7702 adapter can carry it.
|
|
1151
|
+
(!delegatedPolicy || adapter?.route === "eip7702")
|
|
1152
|
+
);
|
|
1153
|
+
const ready = Boolean(
|
|
1154
|
+
policyReady && (delegatedPolicy ? broadcastReady : plan.route || broadcastReady)
|
|
983
1155
|
);
|
|
984
|
-
const ready = Boolean(policyReady && (plan.route || broadcastReady));
|
|
985
1156
|
const reason = !policy ? "Policy not found." : policy.status !== "active" ? `Policy is ${policy.status}.` : !policy.authorized ? "The main wallet has not signed this policy." : !authorizationVerified ? "The persisted policy signature no longer matches its scope, signer, or origin." : !signerMatches ? "The connected account is not the policy signer." : !scope.valid ? scope.reason ?? "The transaction is outside the policy scope." : broadcastReady ? `The configured ${adapter?.route ?? "AA/7702"} adapter can submit this policy-authorized operation without another main-wallet prompt.${adapterCheck?.sponsored ? " Gas sponsorship is guaranteed." : ""} ${adapterCheck?.reason ?? "The on-chain execution adapter is ready."}` : !adapter ? `${plan.reason} The signed off-chain policy permits this request; an AA/7702 adapter is still required to broadcast without another wallet prompt.` : !adapterCheck?.ready || !adapterCheck.authorizationInstalled ? `${plan.reason} ${adapterCheck?.reason ?? "The execution adapter is not ready."}` : !adapterCheck.promptless ? `${plan.reason} The configured adapter would invoke the main wallet again, so promptless broadcast is not ready.` : !adapterSponsorshipReady ? `${plan.reason} Sponsored gas is required, but the configured adapter does not guarantee sponsorship.` : callCount !== 1 ? `${plan.reason} This policy adapter prepares one execution at a time and cannot claim a multi-call broadcast.` : !delegationMatches ? `${plan.reason} The configured EIP-7702 executor does not match the account's on-chain delegation.` : !plan.route ? plan.reason : `${plan.reason} ${adapterCheck.reason}`;
|
|
986
1157
|
return {
|
|
987
1158
|
policy,
|
|
@@ -1007,37 +1178,76 @@ function createDelegationPolicyFlow(deps) {
|
|
|
1007
1178
|
digest,
|
|
1008
1179
|
tx
|
|
1009
1180
|
);
|
|
1181
|
+
const signRedemption = (policyId, prepared) => {
|
|
1182
|
+
const payload = prepared.payload;
|
|
1183
|
+
if (!payload?.outerTx || !payload.execution) {
|
|
1184
|
+
throw new WalletError8(
|
|
1185
|
+
"invalid_input",
|
|
1186
|
+
"The EIP-7702 adapter did not return a redemption to sign."
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
if (prepared.transaction.chainId !== void 0 && prepared.transaction.chainId !== payload.outerTx.chainId) {
|
|
1190
|
+
throw new WalletError8(
|
|
1191
|
+
"chain_mismatch",
|
|
1192
|
+
`The delegation is for chain ${String(payload.outerTx.chainId)}, not ${prepared.transaction.chainId}.`
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
const { execution } = payload;
|
|
1196
|
+
if (typeof execution.value !== "bigint" || execution.value < 0n || !sameExecutionIntent(prepared.transaction, {
|
|
1197
|
+
to: execution.target,
|
|
1198
|
+
data: execution.callData,
|
|
1199
|
+
value: `0x${execution.value.toString(16)}`,
|
|
1200
|
+
chainId: prepared.transaction.chainId
|
|
1201
|
+
})) {
|
|
1202
|
+
throw new WalletError8(
|
|
1203
|
+
"invalid_input",
|
|
1204
|
+
"The EIP-7702 adapter's execution differs from the requested transaction."
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
return manager.signDelegationRedemption(
|
|
1208
|
+
policyId,
|
|
1209
|
+
prepared.digest,
|
|
1210
|
+
payload.outerTx,
|
|
1211
|
+
payload.execution
|
|
1212
|
+
);
|
|
1213
|
+
};
|
|
1010
1214
|
const signPolicyDigest = async (policyId, digest, tx) => {
|
|
1011
1215
|
const preview = await previewPolicyExecution(policyId, tx, 1, "any");
|
|
1216
|
+
if (preview.policy?.scope.mode === "eip7702") {
|
|
1217
|
+
throw new WalletError8(
|
|
1218
|
+
"method_not_allowed",
|
|
1219
|
+
"An EIP-7702 policy signs only its delegation redemptions; use executePolicy."
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
1012
1222
|
if (!preview.ready) {
|
|
1013
|
-
throw new
|
|
1223
|
+
throw new WalletError8("method_not_allowed", preview.reason);
|
|
1014
1224
|
}
|
|
1015
1225
|
return signVerified(policyId, digest, tx);
|
|
1016
1226
|
};
|
|
1017
1227
|
const executePolicy = async (policyId, tx) => {
|
|
1018
1228
|
const adapter = deps.adapter;
|
|
1019
1229
|
if (!adapter) {
|
|
1020
|
-
throw new
|
|
1230
|
+
throw new WalletError8(
|
|
1021
1231
|
"method_not_allowed",
|
|
1022
1232
|
"No session-policy-aware AA/7702 execution adapter is configured."
|
|
1023
1233
|
);
|
|
1024
1234
|
}
|
|
1025
1235
|
const preview = await previewPolicyExecution(policyId, tx, 1, "any");
|
|
1026
1236
|
if (!preview.broadcastReady || !preview.policy) {
|
|
1027
|
-
throw new
|
|
1237
|
+
throw new WalletError8("method_not_allowed", preview.reason);
|
|
1028
1238
|
}
|
|
1029
1239
|
const prepared = await adapter.prepare({
|
|
1030
1240
|
policy: preview.policy,
|
|
1031
1241
|
transaction: tx
|
|
1032
1242
|
});
|
|
1033
1243
|
if (!/^0x[0-9a-fA-F]{64}$/.test(prepared.digest)) {
|
|
1034
|
-
throw new
|
|
1244
|
+
throw new WalletError8(
|
|
1035
1245
|
"invalid_input",
|
|
1036
1246
|
"Execution adapter returned a digest that is not 32 bytes."
|
|
1037
1247
|
);
|
|
1038
1248
|
}
|
|
1039
1249
|
if (!sameExecutionIntent(tx, prepared.transaction)) {
|
|
1040
|
-
throw new
|
|
1250
|
+
throw new WalletError8(
|
|
1041
1251
|
"invalid_input",
|
|
1042
1252
|
"Execution adapter changed the requested target, value, data, or chain."
|
|
1043
1253
|
);
|
|
@@ -1049,23 +1259,19 @@ function createDelegationPolicyFlow(deps) {
|
|
|
1049
1259
|
const delegation = deps.delegation();
|
|
1050
1260
|
const currentDelegationMatches = adapter.route !== "eip7702" || delegation.delegated === true && currentCheck.executorAddress !== void 0 && delegation.delegate?.toLowerCase() === currentCheck.executorAddress.toLowerCase();
|
|
1051
1261
|
if (!currentCheck.ready || !currentCheck.authorizationInstalled || !currentCheck.promptless || deps.sponsorship === "required" && !currentCheck.sponsored || !currentDelegationMatches) {
|
|
1052
|
-
throw new
|
|
1262
|
+
throw new WalletError8(
|
|
1053
1263
|
"method_not_allowed",
|
|
1054
1264
|
currentCheck.reason || "The on-chain policy authorization is not ready."
|
|
1055
1265
|
);
|
|
1056
1266
|
}
|
|
1057
|
-
const signature = await signVerified(
|
|
1058
|
-
policyId,
|
|
1059
|
-
prepared.digest,
|
|
1060
|
-
prepared.transaction
|
|
1061
|
-
);
|
|
1267
|
+
const signature = preview.policy.scope.mode === "eip7702" ? await signRedemption(policyId, prepared) : await signVerified(policyId, prepared.digest, prepared.transaction);
|
|
1062
1268
|
const submission = await adapter.broadcast({
|
|
1063
1269
|
policy: preview.policy,
|
|
1064
1270
|
prepared,
|
|
1065
1271
|
signature
|
|
1066
1272
|
});
|
|
1067
1273
|
if (submission.route !== adapter.route || submission.status !== "submitted" || !/^0x[0-9a-fA-F]{64}$/.test(submission.hash)) {
|
|
1068
|
-
throw new
|
|
1274
|
+
throw new WalletError8(
|
|
1069
1275
|
"invalid_input",
|
|
1070
1276
|
"Execution adapter returned an invalid submission result."
|
|
1071
1277
|
);
|
|
@@ -1083,6 +1289,64 @@ function createDelegationPolicyFlow(deps) {
|
|
|
1083
1289
|
};
|
|
1084
1290
|
}
|
|
1085
1291
|
|
|
1292
|
+
// src/payment-fetch.ts
|
|
1293
|
+
function record(value) {
|
|
1294
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
1295
|
+
}
|
|
1296
|
+
function text(value) {
|
|
1297
|
+
return typeof value === "string" && value !== "" ? value : null;
|
|
1298
|
+
}
|
|
1299
|
+
function requestUrl(input) {
|
|
1300
|
+
if (input instanceof URL) return input.href;
|
|
1301
|
+
if (typeof input !== "string") return input.url;
|
|
1302
|
+
try {
|
|
1303
|
+
return new Request(input).url;
|
|
1304
|
+
} catch {
|
|
1305
|
+
return input;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
function describePayment(input, result) {
|
|
1309
|
+
const paid = record(result.paid);
|
|
1310
|
+
if (!paid) return null;
|
|
1311
|
+
const resource = requestUrl(input);
|
|
1312
|
+
if (typeof paid.scheme === "string" && typeof paid.network === "string") {
|
|
1313
|
+
const settlement = record(result.settlement);
|
|
1314
|
+
return {
|
|
1315
|
+
protocol: "x402",
|
|
1316
|
+
resource,
|
|
1317
|
+
chainId: text(paid.network),
|
|
1318
|
+
asset: text(paid.asset),
|
|
1319
|
+
payTo: text(paid.payTo),
|
|
1320
|
+
amount: text(paid.amount),
|
|
1321
|
+
// A hash reported for another chain is not this payment's.
|
|
1322
|
+
reference: settlement?.success === true && settlement.network === paid.network ? text(settlement.transaction) : null
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
const challenge = record(record(paid.challenge)?.params);
|
|
1326
|
+
const request = record(paid.request);
|
|
1327
|
+
if (challenge && request) {
|
|
1328
|
+
const chainId = challenge.method === "evm" && typeof request.chainId === "number" && Number.isSafeInteger(request.chainId) ? `eip155:${request.chainId}` : challenge.method === "solana" && typeof request.network === "string" && /^solana:[1-9A-HJ-NP-Za-km-z]{32}$/.test(request.network) ? request.network : null;
|
|
1329
|
+
return {
|
|
1330
|
+
protocol: "mpp",
|
|
1331
|
+
resource,
|
|
1332
|
+
chainId,
|
|
1333
|
+
asset: text(request.currency),
|
|
1334
|
+
payTo: text(request.recipient),
|
|
1335
|
+
amount: text(request.amount),
|
|
1336
|
+
reference: text(record(result.receipt)?.reference)
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
return {
|
|
1340
|
+
protocol: "unknown",
|
|
1341
|
+
resource,
|
|
1342
|
+
chainId: null,
|
|
1343
|
+
asset: null,
|
|
1344
|
+
payTo: null,
|
|
1345
|
+
amount: null,
|
|
1346
|
+
reference: null
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1086
1350
|
// src/web3-store.ts
|
|
1087
1351
|
import { logger } from "@naculus/connect-core";
|
|
1088
1352
|
function withTimeout(promise, ms, label = "Operation") {
|
|
@@ -1229,6 +1493,7 @@ export {
|
|
|
1229
1493
|
clearOneInAppNotification,
|
|
1230
1494
|
compareCostsKey,
|
|
1231
1495
|
createDecimalsCache,
|
|
1496
|
+
createDelegationFrameworkAdapter,
|
|
1232
1497
|
createDelegationPolicyFlow,
|
|
1233
1498
|
createNotification,
|
|
1234
1499
|
createNotificationSettingsStorage,
|
|
@@ -1236,6 +1501,7 @@ export {
|
|
|
1236
1501
|
defaultSiwxDomain,
|
|
1237
1502
|
defaultSiwxUri,
|
|
1238
1503
|
describeChain,
|
|
1504
|
+
describePayment,
|
|
1239
1505
|
eip155ChainIdToNumber,
|
|
1240
1506
|
encodeErc20Approve,
|
|
1241
1507
|
encodeErc20Transfer,
|