@naculus/connect-appkit-core 0.3.0 → 0.5.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 +371 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +162 -2
- package/dist/index.d.ts +162 -2
- package/dist/index.js +377 -27
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -37,13 +37,16 @@ __export(src_exports, {
|
|
|
37
37
|
clearOneInAppNotification: () => clearOneInAppNotification,
|
|
38
38
|
compareCostsKey: () => compareCostsKey,
|
|
39
39
|
createDecimalsCache: () => createDecimalsCache,
|
|
40
|
+
createDelegationFrameworkAdapter: () => createDelegationFrameworkAdapter,
|
|
40
41
|
createDelegationPolicyFlow: () => createDelegationPolicyFlow,
|
|
41
42
|
createNotification: () => createNotification,
|
|
42
43
|
createNotificationSettingsStorage: () => createNotificationSettingsStorage,
|
|
44
|
+
createSolanaSessionKeyFlow: () => createSolanaSessionKeyFlow,
|
|
43
45
|
decodeRevertReason: () => decodeRevertReason,
|
|
44
46
|
defaultSiwxDomain: () => defaultSiwxDomain,
|
|
45
47
|
defaultSiwxUri: () => defaultSiwxUri,
|
|
46
48
|
describeChain: () => describeChain,
|
|
49
|
+
describePayment: () => describePayment,
|
|
47
50
|
eip155ChainIdToNumber: () => eip155ChainIdToNumber,
|
|
48
51
|
encodeErc20Approve: () => encodeErc20Approve,
|
|
49
52
|
encodeErc20Transfer: () => encodeErc20Transfer,
|
|
@@ -871,8 +874,104 @@ function assertHexSignature(value) {
|
|
|
871
874
|
return value;
|
|
872
875
|
}
|
|
873
876
|
|
|
874
|
-
// src/delegation-
|
|
877
|
+
// src/delegation-framework-adapter.ts
|
|
875
878
|
var import_connect_core15 = require("@naculus/connect-core");
|
|
879
|
+
function createDelegationFrameworkAdapter(options) {
|
|
880
|
+
const { manager, rpc, codec } = options;
|
|
881
|
+
return {
|
|
882
|
+
route: "eip7702",
|
|
883
|
+
async check({ policy }) {
|
|
884
|
+
const ready = policy.scope.mode === "eip7702" && policy.status === "active" && Boolean(policy.authorized);
|
|
885
|
+
return {
|
|
886
|
+
ready,
|
|
887
|
+
authorizationInstalled: ready,
|
|
888
|
+
sponsored: false,
|
|
889
|
+
promptless: true,
|
|
890
|
+
executorAddress: import_connect_core15.DELEGATION_FRAMEWORK.eip7702StatelessDeleGator,
|
|
891
|
+
reason: ready ? "The session key redeems its delegation; the chain enforces the caveats." : "This policy has no attached EIP-7702 delegation."
|
|
892
|
+
};
|
|
893
|
+
},
|
|
894
|
+
async prepare({ policy, transaction }) {
|
|
895
|
+
if (!transaction.to) {
|
|
896
|
+
throw new import_connect_core15.WalletError(
|
|
897
|
+
"invalid_input",
|
|
898
|
+
"A delegated execution needs a target."
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
let value;
|
|
902
|
+
try {
|
|
903
|
+
value = BigInt(transaction.value ?? "0");
|
|
904
|
+
} catch {
|
|
905
|
+
throw new import_connect_core15.WalletError(
|
|
906
|
+
"invalid_input",
|
|
907
|
+
"Transaction value is not a quantity."
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
const execution = {
|
|
911
|
+
target: transaction.to,
|
|
912
|
+
value,
|
|
913
|
+
callData: transaction.data ?? "0x"
|
|
914
|
+
};
|
|
915
|
+
const call = await manager.buildDelegationRedemption(
|
|
916
|
+
policy.id,
|
|
917
|
+
execution
|
|
918
|
+
);
|
|
919
|
+
const chainId = options.chainId();
|
|
920
|
+
if (chainId !== call.chainId) {
|
|
921
|
+
throw new import_connect_core15.WalletError(
|
|
922
|
+
"chain_mismatch",
|
|
923
|
+
`The delegation is for chain ${call.chainId}, not ${String(chainId)}.`
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
const from = (0, import_connect_core15.sessionKeyAddress)(policy.publicKey);
|
|
927
|
+
const [nonce, gas, fees] = await Promise.all([
|
|
928
|
+
rpc.getTransactionCount(from),
|
|
929
|
+
rpc.estimateGas({ from, to: call.to, data: call.data }),
|
|
930
|
+
rpc.fees()
|
|
931
|
+
]);
|
|
932
|
+
const unsigned = {
|
|
933
|
+
type: "eip1559",
|
|
934
|
+
chainId,
|
|
935
|
+
nonce,
|
|
936
|
+
to: call.to,
|
|
937
|
+
value: 0n,
|
|
938
|
+
data: call.data,
|
|
939
|
+
gas,
|
|
940
|
+
maxFeePerGas: fees.maxFeePerGas,
|
|
941
|
+
maxPriorityFeePerGas: fees.maxPriorityFeePerGas
|
|
942
|
+
};
|
|
943
|
+
const payload = {
|
|
944
|
+
outerTx: {
|
|
945
|
+
to: call.to,
|
|
946
|
+
value: "0x0",
|
|
947
|
+
data: call.data,
|
|
948
|
+
chainId,
|
|
949
|
+
gas: `0x${gas.toString(16)}`
|
|
950
|
+
},
|
|
951
|
+
execution,
|
|
952
|
+
unsigned
|
|
953
|
+
};
|
|
954
|
+
return {
|
|
955
|
+
digest: codec.signingHash(unsigned),
|
|
956
|
+
transaction,
|
|
957
|
+
payload
|
|
958
|
+
};
|
|
959
|
+
},
|
|
960
|
+
async broadcast({ prepared, signature }) {
|
|
961
|
+
const { unsigned } = prepared.payload;
|
|
962
|
+
const hash = await rpc.sendRawTransaction(
|
|
963
|
+
codec.serialize(unsigned, signature)
|
|
964
|
+
);
|
|
965
|
+
return { route: "eip7702", hash, status: "submitted" };
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// src/delegation-policy.ts
|
|
971
|
+
var import_connect_core16 = require("@naculus/connect-core");
|
|
972
|
+
function delegatesToStatelessDeleGator(delegation) {
|
|
973
|
+
return delegation.delegated === true && delegation.delegate?.toLowerCase() === import_connect_core16.DELEGATION_FRAMEWORK.eip7702StatelessDeleGator.toLowerCase();
|
|
974
|
+
}
|
|
876
975
|
function sorted(values) {
|
|
877
976
|
return values ? [...values].map((value) => value.toLowerCase()).sort() : null;
|
|
878
977
|
}
|
|
@@ -919,12 +1018,13 @@ function buildDelegationPolicyMessage(policy, origin) {
|
|
|
919
1018
|
${JSON.stringify(payload)}`;
|
|
920
1019
|
}
|
|
921
1020
|
function isVerifiablePolicy(policy) {
|
|
922
|
-
return policy.status === "active" && Boolean(policy.authorized) && policy.scope.mode === "offchain";
|
|
1021
|
+
return policy.status === "active" && Boolean(policy.authorized) && (policy.scope.mode === "offchain" || policy.scope.mode === "eip7702");
|
|
923
1022
|
}
|
|
924
1023
|
function createDelegationPolicyFlow(deps) {
|
|
925
1024
|
const { manager, origin } = deps;
|
|
926
1025
|
const verifyStoredPolicy = async (policy) => {
|
|
927
1026
|
if (!isVerifiablePolicy(policy)) return false;
|
|
1027
|
+
if (policy.scope.mode === "eip7702") return true;
|
|
928
1028
|
return manager.verifyOffchainAuthorization(
|
|
929
1029
|
policy.id,
|
|
930
1030
|
buildDelegationPolicyMessage(policy, origin),
|
|
@@ -934,28 +1034,29 @@ function createDelegationPolicyFlow(deps) {
|
|
|
934
1034
|
const createPolicy = async (scope) => {
|
|
935
1035
|
const signer = deps.signer();
|
|
936
1036
|
if (!signer) {
|
|
937
|
-
throw new
|
|
1037
|
+
throw new import_connect_core16.WalletError("wallet_unavailable", "No active EVM account");
|
|
938
1038
|
}
|
|
1039
|
+
if (scope.mode === "eip7702") return createDelegatedPolicy(scope, signer);
|
|
939
1040
|
if (scope.mode && scope.mode !== "offchain") {
|
|
940
|
-
throw new
|
|
1041
|
+
throw new import_connect_core16.WalletError(
|
|
941
1042
|
"method_not_allowed",
|
|
942
|
-
"This flow creates
|
|
1043
|
+
"This flow creates off-chain and EIP-7702 policies only; AA-module policies need an on-chain module."
|
|
943
1044
|
);
|
|
944
1045
|
}
|
|
945
1046
|
if (scope.allowedRecipients && scope.allowedRecipients.length > 0) {
|
|
946
|
-
throw new
|
|
1047
|
+
throw new import_connect_core16.WalletError(
|
|
947
1048
|
"method_not_allowed",
|
|
948
1049
|
"Recipient-limited policies are not supported by this flow: its executions sign raw digests, which connect-core refuses while allowedRecipients is set."
|
|
949
1050
|
);
|
|
950
1051
|
}
|
|
951
1052
|
if (!deps.encryptionKeyConfigured) {
|
|
952
|
-
throw new
|
|
1053
|
+
throw new import_connect_core16.WalletError(
|
|
953
1054
|
"method_not_allowed",
|
|
954
1055
|
"Persistent delegation policies require a host-provided encryptionKey. The deterministic compatibility fallback is not a production key boundary."
|
|
955
1056
|
);
|
|
956
1057
|
}
|
|
957
1058
|
if (!deps.storageAvailable()) {
|
|
958
|
-
throw new
|
|
1059
|
+
throw new import_connect_core16.WalletError(
|
|
959
1060
|
"storage_unavailable",
|
|
960
1061
|
"Persistent delegation policy storage is unavailable in this browser"
|
|
961
1062
|
);
|
|
@@ -969,7 +1070,7 @@ function createDelegationPolicyFlow(deps) {
|
|
|
969
1070
|
const message = buildDelegationPolicyMessage(draft, origin);
|
|
970
1071
|
const signature = await deps.signMessage(message);
|
|
971
1072
|
if (!/^0x[0-9a-fA-F]{130}$/.test(signature)) {
|
|
972
|
-
throw new
|
|
1073
|
+
throw new import_connect_core16.WalletError(
|
|
973
1074
|
"invalid_input",
|
|
974
1075
|
"Wallet did not return a valid 65-byte EVM policy signature"
|
|
975
1076
|
);
|
|
@@ -980,7 +1081,7 @@ function createDelegationPolicyFlow(deps) {
|
|
|
980
1081
|
signerAddress: signer
|
|
981
1082
|
});
|
|
982
1083
|
if (!recovers) {
|
|
983
|
-
throw new
|
|
1084
|
+
throw new import_connect_core16.WalletError(
|
|
984
1085
|
"invalid_input",
|
|
985
1086
|
"Policy signature does not recover to the connected EVM account"
|
|
986
1087
|
);
|
|
@@ -995,13 +1096,13 @@ function createDelegationPolicyFlow(deps) {
|
|
|
995
1096
|
(policy) => policy.id === draft?.id
|
|
996
1097
|
);
|
|
997
1098
|
if (!authorized?.authorized) {
|
|
998
|
-
throw new
|
|
1099
|
+
throw new import_connect_core16.WalletError(
|
|
999
1100
|
"invalid_input",
|
|
1000
1101
|
"Policy authorization was not persisted"
|
|
1001
1102
|
);
|
|
1002
1103
|
}
|
|
1003
1104
|
if (!await verifyStoredPolicy(authorized)) {
|
|
1004
|
-
throw new
|
|
1105
|
+
throw new import_connect_core16.WalletError(
|
|
1005
1106
|
"invalid_input",
|
|
1006
1107
|
"Persisted policy signature did not verify against its stored scope and origin"
|
|
1007
1108
|
);
|
|
@@ -1018,6 +1119,66 @@ function createDelegationPolicyFlow(deps) {
|
|
|
1018
1119
|
throw cause instanceof Error ? cause : new Error("Policy creation failed");
|
|
1019
1120
|
}
|
|
1020
1121
|
};
|
|
1122
|
+
const createDelegatedPolicy = async (scope, signer) => {
|
|
1123
|
+
if (!deps.signTypedData || !deps.chainId) {
|
|
1124
|
+
throw new import_connect_core16.WalletError(
|
|
1125
|
+
"method_not_allowed",
|
|
1126
|
+
"EIP-7702 policies need the wallet's signTypedData and the current chain."
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
if (!deps.encryptionKeyConfigured) {
|
|
1130
|
+
throw new import_connect_core16.WalletError(
|
|
1131
|
+
"method_not_allowed",
|
|
1132
|
+
"Persistent delegation policies require a host-provided encryptionKey. The deterministic compatibility fallback is not a production key boundary."
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
if (!deps.storageAvailable()) {
|
|
1136
|
+
throw new import_connect_core16.WalletError(
|
|
1137
|
+
"storage_unavailable",
|
|
1138
|
+
"Persistent delegation policy storage is unavailable in this browser"
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
if (!delegatesToStatelessDeleGator(deps.delegation())) {
|
|
1142
|
+
throw new import_connect_core16.WalletError(
|
|
1143
|
+
"method_not_allowed",
|
|
1144
|
+
`The account must first delegate to EIP7702StatelessDeleGatorImpl (${import_connect_core16.DELEGATION_FRAMEWORK.eip7702StatelessDeleGator}).`
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
const chainId = deps.chainId();
|
|
1148
|
+
if (chainId === null || !Number.isSafeInteger(chainId)) {
|
|
1149
|
+
throw new import_connect_core16.WalletError("wallet_unavailable", "No connected EVM chain");
|
|
1150
|
+
}
|
|
1151
|
+
let draft = null;
|
|
1152
|
+
try {
|
|
1153
|
+
draft = await manager.createSessionKey(
|
|
1154
|
+
{ ...scope, mode: "eip7702" },
|
|
1155
|
+
signer
|
|
1156
|
+
);
|
|
1157
|
+
const delegation = await manager.prepareDelegation(draft.id, chainId);
|
|
1158
|
+
const signature = await deps.signTypedData(
|
|
1159
|
+
(0, import_connect_core16.delegationTypedData)(delegation)
|
|
1160
|
+
);
|
|
1161
|
+
if (!/^0x[0-9a-fA-F]{130}$/.test(signature)) {
|
|
1162
|
+
throw new import_connect_core16.WalletError(
|
|
1163
|
+
"invalid_input",
|
|
1164
|
+
"Wallet did not return a valid 65-byte EVM signature"
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
await manager.attachDelegation(
|
|
1168
|
+
draft.id,
|
|
1169
|
+
delegation,
|
|
1170
|
+
signature
|
|
1171
|
+
);
|
|
1172
|
+
await deps.refresh();
|
|
1173
|
+
return (await manager.listSessions()).find((s) => s.id === draft?.id) ?? draft;
|
|
1174
|
+
} catch (cause) {
|
|
1175
|
+
if (draft) await manager.revokeSession(draft.id).catch(() => {
|
|
1176
|
+
});
|
|
1177
|
+
await deps.refresh().catch(() => {
|
|
1178
|
+
});
|
|
1179
|
+
throw cause;
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
1021
1182
|
const revokePolicy = async (policyId) => {
|
|
1022
1183
|
await manager.revokeSession(policyId);
|
|
1023
1184
|
await deps.refresh();
|
|
@@ -1050,16 +1211,21 @@ function createDelegationPolicyFlow(deps) {
|
|
|
1050
1211
|
const delegationMatches = Boolean(
|
|
1051
1212
|
adapter?.route !== "eip7702" || delegation.delegated === true && adapterCheck?.executorAddress && delegation.delegate?.toLowerCase() === adapterCheck.executorAddress.toLowerCase()
|
|
1052
1213
|
);
|
|
1214
|
+
const delegatedPolicy = policy?.scope.mode === "eip7702";
|
|
1053
1215
|
const policyReady = Boolean(
|
|
1054
|
-
policy?.status === "active" && policy.authorized && authorizationVerified && policy.scope.mode === "offchain" && signerMatches && scope.valid
|
|
1216
|
+
policy?.status === "active" && policy.authorized && authorizationVerified && (policy.scope.mode === "offchain" || delegatedPolicy) && signerMatches && scope.valid
|
|
1055
1217
|
);
|
|
1056
1218
|
const adapterSponsorshipReady = Boolean(
|
|
1057
1219
|
deps.sponsorship !== "required" || adapterCheck?.sponsored
|
|
1058
1220
|
);
|
|
1059
1221
|
const broadcastReady = Boolean(
|
|
1060
|
-
policyReady && callCount === 1 && adapterCheck?.ready && adapterCheck.authorizationInstalled && adapterCheck.promptless && adapterSponsorshipReady && delegationMatches
|
|
1222
|
+
policyReady && callCount === 1 && adapterCheck?.ready && adapterCheck.authorizationInstalled && adapterCheck.promptless && adapterSponsorshipReady && delegationMatches && // An eip7702 policy executes only through a redemption: the key
|
|
1223
|
+
// signs nothing else, so only an eip7702 adapter can carry it.
|
|
1224
|
+
(!delegatedPolicy || adapter?.route === "eip7702")
|
|
1225
|
+
);
|
|
1226
|
+
const ready = Boolean(
|
|
1227
|
+
policyReady && (delegatedPolicy ? broadcastReady : plan.route || broadcastReady)
|
|
1061
1228
|
);
|
|
1062
|
-
const ready = Boolean(policyReady && (plan.route || broadcastReady));
|
|
1063
1229
|
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}`;
|
|
1064
1230
|
return {
|
|
1065
1231
|
policy,
|
|
@@ -1085,37 +1251,76 @@ function createDelegationPolicyFlow(deps) {
|
|
|
1085
1251
|
digest,
|
|
1086
1252
|
tx
|
|
1087
1253
|
);
|
|
1254
|
+
const signRedemption = (policyId, prepared) => {
|
|
1255
|
+
const payload = prepared.payload;
|
|
1256
|
+
if (!payload?.outerTx || !payload.execution) {
|
|
1257
|
+
throw new import_connect_core16.WalletError(
|
|
1258
|
+
"invalid_input",
|
|
1259
|
+
"The EIP-7702 adapter did not return a redemption to sign."
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
if (prepared.transaction.chainId !== void 0 && prepared.transaction.chainId !== payload.outerTx.chainId) {
|
|
1263
|
+
throw new import_connect_core16.WalletError(
|
|
1264
|
+
"chain_mismatch",
|
|
1265
|
+
`The delegation is for chain ${String(payload.outerTx.chainId)}, not ${prepared.transaction.chainId}.`
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
1268
|
+
const { execution } = payload;
|
|
1269
|
+
if (typeof execution.value !== "bigint" || execution.value < 0n || !sameExecutionIntent(prepared.transaction, {
|
|
1270
|
+
to: execution.target,
|
|
1271
|
+
data: execution.callData,
|
|
1272
|
+
value: `0x${execution.value.toString(16)}`,
|
|
1273
|
+
chainId: prepared.transaction.chainId
|
|
1274
|
+
})) {
|
|
1275
|
+
throw new import_connect_core16.WalletError(
|
|
1276
|
+
"invalid_input",
|
|
1277
|
+
"The EIP-7702 adapter's execution differs from the requested transaction."
|
|
1278
|
+
);
|
|
1279
|
+
}
|
|
1280
|
+
return manager.signDelegationRedemption(
|
|
1281
|
+
policyId,
|
|
1282
|
+
prepared.digest,
|
|
1283
|
+
payload.outerTx,
|
|
1284
|
+
payload.execution
|
|
1285
|
+
);
|
|
1286
|
+
};
|
|
1088
1287
|
const signPolicyDigest = async (policyId, digest, tx) => {
|
|
1089
1288
|
const preview = await previewPolicyExecution(policyId, tx, 1, "any");
|
|
1289
|
+
if (preview.policy?.scope.mode === "eip7702") {
|
|
1290
|
+
throw new import_connect_core16.WalletError(
|
|
1291
|
+
"method_not_allowed",
|
|
1292
|
+
"An EIP-7702 policy signs only its delegation redemptions; use executePolicy."
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1090
1295
|
if (!preview.ready) {
|
|
1091
|
-
throw new
|
|
1296
|
+
throw new import_connect_core16.WalletError("method_not_allowed", preview.reason);
|
|
1092
1297
|
}
|
|
1093
1298
|
return signVerified(policyId, digest, tx);
|
|
1094
1299
|
};
|
|
1095
1300
|
const executePolicy = async (policyId, tx) => {
|
|
1096
1301
|
const adapter = deps.adapter;
|
|
1097
1302
|
if (!adapter) {
|
|
1098
|
-
throw new
|
|
1303
|
+
throw new import_connect_core16.WalletError(
|
|
1099
1304
|
"method_not_allowed",
|
|
1100
1305
|
"No session-policy-aware AA/7702 execution adapter is configured."
|
|
1101
1306
|
);
|
|
1102
1307
|
}
|
|
1103
1308
|
const preview = await previewPolicyExecution(policyId, tx, 1, "any");
|
|
1104
1309
|
if (!preview.broadcastReady || !preview.policy) {
|
|
1105
|
-
throw new
|
|
1310
|
+
throw new import_connect_core16.WalletError("method_not_allowed", preview.reason);
|
|
1106
1311
|
}
|
|
1107
1312
|
const prepared = await adapter.prepare({
|
|
1108
1313
|
policy: preview.policy,
|
|
1109
1314
|
transaction: tx
|
|
1110
1315
|
});
|
|
1111
1316
|
if (!/^0x[0-9a-fA-F]{64}$/.test(prepared.digest)) {
|
|
1112
|
-
throw new
|
|
1317
|
+
throw new import_connect_core16.WalletError(
|
|
1113
1318
|
"invalid_input",
|
|
1114
1319
|
"Execution adapter returned a digest that is not 32 bytes."
|
|
1115
1320
|
);
|
|
1116
1321
|
}
|
|
1117
1322
|
if (!sameExecutionIntent(tx, prepared.transaction)) {
|
|
1118
|
-
throw new
|
|
1323
|
+
throw new import_connect_core16.WalletError(
|
|
1119
1324
|
"invalid_input",
|
|
1120
1325
|
"Execution adapter changed the requested target, value, data, or chain."
|
|
1121
1326
|
);
|
|
@@ -1127,23 +1332,19 @@ function createDelegationPolicyFlow(deps) {
|
|
|
1127
1332
|
const delegation = deps.delegation();
|
|
1128
1333
|
const currentDelegationMatches = adapter.route !== "eip7702" || delegation.delegated === true && currentCheck.executorAddress !== void 0 && delegation.delegate?.toLowerCase() === currentCheck.executorAddress.toLowerCase();
|
|
1129
1334
|
if (!currentCheck.ready || !currentCheck.authorizationInstalled || !currentCheck.promptless || deps.sponsorship === "required" && !currentCheck.sponsored || !currentDelegationMatches) {
|
|
1130
|
-
throw new
|
|
1335
|
+
throw new import_connect_core16.WalletError(
|
|
1131
1336
|
"method_not_allowed",
|
|
1132
1337
|
currentCheck.reason || "The on-chain policy authorization is not ready."
|
|
1133
1338
|
);
|
|
1134
1339
|
}
|
|
1135
|
-
const signature = await signVerified(
|
|
1136
|
-
policyId,
|
|
1137
|
-
prepared.digest,
|
|
1138
|
-
prepared.transaction
|
|
1139
|
-
);
|
|
1340
|
+
const signature = preview.policy.scope.mode === "eip7702" ? await signRedemption(policyId, prepared) : await signVerified(policyId, prepared.digest, prepared.transaction);
|
|
1140
1341
|
const submission = await adapter.broadcast({
|
|
1141
1342
|
policy: preview.policy,
|
|
1142
1343
|
prepared,
|
|
1143
1344
|
signature
|
|
1144
1345
|
});
|
|
1145
1346
|
if (submission.route !== adapter.route || submission.status !== "submitted" || !/^0x[0-9a-fA-F]{64}$/.test(submission.hash)) {
|
|
1146
|
-
throw new
|
|
1347
|
+
throw new import_connect_core16.WalletError(
|
|
1147
1348
|
"invalid_input",
|
|
1148
1349
|
"Execution adapter returned an invalid submission result."
|
|
1149
1350
|
);
|
|
@@ -1161,8 +1362,146 @@ function createDelegationPolicyFlow(deps) {
|
|
|
1161
1362
|
};
|
|
1162
1363
|
}
|
|
1163
1364
|
|
|
1365
|
+
// src/payment-fetch.ts
|
|
1366
|
+
function record(value) {
|
|
1367
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
1368
|
+
}
|
|
1369
|
+
function text(value) {
|
|
1370
|
+
return typeof value === "string" && value !== "" ? value : null;
|
|
1371
|
+
}
|
|
1372
|
+
function requestUrl(input) {
|
|
1373
|
+
if (input instanceof URL) return input.href;
|
|
1374
|
+
if (typeof input !== "string") return input.url;
|
|
1375
|
+
try {
|
|
1376
|
+
return new Request(input).url;
|
|
1377
|
+
} catch {
|
|
1378
|
+
return input;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
function describePayment(input, result) {
|
|
1382
|
+
const paid = record(result.paid);
|
|
1383
|
+
if (!paid) return null;
|
|
1384
|
+
const resource = requestUrl(input);
|
|
1385
|
+
if (typeof paid.scheme === "string" && typeof paid.network === "string") {
|
|
1386
|
+
const settlement = record(result.settlement);
|
|
1387
|
+
return {
|
|
1388
|
+
protocol: "x402",
|
|
1389
|
+
resource,
|
|
1390
|
+
chainId: text(paid.network),
|
|
1391
|
+
asset: text(paid.asset),
|
|
1392
|
+
payTo: text(paid.payTo),
|
|
1393
|
+
amount: text(paid.amount),
|
|
1394
|
+
// A hash reported for another chain is not this payment's.
|
|
1395
|
+
reference: settlement?.success === true && settlement.network === paid.network ? text(settlement.transaction) : null
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
const challenge = record(record(paid.challenge)?.params);
|
|
1399
|
+
const request = record(paid.request);
|
|
1400
|
+
if (challenge && request) {
|
|
1401
|
+
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;
|
|
1402
|
+
return {
|
|
1403
|
+
protocol: "mpp",
|
|
1404
|
+
resource,
|
|
1405
|
+
chainId,
|
|
1406
|
+
asset: text(request.currency),
|
|
1407
|
+
payTo: text(request.recipient),
|
|
1408
|
+
amount: text(request.amount),
|
|
1409
|
+
reference: text(record(result.receipt)?.reference)
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
return {
|
|
1413
|
+
protocol: "unknown",
|
|
1414
|
+
resource,
|
|
1415
|
+
chainId: null,
|
|
1416
|
+
asset: null,
|
|
1417
|
+
payTo: null,
|
|
1418
|
+
amount: null,
|
|
1419
|
+
reference: null
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
// src/solana-session-key.ts
|
|
1424
|
+
var import_connect_core17 = require("@naculus/connect-core");
|
|
1425
|
+
function send(rpc) {
|
|
1426
|
+
const sendTransaction = rpc.sendTransaction;
|
|
1427
|
+
if (!sendTransaction) {
|
|
1428
|
+
throw new import_connect_core17.WalletError(
|
|
1429
|
+
"invalid_input",
|
|
1430
|
+
"The Solana RPC must implement sendTransaction to approve or revoke."
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
return (tx) => sendTransaction.call(rpc, tx);
|
|
1434
|
+
}
|
|
1435
|
+
function createSolanaSessionKeyFlow(deps) {
|
|
1436
|
+
const { manager, rpc, owner } = deps;
|
|
1437
|
+
const list = async () => (await manager.listSessions()).filter((key) => key.owner === owner.address).sort((a, b) => b.createdAt - a.createdAt);
|
|
1438
|
+
return {
|
|
1439
|
+
list,
|
|
1440
|
+
async create(scope) {
|
|
1441
|
+
const broadcast = send(rpc);
|
|
1442
|
+
const draft = await manager.createSessionKey(scope, owner.address, rpc);
|
|
1443
|
+
let approval;
|
|
1444
|
+
try {
|
|
1445
|
+
const { transaction, recentBlockhash } = await manager.prepareApproval(
|
|
1446
|
+
draft.id,
|
|
1447
|
+
rpc
|
|
1448
|
+
);
|
|
1449
|
+
const signed = await owner.signTransaction(transaction);
|
|
1450
|
+
approval = await manager.attachApproval(
|
|
1451
|
+
draft.id,
|
|
1452
|
+
signed,
|
|
1453
|
+
recentBlockhash
|
|
1454
|
+
);
|
|
1455
|
+
} catch (cause) {
|
|
1456
|
+
await manager.revoke(draft.id).catch(() => {
|
|
1457
|
+
});
|
|
1458
|
+
throw cause;
|
|
1459
|
+
}
|
|
1460
|
+
let signature;
|
|
1461
|
+
try {
|
|
1462
|
+
signature = await broadcast(approval);
|
|
1463
|
+
} catch (cause) {
|
|
1464
|
+
await manager.revoke(draft.id).catch(() => {
|
|
1465
|
+
});
|
|
1466
|
+
throw new import_connect_core17.WalletError(
|
|
1467
|
+
"rpc_error",
|
|
1468
|
+
`The approval could not be confirmed as sent (${cause instanceof Error ? cause.message : String(cause)}); the key is revoked here. Call revoke("${draft.id}") to send the on-chain Revoke in case it landed.`
|
|
1469
|
+
);
|
|
1470
|
+
}
|
|
1471
|
+
const key = (await list().catch(() => [])).find((k) => k.id === draft.id);
|
|
1472
|
+
return { key: key ?? { ...draft, status: "active" }, signature };
|
|
1473
|
+
},
|
|
1474
|
+
async revoke(id) {
|
|
1475
|
+
const key = (await list()).find((k) => k.id === id);
|
|
1476
|
+
if (!key) {
|
|
1477
|
+
throw new import_connect_core17.WalletError(
|
|
1478
|
+
"invalid_input",
|
|
1479
|
+
`No Solana session key ${id} for this owner.`
|
|
1480
|
+
);
|
|
1481
|
+
}
|
|
1482
|
+
await manager.revoke(id);
|
|
1483
|
+
const broadcast = send(rpc);
|
|
1484
|
+
const { transaction, recentBlockhash } = await manager.prepareRevocation(
|
|
1485
|
+
id,
|
|
1486
|
+
rpc
|
|
1487
|
+
);
|
|
1488
|
+
const signed = await owner.signTransaction(transaction);
|
|
1489
|
+
const revocation = (0, import_connect_core17.verifySignedOwnerTransaction)(signed, {
|
|
1490
|
+
kind: "revoke",
|
|
1491
|
+
revocation: {
|
|
1492
|
+
owner: key.owner,
|
|
1493
|
+
mint: key.scope.mint,
|
|
1494
|
+
tokenProgram: key.tokenProgram,
|
|
1495
|
+
recentBlockhash
|
|
1496
|
+
}
|
|
1497
|
+
});
|
|
1498
|
+
return { signature: await broadcast(revocation) };
|
|
1499
|
+
}
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1164
1503
|
// src/web3-store.ts
|
|
1165
|
-
var
|
|
1504
|
+
var import_connect_core18 = require("@naculus/connect-core");
|
|
1166
1505
|
function withTimeout(promise, ms, label = "Operation") {
|
|
1167
1506
|
let timeoutId;
|
|
1168
1507
|
const timeout = new Promise((_, reject) => {
|
|
@@ -1184,7 +1523,7 @@ async function withRetry(fn, options) {
|
|
|
1184
1523
|
lastError = error;
|
|
1185
1524
|
if (attempt < options.maxRetries) {
|
|
1186
1525
|
const delay = options.baseDelay * 2 ** attempt;
|
|
1187
|
-
|
|
1526
|
+
import_connect_core18.logger.warn(
|
|
1188
1527
|
"appkit/core",
|
|
1189
1528
|
`Retry attempt ${attempt + 1}/${options.maxRetries} after ${delay}ms`
|
|
1190
1529
|
);
|
|
@@ -1308,13 +1647,16 @@ function siwxResultToSession(result, now = /* @__PURE__ */ new Date()) {
|
|
|
1308
1647
|
clearOneInAppNotification,
|
|
1309
1648
|
compareCostsKey,
|
|
1310
1649
|
createDecimalsCache,
|
|
1650
|
+
createDelegationFrameworkAdapter,
|
|
1311
1651
|
createDelegationPolicyFlow,
|
|
1312
1652
|
createNotification,
|
|
1313
1653
|
createNotificationSettingsStorage,
|
|
1654
|
+
createSolanaSessionKeyFlow,
|
|
1314
1655
|
decodeRevertReason,
|
|
1315
1656
|
defaultSiwxDomain,
|
|
1316
1657
|
defaultSiwxUri,
|
|
1317
1658
|
describeChain,
|
|
1659
|
+
describePayment,
|
|
1318
1660
|
eip155ChainIdToNumber,
|
|
1319
1661
|
encodeErc20Approve,
|
|
1320
1662
|
encodeErc20Transfer,
|