@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.
@@ -2303,6 +2303,8 @@ class KitError extends Error {
2303
2303
  Blockchain["Optimism_Sepolia"] = "Optimism_Sepolia";
2304
2304
  Blockchain["Pharos"] = "Pharos";
2305
2305
  Blockchain["Pharos_Testnet"] = "Pharos_Testnet";
2306
+ Blockchain["Plasma"] = "Plasma";
2307
+ Blockchain["Plasma_Testnet"] = "Plasma_Testnet";
2306
2308
  Blockchain["Polkadot_Asset_Hub"] = "Polkadot_Asset_Hub";
2307
2309
  Blockchain["Polkadot_Westmint"] = "Polkadot_Westmint";
2308
2310
  Blockchain["Plume"] = "Plume";
@@ -2372,6 +2374,7 @@ var BridgeChain;
2372
2374
  BridgeChain["Morph"] = "Morph";
2373
2375
  BridgeChain["Optimism"] = "Optimism";
2374
2376
  BridgeChain["Pharos"] = "Pharos";
2377
+ BridgeChain["Plasma"] = "Plasma";
2375
2378
  BridgeChain["Plume"] = "Plume";
2376
2379
  BridgeChain["Polygon"] = "Polygon";
2377
2380
  BridgeChain["Sei"] = "Sei";
@@ -2398,6 +2401,7 @@ var BridgeChain;
2398
2401
  BridgeChain["Morph_Testnet"] = "Morph_Testnet";
2399
2402
  BridgeChain["Optimism_Sepolia"] = "Optimism_Sepolia";
2400
2403
  BridgeChain["Pharos_Testnet"] = "Pharos_Testnet";
2404
+ BridgeChain["Plasma_Testnet"] = "Plasma_Testnet";
2401
2405
  BridgeChain["Plume_Testnet"] = "Plume_Testnet";
2402
2406
  BridgeChain["Polygon_Amoy_Testnet"] = "Polygon_Amoy_Testnet";
2403
2407
  BridgeChain["Sei_Testnet"] = "Sei_Testnet";
@@ -2844,6 +2848,8 @@ var EarnChain;
2844
2848
  * This program handles minting operations for Gateway transactions
2845
2849
  * on Solana devnet.
2846
2850
  */ const GATEWAY_MINTER_SOLANA_DEVNET = 'GATEmKK2ECL1brEngQZWCgMWPbvrEYqsV6u29dAaHavr';
2851
+ /** TokenMessengerWithFees address shared by enabled EVM mainnet sources. */ const TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET = '0x71f54F818671cD0D7ea140Da213e5C8b5C92a408';
2852
+ /** TokenMessengerWithFees address shared by enabled EVM testnet sources. */ const TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET = '0x8745D906D67C346E5eb1aEEED38Eb87F34DF0C0A';
2847
2853
  /**
2848
2854
  * Circle's fee recipient address for EVM chains.
2849
2855
  *
@@ -2891,6 +2897,7 @@ var EarnChain;
2891
2897
  v2: {
2892
2898
  type: 'split',
2893
2899
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
2900
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
2894
2901
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
2895
2902
  confirmations: 1,
2896
2903
  fastConfirmations: 1
@@ -2958,6 +2965,7 @@ var EarnChain;
2958
2965
  v2: {
2959
2966
  type: 'split',
2960
2967
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
2968
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
2961
2969
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
2962
2970
  confirmations: 65,
2963
2971
  fastConfirmations: 1
@@ -3022,6 +3030,7 @@ var EarnChain;
3022
3030
  v2: {
3023
3031
  type: 'split',
3024
3032
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
3033
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3025
3034
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
3026
3035
  confirmations: 65,
3027
3036
  fastConfirmations: 1
@@ -3086,6 +3095,7 @@ var EarnChain;
3086
3095
  v2: {
3087
3096
  type: 'split',
3088
3097
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3098
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3089
3099
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3090
3100
  confirmations: 1,
3091
3101
  fastConfirmations: 1
@@ -3147,6 +3157,7 @@ var EarnChain;
3147
3157
  v2: {
3148
3158
  type: 'split',
3149
3159
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3160
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3150
3161
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3151
3162
  confirmations: 1,
3152
3163
  fastConfirmations: 1
@@ -3214,6 +3225,7 @@ var EarnChain;
3214
3225
  v2: {
3215
3226
  type: 'split',
3216
3227
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3228
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3217
3229
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3218
3230
  confirmations: 65,
3219
3231
  fastConfirmations: 1
@@ -3278,6 +3290,7 @@ var EarnChain;
3278
3290
  v2: {
3279
3291
  type: 'split',
3280
3292
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3293
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3281
3294
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3282
3295
  confirmations: 65,
3283
3296
  fastConfirmations: 1
@@ -3388,6 +3401,7 @@ var EarnChain;
3388
3401
  v2: {
3389
3402
  type: 'split',
3390
3403
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3404
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3391
3405
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3392
3406
  confirmations: 65,
3393
3407
  fastConfirmations: 1
@@ -3432,6 +3446,7 @@ var EarnChain;
3432
3446
  v2: {
3433
3447
  type: 'split',
3434
3448
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3449
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3435
3450
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3436
3451
  confirmations: 65,
3437
3452
  fastConfirmations: 1
@@ -3663,6 +3678,7 @@ var EarnChain;
3663
3678
  v2: {
3664
3679
  type: 'split',
3665
3680
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3681
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3666
3682
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3667
3683
  confirmations: 65,
3668
3684
  fastConfirmations: 2
@@ -3727,6 +3743,7 @@ var EarnChain;
3727
3743
  v2: {
3728
3744
  type: 'split',
3729
3745
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
3746
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3730
3747
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
3731
3748
  confirmations: 65,
3732
3749
  fastConfirmations: 2
@@ -3837,6 +3854,7 @@ var EarnChain;
3837
3854
  v2: {
3838
3855
  type: 'split',
3839
3856
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
3857
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
3840
3858
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
3841
3859
  confirmations: 1,
3842
3860
  fastConfirmations: 1
@@ -3896,6 +3914,7 @@ var EarnChain;
3896
3914
  v2: {
3897
3915
  type: 'split',
3898
3916
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
3917
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
3899
3918
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
3900
3919
  confirmations: 1,
3901
3920
  fastConfirmations: 1
@@ -4050,6 +4069,7 @@ var EarnChain;
4050
4069
  v2: {
4051
4070
  type: 'split',
4052
4071
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4072
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4053
4073
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4054
4074
  confirmations: 65,
4055
4075
  fastConfirmations: 1
@@ -4097,6 +4117,7 @@ var EarnChain;
4097
4117
  v2: {
4098
4118
  type: 'split',
4099
4119
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4120
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4100
4121
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4101
4122
  confirmations: 65,
4102
4123
  fastConfirmations: 1
@@ -4141,6 +4162,7 @@ var EarnChain;
4141
4162
  v2: {
4142
4163
  type: 'split',
4143
4164
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4165
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4144
4166
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4145
4167
  confirmations: 1,
4146
4168
  fastConfirmations: 1
@@ -4186,6 +4208,7 @@ var EarnChain;
4186
4208
  v2: {
4187
4209
  type: 'split',
4188
4210
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
4211
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4189
4212
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
4190
4213
  confirmations: 1,
4191
4214
  fastConfirmations: 1
@@ -4232,6 +4255,7 @@ var EarnChain;
4232
4255
  v2: {
4233
4256
  type: 'split',
4234
4257
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4258
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4235
4259
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4236
4260
  confirmations: 1,
4237
4261
  fastConfirmations: 1
@@ -4545,6 +4569,7 @@ var EarnChain;
4545
4569
  v2: {
4546
4570
  type: 'split',
4547
4571
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4572
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4548
4573
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4549
4574
  confirmations: 65,
4550
4575
  fastConfirmations: 1
@@ -4609,6 +4634,7 @@ var EarnChain;
4609
4634
  v2: {
4610
4635
  type: 'split',
4611
4636
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
4637
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4612
4638
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
4613
4639
  confirmations: 65,
4614
4640
  fastConfirmations: 1
@@ -4729,6 +4755,98 @@ var EarnChain;
4729
4755
  }
4730
4756
  });
4731
4757
 
4758
+ /**
4759
+ * Plasma Mainnet chain definition
4760
+ * @remarks
4761
+ * This represents the official production network for the Plasma blockchain.
4762
+ * Plasma is an EVM-equivalent Layer 1 blockchain purpose-built for global
4763
+ * stablecoin payments, with deterministic BFT finality (PlasmaBFT/Fast-HotStuff).
4764
+ */ const Plasma = defineChain({
4765
+ type: 'evm',
4766
+ chain: Blockchain.Plasma,
4767
+ name: 'Plasma',
4768
+ title: 'Plasma Mainnet',
4769
+ nativeCurrency: {
4770
+ name: 'Plasma',
4771
+ symbol: 'XPL',
4772
+ decimals: 18
4773
+ },
4774
+ chainId: 9745,
4775
+ isTestnet: false,
4776
+ explorerUrl: 'https://plasmascan.to/tx/{hash}',
4777
+ rpcEndpoints: [
4778
+ 'https://rpc.plasma.to'
4779
+ ],
4780
+ eurcAddress: '0x3EE196E78d4d4248b849B8E1C7F44C5457FAFD2C',
4781
+ usdcAddress: '0x2d661C89D812261039AF9764eceaAee884f5F67F',
4782
+ usdtAddress: null,
4783
+ cctp: {
4784
+ domain: 33,
4785
+ contracts: {
4786
+ v2: {
4787
+ type: 'split',
4788
+ tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4789
+ messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4790
+ confirmations: 3,
4791
+ fastConfirmations: 1
4792
+ }
4793
+ },
4794
+ forwarderSupported: {
4795
+ source: false,
4796
+ destination: false
4797
+ }
4798
+ },
4799
+ kitContracts: {
4800
+ bridge: BRIDGE_CONTRACT_EVM_MAINNET
4801
+ }
4802
+ });
4803
+
4804
+ /**
4805
+ * Plasma Testnet chain definition
4806
+ * @remarks
4807
+ * This represents the official test network for the Plasma blockchain.
4808
+ * Plasma is an EVM-equivalent Layer 1 blockchain purpose-built for global
4809
+ * stablecoin payments, with deterministic BFT finality (PlasmaBFT/Fast-HotStuff).
4810
+ */ const PlasmaTestnet = defineChain({
4811
+ type: 'evm',
4812
+ chain: Blockchain.Plasma_Testnet,
4813
+ name: 'Plasma Testnet',
4814
+ title: 'Plasma Testnet',
4815
+ nativeCurrency: {
4816
+ name: 'Plasma',
4817
+ symbol: 'XPL',
4818
+ decimals: 18
4819
+ },
4820
+ chainId: 9746,
4821
+ isTestnet: true,
4822
+ explorerUrl: 'https://testnet.plasmascan.to/tx/{hash}',
4823
+ rpcEndpoints: [
4824
+ 'https://testnet-rpc.plasma.to'
4825
+ ],
4826
+ eurcAddress: '0x98AfA0F93Dd993B736399f9074eDcEBD1985A330',
4827
+ usdcAddress: '0xE67Fb267022cBA8064Dd388CC2FED724F3120D9D',
4828
+ usdtAddress: null,
4829
+ cctp: {
4830
+ domain: 33,
4831
+ contracts: {
4832
+ v2: {
4833
+ type: 'split',
4834
+ tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4835
+ messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4836
+ confirmations: 3,
4837
+ fastConfirmations: 1
4838
+ }
4839
+ },
4840
+ forwarderSupported: {
4841
+ source: false,
4842
+ destination: false
4843
+ }
4844
+ },
4845
+ kitContracts: {
4846
+ bridge: BRIDGE_CONTRACT_EVM_TESTNET
4847
+ }
4848
+ });
4849
+
4732
4850
  /**
4733
4851
  * Plume Mainnet chain definition
4734
4852
  * @remarks
@@ -4760,6 +4878,7 @@ var EarnChain;
4760
4878
  v2: {
4761
4879
  type: 'split',
4762
4880
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
4881
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4763
4882
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4764
4883
  confirmations: 65,
4765
4884
  fastConfirmations: 1
@@ -4806,6 +4925,7 @@ var EarnChain;
4806
4925
  v2: {
4807
4926
  type: 'split',
4808
4927
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
4928
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4809
4929
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4810
4930
  confirmations: 65,
4811
4931
  fastConfirmations: 1
@@ -4907,6 +5027,7 @@ var EarnChain;
4907
5027
  v2: {
4908
5028
  type: 'split',
4909
5029
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5030
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
4910
5031
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
4911
5032
  confirmations: 33,
4912
5033
  fastConfirmations: 13
@@ -4972,6 +5093,7 @@ var EarnChain;
4972
5093
  v2: {
4973
5094
  type: 'split',
4974
5095
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5096
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
4975
5097
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
4976
5098
  confirmations: 33,
4977
5099
  fastConfirmations: 13
@@ -5031,6 +5153,7 @@ var EarnChain;
5031
5153
  v2: {
5032
5154
  type: 'split',
5033
5155
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5156
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5034
5157
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5035
5158
  confirmations: 1,
5036
5159
  fastConfirmations: 1
@@ -5090,6 +5213,7 @@ var EarnChain;
5090
5213
  v2: {
5091
5214
  type: 'split',
5092
5215
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5216
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5093
5217
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5094
5218
  confirmations: 1,
5095
5219
  fastConfirmations: 1
@@ -5147,6 +5271,7 @@ var EarnChain;
5147
5271
  v2: {
5148
5272
  type: 'split',
5149
5273
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5274
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5150
5275
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5151
5276
  confirmations: 1,
5152
5277
  fastConfirmations: 1
@@ -5205,6 +5330,7 @@ var EarnChain;
5205
5330
  v2: {
5206
5331
  type: 'split',
5207
5332
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5333
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5208
5334
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5209
5335
  confirmations: 1,
5210
5336
  fastConfirmations: 1
@@ -5520,6 +5646,7 @@ var EarnChain;
5520
5646
  v2: {
5521
5647
  type: 'split',
5522
5648
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5649
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5523
5650
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5524
5651
  confirmations: 65,
5525
5652
  fastConfirmations: 1
@@ -5584,6 +5711,7 @@ var EarnChain;
5584
5711
  v2: {
5585
5712
  type: 'split',
5586
5713
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5714
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5587
5715
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5588
5716
  confirmations: 65,
5589
5717
  fastConfirmations: 1
@@ -5641,6 +5769,7 @@ var EarnChain;
5641
5769
  v2: {
5642
5770
  type: 'split',
5643
5771
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cF5d',
5772
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5644
5773
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5645
5774
  confirmations: 65,
5646
5775
  fastConfirmations: 1
@@ -5700,6 +5829,7 @@ var EarnChain;
5700
5829
  v2: {
5701
5830
  type: 'split',
5702
5831
  tokenMessenger: '0x8fe6b999dc680ccfdd5bf7eb0974218be2542daa',
5832
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5703
5833
  messageTransmitter: '0xe737e5cebeeba77efe34d4aa090756590b1ce275',
5704
5834
  confirmations: 65,
5705
5835
  fastConfirmations: 1
@@ -5760,6 +5890,7 @@ var EarnChain;
5760
5890
  v2: {
5761
5891
  type: 'split',
5762
5892
  tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
5893
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
5763
5894
  messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
5764
5895
  confirmations: 3,
5765
5896
  fastConfirmations: 3
@@ -5805,6 +5936,7 @@ var EarnChain;
5805
5936
  v2: {
5806
5937
  type: 'split',
5807
5938
  tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
5939
+ tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
5808
5940
  messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
5809
5941
  confirmations: 3,
5810
5942
  fastConfirmations: 1
@@ -6015,6 +6147,8 @@ var Chains = {
6015
6147
  OptimismSepolia: OptimismSepolia,
6016
6148
  Pharos: Pharos,
6017
6149
  PharosTestnet: PharosTestnet,
6150
+ Plasma: Plasma,
6151
+ PlasmaTestnet: PlasmaTestnet,
6018
6152
  Plume: Plume,
6019
6153
  PlumeTestnet: PlumeTestnet,
6020
6154
  PolkadotAssetHub: PolkadotAssetHub,
@@ -7980,6 +8114,7 @@ function parseOrThrow(value, schema, context) {
7980
8114
  [Blockchain.Noble]: 'uusdc',
7981
8115
  [Blockchain.Optimism]: '0x0b2c639c533813f4aa9d7837caf62653d097ff85',
7982
8116
  [Blockchain.Pharos]: '0xC879C018dB60520F4355C26eD1a6D572cdAC1815',
8117
+ [Blockchain.Plasma]: '0x2d661C89D812261039AF9764eceaAee884f5F67F',
7983
8118
  [Blockchain.Plume]: '0x222365EF19F7947e5484218551B56bb3965Aa7aF',
7984
8119
  [Blockchain.Polkadot_Asset_Hub]: '1337',
7985
8120
  [Blockchain.Polygon]: '0x3c499c542cef5e3811e1192ce70d8cc03d5c3359',
@@ -8016,6 +8151,7 @@ function parseOrThrow(value, schema, context) {
8016
8151
  [Blockchain.Noble_Testnet]: 'uusdc',
8017
8152
  [Blockchain.Optimism_Sepolia]: '0x5fd84259d66Cd46123540766Be93DFE6D43130D7',
8018
8153
  [Blockchain.Pharos_Testnet]: '0xcfC8330f4BCAB529c625D12781b1C19466A9Fc8B',
8154
+ [Blockchain.Plasma_Testnet]: '0xE67Fb267022cBA8064Dd388CC2FED724F3120D9D',
8019
8155
  [Blockchain.Plume_Testnet]: '0xcB5f30e335672893c7eb944B374c196392C19D18',
8020
8156
  [Blockchain.Polkadot_Westmint]: '31337',
8021
8157
  [Blockchain.Polygon_Amoy_Testnet]: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
@@ -8078,6 +8214,7 @@ function parseOrThrow(value, schema, context) {
8078
8214
  [Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
8079
8215
  [Blockchain.Cronos]: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
8080
8216
  [Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
8217
+ [Blockchain.Plasma]: '0x3EE196E78d4d4248b849B8E1C7F44C5457FAFD2C',
8081
8218
  [Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
8082
8219
  [Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
8083
8220
  // =========================================================================
@@ -8086,7 +8223,8 @@ function parseOrThrow(value, schema, context) {
8086
8223
  [Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
8087
8224
  [Blockchain.Base_Sepolia]: '0x808456652fdb597867f38412077A9182bf77359F',
8088
8225
  [Blockchain.Cronos_Testnet]: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
8089
- [Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4'
8226
+ [Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4',
8227
+ [Blockchain.Plasma_Testnet]: '0x98AfA0F93Dd993B736399f9074eDcEBD1985A330'
8090
8228
  }
8091
8229
  };
8092
8230
 
@@ -8893,7 +9031,7 @@ function parseOrThrow(value, schema, context) {
8893
9031
  }
8894
9032
 
8895
9033
  var name = "@circle-fin/unified-balance-kit";
8896
- var version = "1.4.1";
9034
+ var version = "1.5.0";
8897
9035
  var pkg = {
8898
9036
  name: name,
8899
9037
  version: version};
@@ -12469,6 +12607,23 @@ async function signUnits(group, signingUnits) {
12469
12607
  }
12470
12608
  return signedSets;
12471
12609
  }
12610
+ /**
12611
+ * Fail loudly if a signing group carries an intent it does not own.
12612
+ *
12613
+ * Every intent in a group is signed by `group.address`, so that signer must own
12614
+ * each intent's `spec.sourceSigner`. If distinct spend sources ever collapse
12615
+ * into one group again (DEVX-3638), this throws before signing instead of
12616
+ * silently producing a wrong-signer signature. specs are bytes32 and
12617
+ * `group.address` is a native address, so normalize both before comparing.
12618
+ */ function assertGroupSignerOwnsIntents(group) {
12619
+ if (group.address == null || group.address === '') return;
12620
+ const groupSigner = convertAddress(group.address, 'bytes32').toLowerCase();
12621
+ for (const intent of group.intents){
12622
+ if (intent.spec.sourceSigner.toLowerCase() !== groupSigner) {
12623
+ 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.');
12624
+ }
12625
+ }
12626
+ }
12472
12627
  /**
12473
12628
  * Sign an EVM adapter group.
12474
12629
  *
@@ -12511,22 +12666,42 @@ async function signUnits(group, signingUnits) {
12511
12666
  // Validate the collection before doing bytecode reads or asking a wallet
12512
12667
  // to sign. evmSigningData owns the canonical BurnIntent validation.
12513
12668
  validateGroupIntents(group.intents);
12669
+ // Guard against a wrong-signer collapse: the group's signer must own every
12670
+ // intent it carries.
12671
+ assertGroupSignerOwnsIntents(group);
12514
12672
  const chainsByDomain = collectChainsByDomain(group);
12515
12673
  const signerTypeByDomain = await classifySignerTypes(group, chainsByDomain);
12516
12674
  const signingUnits = createSigningUnits(group, signerTypeByDomain);
12517
12675
  return await signUnits(group, signingUnits);
12518
12676
  }
12519
12677
 
12678
+ // One adapter instance can serve several signer addresses (e.g. a single
12679
+ // dev-controlled adapter used for multiple wallets), so the group map must be
12680
+ // keyed on `(adapter, sourceSigner)` rather than the adapter reference alone.
12681
+ // Keying on the adapter alone collapsed two same-chain sources into one group,
12682
+ // signing the second wallet's intent with the first wallet (DEVX-3638 /
12683
+ // DEVX-3194). A Map needs a primitive key, so give each adapter instance a
12684
+ // stable token and combine it with the (case-normalized) signer address.
12685
+ const adapterTokens = new WeakMap();
12686
+ let nextAdapterToken = 0;
12687
+ function groupKey(alloc) {
12688
+ let token = adapterTokens.get(alloc.adapter);
12689
+ if (token === undefined) {
12690
+ token = nextAdapterToken++;
12691
+ adapterTokens.set(alloc.adapter, token);
12692
+ }
12693
+ return `${String(token)}:${alloc.sourceSigner.toLowerCase()}`;
12694
+ }
12520
12695
  /**
12521
12696
  * Add an EVM intent into the batched EVM group map.
12522
12697
  *
12523
- * On EVM, all intents for the same adapter are batched into a single
12524
- * group. The signing step uses `chainsByDomain` to preserve EOA batching
12698
+ * On EVM, all intents for the same adapter **and signer** are batched into a
12699
+ * single group. The signing step uses `chainsByDomain` to preserve EOA batching
12525
12700
  * while signing ERC-1271 intents separately on their source chains.
12526
12701
  *
12527
12702
  * @param intent - The burn intent to group.
12528
12703
  * @param alloc - The allocation that resolved to this intent.
12529
- * @param evmGroups - Mutable map of adapter → EVM group.
12704
+ * @param evmGroups - Mutable map of `(adapter, sourceSigner)` key → EVM group.
12530
12705
  *
12531
12706
  * @example
12532
12707
  * ```typescript
@@ -12536,12 +12711,13 @@ async function signUnits(group, signingUnits) {
12536
12711
  * groupEvmIntents(intent, alloc, groups)
12537
12712
  * ```
12538
12713
  */ function groupEvmIntents(intent, alloc, evmGroups) {
12539
- const existing = evmGroups.get(alloc.adapter);
12714
+ const key = groupKey(alloc);
12715
+ const existing = evmGroups.get(key);
12540
12716
  if (existing) {
12541
12717
  existing.intents.push(intent);
12542
12718
  existing.chainsByDomain.set(alloc.chain.gateway.domain, alloc.chain);
12543
12719
  } else {
12544
- evmGroups.set(alloc.adapter, {
12720
+ evmGroups.set(key, {
12545
12721
  adapter: alloc.adapter,
12546
12722
  chain: alloc.chain,
12547
12723
  intents: [
@@ -13570,6 +13746,8 @@ const gatewayInfoSchema = zod.z.object({
13570
13746
  * Fetch Gateway info from the `/v1/info` endpoint.
13571
13747
  *
13572
13748
  * @param isTestnet - Whether to query the testnet or mainnet API.
13749
+ * @param config - Optional polling config overrides, including custom
13750
+ * `headers` forwarded with the request.
13573
13751
  * @returns Parsed Gateway info including per-domain processed heights.
13574
13752
  * @throws KitError on HTTP failure or invalid response.
13575
13753
  *
@@ -13578,11 +13756,11 @@ const gatewayInfoSchema = zod.z.object({
13578
13756
  * const info = await fetchGatewayInfo(true)
13579
13757
  * console.log(info.domains.map(d => `${d.chain}: ${d.processedHeight}`))
13580
13758
  * ```
13581
- */ async function fetchGatewayInfo(isTestnet) {
13759
+ */ async function fetchGatewayInfo(isTestnet, config) {
13582
13760
  const apiBaseUrl = getGatewayApiBaseUrl(isTestnet);
13583
13761
  const url = `${apiBaseUrl}/v1/info`;
13584
13762
  try {
13585
- return await pollApiGet(url, assertGatewayInfoResponse);
13763
+ return await pollApiGet(url, assertGatewayInfoResponse, config);
13586
13764
  } catch (error) {
13587
13765
  if (error instanceof KitError) {
13588
13766
  throw error;
@@ -13608,6 +13786,8 @@ const gatewayInfoSchema = zod.z.object({
13608
13786
  *
13609
13787
  * @param isTestnet - Whether to query the testnet or mainnet API.
13610
13788
  * @param domain - The Gateway domain number (e.g. 0 = Ethereum, 6 = Base).
13789
+ * @param config - Optional polling config overrides, including custom
13790
+ * `headers` forwarded with the `/v1/info` request.
13611
13791
  * @returns The processed height as a bigint.
13612
13792
  * @throws KitError when the domain is not found in the response.
13613
13793
  *
@@ -13616,10 +13796,10 @@ const gatewayInfoSchema = zod.z.object({
13616
13796
  * const height = await getProcessedHeight(true, 6) // Base Sepolia
13617
13797
  * console.log(`Gateway processed up to block ${height}`)
13618
13798
  * ```
13619
- */ async function getProcessedHeight(isTestnet, domain) {
13799
+ */ async function getProcessedHeight(isTestnet, domain, config) {
13620
13800
  // No caching in v1 — /v1/info is cheap and delegate status checks
13621
13801
  // are infrequent. Revisit if rate-limit or latency issues appear.
13622
- const info = await fetchGatewayInfo(isTestnet);
13802
+ const info = await fetchGatewayInfo(isTestnet, config);
13623
13803
  const entry = info.domains.find((d)=>d.domain === domain);
13624
13804
  if (!entry) {
13625
13805
  throw new KitError({
@@ -14085,12 +14265,22 @@ function throwNetworkMismatch(expected, actual) {
14085
14265
  * @param allocations - Normalized allocations used to map domain → adapter/chain.
14086
14266
  * @returns Array of groups, each with adapter, chain, and intents to sign.
14087
14267
  */ function groupIntentsByAdapter(intents, allocations) {
14268
+ // Keyed by `(adapter, sourceSigner)` (see groupEvmIntents), not by adapter
14269
+ // alone: two spend sources on the same chain — including two addresses behind
14270
+ // one shared adapter — must stay in separate signing groups.
14088
14271
  const evmGroups = new Map();
14089
14272
  const solanaGroups = [];
14090
14273
  for (const intent of intents){
14091
- const alloc = allocations.find((a)=>a.chain.gateway.domain === intent.spec.sourceDomain);
14274
+ // Match each intent back to its source allocation by BOTH Gateway domain
14275
+ // and signer. Two spend sources on the same chain share a domain, so
14276
+ // matching on domain alone always returned the FIRST allocation — folding
14277
+ // the second wallet's intent into the first wallet's signing group so it
14278
+ // was signed by the wrong wallet (DEVX-3638). specs carry sourceSigner as
14279
+ // bytes32 and allocations carry native addresses, so normalize both.
14280
+ const intentSigner = intent.spec.sourceSigner.toLowerCase();
14281
+ const alloc = allocations.find((a)=>a.chain.gateway.domain === intent.spec.sourceDomain && convertAddress(a.sourceSigner, 'bytes32').toLowerCase() === intentSigner);
14092
14282
  if (!alloc) {
14093
- 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');
14283
+ 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');
14094
14284
  }
14095
14285
  if (alloc.chain.type === 'solana') {
14096
14286
  solanaGroups.push(groupSolanaIntents(intent, alloc));
@@ -17507,12 +17697,12 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17507
17697
  * exceeds the 5-minute timeout without reaching a terminal status.
17508
17698
  * @throws KitError Propagated from {@link pollApiGet} if the HTTP
17509
17699
  * request itself fails or returns a non-OK response.
17510
- */ async function pollForwarderCompletion(apiBaseUrl, transferId) {
17700
+ */ async function pollForwarderCompletion(apiBaseUrl, transferId, requestConfig) {
17511
17701
  const startTime = Date.now();
17512
17702
  while(Date.now() - startTime < FORWARDER_POLL_TIMEOUT_MS){
17513
17703
  let status;
17514
17704
  try {
17515
- status = await pollApiGet(`${apiBaseUrl}/v1/transfer/${transferId}`, assertGatewayTransferDetails);
17705
+ status = await pollApiGet(`${apiBaseUrl}/v1/transfer/${transferId}`, assertGatewayTransferDetails, requestConfig);
17516
17706
  } catch (error) {
17517
17707
  throwGatewayApiError(error);
17518
17708
  }
@@ -17630,7 +17820,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17630
17820
  * @param params - Spend parameters (source(s) and token).
17631
17821
  * @param destChain - Resolved destination chain (used for network type).
17632
17822
  * @returns Confirmed balances tagged with their originating source index.
17633
- */ async function fetchChainBalances(params, destChain) {
17823
+ */ async function fetchChainBalances(params, destChain, requestConfig) {
17634
17824
  const rawSources = Array.isArray(params.from) ? params.from : [
17635
17825
  params.from
17636
17826
  ];
@@ -17659,7 +17849,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17659
17849
  token: params.token,
17660
17850
  sources: querySource,
17661
17851
  networkType
17662
- });
17852
+ }, requestConfig);
17663
17853
  }));
17664
17854
  const chainBalances = [];
17665
17855
  for(let i = 0; i < balanceResults.length; i++){
@@ -17732,9 +17922,9 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17732
17922
  * @param recipientAddress - Resolved recipient address.
17733
17923
  * @param useForwarder - Whether the Forwarding Service path is active.
17734
17924
  * @returns Allocations, intents, and (auto-allocation only) confirmed balances.
17735
- */ async function resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder) {
17925
+ */ async function resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder, requestConfig) {
17736
17926
  if (params.amountIn) {
17737
- const chainBalances = await fetchChainBalances(params, destChain);
17927
+ const chainBalances = await fetchChainBalances(params, destChain, requestConfig);
17738
17928
  const { allocations, intents } = await buildAutoAllocatedFromBalances(params, destChain, recipientAddress, useForwarder, params.amountIn, chainBalances);
17739
17929
  return {
17740
17930
  allocations,
@@ -17757,11 +17947,11 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17757
17947
  * @param useForwarder - Whether the Forwarding Service path is active.
17758
17948
  * @param allocations - Normalised allocations (forwarded to error handler).
17759
17949
  * @returns Estimate entries and optional forwarding fee.
17760
- */ async function fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations) {
17950
+ */ async function fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations, requestConfig) {
17761
17951
  if (useForwarder) {
17762
17952
  let fwdResponse;
17763
17953
  try {
17764
- fwdResponse = await pollApiPost(`${apiBaseUrl}/v1/estimate?enableForwarder=true`, estimateBody, assertGatewayForwarderEstimateResponse);
17954
+ fwdResponse = await pollApiPost(`${apiBaseUrl}/v1/estimate?enableForwarder=true`, estimateBody, assertGatewayForwarderEstimateResponse, requestConfig);
17765
17955
  } catch (error) {
17766
17956
  throwGatewayApiError(error, allocations);
17767
17957
  }
@@ -17772,7 +17962,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17772
17962
  }
17773
17963
  let entries;
17774
17964
  try {
17775
- entries = await pollApiPost(`${apiBaseUrl}/v1/estimate`, estimateBody, assertGatewayEstimateResponse);
17965
+ entries = await pollApiPost(`${apiBaseUrl}/v1/estimate`, estimateBody, assertGatewayEstimateResponse, requestConfig);
17776
17966
  } catch (error) {
17777
17967
  throwGatewayApiError(error, allocations);
17778
17968
  }
@@ -17843,14 +18033,14 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17843
18033
  * @param destChain - Resolved destination chain with Gateway v1 config.
17844
18034
  * @param useForwarder - Whether the Forwarding Service path is active.
17845
18035
  * @returns Estimated intents (with real maxFee) and optional forwarding fee.
17846
- */ async function validateAndEstimate(allocations, intents, destChain, useForwarder) {
18036
+ */ async function validateAndEstimate(allocations, intents, destChain, useForwarder, requestConfig) {
17847
18037
  assertNetworkCompatibility(allocations, destChain);
17848
18038
  if (useForwarder) {
17849
18039
  assertForwarderRouteSupport(destChain, allocations);
17850
18040
  }
17851
18041
  const apiBaseUrl = getGatewayApiBaseUrl(destChain.isTestnet);
17852
18042
  const estimateBody = buildEstimateRequestBody(intents);
17853
- const { entries, forwardingFee } = await fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations);
18043
+ const { entries, forwardingFee } = await fetchEstimate(apiBaseUrl, estimateBody, useForwarder, allocations, requestConfig);
17854
18044
  const estimatedIntents = parseEstimateResponse(entries, intents);
17855
18045
  return {
17856
18046
  estimatedIntents,
@@ -17909,7 +18099,7 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17909
18099
  }
17910
18100
  throw err;
17911
18101
  }
17912
- const { estimatedIntents, forwardingFee } = await validateAndEstimate(corrected.allocations, corrected.intents, opts.destChain, opts.useForwarder);
18102
+ const { estimatedIntents, forwardingFee } = await validateAndEstimate(corrected.allocations, corrected.intents, opts.destChain, opts.useForwarder, opts.requestConfig);
17913
18103
  const stillOverdrawn = findOverdrawnChains(estimatedIntents, corrected.allocations, opts.chainBalances);
17914
18104
  if (stillOverdrawn.length === 0) {
17915
18105
  return {
@@ -17943,12 +18133,12 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17943
18133
  * @param recipientAddress - Resolved recipient address.
17944
18134
  * @param useForwarder - Whether the Forwarding Service path is active.
17945
18135
  * @returns Allocations, estimated intents, and optional forwarding fee.
17946
- */ async function resolveValidatedIntents(params, destChain, recipientAddress, useForwarder) {
18136
+ */ async function resolveValidatedIntents(params, destChain, recipientAddress, useForwarder, requestConfig) {
17947
18137
  if (useForwarder) {
17948
18138
  assertForwarderRouteSupport(destChain);
17949
18139
  }
17950
- const { allocations, intents, chainBalances } = await resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder);
17951
- const { estimatedIntents, forwardingFee } = await validateAndEstimate(allocations, intents, destChain, useForwarder);
18140
+ const { allocations, intents, chainBalances } = await resolveAllocationsAndIntents(params, destChain, recipientAddress, useForwarder, requestConfig);
18141
+ const { estimatedIntents, forwardingFee } = await validateAndEstimate(allocations, intents, destChain, useForwarder, requestConfig);
17952
18142
  if (params.amountIn && chainBalances) {
17953
18143
  const overdrawn = findOverdrawnChains(estimatedIntents, allocations, chainBalances);
17954
18144
  if (overdrawn.length > 0) {
@@ -17961,7 +18151,10 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
17961
18151
  chainBalances,
17962
18152
  estimatedIntents,
17963
18153
  allocations,
17964
- overdrawn
18154
+ overdrawn,
18155
+ ...requestConfig ? {
18156
+ requestConfig
18157
+ } : {}
17965
18158
  });
17966
18159
  }
17967
18160
  }
@@ -18005,10 +18198,10 @@ const FORWARDER_POLL_TIMEOUT_MS = 300_000;
18005
18198
  attestationSignature: transferResponse.signature
18006
18199
  };
18007
18200
  }
18008
- async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, steps) {
18201
+ async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, steps, requestConfig) {
18009
18202
  const chainName = destChain.name;
18010
18203
  const recipientAddress = await resolveRecipientAddress(params.to);
18011
- const { allocations, estimatedIntents, forwardingFee: estimateFwdFee } = await resolveValidatedIntents(params, destChain, recipientAddress, useForwarder);
18204
+ const { allocations, estimatedIntents, forwardingFee: estimateFwdFee } = await resolveValidatedIntents(params, destChain, recipientAddress, useForwarder, requestConfig);
18012
18205
  pushStep(steps, dispatcher, 'gateway.spend.step.buildBurnIntents', chainName, {
18013
18206
  name: 'buildBurnIntents',
18014
18207
  state: 'success',
@@ -18045,7 +18238,7 @@ async function runSpendNormalPath(params, destChain, useForwarder, dispatcher, s
18045
18238
  const forwarderParam = useForwarder ? '?enableForwarder=true' : '';
18046
18239
  let transferResponse;
18047
18240
  try {
18048
- transferResponse = await pollApiPost(`${transferApiBaseUrl}/v1/transfer${forwarderParam}`, transferBody, assertGatewayTransferResponse);
18241
+ transferResponse = await pollApiPost(`${transferApiBaseUrl}/v1/transfer${forwarderParam}`, transferBody, assertGatewayTransferResponse, requestConfig);
18049
18242
  } catch (error) {
18050
18243
  throwGatewayApiError(error, allocations);
18051
18244
  }
@@ -18125,10 +18318,11 @@ function updateFeesWithActual(fees, completionStatus) {
18125
18318
  amount: actual
18126
18319
  } : f);
18127
18320
  }
18128
- async function resolveDestinationTxHash(params, destChain, forwarder, transferId, attestation, attestationSignature, fees) {
18321
+ async function resolveDestinationTxHash(opts) {
18322
+ const { params, destChain, forwarder, transferId, attestation, attestationSignature, fees, requestConfig } = opts;
18129
18323
  if (forwarder && transferId) {
18130
18324
  const apiBaseUrl = getGatewayApiBaseUrl(destChain.isTestnet);
18131
- const completionStatus = await pollForwarderCompletion(apiBaseUrl, transferId);
18325
+ const completionStatus = await pollForwarderCompletion(apiBaseUrl, transferId, requestConfig);
18132
18326
  if (!completionStatus.transactionHash) {
18133
18327
  throw new KitError({
18134
18328
  ...OnchainError.TRANSACTION_REVERTED,
@@ -18211,9 +18405,20 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18211
18405
  /**
18212
18406
  * Execute the mint step, recording success/error as a spend step.
18213
18407
  */ async function executeMintStep(opts) {
18214
- const { params, destChain, forwarder, transferId, attestation, attestationSignature, fees, steps, dispatcher } = opts;
18408
+ const { params, destChain, forwarder, transferId, attestation, attestationSignature, fees, steps, dispatcher, requestConfig } = opts;
18215
18409
  try {
18216
- const mintResult = await resolveDestinationTxHash(params, destChain, forwarder, transferId, attestation, attestationSignature, fees);
18410
+ const mintResult = await resolveDestinationTxHash({
18411
+ params,
18412
+ destChain,
18413
+ forwarder,
18414
+ transferId,
18415
+ attestation,
18416
+ attestationSignature,
18417
+ fees,
18418
+ ...requestConfig ? {
18419
+ requestConfig
18420
+ } : {}
18421
+ });
18217
18422
  pushStep(steps, dispatcher, 'gateway.spend.step.mint', destChain.name, {
18218
18423
  name: 'mint',
18219
18424
  state: 'success',
@@ -18268,7 +18473,8 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18268
18473
  assertSpendAddresses(params, destChain);
18269
18474
  const forwarder = isForwarderEnabled(params.to);
18270
18475
  const steps = [];
18271
- const context = params.config?.retry ? await resolveRetryContext(params) : await resolveNormalContext(params, destChain, forwarder, dispatcher, steps);
18476
+ const requestConfig = options?.requestConfig;
18477
+ const context = params.config?.retry ? await resolveRetryContext(params) : await resolveNormalContext(params, destChain, forwarder, dispatcher, steps, requestConfig);
18272
18478
  const fees = appendForwarderFee(context.fees, context.forwardingFee);
18273
18479
  const mintResult = await executeMintStep({
18274
18480
  params,
@@ -18279,7 +18485,10 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18279
18485
  attestationSignature: context.attestationSignature,
18280
18486
  fees,
18281
18487
  steps,
18282
- dispatcher
18488
+ dispatcher,
18489
+ ...requestConfig ? {
18490
+ requestConfig
18491
+ } : {}
18283
18492
  });
18284
18493
  // A throwing `onBroadcast` must never strand the caller after a
18285
18494
  // successful mint — the chain has moved. `safeInvokeCallback` swallows
@@ -18296,14 +18505,14 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18296
18505
  /**
18297
18506
  * Resolve the spend context via the normal (non-retry) path.
18298
18507
  * Validates `from`, then delegates to `runSpendNormalPath`.
18299
- */ async function resolveNormalContext(params, destChain, forwarder, dispatcher, steps) {
18508
+ */ async function resolveNormalContext(params, destChain, forwarder, dispatcher, steps, requestConfig) {
18300
18509
  if (!params.from) {
18301
18510
  throw createValidationFailedError$1('from', params.from, 'Source (from) is required when config.retry is not provided.');
18302
18511
  }
18303
18512
  return runSpendNormalPath({
18304
18513
  ...params,
18305
18514
  from: params.from
18306
- }, destChain, forwarder, dispatcher, steps);
18515
+ }, destChain, forwarder, dispatcher, steps, requestConfig);
18307
18516
  }
18308
18517
  /**
18309
18518
  * Estimate fees for a Gateway spend without executing it.
@@ -18326,13 +18535,13 @@ function buildSpendResult(recipientAddress, destChain, txHash, allocationResults
18326
18535
  * })
18327
18536
  * fees.forEach((f) => console.log(f.type, f.amount, f.allocations))
18328
18537
  * ```
18329
- */ async function estimateSpend$1(params) {
18538
+ */ async function estimateSpend$1(params, requestConfig) {
18330
18539
  const destChain = resolveChainIdentifier(params.to.chain);
18331
18540
  assertGatewayV1(destChain);
18332
18541
  assertSpendAddresses(params, destChain);
18333
18542
  const forwarder = isForwarderEnabled(params.to);
18334
18543
  const recipientAddress = await resolveRecipientAddress(params.to);
18335
- const { allocations, estimatedIntents, forwardingFee } = await resolveValidatedIntents(params, destChain, recipientAddress, forwarder);
18544
+ const { allocations, estimatedIntents, forwardingFee } = await resolveValidatedIntents(params, destChain, recipientAddress, forwarder, requestConfig);
18336
18545
  const fees = computeEstimateFees(estimatedIntents, allocations, params.config?.customFee);
18337
18546
  if (forwardingFee) {
18338
18547
  fees.push({
@@ -18456,6 +18665,9 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18456
18665
  * the delegate is `'ready'` (finalized); otherwise it is `'pending'`.
18457
18666
  *
18458
18667
  * @param params - The adapter context (`from`), delegate address, and token.
18668
+ * @param requestConfig - Optional polling config overrides, including custom
18669
+ * `headers` forwarded with the `/v1/info` request used on the EVM finality
18670
+ * check.
18459
18671
  * @returns Promise resolving to `'none'`, `'pending'`, or `'ready'`.
18460
18672
  * @throws KitError if the chain is unsupported or `/v1/info` fails.
18461
18673
  *
@@ -18475,7 +18687,7 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18475
18687
  * const status = await getDelegateStatus(params)
18476
18688
  * if (status === 'ready') { // safe to spend }
18477
18689
  * ```
18478
- */ async function getDelegateStatus$1(params) {
18690
+ */ async function getDelegateStatus$1(params, requestConfig) {
18479
18691
  const { from, delegateAddress } = params;
18480
18692
  const { adapter } = from;
18481
18693
  const chain = resolveChainIdentifier(from.chain);
@@ -18515,7 +18727,7 @@ function assertNotSelfDelegation(chain, signerAddress, delegateAddress, action)
18515
18727
  return String(finalizedResult).toLowerCase() === 'true' ? 'ready' : 'pending';
18516
18728
  }
18517
18729
  // EVM: use processedHeight from /v1/info
18518
- const processedHeight = await getProcessedHeight(chain.isTestnet, chain.gateway.domain);
18730
+ const processedHeight = await getProcessedHeight(chain.isTestnet, chain.gateway.domain, requestConfig);
18519
18731
  // If the RPC node lags Gateway's indexer view, the historical read at
18520
18732
  // processedHeight may throw a block-range error. This is safe to treat
18521
18733
  // as 'pending' because processedHeight comes from Gateway's /v1/info
@@ -18733,6 +18945,35 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18733
18945
  dispatchEvent(dispatcher, opName, 'failed', chain, extractErrorInfo(error));
18734
18946
  }
18735
18947
 
18948
+ // ---------------------------------------------------------------------------
18949
+ // Config validation
18950
+ // ---------------------------------------------------------------------------
18951
+ function isPlainObject(value) {
18952
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
18953
+ return false;
18954
+ }
18955
+ const prototype = Object.getPrototypeOf(value);
18956
+ return prototype === Object.prototype || prototype === null;
18957
+ }
18958
+ function assertHeadersConfig(headers) {
18959
+ if (headers === undefined) {
18960
+ return;
18961
+ }
18962
+ if (!isPlainObject(headers)) {
18963
+ throw createValidationFailedError$1('config.headers', headers, 'config.headers must be a plain object with string header values when provided');
18964
+ }
18965
+ for (const [name, value] of Object.entries(headers)){
18966
+ if (typeof value !== 'string') {
18967
+ throw createValidationFailedError$1(`config.headers.${name}`, value, 'header values must be strings');
18968
+ }
18969
+ }
18970
+ }
18971
+ function assertGatewayV1Config(config) {
18972
+ if (!isPlainObject(config)) {
18973
+ throw createValidationFailedError$1('config', config, 'config must be a plain object when provided');
18974
+ }
18975
+ assertHeadersConfig(config['headers']);
18976
+ }
18736
18977
  // ---------------------------------------------------------------------------
18737
18978
  // Factory
18738
18979
  // ---------------------------------------------------------------------------
@@ -18742,7 +18983,12 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18742
18983
  * Returns a plain object that implements {@link IGatewayProvider} by
18743
18984
  * delegating to the standalone functions in `operations/`.
18744
18985
  *
18986
+ * @param config - Optional provider configuration. Supply `headers` to
18987
+ * forward custom HTTP headers with every Gateway API request. See
18988
+ * {@link GatewayV1Config}.
18745
18989
  * @returns An {@link IGatewayProvider} instance.
18990
+ * @throws Throws when `config` or `config.headers` is not a plain object, or a
18991
+ * header value is not a string.
18746
18992
  *
18747
18993
  * @example
18748
18994
  * ```typescript
@@ -18751,7 +18997,23 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18751
18997
  * const provider = createGatewayV1Provider()
18752
18998
  * const chains = provider.getSupportedChains()
18753
18999
  * ```
18754
- */ function createGatewayV1Provider() {
19000
+ *
19001
+ * @example
19002
+ * ```typescript
19003
+ * // Forward a custom header on every Gateway API request.
19004
+ * const provider = createGatewayV1Provider({
19005
+ * headers: { 'X-Access-Key': process.env.GATEWAY_ACCESS_KEY! },
19006
+ * })
19007
+ * ```
19008
+ */ function createGatewayV1Provider(config = {}) {
19009
+ assertGatewayV1Config(config);
19010
+ // Captured once and threaded to every Gateway API call the operations make,
19011
+ // so a configured header reaches balances, estimate, transfer, forwarder
19012
+ // status, and /v1/info alike. Left undefined when no headers are configured
19013
+ // so the operations keep their existing defaults untouched.
19014
+ const requestConfig = config.headers ? {
19015
+ headers: config.headers
19016
+ } : undefined;
18755
19017
  /**
18756
19018
  * Execute an operation with started/succeeded/failed event dispatch.
18757
19019
  */ async function withEvents(opName, chain, startedData, params, fn) {
@@ -18782,21 +19044,25 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18782
19044
  }, params, depositFor$1),
18783
19045
  spend: async (params, options)=>{
18784
19046
  const destChainName = extractChainInfo(params.to.chain).name;
19047
+ const mergedOptions = requestConfig ? {
19048
+ ...options,
19049
+ requestConfig
19050
+ } : options;
18785
19051
  return withEvents('spend', destChainName, {
18786
19052
  destinationChain: destChainName,
18787
19053
  token: params.token ?? 'USDC'
18788
- }, params, async (p)=>spend$1(p, provider.actionDispatcher, options));
19054
+ }, params, async (p)=>spend$1(p, provider.actionDispatcher, mergedOptions));
18789
19055
  },
18790
19056
  estimateSpend: async (params)=>{
18791
19057
  const destChainName = extractChainInfo(params.to.chain).name;
18792
19058
  return withEvents('estimateSpend', destChainName, {
18793
19059
  destinationChain: destChainName,
18794
19060
  token: params.token ?? 'USDC'
18795
- }, params, estimateSpend$1);
19061
+ }, params, async (p)=>estimateSpend$1(p, requestConfig));
18796
19062
  },
18797
19063
  getBalances: async (params)=>withEvents('getBalances', 'aggregate', {
18798
19064
  token: params.token ?? 'USDC'
18799
- }, params, getBalances$1),
19065
+ }, params, async (p)=>getBalances$1(p, requestConfig)),
18800
19066
  addDelegate: async (params)=>withEvents('addDelegate', extractChainInfo(params.from.chain).name, {
18801
19067
  delegateAddress: params.delegateAddress
18802
19068
  }, params, addDelegate$1),
@@ -18814,7 +19080,9 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18814
19080
  // in withEvents. getSupportedChains is synchronous. getDelegateStatus is a
18815
19081
  // lightweight read that consumers treat as a utility check, unlike
18816
19082
  // getBalances which involves API polling and benefits from lifecycle events.
18817
- getDelegateStatus: getDelegateStatus$1,
19083
+ // getDelegateStatus is wrapped to forward the provider's request config to
19084
+ // its /v1/info call; getSupportedChains makes no API call.
19085
+ getDelegateStatus: async (params)=>getDelegateStatus$1(params, requestConfig),
18818
19086
  getSupportedChains: getSupportedChains$1
18819
19087
  };
18820
19088
  return provider;
@@ -18824,6 +19092,7 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18824
19092
  * The default providers that will be used in addition to the providers
18825
19093
  * provided to the createUnifiedBalanceKitContext factory function.
18826
19094
  *
19095
+ * @param config - Optional configuration forwarded to the default provider.
18827
19096
  * @returns A readonly tuple with one element: the default Gateway v1 provider
18828
19097
  * instance created via {@link createGatewayV1Provider}.
18829
19098
  * @internal
@@ -18835,8 +19104,10 @@ function dispatchEvent(dispatcher, opName, stage, chain, data) {
18835
19104
  * const { providers } = createUnifiedBalanceKitContext()
18836
19105
  * // providers[0] is the default Gateway v1 instance from getDefaultProviders()
18837
19106
  * ```
18838
- */ const getDefaultProviders = ()=>[
18839
- createGatewayV1Provider()
19107
+ */ const getDefaultProviders = (config = {})=>[
19108
+ createGatewayV1Provider(config.headers ? {
19109
+ headers: config.headers
19110
+ } : {})
18840
19111
  ];
18841
19112
  function createUnifiedBalanceKitContext(config = {}) {
18842
19113
  // Runtime guard: `excludeDefaultProviders: true` with no `providers` is
@@ -18850,7 +19121,10 @@ function createUnifiedBalanceKitContext(config = {}) {
18850
19121
  // Initialize default providers — either the canonical singleton tuple or
18851
19122
  // an empty list when the caller has opted out. Typed loosely here; each
18852
19123
  // public overload narrows the return type for callers.
18853
- const defaultProviders = config.excludeDefaultProviders === true ? [] : getDefaultProviders();
19124
+ const defaultProvidersConfig = config.headers ? {
19125
+ headers: config.headers
19126
+ } : {};
19127
+ const defaultProviders = config.excludeDefaultProviders === true ? [] : getDefaultProviders(defaultProvidersConfig);
18854
19128
  const providers = [
18855
19129
  ...defaultProviders,
18856
19130
  ...config.providers ?? []
@@ -19541,29 +19815,65 @@ function sumAllocationsFromSources(sources) {
19541
19815
  }
19542
19816
  });
19543
19817
 
19818
+ function normalizeAddressIdentity(value) {
19819
+ if (typeof value !== 'string') return undefined;
19820
+ try {
19821
+ return convertAddress(value, 'bytes32').toLowerCase();
19822
+ } catch {
19823
+ // Address validation below owns the structured error for invalid input.
19824
+ return value;
19825
+ }
19826
+ }
19544
19827
  /**
19545
- * Reject `from` arrays containing the same adapter reference more than once.
19546
- * Must run on the raw input (before Zod parsing) because `z.object()` creates
19547
- * new wrapper objects and identity (`===`) is lost.
19828
+ * Reject `from` arrays that describe the same spend source more than once.
19829
+ *
19830
+ * One adapter instance may legitimately be reused across distinct Gateway
19831
+ * source accounts. When `sourceAccount` is omitted, the signer address
19832
+ * identifies the source. Must run on the raw input (before Zod parsing)
19833
+ * because `z.object()` creates new wrapper objects and adapter identity
19834
+ * (`===`) is lost.
19548
19835
  *
19549
19836
  * @internal
19550
- */ function assertNoDuplicateAdapters(params) {
19837
+ */ function assertNoDuplicateSpendSources(params) {
19551
19838
  if (params == null || typeof params !== 'object') return;
19552
19839
  const from = params['from'];
19553
19840
  if (!Array.isArray(from) || from.length < 2) return;
19554
- const seen = new Set();
19841
+ const seen = new Map();
19555
19842
  for (const source of from){
19556
19843
  if (source == null || typeof source !== 'object') continue;
19557
- const adapter = source['adapter'];
19844
+ const record = source;
19845
+ const adapter = record['adapter'];
19558
19846
  if (adapter == null) continue;
19559
- if (seen.has(adapter)) {
19847
+ const sourceAccount = normalizeAddressIdentity(record['sourceAccount']) ?? normalizeAddressIdentity(record['address']);
19848
+ let sourceAccounts = seen.get(adapter);
19849
+ if (sourceAccounts == null) {
19850
+ sourceAccounts = new Set();
19851
+ seen.set(adapter, sourceAccounts);
19852
+ }
19853
+ if (sourceAccounts.has(sourceAccount)) {
19560
19854
  throw new KitError({
19561
19855
  ...InputError.VALIDATION_FAILED,
19562
19856
  recoverability: 'FATAL',
19563
- message: 'Duplicate adapter instance detected in from array. ' + 'Each source must use a distinct adapter object.'
19857
+ message: 'Duplicate spend source detected in from array. The same adapter ' + 'and Gateway source account are reused more than once.'
19564
19858
  });
19565
19859
  }
19566
- seen.add(adapter);
19860
+ sourceAccounts.add(sourceAccount);
19861
+ }
19862
+ }
19863
+ function assertSourceAddressContexts(from) {
19864
+ const sources = Array.isArray(from) ? from : [
19865
+ from
19866
+ ];
19867
+ for (const raw of sources){
19868
+ if (raw == null || typeof raw !== 'object') continue;
19869
+ const source = raw;
19870
+ const addressContext = source.adapter?.capabilities?.addressContext;
19871
+ if (addressContext === 'developer-controlled' && (typeof source.address !== 'string' || source.address === '')) {
19872
+ throw createValidationFailedError$1('address', source.address, 'Address is required for developer-controlled adapters.');
19873
+ }
19874
+ if (addressContext === 'user-controlled' && source.address !== undefined) {
19875
+ throw createValidationFailedError$1('address', source.address, 'Address should not be provided for user-controlled adapters. ' + 'The address is automatically resolved from the connected wallet.');
19876
+ }
19567
19877
  }
19568
19878
  }
19569
19879
  /**
@@ -19577,14 +19887,17 @@ function sumAllocationsFromSources(sources) {
19577
19887
  * @throws \{KitError\} When validation fails; error code is
19578
19888
  * {@link InputError.VALIDATION_FAILED}.
19579
19889
  */ function assertSpendParams(params) {
19580
- assertNoDuplicateAdapters(params);
19890
+ assertNoDuplicateSpendSources(params);
19891
+ if (params != null && typeof params === 'object' && 'from' in params) {
19892
+ assertSourceAddressContexts(params['from']);
19893
+ }
19581
19894
  const result = spendParamsSchema.safeParse(params);
19582
19895
  if (!result.success) {
19583
19896
  throw convertZodErrorToStructured(result.error, params);
19584
19897
  }
19585
19898
  const data = result.data;
19586
19899
  // Validate recipientAddress against the destination chain
19587
- if (data.to.recipientAddress) {
19900
+ if (data.to.recipientAddress !== undefined && data.to.recipientAddress !== '') {
19588
19901
  const toChain = data.to.chain;
19589
19902
  if (!isValidAddressForChain(data.to.recipientAddress, toChain)) {
19590
19903
  const chainInfo = extractChainInfo(toChain);
@@ -19592,7 +19905,7 @@ function sumAllocationsFromSources(sources) {
19592
19905
  }
19593
19906
  }
19594
19907
  // Validate sourceAccount against each source's allocation chain
19595
- if (data.from) {
19908
+ if (data.from !== undefined) {
19596
19909
  assertSourceAccountAddresses(data.from);
19597
19910
  }
19598
19911
  }
@@ -19607,11 +19920,15 @@ function assertSourceAccountAddresses(from) {
19607
19920
  from
19608
19921
  ];
19609
19922
  for (const raw of sources){
19610
- if (!raw || typeof raw !== 'object' || !('sourceAccount' in raw)) continue;
19923
+ if (raw === null || typeof raw !== 'object' || !('sourceAccount' in raw)) {
19924
+ continue;
19925
+ }
19611
19926
  const source = raw;
19612
- if (!source.sourceAccount) continue;
19927
+ if (source.sourceAccount === undefined || source.sourceAccount === '') {
19928
+ continue;
19929
+ }
19613
19930
  const sourceChain = getSourceChainFromAllocations(source.allocations);
19614
- if (!sourceChain) continue;
19931
+ if (sourceChain === undefined) continue;
19615
19932
  if (!isValidAddressForChain(source.sourceAccount, sourceChain)) {
19616
19933
  const chainInfo = extractChainInfo(sourceChain);
19617
19934
  throw createInvalidAddressError(source.sourceAccount, String(chainInfo.name), chainInfo.expectedAddressFormat);