@circle-fin/app-kit 1.12.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -658,6 +658,11 @@ class KitError extends Error {
658
658
  name: 'INPUT_UNSUPPORTED_TOKEN',
659
659
  type: 'INPUT'
660
660
  },
661
+ /** Action not supported by this adapter / ecosystem */ UNSUPPORTED_ACTION: {
662
+ code: 1008,
663
+ name: 'INPUT_UNSUPPORTED_ACTION',
664
+ type: 'INPUT'
665
+ },
661
666
  /** No route satisfies the slippage or minimum-output constraint */ SLIPPAGE_CONSTRAINT_NOT_MET: {
662
667
  code: 1009,
663
668
  name: 'INPUT_SLIPPAGE_CONSTRAINT_NOT_MET',
@@ -2292,6 +2297,8 @@ class KitError extends Error {
2292
2297
  Blockchain["Optimism_Sepolia"] = "Optimism_Sepolia";
2293
2298
  Blockchain["Pharos"] = "Pharos";
2294
2299
  Blockchain["Pharos_Testnet"] = "Pharos_Testnet";
2300
+ Blockchain["Plasma"] = "Plasma";
2301
+ Blockchain["Plasma_Testnet"] = "Plasma_Testnet";
2295
2302
  Blockchain["Polkadot_Asset_Hub"] = "Polkadot_Asset_Hub";
2296
2303
  Blockchain["Polkadot_Westmint"] = "Polkadot_Westmint";
2297
2304
  Blockchain["Plume"] = "Plume";
@@ -2361,6 +2368,7 @@ var BridgeChain;
2361
2368
  BridgeChain["Morph"] = "Morph";
2362
2369
  BridgeChain["Optimism"] = "Optimism";
2363
2370
  BridgeChain["Pharos"] = "Pharos";
2371
+ BridgeChain["Plasma"] = "Plasma";
2364
2372
  BridgeChain["Plume"] = "Plume";
2365
2373
  BridgeChain["Polygon"] = "Polygon";
2366
2374
  BridgeChain["Sei"] = "Sei";
@@ -2387,6 +2395,7 @@ var BridgeChain;
2387
2395
  BridgeChain["Morph_Testnet"] = "Morph_Testnet";
2388
2396
  BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
2389
2397
  BridgeChain["Pharos_Testnet"] = "Pharos_Testnet";
2398
+ BridgeChain["Plasma_Testnet"] = "Plasma_Testnet";
2390
2399
  BridgeChain["Plume_Testnet"] = "Plume_Testnet";
2391
2400
  BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
2392
2401
  BridgeChain["Sei_Testnet"] = "Sei_Testnet";
@@ -2833,6 +2842,8 @@ var EarnChain;
2833
2842
  * This program handles minting operations for Gateway transactions
2834
2843
  * on Solana devnet.
2835
2844
  */ const GATEWAY_MINTER_SOLANA_DEVNET = 'GATEmKK2ECL1brEngQZWCgMWPbvrEYqsV6u29dAaHavr';
2845
+ /** TokenMessengerWithFees address shared by enabled EVM mainnet sources. */ const TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET = '0x71f54F818671cD0D7ea140Da213e5C8b5C92a408';
2846
+ /** TokenMessengerWithFees address shared by enabled EVM testnet sources. */ const TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET = '0x8745D906D67C346E5eb1aEEED38Eb87F34DF0C0A';
2836
2847
  /**
2837
2848
  * Circle's fee recipient address for EVM chains.
2838
2849
  *
@@ -2880,6 +2891,7 @@ var EarnChain;
2880
2891
  v2: {
2881
2892
  type: 'split',
2882
2893
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
2894
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
2883
2895
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
2884
2896
  confirmations: 1,
2885
2897
  fastConfirmations: 1
@@ -2947,6 +2959,7 @@ var EarnChain;
2947
2959
  v2: {
2948
2960
  type: 'split',
2949
2961
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
2962
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
2950
2963
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
2951
2964
  confirmations: 65,
2952
2965
  fastConfirmations: 1
@@ -3011,6 +3024,7 @@ var EarnChain;
3011
3024
  v2: {
3012
3025
  type: 'split',
3013
3026
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
3027
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3014
3028
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
3015
3029
  confirmations: 65,
3016
3030
  fastConfirmations: 1
@@ -3075,6 +3089,7 @@ var EarnChain;
3075
3089
  v2: {
3076
3090
  type: 'split',
3077
3091
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3092
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3078
3093
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3079
3094
  confirmations: 1,
3080
3095
  fastConfirmations: 1
@@ -3136,6 +3151,7 @@ var EarnChain;
3136
3151
  v2: {
3137
3152
  type: 'split',
3138
3153
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3154
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3139
3155
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3140
3156
  confirmations: 1,
3141
3157
  fastConfirmations: 1
@@ -3203,6 +3219,7 @@ var EarnChain;
3203
3219
  v2: {
3204
3220
  type: 'split',
3205
3221
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3222
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3206
3223
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3207
3224
  confirmations: 65,
3208
3225
  fastConfirmations: 1
@@ -3267,6 +3284,7 @@ var EarnChain;
3267
3284
  v2: {
3268
3285
  type: 'split',
3269
3286
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3287
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3270
3288
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3271
3289
  confirmations: 65,
3272
3290
  fastConfirmations: 1
@@ -3377,6 +3395,7 @@ var EarnChain;
3377
3395
  v2: {
3378
3396
  type: 'split',
3379
3397
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3398
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3380
3399
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3381
3400
  confirmations: 65,
3382
3401
  fastConfirmations: 1
@@ -3421,6 +3440,7 @@ var EarnChain;
3421
3440
  v2: {
3422
3441
  type: 'split',
3423
3442
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3443
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3424
3444
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3425
3445
  confirmations: 65,
3426
3446
  fastConfirmations: 1
@@ -3652,6 +3672,7 @@ var EarnChain;
3652
3672
  v2: {
3653
3673
  type: 'split',
3654
3674
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3675
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3655
3676
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3656
3677
  confirmations: 65,
3657
3678
  fastConfirmations: 2
@@ -3716,6 +3737,7 @@ var EarnChain;
3716
3737
  v2: {
3717
3738
  type: 'split',
3718
3739
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3740
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3719
3741
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3720
3742
  confirmations: 65,
3721
3743
  fastConfirmations: 2
@@ -3826,6 +3848,7 @@ var EarnChain;
3826
3848
  v2: {
3827
3849
  type: 'split',
3828
3850
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3851
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3829
3852
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3830
3853
  confirmations: 1,
3831
3854
  fastConfirmations: 1
@@ -3885,6 +3908,7 @@ var EarnChain;
3885
3908
  v2: {
3886
3909
  type: 'split',
3887
3910
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
3911
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3888
3912
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
3889
3913
  confirmations: 1,
3890
3914
  fastConfirmations: 1
@@ -4039,6 +4063,7 @@ var EarnChain;
4039
4063
  v2: {
4040
4064
  type: 'split',
4041
4065
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4066
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4042
4067
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4043
4068
  confirmations: 65,
4044
4069
  fastConfirmations: 1
@@ -4086,6 +4111,7 @@ var EarnChain;
4086
4111
  v2: {
4087
4112
  type: 'split',
4088
4113
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4114
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4089
4115
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4090
4116
  confirmations: 65,
4091
4117
  fastConfirmations: 1
@@ -4130,6 +4156,7 @@ var EarnChain;
4130
4156
  v2: {
4131
4157
  type: 'split',
4132
4158
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4159
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4133
4160
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4134
4161
  confirmations: 1,
4135
4162
  fastConfirmations: 1
@@ -4175,6 +4202,7 @@ var EarnChain;
4175
4202
  v2: {
4176
4203
  type: 'split',
4177
4204
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
4205
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4178
4206
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
4179
4207
  confirmations: 1,
4180
4208
  fastConfirmations: 1
@@ -4221,6 +4249,7 @@ var EarnChain;
4221
4249
  v2: {
4222
4250
  type: 'split',
4223
4251
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4252
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4224
4253
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4225
4254
  confirmations: 1,
4226
4255
  fastConfirmations: 1
@@ -4534,6 +4563,7 @@ var EarnChain;
4534
4563
  v2: {
4535
4564
  type: 'split',
4536
4565
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4566
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4537
4567
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4538
4568
  confirmations: 65,
4539
4569
  fastConfirmations: 1
@@ -4598,6 +4628,7 @@ var EarnChain;
4598
4628
  v2: {
4599
4629
  type: 'split',
4600
4630
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
4631
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4601
4632
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
4602
4633
  confirmations: 65,
4603
4634
  fastConfirmations: 1
@@ -4718,6 +4749,98 @@ var EarnChain;
4718
4749
  }
4719
4750
  });
4720
4751
 
4752
+ /**
4753
+ * Plasma Mainnet chain definition
4754
+ * @remarks
4755
+ * This represents the official production network for the Plasma blockchain.
4756
+ * Plasma is an EVM-equivalent Layer 1 blockchain purpose-built for global
4757
+ * stablecoin payments, with deterministic BFT finality (PlasmaBFT/Fast-HotStuff).
4758
+ */ const Plasma = defineChain({
4759
+ type: 'evm',
4760
+ chain: Blockchain.Plasma,
4761
+ name: 'Plasma',
4762
+ title: 'Plasma Mainnet',
4763
+ nativeCurrency: {
4764
+ name: 'Plasma',
4765
+ symbol: 'XPL',
4766
+ decimals: 18
4767
+ },
4768
+ chainId: 9745,
4769
+ isTestnet: false,
4770
+ explorerUrl: 'https://plasmascan.to/tx/{hash}',
4771
+ rpcEndpoints: [
4772
+ 'https://rpc.plasma.to'
4773
+ ],
4774
+ eurcAddress: '0x3EE196E78d4d4248b849B8E1C7F44C5457FAFD2C',
4775
+ usdcAddress: '0x2d661C89D812261039AF9764eceaAee884f5F67F',
4776
+ usdtAddress: null,
4777
+ cctp: {
4778
+ domain: 33,
4779
+ contracts: {
4780
+ v2: {
4781
+ type: 'split',
4782
+ tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4783
+ messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4784
+ confirmations: 3,
4785
+ fastConfirmations: 1
4786
+ }
4787
+ },
4788
+ forwarderSupported: {
4789
+ source: false,
4790
+ destination: false
4791
+ }
4792
+ },
4793
+ kitContracts: {
4794
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET
4795
+ }
4796
+ });
4797
+
4798
+ /**
4799
+ * Plasma Testnet chain definition
4800
+ * @remarks
4801
+ * This represents the official test network for the Plasma blockchain.
4802
+ * Plasma is an EVM-equivalent Layer 1 blockchain purpose-built for global
4803
+ * stablecoin payments, with deterministic BFT finality (PlasmaBFT/Fast-HotStuff).
4804
+ */ const PlasmaTestnet = defineChain({
4805
+ type: 'evm',
4806
+ chain: Blockchain.Plasma_Testnet,
4807
+ name: 'Plasma Testnet',
4808
+ title: 'Plasma Testnet',
4809
+ nativeCurrency: {
4810
+ name: 'Plasma',
4811
+ symbol: 'XPL',
4812
+ decimals: 18
4813
+ },
4814
+ chainId: 9746,
4815
+ isTestnet: true,
4816
+ explorerUrl: 'https://testnet.plasmascan.to/tx/{hash}',
4817
+ rpcEndpoints: [
4818
+ 'https://testnet-rpc.plasma.to'
4819
+ ],
4820
+ eurcAddress: '0x98AfA0F93Dd993B736399f9074eDcEBD1985A330',
4821
+ usdcAddress: '0xE67Fb267022cBA8064Dd388CC2FED724F3120D9D',
4822
+ usdtAddress: null,
4823
+ cctp: {
4824
+ domain: 33,
4825
+ contracts: {
4826
+ v2: {
4827
+ type: 'split',
4828
+ tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4829
+ messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4830
+ confirmations: 3,
4831
+ fastConfirmations: 1
4832
+ }
4833
+ },
4834
+ forwarderSupported: {
4835
+ source: false,
4836
+ destination: false
4837
+ }
4838
+ },
4839
+ kitContracts: {
4840
+ bridge: BRIDGE_CONTRACT_EVM_TESTNET
4841
+ }
4842
+ });
4843
+
4721
4844
  /**
4722
4845
  * Plume Mainnet chain definition
4723
4846
  * @remarks
@@ -4749,6 +4872,7 @@ var EarnChain;
4749
4872
  v2: {
4750
4873
  type: 'split',
4751
4874
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4875
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4752
4876
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4753
4877
  confirmations: 65,
4754
4878
  fastConfirmations: 1
@@ -4795,6 +4919,7 @@ var EarnChain;
4795
4919
  v2: {
4796
4920
  type: 'split',
4797
4921
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4922
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4798
4923
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4799
4924
  confirmations: 65,
4800
4925
  fastConfirmations: 1
@@ -4896,6 +5021,7 @@ var EarnChain;
4896
5021
  v2: {
4897
5022
  type: 'split',
4898
5023
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5024
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4899
5025
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4900
5026
  confirmations: 33,
4901
5027
  fastConfirmations: 13
@@ -4961,6 +5087,7 @@ var EarnChain;
4961
5087
  v2: {
4962
5088
  type: 'split',
4963
5089
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5090
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4964
5091
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4965
5092
  confirmations: 33,
4966
5093
  fastConfirmations: 13
@@ -5020,6 +5147,7 @@ var EarnChain;
5020
5147
  v2: {
5021
5148
  type: 'split',
5022
5149
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5150
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5023
5151
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5024
5152
  confirmations: 1,
5025
5153
  fastConfirmations: 1
@@ -5079,6 +5207,7 @@ var EarnChain;
5079
5207
  v2: {
5080
5208
  type: 'split',
5081
5209
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5210
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5082
5211
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5083
5212
  confirmations: 1,
5084
5213
  fastConfirmations: 1
@@ -5136,6 +5265,7 @@ var EarnChain;
5136
5265
  v2: {
5137
5266
  type: 'split',
5138
5267
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5268
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5139
5269
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5140
5270
  confirmations: 1,
5141
5271
  fastConfirmations: 1
@@ -5194,6 +5324,7 @@ var EarnChain;
5194
5324
  v2: {
5195
5325
  type: 'split',
5196
5326
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5327
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5197
5328
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5198
5329
  confirmations: 1,
5199
5330
  fastConfirmations: 1
@@ -5509,6 +5640,7 @@ var EarnChain;
5509
5640
  v2: {
5510
5641
  type: 'split',
5511
5642
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5643
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5512
5644
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5513
5645
  confirmations: 65,
5514
5646
  fastConfirmations: 1
@@ -5573,6 +5705,7 @@ var EarnChain;
5573
5705
  v2: {
5574
5706
  type: 'split',
5575
5707
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5708
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5576
5709
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5577
5710
  confirmations: 65,
5578
5711
  fastConfirmations: 1
@@ -5630,6 +5763,7 @@ var EarnChain;
5630
5763
  v2: {
5631
5764
  type: 'split',
5632
5765
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cF5d',
5766
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5633
5767
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5634
5768
  confirmations: 65,
5635
5769
  fastConfirmations: 1
@@ -5689,6 +5823,7 @@ var EarnChain;
5689
5823
  v2: {
5690
5824
  type: 'split',
5691
5825
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
5826
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5692
5827
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
5693
5828
  confirmations: 65,
5694
5829
  fastConfirmations: 1
@@ -5749,6 +5884,7 @@ var EarnChain;
5749
5884
  v2: {
5750
5885
  type: 'split',
5751
5886
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5887
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5752
5888
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5753
5889
  confirmations: 3,
5754
5890
  fastConfirmations: 3
@@ -5794,6 +5930,7 @@ var EarnChain;
5794
5930
  v2: {
5795
5931
  type: 'split',
5796
5932
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5933
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5797
5934
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5798
5935
  confirmations: 3,
5799
5936
  fastConfirmations: 1
@@ -6004,6 +6141,8 @@ var Chains = /*#__PURE__*/Object.freeze({
6004
6141
  OptimismSepolia: OptimismSepolia,
6005
6142
  Pharos: Pharos,
6006
6143
  PharosTestnet: PharosTestnet,
6144
+ Plasma: Plasma,
6145
+ PlasmaTestnet: PlasmaTestnet,
6007
6146
  Plume: Plume,
6008
6147
  PlumeTestnet: PlumeTestnet,
6009
6148
  PolkadotAssetHub: PolkadotAssetHub,
@@ -7969,6 +8108,7 @@ function parseOrThrow(value, schema, context) {
7969
8108
  [Blockchain.Noble]: 'uusdc',
7970
8109
  [Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
7971
8110
  [Blockchain.Pharos]: '0xC879C018dB60520F4355C26eD1a6D572cdAC1815',
8111
+ [Blockchain.Plasma]: '0x2d661C89D812261039AF9764eceaAee884f5F67F',
7972
8112
  [Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
7973
8113
  [Blockchain.Polkadot_Asset_Hub]: '1337',
7974
8114
  [Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
@@ -7989,6 +8129,7 @@ function parseOrThrow(value, schema, context) {
7989
8129
  [Blockchain.Arbitrum_Sepolia]: '0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d',
7990
8130
  [Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
7991
8131
  [Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
8132
+ [Blockchain.Celo_Alfajores_Testnet]: '0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B',
7992
8133
  [Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
7993
8134
  [Blockchain.Cronos_Testnet]: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
7994
8135
  [Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
@@ -8004,6 +8145,7 @@ function parseOrThrow(value, schema, context) {
8004
8145
  [Blockchain.Noble_Testnet]: 'uusdc',
8005
8146
  [Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
8006
8147
  [Blockchain.Pharos_Testnet]: '0xcfC8330f4BCAB529c625D12781b1C19466A9Fc8B',
8148
+ [Blockchain.Plasma_Testnet]: '0xE67Fb267022cBA8064Dd388CC2FED724F3120D9D',
8007
8149
  [Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
8008
8150
  [Blockchain.Polkadot_Westmint]: '31337',
8009
8151
  [Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
@@ -8066,6 +8208,7 @@ function parseOrThrow(value, schema, context) {
8066
8208
  [Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
8067
8209
  [Blockchain.Cronos]: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
8068
8210
  [Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
8211
+ [Blockchain.Plasma]: '0x3EE196E78d4d4248b849B8E1C7F44C5457FAFD2C',
8069
8212
  [Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
8070
8213
  [Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
8071
8214
  // =========================================================================
@@ -8074,7 +8217,8 @@ function parseOrThrow(value, schema, context) {
8074
8217
  [Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
8075
8218
  [Blockchain.Base_Sepolia]: '0x808456652fdb597867f38412077A9182bf77359F',
8076
8219
  [Blockchain.Cronos_Testnet]: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
8077
- [Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4'
8220
+ [Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4',
8221
+ [Blockchain.Plasma_Testnet]: '0x98AfA0F93Dd993B736399f9074eDcEBD1985A330'
8078
8222
  }
8079
8223
  };
8080
8224
 
@@ -8881,7 +9025,7 @@ function parseOrThrow(value, schema, context) {
8881
9025
  }
8882
9026
 
8883
9027
  var name = "@circle-fin/unified-balance-kit";
8884
- var version = "1.4.0";
9028
+ var version = "1.5.0";
8885
9029
  var pkg = {
8886
9030
  name: name,
8887
9031
  version: version};
@@ -9164,6 +9308,110 @@ var pkg = {
9164
9308
  * ```
9165
9309
  */ const USDC_DECIMALS$1 = 6;
9166
9310
 
9311
+ /**
9312
+ * Canonical list of actions that do not prepare or submit transactions.
9313
+ *
9314
+ * @internal
9315
+ */ const READ_ACTION_KEYS = [
9316
+ 'token.allowance',
9317
+ 'token.balanceOf',
9318
+ 'token.name',
9319
+ 'native.balanceOf',
9320
+ 'usdc.allowance',
9321
+ 'usdc.balanceOf',
9322
+ 'usdc.name',
9323
+ 'gateway.v1.isDelegate',
9324
+ 'gateway.v1.withdrawingBalance',
9325
+ 'gateway.v1.withdrawalBlock',
9326
+ 'gateway.v1.signBurnIntents'
9327
+ ];
9328
+ const READ_ACTION_KEY_SET = new Set(READ_ACTION_KEYS);
9329
+ /**
9330
+ * Check whether a runtime value identifies a read action.
9331
+ *
9332
+ * @param action - The value to classify.
9333
+ * @returns Whether the value is a registered read-action key.
9334
+ *
9335
+ * @example
9336
+ * ```typescript
9337
+ * import { isReadActionKey } from '@core/adapter'
9338
+ *
9339
+ * if (isReadActionKey(value)) {
9340
+ * await adapter.readAction(value, params, context)
9341
+ * }
9342
+ * ```
9343
+ *
9344
+ * @internal
9345
+ */ function isReadActionKey(action) {
9346
+ return typeof action === 'string' && READ_ACTION_KEY_SET.has(action);
9347
+ }
9348
+
9349
+ /**
9350
+ * Create the standard error for a missing or non-read action.
9351
+ *
9352
+ * @param action - The unsupported action value.
9353
+ * @returns A fatal unsupported-action error.
9354
+ *
9355
+ * @internal
9356
+ */ function createUnsupportedReadActionError(action) {
9357
+ return new KitError({
9358
+ ...InputError.UNSUPPORTED_ACTION,
9359
+ recoverability: 'FATAL',
9360
+ message: `Read action "${String(action)}" is not registered in this adapter.`
9361
+ });
9362
+ }
9363
+ /**
9364
+ * Execute a read through the adapter's dedicated read seam when available.
9365
+ *
9366
+ * @remarks
9367
+ * Fall back to the legacy `prepareAction().execute()` contract so providers
9368
+ * remain runtime-compatible with adapter versions released before `readAction`.
9369
+ * Consumers must upgrade their adapter package for reads to bypass custom
9370
+ * `prepareAction` wrappers.
9371
+ *
9372
+ * @typeParam TAdapterCapabilities - The adapter capabilities type.
9373
+ * @typeParam TActionKey - The read action key.
9374
+ * @param adapter - The adapter that owns the read action.
9375
+ * @param action - The read action to execute.
9376
+ * @param params - The parameters for the read action.
9377
+ * @param ctx - The operation context.
9378
+ * @returns The raw read-action result.
9379
+ * @throws {KitError} When `action` is not a supported read-action key.
9380
+ *
9381
+ * @example
9382
+ * ```typescript
9383
+ * import { executeAdapterReadAction } from '@core/adapter'
9384
+ * import { Ethereum } from '@core/chains'
9385
+ *
9386
+ * const allowance = await executeAdapterReadAction(
9387
+ * adapter,
9388
+ * 'token.allowance',
9389
+ * { tokenAddress, delegate },
9390
+ * { chain: Ethereum },
9391
+ * )
9392
+ * ```
9393
+ *
9394
+ * @internal
9395
+ */ async function executeAdapterReadAction(adapter, action, params, ctx) {
9396
+ if (!isReadActionKey(action)) {
9397
+ throw createUnsupportedReadActionError(action);
9398
+ }
9399
+ const runtimeAdapter = adapter;
9400
+ if (typeof runtimeAdapter.readAction === 'function') {
9401
+ return runtimeAdapter.readAction(action, params, ctx);
9402
+ }
9403
+ let request;
9404
+ try {
9405
+ request = await adapter.prepareAction(action, params, ctx);
9406
+ } catch (error) {
9407
+ if (error instanceof Error && error.message === `Action ${action} is not supported`) {
9408
+ throw createUnsupportedReadActionError(action);
9409
+ }
9410
+ throw error;
9411
+ }
9412
+ return request.execute();
9413
+ }
9414
+
9167
9415
  /**
9168
9416
  * Schema for validating hexadecimal strings with '0x' prefix.
9169
9417
  *
@@ -9373,16 +9621,15 @@ var pkg = {
9373
9621
  * ```
9374
9622
  */ const validateBalanceForTransaction = async (params)=>{
9375
9623
  const { amount, adapter, token, tokenAddress, operationContext } = params;
9376
- const balancePrepared = await adapter.prepareAction('usdc.balanceOf', {
9624
+ const balance = await executeAdapterReadAction(adapter, 'usdc.balanceOf', {
9377
9625
  walletAddress: operationContext.address
9378
9626
  }, operationContext);
9379
- const balance = await balancePrepared.execute();
9380
- if (BigInt(balance) < BigInt(amount)) {
9627
+ if (BigInt(String(balance)) < BigInt(amount)) {
9381
9628
  // Extract chain name from operationContext
9382
9629
  const chainName = extractChainInfo(operationContext.chain).name;
9383
9630
  // Create KitError with rich context in trace
9384
9631
  throw createInsufficientTokenBalanceError(chainName, token, {
9385
- balance: balance.toString(),
9632
+ balance: String(balance),
9386
9633
  amount,
9387
9634
  tokenAddress,
9388
9635
  walletAddress: operationContext.address
@@ -12354,6 +12601,23 @@ async function signUnits(group, signingUnits) {
12354
12601
  }
12355
12602
  return signedSets;
12356
12603
  }
12604
+ /**
12605
+ * Fail loudly if a signing group carries an intent it does not own.
12606
+ *
12607
+ * Every intent in a group is signed by `group.address`, so that signer must own
12608
+ * each intent's `spec.sourceSigner`. If distinct spend sources ever collapse
12609
+ * into one group again (DEVX-3638), this throws before signing instead of
12610
+ * silently producing a wrong-signer signature. specs are bytes32 and
12611
+ * `group.address` is a native address, so normalize both before comparing.
12612
+ */ function assertGroupSignerOwnsIntents(group) {
12613
+ if (group.address == null || group.address === '') return;
12614
+ const groupSigner = convertAddress(group.address, 'bytes32').toLowerCase();
12615
+ for (const intent of group.intents){
12616
+ if (intent.spec.sourceSigner.toLowerCase() !== groupSigner) {
12617
+ throw createValidationFailedError$1('group.address', group.address, `Signing group for ${group.address} carries an intent whose ` + `sourceSigner is ${intent.spec.sourceSigner}; a group must be signed ` + 'by the wallet that owns every intent it carries. This indicates ' + 'distinct spend sources collapsed into a single signing group.');
12618
+ }
12619
+ }
12620
+ }
12357
12621
  /**
12358
12622
  * Sign an EVM adapter group.
12359
12623
  *
@@ -12396,22 +12660,42 @@ async function signUnits(group, signingUnits) {
12396
12660
  // Validate the collection before doing bytecode reads or asking a wallet
12397
12661
  // to sign. evmSigningData owns the canonical BurnIntent validation.
12398
12662
  validateGroupIntents(group.intents);
12663
+ // Guard against a wrong-signer collapse: the group's signer must own every
12664
+ // intent it carries.
12665
+ assertGroupSignerOwnsIntents(group);
12399
12666
  const chainsByDomain = collectChainsByDomain(group);
12400
12667
  const signerTypeByDomain = await classifySignerTypes(group, chainsByDomain);
12401
12668
  const signingUnits = createSigningUnits(group, signerTypeByDomain);
12402
12669
  return await signUnits(group, signingUnits);
12403
12670
  }
12404
12671
 
12672
+ // One adapter instance can serve several signer addresses (e.g. a single
12673
+ // dev-controlled adapter used for multiple wallets), so the group map must be
12674
+ // keyed on `(adapter, sourceSigner)` rather than the adapter reference alone.
12675
+ // Keying on the adapter alone collapsed two same-chain sources into one group,
12676
+ // signing the second wallet's intent with the first wallet (DEVX-3638 /
12677
+ // DEVX-3194). A Map needs a primitive key, so give each adapter instance a
12678
+ // stable token and combine it with the (case-normalized) signer address.
12679
+ const adapterTokens = new WeakMap();
12680
+ let nextAdapterToken = 0;
12681
+ function groupKey(alloc) {
12682
+ let token = adapterTokens.get(alloc.adapter);
12683
+ if (token === undefined) {
12684
+ token = nextAdapterToken++;
12685
+ adapterTokens.set(alloc.adapter, token);
12686
+ }
12687
+ return `${String(token)}:${alloc.sourceSigner.toLowerCase()}`;
12688
+ }
12405
12689
  /**
12406
12690
  * Add an EVM intent into the batched EVM group map.
12407
12691
  *
12408
- * On EVM, all intents for the same adapter are batched into a single
12409
- * group. The signing step uses `chainsByDomain` to preserve EOA batching
12692
+ * On EVM, all intents for the same adapter **and signer** are batched into a
12693
+ * single group. The signing step uses `chainsByDomain` to preserve EOA batching
12410
12694
  * while signing ERC-1271 intents separately on their source chains.
12411
12695
  *
12412
12696
  * @param intent - The burn intent to group.
12413
12697
  * @param alloc - The allocation that resolved to this intent.
12414
- * @param evmGroups - Mutable map of adapter → EVM group.
12698
+ * @param evmGroups - Mutable map of `(adapter, sourceSigner)` key → EVM group.
12415
12699
  *
12416
12700
  * @example
12417
12701
  * ```typescript
@@ -12421,12 +12705,13 @@ async function signUnits(group, signingUnits) {
12421
12705
  * groupEvmIntents(intent, alloc, groups)
12422
12706
  * ```
12423
12707
  */ function groupEvmIntents(intent, alloc, evmGroups) {
12424
- const existing = evmGroups.get(alloc.adapter);
12708
+ const key = groupKey(alloc);
12709
+ const existing = evmGroups.get(key);
12425
12710
  if (existing) {
12426
12711
  existing.intents.push(intent);
12427
12712
  existing.chainsByDomain.set(alloc.chain.gateway.domain, alloc.chain);
12428
12713
  } else {
12429
- evmGroups.set(alloc.adapter, {
12714
+ evmGroups.set(key, {
12430
12715
  adapter: alloc.adapter,
12431
12716
  chain: alloc.chain,
12432
12717
  intents: [
@@ -13455,6 +13740,8 @@ const gatewayInfoSchema = z.object({
13455
13740
  * Fetch Gateway info from the `/v1/info` endpoint.
13456
13741
  *
13457
13742
  * @param isTestnet - Whether to query the testnet or mainnet API.
13743
+ * @param config - Optional polling config overrides, including custom
13744
+ * `headers` forwarded with the request.
13458
13745
  * @returns Parsed Gateway info including per-domain processed heights.
13459
13746
  * @throws KitError on HTTP failure or invalid response.
13460
13747
  *
@@ -13463,11 +13750,11 @@ const gatewayInfoSchema = z.object({
13463
13750
  * const info = await fetchGatewayInfo(true)
13464
13751
  * console.log(info.domains.map(d => `${d.chain}: ${d.processedHeight}`))
13465
13752
  * ```
13466
- */ async function fetchGatewayInfo(isTestnet) {
13753
+ */ async function fetchGatewayInfo(isTestnet, config) {
13467
13754
  const apiBaseUrl = getGatewayApiBaseUrl(isTestnet);
13468
13755
  const url = `${apiBaseUrl}/v1/info`;
13469
13756
  try {
13470
- return await pollApiGet(url, assertGatewayInfoResponse);
13757
+ return await pollApiGet(url, assertGatewayInfoResponse, config);
13471
13758
  } catch (error) {
13472
13759
  if (error instanceof KitError) {
13473
13760
  throw error;
@@ -13493,6 +13780,8 @@ const gatewayInfoSchema = z.object({
13493
13780
  *
13494
13781
  * @param isTestnet - Whether to query the testnet or mainnet API.
13495
13782
  * @param domain - The Gateway domain number (e.g. 0 = Ethereum, 6 = Base).
13783
+ * @param config - Optional polling config overrides, including custom
13784
+ * `headers` forwarded with the `/v1/info` request.
13496
13785
  * @returns The processed height as a bigint.
13497
13786
  * @throws KitError when the domain is not found in the response.
13498
13787
  *
@@ -13501,10 +13790,10 @@ const gatewayInfoSchema = z.object({
13501
13790
  * const height = await getProcessedHeight(true, 6) // Base Sepolia
13502
13791
  * console.log(`Gateway processed up to block ${height}`)
13503
13792
  * ```
13504
- */ async function getProcessedHeight(isTestnet, domain) {
13793
+ */ async function getProcessedHeight(isTestnet, domain, config) {
13505
13794
  // No caching in v1 — /v1/info is cheap and delegate status checks
13506
13795
  // are infrequent. Revisit if rate-limit or latency issues appear.
13507
- const info = await fetchGatewayInfo(isTestnet);
13796
+ const info = await fetchGatewayInfo(isTestnet, config);
13508
13797
  const entry = info.domains.find((d)=>d.domain === domain);
13509
13798
  if (!entry) {
13510
13799
  throw new KitError({
@@ -13970,12 +14259,22 @@ function throwNetworkMismatch(expected, actual) {
13970
14259
  * @param allocations - Normalized allocations used to map domain → adapter/chain.
13971
14260
  * @returns Array of groups, each with adapter, chain, and intents to sign.
13972
14261
  */ function groupIntentsByAdapter(intents, allocations) {
14262
+ // Keyed by `(adapter, sourceSigner)` (see groupEvmIntents), not by adapter
14263
+ // alone: two spend sources on the same chain — including two addresses behind
14264
+ // one shared adapter — must stay in separate signing groups.
13973
14265
  const evmGroups = new Map();
13974
14266
  const solanaGroups = [];
13975
14267
  for (const intent of intents){
13976
- const alloc = allocations.find((a)=>a.chain.gateway.domain === intent.spec.sourceDomain);
14268
+ // Match each intent back to its source allocation by BOTH Gateway domain
14269
+ // and signer. Two spend sources on the same chain share a domain, so
14270
+ // matching on domain alone always returned the FIRST allocation — folding
14271
+ // the second wallet's intent into the first wallet's signing group so it
14272
+ // was signed by the wrong wallet (DEVX-3638). specs carry sourceSigner as
14273
+ // bytes32 and allocations carry native addresses, so normalize both.
14274
+ const intentSigner = intent.spec.sourceSigner.toLowerCase();
14275
+ const alloc = allocations.find((a)=>a.chain.gateway.domain === intent.spec.sourceDomain && convertAddress(a.sourceSigner, 'bytes32').toLowerCase() === intentSigner);
13977
14276
  if (!alloc) {
13978
- throw createValidationFailedError$1('intent.spec.sourceDomain', intent.spec.sourceDomain, `No allocation found for sourceDomain ${String(intent.spec.sourceDomain)}; ` + 'estimate response contains an intent that does not match any allocation');
14277
+ throw createValidationFailedError$1('intent.spec.sourceDomain', intent.spec.sourceDomain, `No allocation found for sourceDomain ${String(intent.spec.sourceDomain)} and sourceSigner ${String(intent.spec.sourceSigner)}; ` + 'estimate response contains an intent that does not match any allocation');
13979
14278
  }
13980
14279
  if (alloc.chain.type === 'solana') {
13981
14280
  solanaGroups.push(groupSolanaIntents(intent, alloc));
@@ -17392,12 +17691,12 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17392
17691
  * exceeds the 5-minute timeout without reaching a terminal status.
17393
17692
  * @throws KitError Propagated from {@link pollApiGet} if the HTTP
17394
17693
  * request itself fails or returns a non-OK response.
17395
- */ async function pollForwarderCompletion(apiBaseUrl, transferId) {
17694
+ */ async function pollForwarderCompletion(apiBaseUrl, transferId, requestConfig) {
17396
17695
  const startTime = Date.now();
17397
17696
  while(Date.now() - startTime < FORWARDER_POLL_TIMEOUT_MS){
17398
17697
  let status;
17399
17698
  try {
17400
- status = await pollApiGet(`${apiBaseUrl}/v1/transfer/${transferId}`, assertGatewayTransferDetails);
17699
+ status = await pollApiGet(`${apiBaseUrl}/v1/transfer/${transferId}`, assertGatewayTransferDetails, requestConfig);
17401
17700
  } catch (error) {
17402
17701
  throwGatewayApiError(error);
17403
17702
  }
@@ -17515,7 +17814,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17515
17814
  * @param params - Spend parameters (source(s) and token).
17516
17815
  * @param destChain - Resolved destination chain (used for network type).
17517
17816
  * @returns Confirmed balances tagged with their originating source index.
17518
- */ async function fetchChainBalances(params, destChain) {
17817
+ */ async function fetchChainBalances(params, destChain, requestConfig) {
17519
17818
  const rawSources = Array.isArray(params.from) ? params.from : [
17520
17819
  params.from
17521
17820
  ];
@@ -17544,7 +17843,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17544
17843
  token: params.token,
17545
17844
  sources: querySource,
17546
17845
  networkType
17547
- });
17846
+ }, requestConfig);
17548
17847
  }));
17549
17848
  const chainBalances = [];
17550
17849
  for(let i = 0; i < balanceResults.length; i++){
@@ -17617,9 +17916,9 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17617
17916
  * @param recipientAddress - Resolved recipient address.
17618
17917
  * @param useForwarder - Whether the Forwarding Service path is active.
17619
17918
  * @returns Allocations, intents, and (auto-allocation only) confirmed balances.
17620
- */ async function resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder) {
17919
+ */ async function resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder, requestConfig) {
17621
17920
  if (params.amountIn) {
17622
- const chainBalances = await fetchChainBalances(params, destChain);
17921
+ const chainBalances = await fetchChainBalances(params, destChain, requestConfig);
17623
17922
  const { allocations, intents } = await buildAutoAllocatedFromBalances(params, destChain, recipientAddress, useForwarder, params.amountIn, chainBalances);
17624
17923
  return {
17625
17924
  allocations,
@@ -17642,11 +17941,11 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17642
17941
  * @param useForwarder - Whether the Forwarding Service path is active.
17643
17942
  * @param allocations - Normalised allocations (forwarded to error handler).
17644
17943
  * @returns Estimate entries and optional forwarding fee.
17645
- */ async function fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations) {
17944
+ */ async function fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations, requestConfig) {
17646
17945
  if (useForwarder) {
17647
17946
  let fwdResponse;
17648
17947
  try {
17649
- fwdResponse = await pollApiPost(`${apiBaseUrl}/v1/estimate?enableForwarder=true`, estimateBody, assertGatewayForwarderEstimateResponse);
17948
+ fwdResponse = await pollApiPost(`${apiBaseUrl}/v1/estimate?enableForwarder=true`, estimateBody, assertGatewayForwarderEstimateResponse, requestConfig);
17650
17949
  } catch (error) {
17651
17950
  throwGatewayApiError(error, allocations);
17652
17951
  }
@@ -17657,7 +17956,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17657
17956
  }
17658
17957
  let entries;
17659
17958
  try {
17660
- entries = await pollApiPost(`${apiBaseUrl}/v1/estimate`, estimateBody, assertGatewayEstimateResponse);
17959
+ entries = await pollApiPost(`${apiBaseUrl}/v1/estimate`, estimateBody, assertGatewayEstimateResponse, requestConfig);
17661
17960
  } catch (error) {
17662
17961
  throwGatewayApiError(error, allocations);
17663
17962
  }
@@ -17728,14 +18027,14 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17728
18027
  * @param destChain - Resolved destination chain with Gateway v1 config.
17729
18028
  * @param useForwarder - Whether the Forwarding Service path is active.
17730
18029
  * @returns Estimated intents (with real maxFee) and optional forwarding fee.
17731
- */ async function validateAndEstimate(allocations, intents, destChain, useForwarder) {
18030
+ */ async function validateAndEstimate(allocations, intents, destChain, useForwarder, requestConfig) {
17732
18031
  assertNetworkCompatibility(allocations, destChain);
17733
18032
  if (useForwarder) {
17734
18033
  assertForwarderRouteSupport(destChain, allocations);
17735
18034
  }
17736
18035
  const apiBaseUrl = getGatewayApiBaseUrl(destChain.isTestnet);
17737
18036
  const estimateBody = buildEstimateRequestBody(intents);
17738
- const { entries, forwardingFee } = await fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations);
18037
+ const { entries, forwardingFee } = await fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations, requestConfig);
17739
18038
  const estimatedIntents = parseEstimateResponse(entries, intents);
17740
18039
  return {
17741
18040
  estimatedIntents,
@@ -17794,7 +18093,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17794
18093
  }
17795
18094
  throw err;
17796
18095
  }
17797
- const { estimatedIntents, forwardingFee } = await validateAndEstimate(corrected.allocations, corrected.intents, opts.destChain, opts.useForwarder);
18096
+ const { estimatedIntents, forwardingFee } = await validateAndEstimate(corrected.allocations, corrected.intents, opts.destChain, opts.useForwarder, opts.requestConfig);
17798
18097
  const stillOverdrawn = findOverdrawnChains(estimatedIntents, corrected.allocations, opts.chainBalances);
17799
18098
  if (stillOverdrawn.length === 0) {
17800
18099
  return {
@@ -17828,12 +18127,12 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17828
18127
  * @param recipientAddress - Resolved recipient address.
17829
18128
  * @param useForwarder - Whether the Forwarding Service path is active.
17830
18129
  * @returns Allocations, estimated intents, and optional forwarding fee.
17831
- */ async function resolveValidatedIntents(params, destChain, recipientAddress, useForwarder) {
18130
+ */ async function resolveValidatedIntents(params, destChain, recipientAddress, useForwarder, requestConfig) {
17832
18131
  if (useForwarder) {
17833
18132
  assertForwarderRouteSupport(destChain);
17834
18133
  }
17835
- const { allocations, intents, chainBalances } = await resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder);
17836
- const { estimatedIntents, forwardingFee } = await validateAndEstimate(allocations, intents, destChain, useForwarder);
18134
+ const { allocations, intents, chainBalances } = await resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder, requestConfig);
18135
+ const { estimatedIntents, forwardingFee } = await validateAndEstimate(allocations, intents, destChain, useForwarder, requestConfig);
17837
18136
  if (params.amountIn && chainBalances) {
17838
18137
  const overdrawn = findOverdrawnChains(estimatedIntents, allocations, chainBalances);
17839
18138
  if (overdrawn.length > 0) {
@@ -17846,7 +18145,10 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17846
18145
  chainBalances,
17847
18146
  estimatedIntents,
17848
18147
  allocations,
17849
- overdrawn
18148
+ overdrawn,
18149
+ ...requestConfig ? {
18150
+ requestConfig
18151
+ } : {}
17850
18152
  });
17851
18153
  }
17852
18154
  }
@@ -17890,10 +18192,10 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17890
18192
  attestationSignature: transferResponse.signature
17891
18193
  };
17892
18194
  }
17893
- async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, steps) {
18195
+ async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, steps, requestConfig) {
17894
18196
  const chainName = destChain.name;
17895
18197
  const recipientAddress = await resolveRecipientAddress(params.to);
17896
- const { allocations, estimatedIntents, forwardingFee: estimateFwdFee } = await resolveValidatedIntents(params, destChain, recipientAddress, useForwarder);
18198
+ const { allocations, estimatedIntents, forwardingFee: estimateFwdFee } = await resolveValidatedIntents(params, destChain, recipientAddress, useForwarder, requestConfig);
17897
18199
  pushStep(steps, dispatcher, 'gateway.spend.step.buildBurnIntents', chainName, {
17898
18200
  name: 'buildBurnIntents',
17899
18201
  state: 'success',
@@ -17930,7 +18232,7 @@ async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, s
17930
18232
  const forwarderParam = useForwarder ? '?enableForwarder=true' : '';
17931
18233
  let transferResponse;
17932
18234
  try {
17933
- transferResponse = await pollApiPost(`${transferApiBaseUrl}/v1/transfer${forwarderParam}`, transferBody, assertGatewayTransferResponse);
18235
+ transferResponse = await pollApiPost(`${transferApiBaseUrl}/v1/transfer${forwarderParam}`, transferBody, assertGatewayTransferResponse, requestConfig);
17934
18236
  } catch (error) {
17935
18237
  throwGatewayApiError(error, allocations);
17936
18238
  }
@@ -18010,10 +18312,11 @@ function updateFeesWithActual(fees, completionStatus) {
18010
18312
  amount: actual
18011
18313
  } : f);
18012
18314
  }
18013
- async function resolveDestinationTxHash(params, destChain, forwarder, transferId, attestation, attestationSignature, fees) {
18315
+ async function resolveDestinationTxHash(opts) {
18316
+ const { params, destChain, forwarder, transferId, attestation, attestationSignature, fees, requestConfig } = opts;
18014
18317
  if (forwarder && transferId) {
18015
18318
  const apiBaseUrl = getGatewayApiBaseUrl(destChain.isTestnet);
18016
- const completionStatus = await pollForwarderCompletion(apiBaseUrl, transferId);
18319
+ const completionStatus = await pollForwarderCompletion(apiBaseUrl, transferId, requestConfig);
18017
18320
  if (!completionStatus.transactionHash) {
18018
18321
  throw new KitError({
18019
18322
  ...OnchainError.TRANSACTION_REVERTED,
@@ -18096,9 +18399,20 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18096
18399
  /**
18097
18400
  * Execute the mint step, recording success/error as a spend step.
18098
18401
  */ async function executeMintStep(opts) {
18099
- const { params, destChain, forwarder, transferId, attestation, attestationSignature, fees, steps, dispatcher } = opts;
18402
+ const { params, destChain, forwarder, transferId, attestation, attestationSignature, fees, steps, dispatcher, requestConfig } = opts;
18100
18403
  try {
18101
- const mintResult = await resolveDestinationTxHash(params, destChain, forwarder, transferId, attestation, attestationSignature, fees);
18404
+ const mintResult = await resolveDestinationTxHash({
18405
+ params,
18406
+ destChain,
18407
+ forwarder,
18408
+ transferId,
18409
+ attestation,
18410
+ attestationSignature,
18411
+ fees,
18412
+ ...requestConfig ? {
18413
+ requestConfig
18414
+ } : {}
18415
+ });
18102
18416
  pushStep(steps, dispatcher, 'gateway.spend.step.mint', destChain.name, {
18103
18417
  name: 'mint',
18104
18418
  state: 'success',
@@ -18153,7 +18467,8 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18153
18467
  assertSpendAddresses(params, destChain);
18154
18468
  const forwarder = isForwarderEnabled(params.to);
18155
18469
  const steps = [];
18156
- const context = params.config?.retry ? await resolveRetryContext(params) : await resolveNormalContext(params, destChain, forwarder, dispatcher, steps);
18470
+ const requestConfig = options?.requestConfig;
18471
+ const context = params.config?.retry ? await resolveRetryContext(params) : await resolveNormalContext(params, destChain, forwarder, dispatcher, steps, requestConfig);
18157
18472
  const fees = appendForwarderFee(context.fees, context.forwardingFee);
18158
18473
  const mintResult = await executeMintStep({
18159
18474
  params,
@@ -18164,7 +18479,10 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18164
18479
  attestationSignature: context.attestationSignature,
18165
18480
  fees,
18166
18481
  steps,
18167
- dispatcher
18482
+ dispatcher,
18483
+ ...requestConfig ? {
18484
+ requestConfig
18485
+ } : {}
18168
18486
  });
18169
18487
  // A throwing `onBroadcast` must never strand the caller after a
18170
18488
  // successful mint — the chain has moved. `safeInvokeCallback` swallows
@@ -18181,14 +18499,14 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18181
18499
  /**
18182
18500
  * Resolve the spend context via the normal (non-retry) path.
18183
18501
  * Validates `from`, then delegates to `runSpendNormalPath`.
18184
- */ async function resolveNormalContext(params, destChain, forwarder, dispatcher, steps) {
18502
+ */ async function resolveNormalContext(params, destChain, forwarder, dispatcher, steps, requestConfig) {
18185
18503
  if (!params.from) {
18186
18504
  throw createValidationFailedError$1('from', params.from, 'Source (from) is required when config.retry is not provided.');
18187
18505
  }
18188
18506
  return runSpendNormalPath({
18189
18507
  ...params,
18190
18508
  from: params.from
18191
- }, destChain, forwarder, dispatcher, steps);
18509
+ }, destChain, forwarder, dispatcher, steps, requestConfig);
18192
18510
  }
18193
18511
  /**
18194
18512
  * Estimate fees for a Gateway spend without executing it.
@@ -18211,13 +18529,13 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18211
18529
  * })
18212
18530
  * fees.forEach((f) => console.log(f.type, f.amount, f.allocations))
18213
18531
  * ```
18214
- */ async function estimateSpend$1(params) {
18532
+ */ async function estimateSpend$1(params, requestConfig) {
18215
18533
  const destChain = resolveChainIdentifier(params.to.chain);
18216
18534
  assertGatewayV1(destChain);
18217
18535
  assertSpendAddresses(params, destChain);
18218
18536
  const forwarder = isForwarderEnabled(params.to);
18219
18537
  const recipientAddress = await resolveRecipientAddress(params.to);
18220
- const { allocations, estimatedIntents, forwardingFee } = await resolveValidatedIntents(params, destChain, recipientAddress, forwarder);
18538
+ const { allocations, estimatedIntents, forwardingFee } = await resolveValidatedIntents(params, destChain, recipientAddress, forwarder, requestConfig);
18221
18539
  const fees = computeEstimateFees(estimatedIntents, allocations, params.config?.customFee);
18222
18540
  if (forwardingFee) {
18223
18541
  fees.push({
@@ -18341,6 +18659,9 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18341
18659
  * the delegate is `'ready'` (finalized); otherwise it is `'pending'`.
18342
18660
  *
18343
18661
  * @param params - The adapter context (`from`), delegate address, and token.
18662
+ * @param requestConfig - Optional polling config overrides, including custom
18663
+ * `headers` forwarded with the `/v1/info` request used on the EVM finality
18664
+ * check.
18344
18665
  * @returns Promise resolving to `'none'`, `'pending'`, or `'ready'`.
18345
18666
  * @throws KitError if the chain is unsupported or `/v1/info` fails.
18346
18667
  *
@@ -18360,7 +18681,7 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18360
18681
  * const status = await getDelegateStatus(params)
18361
18682
  * if (status === 'ready') { // safe to spend }
18362
18683
  * ```
18363
- */ async function getDelegateStatus$1(params) {
18684
+ */ async function getDelegateStatus$1(params, requestConfig) {
18364
18685
  const { from, delegateAddress } = params;
18365
18686
  const { adapter } = from;
18366
18687
  const chain = resolveChainIdentifier(from.chain);
@@ -18376,8 +18697,7 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18376
18697
  chain
18377
18698
  };
18378
18699
  // Step 1: Quick check at latest block (no HTTP call)
18379
- const latestRequest = await adapter.prepareAction('gateway.v1.isDelegate', baseActionParams, operationContext);
18380
- const latestResult = await latestRequest.execute();
18700
+ const latestResult = await executeAdapterReadAction(adapter, 'gateway.v1.isDelegate', baseActionParams, operationContext);
18381
18701
  if (String(latestResult).toLowerCase() !== 'true') {
18382
18702
  return 'none';
18383
18703
  }
@@ -18386,13 +18706,12 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18386
18706
  // Solana uses confirmed vs finalized commitment as a proxy for
18387
18707
  // Gateway finality. This is conservative — can only over-report
18388
18708
  // 'pending', never falsely report 'ready'.
18389
- const finalizedRequest = await adapter.prepareAction('gateway.v1.isDelegate', {
18390
- ...baseActionParams,
18391
- commitment: 'finalized'
18392
- }, operationContext);
18393
18709
  let finalizedResult;
18394
18710
  try {
18395
- finalizedResult = await finalizedRequest.execute();
18711
+ finalizedResult = await executeAdapterReadAction(adapter, 'gateway.v1.isDelegate', {
18712
+ ...baseActionParams,
18713
+ commitment: 'finalized'
18714
+ }, operationContext);
18396
18715
  } catch (error) {
18397
18716
  if (isBlockRangeError(error)) {
18398
18717
  return 'pending';
@@ -18402,11 +18721,7 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18402
18721
  return String(finalizedResult).toLowerCase() === 'true' ? 'ready' : 'pending';
18403
18722
  }
18404
18723
  // EVM: use processedHeight from /v1/info
18405
- const processedHeight = await getProcessedHeight(chain.isTestnet, chain.gateway.domain);
18406
- const finalizedRequest = await adapter.prepareAction('gateway.v1.isDelegate', {
18407
- ...baseActionParams,
18408
- blockNumber: processedHeight
18409
- }, operationContext);
18724
+ const processedHeight = await getProcessedHeight(chain.isTestnet, chain.gateway.domain, requestConfig);
18410
18725
  // If the RPC node lags Gateway's indexer view, the historical read at
18411
18726
  // processedHeight may throw a block-range error. This is safe to treat
18412
18727
  // as 'pending' because processedHeight comes from Gateway's /v1/info
@@ -18415,7 +18730,10 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18415
18730
  // Re-throw structural errors to avoid masking real bugs.
18416
18731
  let finalizedResult;
18417
18732
  try {
18418
- finalizedResult = await finalizedRequest.execute();
18733
+ finalizedResult = await executeAdapterReadAction(adapter, 'gateway.v1.isDelegate', {
18734
+ ...baseActionParams,
18735
+ blockNumber: processedHeight
18736
+ }, operationContext);
18419
18737
  } catch (error) {
18420
18738
  if (isBlockRangeError(error)) {
18421
18739
  return 'pending';
@@ -18476,8 +18794,8 @@ function parseAmountSafe(amount) {
18476
18794
  chain
18477
18795
  };
18478
18796
  const [withdrawingRaw, withdrawalBlockRaw] = await Promise.all([
18479
- adapter.prepareAction('gateway.v1.withdrawingBalance', readParams, operationContext).then(async (req)=>req.execute()),
18480
- adapter.prepareAction('gateway.v1.withdrawalBlock', readParams, operationContext).then(async (req)=>req.execute())
18797
+ executeAdapterReadAction(adapter, 'gateway.v1.withdrawingBalance', readParams, operationContext),
18798
+ executeAdapterReadAction(adapter, 'gateway.v1.withdrawalBlock', readParams, operationContext)
18481
18799
  ]);
18482
18800
  const withdrawingValue = safeBigInt(String(withdrawingRaw), 'withdrawingBalance');
18483
18801
  const withdrawalBlockValue = safeBigInt(String(withdrawalBlockRaw), 'withdrawalBlock');
@@ -18517,12 +18835,11 @@ function parseAmountSafe(amount) {
18517
18835
  const tokenAddress = getTokenAddress(chain, params.token);
18518
18836
  // Read the pending balance before withdrawing — the contract resets it to 0
18519
18837
  // after withdraw() executes, so this is the only way to capture the amount.
18520
- const withdrawingBalanceReq = await adapter.prepareAction('gateway.v1.withdrawingBalance', {
18838
+ const withdrawingRaw = await executeAdapterReadAction(adapter, 'gateway.v1.withdrawingBalance', {
18521
18839
  token: tokenAddress,
18522
18840
  depositor: signerAddress,
18523
18841
  chain
18524
18842
  }, operationContext);
18525
- const withdrawingRaw = await withdrawingBalanceReq.execute();
18526
18843
  const withdrawingValue = safeBigInt(String(withdrawingRaw), 'withdrawingBalance');
18527
18844
  if (withdrawingValue === 0n) {
18528
18845
  throw new KitError({
@@ -18622,6 +18939,35 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18622
18939
  dispatchEvent(dispatcher, opName, 'failed', chain, extractErrorInfo(error));
18623
18940
  }
18624
18941
 
18942
+ // ---------------------------------------------------------------------------
18943
+ // Config validation
18944
+ // ---------------------------------------------------------------------------
18945
+ function isPlainObject(value) {
18946
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
18947
+ return false;
18948
+ }
18949
+ const prototype = Object.getPrototypeOf(value);
18950
+ return prototype === Object.prototype || prototype === null;
18951
+ }
18952
+ function assertHeadersConfig(headers) {
18953
+ if (headers === undefined) {
18954
+ return;
18955
+ }
18956
+ if (!isPlainObject(headers)) {
18957
+ throw createValidationFailedError$1('config.headers', headers, 'config.headers must be a plain object with string header values when provided');
18958
+ }
18959
+ for (const [name, value] of Object.entries(headers)){
18960
+ if (typeof value !== 'string') {
18961
+ throw createValidationFailedError$1(`config.headers.${name}`, value, 'header values must be strings');
18962
+ }
18963
+ }
18964
+ }
18965
+ function assertGatewayV1Config(config) {
18966
+ if (!isPlainObject(config)) {
18967
+ throw createValidationFailedError$1('config', config, 'config must be a plain object when provided');
18968
+ }
18969
+ assertHeadersConfig(config['headers']);
18970
+ }
18625
18971
  // ---------------------------------------------------------------------------
18626
18972
  // Factory
18627
18973
  // ---------------------------------------------------------------------------
@@ -18631,7 +18977,12 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18631
18977
  * Returns a plain object that implements {@link IGatewayProvider} by
18632
18978
  * delegating to the standalone functions in `operations/`.
18633
18979
  *
18980
+ * @param config - Optional provider configuration. Supply `headers` to
18981
+ * forward custom HTTP headers with every Gateway API request. See
18982
+ * {@link GatewayV1Config}.
18634
18983
  * @returns An {@link IGatewayProvider} instance.
18984
+ * @throws Throws when `config` or `config.headers` is not a plain object, or a
18985
+ * header value is not a string.
18635
18986
  *
18636
18987
  * @example
18637
18988
  * ```typescript
@@ -18640,7 +18991,23 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18640
18991
  * const provider = createGatewayV1Provider()
18641
18992
  * const chains = provider.getSupportedChains()
18642
18993
  * ```
18643
- */ function createGatewayV1Provider() {
18994
+ *
18995
+ * @example
18996
+ * ```typescript
18997
+ * // Forward a custom header on every Gateway API request.
18998
+ * const provider = createGatewayV1Provider({
18999
+ * headers: { 'X-Access-Key': process.env.GATEWAY_ACCESS_KEY! },
19000
+ * })
19001
+ * ```
19002
+ */ function createGatewayV1Provider(config = {}) {
19003
+ assertGatewayV1Config(config);
19004
+ // Captured once and threaded to every Gateway API call the operations make,
19005
+ // so a configured header reaches balances, estimate, transfer, forwarder
19006
+ // status, and /v1/info alike. Left undefined when no headers are configured
19007
+ // so the operations keep their existing defaults untouched.
19008
+ const requestConfig = config.headers ? {
19009
+ headers: config.headers
19010
+ } : undefined;
18644
19011
  /**
18645
19012
  * Execute an operation with started/succeeded/failed event dispatch.
18646
19013
  */ async function withEvents(opName, chain, startedData, params, fn) {
@@ -18671,21 +19038,25 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18671
19038
  }, params, depositFor$1),
18672
19039
  spend: async (params, options)=>{
18673
19040
  const destChainName = extractChainInfo(params.to.chain).name;
19041
+ const mergedOptions = requestConfig ? {
19042
+ ...options,
19043
+ requestConfig
19044
+ } : options;
18674
19045
  return withEvents('spend', destChainName, {
18675
19046
  destinationChain: destChainName,
18676
19047
  token: params.token ?? 'USDC'
18677
- }, params, async (p)=>spend$1(p, provider.actionDispatcher, options));
19048
+ }, params, async (p)=>spend$1(p, provider.actionDispatcher, mergedOptions));
18678
19049
  },
18679
19050
  estimateSpend: async (params)=>{
18680
19051
  const destChainName = extractChainInfo(params.to.chain).name;
18681
19052
  return withEvents('estimateSpend', destChainName, {
18682
19053
  destinationChain: destChainName,
18683
19054
  token: params.token ?? 'USDC'
18684
- }, params, estimateSpend$1);
19055
+ }, params, async (p)=>estimateSpend$1(p, requestConfig));
18685
19056
  },
18686
19057
  getBalances: async (params)=>withEvents('getBalances', 'aggregate', {
18687
19058
  token: params.token ?? 'USDC'
18688
- }, params, getBalances$1),
19059
+ }, params, async (p)=>getBalances$1(p, requestConfig)),
18689
19060
  addDelegate: async (params)=>withEvents('addDelegate', extractChainInfo(params.from.chain).name, {
18690
19061
  delegateAddress: params.delegateAddress
18691
19062
  }, params, addDelegate$1),
@@ -18703,7 +19074,9 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18703
19074
  // in withEvents. getSupportedChains is synchronous. getDelegateStatus is a
18704
19075
  // lightweight read that consumers treat as a utility check, unlike
18705
19076
  // getBalances which involves API polling and benefits from lifecycle events.
18706
- getDelegateStatus: getDelegateStatus$1,
19077
+ // getDelegateStatus is wrapped to forward the provider's request config to
19078
+ // its /v1/info call; getSupportedChains makes no API call.
19079
+ getDelegateStatus: async (params)=>getDelegateStatus$1(params, requestConfig),
18707
19080
  getSupportedChains: getSupportedChains$1
18708
19081
  };
18709
19082
  return provider;
@@ -18713,6 +19086,7 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18713
19086
  * The default providers that will be used in addition to the providers
18714
19087
  * provided to the createUnifiedBalanceKitContext factory function.
18715
19088
  *
19089
+ * @param config - Optional configuration forwarded to the default provider.
18716
19090
  * @returns A readonly tuple with one element: the default Gateway v1 provider
18717
19091
  * instance created via {@link createGatewayV1Provider}.
18718
19092
  * @internal
@@ -18724,8 +19098,10 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18724
19098
  * const { providers } = createUnifiedBalanceKitContext()
18725
19099
  * // providers[0] is the default Gateway v1 instance from getDefaultProviders()
18726
19100
  * ```
18727
- */ const getDefaultProviders = ()=>[
18728
- createGatewayV1Provider()
19101
+ */ const getDefaultProviders = (config = {})=>[
19102
+ createGatewayV1Provider(config.headers ? {
19103
+ headers: config.headers
19104
+ } : {})
18729
19105
  ];
18730
19106
  function createUnifiedBalanceKitContext(config = {}) {
18731
19107
  // Runtime guard: `excludeDefaultProviders: true` with no `providers` is
@@ -18739,7 +19115,10 @@ function createUnifiedBalanceKitContext(config = {}) {
18739
19115
  // Initialize default providers — either the canonical singleton tuple or
18740
19116
  // an empty list when the caller has opted out. Typed loosely here; each
18741
19117
  // public overload narrows the return type for callers.
18742
- const defaultProviders = config.excludeDefaultProviders === true ? [] : getDefaultProviders();
19118
+ const defaultProvidersConfig = config.headers ? {
19119
+ headers: config.headers
19120
+ } : {};
19121
+ const defaultProviders = config.excludeDefaultProviders === true ? [] : getDefaultProviders(defaultProvidersConfig);
18743
19122
  const providers = [
18744
19123
  ...defaultProviders,
18745
19124
  ...config.providers ?? []
@@ -19430,29 +19809,65 @@ function sumAllocationsFromSources(sources) {
19430
19809
  }
19431
19810
  });
19432
19811
 
19812
+ function normalizeAddressIdentity(value) {
19813
+ if (typeof value !== 'string') return undefined;
19814
+ try {
19815
+ return convertAddress(value, 'bytes32').toLowerCase();
19816
+ } catch {
19817
+ // Address validation below owns the structured error for invalid input.
19818
+ return value;
19819
+ }
19820
+ }
19433
19821
  /**
19434
- * Reject `from` arrays containing the same adapter reference more than once.
19435
- * Must run on the raw input (before Zod parsing) because `z.object()` creates
19436
- * new wrapper objects and identity (`===`) is lost.
19822
+ * Reject `from` arrays that describe the same spend source more than once.
19823
+ *
19824
+ * One adapter instance may legitimately be reused across distinct Gateway
19825
+ * source accounts. When `sourceAccount` is omitted, the signer address
19826
+ * identifies the source. Must run on the raw input (before Zod parsing)
19827
+ * because `z.object()` creates new wrapper objects and adapter identity
19828
+ * (`===`) is lost.
19437
19829
  *
19438
19830
  * @internal
19439
- */ function assertNoDuplicateAdapters(params) {
19831
+ */ function assertNoDuplicateSpendSources(params) {
19440
19832
  if (params == null || typeof params !== 'object') return;
19441
19833
  const from = params['from'];
19442
19834
  if (!Array.isArray(from) || from.length < 2) return;
19443
- const seen = new Set();
19835
+ const seen = new Map();
19444
19836
  for (const source of from){
19445
19837
  if (source == null || typeof source !== 'object') continue;
19446
- const adapter = source['adapter'];
19838
+ const record = source;
19839
+ const adapter = record['adapter'];
19447
19840
  if (adapter == null) continue;
19448
- if (seen.has(adapter)) {
19841
+ const sourceAccount = normalizeAddressIdentity(record['sourceAccount']) ?? normalizeAddressIdentity(record['address']);
19842
+ let sourceAccounts = seen.get(adapter);
19843
+ if (sourceAccounts == null) {
19844
+ sourceAccounts = new Set();
19845
+ seen.set(adapter, sourceAccounts);
19846
+ }
19847
+ if (sourceAccounts.has(sourceAccount)) {
19449
19848
  throw new KitError({
19450
19849
  ...InputError.VALIDATION_FAILED,
19451
19850
  recoverability: 'FATAL',
19452
- message: 'Duplicate adapter instance detected in from array. ' + 'Each source must use a distinct adapter object.'
19851
+ message: 'Duplicate spend source detected in from array. The same adapter ' + 'and Gateway source account are reused more than once.'
19453
19852
  });
19454
19853
  }
19455
- seen.add(adapter);
19854
+ sourceAccounts.add(sourceAccount);
19855
+ }
19856
+ }
19857
+ function assertSourceAddressContexts(from) {
19858
+ const sources = Array.isArray(from) ? from : [
19859
+ from
19860
+ ];
19861
+ for (const raw of sources){
19862
+ if (raw == null || typeof raw !== 'object') continue;
19863
+ const source = raw;
19864
+ const addressContext = source.adapter?.capabilities?.addressContext;
19865
+ if (addressContext === 'developer-controlled' && (typeof source.address !== 'string' || source.address === '')) {
19866
+ throw createValidationFailedError$1('address', source.address, 'Address is required for developer-controlled adapters.');
19867
+ }
19868
+ if (addressContext === 'user-controlled' && source.address !== undefined) {
19869
+ throw createValidationFailedError$1('address', source.address, 'Address should not be provided for user-controlled adapters. ' + 'The address is automatically resolved from the connected wallet.');
19870
+ }
19456
19871
  }
19457
19872
  }
19458
19873
  /**
@@ -19466,14 +19881,17 @@ function sumAllocationsFromSources(sources) {
19466
19881
  * @throws \{KitError\} When validation fails; error code is
19467
19882
  * {@link InputError.VALIDATION_FAILED}.
19468
19883
  */ function assertSpendParams(params) {
19469
- assertNoDuplicateAdapters(params);
19884
+ assertNoDuplicateSpendSources(params);
19885
+ if (params != null && typeof params === 'object' && 'from' in params) {
19886
+ assertSourceAddressContexts(params['from']);
19887
+ }
19470
19888
  const result = spendParamsSchema.safeParse(params);
19471
19889
  if (!result.success) {
19472
19890
  throw convertZodErrorToStructured(result.error, params);
19473
19891
  }
19474
19892
  const data = result.data;
19475
19893
  // Validate recipientAddress against the destination chain
19476
- if (data.to.recipientAddress) {
19894
+ if (data.to.recipientAddress !== undefined && data.to.recipientAddress !== '') {
19477
19895
  const toChain = data.to.chain;
19478
19896
  if (!isValidAddressForChain(data.to.recipientAddress, toChain)) {
19479
19897
  const chainInfo = extractChainInfo(toChain);
@@ -19481,7 +19899,7 @@ function sumAllocationsFromSources(sources) {
19481
19899
  }
19482
19900
  }
19483
19901
  // Validate sourceAccount against each source's allocation chain
19484
- if (data.from) {
19902
+ if (data.from !== undefined) {
19485
19903
  assertSourceAccountAddresses(data.from);
19486
19904
  }
19487
19905
  }
@@ -19496,11 +19914,15 @@ function assertSourceAccountAddresses(from) {
19496
19914
  from
19497
19915
  ];
19498
19916
  for (const raw of sources){
19499
- if (!raw || typeof raw !== 'object' || !('sourceAccount' in raw)) continue;
19917
+ if (raw === null || typeof raw !== 'object' || !('sourceAccount' in raw)) {
19918
+ continue;
19919
+ }
19500
19920
  const source = raw;
19501
- if (!source.sourceAccount) continue;
19921
+ if (source.sourceAccount === undefined || source.sourceAccount === '') {
19922
+ continue;
19923
+ }
19502
19924
  const sourceChain = getSourceChainFromAllocations(source.allocations);
19503
- if (!sourceChain) continue;
19925
+ if (sourceChain === undefined) continue;
19504
19926
  if (!isValidAddressForChain(source.sourceAccount, sourceChain)) {
19505
19927
  const chainInfo = extractChainInfo(sourceChain);
19506
19928
  throw createInvalidAddressError(source.sourceAccount, String(chainInfo.name), chainInfo.expectedAddressFormat);