package arbitrum import ( "context" "fmt" "strings" "time" "github.com/ethereum/go-ethereum/ethclient" "golang.org/x/time/rate" ) // RateLimitedRPC wraps an ethclient.Client with rate limiting type RateLimitedRPC struct { client *ethclient.Client limiter *rate.Limiter retryCount int } // NewRateLimitedRPC creates a new rate limited RPC client func NewRateLimitedRPC(client *ethclient.Client, requestsPerSecond float64, retryCount int) *RateLimitedRPC { // Create a rate limiter that allows requestsPerSecond requests per second // with a burst equal to 2x requests per second limiter := rate.NewLimiter(rate.Limit(requestsPerSecond), int(requestsPerSecond*2)) return &RateLimitedRPC{ client: client, limiter: limiter, retryCount: retryCount, } } // CallWithRetry calls an RPC method with rate limiting and retry logic func (r *RateLimitedRPC) CallWithRetry(ctx context.Context, method string, args ...interface{}) (interface{}, error) { for i := 0; i < r.retryCount; i++ { // Wait for rate limiter allowance if err := r.limiter.Wait(ctx); err != nil { return nil, fmt.Errorf("rate limiter error: %w", err) } // Execute the call result, err := r.executeCall(ctx, method, args...) if err == nil { return result, nil } // Check if this is a rate limit error that warrants retrying if isRateLimitError(err) { // Apply exponential backoff before retrying backoffTime := time.Duration(1<