@virtuals-protocol/acp-node 0.3.0-beta.38 → 0.3.0-beta.39

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.js CHANGED
@@ -35,7 +35,7 @@ var require_package = __commonJS({
35
35
  "package.json"(exports2, module2) {
36
36
  module2.exports = {
37
37
  name: "@virtuals-protocol/acp-node",
38
- version: "0.3.0-beta.38",
38
+ version: "0.3.0-beta.39",
39
39
  main: "./dist/index.js",
40
40
  module: "./dist/index.mjs",
41
41
  types: "./dist/index.d.ts",
@@ -86,6 +86,7 @@ var require_package = __commonJS({
86
86
  var index_exports = {};
87
87
  __export(index_exports, {
88
88
  ACP_ABI: () => acpAbi_default,
89
+ AcpAccount: () => AcpAccount,
89
90
  AcpAgent: () => acpAgent_default,
90
91
  AcpAgentSort: () => AcpAgentSort,
91
92
  AcpContractClient: () => acpContractClient_default,
@@ -104,6 +105,7 @@ __export(index_exports, {
104
105
  FareAmount: () => FareAmount,
105
106
  FareBigInt: () => FareBigInt,
106
107
  MemoType: () => MemoType,
108
+ PriceType: () => PriceType,
107
109
  baseAcpConfig: () => baseAcpConfig,
108
110
  baseAcpConfigV2: () => baseAcpConfigV2,
109
111
  baseAcpX402Config: () => baseAcpX402Config,
@@ -1383,7 +1385,7 @@ var FareAmount = class extends FareAmountBase {
1383
1385
  super(fare.formatAmount(truncateTo6Decimals(fareAmount.toString())), fare);
1384
1386
  }
1385
1387
  add(other) {
1386
- if (this.fare.contractAddress !== other.fare.contractAddress) {
1388
+ if (this.fare.contractAddress.toLowerCase() !== other.fare.contractAddress.toLowerCase()) {
1387
1389
  throw new Error("Token addresses do not match");
1388
1390
  }
1389
1391
  return new FareBigInt(this.amount + other.amount, this.fare);
@@ -1416,6 +1418,10 @@ var ACP_V2_ABI = [
1416
1418
  name: "AccessControlUnauthorizedAccount",
1417
1419
  type: "error"
1418
1420
  },
1421
+ { inputs: [], name: "AccountAlreadySubscribed", type: "error" },
1422
+ { inputs: [], name: "AccountDoesNotExist", type: "error" },
1423
+ { inputs: [], name: "AccountManagerNotSet", type: "error" },
1424
+ { inputs: [], name: "AccountNotActive", type: "error" },
1419
1425
  {
1420
1426
  inputs: [{ internalType: "address", name: "target", type: "address" }],
1421
1427
  name: "AddressEmptyCode",
@@ -1426,6 +1432,13 @@ var ACP_V2_ABI = [
1426
1432
  name: "AddressInsufficientBalance",
1427
1433
  type: "error"
1428
1434
  },
1435
+ { inputs: [], name: "AmountMustBeGreaterThanZero", type: "error" },
1436
+ { inputs: [], name: "AmountOrFeeRequired", type: "error" },
1437
+ { inputs: [], name: "AssetManagerNotSet", type: "error" },
1438
+ { inputs: [], name: "BudgetNotReceived", type: "error" },
1439
+ { inputs: [], name: "CannotSetBudgetOnSubscriptionJob", type: "error" },
1440
+ { inputs: [], name: "DestinationEndpointRequired", type: "error" },
1441
+ { inputs: [], name: "DurationMustBeGreaterThanZero", type: "error" },
1429
1442
  {
1430
1443
  inputs: [
1431
1444
  { internalType: "address", name: "implementation", type: "address" }
@@ -1435,22 +1448,46 @@ var ACP_V2_ABI = [
1435
1448
  },
1436
1449
  { inputs: [], name: "ERC1967NonPayable", type: "error" },
1437
1450
  { inputs: [], name: "EnforcedPause", type: "error" },
1451
+ { inputs: [], name: "EvaluatorFeeTooHigh", type: "error" },
1438
1452
  { inputs: [], name: "ExpectedPause", type: "error" },
1453
+ { inputs: [], name: "ExpiredAtMustBeInFuture", type: "error" },
1454
+ { inputs: [], name: "ExpiryTooShort", type: "error" },
1439
1455
  { inputs: [], name: "FailedInnerCall", type: "error" },
1456
+ { inputs: [], name: "InvalidCrossChainMemoType", type: "error" },
1440
1457
  { inputs: [], name: "InvalidInitialization", type: "error" },
1458
+ { inputs: [], name: "InvalidMemoType", type: "error" },
1459
+ { inputs: [], name: "InvalidModuleType", type: "error" },
1460
+ { inputs: [], name: "InvalidPaymentToken", type: "error" },
1461
+ { inputs: [], name: "InvalidRecipient", type: "error" },
1462
+ { inputs: [], name: "JobManagerNotSet", type: "error" },
1463
+ { inputs: [], name: "MemoManagerNotSet", type: "error" },
1441
1464
  { inputs: [], name: "NotInitializing", type: "error" },
1465
+ { inputs: [], name: "OnlyClient", type: "error" },
1466
+ { inputs: [], name: "OnlyMemoManager", type: "error" },
1467
+ { inputs: [], name: "OnlyProvider", type: "error" },
1468
+ { inputs: [], name: "PaymentManagerNotSet", type: "error" },
1469
+ { inputs: [], name: "PlatformFeeTooHigh", type: "error" },
1442
1470
  { inputs: [], name: "ReentrancyGuardReentrantCall", type: "error" },
1443
1471
  {
1444
1472
  inputs: [{ internalType: "address", name: "token", type: "address" }],
1445
1473
  name: "SafeERC20FailedOperation",
1446
1474
  type: "error"
1447
1475
  },
1476
+ { inputs: [], name: "SubscriptionAccountExpired", type: "error" },
1477
+ { inputs: [], name: "SubscriptionJobMustHaveZeroBudget", type: "error" },
1478
+ { inputs: [], name: "SubscriptionJobMustHaveZeroBudgetMemo", type: "error" },
1479
+ { inputs: [], name: "TokenAddressRequired", type: "error" },
1480
+ { inputs: [], name: "TokenMustBeERC20", type: "error" },
1448
1481
  { inputs: [], name: "UUPSUnauthorizedCallContext", type: "error" },
1449
1482
  {
1450
1483
  inputs: [{ internalType: "bytes32", name: "slot", type: "bytes32" }],
1451
1484
  name: "UUPSUnsupportedProxiableUUID",
1452
1485
  type: "error"
1453
1486
  },
1487
+ { inputs: [], name: "UnableToRefund", type: "error" },
1488
+ { inputs: [], name: "Unauthorized", type: "error" },
1489
+ { inputs: [], name: "ZeroAddress", type: "error" },
1490
+ { inputs: [], name: "ZeroAddressProvider", type: "error" },
1454
1491
  {
1455
1492
  anonymous: false,
1456
1493
  inputs: [
@@ -1490,56 +1527,6 @@ var ACP_V2_ABI = [
1490
1527
  name: "AccountStatusUpdated",
1491
1528
  type: "event"
1492
1529
  },
1493
- {
1494
- anonymous: false,
1495
- inputs: [
1496
- {
1497
- indexed: false,
1498
- internalType: "uint256",
1499
- name: "jobId",
1500
- type: "uint256"
1501
- },
1502
- {
1503
- indexed: true,
1504
- internalType: "address",
1505
- name: "evaluator",
1506
- type: "address"
1507
- },
1508
- {
1509
- indexed: false,
1510
- internalType: "uint256",
1511
- name: "evaluatorFee",
1512
- type: "uint256"
1513
- }
1514
- ],
1515
- name: "ClaimedEvaluatorFee",
1516
- type: "event"
1517
- },
1518
- {
1519
- anonymous: false,
1520
- inputs: [
1521
- {
1522
- indexed: false,
1523
- internalType: "uint256",
1524
- name: "jobId",
1525
- type: "uint256"
1526
- },
1527
- {
1528
- indexed: true,
1529
- internalType: "address",
1530
- name: "provider",
1531
- type: "address"
1532
- },
1533
- {
1534
- indexed: false,
1535
- internalType: "uint256",
1536
- name: "providerFee",
1537
- type: "uint256"
1538
- }
1539
- ],
1540
- name: "ClaimedProviderFee",
1541
- type: "event"
1542
- },
1543
1530
  {
1544
1531
  anonymous: false,
1545
1532
  inputs: [
@@ -1591,31 +1578,6 @@ var ACP_V2_ABI = [
1591
1578
  name: "Paused",
1592
1579
  type: "event"
1593
1580
  },
1594
- {
1595
- anonymous: false,
1596
- inputs: [
1597
- {
1598
- indexed: false,
1599
- internalType: "uint256",
1600
- name: "jobId",
1601
- type: "uint256"
1602
- },
1603
- {
1604
- indexed: true,
1605
- internalType: "address",
1606
- name: "client",
1607
- type: "address"
1608
- },
1609
- {
1610
- indexed: false,
1611
- internalType: "uint256",
1612
- name: "amount",
1613
- type: "uint256"
1614
- }
1615
- ],
1616
- name: "RefundedBudget",
1617
- type: "event"
1618
- },
1619
1581
  {
1620
1582
  anonymous: false,
1621
1583
  inputs: [
@@ -1763,6 +1725,13 @@ var ACP_V2_ABI = [
1763
1725
  stateMutability: "nonpayable",
1764
1726
  type: "function"
1765
1727
  },
1728
+ {
1729
+ inputs: [{ internalType: "uint256", name: "jobId", type: "uint256" }],
1730
+ name: "claimBudgetFromMemoManager",
1731
+ outputs: [],
1732
+ stateMutability: "nonpayable",
1733
+ type: "function"
1734
+ },
1766
1735
  {
1767
1736
  inputs: [
1768
1737
  { internalType: "address", name: "provider", type: "address" },
@@ -1876,6 +1845,28 @@ var ACP_V2_ABI = [
1876
1845
  stateMutability: "nonpayable",
1877
1846
  type: "function"
1878
1847
  },
1848
+ {
1849
+ inputs: [
1850
+ { internalType: "uint256", name: "jobId", type: "uint256" },
1851
+ { internalType: "string", name: "content", type: "string" },
1852
+ { internalType: "address", name: "token", type: "address" },
1853
+ { internalType: "uint256", name: "amount", type: "uint256" },
1854
+ { internalType: "address", name: "recipient", type: "address" },
1855
+ { internalType: "uint256", name: "feeAmount", type: "uint256" },
1856
+ { internalType: "enum ACPTypes.FeeType", name: "feeType", type: "uint8" },
1857
+ { internalType: "uint256", name: "duration", type: "uint256" },
1858
+ { internalType: "uint256", name: "expiredAt", type: "uint256" },
1859
+ {
1860
+ internalType: "enum ACPTypes.JobPhase",
1861
+ name: "nextPhase",
1862
+ type: "uint8"
1863
+ }
1864
+ ],
1865
+ name: "createSubscriptionMemo",
1866
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
1867
+ stateMutability: "nonpayable",
1868
+ type: "function"
1869
+ },
1879
1870
  {
1880
1871
  inputs: [
1881
1872
  { internalType: "address", name: "provider", type: "address" },
@@ -1944,7 +1935,8 @@ var ACP_V2_ABI = [
1944
1935
  name: "completedJobCount",
1945
1936
  type: "uint256"
1946
1937
  },
1947
- { internalType: "bool", name: "isActive", type: "bool" }
1938
+ { internalType: "bool", name: "isActive", type: "bool" },
1939
+ { internalType: "uint256", name: "expiry", type: "uint256" }
1948
1940
  ],
1949
1941
  internalType: "struct ACPTypes.Account",
1950
1942
  name: "",
@@ -2101,13 +2093,6 @@ var ACP_V2_ABI = [
2101
2093
  stateMutability: "view",
2102
2094
  type: "function"
2103
2095
  },
2104
- {
2105
- inputs: [],
2106
- name: "getPhases",
2107
- outputs: [{ internalType: "string[7]", name: "", type: "string[7]" }],
2108
- stateMutability: "pure",
2109
- type: "function"
2110
- },
2111
2096
  {
2112
2097
  inputs: [{ internalType: "bytes32", name: "role", type: "bytes32" }],
2113
2098
  name: "getRoleAdmin",
@@ -2152,11 +2137,8 @@ var ACP_V2_ABI = [
2152
2137
  type: "function"
2153
2138
  },
2154
2139
  {
2155
- inputs: [
2156
- { internalType: "uint256", name: "jobId", type: "uint256" },
2157
- { internalType: "address", name: "account", type: "address" }
2158
- ],
2159
- name: "isJobEvaluator",
2140
+ inputs: [{ internalType: "uint256", name: "jobId", type: "uint256" }],
2141
+ name: "isSubscriptionJob",
2160
2142
  outputs: [{ internalType: "bool", name: "", type: "bool" }],
2161
2143
  stateMutability: "view",
2162
2144
  type: "function"
@@ -2264,6 +2246,13 @@ var ACP_V2_ABI = [
2264
2246
  stateMutability: "nonpayable",
2265
2247
  type: "function"
2266
2248
  },
2249
+ {
2250
+ inputs: [{ internalType: "uint256", name: "jobId", type: "uint256" }],
2251
+ name: "setupEscrowFromMemoManager",
2252
+ outputs: [],
2253
+ stateMutability: "nonpayable",
2254
+ type: "function"
2255
+ },
2267
2256
  {
2268
2257
  inputs: [
2269
2258
  { internalType: "uint256", name: "memoId", type: "uint256" },
@@ -2299,6 +2288,18 @@ var ACP_V2_ABI = [
2299
2288
  stateMutability: "nonpayable",
2300
2289
  type: "function"
2301
2290
  },
2291
+ {
2292
+ inputs: [
2293
+ { internalType: "uint256", name: "accountId", type: "uint256" },
2294
+ { internalType: "uint256", name: "duration", type: "uint256" },
2295
+ { internalType: "string", name: "metadata", type: "string" },
2296
+ { internalType: "address", name: "provider", type: "address" }
2297
+ ],
2298
+ name: "updateAccountSubscriptionFromMemoManager",
2299
+ outputs: [],
2300
+ stateMutability: "nonpayable",
2301
+ type: "function"
2302
+ },
2302
2303
  {
2303
2304
  inputs: [
2304
2305
  { internalType: "uint256", name: "evaluatorFeeBP_", type: "uint256" }
@@ -3646,6 +3647,7 @@ var MemoType = /* @__PURE__ */ ((MemoType3) => {
3646
3647
  MemoType3[MemoType3["PAYABLE_TRANSFER_ESCROW"] = 8] = "PAYABLE_TRANSFER_ESCROW";
3647
3648
  MemoType3[MemoType3["NOTIFICATION"] = 9] = "NOTIFICATION";
3648
3649
  MemoType3[MemoType3["PAYABLE_NOTIFICATION"] = 10] = "PAYABLE_NOTIFICATION";
3650
+ MemoType3[MemoType3["PAYABLE_REQUEST_SUBSCRIPTION"] = 11] = "PAYABLE_REQUEST_SUBSCRIPTION";
3649
3651
  return MemoType3;
3650
3652
  })(MemoType || {});
3651
3653
  var AcpJobPhases = /* @__PURE__ */ ((AcpJobPhases3) => {
@@ -3714,6 +3716,35 @@ ${JSON.stringify(
3714
3716
  );
3715
3717
  }
3716
3718
  }
3719
+ /**
3720
+ * Returns a createAccount operation payload if the contract supports it (V2).
3721
+ * Returns null for V1 or when the ABI does not include createAccount.
3722
+ */
3723
+ createAccount(providerAddress, metadata) {
3724
+ try {
3725
+ const hasCreateAccount = this.abi.some(
3726
+ (item) => item.type === "function" && item.name === "createAccount"
3727
+ );
3728
+ if (!hasCreateAccount) return null;
3729
+ const data = (0, import_viem2.encodeFunctionData)({
3730
+ abi: this.abi,
3731
+ functionName: "createAccount",
3732
+ args: [providerAddress, metadata]
3733
+ });
3734
+ return {
3735
+ data,
3736
+ contractAddress: this.contractAddress
3737
+ };
3738
+ } catch {
3739
+ return null;
3740
+ }
3741
+ }
3742
+ /**
3743
+ * Returns the new account id from a createAccount user op receipt, or null if not supported.
3744
+ */
3745
+ async getAccountIdFromUserOpHash(_userOpHash) {
3746
+ return null;
3747
+ }
3717
3748
  get walletAddress() {
3718
3749
  return this.agentWalletAddress;
3719
3750
  }
@@ -3806,6 +3837,33 @@ ${JSON.stringify(
3806
3837
  throw new acpError_default("Failed to create payable memo", error);
3807
3838
  }
3808
3839
  }
3840
+ createSubscriptionMemo(jobId, content, amountBaseUnit, recipient, feeAmountBaseUnit, feeType, duration, nextPhase, expiredAt, token = this.config.baseFare.contractAddress) {
3841
+ try {
3842
+ const data = (0, import_viem2.encodeFunctionData)({
3843
+ abi: this.abi,
3844
+ functionName: "createSubscriptionMemo",
3845
+ args: [
3846
+ jobId,
3847
+ content,
3848
+ token,
3849
+ amountBaseUnit,
3850
+ recipient,
3851
+ feeAmountBaseUnit,
3852
+ feeType,
3853
+ duration,
3854
+ Math.floor(expiredAt.getTime() / 1e3),
3855
+ nextPhase
3856
+ ]
3857
+ });
3858
+ const payload = {
3859
+ data,
3860
+ contractAddress: this.contractAddress
3861
+ };
3862
+ return payload;
3863
+ } catch (error) {
3864
+ throw new acpError_default("Failed to create subscription memo", error);
3865
+ }
3866
+ }
3809
3867
  createCrossChainPayableMemo(jobId, content, token, amountBaseUnit, recipient, feeAmountBaseUnit, feeType, type, expiredAt, nextPhase, destinationEid, secured = true) {
3810
3868
  try {
3811
3869
  const data = (0, import_viem2.encodeFunctionData)({
@@ -4121,8 +4179,35 @@ function appendBuilderCodeData(data, suffix) {
4121
4179
  // src/acpJobOffering.ts
4122
4180
  var import_viem4 = require("viem");
4123
4181
  var import_ajv = __toESM(require("ajv"));
4182
+
4183
+ // src/acpAccount.ts
4184
+ var AcpAccount = class {
4185
+ constructor(contractClient, id, clientAddress, providerAddress, metadata, expiryAt) {
4186
+ this.contractClient = contractClient;
4187
+ this.id = id;
4188
+ this.clientAddress = clientAddress;
4189
+ this.providerAddress = providerAddress;
4190
+ this.metadata = metadata;
4191
+ this.expiryAt = expiryAt;
4192
+ }
4193
+ async updateMetadata(metadata) {
4194
+ const hash = await this.contractClient.updateAccountMetadata(
4195
+ this.id,
4196
+ JSON.stringify(metadata)
4197
+ );
4198
+ return hash;
4199
+ }
4200
+ };
4201
+
4202
+ // src/acpJobOffering.ts
4203
+ var PriceType = /* @__PURE__ */ ((PriceType2) => {
4204
+ PriceType2["FIXED"] = "fixed";
4205
+ PriceType2["PERCENTAGE"] = "percentage";
4206
+ PriceType2["SUBSCRIPTION"] = "subscription";
4207
+ return PriceType2;
4208
+ })(PriceType || {});
4124
4209
  var AcpJobOffering = class {
4125
- constructor(acpClient, acpContractClient, providerAddress, name, price, priceType, requiredFunds, slaMinutes, requirement, deliverable) {
4210
+ constructor(acpClient, acpContractClient, providerAddress, name, price, priceType = "fixed" /* FIXED */, requiredFunds, slaMinutes, requirement, deliverable, subscriptionTiers = [], isPrivate = false) {
4126
4211
  this.acpClient = acpClient;
4127
4212
  this.acpContractClient = acpContractClient;
4128
4213
  this.providerAddress = providerAddress;
@@ -4133,10 +4218,49 @@ var AcpJobOffering = class {
4133
4218
  this.slaMinutes = slaMinutes;
4134
4219
  this.requirement = requirement;
4135
4220
  this.deliverable = deliverable;
4221
+ this.subscriptionTiers = subscriptionTiers;
4222
+ this.isPrivate = isPrivate;
4136
4223
  this.ajv = new import_ajv.default({ allErrors: true });
4137
4224
  }
4138
- async initiateJob(serviceRequirement, evaluatorAddress) {
4139
- const expiredAt = new Date(Date.now() + this.slaMinutes * 60 * 1e3);
4225
+ async initiateJob(serviceRequirement, evaluatorAddress, expiredAt = new Date(Date.now() + this.slaMinutes * 60 * 1e3), preferredSubscriptionTier) {
4226
+ this.validateRequest(serviceRequirement);
4227
+ const finalServiceRequirement = {
4228
+ name: this.name,
4229
+ requirement: serviceRequirement,
4230
+ priceValue: this.price,
4231
+ priceType: this.priceType
4232
+ };
4233
+ const subscriptionRequired = this.isSubscriptionRequired(
4234
+ preferredSubscriptionTier
4235
+ );
4236
+ this.validateSubscriptionTier(preferredSubscriptionTier);
4237
+ const effectivePrice = subscriptionRequired ? 0 : this.price;
4238
+ const effectivePriceType = subscriptionRequired ? "subscription" /* SUBSCRIPTION */ : this.priceType === "subscription" /* SUBSCRIPTION */ ? "fixed" /* FIXED */ : this.priceType;
4239
+ const fareAmount = new FareAmount(
4240
+ effectivePriceType === "fixed" /* FIXED */ ? effectivePrice : 0,
4241
+ this.acpContractClient.config.baseFare
4242
+ );
4243
+ const account = await this.resolveAccount(
4244
+ subscriptionRequired,
4245
+ preferredSubscriptionTier
4246
+ );
4247
+ const jobId = await this.createJob(
4248
+ account,
4249
+ evaluatorAddress,
4250
+ expiredAt,
4251
+ fareAmount,
4252
+ subscriptionRequired,
4253
+ preferredSubscriptionTier ?? ""
4254
+ );
4255
+ await this.sendInitialMemo(jobId, fareAmount, subscriptionRequired, {
4256
+ name: this.name,
4257
+ requirement: finalServiceRequirement,
4258
+ priceValue: effectivePrice,
4259
+ priceType: effectivePriceType
4260
+ });
4261
+ return jobId;
4262
+ }
4263
+ validateRequest(serviceRequirement) {
4140
4264
  if (this.providerAddress === this.acpClient.walletAddress) {
4141
4265
  throw new acpError_default(
4142
4266
  "Provider address cannot be the same as the client address"
@@ -4144,84 +4268,147 @@ var AcpJobOffering = class {
4144
4268
  }
4145
4269
  if (this.requirement && typeof this.requirement === "object") {
4146
4270
  const validator = this.ajv.compile(this.requirement);
4147
- const valid = validator(serviceRequirement);
4148
- if (!valid) {
4271
+ if (!validator(serviceRequirement)) {
4149
4272
  throw new acpError_default(this.ajv.errorsText(validator.errors));
4150
4273
  }
4151
4274
  }
4152
- const finalServiceRequirement = {
4153
- name: this.name,
4154
- requirement: serviceRequirement,
4155
- priceValue: this.price,
4156
- priceType: this.priceType
4157
- };
4158
- const fareAmount = new FareAmount(
4159
- this.priceType === "fixed" /* FIXED */ ? this.price : 0,
4160
- this.acpContractClient.config.baseFare
4161
- );
4162
- const account = await this.acpClient.getByClientAndProvider(
4275
+ }
4276
+ isSubscriptionRequired(preferredSubscriptionTier) {
4277
+ const hasSubscriptionTiers = this.subscriptionTiers.length > 0;
4278
+ return preferredSubscriptionTier != null || this.priceType === "subscription" /* SUBSCRIPTION */ && hasSubscriptionTiers;
4279
+ }
4280
+ validateSubscriptionTier(preferredSubscriptionTier) {
4281
+ if (!preferredSubscriptionTier) return;
4282
+ if (this.subscriptionTiers.length === 0) {
4283
+ throw new acpError_default(
4284
+ `Offering "${this.name}" does not support subscription tiers`
4285
+ );
4286
+ }
4287
+ if (!this.subscriptionTiers.includes(preferredSubscriptionTier)) {
4288
+ throw new acpError_default(
4289
+ `Preferred subscription tier "${preferredSubscriptionTier}" is not offered. Available: ${this.subscriptionTiers.join(", ")}`
4290
+ );
4291
+ }
4292
+ }
4293
+ /**
4294
+ * Resolve the account to use for the job.
4295
+ *
4296
+ * For non-subscription jobs: returns the existing account if found.
4297
+ * For subscription jobs, priority:
4298
+ * 1. Valid account matching preferred tier
4299
+ * 2. Any valid (non-expired) account
4300
+ * 3. Expired/unactivated account (expiryAt = 0) to reuse
4301
+ * 4. null — createJob will create a new one
4302
+ */
4303
+ async resolveAccount(subscriptionRequired, preferredSubscriptionTier) {
4304
+ const raw = await this.acpClient.getByClientAndProvider(
4163
4305
  this.acpContractClient.walletAddress,
4164
4306
  this.providerAddress,
4165
- this.acpContractClient
4307
+ this.acpContractClient,
4308
+ subscriptionRequired ? this.name : void 0
4166
4309
  );
4310
+ if (!subscriptionRequired) {
4311
+ if (!(raw instanceof AcpAccount)) return null;
4312
+ const meta = raw.metadata;
4313
+ if (meta && typeof meta === "object" && meta.name) return null;
4314
+ return raw;
4315
+ }
4316
+ const subscriptionCheck = raw && typeof raw === "object" && "accounts" in raw ? raw : null;
4317
+ if (!subscriptionCheck) return null;
4318
+ const now = Math.floor(Date.now() / 1e3);
4319
+ const allAccounts = subscriptionCheck.accounts ?? [];
4320
+ const matchedAccount = this.findPreferredAccount(allAccounts, preferredSubscriptionTier, now) ?? allAccounts.find((a) => a.expiryAt != null && a.expiryAt > now) ?? allAccounts.find((a) => a.expiryAt == null || a.expiryAt === 0);
4321
+ if (!matchedAccount) return null;
4322
+ return new AcpAccount(
4323
+ this.acpContractClient,
4324
+ matchedAccount.id,
4325
+ matchedAccount.clientAddress ?? this.acpContractClient.walletAddress,
4326
+ matchedAccount.providerAddress ?? this.providerAddress,
4327
+ matchedAccount.metadata,
4328
+ matchedAccount.expiryAt
4329
+ );
4330
+ }
4331
+ findPreferredAccount(accounts, preferredTier, now) {
4332
+ if (!preferredTier) return void 0;
4333
+ return accounts.find((a) => {
4334
+ if (a.expiryAt == null || a.expiryAt <= now) return false;
4335
+ const meta = typeof a.metadata === "string" ? (() => {
4336
+ try {
4337
+ return JSON.parse(a.metadata);
4338
+ } catch {
4339
+ return {};
4340
+ }
4341
+ })() : a.metadata ?? {};
4342
+ return meta?.name === preferredTier;
4343
+ });
4344
+ }
4345
+ async createJob(account, evaluatorAddress, expiredAt, fareAmount, subscriptionRequired, subscriptionTier) {
4167
4346
  const isV1 = [
4168
4347
  baseSepoliaAcpConfig.contractAddress,
4169
4348
  baseSepoliaAcpX402Config.contractAddress,
4170
4349
  baseAcpConfig.contractAddress,
4171
4350
  baseAcpX402Config.contractAddress
4172
4351
  ].includes(this.acpContractClient.config.contractAddress);
4173
- let createJobPayload;
4174
4352
  const chainId = this.acpContractClient.config.chain.id;
4175
4353
  const isUsdcPaymentToken = USDC_TOKEN_ADDRESS[chainId].toLowerCase() === fareAmount.fare.contractAddress.toLowerCase();
4176
4354
  const isX402Job = this.acpContractClient.config.x402Config && isUsdcPaymentToken;
4177
- if (isV1 || !account) {
4178
- createJobPayload = this.acpContractClient.createJob(
4179
- this.providerAddress,
4180
- evaluatorAddress || this.acpContractClient.walletAddress,
4181
- expiredAt,
4182
- fareAmount.fare.contractAddress,
4183
- fareAmount.amount,
4184
- "",
4185
- isX402Job
4186
- );
4187
- } else {
4188
- createJobPayload = this.acpContractClient.createJobWithAccount(
4189
- account.id,
4190
- evaluatorAddress || import_viem4.zeroAddress,
4191
- fareAmount.amount,
4192
- fareAmount.fare.contractAddress,
4193
- expiredAt,
4194
- isX402Job
4195
- );
4196
- }
4197
- const { userOpHash } = await this.acpContractClient.handleOperation([
4198
- createJobPayload
4355
+ const budget = subscriptionRequired ? 0n : fareAmount.amount;
4356
+ const subscriptionMetadata = subscriptionRequired ? JSON.stringify({ name: subscriptionTier }) : "";
4357
+ const operation = isV1 || !account ? this.acpContractClient.createJob(
4358
+ this.providerAddress,
4359
+ evaluatorAddress || this.acpContractClient.walletAddress,
4360
+ expiredAt,
4361
+ fareAmount.fare.contractAddress,
4362
+ budget,
4363
+ subscriptionMetadata,
4364
+ isX402Job
4365
+ ) : this.acpContractClient.createJobWithAccount(
4366
+ account.id,
4367
+ evaluatorAddress || import_viem4.zeroAddress,
4368
+ budget,
4369
+ fareAmount.fare.contractAddress,
4370
+ expiredAt,
4371
+ isX402Job
4372
+ );
4373
+ const { userOpHash, txnHash } = await this.acpContractClient.handleOperation([
4374
+ operation
4199
4375
  ]);
4200
- const jobId = await this.acpContractClient.getJobId(
4376
+ return this.acpContractClient.getJobId(
4201
4377
  userOpHash,
4202
4378
  this.acpContractClient.walletAddress,
4203
4379
  this.providerAddress
4204
4380
  );
4381
+ }
4382
+ async sendInitialMemo(jobId, fareAmount, subscriptionRequired, serviceRequirement) {
4205
4383
  const payloads = [];
4206
- const setBudgetWithPaymentTokenPayload = this.acpContractClient.setBudgetWithPaymentToken(
4207
- jobId,
4208
- fareAmount.amount,
4209
- fareAmount.fare.contractAddress
4210
- );
4211
- if (setBudgetWithPaymentTokenPayload) {
4212
- payloads.push(setBudgetWithPaymentTokenPayload);
4384
+ if (!subscriptionRequired) {
4385
+ const setBudgetPayload = this.acpContractClient.setBudgetWithPaymentToken(
4386
+ jobId,
4387
+ fareAmount.amount,
4388
+ fareAmount.fare.contractAddress
4389
+ );
4390
+ if (setBudgetPayload) {
4391
+ payloads.push(setBudgetPayload);
4392
+ }
4393
+ }
4394
+ let content = JSON.stringify(serviceRequirement);
4395
+ if (this.isPrivate) {
4396
+ const memoContent = await this.acpClient.createMemoContent(
4397
+ jobId,
4398
+ content
4399
+ );
4400
+ content = memoContent.url;
4213
4401
  }
4214
4402
  payloads.push(
4215
4403
  this.acpContractClient.createMemo(
4216
4404
  jobId,
4217
- JSON.stringify(finalServiceRequirement),
4218
- 0 /* MESSAGE */,
4405
+ content,
4406
+ this.isPrivate ? 4 /* OBJECT_URL */ : 0 /* MESSAGE */,
4219
4407
  true,
4220
4408
  1 /* NEGOTIATION */
4221
4409
  )
4222
4410
  );
4223
4411
  await this.acpContractClient.handleOperation(payloads);
4224
- return jobId;
4225
4412
  }
4226
4413
  };
4227
4414
  var acpJobOffering_default = AcpJobOffering;
@@ -4229,7 +4416,7 @@ var acpJobOffering_default = AcpJobOffering;
4229
4416
  // src/acpJob.ts
4230
4417
  var util = __toESM(require("util"));
4231
4418
  var AcpJob = class {
4232
- constructor(acpClient, id, clientAddress, providerAddress, evaluatorAddress, price, priceTokenAddress, memos, phase, context, contractAddress, _deliverable, netPayableAmount) {
4419
+ constructor(acpClient, id, clientAddress, providerAddress, evaluatorAddress, price, priceTokenAddress, memos, phase, context, contractAddress, netPayableAmount) {
4233
4420
  this.acpClient = acpClient;
4234
4421
  this.id = id;
4235
4422
  this.clientAddress = clientAddress;
@@ -4241,10 +4428,10 @@ var AcpJob = class {
4241
4428
  this.phase = phase;
4242
4429
  this.context = context;
4243
4430
  this.contractAddress = contractAddress;
4244
- this._deliverable = _deliverable;
4245
4431
  this.netPayableAmount = netPayableAmount;
4246
4432
  this.priceType = "fixed" /* FIXED */;
4247
4433
  this.priceValue = 0;
4434
+ this.isPrivate = false;
4248
4435
  const content = this.memos.find(
4249
4436
  (m) => m.nextPhase === 1 /* NEGOTIATION */
4250
4437
  )?.content;
@@ -4267,6 +4454,9 @@ var AcpJob = class {
4267
4454
  if (contentObj.priceValue) {
4268
4455
  this.priceValue = contentObj.priceValue || this.price;
4269
4456
  }
4457
+ if (contentObj.isPrivate) {
4458
+ this.isPrivate = contentObj.isPrivate;
4459
+ }
4270
4460
  }
4271
4461
  get acpContractClient() {
4272
4462
  return this.acpClient.contractClientByAddress(this.contractAddress);
@@ -4301,27 +4491,49 @@ var AcpJob = class {
4301
4491
  get latestMemo() {
4302
4492
  return this.memos[this.memos.length - 1];
4303
4493
  }
4304
- async getDeliverable() {
4305
- if (!this._deliverable) {
4494
+ getDeliverable() {
4495
+ const deliverableMemo = this.memos.find(
4496
+ (m) => m.nextPhase === 4 /* COMPLETED */
4497
+ );
4498
+ if (!deliverableMemo) {
4306
4499
  return null;
4307
4500
  }
4308
- if (typeof this._deliverable !== "string") {
4309
- return this._deliverable;
4310
- }
4311
- const regex = /api\/memo-contents\/([0-9]+)$/;
4312
- const result = this._deliverable?.match(regex);
4313
- if (!result) {
4314
- return this._deliverable;
4315
- }
4316
- const deliverable = await this.acpClient.getMemoContent(this._deliverable);
4317
- return tryParseJson(deliverable) || deliverable;
4501
+ return tryParseJson(deliverableMemo.content) || deliverableMemo.content;
4318
4502
  }
4319
4503
  async createRequirement(content) {
4320
4504
  const operations = [];
4505
+ let finalContent = content;
4506
+ if (this.isPrivate) {
4507
+ const memoContent = await this.acpClient.createMemoContent(
4508
+ this.id,
4509
+ content
4510
+ );
4511
+ finalContent = memoContent.url;
4512
+ }
4321
4513
  operations.push(
4322
4514
  this.acpContractClient.createMemo(
4323
4515
  this.id,
4324
- content,
4516
+ finalContent,
4517
+ this.isPrivate ? 4 /* OBJECT_URL */ : 0 /* MESSAGE */,
4518
+ true,
4519
+ 2 /* TRANSACTION */
4520
+ )
4521
+ );
4522
+ return await this.acpContractClient.handleOperation(operations);
4523
+ }
4524
+ async acceptRequirement(memo, reason) {
4525
+ const operations = [];
4526
+ operations.push(
4527
+ this.acpContractClient.signMemo(
4528
+ memo.id,
4529
+ true,
4530
+ reason ?? "Requirement accepted"
4531
+ )
4532
+ );
4533
+ operations.push(
4534
+ this.acpContractClient.createMemo(
4535
+ this.id,
4536
+ reason ?? "Proceeding to delivery",
4325
4537
  0 /* MESSAGE */,
4326
4538
  true,
4327
4539
  2 /* TRANSACTION */
@@ -4329,7 +4541,38 @@ var AcpJob = class {
4329
4541
  );
4330
4542
  return await this.acpContractClient.handleOperation(operations);
4331
4543
  }
4332
- async createPayableRequirement(content, type, amount, recipient, expiredAt = new Date(Date.now() + 1e3 * 60 * 5)) {
4544
+ async createPayableRequirement(content, type, amount, recipient, expiredAt = new Date(Date.now() + 1e3 * 60 * 5), duration) {
4545
+ if (type === 11 /* PAYABLE_REQUEST_SUBSCRIPTION */ && !duration) {
4546
+ throw new acpError_default("Duration is required for subscription payment requests");
4547
+ }
4548
+ if (type === 11 /* PAYABLE_REQUEST_SUBSCRIPTION */) {
4549
+ this.priceType = "subscription" /* SUBSCRIPTION */;
4550
+ if (this.priceValue !== 0) {
4551
+ throw new acpError_default(
4552
+ `Subscription payment request zero budget, got: ${this.priceValue}`
4553
+ );
4554
+ }
4555
+ let parsed;
4556
+ try {
4557
+ const result = JSON.parse(content);
4558
+ if (typeof result !== "object" || result === null || Array.isArray(result)) {
4559
+ throw new Error();
4560
+ }
4561
+ parsed = result;
4562
+ } catch {
4563
+ throw new acpError_default(
4564
+ `Subscription memo content must be a JSON object string, got: ${content}`
4565
+ );
4566
+ }
4567
+ const missing = ["name", "duration", "price"].filter(
4568
+ (k) => !(k in parsed)
4569
+ );
4570
+ if (missing.length > 0) {
4571
+ throw new acpError_default(
4572
+ `Subscription memo content is missing required fields: ${missing.join(", ")}`
4573
+ );
4574
+ }
4575
+ }
4333
4576
  const operations = [];
4334
4577
  if (type === 8 /* PAYABLE_TRANSFER_ESCROW */) {
4335
4578
  operations.push(
@@ -4341,11 +4584,34 @@ var AcpJob = class {
4341
4584
  }
4342
4585
  const feeAmount = new FareAmount(0, this.acpContractClient.config.baseFare);
4343
4586
  const isPercentagePricing = this.priceType === "percentage" /* PERCENTAGE */;
4344
- if (amount.fare.chainId && amount.fare.chainId !== this.acpContractClient.config.chain.id) {
4587
+ let finalContent = content;
4588
+ if (this.isPrivate) {
4589
+ const memoContent = await this.acpClient.createMemoContent(
4590
+ this.id,
4591
+ content
4592
+ );
4593
+ finalContent = memoContent.url;
4594
+ }
4595
+ if (type === 11 /* PAYABLE_REQUEST_SUBSCRIPTION */) {
4345
4596
  operations.push(
4346
- this.acpContractClient.createCrossChainPayableMemo(
4597
+ this.acpContractClient.createSubscriptionMemo(
4347
4598
  this.id,
4348
4599
  content,
4600
+ amount.amount,
4601
+ recipient,
4602
+ isPercentagePricing ? BigInt(Math.round(this.priceValue * 1e4)) : feeAmount.amount,
4603
+ isPercentagePricing ? 3 /* PERCENTAGE_FEE */ : 0 /* NO_FEE */,
4604
+ duration,
4605
+ 2 /* TRANSACTION */,
4606
+ expiredAt,
4607
+ amount.fare.contractAddress
4608
+ )
4609
+ );
4610
+ } else if (amount.fare.chainId && amount.fare.chainId !== this.acpContractClient.config.chain.id) {
4611
+ operations.push(
4612
+ this.acpContractClient.createCrossChainPayableMemo(
4613
+ this.id,
4614
+ finalContent,
4349
4615
  amount.fare.contractAddress,
4350
4616
  amount.amount,
4351
4617
  recipient,
@@ -4361,7 +4627,7 @@ var AcpJob = class {
4361
4627
  operations.push(
4362
4628
  this.acpContractClient.createPayableMemo(
4363
4629
  this.id,
4364
- content,
4630
+ finalContent,
4365
4631
  amount.amount,
4366
4632
  recipient,
4367
4633
  isPercentagePricing ? BigInt(Math.round(this.priceValue * 1e4)) : feeAmount.amount,
@@ -4392,14 +4658,15 @@ var AcpJob = class {
4392
4658
  memo.payableDetails.token,
4393
4659
  this.config
4394
4660
  ) : new FareAmount(0, this.baseFare);
4395
- const totalAmount = baseFareAmount.fare.contractAddress === transferAmount.fare.contractAddress ? baseFareAmount.add(transferAmount) : baseFareAmount;
4661
+ const sameToken = baseFareAmount.fare.contractAddress.toLowerCase() === transferAmount.fare.contractAddress.toLowerCase();
4662
+ const totalAmount = sameToken ? baseFareAmount.add(transferAmount) : baseFareAmount;
4396
4663
  operations.push(
4397
4664
  this.acpContractClient.approveAllowance(
4398
4665
  totalAmount.amount,
4399
4666
  this.baseFare.contractAddress
4400
4667
  )
4401
4668
  );
4402
- if (baseFareAmount.fare.contractAddress !== transferAmount.fare.contractAddress) {
4669
+ if (!sameToken) {
4403
4670
  operations.push(
4404
4671
  this.acpContractClient.approveAllowance(
4405
4672
  transferAmount.amount,
@@ -4408,11 +4675,19 @@ var AcpJob = class {
4408
4675
  );
4409
4676
  }
4410
4677
  operations.push(this.acpContractClient.signMemo(memo.id, true, reason));
4678
+ let finalContent = `Payment made. ${reason ?? ""}`.trim();
4679
+ if (this.isPrivate) {
4680
+ const memoContent = await this.acpClient.createMemoContent(
4681
+ this.id,
4682
+ finalContent
4683
+ );
4684
+ finalContent = memoContent.url;
4685
+ }
4411
4686
  operations.push(
4412
4687
  this.acpContractClient.createMemo(
4413
4688
  this.id,
4414
- `Payment made. ${reason ?? ""}`.trim(),
4415
- 0 /* MESSAGE */,
4689
+ finalContent,
4690
+ this.isPrivate ? 4 /* OBJECT_URL */ : 0 /* MESSAGE */,
4416
4691
  true,
4417
4692
  3 /* EVALUATION */
4418
4693
  )
@@ -4497,12 +4772,20 @@ var AcpJob = class {
4497
4772
  }
4498
4773
  return await latestMemo.sign(false, memoContent);
4499
4774
  }
4775
+ let finalContent = memoContent;
4776
+ if (this.isPrivate) {
4777
+ const memoContent2 = await this.acpClient.createMemoContent(
4778
+ this.id,
4779
+ finalContent
4780
+ );
4781
+ finalContent = memoContent2.url;
4782
+ }
4500
4783
  const operations = [];
4501
4784
  operations.push(
4502
4785
  this.acpContractClient.createMemo(
4503
4786
  this.id,
4504
- memoContent,
4505
- 0 /* MESSAGE */,
4787
+ finalContent,
4788
+ this.isPrivate ? 4 /* OBJECT_URL */ : 0 /* MESSAGE */,
4506
4789
  true,
4507
4790
  5 /* REJECTED */
4508
4791
  )
@@ -4519,10 +4802,18 @@ var AcpJob = class {
4519
4802
  amount.fare.contractAddress
4520
4803
  )
4521
4804
  );
4805
+ let finalContent = memoContent;
4806
+ if (this.isPrivate) {
4807
+ const memoContent2 = await this.acpClient.createMemoContent(
4808
+ this.id,
4809
+ finalContent
4810
+ );
4811
+ finalContent = memoContent2.url;
4812
+ }
4522
4813
  operations.push(
4523
4814
  this.acpContractClient.createPayableMemo(
4524
4815
  this.id,
4525
- memoContent,
4816
+ finalContent,
4526
4817
  amount.amount,
4527
4818
  this.clientAddress,
4528
4819
  feeAmount.amount,
@@ -4593,19 +4884,70 @@ var AcpJob = class {
4593
4884
  );
4594
4885
  return await this.acpContractClient.handleOperation(operations);
4595
4886
  }
4887
+ async paySubscription(reason) {
4888
+ if (this.phase === 6 /* EXPIRED */) {
4889
+ throw new acpError_default("Job has expired, cannot process subscription payment");
4890
+ }
4891
+ if (this.phase === 4 /* COMPLETED */) {
4892
+ throw new acpError_default(
4893
+ "Job is already completed, cannot process subscription payment"
4894
+ );
4895
+ }
4896
+ const memo = this.memos.find(
4897
+ (m) => m.type === 11 /* PAYABLE_REQUEST_SUBSCRIPTION */
4898
+ );
4899
+ if (!memo) {
4900
+ throw new acpError_default("No subscription payment request memo found");
4901
+ }
4902
+ if (!memo.payableDetails) {
4903
+ throw new acpError_default("Subscription memo has no payable details");
4904
+ }
4905
+ const operations = [];
4906
+ operations.push(
4907
+ this.acpContractClient.approveAllowance(
4908
+ memo.payableDetails.amount,
4909
+ memo.payableDetails.token
4910
+ )
4911
+ );
4912
+ operations.push(
4913
+ this.acpContractClient.signMemo(
4914
+ memo.id,
4915
+ true,
4916
+ reason || "Subscription payment approved"
4917
+ )
4918
+ );
4919
+ operations.push(
4920
+ this.acpContractClient.createMemo(
4921
+ this.id,
4922
+ `Subscription payment made. ${reason ?? ""}`.trim(),
4923
+ 0 /* MESSAGE */,
4924
+ true,
4925
+ memo.nextPhase
4926
+ )
4927
+ );
4928
+ return await this.acpContractClient.handleOperation(operations);
4929
+ }
4596
4930
  async evaluate(accept, reason) {
4597
4931
  if (this.latestMemo?.nextPhase !== 4 /* COMPLETED */) {
4598
4932
  throw new acpError_default("No evaluation memo found");
4599
4933
  }
4600
4934
  const memo = this.latestMemo;
4601
- await memo.sign(accept, reason);
4935
+ return await memo.sign(accept, reason);
4602
4936
  }
4603
4937
  async createNotification(content) {
4604
4938
  const operations = [];
4939
+ let finalContent = content;
4940
+ if (this.isPrivate) {
4941
+ const memoContent = await this.acpClient.createMemoContent(
4942
+ this.id,
4943
+ content
4944
+ );
4945
+ finalContent = memoContent.url;
4946
+ }
4605
4947
  operations.push(
4606
4948
  this.acpContractClient.createMemo(
4607
4949
  this.id,
4608
- content,
4950
+ finalContent,
4609
4951
  9 /* NOTIFICATION */,
4610
4952
  true,
4611
4953
  4 /* COMPLETED */
@@ -4623,10 +4965,18 @@ var AcpJob = class {
4623
4965
  );
4624
4966
  const feeAmount = new FareAmount(0, this.acpContractClient.config.baseFare);
4625
4967
  const isPercentagePricing = this.priceType === "percentage" /* PERCENTAGE */ && !skipFee;
4968
+ let finalContent = content;
4969
+ if (this.isPrivate) {
4970
+ const memoContent = await this.acpClient.createMemoContent(
4971
+ this.id,
4972
+ content
4973
+ );
4974
+ finalContent = memoContent.url;
4975
+ }
4626
4976
  operations.push(
4627
4977
  this.acpContractClient.createPayableMemo(
4628
4978
  this.id,
4629
- content,
4979
+ finalContent,
4630
4980
  amount.amount,
4631
4981
  this.clientAddress,
4632
4982
  isPercentagePricing ? BigInt(Math.round(this.priceValue * 1e4)) : feeAmount.amount,
@@ -4733,9 +5083,17 @@ var AcpJob = class {
4733
5083
  );
4734
5084
  const feeAmount = new FareAmount(0, this.acpContractClient.config.baseFare);
4735
5085
  const isPercentagePricing = this.priceType === "percentage" /* PERCENTAGE */ && !skipFee;
5086
+ let finalContent = content;
5087
+ if (this.isPrivate) {
5088
+ const memoContent = await this.acpClient.createMemoContent(
5089
+ this.id,
5090
+ content
5091
+ );
5092
+ finalContent = memoContent.url;
5093
+ }
4736
5094
  const createMemoOperation = this.acpContractClient.createCrossChainPayableMemo(
4737
5095
  this.id,
4738
- content,
5096
+ finalContent,
4739
5097
  amount.fare.contractAddress,
4740
5098
  amount.amount,
4741
5099
  recipient,
@@ -4770,9 +5128,9 @@ var acpJob_default = AcpJob;
4770
5128
 
4771
5129
  // src/acpMemo.ts
4772
5130
  var import_util = __toESM(require("util"));
4773
- var AcpMemo = class {
4774
- constructor(contractClient, id, type, content, nextPhase, status, senderAddress, signedReason, expiry, payableDetails, txHash, signedTxHash, state) {
4775
- this.contractClient = contractClient;
5131
+ var AcpMemo = class _AcpMemo {
5132
+ constructor(acpClient, id, type, content, nextPhase, status, senderAddress, signedReason, expiry, payableDetails, txHash, signedTxHash, state) {
5133
+ this.acpClient = acpClient;
4776
5134
  this.id = id;
4777
5135
  this.type = type;
4778
5136
  this.content = content;
@@ -4790,8 +5148,39 @@ var AcpMemo = class {
4790
5148
  this.payableDetails.feeAmount = BigInt(this.payableDetails.feeAmount);
4791
5149
  }
4792
5150
  }
5151
+ static async build(acpClient, id, type, content, nextPhase, status, senderAddress, signedReason, expiry, payableDetails, txHash, signedTxHash, state) {
5152
+ let memoContent = content;
5153
+ const regex = /api\/memo-contents\/([0-9]+)$/;
5154
+ const result = memoContent.match(regex);
5155
+ if (result) {
5156
+ memoContent = await acpClient.getMemoContent(content);
5157
+ }
5158
+ return new _AcpMemo(
5159
+ acpClient,
5160
+ id,
5161
+ type,
5162
+ memoContent,
5163
+ nextPhase,
5164
+ status,
5165
+ senderAddress,
5166
+ signedReason,
5167
+ expiry,
5168
+ payableDetails,
5169
+ txHash,
5170
+ signedTxHash,
5171
+ state
5172
+ );
5173
+ }
5174
+ async getContent() {
5175
+ const regex = /api\/memo-contents\/([0-9]+)$/;
5176
+ const result = this.content.match(regex);
5177
+ if (!result) {
5178
+ return this.content;
5179
+ }
5180
+ return this.acpClient.getMemoContent(this.content);
5181
+ }
4793
5182
  async create(jobId, isSecured = true) {
4794
- return this.contractClient.createMemo(
5183
+ return this.acpClient.acpContractClient.createMemo(
4795
5184
  jobId,
4796
5185
  this.content,
4797
5186
  this.type,
@@ -4800,44 +5189,30 @@ var AcpMemo = class {
4800
5189
  );
4801
5190
  }
4802
5191
  async sign(approved, reason) {
4803
- const payload = this.contractClient.signMemo(this.id, approved, reason);
4804
- return await this.contractClient.handleOperation([payload]);
4805
- }
4806
- [import_util.default.inspect.custom]() {
4807
- return {
4808
- id: this.id,
4809
- senderAddress: this.senderAddress,
4810
- type: MemoType[this.type],
4811
- status: this.status,
4812
- content: this.content,
4813
- signedReason: this.signedReason,
4814
- txHash: this.txHash,
4815
- signedTxHash: this.signedTxHash,
4816
- nextPhase: AcpJobPhases[this.nextPhase],
4817
- expiry: this.expiry,
4818
- payableDetails: this.payableDetails
4819
- };
4820
- }
4821
- };
4822
- var acpMemo_default = AcpMemo;
4823
-
4824
- // src/acpAccount.ts
4825
- var AcpAccount = class {
4826
- constructor(contractClient, id, clientAddress, providerAddress, metadata) {
4827
- this.contractClient = contractClient;
4828
- this.id = id;
4829
- this.clientAddress = clientAddress;
4830
- this.providerAddress = providerAddress;
4831
- this.metadata = metadata;
4832
- }
4833
- async updateMetadata(metadata) {
4834
- const hash = await this.contractClient.updateAccountMetadata(
5192
+ const payload = this.acpClient.acpContractClient.signMemo(
4835
5193
  this.id,
4836
- JSON.stringify(metadata)
5194
+ approved,
5195
+ reason
4837
5196
  );
4838
- return hash;
5197
+ return await this.acpClient.acpContractClient.handleOperation([payload]);
5198
+ }
5199
+ [import_util.default.inspect.custom]() {
5200
+ return {
5201
+ id: this.id,
5202
+ senderAddress: this.senderAddress,
5203
+ type: MemoType[this.type],
5204
+ status: this.status,
5205
+ content: this.content,
5206
+ signedReason: this.signedReason,
5207
+ txHash: this.txHash,
5208
+ signedTxHash: this.signedTxHash,
5209
+ nextPhase: AcpJobPhases[this.nextPhase],
5210
+ expiry: this.expiry,
5211
+ payableDetails: this.payableDetails
5212
+ };
4839
5213
  }
4840
5214
  };
5215
+ var acpMemo_default = AcpMemo;
4841
5216
 
4842
5217
  // src/acpClient.ts
4843
5218
  var import_axios = __toESM(require("axios"));
@@ -4854,6 +5229,7 @@ var AcpAgent = class {
4854
5229
  this.twitterHandle = args.twitterHandle;
4855
5230
  this.metrics = args.metrics;
4856
5231
  this.resources = args.resources;
5232
+ this.subscriptions = Object.freeze([...args.subscriptions ?? []]);
4857
5233
  }
4858
5234
  };
4859
5235
  var acpAgent_default = AcpAgent;
@@ -4964,6 +5340,7 @@ var AcpClient = class {
4964
5340
  });
4965
5341
  return response.data.data;
4966
5342
  } catch (err) {
5343
+ console.log("err->>", err.response.data);
4967
5344
  throw new acpError_default("Failed to verify auth challenge", err);
4968
5345
  }
4969
5346
  }
@@ -5018,18 +5395,26 @@ var AcpClient = class {
5018
5395
  socket.on("onEvaluate" /* ON_EVALUATE */, async (data, callback) => {
5019
5396
  callback(true);
5020
5397
  if (this.onEvaluate) {
5021
- const job = this._hydrateJob(data);
5398
+ const job = await this._hydrateJob(data);
5022
5399
  this.onEvaluate(job);
5023
5400
  }
5024
5401
  });
5025
5402
  socket.on("onNewTask" /* ON_NEW_TASK */, async (data, callback) => {
5026
5403
  callback(true);
5027
5404
  if (this.onNewTask) {
5028
- const job = this._hydrateJob(data);
5029
- this.onNewTask(
5030
- job,
5031
- job.memos.find((m) => m.id == data.memoToSign)
5032
- );
5405
+ const job = await this._hydrateJob(data);
5406
+ if (job.phase === 6 /* EXPIRED */) {
5407
+ console.warn(`onNewTask skipped for job ${data.id}: job has expired`);
5408
+ return;
5409
+ }
5410
+ try {
5411
+ await this.onNewTask(
5412
+ job,
5413
+ job.memos.find((m) => m.id == data.memoToSign)
5414
+ );
5415
+ } catch (err) {
5416
+ console.error(`onNewTask error for job ${data.id}:`, err);
5417
+ }
5033
5418
  }
5034
5419
  });
5035
5420
  const cleanup = async () => {
@@ -5056,8 +5441,6 @@ var AcpClient = class {
5056
5441
  errCallback(err);
5057
5442
  } else if (err.response?.data.error?.message) {
5058
5443
  throw new acpError_default(err.response?.data.error.message);
5059
- } else {
5060
- throw new acpError_default(`Failed to fetch ${url}: ${err.message}`, err);
5061
5444
  }
5062
5445
  } else {
5063
5446
  throw new acpError_default(
@@ -5067,10 +5450,10 @@ var AcpClient = class {
5067
5450
  }
5068
5451
  }
5069
5452
  }
5070
- _hydrateMemo(memo, contractClient) {
5453
+ async _hydrateMemo(memo) {
5071
5454
  try {
5072
- return new acpMemo_default(
5073
- contractClient,
5455
+ return await acpMemo_default.build(
5456
+ this,
5074
5457
  memo.id,
5075
5458
  memo.memoType,
5076
5459
  memo.content,
@@ -5078,7 +5461,7 @@ var AcpClient = class {
5078
5461
  memo.status,
5079
5462
  memo.senderAddress,
5080
5463
  memo.signedReason,
5081
- memo.expiry ? new Date(Number(memo.expiry) * 1e3) : void 0,
5464
+ memo.expiry ? new Date(parseInt(memo.expiry) * 1e3) : void 0,
5082
5465
  memo.payableDetails,
5083
5466
  memo.txHash,
5084
5467
  memo.signedTxHash,
@@ -5088,7 +5471,7 @@ var AcpClient = class {
5088
5471
  throw new acpError_default(`Failed to hydrate memo ${memo.id}`, err);
5089
5472
  }
5090
5473
  }
5091
- _hydrateJob(job) {
5474
+ async _hydrateJob(job) {
5092
5475
  try {
5093
5476
  return new acpJob_default(
5094
5477
  this,
@@ -5098,31 +5481,27 @@ var AcpClient = class {
5098
5481
  job.evaluatorAddress,
5099
5482
  job.price,
5100
5483
  job.priceTokenAddress,
5101
- job.memos.map(
5102
- (memo) => this._hydrateMemo(
5103
- memo,
5104
- this.contractClientByAddress(job.contractAddress)
5105
- )
5106
- ),
5484
+ await Promise.all(job.memos.map((memo) => this._hydrateMemo(memo))),
5107
5485
  job.phase,
5108
5486
  job.context,
5109
5487
  job.contractAddress,
5110
- job.deliverable,
5111
5488
  job.netPayableAmount
5112
5489
  );
5113
5490
  } catch (err) {
5114
5491
  throw new acpError_default(`Failed to hydrate job ${job.id}`, err);
5115
5492
  }
5116
5493
  }
5117
- _hydrateJobs(rawJobs, options) {
5118
- const jobs = rawJobs.map((job) => {
5119
- try {
5120
- return this._hydrateJob(job);
5121
- } catch (err) {
5122
- console.warn(`${options?.logPrefix ?? "Skipped"}`, err);
5123
- return null;
5124
- }
5125
- });
5494
+ async _hydrateJobs(rawJobs, options) {
5495
+ const jobs = await Promise.all(
5496
+ rawJobs.map((job) => {
5497
+ try {
5498
+ return this._hydrateJob(job);
5499
+ } catch (err) {
5500
+ console.warn(`${options?.logPrefix ?? "Skipped"}`, err);
5501
+ return null;
5502
+ }
5503
+ })
5504
+ );
5126
5505
  return jobs.filter((job) => !!job);
5127
5506
  }
5128
5507
  _hydrateAgent(agent) {
@@ -5151,14 +5530,17 @@ var AcpClient = class {
5151
5530
  offering.requiredFunds,
5152
5531
  offering.slaMinutes,
5153
5532
  offering.requirement,
5154
- offering.deliverable
5533
+ offering.deliverable,
5534
+ offering.subscriptionTiers ?? [],
5535
+ offering.isPrivate
5155
5536
  );
5156
5537
  }),
5157
5538
  contractAddress: agent.contractAddress,
5158
5539
  twitterHandle: agent.twitterHandle,
5159
5540
  walletAddress: agent.walletAddress,
5160
5541
  metrics: agent.metrics,
5161
- resources: agent.resources
5542
+ resources: agent.resources,
5543
+ subscriptions: agent.subscriptions ?? []
5162
5544
  });
5163
5545
  }
5164
5546
  async browseAgents(keyword, options = {}) {
@@ -5207,65 +5589,87 @@ var AcpClient = class {
5207
5589
  return this._hydrateAgent(agent);
5208
5590
  });
5209
5591
  }
5210
- async initiateJob(providerAddress, serviceRequirement, fareAmount, evaluatorAddress, expiredAt = new Date(Date.now() + 1e3 * 60 * 60 * 24)) {
5592
+ async initiateJob(providerAddress, serviceRequirement, fareAmount, evaluatorAddress, expiredAt = new Date(Date.now() + 1e3 * 60 * 60 * 24), offeringName, preferredSubscriptionTier) {
5211
5593
  if (providerAddress === this.walletAddress) {
5212
5594
  throw new acpError_default(
5213
5595
  "Provider address cannot be the same as the client address"
5214
5596
  );
5215
5597
  }
5216
- const account = await this.getByClientAndProvider(
5217
- this.walletAddress,
5598
+ const subscriptionRequired = preferredSubscriptionTier != null;
5599
+ const { account } = await this._resolveSubscriptionAccount(
5218
5600
  providerAddress,
5219
- this.acpContractClient
5601
+ offeringName,
5602
+ preferredSubscriptionTier
5220
5603
  );
5604
+ const budget = subscriptionRequired ? 0n : fareAmount.amount;
5605
+ const subscriptionMetadata = subscriptionRequired ? JSON.stringify({ name: preferredSubscriptionTier ?? "" }) : "";
5221
5606
  const isV1 = [
5222
5607
  baseSepoliaAcpConfig.contractAddress,
5223
5608
  baseSepoliaAcpX402Config.contractAddress,
5224
5609
  baseAcpConfig.contractAddress,
5225
5610
  baseAcpX402Config.contractAddress
5226
5611
  ].includes(this.acpContractClient.config.contractAddress);
5227
- const defaultEvaluatorAddress = isV1 && !evaluatorAddress ? this.walletAddress : import_viem6.zeroAddress;
5612
+ const resolvedEvaluator = evaluatorAddress || (isV1 ? this.walletAddress : import_viem6.zeroAddress);
5228
5613
  const chainId = this.acpContractClient.config.chain.id;
5229
- const isUsdcPaymentToken = USDC_TOKEN_ADDRESS[chainId].toLowerCase() === fareAmount.fare.contractAddress.toLowerCase();
5230
- const isX402Job = this.acpContractClient.config.x402Config && isUsdcPaymentToken;
5231
- const createJobPayload = isV1 || !account ? this.acpContractClient.createJob(
5232
- providerAddress,
5233
- evaluatorAddress || defaultEvaluatorAddress,
5234
- expiredAt,
5235
- fareAmount.fare.contractAddress,
5236
- fareAmount.amount,
5237
- "",
5238
- isX402Job
5239
- ) : this.acpContractClient.createJobWithAccount(
5240
- account.id,
5241
- evaluatorAddress || defaultEvaluatorAddress,
5242
- fareAmount.amount,
5243
- fareAmount.fare.contractAddress,
5244
- expiredAt,
5245
- isX402Job
5246
- );
5247
- const { userOpHash } = await this.acpContractClient.handleOperation([
5248
- createJobPayload
5249
- ]);
5614
+ const isX402Job = this.acpContractClient.config.x402Config && USDC_TOKEN_ADDRESS[chainId].toLowerCase() === fareAmount.fare.contractAddress.toLowerCase();
5615
+ const createJobOperations = [];
5616
+ if (isV1 || !account) {
5617
+ createJobOperations.push(
5618
+ this.acpContractClient.createJob(
5619
+ providerAddress,
5620
+ resolvedEvaluator,
5621
+ expiredAt,
5622
+ fareAmount.fare.contractAddress,
5623
+ budget,
5624
+ subscriptionMetadata,
5625
+ isX402Job
5626
+ )
5627
+ );
5628
+ } else {
5629
+ createJobOperations.push(
5630
+ this.acpContractClient.createJobWithAccount(
5631
+ account.id,
5632
+ resolvedEvaluator,
5633
+ budget,
5634
+ fareAmount.fare.contractAddress,
5635
+ expiredAt,
5636
+ isX402Job
5637
+ )
5638
+ );
5639
+ }
5640
+ const { userOpHash } = await this.acpContractClient.handleOperation(createJobOperations);
5250
5641
  const jobId = await this.acpContractClient.getJobId(
5251
5642
  userOpHash,
5252
5643
  this.walletAddress,
5253
5644
  providerAddress
5254
5645
  );
5255
5646
  const payloads = [];
5256
- const setBudgetWithPaymentTokenPayload = this.acpContractClient.setBudgetWithPaymentToken(
5257
- jobId,
5258
- fareAmount.amount,
5259
- fareAmount.fare.contractAddress
5260
- );
5261
- if (setBudgetWithPaymentTokenPayload) {
5262
- payloads.push(setBudgetWithPaymentTokenPayload);
5647
+ if (!subscriptionRequired) {
5648
+ const setBudgetPayload = this.acpContractClient.setBudgetWithPaymentToken(
5649
+ jobId,
5650
+ fareAmount.amount,
5651
+ fareAmount.fare.contractAddress
5652
+ );
5653
+ if (setBudgetPayload) {
5654
+ payloads.push(setBudgetPayload);
5655
+ }
5656
+ }
5657
+ const memoPayload = subscriptionRequired && typeof serviceRequirement === "object" ? preparePayload({
5658
+ ...serviceRequirement,
5659
+ priceValue: 0,
5660
+ priceType: "subscription" /* SUBSCRIPTION */
5661
+ }) : preparePayload(serviceRequirement);
5662
+ const isPrivate = typeof serviceRequirement === "object" && "isPrivate" in serviceRequirement && serviceRequirement.isPrivate;
5663
+ let content = memoPayload;
5664
+ if (isPrivate) {
5665
+ const memoContent = await this.createMemoContent(jobId, memoPayload);
5666
+ content = memoContent.url;
5263
5667
  }
5264
5668
  payloads.push(
5265
5669
  this.acpContractClient.createMemo(
5266
5670
  jobId,
5267
- preparePayload(serviceRequirement),
5268
- 0 /* MESSAGE */,
5671
+ isPrivate ? content : memoPayload,
5672
+ isPrivate ? 4 /* OBJECT_URL */ : 0 /* MESSAGE */,
5269
5673
  true,
5270
5674
  1 /* NEGOTIATION */
5271
5675
  )
@@ -5323,10 +5727,7 @@ var AcpClient = class {
5323
5727
  if (!memo) {
5324
5728
  return null;
5325
5729
  }
5326
- return this._hydrateMemo(
5327
- memo,
5328
- this.contractClientByAddress(memo.contractAddress)
5329
- );
5730
+ return this._hydrateMemo(memo);
5330
5731
  }
5331
5732
  async getAgent(walletAddress, options = {}) {
5332
5733
  const params = {
@@ -5354,32 +5755,195 @@ var AcpClient = class {
5354
5755
  account.id,
5355
5756
  account.clientAddress,
5356
5757
  account.providerAddress,
5357
- account.metadata
5758
+ account.metadata,
5759
+ account.expiryAt
5358
5760
  );
5359
5761
  }
5360
- async getByClientAndProvider(clientAddress, providerAddress, acpContractClient) {
5361
- const response = await this._fetch(
5362
- `/accounts/client/${clientAddress}/provider/${providerAddress}`,
5363
- "GET",
5364
- {},
5365
- {},
5366
- (err) => {
5367
- if (err.response?.status === 404) {
5368
- return;
5369
- }
5370
- throw new acpError_default("Failed to get account by client and provider", err);
5762
+ /**
5763
+ * Gets account or subscription data for a client–provider pair.
5764
+ * When offeringName is provided, the backend may return subscription tiers and accounts
5765
+ * (ISubscriptionCheckResponse). When not provided, returns a single AcpAccount or null.
5766
+ */
5767
+ async getByClientAndProvider(clientAddress, providerAddress, acpContractClient, offeringName) {
5768
+ let endpoint = `/accounts/client/${clientAddress}/provider/${providerAddress}`;
5769
+ if (offeringName) {
5770
+ endpoint = `/accounts/sub/client/${clientAddress}/provider/${providerAddress}`;
5771
+ }
5772
+ const response = await this._fetch(endpoint, "GET", {}, {}, (err) => {
5773
+ if (err.response?.status === 404) {
5774
+ return;
5371
5775
  }
5372
- );
5776
+ throw new acpError_default("Failed to get account by client and provider", err);
5777
+ });
5373
5778
  if (!response) {
5374
5779
  return null;
5375
5780
  }
5781
+ if (typeof response === "object" && "accounts" in response && Array.isArray(response.accounts)) {
5782
+ const sub = response;
5783
+ sub.accounts = sub.accounts.map((a) => ({
5784
+ ...a,
5785
+ expiryAt: a.expiryAt ?? a.expiry
5786
+ }));
5787
+ return sub;
5788
+ }
5789
+ const account = response;
5790
+ const expiryAt = account.expiryAt ?? account.expiry;
5376
5791
  return new AcpAccount(
5377
5792
  acpContractClient || this.contractClients[0],
5378
- response.id,
5379
- response.clientAddress,
5380
- response.providerAddress,
5381
- response.metadata
5793
+ account.id,
5794
+ account.clientAddress,
5795
+ account.providerAddress,
5796
+ account.metadata,
5797
+ expiryAt
5798
+ );
5799
+ }
5800
+ /**
5801
+ * Narrows a backend response to ISubscriptionCheckResponse if it has an accounts array.
5802
+ */
5803
+ _asSubscriptionCheck(raw) {
5804
+ return raw && typeof raw === "object" && "accounts" in raw ? raw : null;
5805
+ }
5806
+ /**
5807
+ * Resolve the account to use for the job.
5808
+ *
5809
+ * For subscription jobs, priority:
5810
+ * 1. Valid account matching preferred tier
5811
+ * 2. Any valid (non-expired) account
5812
+ * 3. Unactivated account (expiryAt = 0) to reuse
5813
+ * 4. null — createJob will create a new one
5814
+ */
5815
+ async _resolveSubscriptionAccount(providerAddress, offeringName, preferredSubscriptionTier) {
5816
+ if (!offeringName) return { account: null };
5817
+ const raw = await this.getByClientAndProvider(
5818
+ this.walletAddress,
5819
+ providerAddress,
5820
+ this.acpContractClient,
5821
+ offeringName
5822
+ );
5823
+ const subscriptionCheck = raw && typeof raw === "object" && "accounts" in raw ? raw : null;
5824
+ if (!subscriptionCheck) return { account: null };
5825
+ const now = Math.floor(Date.now() / 1e3);
5826
+ const allAccounts = subscriptionCheck.accounts ?? [];
5827
+ const matchedAccount = this._findPreferredAccount(allAccounts, preferredSubscriptionTier, now) ?? allAccounts.find((a) => a.expiryAt != null && a.expiryAt > now) ?? allAccounts.find((a) => a.expiryAt == null || a.expiryAt === 0);
5828
+ if (!matchedAccount) return { account: null };
5829
+ return {
5830
+ account: new AcpAccount(
5831
+ this.acpContractClient,
5832
+ matchedAccount.id,
5833
+ matchedAccount.clientAddress ?? this.walletAddress,
5834
+ matchedAccount.providerAddress ?? providerAddress,
5835
+ matchedAccount.metadata,
5836
+ matchedAccount.expiryAt
5837
+ )
5838
+ };
5839
+ }
5840
+ _findPreferredAccount(accounts, preferredTier, now) {
5841
+ if (!preferredTier) return void 0;
5842
+ return accounts.find((a) => {
5843
+ if (a.expiryAt == null || a.expiryAt <= now) return false;
5844
+ const meta = typeof a.metadata === "string" ? (() => {
5845
+ try {
5846
+ return JSON.parse(a.metadata);
5847
+ } catch {
5848
+ return {};
5849
+ }
5850
+ })() : a.metadata ?? {};
5851
+ return meta?.name === preferredTier;
5852
+ });
5853
+ }
5854
+ /**
5855
+ * Returns the first subscription account with expiryAt > now, or null.
5856
+ */
5857
+ _getValidSubscriptionAccountFromResponse(response, acpContractClient) {
5858
+ const now = Math.floor(Date.now() / 1e3);
5859
+ const valid = response.accounts?.find(
5860
+ (a) => a.expiryAt != null && a.expiryAt > now
5861
+ );
5862
+ if (!valid) return null;
5863
+ return new AcpAccount(
5864
+ acpContractClient,
5865
+ valid.id,
5866
+ valid.clientAddress,
5867
+ valid.providerAddress,
5868
+ valid.metadata,
5869
+ valid.expiryAt
5870
+ );
5871
+ }
5872
+ /**
5873
+ * Seller-facing: determines whether to create a subscription payment request memo.
5874
+ * Call this when handling a new job (e.g. in REQUEST phase); then branch on
5875
+ * needsSubscriptionPayment and use tier when true.
5876
+ */
5877
+ async getSubscriptionPaymentRequirement(clientAddress, providerAddress, offeringName) {
5878
+ let raw;
5879
+ try {
5880
+ raw = await this.getByClientAndProvider(
5881
+ clientAddress,
5882
+ providerAddress,
5883
+ void 0,
5884
+ offeringName
5885
+ );
5886
+ } catch {
5887
+ return {
5888
+ needsSubscriptionPayment: false,
5889
+ action: "no_subscription_required"
5890
+ };
5891
+ }
5892
+ const response = this._asSubscriptionCheck(raw);
5893
+ if (!response?.accounts?.length) {
5894
+ return {
5895
+ needsSubscriptionPayment: false,
5896
+ action: "no_subscription_required"
5897
+ };
5898
+ }
5899
+ const now = Math.floor(Date.now() / 1e3);
5900
+ const hasValidSubscription = response.accounts.some(
5901
+ (a) => a.expiryAt != null && a.expiryAt > now
5382
5902
  );
5903
+ if (hasValidSubscription) {
5904
+ return {
5905
+ needsSubscriptionPayment: false,
5906
+ action: "valid_subscription"
5907
+ };
5908
+ }
5909
+ const firstAccount = response.accounts[0];
5910
+ const tier = {
5911
+ name: firstAccount.metadata?.name ?? "",
5912
+ price: firstAccount.metadata?.price ?? 0,
5913
+ duration: firstAccount.metadata?.duration ?? 0
5914
+ };
5915
+ return {
5916
+ needsSubscriptionPayment: true,
5917
+ tier
5918
+ };
5919
+ }
5920
+ async getValidSubscriptionAccount(providerAddress, offeringName, clientAddress, acpContractClient) {
5921
+ const raw = await this.getByClientAndProvider(
5922
+ clientAddress,
5923
+ providerAddress,
5924
+ acpContractClient,
5925
+ offeringName
5926
+ );
5927
+ const subscriptionCheck = this._asSubscriptionCheck(raw);
5928
+ if (!subscriptionCheck) return null;
5929
+ const contractClient = acpContractClient || this.contractClients[0];
5930
+ const account = this._getValidSubscriptionAccountFromResponse(
5931
+ subscriptionCheck,
5932
+ contractClient
5933
+ );
5934
+ if (account) return account;
5935
+ const legacy = subscriptionCheck;
5936
+ if (legacy.subscriptionRequired && legacy.hasValidSubscription && legacy.account) {
5937
+ return new AcpAccount(
5938
+ contractClient,
5939
+ legacy.account.id,
5940
+ legacy.account.clientAddress,
5941
+ legacy.account.providerAddress,
5942
+ legacy.account.metadata,
5943
+ legacy.account.expiryAt
5944
+ );
5945
+ }
5946
+ return null;
5383
5947
  }
5384
5948
  async createMemoContent(jobId, content) {
5385
5949
  const response = await this._fetch(
@@ -5688,9 +6252,7 @@ var AcpContractClient = class _AcpContractClient extends baseAcpContractClient_d
5688
6252
  throw new acpError_default(`Failed to send user operation`, finalError);
5689
6253
  }
5690
6254
  async getJobId(createJobUserOpHash, clientAddress, providerAddress) {
5691
- const result = await this.sessionKeyClient.getUserOperationReceipt(
5692
- createJobUserOpHash
5693
- );
6255
+ const result = await this.sessionKeyClient.getUserOperationReceipt(createJobUserOpHash);
5694
6256
  if (!result) {
5695
6257
  throw new acpError_default("Failed to get user operation receipt");
5696
6258
  }
@@ -6556,6 +7118,7 @@ var MEMO_MANAGER_ABI = [
6556
7118
  { inputs: [], name: "InvalidMemoState", type: "error" },
6557
7119
  { inputs: [], name: "InvalidMemoStateTransition", type: "error" },
6558
7120
  { inputs: [], name: "InvalidMemoType", type: "error" },
7121
+ { inputs: [], name: "InvalidSubscriptionDuration", type: "error" },
6559
7122
  { inputs: [], name: "JobAlreadyCompleted", type: "error" },
6560
7123
  { inputs: [], name: "JobDoesNotExist", type: "error" },
6561
7124
  { inputs: [], name: "MemoAlreadyApproved", type: "error" },
@@ -6591,6 +7154,7 @@ var MEMO_MANAGER_ABI = [
6591
7154
  { inputs: [], name: "ZeroAddressToken", type: "error" },
6592
7155
  { inputs: [], name: "ZeroAssetManagerAddress", type: "error" },
6593
7156
  { inputs: [], name: "ZeroJobManagerAddress", type: "error" },
7157
+ { inputs: [], name: "ZeroPaymentManagerAddress", type: "error" },
6594
7158
  {
6595
7159
  anonymous: false,
6596
7160
  inputs: [
@@ -6863,6 +7427,31 @@ var MEMO_MANAGER_ABI = [
6863
7427
  name: "RoleRevoked",
6864
7428
  type: "event"
6865
7429
  },
7430
+ {
7431
+ anonymous: false,
7432
+ inputs: [
7433
+ {
7434
+ indexed: true,
7435
+ internalType: "uint256",
7436
+ name: "memoId",
7437
+ type: "uint256"
7438
+ },
7439
+ {
7440
+ indexed: true,
7441
+ internalType: "uint256",
7442
+ name: "accountId",
7443
+ type: "uint256"
7444
+ },
7445
+ {
7446
+ indexed: false,
7447
+ internalType: "uint256",
7448
+ name: "duration",
7449
+ type: "uint256"
7450
+ }
7451
+ ],
7452
+ name: "SubscriptionActivated",
7453
+ type: "event"
7454
+ },
6866
7455
  {
6867
7456
  anonymous: false,
6868
7457
  inputs: [
@@ -6930,17 +7519,6 @@ var MEMO_MANAGER_ABI = [
6930
7519
  stateMutability: "view",
6931
7520
  type: "function"
6932
7521
  },
6933
- {
6934
- inputs: [
6935
- { internalType: "uint256[]", name: "memoIds", type: "uint256[]" },
6936
- { internalType: "bool", name: "approved", type: "bool" },
6937
- { internalType: "string", name: "reason", type: "string" }
6938
- ],
6939
- name: "bulkApproveMemos",
6940
- outputs: [],
6941
- stateMutability: "nonpayable",
6942
- type: "function"
6943
- },
6944
7522
  {
6945
7523
  inputs: [
6946
7524
  { internalType: "uint256", name: "memoId", type: "uint256" },
@@ -7018,9 +7596,40 @@ var MEMO_MANAGER_ABI = [
7018
7596
  type: "function"
7019
7597
  },
7020
7598
  {
7021
- inputs: [{ internalType: "uint256", name: "memoId", type: "uint256" }],
7022
- name: "emergencyApproveMemo",
7023
- outputs: [],
7599
+ inputs: [
7600
+ { internalType: "uint256", name: "jobId", type: "uint256" },
7601
+ { internalType: "address", name: "sender", type: "address" },
7602
+ { internalType: "string", name: "content", type: "string" },
7603
+ {
7604
+ components: [
7605
+ { internalType: "address", name: "token", type: "address" },
7606
+ { internalType: "uint256", name: "amount", type: "uint256" },
7607
+ { internalType: "address", name: "recipient", type: "address" },
7608
+ { internalType: "uint256", name: "feeAmount", type: "uint256" },
7609
+ {
7610
+ internalType: "enum ACPTypes.FeeType",
7611
+ name: "feeType",
7612
+ type: "uint8"
7613
+ },
7614
+ { internalType: "bool", name: "isExecuted", type: "bool" },
7615
+ { internalType: "uint256", name: "expiredAt", type: "uint256" },
7616
+ { internalType: "uint32", name: "lzSrcEid", type: "uint32" },
7617
+ { internalType: "uint32", name: "lzDstEid", type: "uint32" }
7618
+ ],
7619
+ internalType: "struct ACPTypes.PayableDetails",
7620
+ name: "payableDetails_",
7621
+ type: "tuple"
7622
+ },
7623
+ { internalType: "uint256", name: "duration", type: "uint256" },
7624
+ { internalType: "uint256", name: "expiredAt", type: "uint256" },
7625
+ {
7626
+ internalType: "enum ACPTypes.JobPhase",
7627
+ name: "nextPhase",
7628
+ type: "uint8"
7629
+ }
7630
+ ],
7631
+ name: "createSubscriptionMemo",
7632
+ outputs: [{ internalType: "uint256", name: "memoId", type: "uint256" }],
7024
7633
  stateMutability: "nonpayable",
7025
7634
  type: "function"
7026
7635
  },
@@ -7031,13 +7640,6 @@ var MEMO_MANAGER_ABI = [
7031
7640
  stateMutability: "nonpayable",
7032
7641
  type: "function"
7033
7642
  },
7034
- {
7035
- inputs: [],
7036
- name: "getAssetManager",
7037
- outputs: [{ internalType: "address", name: "", type: "address" }],
7038
- stateMutability: "view",
7039
- type: "function"
7040
- },
7041
7643
  {
7042
7644
  inputs: [
7043
7645
  { internalType: "uint256", name: "jobId", type: "uint256" },
@@ -7234,17 +7836,6 @@ var MEMO_MANAGER_ABI = [
7234
7836
  stateMutability: "view",
7235
7837
  type: "function"
7236
7838
  },
7237
- {
7238
- inputs: [{ internalType: "uint256", name: "memoId", type: "uint256" }],
7239
- name: "getMemoApprovalStatus",
7240
- outputs: [
7241
- { internalType: "bool", name: "isApproved", type: "bool" },
7242
- { internalType: "address", name: "approvedBy", type: "address" },
7243
- { internalType: "uint256", name: "approvedAt", type: "uint256" }
7244
- ],
7245
- stateMutability: "view",
7246
- type: "function"
7247
- },
7248
7839
  {
7249
7840
  inputs: [{ internalType: "uint256", name: "memoId", type: "uint256" }],
7250
7841
  name: "getMemoWithPayableDetails",
@@ -7307,34 +7898,6 @@ var MEMO_MANAGER_ABI = [
7307
7898
  stateMutability: "view",
7308
7899
  type: "function"
7309
7900
  },
7310
- {
7311
- inputs: [{ internalType: "uint256", name: "memoId", type: "uint256" }],
7312
- name: "getPayableDetails",
7313
- outputs: [
7314
- {
7315
- components: [
7316
- { internalType: "address", name: "token", type: "address" },
7317
- { internalType: "uint256", name: "amount", type: "uint256" },
7318
- { internalType: "address", name: "recipient", type: "address" },
7319
- { internalType: "uint256", name: "feeAmount", type: "uint256" },
7320
- {
7321
- internalType: "enum ACPTypes.FeeType",
7322
- name: "feeType",
7323
- type: "uint8"
7324
- },
7325
- { internalType: "bool", name: "isExecuted", type: "bool" },
7326
- { internalType: "uint256", name: "expiredAt", type: "uint256" },
7327
- { internalType: "uint32", name: "lzSrcEid", type: "uint32" },
7328
- { internalType: "uint32", name: "lzDstEid", type: "uint32" }
7329
- ],
7330
- internalType: "struct ACPTypes.PayableDetails",
7331
- name: "",
7332
- type: "tuple"
7333
- }
7334
- ],
7335
- stateMutability: "view",
7336
- type: "function"
7337
- },
7338
7901
  {
7339
7902
  inputs: [{ internalType: "bytes32", name: "role", type: "bytes32" }],
7340
7903
  name: "getRoleAdmin",
@@ -7373,16 +7936,6 @@ var MEMO_MANAGER_ABI = [
7373
7936
  stateMutability: "nonpayable",
7374
7937
  type: "function"
7375
7938
  },
7376
- {
7377
- inputs: [
7378
- { internalType: "uint256", name: "jobId", type: "uint256" },
7379
- { internalType: "address", name: "user", type: "address" }
7380
- ],
7381
- name: "isJobEvaluator",
7382
- outputs: [{ internalType: "bool", name: "", type: "bool" }],
7383
- stateMutability: "view",
7384
- type: "function"
7385
- },
7386
7939
  {
7387
7940
  inputs: [
7388
7941
  { internalType: "uint256", name: "memoId", type: "uint256" },
@@ -7554,23 +8107,16 @@ var MEMO_MANAGER_ABI = [
7554
8107
  },
7555
8108
  {
7556
8109
  inputs: [
7557
- {
7558
- internalType: "enum ACPTypes.MemoType",
7559
- name: "memoType",
7560
- type: "uint8"
7561
- },
7562
- { internalType: "uint256", name: "requiredApprovals_", type: "uint256" }
8110
+ { internalType: "address", name: "assetManager_", type: "address" }
7563
8111
  ],
7564
- name: "setApprovalRequirements",
8112
+ name: "setAssetManager",
7565
8113
  outputs: [],
7566
8114
  stateMutability: "nonpayable",
7567
8115
  type: "function"
7568
8116
  },
7569
8117
  {
7570
- inputs: [
7571
- { internalType: "address", name: "assetManager_", type: "address" }
7572
- ],
7573
- name: "setAssetManager",
8118
+ inputs: [{ internalType: "uint256", name: "memoId", type: "uint256" }],
8119
+ name: "setPayableDetailsExecuted",
7574
8120
  outputs: [],
7575
8121
  stateMutability: "nonpayable",
7576
8122
  type: "function"
@@ -7866,6 +8412,37 @@ var AcpContractClientV2 = class _AcpContractClientV2 extends baseAcpContractClie
7866
8412
  }
7867
8413
  return Number(createdJobEvent.args.jobId);
7868
8414
  }
8415
+ async getAccountIdFromUserOpHash(userOpHash) {
8416
+ const result = await this.sessionKeyClient.getUserOperationReceipt(
8417
+ userOpHash,
8418
+ "pending"
8419
+ );
8420
+ if (!result || !result.logs?.length) {
8421
+ return null;
8422
+ }
8423
+ const contractAddresses = [
8424
+ this.contractAddress.toLowerCase(),
8425
+ this.accountManagerAddress.toLowerCase()
8426
+ ];
8427
+ for (const log of result.logs) {
8428
+ if (!contractAddresses.includes(log.address?.toLowerCase())) {
8429
+ continue;
8430
+ }
8431
+ try {
8432
+ const decoded = (0, import_viem9.decodeEventLog)({
8433
+ abi: this.abi,
8434
+ data: log.data,
8435
+ topics: log.topics
8436
+ });
8437
+ if (decoded.eventName === "AccountCreated") {
8438
+ const args = decoded.args;
8439
+ if (args?.accountId != null) return Number(args.accountId);
8440
+ }
8441
+ } catch {
8442
+ }
8443
+ }
8444
+ return null;
8445
+ }
7869
8446
  async updateJobX402Nonce(jobId, nonce) {
7870
8447
  return await this.acpX402.updateJobNonce(jobId, nonce);
7871
8448
  }
@@ -7920,6 +8497,7 @@ var index_default = acpClient_default;
7920
8497
  // Annotate the CommonJS export names for ESM import in node:
7921
8498
  0 && (module.exports = {
7922
8499
  ACP_ABI,
8500
+ AcpAccount,
7923
8501
  AcpAgent,
7924
8502
  AcpAgentSort,
7925
8503
  AcpContractClient,
@@ -7938,6 +8516,7 @@ var index_default = acpClient_default;
7938
8516
  FareAmount,
7939
8517
  FareBigInt,
7940
8518
  MemoType,
8519
+ PriceType,
7941
8520
  baseAcpConfig,
7942
8521
  baseAcpConfigV2,
7943
8522
  baseAcpX402Config,