@virtuals-protocol/acp-node 0.3.0-beta.16 → 0.3.0-beta.18

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.mjs CHANGED
@@ -8,12 +8,13 @@ var require_package = __commonJS({
8
8
  "package.json"(exports, module) {
9
9
  module.exports = {
10
10
  name: "@virtuals-protocol/acp-node",
11
- version: "0.3.0-beta.16",
11
+ version: "0.3.0-beta.18",
12
12
  main: "./dist/index.js",
13
13
  module: "./dist/index.mjs",
14
14
  types: "./dist/index.d.ts",
15
15
  scripts: {
16
16
  test: "jest",
17
+ "test:ci": "jest --ci --reporters=default --reporters=jest-junit",
17
18
  "test:watch": "jest --watch",
18
19
  "test:coverage": "jest --coverage",
19
20
  tsup: "tsup src/index.ts --dts --format cjs,esm --out-dir dist"
@@ -29,6 +30,7 @@ var require_package = __commonJS({
29
30
  "babel-jest": "^30.2.0",
30
31
  dotenv: "^17.2.3",
31
32
  jest: "^30.2.0",
33
+ "jest-junit": "^16.0.0",
32
34
  "ts-jest": "^29.4.5",
33
35
  typescript: "^5.8.3"
34
36
  },
@@ -1236,7 +1238,10 @@ import {
1236
1238
  } from "viem";
1237
1239
 
1238
1240
  // src/configs/acpConfigs.ts
1239
- import { baseSepolia, base } from "@account-kit/infra";
1241
+ import {
1242
+ baseSepolia,
1243
+ base
1244
+ } from "@account-kit/infra";
1240
1245
 
1241
1246
  // src/acpFare.ts
1242
1247
  import {
@@ -1264,27 +1269,42 @@ var acpError_default = AcpError;
1264
1269
 
1265
1270
  // src/acpFare.ts
1266
1271
  var Fare = class _Fare {
1267
- constructor(contractAddress, decimals) {
1272
+ constructor(contractAddress, decimals, chainId) {
1268
1273
  this.contractAddress = contractAddress;
1269
1274
  this.decimals = decimals;
1275
+ this.chainId = chainId;
1270
1276
  }
1271
1277
  formatAmount(amount) {
1272
1278
  return parseUnits(amount.toString(), this.decimals);
1273
1279
  }
1274
- static async fromContractAddress(contractAddress, config = baseAcpConfig) {
1280
+ static async fromContractAddress(contractAddress, config = baseAcpConfig, chainId = config.chain.id) {
1275
1281
  if (contractAddress === config.baseFare.contractAddress) {
1276
1282
  return config.baseFare;
1277
1283
  }
1284
+ let chainConfig = config.chain;
1285
+ let rpcUrl = config.rpcEndpoint;
1286
+ if (chainId !== config.chain.id) {
1287
+ const selectedConfig = config.chains?.find(
1288
+ (chain) => chain.chain.id === chainId
1289
+ );
1290
+ if (!selectedConfig) {
1291
+ throw new acpError_default(
1292
+ `Chain configuration for chainId ${chainId} not found.`
1293
+ );
1294
+ }
1295
+ chainConfig = selectedConfig.chain;
1296
+ rpcUrl = selectedConfig.rpcUrl;
1297
+ }
1278
1298
  const publicClient = createPublicClient({
1279
- chain: config.chain,
1280
- transport: http(config.rpcEndpoint)
1299
+ chain: chainConfig,
1300
+ transport: http(rpcUrl)
1281
1301
  });
1282
1302
  const decimals = await publicClient.readContract({
1283
1303
  address: contractAddress,
1284
1304
  abi: erc20Abi,
1285
1305
  functionName: "decimals"
1286
1306
  });
1287
- return new _Fare(contractAddress, decimals);
1307
+ return new _Fare(contractAddress, decimals, chainId);
1288
1308
  }
1289
1309
  };
1290
1310
  var FareAmountBase = class {
@@ -1703,6 +1723,34 @@ var ACP_V2_ABI = [
1703
1723
  stateMutability: "nonpayable",
1704
1724
  type: "function"
1705
1725
  },
1726
+ {
1727
+ inputs: [
1728
+ { internalType: "uint256", name: "jobId", type: "uint256" },
1729
+ { internalType: "string", name: "content", type: "string" },
1730
+ { internalType: "address", name: "token", type: "address" },
1731
+ { internalType: "uint256", name: "amount", type: "uint256" },
1732
+ { internalType: "address", name: "recipient", type: "address" },
1733
+ { internalType: "uint256", name: "feeAmount", type: "uint256" },
1734
+ { internalType: "enum ACPTypes.FeeType", name: "feeType", type: "uint8" },
1735
+ {
1736
+ internalType: "enum ACPTypes.MemoType",
1737
+ name: "memoType",
1738
+ type: "uint8"
1739
+ },
1740
+ { internalType: "uint256", name: "expiredAt", type: "uint256" },
1741
+ { internalType: "bool", name: "isSecured", type: "bool" },
1742
+ {
1743
+ internalType: "enum ACPTypes.JobPhase",
1744
+ name: "nextPhase",
1745
+ type: "uint8"
1746
+ },
1747
+ { internalType: "uint32", name: "lzDstEid", type: "uint32" }
1748
+ ],
1749
+ name: "createCrossChainPayableMemo",
1750
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
1751
+ stateMutability: "nonpayable",
1752
+ type: "function"
1753
+ },
1706
1754
  {
1707
1755
  inputs: [
1708
1756
  { internalType: "address", name: "provider", type: "address" },
@@ -1887,7 +1935,12 @@ var ACP_V2_ABI = [
1887
1935
  name: "nextPhase",
1888
1936
  type: "uint8"
1889
1937
  },
1890
- { internalType: "uint256", name: "expiredAt", type: "uint256" }
1938
+ { internalType: "uint256", name: "expiredAt", type: "uint256" },
1939
+ {
1940
+ internalType: "enum ACPTypes.MemoState",
1941
+ name: "state",
1942
+ type: "uint8"
1943
+ }
1891
1944
  ],
1892
1945
  internalType: "struct ACPTypes.Memo[]",
1893
1946
  name: "memos",
@@ -1934,7 +1987,12 @@ var ACP_V2_ABI = [
1934
1987
  name: "nextPhase",
1935
1988
  type: "uint8"
1936
1989
  },
1937
- { internalType: "uint256", name: "expiredAt", type: "uint256" }
1990
+ { internalType: "uint256", name: "expiredAt", type: "uint256" },
1991
+ {
1992
+ internalType: "enum ACPTypes.MemoState",
1993
+ name: "state",
1994
+ type: "uint8"
1995
+ }
1938
1996
  ],
1939
1997
  internalType: "struct ACPTypes.Memo[]",
1940
1998
  name: "memos",
@@ -1977,7 +2035,12 @@ var ACP_V2_ABI = [
1977
2035
  name: "nextPhase",
1978
2036
  type: "uint8"
1979
2037
  },
1980
- { internalType: "uint256", name: "expiredAt", type: "uint256" }
2038
+ { internalType: "uint256", name: "expiredAt", type: "uint256" },
2039
+ {
2040
+ internalType: "enum ACPTypes.MemoState",
2041
+ name: "state",
2042
+ type: "uint8"
2043
+ }
1981
2044
  ],
1982
2045
  internalType: "struct ACPTypes.Memo[]",
1983
2046
  name: "memos",
@@ -2233,7 +2296,7 @@ var acpAbiV2_default = ACP_V2_ABI;
2233
2296
  var V1_MAX_RETRIES = 10;
2234
2297
  var V2_MAX_RETRIES = 3;
2235
2298
  var AcpContractConfig2 = class {
2236
- constructor(chain, contractAddress, baseFare, alchemyRpcUrl, acpUrl, abi, maxRetries, rpcEndpoint, x402Config) {
2299
+ constructor(chain, contractAddress, baseFare, alchemyRpcUrl, acpUrl, abi, maxRetries, rpcEndpoint, x402Config, chains = []) {
2237
2300
  this.chain = chain;
2238
2301
  this.contractAddress = contractAddress;
2239
2302
  this.baseFare = baseFare;
@@ -2243,6 +2306,7 @@ var AcpContractConfig2 = class {
2243
2306
  this.maxRetries = maxRetries;
2244
2307
  this.rpcEndpoint = rpcEndpoint;
2245
2308
  this.x402Config = x402Config;
2309
+ this.chains = chains;
2246
2310
  }
2247
2311
  };
2248
2312
  var baseSepoliaAcpConfig = new AcpContractConfig2(
@@ -3470,7 +3534,18 @@ var SINGLE_SIGNER_VALIDATION_MODULE_ABI = [
3470
3534
  var singleSignerValidationModuleAbi_default = SINGLE_SIGNER_VALIDATION_MODULE_ABI;
3471
3535
 
3472
3536
  // src/constants.ts
3473
- import { base as base2, baseSepolia as baseSepolia2 } from "viem/chains";
3537
+ import {
3538
+ arbitrum as arbitrum2,
3539
+ arbitrumSepolia as arbitrumSepolia2,
3540
+ base as base2,
3541
+ baseSepolia as baseSepolia2,
3542
+ bsc as bsc2,
3543
+ bscTestnet as bscTestnet2,
3544
+ mainnet as mainnet2,
3545
+ polygon as polygon2,
3546
+ polygonAmoy as polygonAmoy2,
3547
+ sepolia as sepolia2
3548
+ } from "viem/chains";
3474
3549
  var USDC_TOKEN_ADDRESS = {
3475
3550
  [baseSepolia2.id]: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
3476
3551
  [base2.id]: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
@@ -3488,6 +3563,16 @@ var HTTP_STATUS_CODES = {
3488
3563
  PAYMENT_REQUIRED: 402
3489
3564
  };
3490
3565
  var SINGLE_SIGNER_VALIDATION_MODULE_ADDRESS = "0x00000000000099DE0BF6fA90dEB851E2A2df7d83";
3566
+ var ASSET_MANAGER_ADDRESSES = {
3567
+ [bscTestnet2.id]: "0xfCf52B02936623852dd5132007E9414f9060168b",
3568
+ [bsc2.id]: "",
3569
+ [polygonAmoy2.id]: "0xfCf52B02936623852dd5132007E9414f9060168b",
3570
+ [polygon2.id]: "",
3571
+ [arbitrum2.id]: "",
3572
+ [arbitrumSepolia2.id]: "0xfCf52B02936623852dd5132007E9414f9060168b",
3573
+ [sepolia2.id]: "0xfCf52B02936623852dd5132007E9414f9060168b",
3574
+ [mainnet2.id]: ""
3575
+ };
3491
3576
 
3492
3577
  // src/contractClients/baseAcpContractClient.ts
3493
3578
  var MemoType = /* @__PURE__ */ ((MemoType3) => {
@@ -3502,6 +3587,7 @@ var MemoType = /* @__PURE__ */ ((MemoType3) => {
3502
3587
  MemoType3[MemoType3["PAYABLE_TRANSFER_ESCROW"] = 8] = "PAYABLE_TRANSFER_ESCROW";
3503
3588
  MemoType3[MemoType3["NOTIFICATION"] = 9] = "NOTIFICATION";
3504
3589
  MemoType3[MemoType3["PAYABLE_NOTIFICATION"] = 10] = "PAYABLE_NOTIFICATION";
3590
+ MemoType3[MemoType3["TRANSFER_EVENT"] = 11] = "TRANSFER_EVENT";
3505
3591
  return MemoType3;
3506
3592
  })(MemoType || {});
3507
3593
  var AcpJobPhases = /* @__PURE__ */ ((AcpJobPhases3) => {
@@ -3518,6 +3604,7 @@ var BaseAcpContractClient = class {
3518
3604
  constructor(agentWalletAddress, config = baseAcpConfig) {
3519
3605
  this.agentWalletAddress = agentWalletAddress;
3520
3606
  this.config = config;
3607
+ this.publicClients = {};
3521
3608
  this.chain = config.chain;
3522
3609
  this.abi = config.abi;
3523
3610
  this.contractAddress = config.contractAddress;
@@ -3617,12 +3704,12 @@ ${JSON.stringify(
3617
3704
  throw new acpError_default("Failed to create job", error);
3618
3705
  }
3619
3706
  }
3620
- approveAllowance(amountBaseUnit, paymentTokenAddress = this.config.baseFare.contractAddress) {
3707
+ approveAllowance(amountBaseUnit, paymentTokenAddress = this.config.baseFare.contractAddress, targetAddress) {
3621
3708
  try {
3622
3709
  const data = encodeFunctionData({
3623
3710
  abi: erc20Abi2,
3624
3711
  functionName: "approve",
3625
- args: [this.contractAddress, amountBaseUnit]
3712
+ args: [targetAddress ?? this.contractAddress, amountBaseUnit]
3626
3713
  });
3627
3714
  const payload = {
3628
3715
  data,
@@ -3661,6 +3748,35 @@ ${JSON.stringify(
3661
3748
  throw new acpError_default("Failed to create payable memo", error);
3662
3749
  }
3663
3750
  }
3751
+ createCrossChainPayableMemo(jobId, content, token, amountBaseUnit, recipient, feeAmountBaseUnit, feeType, type, expiredAt, nextPhase, destinationEid, secured = true) {
3752
+ try {
3753
+ const data = encodeFunctionData({
3754
+ abi: this.abi,
3755
+ functionName: "createCrossChainPayableMemo",
3756
+ args: [
3757
+ jobId,
3758
+ content,
3759
+ token,
3760
+ amountBaseUnit,
3761
+ recipient,
3762
+ feeAmountBaseUnit,
3763
+ feeType,
3764
+ type,
3765
+ expiredAt,
3766
+ secured,
3767
+ nextPhase,
3768
+ destinationEid
3769
+ ]
3770
+ });
3771
+ const payload = {
3772
+ data,
3773
+ contractAddress: this.contractAddress
3774
+ };
3775
+ return payload;
3776
+ } catch (error) {
3777
+ throw new acpError_default("Failed to create cross chain payable memo", error);
3778
+ }
3779
+ }
3664
3780
  createMemo(jobId, content, type, isSecured, nextPhase) {
3665
3781
  try {
3666
3782
  const data = encodeFunctionData({
@@ -3677,6 +3793,22 @@ ${JSON.stringify(
3677
3793
  throw new acpError_default("Failed to create memo", error);
3678
3794
  }
3679
3795
  }
3796
+ createMemoWithMetadata(jobId, content, type, isSecured, nextPhase, metadata) {
3797
+ try {
3798
+ const data = encodeFunctionData({
3799
+ abi: this.abi,
3800
+ functionName: "createMemoWithMetadata",
3801
+ args: [jobId, content, type, isSecured, nextPhase, metadata]
3802
+ });
3803
+ const payload = {
3804
+ data,
3805
+ contractAddress: this.contractAddress
3806
+ };
3807
+ return payload;
3808
+ } catch (error) {
3809
+ throw new acpError_default("Failed to create memo with metadata", error);
3810
+ }
3811
+ }
3680
3812
  signMemo(memoId, isApproved, reason) {
3681
3813
  try {
3682
3814
  const data = encodeFunctionData({
@@ -3762,9 +3894,47 @@ ${JSON.stringify(
3762
3894
  throw new acpError_default("Failed to submit TransferWithAuthorization", error);
3763
3895
  }
3764
3896
  }
3897
+ async getERC20Balance(chainId, tokenAddress, walletAddress) {
3898
+ const publicClient = this.publicClients[chainId];
3899
+ if (!publicClient) {
3900
+ throw new acpError_default(`Public client for chainId ${chainId} not found`);
3901
+ }
3902
+ return await publicClient.readContract({
3903
+ address: tokenAddress,
3904
+ abi: erc20Abi2,
3905
+ functionName: "balanceOf",
3906
+ args: [walletAddress]
3907
+ });
3908
+ }
3909
+ async getERC20Allowance(chainId, tokenAddress, walletAddress, spenderAddress) {
3910
+ const publicClient = this.publicClients[chainId];
3911
+ if (!publicClient) {
3912
+ throw new acpError_default(`Public client for chainId ${chainId} not found`);
3913
+ }
3914
+ return await publicClient.readContract({
3915
+ address: tokenAddress,
3916
+ abi: erc20Abi2,
3917
+ functionName: "allowance",
3918
+ args: [walletAddress, spenderAddress]
3919
+ });
3920
+ }
3921
+ async getERC20Symbol(chainId, tokenAddress) {
3922
+ const publicClient = this.publicClients[chainId];
3923
+ if (!publicClient) {
3924
+ throw new acpError_default(`Public client for chainId ${chainId} not found`);
3925
+ }
3926
+ return await publicClient.readContract({
3927
+ address: tokenAddress,
3928
+ abi: erc20Abi2,
3929
+ functionName: "symbol"
3930
+ });
3931
+ }
3765
3932
  };
3766
3933
  var baseAcpContractClient_default = BaseAcpContractClient;
3767
3934
 
3935
+ // src/acpJob.ts
3936
+ import { formatUnits } from "viem";
3937
+
3768
3938
  // src/interfaces.ts
3769
3939
  var AcpMemoStatus = /* @__PURE__ */ ((AcpMemoStatus2) => {
3770
3940
  AcpMemoStatus2["PENDING"] = "PENDING";
@@ -3772,6 +3942,15 @@ var AcpMemoStatus = /* @__PURE__ */ ((AcpMemoStatus2) => {
3772
3942
  AcpMemoStatus2["REJECTED"] = "REJECTED";
3773
3943
  return AcpMemoStatus2;
3774
3944
  })(AcpMemoStatus || {});
3945
+ var AcpMemoState = /* @__PURE__ */ ((AcpMemoState2) => {
3946
+ AcpMemoState2["NONE"] = "NONE";
3947
+ AcpMemoState2["PENDING"] = "PENDING";
3948
+ AcpMemoState2["IN_PROGRESS"] = "IN_PROGRESS";
3949
+ AcpMemoState2["READY"] = "READY";
3950
+ AcpMemoState2["COMPLETED"] = "COMPLETED";
3951
+ AcpMemoState2["REJECTED"] = "REJECTED";
3952
+ return AcpMemoState2;
3953
+ })(AcpMemoState || {});
3775
3954
  var AcpAgentSort = /* @__PURE__ */ ((AcpAgentSort2) => {
3776
3955
  AcpAgentSort2["SUCCESSFUL_JOB_COUNT"] = "successfulJobCount";
3777
3956
  AcpAgentSort2["SUCCESS_RATE"] = "successRate";
@@ -3810,6 +3989,19 @@ var PositionDirection = /* @__PURE__ */ ((PositionDirection2) => {
3810
3989
  })(PositionDirection || {});
3811
3990
 
3812
3991
  // src/utils.ts
3992
+ import { decodeAbiParameters, encodeAbiParameters } from "viem";
3993
+ import {
3994
+ arbitrum as arbitrum3,
3995
+ arbitrumSepolia as arbitrumSepolia3,
3996
+ base as base3,
3997
+ baseSepolia as baseSepolia3,
3998
+ bsc as bsc3,
3999
+ bscTestnet as bscTestnet3,
4000
+ mainnet as mainnet3,
4001
+ polygon as polygon3,
4002
+ polygonAmoy as polygonAmoy3,
4003
+ sepolia as sepolia3
4004
+ } from "viem/chains";
3813
4005
  function tryParseJson(content) {
3814
4006
  try {
3815
4007
  return JSON.parse(content);
@@ -3826,6 +4018,31 @@ function safeBase64Encode(data) {
3826
4018
  }
3827
4019
  return Buffer.from(data).toString("base64");
3828
4020
  }
4021
+ function getDestinationEndpointId(chainId) {
4022
+ switch (chainId) {
4023
+ case baseSepolia3.id:
4024
+ return 40245;
4025
+ case sepolia3.id:
4026
+ return 40161;
4027
+ case polygonAmoy3.id:
4028
+ return 40267;
4029
+ case arbitrumSepolia3.id:
4030
+ return 40231;
4031
+ case bscTestnet3.id:
4032
+ return 40102;
4033
+ case base3.id:
4034
+ return 30184;
4035
+ case mainnet3.id:
4036
+ return 30101;
4037
+ case polygon3.id:
4038
+ return 30109;
4039
+ case arbitrum3.id:
4040
+ return 30110;
4041
+ case bsc3.id:
4042
+ return 30102;
4043
+ }
4044
+ throw new Error(`Unsupported chain ID: ${chainId}`);
4045
+ }
3829
4046
 
3830
4047
  // src/acpJobOffering.ts
3831
4048
  import { zeroAddress as zeroAddress2 } from "viem";
@@ -4028,20 +4245,38 @@ var AcpJob = class {
4028
4245
  }
4029
4246
  const feeAmount = new FareAmount(0, this.acpContractClient.config.baseFare);
4030
4247
  const isPercentagePricing = this.priceType === "percentage" /* PERCENTAGE */;
4031
- operations.push(
4032
- this.acpContractClient.createPayableMemo(
4033
- this.id,
4034
- content,
4035
- amount.amount,
4036
- recipient,
4037
- isPercentagePricing ? BigInt(Math.round(this.priceValue * 1e4)) : feeAmount.amount,
4038
- isPercentagePricing ? 3 /* PERCENTAGE_FEE */ : 0 /* NO_FEE */,
4039
- 2 /* TRANSACTION */,
4040
- type,
4041
- expiredAt,
4042
- amount.fare.contractAddress
4043
- )
4044
- );
4248
+ if (amount.fare.chainId && amount.fare.chainId !== this.acpContractClient.config.chain.id) {
4249
+ operations.push(
4250
+ this.acpContractClient.createCrossChainPayableMemo(
4251
+ this.id,
4252
+ content,
4253
+ amount.fare.contractAddress,
4254
+ amount.amount,
4255
+ recipient,
4256
+ isPercentagePricing ? BigInt(Math.round(this.priceValue * 1e4)) : feeAmount.amount,
4257
+ isPercentagePricing ? 3 /* PERCENTAGE_FEE */ : 0 /* NO_FEE */,
4258
+ type,
4259
+ expiredAt,
4260
+ 2 /* TRANSACTION */,
4261
+ getDestinationEndpointId(amount.fare.chainId)
4262
+ )
4263
+ );
4264
+ } else {
4265
+ operations.push(
4266
+ this.acpContractClient.createPayableMemo(
4267
+ this.id,
4268
+ content,
4269
+ amount.amount,
4270
+ recipient,
4271
+ isPercentagePricing ? BigInt(Math.round(this.priceValue * 1e4)) : feeAmount.amount,
4272
+ isPercentagePricing ? 3 /* PERCENTAGE_FEE */ : 0 /* NO_FEE */,
4273
+ 2 /* TRANSACTION */,
4274
+ type,
4275
+ expiredAt,
4276
+ amount.fare.contractAddress
4277
+ )
4278
+ );
4279
+ }
4045
4280
  return await this.acpContractClient.handleOperation(operations);
4046
4281
  }
4047
4282
  async payAndAcceptRequirement(reason) {
@@ -4083,9 +4318,11 @@ var AcpJob = class {
4083
4318
  3 /* EVALUATION */
4084
4319
  )
4085
4320
  );
4086
- const x402PaymentDetails = await this.acpContractClient.getX402PaymentDetails(this.id);
4087
- if (x402PaymentDetails.isX402) {
4088
- await this.performX402Payment(this.price);
4321
+ if (this.price > 0) {
4322
+ const x402PaymentDetails = await this.acpContractClient.getX402PaymentDetails(this.id);
4323
+ if (x402PaymentDetails.isX402) {
4324
+ await this.performX402Payment(this.price);
4325
+ }
4089
4326
  }
4090
4327
  return await this.acpContractClient.handleOperation(operations);
4091
4328
  }
@@ -4172,6 +4409,9 @@ var AcpJob = class {
4172
4409
  if (this.latestMemo?.nextPhase !== 3 /* EVALUATION */) {
4173
4410
  throw new acpError_default("No transaction memo found");
4174
4411
  }
4412
+ if (amount.fare.chainId !== this.acpContractClient.config.chain.id) {
4413
+ return await this.deliverCrossChainPayable(this.clientAddress, amount);
4414
+ }
4175
4415
  const operations = [];
4176
4416
  operations.push(
4177
4417
  this.acpContractClient.approveAllowance(
@@ -4302,6 +4542,56 @@ var AcpJob = class {
4302
4542
  waitMs = Math.min(waitMs * 2, maxWaitMs);
4303
4543
  }
4304
4544
  }
4545
+ async deliverCrossChainPayable(recipient, amount) {
4546
+ if (!amount.fare.chainId) {
4547
+ throw new acpError_default("Chain ID is required for cross chain payable");
4548
+ }
4549
+ const chainId = amount.fare.chainId;
4550
+ const tokenBalance = await this.acpContractClient.getERC20Balance(
4551
+ chainId,
4552
+ amount.fare.contractAddress,
4553
+ this.acpContractClient.agentWalletAddress
4554
+ );
4555
+ if (tokenBalance < amount.amount) {
4556
+ throw new acpError_default("Insufficient token balance for cross chain payable");
4557
+ }
4558
+ const currentAllowance = await this.acpContractClient.getERC20Allowance(
4559
+ chainId,
4560
+ amount.fare.contractAddress,
4561
+ this.acpContractClient.agentWalletAddress,
4562
+ ASSET_MANAGER_ADDRESSES[chainId]
4563
+ );
4564
+ const approveAllowanceOperation = this.acpContractClient.approveAllowance(
4565
+ amount.amount + currentAllowance,
4566
+ amount.fare.contractAddress,
4567
+ ASSET_MANAGER_ADDRESSES[chainId]
4568
+ );
4569
+ await this.acpContractClient.handleOperation(
4570
+ [approveAllowanceOperation],
4571
+ chainId
4572
+ );
4573
+ const tokenSymbol = await this.acpContractClient.getERC20Symbol(
4574
+ chainId,
4575
+ amount.fare.contractAddress
4576
+ );
4577
+ const createMemoOperation = this.acpContractClient.createCrossChainPayableMemo(
4578
+ this.id,
4579
+ `Performing cross chain payable transfer of ${formatUnits(
4580
+ amount.amount,
4581
+ amount.fare.decimals
4582
+ )} ${tokenSymbol} to ${recipient}`,
4583
+ amount.fare.contractAddress,
4584
+ amount.amount,
4585
+ recipient,
4586
+ BigInt(0),
4587
+ 0 /* NO_FEE */,
4588
+ 7 /* PAYABLE_TRANSFER */,
4589
+ new Date(Date.now() + 1e3 * 60 * 5),
4590
+ 4 /* COMPLETED */,
4591
+ getDestinationEndpointId(chainId)
4592
+ );
4593
+ await this.acpContractClient.handleOperation([createMemoOperation]);
4594
+ }
4305
4595
  [util.inspect.custom]() {
4306
4596
  return {
4307
4597
  id: this.id,
@@ -4325,7 +4615,7 @@ var acpJob_default = AcpJob;
4325
4615
  // src/acpMemo.ts
4326
4616
  import util2 from "util";
4327
4617
  var AcpMemo = class {
4328
- constructor(contractClient, id, type, content, nextPhase, status, senderAddress, signedReason, expiry, payableDetails, txHash, signedTxHash) {
4618
+ constructor(contractClient, id, type, content, nextPhase, status, senderAddress, signedReason, expiry, payableDetails, txHash, signedTxHash, state) {
4329
4619
  this.contractClient = contractClient;
4330
4620
  this.id = id;
4331
4621
  this.type = type;
@@ -4338,6 +4628,7 @@ var AcpMemo = class {
4338
4628
  this.payableDetails = payableDetails;
4339
4629
  this.txHash = txHash;
4340
4630
  this.signedTxHash = signedTxHash;
4631
+ this.state = state;
4341
4632
  if (this.payableDetails) {
4342
4633
  this.payableDetails.amount = BigInt(this.payableDetails.amount);
4343
4634
  this.payableDetails.feeAmount = BigInt(this.payableDetails.feeAmount);
@@ -4488,7 +4779,8 @@ var AcpClient = class {
4488
4779
  memo.expiry ? new Date(parseInt(memo.expiry) * 1e3) : void 0,
4489
4780
  memo.payableDetails,
4490
4781
  memo.txHash,
4491
- memo.signedTxHash
4782
+ memo.signedTxHash,
4783
+ memo.state
4492
4784
  );
4493
4785
  }),
4494
4786
  data.phase,
@@ -4526,7 +4818,8 @@ var AcpClient = class {
4526
4818
  memo.expiry ? new Date(parseInt(memo.expiry) * 1e3) : void 0,
4527
4819
  memo.payableDetails,
4528
4820
  memo.txHash,
4529
- memo.signedTxHash
4821
+ memo.signedTxHash,
4822
+ memo.state
4530
4823
  );
4531
4824
  }),
4532
4825
  data.phase,
@@ -4551,7 +4844,14 @@ var AcpClient = class {
4551
4844
  process.on("SIGTERM", cleanup);
4552
4845
  }
4553
4846
  async browseAgents(keyword, options) {
4554
- let { cluster, sort_by, top_k, graduationStatus, onlineStatus, showHiddenOfferings } = options;
4847
+ let {
4848
+ cluster,
4849
+ sort_by,
4850
+ top_k,
4851
+ graduationStatus,
4852
+ onlineStatus,
4853
+ showHiddenOfferings
4854
+ } = options;
4555
4855
  top_k = top_k ?? 5;
4556
4856
  let url = `${this.acpUrl}/api/agents/v4/search?search=${keyword}`;
4557
4857
  if (sort_by && sort_by.length > 0) {
@@ -4742,7 +5042,8 @@ var AcpClient = class {
4742
5042
  memo.expiry ? new Date(parseInt(memo.expiry) * 1e3) : void 0,
4743
5043
  memo.payableDetails,
4744
5044
  memo.txHash,
4745
- memo.signedTxHash
5045
+ memo.signedTxHash,
5046
+ memo.state
4746
5047
  )
4747
5048
  );
4748
5049
  jobs.push(
@@ -4816,7 +5117,8 @@ var AcpClient = class {
4816
5117
  memo.expiry ? new Date(parseInt(memo.expiry) * 1e3) : void 0,
4817
5118
  memo.payableDetails,
4818
5119
  memo.txHash,
4819
- memo.signedTxHash
5120
+ memo.signedTxHash,
5121
+ memo.state
4820
5122
  )
4821
5123
  );
4822
5124
  return new acpJob_default(
@@ -4875,7 +5177,8 @@ var AcpClient = class {
4875
5177
  memo.expiry ? new Date(parseInt(memo.expiry) * 1e3) : void 0,
4876
5178
  memo.payableDetails,
4877
5179
  memo.txHash,
4878
- memo.signedTxHash
5180
+ memo.signedTxHash,
5181
+ memo.state
4879
5182
  );
4880
5183
  } catch (err) {
4881
5184
  throw new acpError_default(
@@ -4988,6 +5291,9 @@ var AcpX402 = class {
4988
5291
  const acpJob = await response.json();
4989
5292
  return acpJob;
4990
5293
  } catch (error) {
5294
+ if (error instanceof acpError_default) {
5295
+ throw error;
5296
+ }
4991
5297
  throw new acpError_default("Failed to update job X402 nonce", error);
4992
5298
  }
4993
5299
  }
@@ -5076,6 +5382,9 @@ var AcpX402 = class {
5076
5382
  data
5077
5383
  };
5078
5384
  } catch (error) {
5385
+ if (error instanceof acpError_default) {
5386
+ throw error;
5387
+ }
5079
5388
  throw new acpError_default("Failed to perform X402 request", error);
5080
5389
  }
5081
5390
  }
@@ -6009,6 +6318,7 @@ var JOB_MANAGER_ABI = [
6009
6318
  var jobManagerAbi_default = JOB_MANAGER_ABI;
6010
6319
 
6011
6320
  // src/contractClients/acpContractClientV2.ts
6321
+ import { base as base4, baseSepolia as baseSepolia4 } from "viem/chains";
6012
6322
  var AcpContractClientV2 = class _AcpContractClientV2 extends baseAcpContractClient_default {
6013
6323
  constructor(jobManagerAddress, memoManagerAddress, accountManagerAddress, agentWalletAddress, config = baseAcpConfigV2) {
6014
6324
  super(agentWalletAddress, config);
@@ -6018,8 +6328,17 @@ var AcpContractClientV2 = class _AcpContractClientV2 extends baseAcpContractClie
6018
6328
  this.PRIORITY_FEE_MULTIPLIER = 2;
6019
6329
  this.MAX_FEE_PER_GAS = 2e7;
6020
6330
  this.MAX_PRIORITY_FEE_PER_GAS = 21e6;
6331
+ this.GAS_FEE_MULTIPLIER = 0.5;
6332
+ this._sessionKeyClients = {};
6021
6333
  }
6022
6334
  static async build(walletPrivateKey, sessionEntityKeyId, agentWalletAddress, config = baseAcpConfigV2) {
6335
+ const publicClients = {};
6336
+ for (const chain of config.chains) {
6337
+ publicClients[chain.chain.id] = createPublicClient4({
6338
+ chain: chain.chain,
6339
+ transport: http3(chain.rpcUrl)
6340
+ });
6341
+ }
6023
6342
  const publicClient = createPublicClient4({
6024
6343
  chain: config.chain,
6025
6344
  transport: http3(config.rpcEndpoint)
@@ -6055,6 +6374,7 @@ var AcpContractClientV2 = class _AcpContractClientV2 extends baseAcpContractClie
6055
6374
  agentWalletAddress,
6056
6375
  config
6057
6376
  );
6377
+ acpContractClient.publicClients = publicClients;
6058
6378
  await acpContractClient.init(walletPrivateKey, sessionEntityKeyId);
6059
6379
  return acpContractClient;
6060
6380
  }
@@ -6073,6 +6393,21 @@ var AcpContractClientV2 = class _AcpContractClientV2 extends baseAcpContractClie
6073
6393
  isGlobalValidation: true
6074
6394
  }
6075
6395
  });
6396
+ for (const chain of this.config.chains) {
6397
+ this._sessionKeyClients[chain.chain.id] = await createModularAccountV2Client2({
6398
+ chain: chain.chain,
6399
+ transport: alchemy2({
6400
+ rpcUrl: `${this.config.alchemyRpcUrl}?chainId=${chain.chain.id}`
6401
+ }),
6402
+ signer: sessionKeySigner,
6403
+ policyId: "186aaa4a-5f57-4156-83fb-e456365a8820",
6404
+ accountAddress: this.agentWalletAddress,
6405
+ signerEntity: {
6406
+ entityId: sessionEntityKeyId,
6407
+ isGlobalValidation: true
6408
+ }
6409
+ });
6410
+ }
6076
6411
  this._acpX402 = new AcpX402(
6077
6412
  this.config,
6078
6413
  this.sessionKeyClient,
@@ -6085,7 +6420,10 @@ var AcpContractClientV2 = class _AcpContractClientV2 extends baseAcpContractClie
6085
6420
  `ACP Contract Client validation failed: agent account ${this.agentWalletAddress} is not deployed on-chain`
6086
6421
  );
6087
6422
  }
6088
- await this.validateSessionKeyOnChain(sessionSignerAddress, sessionEntityKeyId);
6423
+ await this.validateSessionKeyOnChain(
6424
+ sessionSignerAddress,
6425
+ sessionEntityKeyId
6426
+ );
6089
6427
  console.log("Connected to ACP:", {
6090
6428
  agentWalletAddress: this.agentWalletAddress,
6091
6429
  whitelistedWalletAddress: sessionSignerAddress,
@@ -6113,11 +6451,20 @@ var AcpContractClientV2 = class _AcpContractClientV2 extends baseAcpContractClie
6113
6451
  }
6114
6452
  return this._acpX402;
6115
6453
  }
6116
- async calculateGasFees() {
6454
+ async calculateGasFees(chainId) {
6455
+ if (chainId) {
6456
+ const { maxFeePerGas } = await this.publicClients[chainId].estimateFeesPerGas();
6457
+ const increasedMaxFeePerGas = BigInt(maxFeePerGas) + BigInt(maxFeePerGas) * BigInt(this.GAS_FEE_MULTIPLIER * 100) / BigInt(100);
6458
+ return increasedMaxFeePerGas;
6459
+ }
6117
6460
  const finalMaxFeePerGas = BigInt(this.MAX_FEE_PER_GAS) + BigInt(this.MAX_PRIORITY_FEE_PER_GAS) * BigInt(Math.max(0, this.PRIORITY_FEE_MULTIPLIER - 1));
6118
6461
  return finalMaxFeePerGas;
6119
6462
  }
6120
- async handleOperation(operations) {
6463
+ async handleOperation(operations, chainId) {
6464
+ const sessionKeyClient = chainId ? this._sessionKeyClients[chainId] : this.sessionKeyClient;
6465
+ if (!sessionKeyClient) {
6466
+ throw new acpError_default("Session key client not initialized");
6467
+ }
6121
6468
  const payload = {
6122
6469
  uo: operations.map((operation) => ({
6123
6470
  target: operation.contractAddress,
@@ -6138,16 +6485,21 @@ var AcpContractClientV2 = class _AcpContractClientV2 extends baseAcpContractClie
6138
6485
  maxFeePerGas: `0x${gasFees.toString(16)}`
6139
6486
  };
6140
6487
  }
6141
- const { hash } = await this.sessionKeyClient.sendUserOperation(payload);
6142
- const txnHash = await this.sessionKeyClient.waitForUserOperationTransaction({
6488
+ const { hash } = await sessionKeyClient.sendUserOperation(payload);
6489
+ const checkTransactionConfig = {
6143
6490
  hash,
6144
- tag: "pending",
6145
6491
  retries: {
6146
6492
  intervalMs: 200,
6147
6493
  multiplier: 1.1,
6148
6494
  maxRetries: 10
6149
6495
  }
6150
- });
6496
+ };
6497
+ if (!chainId || chainId === baseSepolia4.id || chainId === base4.id) {
6498
+ checkTransactionConfig["tag"] = "pending";
6499
+ }
6500
+ const txnHash = await sessionKeyClient.waitForUserOperationTransaction(
6501
+ checkTransactionConfig
6502
+ );
6151
6503
  return { userOpHash: hash, txnHash };
6152
6504
  } catch (error) {
6153
6505
  retries -= 1;
@@ -6229,6 +6581,7 @@ export {
6229
6581
  acpJob_default as AcpJob,
6230
6582
  AcpJobPhases,
6231
6583
  acpMemo_default as AcpMemo,
6584
+ AcpMemoState,
6232
6585
  AcpMemoStatus,
6233
6586
  AcpOnlineStatus,
6234
6587
  baseAcpContractClient_default as BaseAcpContractClient,