Skip to content

Commit

Permalink
CCIP-4566 token pool views (#16116)
Browse files Browse the repository at this point in the history
* CCIP-4566 token pool views

* lint

* review fixes

* lint

* lint
  • Loading branch information
bukata-sa authored Jan 31, 2025
1 parent 49c6021 commit fe48a3a
Show file tree
Hide file tree
Showing 3 changed files with 280 additions and 6 deletions.
37 changes: 37 additions & 0 deletions deployment/ccip/changeset/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_0"
"github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_2"
"github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_5"
"github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_5_1"
"github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_6"
commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset"
commontypes "github.com/smartcontractkit/chainlink/deployment/common/types"
Expand Down Expand Up @@ -184,6 +185,42 @@ func (c CCIPChainState) GenerateView() (view.ChainView, error) {
}
chainView.TokenAdminRegistry[c.TokenAdminRegistry.Address().Hex()] = taView
}
for tokenSymbol, versionToPool := range c.BurnMintTokenPools {
for _, tokenPool := range versionToPool {
tokenPoolView, err := v1_5_1.GenerateTokenPoolView(tokenPool)
if err != nil {
return chainView, errors.Wrapf(err, "failed to generate burn mint token pool view for %s", tokenPool.Address().String())
}
chainView.BurnMintTokenPool = helpers.AddValueToNestedMap(chainView.BurnMintTokenPool, tokenPool.Address().Hex(), string(tokenSymbol), tokenPoolView)
}
}
for tokenSymbol, versionToPool := range c.BurnWithFromMintTokenPools {
for _, tokenPool := range versionToPool {
tokenPoolView, err := v1_5_1.GenerateTokenPoolView(tokenPool)
if err != nil {
return chainView, errors.Wrapf(err, "failed to generate burn mint token pool view for %s", tokenPool.Address().String())
}
chainView.BurnMintTokenPool = helpers.AddValueToNestedMap(chainView.BurnMintTokenPool, tokenPool.Address().Hex(), string(tokenSymbol), tokenPoolView)
}
}
for tokenSymbol, versionToPool := range c.BurnFromMintTokenPools {
for _, tokenPool := range versionToPool {
tokenPoolView, err := v1_5_1.GenerateTokenPoolView(tokenPool)
if err != nil {
return chainView, errors.Wrapf(err, "failed to generate burn mint token pool view for %s", tokenPool.Address().String())
}
chainView.BurnMintTokenPool = helpers.AddValueToNestedMap(chainView.BurnMintTokenPool, tokenPool.Address().Hex(), string(tokenSymbol), tokenPoolView)
}
}
for tokenSymbol, versionToPool := range c.LockReleaseTokenPools {
for _, tokenPool := range versionToPool {
tokenPoolView, err := v1_5_1.GenerateLockReleaseTokenPoolView(tokenPool)
if err != nil {
return chainView, errors.Wrapf(err, "failed to generate lock release token pool view for %s", tokenPool.Address().String())
}
chainView.LockReleaseTokenPool = helpers.AddValueToNestedMap(chainView.LockReleaseTokenPool, tokenPool.Address().Hex(), string(tokenSymbol), tokenPoolView)
}
}
if c.NonceManager != nil {
nmView, err := v1_6.GenerateNonceManagerView(c.NonceManager)
if err != nil {
Expand Down
233 changes: 233 additions & 0 deletions deployment/ccip/view/v1_5_1/token_pool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
package v1_5_1

import (
"fmt"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"golang.org/x/exp/maps"

"github.com/smartcontractkit/chainlink/deployment/common/view/types"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_from_mint_token_pool"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_mint_token_pool"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_with_from_mint_token_pool"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/lock_release_token_pool"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_pool"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool"
)

type TokenPoolContract interface {
Address() common.Address
Owner(opts *bind.CallOpts) (common.Address, error)
TypeAndVersion(*bind.CallOpts) (string, error)
GetToken(opts *bind.CallOpts) (common.Address, error)
GetSupportedChains(opts *bind.CallOpts) ([]uint64, error)
GetRemotePools(opts *bind.CallOpts, remoteChainSelector uint64) ([][]byte, error)
GetRemoteToken(opts *bind.CallOpts, remoteChainSelector uint64) ([]byte, error)
GetAllowList(opts *bind.CallOpts) ([]common.Address, error)
GetAllowListEnabled(opts *bind.CallOpts) (bool, error)
}

func GetCurrentInboundRateLimiterState(t TokenPoolContract, remoteChainSelector uint64) (token_pool.RateLimiterTokenBucket, error) {
switch v := t.(type) {
case *burn_mint_token_pool.BurnMintTokenPool:
state, err := v.GetCurrentInboundRateLimiterState(nil, remoteChainSelector)
return token_pool.RateLimiterTokenBucket(state), err
case *burn_from_mint_token_pool.BurnFromMintTokenPool:
state, err := v.GetCurrentInboundRateLimiterState(nil, remoteChainSelector)
return token_pool.RateLimiterTokenBucket(state), err
case *burn_with_from_mint_token_pool.BurnWithFromMintTokenPool:
state, err := v.GetCurrentInboundRateLimiterState(nil, remoteChainSelector)
return token_pool.RateLimiterTokenBucket(state), err
case *lock_release_token_pool.LockReleaseTokenPool:
state, err := v.GetCurrentInboundRateLimiterState(nil, remoteChainSelector)
return token_pool.RateLimiterTokenBucket(state), err
case *usdc_token_pool.USDCTokenPool:
state, err := v.GetCurrentInboundRateLimiterState(nil, remoteChainSelector)
return token_pool.RateLimiterTokenBucket(state), err
default:
return token_pool.RateLimiterTokenBucket{}, fmt.Errorf("unknown type %T", t)
}
}

func GetCurrentOutboundRateLimiterState(t TokenPoolContract, remoteChainSelector uint64) (token_pool.RateLimiterTokenBucket, error) {
switch v := t.(type) {
case *burn_mint_token_pool.BurnMintTokenPool:
state, err := v.GetCurrentOutboundRateLimiterState(nil, remoteChainSelector)
return token_pool.RateLimiterTokenBucket(state), err
case *burn_from_mint_token_pool.BurnFromMintTokenPool:
state, err := v.GetCurrentOutboundRateLimiterState(nil, remoteChainSelector)
return token_pool.RateLimiterTokenBucket(state), err
case *burn_with_from_mint_token_pool.BurnWithFromMintTokenPool:
state, err := v.GetCurrentOutboundRateLimiterState(nil, remoteChainSelector)
return token_pool.RateLimiterTokenBucket(state), err
case *lock_release_token_pool.LockReleaseTokenPool:
state, err := v.GetCurrentOutboundRateLimiterState(nil, remoteChainSelector)
return token_pool.RateLimiterTokenBucket(state), err
case *usdc_token_pool.USDCTokenPool:
state, err := v.GetCurrentOutboundRateLimiterState(nil, remoteChainSelector)
return token_pool.RateLimiterTokenBucket(state), err
default:
return token_pool.RateLimiterTokenBucket{}, fmt.Errorf("unknown type %T", t)
}
}

type RemoteChainConfig struct {
// RemoteTokenAddress is the raw representation of the token address on the remote chain.
RemoteTokenAddress []byte
// RemotePoolAddresses are raw addresses of valid token pools on the remote chain.
RemotePoolAddresses [][]byte
// InboundRateLimiterConfig is the rate limiter config for inbound transfers from the remote chain.
InboundRateLimterConfig token_pool.RateLimiterConfig
// OutboundRateLimiterConfig is the rate limiter config for outbound transfers to the remote chain.
OutboundRateLimiterConfig token_pool.RateLimiterConfig
}

type TokenPoolView struct {
types.ContractMetaData
Token common.Address `json:"token"`
RemoteChainConfigs map[uint64]RemoteChainConfig `json:"remoteChainConfigs"`
AllowList []common.Address `json:"allowList"`
AllowListEnabled bool `json:"allowListEnable"`
}

type USDCTokenPoolView struct {
TokenPoolView
TokenMessenger common.Address
MessageTransmitter common.Address
LocalDomain uint32
ChainToDomain map[uint64]usdc_token_pool.USDCTokenPoolDomain
}

type LockReleaseTokenPoolView struct {
TokenPoolView
AcceptLiquidity bool
Rebalancer common.Address
}

func GenerateTokenPoolView(pool TokenPoolContract) (TokenPoolView, error) {
owner, err := pool.Owner(nil)
if err != nil {
return TokenPoolView{}, err
}
typeAndVersion, err := pool.TypeAndVersion(nil)
if err != nil {
return TokenPoolView{}, err
}
token, err := pool.GetToken(nil)
if err != nil {
return TokenPoolView{}, err
}
allowList, err := pool.GetAllowList(nil)
if err != nil {
return TokenPoolView{}, err
}
allowListEnabled, err := pool.GetAllowListEnabled(nil)
if err != nil {
return TokenPoolView{}, err
}
remoteChains, err := pool.GetSupportedChains(nil)
if err != nil {
return TokenPoolView{}, err
}
remoteChainConfigs := make(map[uint64]RemoteChainConfig)
for _, remoteChain := range remoteChains {
remotePools, err := pool.GetRemotePools(nil, remoteChain)
if err != nil {
return TokenPoolView{}, err
}
remoteToken, err := pool.GetRemoteToken(nil, remoteChain)
if err != nil {
return TokenPoolView{}, err
}
inboundState, err := GetCurrentInboundRateLimiterState(pool, remoteChain)
if err != nil {
return TokenPoolView{}, err
}
outboundState, err := GetCurrentOutboundRateLimiterState(pool, remoteChain)
if err != nil {
return TokenPoolView{}, err
}
remoteChainConfigs[remoteChain] = RemoteChainConfig{
RemoteTokenAddress: remoteToken,
RemotePoolAddresses: remotePools,
InboundRateLimterConfig: token_pool.RateLimiterConfig{
IsEnabled: inboundState.IsEnabled,
Capacity: inboundState.Capacity,
Rate: inboundState.Rate,
},
OutboundRateLimiterConfig: token_pool.RateLimiterConfig{
IsEnabled: outboundState.IsEnabled,
Capacity: outboundState.Capacity,
Rate: outboundState.Rate,
},
}
}

return TokenPoolView{
ContractMetaData: types.ContractMetaData{
TypeAndVersion: typeAndVersion,
Address: pool.Address(),
Owner: owner,
},
Token: token,
RemoteChainConfigs: remoteChainConfigs,
AllowList: allowList,
AllowListEnabled: allowListEnabled,
}, nil
}

func GenerateLockReleaseTokenPoolView(pool *lock_release_token_pool.LockReleaseTokenPool) (LockReleaseTokenPoolView, error) {
basePoolView, err := GenerateTokenPoolView(pool)
if err != nil {
return LockReleaseTokenPoolView{}, err
}
acceptLiquidity, err := pool.CanAcceptLiquidity(nil)
if err != nil {
return LockReleaseTokenPoolView{}, err
}
rebalancer, err := pool.GetRebalancer(nil)
if err != nil {
return LockReleaseTokenPoolView{}, err
}
return LockReleaseTokenPoolView{
TokenPoolView: basePoolView,
AcceptLiquidity: acceptLiquidity,
Rebalancer: rebalancer,
}, nil
}

func GenerateUSDCTokenPoolView(pool *usdc_token_pool.USDCTokenPool) (USDCTokenPoolView, error) {
basePoolView, err := GenerateTokenPoolView(pool)
if err != nil {
return USDCTokenPoolView{}, err
}
tokenMessenger, err := pool.ITokenMessenger(nil)
if err != nil {
return USDCTokenPoolView{}, err
}
messageTransmitter, err := pool.IMessageTransmitter(nil)
if err != nil {
return USDCTokenPoolView{}, err
}
localDomain, err := pool.ILocalDomainIdentifier(nil)
if err != nil {
return USDCTokenPoolView{}, err
}
chainToDomain := make(map[uint64]usdc_token_pool.USDCTokenPoolDomain)
remoteChains := maps.Keys(basePoolView.RemoteChainConfigs)
for _, chainSel := range remoteChains {
domain, err := pool.GetDomain(nil, chainSel)
if err != nil {
return USDCTokenPoolView{}, err
}
chainToDomain[chainSel] = domain
}
return USDCTokenPoolView{
TokenPoolView: basePoolView,
TokenMessenger: tokenMessenger,
MessageTransmitter: messageTransmitter,
LocalDomain: localDomain,
ChainToDomain: chainToDomain,
}, nil
}
16 changes: 10 additions & 6 deletions deployment/ccip/view/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_0"
"github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_2"
"github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_5"
"github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_5_1"
"github.com/smartcontractkit/chainlink/deployment/ccip/view/v1_6"
"github.com/smartcontractkit/chainlink/deployment/common/view"
common_v1_0 "github.com/smartcontractkit/chainlink/deployment/common/view/v1_0"
Expand All @@ -17,12 +18,15 @@ type ChainView struct {
// v1.2
Router map[string]v1_2.RouterView `json:"router,omitempty"`
// v1.5
TokenAdminRegistry map[string]v1_5.TokenAdminRegistryView `json:"tokenAdminRegistry,omitempty"`
CommitStore map[string]v1_5.CommitStoreView `json:"commitStore,omitempty"`
PriceRegistry map[string]v1_2.PriceRegistryView `json:"priceRegistry,omitempty"`
EVM2EVMOnRamp map[string]v1_5.OnRampView `json:"evm2evmOnRamp,omitempty"`
EVM2EVMOffRamp map[string]v1_5.OffRampView `json:"evm2evmOffRamp,omitempty"`
RMN map[string]v1_5.RMNView `json:"rmn,omitempty"`
TokenAdminRegistry map[string]v1_5.TokenAdminRegistryView `json:"tokenAdminRegistry,omitempty"`
BurnMintTokenPool map[string]map[string]v1_5_1.TokenPoolView `json:"burnMintTokenPool,omitempty"`
LockReleaseTokenPool map[string]map[string]v1_5_1.LockReleaseTokenPoolView `json:"lockReleaseTokenPool,omitempty"`
USDCTokenPool map[string]map[string]v1_5_1.USDCTokenPoolView `json:"usdcTokenPool,omitempty"`
CommitStore map[string]v1_5.CommitStoreView `json:"commitStore,omitempty"`
PriceRegistry map[string]v1_2.PriceRegistryView `json:"priceRegistry,omitempty"`
EVM2EVMOnRamp map[string]v1_5.OnRampView `json:"evm2evmOnRamp,omitempty"`
EVM2EVMOffRamp map[string]v1_5.OffRampView `json:"evm2evmOffRamp,omitempty"`
RMN map[string]v1_5.RMNView `json:"rmn,omitempty"`

// v1.6
FeeQuoter map[string]v1_6.FeeQuoterView `json:"feeQuoter,omitempty"`
Expand Down

0 comments on commit fe48a3a

Please sign in to comment.