@haven_ai/sdk 0.5.0-alpha.1 → 0.7.0-alpha.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/README.md +24 -8
- package/dist/{base64-BUMXmruY.d.cts → base64-_seD1uw8.d.cts} +425 -18
- package/dist/{base64-BUMXmruY.d.ts → base64-_seD1uw8.d.ts} +425 -18
- package/dist/{chunk-JKUIE45B.cjs → chunk-3SVPI4LS.cjs} +130 -9
- package/dist/chunk-3SVPI4LS.cjs.map +1 -0
- package/dist/{chunk-QSSVOPWA.cjs → chunk-J6DQEBK2.cjs} +340 -17
- package/dist/chunk-J6DQEBK2.cjs.map +1 -0
- package/dist/{chunk-GLNG2GF7.js → chunk-NNIT7WAI.js} +127 -10
- package/dist/chunk-NNIT7WAI.js.map +1 -0
- package/dist/{chunk-KQ7JXKTV.js → chunk-R3RZJJWL.js} +321 -6
- package/dist/chunk-R3RZJJWL.js.map +1 -0
- package/dist/edge.cjs +296 -57
- package/dist/edge.cjs.map +1 -1
- package/dist/edge.d.cts +122 -5
- package/dist/edge.d.ts +122 -5
- package/dist/edge.js +204 -4
- package/dist/edge.js.map +1 -1
- package/dist/index.cjs +772 -350
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +162 -28
- package/dist/index.d.ts +162 -28
- package/dist/index.js +461 -80
- package/dist/index.js.map +1 -1
- package/dist/test-support.cjs +18 -18
- package/dist/test-support.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-GLNG2GF7.js.map +0 -1
- package/dist/chunk-JKUIE45B.cjs.map +0 -1
- package/dist/chunk-KQ7JXKTV.js.map +0 -1
- package/dist/chunk-QSSVOPWA.cjs.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk3SVPI4LS_cjs = require('./chunk-3SVPI4LS.cjs');
|
|
4
4
|
var viem = require('viem');
|
|
5
5
|
var crypto = require('crypto');
|
|
6
6
|
|
|
7
7
|
var TYPED_DATA_NOT_ALLOWED = "TYPED_DATA_NOT_ALLOWED";
|
|
8
|
-
var HavenTypedDataRefusedError = class extends
|
|
8
|
+
var HavenTypedDataRefusedError = class extends chunk3SVPI4LS_cjs.HavenSigningError {
|
|
9
9
|
constructor(message) {
|
|
10
10
|
super(message);
|
|
11
11
|
this.code = TYPED_DATA_NOT_ALLOWED;
|
|
@@ -46,7 +46,7 @@ function assertBoundDirectPaymentUserOp(typedData, delegateAddress) {
|
|
|
46
46
|
`This signer only signs direct payments on chains the delegation rail has pinned contracts for (${[...DIRECT_PAYMENT_CHAIN_IDS].join(", ")}); this typed data names chain ${String(domain.chainId)}. Refusing.`
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
|
-
const ownAccount =
|
|
49
|
+
const ownAccount = chunk3SVPI4LS_cjs.deriveDelegateAccountAddress(delegateAddress);
|
|
50
50
|
const sender = typeof message.sender === "string" ? message.sender : "";
|
|
51
51
|
if (sender.toLowerCase() !== ownAccount.toLowerCase()) {
|
|
52
52
|
throw new HavenTypedDataRefusedError(
|
|
@@ -76,9 +76,9 @@ function assertBoundDirectPaymentUserOp(typedData, delegateAddress) {
|
|
|
76
76
|
"This UserOperation's execute() call does not re-encode to the exact callData bytes (trailing or non-canonical bytes). Refusing."
|
|
77
77
|
);
|
|
78
78
|
}
|
|
79
|
-
if (decoded.target.toLowerCase() !==
|
|
79
|
+
if (decoded.target.toLowerCase() !== chunk3SVPI4LS_cjs.DELEGATION_MANAGER.toLowerCase()) {
|
|
80
80
|
throw new HavenTypedDataRefusedError(
|
|
81
|
-
`This UserOperation's execute() calls ${decoded.target}, not the DelegationManager (${
|
|
81
|
+
`This UserOperation's execute() calls ${decoded.target}, not the DelegationManager (${chunk3SVPI4LS_cjs.DELEGATION_MANAGER}). A direct payment only ever redeems the agent's own budget delegation \u2014 refusing what looks like a self-call (e.g. transferOwnership, updateSigners, upgradeToAndCall) or a call to an unrelated contract.`
|
|
82
82
|
);
|
|
83
83
|
}
|
|
84
84
|
if (decoded.value !== 0n) {
|
|
@@ -87,20 +87,20 @@ function assertBoundDirectPaymentUserOp(typedData, delegateAddress) {
|
|
|
87
87
|
);
|
|
88
88
|
}
|
|
89
89
|
try {
|
|
90
|
-
|
|
90
|
+
chunk3SVPI4LS_cjs.assertRedeemsOwnBudgetDelegation(decoded.callData, ownAccount);
|
|
91
91
|
} catch (err) {
|
|
92
92
|
throw new HavenTypedDataRefusedError(err instanceof Error ? err.message : String(err));
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
function assertOwnSettlementChild(typedData, expectation, delegateAddress) {
|
|
96
96
|
try {
|
|
97
|
-
|
|
97
|
+
chunk3SVPI4LS_cjs.verifySettlementChild(typedData, {
|
|
98
98
|
...expectation,
|
|
99
|
-
delegatorAccount:
|
|
99
|
+
delegatorAccount: chunk3SVPI4LS_cjs.deriveDelegateAccountAddress(delegateAddress)
|
|
100
100
|
});
|
|
101
101
|
} catch (err) {
|
|
102
102
|
if (err instanceof HavenTypedDataRefusedError) throw err;
|
|
103
|
-
if (err instanceof
|
|
103
|
+
if (err instanceof chunk3SVPI4LS_cjs.HavenSigningError) throw new HavenTypedDataRefusedError(err.message);
|
|
104
104
|
throw new HavenTypedDataRefusedError(
|
|
105
105
|
`Refusing to sign the x402 settlement child: it is malformed (${err instanceof Error ? err.message : String(err)}).`
|
|
106
106
|
);
|
|
@@ -129,7 +129,7 @@ function assertFundingLegPaysDelegate(typedData, expected) {
|
|
|
129
129
|
try {
|
|
130
130
|
const { args: executeArgs } = viem.decodeFunctionData({ abi: EXECUTE_ABI, data: message.callData });
|
|
131
131
|
const inner = executeArgs[0].callData;
|
|
132
|
-
const { args } = viem.decodeFunctionData({ abi:
|
|
132
|
+
const { args } = viem.decodeFunctionData({ abi: chunk3SVPI4LS_cjs.REDEEM_DELEGATIONS_ABI, data: inner });
|
|
133
133
|
const executions = args[2];
|
|
134
134
|
executionCallData = executions[0];
|
|
135
135
|
} catch {
|
|
@@ -248,7 +248,7 @@ var TRANSFER_WITH_AUTHORIZATION_TYPES = {
|
|
|
248
248
|
function sweepUsdcAddress(chainId) {
|
|
249
249
|
const address = USDC_ADDRESS_BY_CHAIN[chainId];
|
|
250
250
|
if (!address) {
|
|
251
|
-
throw new
|
|
251
|
+
throw new chunk3SVPI4LS_cjs.HavenSigningError(
|
|
252
252
|
`Sweep is not supported on chain ${chainId}. Supported: ${SWEEPABLE_CHAIN_IDS.join(", ")}.`
|
|
253
253
|
);
|
|
254
254
|
}
|
|
@@ -257,7 +257,7 @@ function sweepUsdcAddress(chainId) {
|
|
|
257
257
|
function sweepUsdcDomain(chainId) {
|
|
258
258
|
const domain = USDC_EIP712_DOMAIN_BY_CHAIN[chainId];
|
|
259
259
|
if (!domain) {
|
|
260
|
-
throw new
|
|
260
|
+
throw new chunk3SVPI4LS_cjs.HavenSigningError(
|
|
261
261
|
`Sweep is not supported on chain ${chainId}. Supported: ${SWEEPABLE_CHAIN_IDS.join(", ")}.`
|
|
262
262
|
);
|
|
263
263
|
}
|
|
@@ -270,12 +270,12 @@ function buildSweepTypedData(auth) {
|
|
|
270
270
|
const domain = sweepUsdcDomain(auth.chainId);
|
|
271
271
|
const expectedToken = sweepUsdcAddress(auth.chainId);
|
|
272
272
|
if (!sameAddress(auth.token, expectedToken)) {
|
|
273
|
-
throw new
|
|
273
|
+
throw new chunk3SVPI4LS_cjs.HavenSigningError(
|
|
274
274
|
`Sweep token ${auth.token} is not the canonical USDC contract for chain ${auth.chainId}.`
|
|
275
275
|
);
|
|
276
276
|
}
|
|
277
277
|
if (!/^0x[0-9a-fA-F]{64}$/.test(auth.nonce)) {
|
|
278
|
-
throw new
|
|
278
|
+
throw new chunk3SVPI4LS_cjs.HavenSigningError("Sweep nonce must be a 0x-prefixed 32-byte hex string.");
|
|
279
279
|
}
|
|
280
280
|
return {
|
|
281
281
|
domain,
|
|
@@ -767,6 +767,12 @@ function resolveTokenFromAddress(address, network) {
|
|
|
767
767
|
}
|
|
768
768
|
return ALL_TOKENS[lower] ?? null;
|
|
769
769
|
}
|
|
770
|
+
function resolveTokenBySymbol(chainId, symbol) {
|
|
771
|
+
const table = NETWORK_TOKENS[`eip155:${chainId}`];
|
|
772
|
+
if (!table) return null;
|
|
773
|
+
const hit = Object.entries(table).find(([, token]) => token.symbol === symbol);
|
|
774
|
+
return hit ? { ...hit[1] } : null;
|
|
775
|
+
}
|
|
770
776
|
function stableStringify2(value) {
|
|
771
777
|
if (value === null || typeof value !== "object") {
|
|
772
778
|
const primitive = JSON.stringify(value);
|
|
@@ -779,7 +785,7 @@ function stableStringify2(value) {
|
|
|
779
785
|
}
|
|
780
786
|
|
|
781
787
|
// src/client-identity.ts
|
|
782
|
-
var SDK_VERSION = "0.
|
|
788
|
+
var SDK_VERSION = "0.7.0-alpha.0";
|
|
783
789
|
var HAVEN_CLIENT_HEADER = "X-Haven-Client";
|
|
784
790
|
function havenClientIdentity(pkg, version) {
|
|
785
791
|
return `${pkg}/${version}`;
|
|
@@ -898,14 +904,326 @@ function unsupportedNodeVersionMessage(options) {
|
|
|
898
904
|
function major(version) {
|
|
899
905
|
return String(parseNodeVersion(version)[0]);
|
|
900
906
|
}
|
|
907
|
+
var MAX_TASK_BUDGET_TTL_SECONDS = 86400;
|
|
908
|
+
var EXPECTED_DELEGATION_TYPES = {
|
|
909
|
+
Caveat: [
|
|
910
|
+
{ name: "enforcer", type: "address" },
|
|
911
|
+
{ name: "terms", type: "bytes" }
|
|
912
|
+
],
|
|
913
|
+
Delegation: [
|
|
914
|
+
{ name: "delegate", type: "address" },
|
|
915
|
+
{ name: "delegator", type: "address" },
|
|
916
|
+
{ name: "authority", type: "bytes32" },
|
|
917
|
+
{ name: "caveats", type: "Caveat[]" },
|
|
918
|
+
{ name: "salt", type: "uint256" }
|
|
919
|
+
]
|
|
920
|
+
};
|
|
921
|
+
var DELEGATION_DOMAIN_NAME = "DelegationManager";
|
|
922
|
+
var DELEGATION_DOMAIN_VERSION = "1";
|
|
923
|
+
function same(a, b) {
|
|
924
|
+
return !!a && !!b && a.toLowerCase() === b.toLowerCase();
|
|
925
|
+
}
|
|
926
|
+
function hex(value) {
|
|
927
|
+
return value.startsWith("0x") ? value.slice(2).toLowerCase() : value.toLowerCase();
|
|
928
|
+
}
|
|
929
|
+
function slice(terms, start, end) {
|
|
930
|
+
const body = hex(terms);
|
|
931
|
+
return end === void 0 ? body.slice(start * 2) : body.slice(start * 2, end * 2);
|
|
932
|
+
}
|
|
933
|
+
function findCaveat(caveats, enforcer) {
|
|
934
|
+
return caveats.find((c) => same(c.enforcer, enforcer));
|
|
935
|
+
}
|
|
936
|
+
function isTaskChildTypedData(value) {
|
|
937
|
+
const td = value;
|
|
938
|
+
if (!td || td.primaryType !== "Delegation" || typeof td.domain?.verifyingContract !== "string" || !Array.isArray(td.message?.caveats)) {
|
|
939
|
+
return false;
|
|
940
|
+
}
|
|
941
|
+
const delegate = td.message?.delegate;
|
|
942
|
+
const delegator = td.message?.delegator;
|
|
943
|
+
return typeof delegate === "string" && typeof delegator === "string" && same(delegate, delegator);
|
|
944
|
+
}
|
|
945
|
+
function refuseTaskChild(what, detail) {
|
|
946
|
+
throw new HavenTypedDataRefusedError(
|
|
947
|
+
`Refusing to sign the task-budget child: ${what}. ${detail} This signature opens a self-delegated slice of the agent budget, so it is verified locally against the expectation Haven declared, rather than trusted.`
|
|
948
|
+
);
|
|
949
|
+
}
|
|
950
|
+
function assertOwnTaskChild(typedData, expected, delegateAddress, now = Date.now()) {
|
|
951
|
+
const td = typedData;
|
|
952
|
+
if (td?.primaryType !== "Delegation") {
|
|
953
|
+
refuseTaskChild("it is not a Delegation payload", `primaryType was '${String(td?.primaryType)}'.`);
|
|
954
|
+
}
|
|
955
|
+
if (!same(td.domain?.verifyingContract, chunk3SVPI4LS_cjs.DELEGATION_MANAGER)) {
|
|
956
|
+
refuseTaskChild(
|
|
957
|
+
"the EIP-712 domain names an unknown DelegationManager",
|
|
958
|
+
`Expected ${chunk3SVPI4LS_cjs.DELEGATION_MANAGER}, got ${td.domain?.verifyingContract}.`
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
if (td.domain?.name !== DELEGATION_DOMAIN_NAME || td.domain?.version !== DELEGATION_DOMAIN_VERSION) {
|
|
962
|
+
refuseTaskChild(
|
|
963
|
+
"the EIP-712 domain name/version does not match the pinned DelegationManager domain",
|
|
964
|
+
`Expected name '${DELEGATION_DOMAIN_NAME}' version '${DELEGATION_DOMAIN_VERSION}'; got name '${String(td.domain?.name)}' version '${String(td.domain?.version)}'.`
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
if (JSON.stringify(td.types?.Caveat) !== JSON.stringify(EXPECTED_DELEGATION_TYPES.Caveat) || JSON.stringify(td.types?.Delegation) !== JSON.stringify(EXPECTED_DELEGATION_TYPES.Delegation)) {
|
|
968
|
+
refuseTaskChild(
|
|
969
|
+
"its EIP-712 type definitions do not match the pinned Delegation/Caveat shape",
|
|
970
|
+
"A renamed, reordered, or additional field on Delegation or Caveat could change what the caveats below mean without changing this check's field-by-field comparisons."
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
const domainChain = Number(td.domain?.chainId);
|
|
974
|
+
if (!Number.isFinite(domainChain) || !DIRECT_PAYMENT_CHAIN_IDS.has(domainChain)) {
|
|
975
|
+
refuseTaskChild(
|
|
976
|
+
"it is scoped to a chain the delegation rail has no pinned contracts for",
|
|
977
|
+
`Chains with pinned contracts: ${[...DIRECT_PAYMENT_CHAIN_IDS].join(", ")}; the child says ${String(td.domain?.chainId)}.`
|
|
978
|
+
);
|
|
979
|
+
}
|
|
980
|
+
if (domainChain !== expected.chainId) {
|
|
981
|
+
refuseTaskChild(
|
|
982
|
+
"it is scoped to the wrong chain",
|
|
983
|
+
`Expected chain ${expected.chainId}; the child says ${td.domain?.chainId}.`
|
|
984
|
+
);
|
|
985
|
+
}
|
|
986
|
+
const ownAccount = chunk3SVPI4LS_cjs.deriveDelegateAccountAddress(delegateAddress);
|
|
987
|
+
const delegator = td.message?.delegator;
|
|
988
|
+
if (typeof delegator !== "string" || !same(delegator, ownAccount)) {
|
|
989
|
+
refuseTaskChild(
|
|
990
|
+
"it is not delegated by this agent's own account",
|
|
991
|
+
`Expected delegator ${ownAccount}; the child names ${String(delegator)}.`
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
const delegate = td.message?.delegate;
|
|
995
|
+
if (typeof delegate !== "string" || !same(delegate, ownAccount)) {
|
|
996
|
+
refuseTaskChild(
|
|
997
|
+
"it is not self-delegated to this agent's own account",
|
|
998
|
+
`Expected delegate ${ownAccount}; the child names ${String(delegate)}.`
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
const authority = td.message?.authority;
|
|
1002
|
+
if (typeof authority !== "string" || !/^0x[0-9a-fA-F]{64}$/.test(authority)) {
|
|
1003
|
+
refuseTaskChild("its authority is not a 32-byte delegation hash", `Got ${String(authority)}.`);
|
|
1004
|
+
}
|
|
1005
|
+
if (authority.toLowerCase() === chunk3SVPI4LS_cjs.ROOT_AUTHORITY) {
|
|
1006
|
+
refuseTaskChild(
|
|
1007
|
+
"it is a ROOT delegation, not a re-delegation of the agent budget",
|
|
1008
|
+
"A task budget always chains under the agent budget delegation."
|
|
1009
|
+
);
|
|
1010
|
+
}
|
|
1011
|
+
if (!same(authority, expected.parentDelegationHash)) {
|
|
1012
|
+
refuseTaskChild(
|
|
1013
|
+
"it chains under a different parent delegation",
|
|
1014
|
+
`Expected authority ${expected.parentDelegationHash}; the child says ${authority}.`
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
const caveats = td.message?.caveats ?? [];
|
|
1018
|
+
const transfer = findCaveat(caveats, chunk3SVPI4LS_cjs.CAVEAT_ENFORCERS.erc20TransferAmount);
|
|
1019
|
+
if (!transfer) {
|
|
1020
|
+
refuseTaskChild(
|
|
1021
|
+
"it has no ERC-20 transfer-amount caveat",
|
|
1022
|
+
"Without it the child is not bounded to an amount."
|
|
1023
|
+
);
|
|
1024
|
+
}
|
|
1025
|
+
const token = `0x${slice(transfer.terms, 0, 20)}`;
|
|
1026
|
+
if (!same(token, expected.tokenAddress)) {
|
|
1027
|
+
refuseTaskChild("it spends a different token", `Expected ${expected.tokenAddress}, child pins ${token}.`);
|
|
1028
|
+
}
|
|
1029
|
+
const amount = BigInt(`0x${slice(transfer.terms, 20, 52)}`);
|
|
1030
|
+
if (amount !== BigInt(expected.maxAmountAtomic)) {
|
|
1031
|
+
refuseTaskChild(
|
|
1032
|
+
"the amount does not match",
|
|
1033
|
+
`Expected ${expected.maxAmountAtomic}; the child allows ${amount.toString()}.`
|
|
1034
|
+
);
|
|
1035
|
+
}
|
|
1036
|
+
const timestamp = findCaveat(caveats, chunk3SVPI4LS_cjs.CAVEAT_ENFORCERS.timestamp);
|
|
1037
|
+
if (!timestamp) {
|
|
1038
|
+
refuseTaskChild("it never expires", "A task-budget child without a timestamp caveat is open-ended.");
|
|
1039
|
+
}
|
|
1040
|
+
const beforeThreshold = Number(BigInt(`0x${slice(timestamp.terms, 16, 32)}`));
|
|
1041
|
+
const nowSec = Math.floor(now / 1e3);
|
|
1042
|
+
if (beforeThreshold <= nowSec) {
|
|
1043
|
+
refuseTaskChild("it has already expired", `Expiry ${beforeThreshold} is not in the future.`);
|
|
1044
|
+
}
|
|
1045
|
+
if (beforeThreshold > nowSec + MAX_TASK_BUDGET_TTL_SECONDS) {
|
|
1046
|
+
refuseTaskChild(
|
|
1047
|
+
"its window is longer than a task budget may live",
|
|
1048
|
+
`Expiry is ${beforeThreshold - nowSec}s out; the ceiling is ${MAX_TASK_BUDGET_TTL_SECONDS}s.`
|
|
1049
|
+
);
|
|
1050
|
+
}
|
|
1051
|
+
if (beforeThreshold !== expected.expiresAt) {
|
|
1052
|
+
refuseTaskChild(
|
|
1053
|
+
"its expiry does not match what Haven declared",
|
|
1054
|
+
`Expected ${expected.expiresAt}; the child says ${beforeThreshold}.`
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
const calldata = findCaveat(caveats, chunk3SVPI4LS_cjs.CAVEAT_ENFORCERS.allowedCalldata);
|
|
1058
|
+
if (expected.recipientAddress) {
|
|
1059
|
+
if (!calldata) {
|
|
1060
|
+
refuseTaskChild(
|
|
1061
|
+
"it has no recipient pin",
|
|
1062
|
+
"The task budget was opened with a pinned recipient, so the child must carry one."
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
const startIndex = BigInt(`0x${slice(calldata.terms, 0, 32)}`);
|
|
1066
|
+
if (startIndex !== 4n) {
|
|
1067
|
+
refuseTaskChild(
|
|
1068
|
+
"the recipient pin points at the wrong calldata offset",
|
|
1069
|
+
`Expected offset 4, got ${startIndex.toString()}.`
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
const paddedRecipient = slice(calldata.terms, 32, 64);
|
|
1073
|
+
if (paddedRecipient.slice(0, 24) !== "0".repeat(24)) {
|
|
1074
|
+
refuseTaskChild("the pinned recipient is not a plain address", "Its 32-byte word is not a padded address.");
|
|
1075
|
+
}
|
|
1076
|
+
const recipient = `0x${paddedRecipient.slice(24)}`;
|
|
1077
|
+
if (!same(recipient, expected.recipientAddress)) {
|
|
1078
|
+
refuseTaskChild(
|
|
1079
|
+
"it pins a different recipient than Haven declared",
|
|
1080
|
+
`Expected ${expected.recipientAddress}; the child pins ${recipient}.`
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
} else if (calldata) {
|
|
1084
|
+
refuseTaskChild(
|
|
1085
|
+
"it pins a recipient the task budget was not opened with",
|
|
1086
|
+
"This task budget is open (no recipient pin); the child must not add one."
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
var DISABLE_DELEGATION_ABI = [
|
|
1091
|
+
{
|
|
1092
|
+
type: "function",
|
|
1093
|
+
name: "disableDelegation",
|
|
1094
|
+
inputs: [{ name: "delegation", type: "tuple", components: chunk3SVPI4LS_cjs.DELEGATION_TUPLE_COMPONENTS }],
|
|
1095
|
+
outputs: [],
|
|
1096
|
+
stateMutability: "nonpayable"
|
|
1097
|
+
}
|
|
1098
|
+
];
|
|
1099
|
+
function assertOwnTaskBudgetCloseUserOp(typedData, expected, delegateAddress) {
|
|
1100
|
+
const domain = typedData.domain ?? {};
|
|
1101
|
+
const message = typedData.message ?? {};
|
|
1102
|
+
if (typeof domain.chainId !== "number" && typeof domain.chainId !== "bigint") {
|
|
1103
|
+
throw new HavenTypedDataRefusedError(
|
|
1104
|
+
`This close UserOperation's domain.chainId is ${typeof domain.chainId} (${String(domain.chainId)}), not a number \u2014 refusing rather than risk signing a different EIP-712 domain than this check evaluated.`
|
|
1105
|
+
);
|
|
1106
|
+
}
|
|
1107
|
+
const chainId = Number(domain.chainId);
|
|
1108
|
+
if (!DIRECT_PAYMENT_CHAIN_IDS.has(chainId)) {
|
|
1109
|
+
throw new HavenTypedDataRefusedError(
|
|
1110
|
+
`This signer only signs a task-budget close on chains the delegation rail has pinned contracts for (${[...DIRECT_PAYMENT_CHAIN_IDS].join(", ")}); this typed data names chain ${String(domain.chainId)}. Refusing.`
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
const ownAccount = chunk3SVPI4LS_cjs.deriveDelegateAccountAddress(delegateAddress);
|
|
1114
|
+
const sender = typeof message.sender === "string" ? message.sender : "";
|
|
1115
|
+
if (sender.toLowerCase() !== ownAccount.toLowerCase()) {
|
|
1116
|
+
throw new HavenTypedDataRefusedError(
|
|
1117
|
+
`This close UserOperation's account (${sender || "unknown"}) is not this signer's own delegate account (${ownAccount}). Sign only your own agent's Haven-prepared payloads.`
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
const callData = message.callData;
|
|
1121
|
+
let decoded;
|
|
1122
|
+
try {
|
|
1123
|
+
const { args } = viem.decodeFunctionData({ abi: EXECUTE_ABI, data: callData });
|
|
1124
|
+
decoded = args[0];
|
|
1125
|
+
} catch {
|
|
1126
|
+
throw new HavenTypedDataRefusedError(
|
|
1127
|
+
"This close UserOperation's callData is not a single execute((address,uint256,bytes)) call. This signer only signs a task-budget close of that exact shape."
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
const reEncodedExecute = viem.encodeFunctionData({ abi: EXECUTE_ABI, functionName: "execute", args: [decoded] });
|
|
1131
|
+
if (reEncodedExecute.toLowerCase() !== callData.toLowerCase()) {
|
|
1132
|
+
throw new HavenTypedDataRefusedError(
|
|
1133
|
+
"This close UserOperation's execute() call does not re-encode to the exact callData bytes (trailing or non-canonical bytes). Refusing."
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
if (decoded.target.toLowerCase() !== chunk3SVPI4LS_cjs.DELEGATION_MANAGER.toLowerCase()) {
|
|
1137
|
+
throw new HavenTypedDataRefusedError(
|
|
1138
|
+
`This close UserOperation's execute() calls ${decoded.target}, not the DelegationManager (${chunk3SVPI4LS_cjs.DELEGATION_MANAGER}). Refusing what looks like a self-call or a call to an unrelated contract.`
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
if (decoded.value !== 0n) {
|
|
1142
|
+
throw new HavenTypedDataRefusedError(
|
|
1143
|
+
`This close UserOperation's execute() sends ${decoded.value} wei of native value alongside the DelegationManager call \u2014 a task-budget close never does. Refusing.`
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
let delegation;
|
|
1147
|
+
try {
|
|
1148
|
+
const { args } = viem.decodeFunctionData({ abi: DISABLE_DELEGATION_ABI, data: decoded.callData });
|
|
1149
|
+
delegation = args[0];
|
|
1150
|
+
} catch {
|
|
1151
|
+
throw new HavenTypedDataRefusedError(
|
|
1152
|
+
"This close UserOperation's execute() does not call disableDelegation(Delegation) \u2014 this signer only signs a task-budget close of that exact shape."
|
|
1153
|
+
);
|
|
1154
|
+
}
|
|
1155
|
+
const reEncodedDisable = viem.encodeFunctionData({
|
|
1156
|
+
abi: DISABLE_DELEGATION_ABI,
|
|
1157
|
+
functionName: "disableDelegation",
|
|
1158
|
+
args: [delegation]
|
|
1159
|
+
});
|
|
1160
|
+
if (reEncodedDisable.toLowerCase() !== decoded.callData.toLowerCase()) {
|
|
1161
|
+
throw new HavenTypedDataRefusedError(
|
|
1162
|
+
"This close UserOperation's disableDelegation call does not re-encode to the exact bytes signed (trailing or non-canonical bytes). Refusing."
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
if (delegation.delegator.toLowerCase() !== ownAccount.toLowerCase()) {
|
|
1166
|
+
throw new HavenTypedDataRefusedError(
|
|
1167
|
+
`This close UserOperation disables a delegation granted by ${delegation.delegator}, not this signer's own account (${ownAccount}). Refusing.`
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
if (delegation.delegate.toLowerCase() !== ownAccount.toLowerCase()) {
|
|
1171
|
+
throw new HavenTypedDataRefusedError(
|
|
1172
|
+
`This close UserOperation disables a delegation granted to ${delegation.delegate}, not this signer's own account (${ownAccount}) \u2014 a task-budget child is always self-delegated. Refusing.`
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
if (delegation.authority.toLowerCase() === chunk3SVPI4LS_cjs.ROOT_AUTHORITY) {
|
|
1176
|
+
throw new HavenTypedDataRefusedError(
|
|
1177
|
+
"This close UserOperation disables a ROOT delegation, not a re-delegation of the agent budget. A task-budget child always chains under the agent budget delegation. Refusing."
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
const actualHash = hashDelegation(delegation);
|
|
1181
|
+
if (actualHash.toLowerCase() !== expected.delegationHash.toLowerCase()) {
|
|
1182
|
+
throw new HavenTypedDataRefusedError(
|
|
1183
|
+
`This close UserOperation disables delegation ${actualHash}, not the task budget's own child (${expected.delegationHash}). Refusing.`
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
var DELEGATION_TYPEHASH = "0x88c1d2ecf185adf710588203a5f263f0ff61be0d33da39792cde19ba9aa4331e";
|
|
1188
|
+
var CAVEAT_TYPEHASH = "0x80ad7e1b04ee6d994a125f4714ca0720908bd80ed16063ec8aee4b88e9253e2d";
|
|
1189
|
+
function hashCaveat(caveat) {
|
|
1190
|
+
const termsHash = viem.keccak256(caveat.terms);
|
|
1191
|
+
const encoded = viem.encodeAbiParameters(
|
|
1192
|
+
[{ type: "bytes32" }, { type: "address" }, { type: "bytes32" }],
|
|
1193
|
+
[CAVEAT_TYPEHASH, caveat.enforcer, termsHash]
|
|
1194
|
+
);
|
|
1195
|
+
return viem.keccak256(encoded);
|
|
1196
|
+
}
|
|
1197
|
+
function hashCaveatsArray(caveats) {
|
|
1198
|
+
const concatenated = `0x${caveats.map((c) => hashCaveat(c).slice(2)).join("")}`;
|
|
1199
|
+
return viem.keccak256(concatenated);
|
|
1200
|
+
}
|
|
1201
|
+
function hashDelegation(delegation) {
|
|
1202
|
+
const caveatsHash = hashCaveatsArray(delegation.caveats);
|
|
1203
|
+
const encoded = viem.encodeAbiParameters(
|
|
1204
|
+
[
|
|
1205
|
+
{ type: "bytes32" },
|
|
1206
|
+
{ type: "address" },
|
|
1207
|
+
{ type: "address" },
|
|
1208
|
+
{ type: "bytes32" },
|
|
1209
|
+
{ type: "bytes32" },
|
|
1210
|
+
{ type: "uint256" }
|
|
1211
|
+
],
|
|
1212
|
+
[DELEGATION_TYPEHASH, delegation.delegate, delegation.delegator, delegation.authority, caveatsHash, delegation.salt]
|
|
1213
|
+
);
|
|
1214
|
+
return viem.keccak256(encoded);
|
|
1215
|
+
}
|
|
901
1216
|
|
|
1217
|
+
exports.CAVEAT_TYPEHASH = CAVEAT_TYPEHASH;
|
|
902
1218
|
exports.DEFAULT_NEXT_TOOL_BY_ACTION = DEFAULT_NEXT_TOOL_BY_ACTION;
|
|
1219
|
+
exports.DELEGATION_TYPEHASH = DELEGATION_TYPEHASH;
|
|
903
1220
|
exports.DIRECT_PAYMENT_CHAIN_IDS = DIRECT_PAYMENT_CHAIN_IDS;
|
|
904
1221
|
exports.ERC7710_ASSET_TRANSFER_METHOD = ERC7710_ASSET_TRANSFER_METHOD;
|
|
905
1222
|
exports.EXECUTE_ABI = EXECUTE_ABI;
|
|
906
1223
|
exports.HAVEN_CLIENT_HEADER = HAVEN_CLIENT_HEADER;
|
|
907
1224
|
exports.HAVEN_MINIMUM_NODE_VERSION = HAVEN_MINIMUM_NODE_VERSION;
|
|
908
1225
|
exports.HavenTypedDataRefusedError = HavenTypedDataRefusedError;
|
|
1226
|
+
exports.MAX_TASK_BUDGET_TTL_SECONDS = MAX_TASK_BUDGET_TTL_SECONDS;
|
|
909
1227
|
exports.NEXT_TOOL_SERVER_NAMES = NEXT_TOOL_SERVER_NAMES;
|
|
910
1228
|
exports.NEXT_TOOL_SERVER_ROLES = NEXT_TOOL_SERVER_ROLES;
|
|
911
1229
|
exports.SDK_CLIENT_IDENTITY = SDK_CLIENT_IDENTITY;
|
|
@@ -928,6 +1246,8 @@ exports.X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = X402_SETTLEMENT_FORWARD_MARGIN_
|
|
|
928
1246
|
exports.assertBoundDirectPaymentUserOp = assertBoundDirectPaymentUserOp;
|
|
929
1247
|
exports.assertFundingLegPaysDelegate = assertFundingLegPaysDelegate;
|
|
930
1248
|
exports.assertOwnSettlementChild = assertOwnSettlementChild;
|
|
1249
|
+
exports.assertOwnTaskBudgetCloseUserOp = assertOwnTaskBudgetCloseUserOp;
|
|
1250
|
+
exports.assertOwnTaskChild = assertOwnTaskChild;
|
|
931
1251
|
exports.buildSweepAuthorizationMessage = buildSweepAuthorizationMessage;
|
|
932
1252
|
exports.buildSweepTypedData = buildSweepTypedData;
|
|
933
1253
|
exports.buildX402ExpectedMessage = buildX402ExpectedMessage;
|
|
@@ -940,16 +1260,19 @@ exports.defaultNextToolFor = defaultNextToolFor;
|
|
|
940
1260
|
exports.encodeBase64Json = encodeBase64Json;
|
|
941
1261
|
exports.encodeBase64Utf8 = encodeBase64Utf8;
|
|
942
1262
|
exports.encodePaymentProof = encodePaymentProof;
|
|
1263
|
+
exports.hashDelegation = hashDelegation;
|
|
943
1264
|
exports.havenClientIdentity = havenClientIdentity;
|
|
944
1265
|
exports.isErc7710Option = isErc7710Option;
|
|
945
1266
|
exports.isSupportedNodeVersion = isSupportedNodeVersion;
|
|
946
1267
|
exports.isSweepableChain = isSweepableChain;
|
|
1268
|
+
exports.isTaskChildTypedData = isTaskChildTypedData;
|
|
947
1269
|
exports.normalizePaymentRequired = normalizePaymentRequired;
|
|
948
1270
|
exports.parseNextTool = parseNextTool;
|
|
949
1271
|
exports.parsePaymentRequired = parsePaymentRequired;
|
|
950
1272
|
exports.parsePaymentRequiredResponse = parsePaymentRequiredResponse;
|
|
951
1273
|
exports.readClientUpdate = readClientUpdate;
|
|
952
1274
|
exports.renderNextTool = renderNextTool;
|
|
1275
|
+
exports.resolveTokenBySymbol = resolveTokenBySymbol;
|
|
953
1276
|
exports.resolveTokenFromAddress = resolveTokenFromAddress;
|
|
954
1277
|
exports.selectErc7710PaymentOption = selectErc7710PaymentOption;
|
|
955
1278
|
exports.selectPaymentOption = selectPaymentOption;
|
|
@@ -966,5 +1289,5 @@ exports.x402FacilitatorAddresses = x402FacilitatorAddresses;
|
|
|
966
1289
|
exports.x402PaymentHeaderNamesFor = x402PaymentHeaderNamesFor;
|
|
967
1290
|
exports.x402PaymentHeaderNamesSent = x402PaymentHeaderNamesSent;
|
|
968
1291
|
exports.x402V2PaymentEnvelope = x402V2PaymentEnvelope;
|
|
969
|
-
//# sourceMappingURL=chunk-
|
|
970
|
-
//# sourceMappingURL=chunk-
|
|
1292
|
+
//# sourceMappingURL=chunk-J6DQEBK2.cjs.map
|
|
1293
|
+
//# sourceMappingURL=chunk-J6DQEBK2.cjs.map
|