@circle-fin/app-kit 1.12.1 → 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.
@@ -2297,6 +2297,8 @@ class KitError extends Error {
2297
2297
  Blockchain["Optimism_Sepolia"] = "Optimism_Sepolia";
2298
2298
  Blockchain["Pharos"] = "Pharos";
2299
2299
  Blockchain["Pharos_Testnet"] = "Pharos_Testnet";
2300
+ Blockchain["Plasma"] = "Plasma";
2301
+ Blockchain["Plasma_Testnet"] = "Plasma_Testnet";
2300
2302
  Blockchain["Polkadot_Asset_Hub"] = "Polkadot_Asset_Hub";
2301
2303
  Blockchain["Polkadot_Westmint"] = "Polkadot_Westmint";
2302
2304
  Blockchain["Plume"] = "Plume";
@@ -2366,6 +2368,7 @@ var BridgeChain;
2366
2368
  BridgeChain["Morph"] = "Morph";
2367
2369
  BridgeChain["Optimism"] = "Optimism";
2368
2370
  BridgeChain["Pharos"] = "Pharos";
2371
+ BridgeChain["Plasma"] = "Plasma";
2369
2372
  BridgeChain["Plume"] = "Plume";
2370
2373
  BridgeChain["Polygon"] = "Polygon";
2371
2374
  BridgeChain["Sei"] = "Sei";
@@ -2392,6 +2395,7 @@ var BridgeChain;
2392
2395
  BridgeChain["Morph_Testnet"] = "Morph_Testnet";
2393
2396
  BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
2394
2397
  BridgeChain["Pharos_Testnet"] = "Pharos_Testnet";
2398
+ BridgeChain["Plasma_Testnet"] = "Plasma_Testnet";
2395
2399
  BridgeChain["Plume_Testnet"] = "Plume_Testnet";
2396
2400
  BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
2397
2401
  BridgeChain["Sei_Testnet"] = "Sei_Testnet";
@@ -2838,6 +2842,8 @@ var EarnChain;
2838
2842
  * This program handles minting operations for Gateway transactions
2839
2843
  * on Solana devnet.
2840
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';
2841
2847
  /**
2842
2848
  * Circle's fee recipient address for EVM chains.
2843
2849
  *
@@ -2885,6 +2891,7 @@ var EarnChain;
2885
2891
  v2: {
2886
2892
  type: 'split',
2887
2893
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
2894
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
2888
2895
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
2889
2896
  confirmations: 1,
2890
2897
  fastConfirmations: 1
@@ -2952,6 +2959,7 @@ var EarnChain;
2952
2959
  v2: {
2953
2960
  type: 'split',
2954
2961
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
2962
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
2955
2963
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
2956
2964
  confirmations: 65,
2957
2965
  fastConfirmations: 1
@@ -3016,6 +3024,7 @@ var EarnChain;
3016
3024
  v2: {
3017
3025
  type: 'split',
3018
3026
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
3027
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3019
3028
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
3020
3029
  confirmations: 65,
3021
3030
  fastConfirmations: 1
@@ -3080,6 +3089,7 @@ var EarnChain;
3080
3089
  v2: {
3081
3090
  type: 'split',
3082
3091
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3092
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3083
3093
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3084
3094
  confirmations: 1,
3085
3095
  fastConfirmations: 1
@@ -3141,6 +3151,7 @@ var EarnChain;
3141
3151
  v2: {
3142
3152
  type: 'split',
3143
3153
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3154
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3144
3155
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3145
3156
  confirmations: 1,
3146
3157
  fastConfirmations: 1
@@ -3208,6 +3219,7 @@ var EarnChain;
3208
3219
  v2: {
3209
3220
  type: 'split',
3210
3221
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3222
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3211
3223
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3212
3224
  confirmations: 65,
3213
3225
  fastConfirmations: 1
@@ -3272,6 +3284,7 @@ var EarnChain;
3272
3284
  v2: {
3273
3285
  type: 'split',
3274
3286
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3287
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3275
3288
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3276
3289
  confirmations: 65,
3277
3290
  fastConfirmations: 1
@@ -3382,6 +3395,7 @@ var EarnChain;
3382
3395
  v2: {
3383
3396
  type: 'split',
3384
3397
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3398
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3385
3399
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3386
3400
  confirmations: 65,
3387
3401
  fastConfirmations: 1
@@ -3426,6 +3440,7 @@ var EarnChain;
3426
3440
  v2: {
3427
3441
  type: 'split',
3428
3442
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3443
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3429
3444
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3430
3445
  confirmations: 65,
3431
3446
  fastConfirmations: 1
@@ -3657,6 +3672,7 @@ var EarnChain;
3657
3672
  v2: {
3658
3673
  type: 'split',
3659
3674
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3675
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3660
3676
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3661
3677
  confirmations: 65,
3662
3678
  fastConfirmations: 2
@@ -3721,6 +3737,7 @@ var EarnChain;
3721
3737
  v2: {
3722
3738
  type: 'split',
3723
3739
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3740
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3724
3741
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3725
3742
  confirmations: 65,
3726
3743
  fastConfirmations: 2
@@ -3831,6 +3848,7 @@ var EarnChain;
3831
3848
  v2: {
3832
3849
  type: 'split',
3833
3850
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3851
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3834
3852
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3835
3853
  confirmations: 1,
3836
3854
  fastConfirmations: 1
@@ -3890,6 +3908,7 @@ var EarnChain;
3890
3908
  v2: {
3891
3909
  type: 'split',
3892
3910
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
3911
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3893
3912
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
3894
3913
  confirmations: 1,
3895
3914
  fastConfirmations: 1
@@ -4044,6 +4063,7 @@ var EarnChain;
4044
4063
  v2: {
4045
4064
  type: 'split',
4046
4065
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4066
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4047
4067
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4048
4068
  confirmations: 65,
4049
4069
  fastConfirmations: 1
@@ -4091,6 +4111,7 @@ var EarnChain;
4091
4111
  v2: {
4092
4112
  type: 'split',
4093
4113
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4114
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4094
4115
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4095
4116
  confirmations: 65,
4096
4117
  fastConfirmations: 1
@@ -4135,6 +4156,7 @@ var EarnChain;
4135
4156
  v2: {
4136
4157
  type: 'split',
4137
4158
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4159
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4138
4160
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4139
4161
  confirmations: 1,
4140
4162
  fastConfirmations: 1
@@ -4180,6 +4202,7 @@ var EarnChain;
4180
4202
  v2: {
4181
4203
  type: 'split',
4182
4204
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
4205
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4183
4206
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
4184
4207
  confirmations: 1,
4185
4208
  fastConfirmations: 1
@@ -4226,6 +4249,7 @@ var EarnChain;
4226
4249
  v2: {
4227
4250
  type: 'split',
4228
4251
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4252
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4229
4253
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4230
4254
  confirmations: 1,
4231
4255
  fastConfirmations: 1
@@ -4539,6 +4563,7 @@ var EarnChain;
4539
4563
  v2: {
4540
4564
  type: 'split',
4541
4565
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4566
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4542
4567
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4543
4568
  confirmations: 65,
4544
4569
  fastConfirmations: 1
@@ -4603,6 +4628,7 @@ var EarnChain;
4603
4628
  v2: {
4604
4629
  type: 'split',
4605
4630
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
4631
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4606
4632
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
4607
4633
  confirmations: 65,
4608
4634
  fastConfirmations: 1
@@ -4723,6 +4749,98 @@ var EarnChain;
4723
4749
  }
4724
4750
  });
4725
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
+
4726
4844
  /**
4727
4845
  * Plume Mainnet chain definition
4728
4846
  * @remarks
@@ -4754,6 +4872,7 @@ var EarnChain;
4754
4872
  v2: {
4755
4873
  type: 'split',
4756
4874
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4875
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4757
4876
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4758
4877
  confirmations: 65,
4759
4878
  fastConfirmations: 1
@@ -4800,6 +4919,7 @@ var EarnChain;
4800
4919
  v2: {
4801
4920
  type: 'split',
4802
4921
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4922
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4803
4923
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4804
4924
  confirmations: 65,
4805
4925
  fastConfirmations: 1
@@ -4901,6 +5021,7 @@ var EarnChain;
4901
5021
  v2: {
4902
5022
  type: 'split',
4903
5023
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5024
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4904
5025
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4905
5026
  confirmations: 33,
4906
5027
  fastConfirmations: 13
@@ -4966,6 +5087,7 @@ var EarnChain;
4966
5087
  v2: {
4967
5088
  type: 'split',
4968
5089
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5090
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4969
5091
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4970
5092
  confirmations: 33,
4971
5093
  fastConfirmations: 13
@@ -5025,6 +5147,7 @@ var EarnChain;
5025
5147
  v2: {
5026
5148
  type: 'split',
5027
5149
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5150
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5028
5151
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5029
5152
  confirmations: 1,
5030
5153
  fastConfirmations: 1
@@ -5084,6 +5207,7 @@ var EarnChain;
5084
5207
  v2: {
5085
5208
  type: 'split',
5086
5209
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5210
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5087
5211
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5088
5212
  confirmations: 1,
5089
5213
  fastConfirmations: 1
@@ -5141,6 +5265,7 @@ var EarnChain;
5141
5265
  v2: {
5142
5266
  type: 'split',
5143
5267
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5268
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5144
5269
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5145
5270
  confirmations: 1,
5146
5271
  fastConfirmations: 1
@@ -5199,6 +5324,7 @@ var EarnChain;
5199
5324
  v2: {
5200
5325
  type: 'split',
5201
5326
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5327
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5202
5328
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5203
5329
  confirmations: 1,
5204
5330
  fastConfirmations: 1
@@ -5514,6 +5640,7 @@ var EarnChain;
5514
5640
  v2: {
5515
5641
  type: 'split',
5516
5642
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5643
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5517
5644
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5518
5645
  confirmations: 65,
5519
5646
  fastConfirmations: 1
@@ -5578,6 +5705,7 @@ var EarnChain;
5578
5705
  v2: {
5579
5706
  type: 'split',
5580
5707
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5708
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5581
5709
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5582
5710
  confirmations: 65,
5583
5711
  fastConfirmations: 1
@@ -5635,6 +5763,7 @@ var EarnChain;
5635
5763
  v2: {
5636
5764
  type: 'split',
5637
5765
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cF5d',
5766
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5638
5767
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5639
5768
  confirmations: 65,
5640
5769
  fastConfirmations: 1
@@ -5694,6 +5823,7 @@ var EarnChain;
5694
5823
  v2: {
5695
5824
  type: 'split',
5696
5825
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
5826
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5697
5827
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
5698
5828
  confirmations: 65,
5699
5829
  fastConfirmations: 1
@@ -5754,6 +5884,7 @@ var EarnChain;
5754
5884
  v2: {
5755
5885
  type: 'split',
5756
5886
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5887
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5757
5888
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5758
5889
  confirmations: 3,
5759
5890
  fastConfirmations: 3
@@ -5799,6 +5930,7 @@ var EarnChain;
5799
5930
  v2: {
5800
5931
  type: 'split',
5801
5932
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5933
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5802
5934
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5803
5935
  confirmations: 3,
5804
5936
  fastConfirmations: 1
@@ -6009,6 +6141,8 @@ var Chains = /*#__PURE__*/Object.freeze({
6009
6141
  OptimismSepolia: OptimismSepolia,
6010
6142
  Pharos: Pharos,
6011
6143
  PharosTestnet: PharosTestnet,
6144
+ Plasma: Plasma,
6145
+ PlasmaTestnet: PlasmaTestnet,
6012
6146
  Plume: Plume,
6013
6147
  PlumeTestnet: PlumeTestnet,
6014
6148
  PolkadotAssetHub: PolkadotAssetHub,
@@ -7974,6 +8108,7 @@ function parseOrThrow(value, schema, context) {
7974
8108
  [Blockchain.Noble]: 'uusdc',
7975
8109
  [Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
7976
8110
  [Blockchain.Pharos]: '0xC879C018dB60520F4355C26eD1a6D572cdAC1815',
8111
+ [Blockchain.Plasma]: '0x2d661C89D812261039AF9764eceaAee884f5F67F',
7977
8112
  [Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
7978
8113
  [Blockchain.Polkadot_Asset_Hub]: '1337',
7979
8114
  [Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
@@ -8010,6 +8145,7 @@ function parseOrThrow(value, schema, context) {
8010
8145
  [Blockchain.Noble_Testnet]: 'uusdc',
8011
8146
  [Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
8012
8147
  [Blockchain.Pharos_Testnet]: '0xcfC8330f4BCAB529c625D12781b1C19466A9Fc8B',
8148
+ [Blockchain.Plasma_Testnet]: '0xE67Fb267022cBA8064Dd388CC2FED724F3120D9D',
8013
8149
  [Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
8014
8150
  [Blockchain.Polkadot_Westmint]: '31337',
8015
8151
  [Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
@@ -8072,6 +8208,7 @@ function parseOrThrow(value, schema, context) {
8072
8208
  [Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
8073
8209
  [Blockchain.Cronos]: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
8074
8210
  [Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
8211
+ [Blockchain.Plasma]: '0x3EE196E78d4d4248b849B8E1C7F44C5457FAFD2C',
8075
8212
  [Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
8076
8213
  [Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
8077
8214
  // =========================================================================
@@ -8080,7 +8217,8 @@ function parseOrThrow(value, schema, context) {
8080
8217
  [Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
8081
8218
  [Blockchain.Base_Sepolia]: '0x808456652fdb597867f38412077A9182bf77359F',
8082
8219
  [Blockchain.Cronos_Testnet]: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
8083
- [Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4'
8220
+ [Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4',
8221
+ [Blockchain.Plasma_Testnet]: '0x98AfA0F93Dd993B736399f9074eDcEBD1985A330'
8084
8222
  }
8085
8223
  };
8086
8224
 
@@ -8887,7 +9025,7 @@ function parseOrThrow(value, schema, context) {
8887
9025
  }
8888
9026
 
8889
9027
  var name = "@circle-fin/unified-balance-kit";
8890
- var version = "1.4.1";
9028
+ var version = "1.5.0";
8891
9029
  var pkg = {
8892
9030
  name: name,
8893
9031
  version: version};
@@ -12463,6 +12601,23 @@ async function signUnits(group, signingUnits) {
12463
12601
  }
12464
12602
  return signedSets;
12465
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
+ }
12466
12621
  /**
12467
12622
  * Sign an EVM adapter group.
12468
12623
  *
@@ -12505,22 +12660,42 @@ async function signUnits(group, signingUnits) {
12505
12660
  // Validate the collection before doing bytecode reads or asking a wallet
12506
12661
  // to sign. evmSigningData owns the canonical BurnIntent validation.
12507
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);
12508
12666
  const chainsByDomain = collectChainsByDomain(group);
12509
12667
  const signerTypeByDomain = await classifySignerTypes(group, chainsByDomain);
12510
12668
  const signingUnits = createSigningUnits(group, signerTypeByDomain);
12511
12669
  return await signUnits(group, signingUnits);
12512
12670
  }
12513
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
+ }
12514
12689
  /**
12515
12690
  * Add an EVM intent into the batched EVM group map.
12516
12691
  *
12517
- * On EVM, all intents for the same adapter are batched into a single
12518
- * 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
12519
12694
  * while signing ERC-1271 intents separately on their source chains.
12520
12695
  *
12521
12696
  * @param intent - The burn intent to group.
12522
12697
  * @param alloc - The allocation that resolved to this intent.
12523
- * @param evmGroups - Mutable map of adapter → EVM group.
12698
+ * @param evmGroups - Mutable map of `(adapter, sourceSigner)` key → EVM group.
12524
12699
  *
12525
12700
  * @example
12526
12701
  * ```typescript
@@ -12530,12 +12705,13 @@ async function signUnits(group, signingUnits) {
12530
12705
  * groupEvmIntents(intent, alloc, groups)
12531
12706
  * ```
12532
12707
  */ function groupEvmIntents(intent, alloc, evmGroups) {
12533
- const existing = evmGroups.get(alloc.adapter);
12708
+ const key = groupKey(alloc);
12709
+ const existing = evmGroups.get(key);
12534
12710
  if (existing) {
12535
12711
  existing.intents.push(intent);
12536
12712
  existing.chainsByDomain.set(alloc.chain.gateway.domain, alloc.chain);
12537
12713
  } else {
12538
- evmGroups.set(alloc.adapter, {
12714
+ evmGroups.set(key, {
12539
12715
  adapter: alloc.adapter,
12540
12716
  chain: alloc.chain,
12541
12717
  intents: [
@@ -13564,6 +13740,8 @@ const gatewayInfoSchema = z.object({
13564
13740
  * Fetch Gateway info from the `/v1/info` endpoint.
13565
13741
  *
13566
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.
13567
13745
  * @returns Parsed Gateway info including per-domain processed heights.
13568
13746
  * @throws KitError on HTTP failure or invalid response.
13569
13747
  *
@@ -13572,11 +13750,11 @@ const gatewayInfoSchema = z.object({
13572
13750
  * const info = await fetchGatewayInfo(true)
13573
13751
  * console.log(info.domains.map(d => `${d.chain}: ${d.processedHeight}`))
13574
13752
  * ```
13575
- */ async function fetchGatewayInfo(isTestnet) {
13753
+ */ async function fetchGatewayInfo(isTestnet, config) {
13576
13754
  const apiBaseUrl = getGatewayApiBaseUrl(isTestnet);
13577
13755
  const url = `${apiBaseUrl}/v1/info`;
13578
13756
  try {
13579
- return await pollApiGet(url, assertGatewayInfoResponse);
13757
+ return await pollApiGet(url, assertGatewayInfoResponse, config);
13580
13758
  } catch (error) {
13581
13759
  if (error instanceof KitError) {
13582
13760
  throw error;
@@ -13602,6 +13780,8 @@ const gatewayInfoSchema = z.object({
13602
13780
  *
13603
13781
  * @param isTestnet - Whether to query the testnet or mainnet API.
13604
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.
13605
13785
  * @returns The processed height as a bigint.
13606
13786
  * @throws KitError when the domain is not found in the response.
13607
13787
  *
@@ -13610,10 +13790,10 @@ const gatewayInfoSchema = z.object({
13610
13790
  * const height = await getProcessedHeight(true, 6) // Base Sepolia
13611
13791
  * console.log(`Gateway processed up to block ${height}`)
13612
13792
  * ```
13613
- */ async function getProcessedHeight(isTestnet, domain) {
13793
+ */ async function getProcessedHeight(isTestnet, domain, config) {
13614
13794
  // No caching in v1 — /v1/info is cheap and delegate status checks
13615
13795
  // are infrequent. Revisit if rate-limit or latency issues appear.
13616
- const info = await fetchGatewayInfo(isTestnet);
13796
+ const info = await fetchGatewayInfo(isTestnet, config);
13617
13797
  const entry = info.domains.find((d)=>d.domain === domain);
13618
13798
  if (!entry) {
13619
13799
  throw new KitError({
@@ -14079,12 +14259,22 @@ function throwNetworkMismatch(expected, actual) {
14079
14259
  * @param allocations - Normalized allocations used to map domain → adapter/chain.
14080
14260
  * @returns Array of groups, each with adapter, chain, and intents to sign.
14081
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.
14082
14265
  const evmGroups = new Map();
14083
14266
  const solanaGroups = [];
14084
14267
  for (const intent of intents){
14085
- 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);
14086
14276
  if (!alloc) {
14087
- 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');
14088
14278
  }
14089
14279
  if (alloc.chain.type === 'solana') {
14090
14280
  solanaGroups.push(groupSolanaIntents(intent, alloc));
@@ -17501,12 +17691,12 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17501
17691
  * exceeds the 5-minute timeout without reaching a terminal status.
17502
17692
  * @throws KitError Propagated from {@link pollApiGet} if the HTTP
17503
17693
  * request itself fails or returns a non-OK response.
17504
- */ async function pollForwarderCompletion(apiBaseUrl, transferId) {
17694
+ */ async function pollForwarderCompletion(apiBaseUrl, transferId, requestConfig) {
17505
17695
  const startTime = Date.now();
17506
17696
  while(Date.now() - startTime < FORWARDER_POLL_TIMEOUT_MS){
17507
17697
  let status;
17508
17698
  try {
17509
- status = await pollApiGet(`${apiBaseUrl}/v1/transfer/${transferId}`, assertGatewayTransferDetails);
17699
+ status = await pollApiGet(`${apiBaseUrl}/v1/transfer/${transferId}`, assertGatewayTransferDetails, requestConfig);
17510
17700
  } catch (error) {
17511
17701
  throwGatewayApiError(error);
17512
17702
  }
@@ -17624,7 +17814,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17624
17814
  * @param params - Spend parameters (source(s) and token).
17625
17815
  * @param destChain - Resolved destination chain (used for network type).
17626
17816
  * @returns Confirmed balances tagged with their originating source index.
17627
- */ async function fetchChainBalances(params, destChain) {
17817
+ */ async function fetchChainBalances(params, destChain, requestConfig) {
17628
17818
  const rawSources = Array.isArray(params.from) ? params.from : [
17629
17819
  params.from
17630
17820
  ];
@@ -17653,7 +17843,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17653
17843
  token: params.token,
17654
17844
  sources: querySource,
17655
17845
  networkType
17656
- });
17846
+ }, requestConfig);
17657
17847
  }));
17658
17848
  const chainBalances = [];
17659
17849
  for(let i = 0; i < balanceResults.length; i++){
@@ -17726,9 +17916,9 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17726
17916
  * @param recipientAddress - Resolved recipient address.
17727
17917
  * @param useForwarder - Whether the Forwarding Service path is active.
17728
17918
  * @returns Allocations, intents, and (auto-allocation only) confirmed balances.
17729
- */ async function resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder) {
17919
+ */ async function resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder, requestConfig) {
17730
17920
  if (params.amountIn) {
17731
- const chainBalances = await fetchChainBalances(params, destChain);
17921
+ const chainBalances = await fetchChainBalances(params, destChain, requestConfig);
17732
17922
  const { allocations, intents } = await buildAutoAllocatedFromBalances(params, destChain, recipientAddress, useForwarder, params.amountIn, chainBalances);
17733
17923
  return {
17734
17924
  allocations,
@@ -17751,11 +17941,11 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17751
17941
  * @param useForwarder - Whether the Forwarding Service path is active.
17752
17942
  * @param allocations - Normalised allocations (forwarded to error handler).
17753
17943
  * @returns Estimate entries and optional forwarding fee.
17754
- */ async function fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations) {
17944
+ */ async function fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations, requestConfig) {
17755
17945
  if (useForwarder) {
17756
17946
  let fwdResponse;
17757
17947
  try {
17758
- fwdResponse = await pollApiPost(`${apiBaseUrl}/v1/estimate?enableForwarder=true`, estimateBody, assertGatewayForwarderEstimateResponse);
17948
+ fwdResponse = await pollApiPost(`${apiBaseUrl}/v1/estimate?enableForwarder=true`, estimateBody, assertGatewayForwarderEstimateResponse, requestConfig);
17759
17949
  } catch (error) {
17760
17950
  throwGatewayApiError(error, allocations);
17761
17951
  }
@@ -17766,7 +17956,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17766
17956
  }
17767
17957
  let entries;
17768
17958
  try {
17769
- entries = await pollApiPost(`${apiBaseUrl}/v1/estimate`, estimateBody, assertGatewayEstimateResponse);
17959
+ entries = await pollApiPost(`${apiBaseUrl}/v1/estimate`, estimateBody, assertGatewayEstimateResponse, requestConfig);
17770
17960
  } catch (error) {
17771
17961
  throwGatewayApiError(error, allocations);
17772
17962
  }
@@ -17837,14 +18027,14 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17837
18027
  * @param destChain - Resolved destination chain with Gateway v1 config.
17838
18028
  * @param useForwarder - Whether the Forwarding Service path is active.
17839
18029
  * @returns Estimated intents (with real maxFee) and optional forwarding fee.
17840
- */ async function validateAndEstimate(allocations, intents, destChain, useForwarder) {
18030
+ */ async function validateAndEstimate(allocations, intents, destChain, useForwarder, requestConfig) {
17841
18031
  assertNetworkCompatibility(allocations, destChain);
17842
18032
  if (useForwarder) {
17843
18033
  assertForwarderRouteSupport(destChain, allocations);
17844
18034
  }
17845
18035
  const apiBaseUrl = getGatewayApiBaseUrl(destChain.isTestnet);
17846
18036
  const estimateBody = buildEstimateRequestBody(intents);
17847
- const { entries, forwardingFee } = await fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations);
18037
+ const { entries, forwardingFee } = await fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations, requestConfig);
17848
18038
  const estimatedIntents = parseEstimateResponse(entries, intents);
17849
18039
  return {
17850
18040
  estimatedIntents,
@@ -17903,7 +18093,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17903
18093
  }
17904
18094
  throw err;
17905
18095
  }
17906
- 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);
17907
18097
  const stillOverdrawn = findOverdrawnChains(estimatedIntents, corrected.allocations, opts.chainBalances);
17908
18098
  if (stillOverdrawn.length === 0) {
17909
18099
  return {
@@ -17937,12 +18127,12 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17937
18127
  * @param recipientAddress - Resolved recipient address.
17938
18128
  * @param useForwarder - Whether the Forwarding Service path is active.
17939
18129
  * @returns Allocations, estimated intents, and optional forwarding fee.
17940
- */ async function resolveValidatedIntents(params, destChain, recipientAddress, useForwarder) {
18130
+ */ async function resolveValidatedIntents(params, destChain, recipientAddress, useForwarder, requestConfig) {
17941
18131
  if (useForwarder) {
17942
18132
  assertForwarderRouteSupport(destChain);
17943
18133
  }
17944
- const { allocations, intents, chainBalances } = await resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder);
17945
- 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);
17946
18136
  if (params.amountIn && chainBalances) {
17947
18137
  const overdrawn = findOverdrawnChains(estimatedIntents, allocations, chainBalances);
17948
18138
  if (overdrawn.length > 0) {
@@ -17955,7 +18145,10 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17955
18145
  chainBalances,
17956
18146
  estimatedIntents,
17957
18147
  allocations,
17958
- overdrawn
18148
+ overdrawn,
18149
+ ...requestConfig ? {
18150
+ requestConfig
18151
+ } : {}
17959
18152
  });
17960
18153
  }
17961
18154
  }
@@ -17999,10 +18192,10 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17999
18192
  attestationSignature: transferResponse.signature
18000
18193
  };
18001
18194
  }
18002
- async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, steps) {
18195
+ async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, steps, requestConfig) {
18003
18196
  const chainName = destChain.name;
18004
18197
  const recipientAddress = await resolveRecipientAddress(params.to);
18005
- const { allocations, estimatedIntents, forwardingFee: estimateFwdFee } = await resolveValidatedIntents(params, destChain, recipientAddress, useForwarder);
18198
+ const { allocations, estimatedIntents, forwardingFee: estimateFwdFee } = await resolveValidatedIntents(params, destChain, recipientAddress, useForwarder, requestConfig);
18006
18199
  pushStep(steps, dispatcher, 'gateway.spend.step.buildBurnIntents', chainName, {
18007
18200
  name: 'buildBurnIntents',
18008
18201
  state: 'success',
@@ -18039,7 +18232,7 @@ async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, s
18039
18232
  const forwarderParam = useForwarder ? '?enableForwarder=true' : '';
18040
18233
  let transferResponse;
18041
18234
  try {
18042
- transferResponse = await pollApiPost(`${transferApiBaseUrl}/v1/transfer${forwarderParam}`, transferBody, assertGatewayTransferResponse);
18235
+ transferResponse = await pollApiPost(`${transferApiBaseUrl}/v1/transfer${forwarderParam}`, transferBody, assertGatewayTransferResponse, requestConfig);
18043
18236
  } catch (error) {
18044
18237
  throwGatewayApiError(error, allocations);
18045
18238
  }
@@ -18119,10 +18312,11 @@ function updateFeesWithActual(fees, completionStatus) {
18119
18312
  amount: actual
18120
18313
  } : f);
18121
18314
  }
18122
- 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;
18123
18317
  if (forwarder && transferId) {
18124
18318
  const apiBaseUrl = getGatewayApiBaseUrl(destChain.isTestnet);
18125
- const completionStatus = await pollForwarderCompletion(apiBaseUrl, transferId);
18319
+ const completionStatus = await pollForwarderCompletion(apiBaseUrl, transferId, requestConfig);
18126
18320
  if (!completionStatus.transactionHash) {
18127
18321
  throw new KitError({
18128
18322
  ...OnchainError.TRANSACTION_REVERTED,
@@ -18205,9 +18399,20 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18205
18399
  /**
18206
18400
  * Execute the mint step, recording success/error as a spend step.
18207
18401
  */ async function executeMintStep(opts) {
18208
- const { params, destChain, forwarder, transferId, attestation, attestationSignature, fees, steps, dispatcher } = opts;
18402
+ const { params, destChain, forwarder, transferId, attestation, attestationSignature, fees, steps, dispatcher, requestConfig } = opts;
18209
18403
  try {
18210
- 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
+ });
18211
18416
  pushStep(steps, dispatcher, 'gateway.spend.step.mint', destChain.name, {
18212
18417
  name: 'mint',
18213
18418
  state: 'success',
@@ -18262,7 +18467,8 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18262
18467
  assertSpendAddresses(params, destChain);
18263
18468
  const forwarder = isForwarderEnabled(params.to);
18264
18469
  const steps = [];
18265
- 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);
18266
18472
  const fees = appendForwarderFee(context.fees, context.forwardingFee);
18267
18473
  const mintResult = await executeMintStep({
18268
18474
  params,
@@ -18273,7 +18479,10 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18273
18479
  attestationSignature: context.attestationSignature,
18274
18480
  fees,
18275
18481
  steps,
18276
- dispatcher
18482
+ dispatcher,
18483
+ ...requestConfig ? {
18484
+ requestConfig
18485
+ } : {}
18277
18486
  });
18278
18487
  // A throwing `onBroadcast` must never strand the caller after a
18279
18488
  // successful mint — the chain has moved. `safeInvokeCallback` swallows
@@ -18290,14 +18499,14 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18290
18499
  /**
18291
18500
  * Resolve the spend context via the normal (non-retry) path.
18292
18501
  * Validates `from`, then delegates to `runSpendNormalPath`.
18293
- */ async function resolveNormalContext(params, destChain, forwarder, dispatcher, steps) {
18502
+ */ async function resolveNormalContext(params, destChain, forwarder, dispatcher, steps, requestConfig) {
18294
18503
  if (!params.from) {
18295
18504
  throw createValidationFailedError$1('from', params.from, 'Source (from) is required when config.retry is not provided.');
18296
18505
  }
18297
18506
  return runSpendNormalPath({
18298
18507
  ...params,
18299
18508
  from: params.from
18300
- }, destChain, forwarder, dispatcher, steps);
18509
+ }, destChain, forwarder, dispatcher, steps, requestConfig);
18301
18510
  }
18302
18511
  /**
18303
18512
  * Estimate fees for a Gateway spend without executing it.
@@ -18320,13 +18529,13 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18320
18529
  * })
18321
18530
  * fees.forEach((f) => console.log(f.type, f.amount, f.allocations))
18322
18531
  * ```
18323
- */ async function estimateSpend$1(params) {
18532
+ */ async function estimateSpend$1(params, requestConfig) {
18324
18533
  const destChain = resolveChainIdentifier(params.to.chain);
18325
18534
  assertGatewayV1(destChain);
18326
18535
  assertSpendAddresses(params, destChain);
18327
18536
  const forwarder = isForwarderEnabled(params.to);
18328
18537
  const recipientAddress = await resolveRecipientAddress(params.to);
18329
- const { allocations, estimatedIntents, forwardingFee } = await resolveValidatedIntents(params, destChain, recipientAddress, forwarder);
18538
+ const { allocations, estimatedIntents, forwardingFee } = await resolveValidatedIntents(params, destChain, recipientAddress, forwarder, requestConfig);
18330
18539
  const fees = computeEstimateFees(estimatedIntents, allocations, params.config?.customFee);
18331
18540
  if (forwardingFee) {
18332
18541
  fees.push({
@@ -18450,6 +18659,9 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18450
18659
  * the delegate is `'ready'` (finalized); otherwise it is `'pending'`.
18451
18660
  *
18452
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.
18453
18665
  * @returns Promise resolving to `'none'`, `'pending'`, or `'ready'`.
18454
18666
  * @throws KitError if the chain is unsupported or `/v1/info` fails.
18455
18667
  *
@@ -18469,7 +18681,7 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18469
18681
  * const status = await getDelegateStatus(params)
18470
18682
  * if (status === 'ready') { // safe to spend }
18471
18683
  * ```
18472
- */ async function getDelegateStatus$1(params) {
18684
+ */ async function getDelegateStatus$1(params, requestConfig) {
18473
18685
  const { from, delegateAddress } = params;
18474
18686
  const { adapter } = from;
18475
18687
  const chain = resolveChainIdentifier(from.chain);
@@ -18509,7 +18721,7 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18509
18721
  return String(finalizedResult).toLowerCase() === 'true' ? 'ready' : 'pending';
18510
18722
  }
18511
18723
  // EVM: use processedHeight from /v1/info
18512
- const processedHeight = await getProcessedHeight(chain.isTestnet, chain.gateway.domain);
18724
+ const processedHeight = await getProcessedHeight(chain.isTestnet, chain.gateway.domain, requestConfig);
18513
18725
  // If the RPC node lags Gateway's indexer view, the historical read at
18514
18726
  // processedHeight may throw a block-range error. This is safe to treat
18515
18727
  // as 'pending' because processedHeight comes from Gateway's /v1/info
@@ -18727,6 +18939,35 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18727
18939
  dispatchEvent(dispatcher, opName, 'failed', chain, extractErrorInfo(error));
18728
18940
  }
18729
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
+ }
18730
18971
  // ---------------------------------------------------------------------------
18731
18972
  // Factory
18732
18973
  // ---------------------------------------------------------------------------
@@ -18736,7 +18977,12 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18736
18977
  * Returns a plain object that implements {@link IGatewayProvider} by
18737
18978
  * delegating to the standalone functions in `operations/`.
18738
18979
  *
18980
+ * @param config - Optional provider configuration. Supply `headers` to
18981
+ * forward custom HTTP headers with every Gateway API request. See
18982
+ * {@link GatewayV1Config}.
18739
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.
18740
18986
  *
18741
18987
  * @example
18742
18988
  * ```typescript
@@ -18745,7 +18991,23 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18745
18991
  * const provider = createGatewayV1Provider()
18746
18992
  * const chains = provider.getSupportedChains()
18747
18993
  * ```
18748
- */ 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;
18749
19011
  /**
18750
19012
  * Execute an operation with started/succeeded/failed event dispatch.
18751
19013
  */ async function withEvents(opName, chain, startedData, params, fn) {
@@ -18776,21 +19038,25 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18776
19038
  }, params, depositFor$1),
18777
19039
  spend: async (params, options)=>{
18778
19040
  const destChainName = extractChainInfo(params.to.chain).name;
19041
+ const mergedOptions = requestConfig ? {
19042
+ ...options,
19043
+ requestConfig
19044
+ } : options;
18779
19045
  return withEvents('spend', destChainName, {
18780
19046
  destinationChain: destChainName,
18781
19047
  token: params.token ?? 'USDC'
18782
- }, params, async (p)=>spend$1(p, provider.actionDispatcher, options));
19048
+ }, params, async (p)=>spend$1(p, provider.actionDispatcher, mergedOptions));
18783
19049
  },
18784
19050
  estimateSpend: async (params)=>{
18785
19051
  const destChainName = extractChainInfo(params.to.chain).name;
18786
19052
  return withEvents('estimateSpend', destChainName, {
18787
19053
  destinationChain: destChainName,
18788
19054
  token: params.token ?? 'USDC'
18789
- }, params, estimateSpend$1);
19055
+ }, params, async (p)=>estimateSpend$1(p, requestConfig));
18790
19056
  },
18791
19057
  getBalances: async (params)=>withEvents('getBalances', 'aggregate', {
18792
19058
  token: params.token ?? 'USDC'
18793
- }, params, getBalances$1),
19059
+ }, params, async (p)=>getBalances$1(p, requestConfig)),
18794
19060
  addDelegate: async (params)=>withEvents('addDelegate', extractChainInfo(params.from.chain).name, {
18795
19061
  delegateAddress: params.delegateAddress
18796
19062
  }, params, addDelegate$1),
@@ -18808,7 +19074,9 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18808
19074
  // in withEvents. getSupportedChains is synchronous. getDelegateStatus is a
18809
19075
  // lightweight read that consumers treat as a utility check, unlike
18810
19076
  // getBalances which involves API polling and benefits from lifecycle events.
18811
- 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),
18812
19080
  getSupportedChains: getSupportedChains$1
18813
19081
  };
18814
19082
  return provider;
@@ -18818,6 +19086,7 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18818
19086
  * The default providers that will be used in addition to the providers
18819
19087
  * provided to the createUnifiedBalanceKitContext factory function.
18820
19088
  *
19089
+ * @param config - Optional configuration forwarded to the default provider.
18821
19090
  * @returns A readonly tuple with one element: the default Gateway v1 provider
18822
19091
  * instance created via {@link createGatewayV1Provider}.
18823
19092
  * @internal
@@ -18829,8 +19098,10 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18829
19098
  * const { providers } = createUnifiedBalanceKitContext()
18830
19099
  * // providers[0] is the default Gateway v1 instance from getDefaultProviders()
18831
19100
  * ```
18832
- */ const getDefaultProviders = ()=>[
18833
- createGatewayV1Provider()
19101
+ */ const getDefaultProviders = (config = {})=>[
19102
+ createGatewayV1Provider(config.headers ? {
19103
+ headers: config.headers
19104
+ } : {})
18834
19105
  ];
18835
19106
  function createUnifiedBalanceKitContext(config = {}) {
18836
19107
  // Runtime guard: `excludeDefaultProviders: true` with no `providers` is
@@ -18844,7 +19115,10 @@ function createUnifiedBalanceKitContext(config = {}) {
18844
19115
  // Initialize default providers — either the canonical singleton tuple or
18845
19116
  // an empty list when the caller has opted out. Typed loosely here; each
18846
19117
  // public overload narrows the return type for callers.
18847
- const defaultProviders = config.excludeDefaultProviders === true ? [] : getDefaultProviders();
19118
+ const defaultProvidersConfig = config.headers ? {
19119
+ headers: config.headers
19120
+ } : {};
19121
+ const defaultProviders = config.excludeDefaultProviders === true ? [] : getDefaultProviders(defaultProvidersConfig);
18848
19122
  const providers = [
18849
19123
  ...defaultProviders,
18850
19124
  ...config.providers ?? []
@@ -19535,29 +19809,65 @@ function sumAllocationsFromSources(sources) {
19535
19809
  }
19536
19810
  });
19537
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
+ }
19538
19821
  /**
19539
- * Reject `from` arrays containing the same adapter reference more than once.
19540
- * Must run on the raw input (before Zod parsing) because `z.object()` creates
19541
- * 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.
19542
19829
  *
19543
19830
  * @internal
19544
- */ function assertNoDuplicateAdapters(params) {
19831
+ */ function assertNoDuplicateSpendSources(params) {
19545
19832
  if (params == null || typeof params !== 'object') return;
19546
19833
  const from = params['from'];
19547
19834
  if (!Array.isArray(from) || from.length < 2) return;
19548
- const seen = new Set();
19835
+ const seen = new Map();
19549
19836
  for (const source of from){
19550
19837
  if (source == null || typeof source !== 'object') continue;
19551
- const adapter = source['adapter'];
19838
+ const record = source;
19839
+ const adapter = record['adapter'];
19552
19840
  if (adapter == null) continue;
19553
- 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)) {
19554
19848
  throw new KitError({
19555
19849
  ...InputError.VALIDATION_FAILED,
19556
19850
  recoverability: 'FATAL',
19557
- 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.'
19558
19852
  });
19559
19853
  }
19560
- 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
+ }
19561
19871
  }
19562
19872
  }
19563
19873
  /**
@@ -19571,14 +19881,17 @@ function sumAllocationsFromSources(sources) {
19571
19881
  * @throws \{KitError\} When validation fails; error code is
19572
19882
  * {@link InputError.VALIDATION_FAILED}.
19573
19883
  */ function assertSpendParams(params) {
19574
- assertNoDuplicateAdapters(params);
19884
+ assertNoDuplicateSpendSources(params);
19885
+ if (params != null && typeof params === 'object' && 'from' in params) {
19886
+ assertSourceAddressContexts(params['from']);
19887
+ }
19575
19888
  const result = spendParamsSchema.safeParse(params);
19576
19889
  if (!result.success) {
19577
19890
  throw convertZodErrorToStructured(result.error, params);
19578
19891
  }
19579
19892
  const data = result.data;
19580
19893
  // Validate recipientAddress against the destination chain
19581
- if (data.to.recipientAddress) {
19894
+ if (data.to.recipientAddress !== undefined && data.to.recipientAddress !== '') {
19582
19895
  const toChain = data.to.chain;
19583
19896
  if (!isValidAddressForChain(data.to.recipientAddress, toChain)) {
19584
19897
  const chainInfo = extractChainInfo(toChain);
@@ -19586,7 +19899,7 @@ function sumAllocationsFromSources(sources) {
19586
19899
  }
19587
19900
  }
19588
19901
  // Validate sourceAccount against each source's allocation chain
19589
- if (data.from) {
19902
+ if (data.from !== undefined) {
19590
19903
  assertSourceAccountAddresses(data.from);
19591
19904
  }
19592
19905
  }
@@ -19601,11 +19914,15 @@ function assertSourceAccountAddresses(from) {
19601
19914
  from
19602
19915
  ];
19603
19916
  for (const raw of sources){
19604
- if (!raw || typeof raw !== 'object' || !('sourceAccount' in raw)) continue;
19917
+ if (raw === null || typeof raw !== 'object' || !('sourceAccount' in raw)) {
19918
+ continue;
19919
+ }
19605
19920
  const source = raw;
19606
- if (!source.sourceAccount) continue;
19921
+ if (source.sourceAccount === undefined || source.sourceAccount === '') {
19922
+ continue;
19923
+ }
19607
19924
  const sourceChain = getSourceChainFromAllocations(source.allocations);
19608
- if (!sourceChain) continue;
19925
+ if (sourceChain === undefined) continue;
19609
19926
  if (!isValidAddressForChain(source.sourceAccount, sourceChain)) {
19610
19927
  const chainInfo = extractChainInfo(sourceChain);
19611
19928
  throw createInvalidAddressError(source.sourceAccount, String(chainInfo.name), chainInfo.expectedAddressFormat);