diff --git a/cmd/process.go b/cmd/process.go index 356e40f..3ac6773 100644 --- a/cmd/process.go +++ b/cmd/process.go @@ -7,8 +7,12 @@ import ( "time" "cosmossdk.io/log" + "cosmossdk.io/math" + cctptypes "github.com/circlefin/noble-cctp/x/cctp/types" "github.com/spf13/cobra" "github.com/strangelove-ventures/noble-cctp-relayer/circle" + "github.com/strangelove-ventures/noble-cctp-relayer/ethereum" + "github.com/strangelove-ventures/noble-cctp-relayer/noble" "github.com/strangelove-ventures/noble-cctp-relayer/types" ) @@ -91,7 +95,8 @@ func StartProcessor( // if a filter's condition is met, mark as filtered if FilterDisabledCCTPRoutes(cfg, logger, msg) || - filterInvalidDestinationCallers(registeredDomains, logger, msg) { + filterInvalidDestinationCallers(registeredDomains, logger, msg) || + filterLowTransfers(cfg, logger, msg) { msg.Status = types.Filtered } @@ -184,6 +189,51 @@ func filterInvalidDestinationCallers(registeredDomains map[types.Domain]types.Ch return !chain.IsDestinationCaller(msg.DestinationCaller) } +// filterLowTransfers returns true if the amount being transfered to the destination chain is lower than the min-mint-amount configured +func filterLowTransfers(cfg *types.Config, logger log.Logger, msg *types.MessageState) bool { + bm, err := new(cctptypes.BurnMessage).Parse(msg.MsgBody) + if err != nil { + logger.Info("This is not a burn message", "err", err) + return true + } + + // TODO: not assume that "noble" is domain 4, add "domain" to the noble chain conifg + var minBurnAmount uint64 + if msg.DestDomain == types.Domain(4) { + nobleCfg, ok := cfg.Chains["noble"].(*noble.ChainConfig) + if !ok { + logger.Info("chain named 'noble' not found in config, filtering transaction") + return true + } + minBurnAmount = nobleCfg.MinMintAmount + } else { + for _, chain := range cfg.Chains { + c, ok := chain.(*ethereum.ChainConfig) + if !ok { + // noble chain, handled above + continue + } + if c.Domain == msg.DestDomain { + minBurnAmount = c.MinMintAmount + } + } + } + + if bm.Amount.LT(math.NewIntFromUint64(minBurnAmount)) { + logger.Info( + "Filtered tx because the transfer amount is less than the minimum allowed amount", + "dest domain", msg.DestDomain, + "source_domain", msg.SourceDomain, + "source_tx", msg.SourceTxHash, + "amount", bm.Amount, + "min_amount", minBurnAmount, + ) + return true + } + + return false +} + func LookupKey(sourceTxHash string) string { // return fmt.Sprintf("%s-%s", sourceTxHash, messageType) return sourceTxHash diff --git a/config/sample-config.yaml b/config/sample-config.yaml index 9281769..cb25332 100644 --- a/config/sample-config.yaml +++ b/config/sample-config.yaml @@ -14,13 +14,15 @@ chains: block-queue-channel-size: 1000000 # 1000000 is a safe default, increase number if starting from a very early block + min-mint-amount: 0 + minter-private-key: # hex encoded privateKey ethereum: chain-id: 5 domain: 0 - rpc: - ws: # websocket + rpc: # Ethereum RPC + ws: # Ethereum Websocket message-transmitter: "0x26413e8157CD32011E726065a5462e97dD4d03D9" start-block: 0 # set to 0 to default to latest block @@ -29,6 +31,8 @@ chains: broadcast-retries: 5 # number of times to attempt the broadcast broadcast-retry-interval: 10 # time between retries in seconds + min-mint-amount: 10000000 + minter-private-key: # private key optimism: @@ -44,6 +48,8 @@ chains: broadcast-retries: 5 # number of times to attempt the broadcast broadcast-retry-interval: 10 # time between retries in seconds + min-mint-amount: 10000000 + minter-private-key: "" arbitrum: @@ -59,6 +65,8 @@ chains: broadcast-retries: 5 # number of times to attempt the broadcast broadcast-retry-interval: 10 # time between retries in seconds + min-mint-amount: 10000000 + minter-private-key: "" avalanche: @@ -74,6 +82,8 @@ chains: broadcast-retries: 5 # number of times to attempt the broadcast broadcast-retry-interval: 10 # time between retries in seconds + min-mint-amount: 10000000 + minter-private-key: "" # source domain id -> []destination domain id diff --git a/ethereum/chain.go b/ethereum/chain.go index 3a55f92..10414c8 100644 --- a/ethereum/chain.go +++ b/ethereum/chain.go @@ -29,6 +29,7 @@ type Ethereum struct { minterAddress string maxRetries int retryIntervalSeconds int + minAmount uint64 mu sync.Mutex } @@ -45,6 +46,7 @@ func NewChain( privateKey string, maxRetries int, retryIntervalSeconds int, + minAmount uint64, ) (*Ethereum, error) { privEcdsaKey, ethereumAddress, err := GetEcdsaKeyAddress(privateKey) if err != nil { @@ -63,6 +65,7 @@ func NewChain( minterAddress: ethereumAddress, maxRetries: maxRetries, retryIntervalSeconds: retryIntervalSeconds, + minAmount: minAmount, }, nil } diff --git a/ethereum/config.go b/ethereum/config.go index f1a810f..9df3809 100644 --- a/ethereum/config.go +++ b/ethereum/config.go @@ -19,6 +19,8 @@ type ChainConfig struct { BroadcastRetries int `yaml:"broadcast-retries"` BroadcastRetryInterval int `yaml:"broadcast-retry-interval"` + MinMintAmount uint64 `yaml:"min-mint-amount"` + // TODO move to keyring MinterPrivateKey string `yaml:"minter-private-key"` } @@ -36,5 +38,6 @@ func (c *ChainConfig) Chain(name string) (types.Chain, error) { c.MinterPrivateKey, c.BroadcastRetries, c.BroadcastRetryInterval, + c.MinMintAmount, ) } diff --git a/noble/chain.go b/noble/chain.go index e1c20d9..c7e4515 100644 --- a/noble/chain.go +++ b/noble/chain.go @@ -35,6 +35,7 @@ type Noble struct { maxRetries int retryIntervalSeconds int blockQueueChannelSize uint64 + minAmount uint64 mu sync.Mutex } @@ -51,6 +52,7 @@ func NewChain( maxRetries int, retryIntervalSeconds int, blockQueueChannelSize uint64, + minAmount uint64, ) (*Noble, error) { cc, err := cosmos.NewProvider(rpcURL) if err != nil { @@ -80,6 +82,7 @@ func NewChain( maxRetries: maxRetries, retryIntervalSeconds: retryIntervalSeconds, blockQueueChannelSize: blockQueueChannelSize, + minAmount: minAmount, }, nil } diff --git a/noble/config.go b/noble/config.go index bcad409..d7634b7 100644 --- a/noble/config.go +++ b/noble/config.go @@ -21,6 +21,8 @@ type ChainConfig struct { BlockQueueChannelSize uint64 `yaml:"block-queue-channel-size"` + MinMintAmount uint64 `yaml:"min-mint-amount"` + // TODO move to keyring MinterPrivateKey string `yaml:"minter-private-key"` } @@ -38,5 +40,6 @@ func (c *ChainConfig) Chain(name string) (types.Chain, error) { c.BroadcastRetries, c.BroadcastRetryInterval, c.BlockQueueChannelSize, + c.MinMintAmount, ) } diff --git a/noble/message_state.go b/noble/message_state.go index 8866c6a..5392834 100644 --- a/noble/message_state.go +++ b/noble/message_state.go @@ -66,6 +66,7 @@ func txToMessageState(tx *ctypes.ResultTx) ([]*types.MessageState, error) { Nonce: msg.Nonce, SourceTxHash: tx.Hash.String(), MsgSentBytes: rawMessageSentBytes, + MsgBody: msg.MessageBody, DestinationCaller: msg.DestinationCaller, Created: now, Updated: now, diff --git a/types/message_state.go b/types/message_state.go index c1535d0..c7e455b 100644 --- a/types/message_state.go +++ b/types/message_state.go @@ -41,6 +41,7 @@ type MessageState struct { SourceTxHash string DestTxHash string MsgSentBytes []byte // bytes of the MessageSent message transmitter event + MsgBody []byte // bytes of the MessageBody DestinationCaller []byte // address authorized to call transaction Channel string // "channel-%d" if a forward, empty if not a forward Created time.Time @@ -68,6 +69,7 @@ func EvmLogToMessageState(abi abi.ABI, messageSent abi.Event, log *ethtypes.Log) DestDomain: Domain(message.DestinationDomain), SourceTxHash: log.TxHash.Hex(), MsgSentBytes: rawMessageSentBytes, + MsgBody: message.MessageBody, DestinationCaller: message.DestinationCaller, Nonce: message.Nonce, Created: time.Now(),