diff --git a/chains/evm/deployment/go.mod b/chains/evm/deployment/go.mod index fd2b315c4..5ed9cd4c5 100644 --- a/chains/evm/deployment/go.mod +++ b/chains/evm/deployment/go.mod @@ -12,8 +12,8 @@ require ( github.com/aws/smithy-go v1.22.5 github.com/ethereum/go-ethereum v1.16.2 github.com/smartcontractkit/chain-selectors v1.0.72 - github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251029160438-93e0a575186e - github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20251029160438-93e0a575186e + github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251030175938-269363720b3b + github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20251030175938-269363720b3b github.com/smartcontractkit/chainlink-common v0.9.6-0.20250929154511-1f5fbda7ae76 github.com/smartcontractkit/chainlink-deployments-framework v0.56.0 github.com/smartcontractkit/chainlink-evm v0.3.3 diff --git a/chains/evm/deployment/go.sum b/chains/evm/deployment/go.sum index a8c1e49e0..92f59f773 100644 --- a/chains/evm/deployment/go.sum +++ b/chains/evm/deployment/go.sum @@ -666,8 +666,8 @@ github.com/smartcontractkit/chain-selectors v1.0.72 h1:AExF2H3mABdLCN0QZd+IjU8Ck github.com/smartcontractkit/chain-selectors v1.0.72/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= github.com/smartcontractkit/chainlink-aptos v0.0.0-20250915164817-46a35eda083d h1:bcfnHPXAhrhUw95X60Y/lDhQAb4SxSyTrqyVCHqfXPI= github.com/smartcontractkit/chainlink-aptos v0.0.0-20250915164817-46a35eda083d/go.mod h1:tEjqontct1/5cKHm4q75nopZa1rwzaQZwd9U9wn0uZE= -github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251029160438-93e0a575186e h1:A5lV4Qdm7Pf5jAADGhBvAIErkWLgFZuvh8+DgYHfTzQ= -github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251029160438-93e0a575186e/go.mod h1:pETrvAF8uvkZgtDgI/oRllZZaC4IpPO26tMxh1u9LC4= +github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251030175938-269363720b3b h1:9l3kWXEliJbJ1sTF/JSE6jFgC/pk5lX/9oBKz87s2Z8= +github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251030175938-269363720b3b/go.mod h1:pETrvAF8uvkZgtDgI/oRllZZaC4IpPO26tMxh1u9LC4= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250908144012-8184001834b5 h1:GmJQqNrWn5pNc8YTei6l2TOSYjK2fRd4+edFZIifCrU= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250908144012-8184001834b5/go.mod h1:Ve1xD71bl193YIZQEoJMmBqLGQJdNs29bwbuObwvbhQ= github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250908144012-8184001834b5 h1:QhcYGEhRLInr1/qh/3RJiVdvJ0nxBHKhPe65WLbSBnU= diff --git a/chains/evm/deployment/v1_7_0/operations/token_pool/token_pool.go b/chains/evm/deployment/v1_7_0/operations/token_pool/token_pool.go index 6cafd0da3..85f08f943 100644 --- a/chains/evm/deployment/v1_7_0/operations/token_pool/token_pool.go +++ b/chains/evm/deployment/v1_7_0/operations/token_pool/token_pool.go @@ -78,6 +78,21 @@ type ApplyCustomBlockConfirmationConfigArgs struct { RateLimitConfigArgs []CustomBlockConfirmationRateLimitConfigArg } +type TokenTransferFeeConfigArg struct { + DestChainSelector uint64 + TokenTransferFeeConfig tokens.TokenTransferFeeConfig +} + +type ApplyTokenTransferFeeConfigUpdatesArgs struct { + TokenTransferFeeConfigArgs []TokenTransferFeeConfigArg + DestToUseDefaultFeeConfigs []uint64 +} + +type GetTokenTransferFeeConfigArgs struct { + LocalToken common.Address + DestChainSelector uint64 +} + var Deploy = contract.NewDeploy(contract.DeployParams[ConstructorArgs]{ Name: "token-pool:deploy", Version: semver.MustParse("1.7.0"), @@ -288,6 +303,34 @@ var SetCustomBlockConfirmationRateLimitConfig = contract.NewWrite(contract.Write }, }) +var ApplyTokenTransferFeeConfigUpdates = contract.NewWrite(contract.WriteParams[ApplyTokenTransferFeeConfigUpdatesArgs, *token_pool.TokenPool]{ + Name: "token-pool:apply-token-transfer-fee-config-updates", + Version: semver.MustParse("1.7.0"), + Description: "Applies token transfer fee overrides or resets defaults for destination chains on a TokenPool", + ContractType: ContractType, + ContractABI: token_pool.TokenPoolABI, + NewContract: token_pool.NewTokenPool, + IsAllowedCaller: contract.OnlyOwner[*token_pool.TokenPool, ApplyTokenTransferFeeConfigUpdatesArgs], + Validate: func(ApplyTokenTransferFeeConfigUpdatesArgs) error { return nil }, + CallContract: func(tokenPool *token_pool.TokenPool, opts *bind.TransactOpts, args ApplyTokenTransferFeeConfigUpdatesArgs) (*types.Transaction, error) { + configs := make([]token_pool.TokenPoolTokenTransferFeeConfigArgs, 0, len(args.TokenTransferFeeConfigArgs)) + for _, cfg := range args.TokenTransferFeeConfigArgs { + configs = append(configs, token_pool.TokenPoolTokenTransferFeeConfigArgs{ + DestChainSelector: cfg.DestChainSelector, + TokenTransferFeeConfig: token_pool.IPoolV2TokenTransferFeeConfig{ + DestGasOverhead: cfg.TokenTransferFeeConfig.DestGasOverhead, + DestBytesOverhead: cfg.TokenTransferFeeConfig.DestBytesOverhead, + DefaultBlockConfirmationFeeUSDCents: cfg.TokenTransferFeeConfig.DefaultBlockConfirmationFeeUSDCents, + CustomBlockConfirmationFeeUSDCents: cfg.TokenTransferFeeConfig.CustomBlockConfirmationFeeUSDCents, + DefaultBlockConfirmationTransferFeeBps: cfg.TokenTransferFeeConfig.DefaultBlockConfirmationTransferFeeBps, + CustomBlockConfirmationTransferFeeBps: cfg.TokenTransferFeeConfig.CustomBlockConfirmationTransferFeeBps, + }, + }) + } + return tokenPool.ApplyTokenTransferFeeConfigUpdates(opts, configs, args.DestToUseDefaultFeeConfigs) + }, +}) + var ApplyAllowListUpdates = contract.NewWrite(contract.WriteParams[ApplyAllowListUpdatesArgs, *token_pool.TokenPool]{ Name: "token-pool:apply-allowlist-updates", Version: semver.MustParse("1.7.0"), @@ -394,6 +437,17 @@ var GetCurrentCustomBlockConfirmationRateLimiterState = contract.NewRead(contrac }, }) +var GetTokenTransferFeeConfig = contract.NewRead(contract.ReadParams[GetTokenTransferFeeConfigArgs, token_pool.IPoolV2TokenTransferFeeConfig, *token_pool.TokenPool]{ + Name: "token-pool:get-token-transfer-fee-config", + Version: semver.MustParse("1.7.0"), + Description: "Gets the token transfer fee configuration for a destination chain on a TokenPool", + ContractType: ContractType, + NewContract: token_pool.NewTokenPool, + CallContract: func(tokenPool *token_pool.TokenPool, opts *bind.CallOpts, args GetTokenTransferFeeConfigArgs) (token_pool.IPoolV2TokenTransferFeeConfig, error) { + return tokenPool.GetTokenTransferFeeConfig(opts, args.LocalToken, args.DestChainSelector, token_pool.ClientEVM2AnyMessage{}, 0, nil) + }, +}) + var GetSupportedChains = contract.NewRead(contract.ReadParams[any, []uint64, *token_pool.TokenPool]{ Name: "token-pool:supported-chains", Version: semver.MustParse("1.7.0"), diff --git a/chains/evm/deployment/v1_7_0/sequences/tokens/configure_token_for_transfers.go b/chains/evm/deployment/v1_7_0/sequences/tokens/configure_token_for_transfers.go index 039ffe7ad..212b39d32 100644 --- a/chains/evm/deployment/v1_7_0/sequences/tokens/configure_token_for_transfers.go +++ b/chains/evm/deployment/v1_7_0/sequences/tokens/configure_token_for_transfers.go @@ -2,12 +2,14 @@ package tokens import ( "fmt" + "strings" "github.com/Masterminds/semver/v3" "github.com/ethereum/go-ethereum/common" evm_contract "github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment/utils/operations/contract" v1_5_0 "github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment/v1_5_0/sequences" "github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment/v1_7_0/operations/token_pool" + tp_bindings "github.com/smartcontractkit/chainlink-ccip/chains/evm/gobindings/generated/latest/token_pool" "github.com/smartcontractkit/chainlink-ccip/deployment/tokens" "github.com/smartcontractkit/chainlink-ccip/deployment/utils/sequences" "github.com/smartcontractkit/chainlink-deployments-framework/chain" @@ -26,15 +28,28 @@ var ConfigureTokenForTransfers = cldf_ops.NewSequence( if !ok { return sequences.OnChainOutput{}, fmt.Errorf("chain with selector %d not found", input.ChainSelector) } + tokenPoolAddress := common.HexToAddress(input.TokenPoolAddress) + + // Fetch the local token address once to reuse for token transfer fee lookups and registration. + tokenAddressReport, err := cldf_ops.ExecuteOperation(b, token_pool.GetToken, chain, evm_contract.FunctionInput[any]{ + ChainSelector: input.ChainSelector, + Address: tokenPoolAddress, + }) + if err != nil { + return sequences.OnChainOutput{}, fmt.Errorf("failed to get token address from token pool with address %s on %s: %w", input.TokenPoolAddress, chain, err) + } + localTokenAddress := tokenAddressReport.Output // Configure remote chains on the token pool as specified // This means adding any remote chains not already added, removing any remote chains that are no longer desired, // or modifying rate limiters on any existing remote chains. customBlockConfirmationArgs := make([]token_pool.CustomBlockConfirmationRateLimitConfigArg, 0, len(input.RemoteChains)) + tokenTransferFeeConfigArgs := make([]token_pool.TokenTransferFeeConfigArg, 0, len(input.RemoteChains)) + destToUseDefaultFeeConfigs := make([]uint64, 0) for destChainSelector, remoteChainConfig := range input.RemoteChains { configureTokenPoolForRemoteChainReport, err := cldf_ops.ExecuteSequence(b, ConfigureTokenPoolForRemoteChain, chain, ConfigureTokenPoolForRemoteChainInput{ ChainSelector: input.ChainSelector, - TokenPoolAddress: common.HexToAddress(input.TokenPoolAddress), + TokenPoolAddress: tokenPoolAddress, RemoteChainSelector: destChainSelector, RemoteChainConfig: remoteChainConfig, }) @@ -43,6 +58,43 @@ var ConfigureTokenForTransfers = cldf_ops.NewSequence( } ops = append(ops, configureTokenPoolForRemoteChainReport.Output.BatchOps...) + supportsTokenPoolFeeConfig := true + var currentFeeConfig tp_bindings.IPoolV2TokenTransferFeeConfig + currentFeeConfigReport, err := cldf_ops.ExecuteOperation(b, token_pool.GetTokenTransferFeeConfig, chain, evm_contract.FunctionInput[token_pool.GetTokenTransferFeeConfigArgs]{ + ChainSelector: input.ChainSelector, + Address: tokenPoolAddress, + Args: token_pool.GetTokenTransferFeeConfigArgs{ + LocalToken: localTokenAddress, + DestChainSelector: destChainSelector, + }, + }) + if err != nil { + if strings.Contains(err.Error(), "execution reverted") { + supportsTokenPoolFeeConfig = false + } else { + return sequences.OnChainOutput{}, fmt.Errorf("failed to get token transfer fee config for token pool %s on %s for remote chain %d: %w", input.TokenPoolAddress, chain, destChainSelector, err) + } + } else { + currentFeeConfig = currentFeeConfigReport.Output + } + + if supportsTokenPoolFeeConfig { + if remoteChainConfig.TokenTransferFeeConfig == nil { + if !tokenTransferFeeConfigIsZero(currentFeeConfig) { + destToUseDefaultFeeConfigs = append(destToUseDefaultFeeConfigs, destChainSelector) + tokenTransferFeeConfigArgs = append(tokenTransferFeeConfigArgs, token_pool.TokenTransferFeeConfigArg{ + DestChainSelector: destChainSelector, + TokenTransferFeeConfig: tokens.TokenTransferFeeConfig{}, + }) + } + } else if !tokenTransferFeeConfigsEqual(currentFeeConfig, *remoteChainConfig.TokenTransferFeeConfig) { + tokenTransferFeeConfigArgs = append(tokenTransferFeeConfigArgs, token_pool.TokenTransferFeeConfigArg{ + DestChainSelector: destChainSelector, + TokenTransferFeeConfig: *remoteChainConfig.TokenTransferFeeConfig, + }) + } + } + if remoteChainConfig.CustomBlockConfirmationConfig != nil { cfg := remoteChainConfig.CustomBlockConfirmationConfig customBlockConfirmationArgs = append(customBlockConfirmationArgs, token_pool.CustomBlockConfirmationRateLimitConfigArg{ @@ -53,11 +105,34 @@ var ConfigureTokenForTransfers = cldf_ops.NewSequence( } } + tokenTransferFeeWrites := make([]evm_contract.WriteOutput, 0, 1) + if len(tokenTransferFeeConfigArgs) > 0 || len(destToUseDefaultFeeConfigs) > 0 { + applyTokenTransferFeesReport, err := cldf_ops.ExecuteOperation(b, token_pool.ApplyTokenTransferFeeConfigUpdates, chain, evm_contract.FunctionInput[token_pool.ApplyTokenTransferFeeConfigUpdatesArgs]{ + ChainSelector: input.ChainSelector, + Address: tokenPoolAddress, + Args: token_pool.ApplyTokenTransferFeeConfigUpdatesArgs{ + TokenTransferFeeConfigArgs: tokenTransferFeeConfigArgs, + DestToUseDefaultFeeConfigs: destToUseDefaultFeeConfigs, + }, + }) + if err != nil { + return sequences.OnChainOutput{}, fmt.Errorf("failed to apply token transfer fee config updates on token pool %s: %w", input.TokenPoolAddress, err) + } + tokenTransferFeeWrites = append(tokenTransferFeeWrites, applyTokenTransferFeesReport.Output) + } + if len(tokenTransferFeeWrites) > 0 { + tokenTransferFeeBatch, err := evm_contract.NewBatchOperationFromWrites(tokenTransferFeeWrites) + if err != nil { + return sequences.OnChainOutput{}, fmt.Errorf("failed to create batch operation for token transfer fee configuration: %w", err) + } + ops = append(ops, tokenTransferFeeBatch) + } + blockConfirmationWrites := make([]evm_contract.WriteOutput, 0, 1) if input.CustomBlockConfirmationConfig != nil { applyConfigReport, err := cldf_ops.ExecuteOperation(b, token_pool.ApplyCustomBlockConfirmationConfigUpdates, chain, evm_contract.FunctionInput[token_pool.ApplyCustomBlockConfirmationConfigArgs]{ ChainSelector: input.ChainSelector, - Address: common.HexToAddress(input.TokenPoolAddress), + Address: tokenPoolAddress, Args: token_pool.ApplyCustomBlockConfirmationConfigArgs{ MinBlockConfirmation: input.CustomBlockConfirmationConfig.MinBlockConfirmation, RateLimitConfigArgs: customBlockConfirmationArgs, @@ -70,7 +145,7 @@ var ConfigureTokenForTransfers = cldf_ops.NewSequence( } else if len(customBlockConfirmationArgs) > 0 { setConfigReport, err := cldf_ops.ExecuteOperation(b, token_pool.SetCustomBlockConfirmationRateLimitConfig, chain, evm_contract.FunctionInput[[]token_pool.CustomBlockConfirmationRateLimitConfigArg]{ ChainSelector: input.ChainSelector, - Address: common.HexToAddress(input.TokenPoolAddress), + Address: tokenPoolAddress, Args: customBlockConfirmationArgs, }) if err != nil { @@ -86,19 +161,11 @@ var ConfigureTokenForTransfers = cldf_ops.NewSequence( ops = append(ops, blockConfirmationBatch) } - tokenAddress, err := cldf_ops.ExecuteOperation(b, token_pool.GetToken, chain, evm_contract.FunctionInput[any]{ - ChainSelector: input.ChainSelector, - Address: common.HexToAddress(input.TokenPoolAddress), - }) - if err != nil { - return sequences.OnChainOutput{}, fmt.Errorf("failed to get token address from token pool with address %s on %s: %w", input.TokenPoolAddress, chain, err) - } - // Register the token with the token admin registry registerTokenReport, err := cldf_ops.ExecuteSequence(b, v1_5_0.RegisterToken, chain, v1_5_0.RegisterTokenInput{ ChainSelector: input.ChainSelector, - TokenAddress: tokenAddress.Output, - TokenPoolAddress: common.HexToAddress(input.TokenPoolAddress), + TokenAddress: localTokenAddress, + TokenPoolAddress: tokenPoolAddress, ExternalAdmin: common.HexToAddress(input.ExternalAdmin), TokenAdminRegistryAddress: common.HexToAddress(input.RegistryAddress), }) @@ -112,3 +179,21 @@ var ConfigureTokenForTransfers = cldf_ops.NewSequence( }, nil }, ) + +func tokenTransferFeeConfigIsZero(config tp_bindings.IPoolV2TokenTransferFeeConfig) bool { + return config.DestGasOverhead == 0 && + config.DestBytesOverhead == 0 && + config.DefaultBlockConfirmationFeeUSDCents == 0 && + config.CustomBlockConfirmationFeeUSDCents == 0 && + config.DefaultBlockConfirmationTransferFeeBps == 0 && + config.CustomBlockConfirmationTransferFeeBps == 0 +} + +func tokenTransferFeeConfigsEqual(current tp_bindings.IPoolV2TokenTransferFeeConfig, desired tokens.TokenTransferFeeConfig) bool { + return current.DestGasOverhead == desired.DestGasOverhead && + current.DestBytesOverhead == desired.DestBytesOverhead && + current.DefaultBlockConfirmationFeeUSDCents == desired.DefaultBlockConfirmationFeeUSDCents && + current.CustomBlockConfirmationFeeUSDCents == desired.CustomBlockConfirmationFeeUSDCents && + current.DefaultBlockConfirmationTransferFeeBps == desired.DefaultBlockConfirmationTransferFeeBps && + current.CustomBlockConfirmationTransferFeeBps == desired.CustomBlockConfirmationTransferFeeBps +} diff --git a/chains/evm/deployment/v1_7_0/sequences/tokens/configure_token_for_transfers_test.go b/chains/evm/deployment/v1_7_0/sequences/tokens/configure_token_for_transfers_test.go index 5f062265e..845dc06fc 100644 --- a/chains/evm/deployment/v1_7_0/sequences/tokens/configure_token_for_transfers_test.go +++ b/chains/evm/deployment/v1_7_0/sequences/tokens/configure_token_for_transfers_test.go @@ -104,6 +104,14 @@ func TestConfigureTokenForTransfers(t *testing.T) { Rate: big.NewInt(70), }, }, + TokenTransferFeeConfig: &tokens_core.TokenTransferFeeConfig{ + DestGasOverhead: 321, + DestBytesOverhead: 654, + DefaultBlockConfirmationFeeUSDCents: 777, + CustomBlockConfirmationFeeUSDCents: 888, + DefaultBlockConfirmationTransferFeeBps: 123, + CustomBlockConfirmationTransferFeeBps: 234, + }, }, remoteChainSel2: { RemoteToken: common.LeftPadBytes(common.FromHex("0x321"), 32), @@ -164,9 +172,23 @@ func TestConfigureTokenForTransfers(t *testing.T) { // Verify configuration for first remote chain checkRemoteChainConfiguration(t, tp, remoteChainSel1, input.RemoteChains[remoteChainSel1]) + assertTokenTransferFeeConfig( + t, + tp, + common.HexToAddress(tokenAddress), + remoteChainSel1, + input.RemoteChains[remoteChainSel1].TokenTransferFeeConfig, + ) // Verify configuration for second remote chain checkRemoteChainConfiguration(t, tp, remoteChainSel2, input.RemoteChains[remoteChainSel2]) + assertTokenTransferFeeConfig( + t, + tp, + common.HexToAddress(tokenAddress), + remoteChainSel2, + input.RemoteChains[remoteChainSel2].TokenTransferFeeConfig, + ) minBlockConfirmation, err := tp.GetMinBlockConfirmation(nil) require.NoError(t, err, "Failed to get configured min block confirmation") @@ -301,6 +323,7 @@ func TestConfigureTokenForTransfers(t *testing.T) { require.Equal(t, uint16(0), minBlockConfirmation, "Min block confirmation should remain default") assertCustomBlockConfirmationBucket(t, tp, remoteChainSel, input.RemoteChains[remoteChainSel].CustomBlockConfirmationConfig) }) + } // checkRemoteChainConfiguration verifies the configuration for a remote chain on the token pool @@ -345,6 +368,32 @@ func checkRemoteChainConfiguration(t *testing.T, tp *tp_bindings.TokenPool, remo } } +func assertTokenTransferFeeConfig( + t *testing.T, + tp *tp_bindings.TokenPool, + localToken common.Address, + destChainSelector uint64, + expected *tokens_core.TokenTransferFeeConfig, +) { + config, err := tp.GetTokenTransferFeeConfig(nil, localToken, destChainSelector, tp_bindings.ClientEVM2AnyMessage{}, 0, nil) + require.NoError(t, err, "Failed to get token transfer fee config") + if expected == nil { + require.Zero(t, config.DestGasOverhead, "Dest gas overhead should be zero when no override is configured") + require.Zero(t, config.DestBytesOverhead, "Dest bytes overhead should be zero when no override is configured") + require.Zero(t, config.DefaultBlockConfirmationFeeUSDCents, "Default fee cents should be zero when no override is configured") + require.Zero(t, config.CustomBlockConfirmationFeeUSDCents, "Custom fee cents should be zero when no override is configured") + require.Zero(t, config.DefaultBlockConfirmationTransferFeeBps, "Default transfer fee bps should be zero when no override is configured") + require.Zero(t, config.CustomBlockConfirmationTransferFeeBps, "Custom transfer fee bps should be zero when no override is configured") + return + } + require.Equal(t, expected.DestGasOverhead, config.DestGasOverhead, "Dest gas overhead mismatch") + require.Equal(t, expected.DestBytesOverhead, config.DestBytesOverhead, "Dest bytes overhead mismatch") + require.Equal(t, expected.DefaultBlockConfirmationFeeUSDCents, config.DefaultBlockConfirmationFeeUSDCents, "Default fee cents mismatch") + require.Equal(t, expected.CustomBlockConfirmationFeeUSDCents, config.CustomBlockConfirmationFeeUSDCents, "Custom fee cents mismatch") + require.Equal(t, expected.DefaultBlockConfirmationTransferFeeBps, config.DefaultBlockConfirmationTransferFeeBps, "Default transfer fee bps mismatch") + require.Equal(t, expected.CustomBlockConfirmationTransferFeeBps, config.CustomBlockConfirmationTransferFeeBps, "Custom transfer fee bps mismatch") +} + func assertCustomBlockConfirmationBucket( t *testing.T, tp *tp_bindings.TokenPool, diff --git a/deployment/tokens/configure_tokens_for_transfers.go b/deployment/tokens/configure_tokens_for_transfers.go index d26875473..83ce73c27 100644 --- a/deployment/tokens/configure_tokens_for_transfers.go +++ b/deployment/tokens/configure_tokens_for_transfers.go @@ -118,6 +118,7 @@ func convertRemoteChainConfig( InboundRateLimiterConfig: inCfg.InboundRateLimiterConfig, OutboundRateLimiterConfig: inCfg.OutboundRateLimiterConfig, CustomBlockConfirmationConfig: inCfg.CustomBlockConfirmationConfig, + TokenTransferFeeConfig: inCfg.TokenTransferFeeConfig, } if inCfg.RemotePool != nil { fullRemotePoolRef, err := datastore_utils.FindAndFormatRef(e.DataStore, *inCfg.RemotePool, remoteChainSelector, datastore_utils.FullRef) diff --git a/deployment/tokens/product.go b/deployment/tokens/product.go index 33cec4f2f..1d0e65e5c 100644 --- a/deployment/tokens/product.go +++ b/deployment/tokens/product.go @@ -38,6 +38,16 @@ type RateLimiterConfig struct { Rate *big.Int } +// TokenTransferFeeConfig captures per-destination fee overrides that a token pool can apply. +type TokenTransferFeeConfig struct { + DestGasOverhead uint32 + DestBytesOverhead uint32 + DefaultBlockConfirmationFeeUSDCents uint32 + CustomBlockConfirmationFeeUSDCents uint32 + DefaultBlockConfirmationTransferFeeBps uint16 + CustomBlockConfirmationTransferFeeBps uint16 +} + // CustomBlockConfirmationRateLimiterConfig encapsulates rate limiter settings applied to // custom block confirmation transfers. type CustomBlockConfirmationRateLimiterConfig struct { @@ -68,6 +78,8 @@ type RemoteChainConfig[R any, CCV any] struct { // CustomBlockConfirmationConfig optionally overrides the rate limiter behaviour for // transfers that request a custom block confirmation depth. CustomBlockConfirmationConfig *CustomBlockConfirmationRateLimiterConfig + // TokenTransferFeeConfig optionally overrides token transfer fees for the remote chain. + TokenTransferFeeConfig *TokenTransferFeeConfig } // ConfigureTokenForTransfersInput is the input for the ConfigureTokenForTransfers sequence. diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 46edbf470..4922881d3 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -25,12 +25,12 @@ require ( github.com/ethereum/go-ethereum v1.16.2 github.com/gagliardetto/solana-go v1.13.0 github.com/smartcontractkit/chain-selectors v1.0.72 - github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251029160438-93e0a575186e + github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20251030175938-269363720b3b github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20251021182606-ee6ba95227d7 github.com/smartcontractkit/chainlink-ccip/chains/solana/deployment v0.0.0-20251021182606-ee6ba95227d7 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20251021182606-ee6ba95227d7 - github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20251029160438-93e0a575186e + github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20251030175938-269363720b3b github.com/smartcontractkit/chainlink-deployments-framework v0.56.0 github.com/stretchr/testify v1.11.1 )