status-im/status-go

View on GitHub
multiaccounts/settings/sync_protobuf_factories.go

Summary

Maintainability
A
0 mins
Test Coverage
F
44%
package settings

import (
    "bytes"
    "encoding/json"
    "reflect"

    "github.com/golang/protobuf/proto"
    "github.com/pkg/errors"

    "github.com/status-im/status-go/protocol/common"
    "github.com/status-im/status-go/protocol/protobuf"
    "github.com/status-im/status-go/sqlite"
)

var (
    ErrTypeAssertionFailed = errors.New("type assertion of interface value failed")
)

func buildRawSyncSettingMessage(msg *protobuf.SyncSetting, chatID string) (*common.RawMessage, error) {
    encodedMessage, err := proto.Marshal(msg)
    if err != nil {
        return nil, err
    }

    return &common.RawMessage{
        LocalChatID: chatID,
        Payload:     encodedMessage,
        MessageType: protobuf.ApplicationMetadataMessage_SYNC_SETTING,
        ResendType:  common.ResendTypeDataSync,
    }, nil
}

// Currency

func buildRawCurrencySyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_CURRENCY,
        Value: &protobuf.SyncSetting_ValueString{ValueString: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func currencyProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertString(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawCurrencySyncMessage(v, clock, chatID)
}

func currencyProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawCurrencySyncMessage(s.Currency, clock, chatID)
}

// GifFavorites

func buildRawGifFavoritesSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_GIF_FAVOURITES,
        Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func gifFavouritesProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertBytes(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawGifFavoritesSyncMessage(v, clock, chatID)
}

func gifFavouritesProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    gf := extractJSONRawMessage(s.GifFavorites)
    return buildRawGifFavoritesSyncMessage(gf, clock, chatID)
}

// GifRecents

func buildRawGifRecentsSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_GIF_RECENTS,
        Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func gifRecentsProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertBytes(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawGifRecentsSyncMessage(v, clock, chatID)
}

func gifRecentsProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    gr := extractJSONRawMessage(s.GifRecents)
    return buildRawGifRecentsSyncMessage(gr, clock, chatID)
}

// MessagesFromContactsOnly

func buildRawMessagesFromContactsOnlySyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_MESSAGES_FROM_CONTACTS_ONLY,
        Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func messagesFromContactsOnlyProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertBool(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawMessagesFromContactsOnlySyncMessage(v, clock, chatID)
}

func messagesFromContactsOnlyProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawMessagesFromContactsOnlySyncMessage(s.MessagesFromContactsOnly, clock, chatID)
}

// PreferredName

func buildRawPreferredNameSyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_PREFERRED_NAME,
        Value: &protobuf.SyncSetting_ValueString{ValueString: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func preferredNameProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertString(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawPreferredNameSyncMessage(v, clock, chatID)
}

func preferredNameProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    var pn string
    if s.PreferredName != nil {
        pn = *s.PreferredName
    }

    return buildRawPreferredNameSyncMessage(pn, clock, chatID)
}

// PreviewPrivacy

func buildRawPreviewPrivacySyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_PREVIEW_PRIVACY,
        Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func previewPrivacyProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertBool(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawPreviewPrivacySyncMessage(v, clock, chatID)
}

func previewPrivacyProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawPreviewPrivacySyncMessage(s.PreviewPrivacy, clock, chatID)
}

// ProfilePicturesShowTo

func buildRawProfilePicturesShowToSyncMessage(v int64, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_PROFILE_PICTURES_SHOW_TO,
        Value: &protobuf.SyncSetting_ValueInt64{ValueInt64: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func profilePicturesShowToProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := parseNumberToInt64(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawProfilePicturesShowToSyncMessage(v, clock, chatID)
}

func profilePicturesShowToProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawProfilePicturesShowToSyncMessage(int64(s.ProfilePicturesShowTo), clock, chatID)
}

// ProfilePicturesVisibility

func buildRawProfilePicturesVisibilitySyncMessage(v int64, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_PROFILE_PICTURES_VISIBILITY,
        Value: &protobuf.SyncSetting_ValueInt64{ValueInt64: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func profilePicturesVisibilityProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := parseNumberToInt64(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawProfilePicturesVisibilitySyncMessage(v, clock, chatID)
}

func profilePicturesVisibilityProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawProfilePicturesVisibilitySyncMessage(int64(s.ProfilePicturesVisibility), clock, chatID)
}

// SendStatusUpdates

func buildRawSendStatusUpdatesSyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_SEND_STATUS_UPDATES,
        Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func sendStatusUpdatesProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertBool(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawSendStatusUpdatesSyncMessage(v, clock, chatID)
}

func sendStatusUpdatesProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawSendStatusUpdatesSyncMessage(s.SendStatusUpdates, clock, chatID)
}

// StickerPacksInstalled

func buildRawStickerPacksInstalledSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_STICKERS_PACKS_INSTALLED,
        Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func stickersPacksInstalledProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := parseJSONBlobData(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawStickerPacksInstalledSyncMessage(v, clock, chatID)
}

func stickersPacksInstalledProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    spi := extractJSONRawMessage(s.StickerPacksInstalled)
    return buildRawStickerPacksInstalledSyncMessage(spi, clock, chatID)
}

// StickerPacksPending

func buildRawStickerPacksPendingSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_STICKERS_PACKS_PENDING,
        Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func stickersPacksPendingProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := parseJSONBlobData(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawStickerPacksPendingSyncMessage(v, clock, chatID)
}

func stickersPacksPendingProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    spp := extractJSONRawMessage(s.StickerPacksPending)
    return buildRawStickerPacksPendingSyncMessage(spp, clock, chatID)
}

// StickersRecentStickers

func buildRawStickersRecentStickersSyncMessage(v []byte, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_STICKERS_RECENT_STICKERS,
        Value: &protobuf.SyncSetting_ValueBytes{ValueBytes: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func stickersRecentStickersProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := parseJSONBlobData(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawStickersRecentStickersSyncMessage(v, clock, chatID)
}

func stickersRecentStickersProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    srs := extractJSONRawMessage(s.StickersRecentStickers)
    return buildRawStickersRecentStickersSyncMessage(srs, clock, chatID)
}

// Helpers

func assertBytes(value interface{}) ([]byte, error) {
    v, ok := value.([]byte)
    if !ok {
        return nil, errors.Wrapf(ErrTypeAssertionFailed, "expected '[]byte', received %T", value)
    }
    return v, nil
}

func assertBool(value interface{}) (bool, error) {
    v, ok := value.(bool)
    if !ok {
        return false, errors.Wrapf(ErrTypeAssertionFailed, "expected 'bool', received %T", value)
    }
    return v, nil
}

func assertString(value interface{}) (string, error) {
    rv := reflect.ValueOf(value)
    if rv.Kind() == reflect.Ptr {
        value = *value.(*string)
    }
    v, ok := value.(string)
    if !ok {
        return "", errors.Wrapf(ErrTypeAssertionFailed, "expected 'string', received %T", value)
    }
    return v, nil
}

func parseJSONBlobData(value interface{}) ([]byte, error) {
    switch v := value.(type) {
    case []byte:
        return v, nil
    case *sqlite.JSONBlob:
        return extractJSONBlob(v)
    default:
        return nil, errors.Wrapf(ErrTypeAssertionFailed, "expected []byte or *sqlite.JSONBlob, received %T", value)
    }
}

func parseNumberToInt64(value interface{}) (int64, error) {
    switch v := value.(type) {
    case float32:
        return int64(v), nil
    case float64:
        return int64(v), nil
    case int:
        return int64(v), nil
    case int8:
        return int64(v), nil
    case int16:
        return int64(v), nil
    case int32:
        return int64(v), nil
    case int64:
        return v, nil
    case uint:
        return int64(v), nil
    case uint8:
        return int64(v), nil
    case uint16:
        return int64(v), nil
    case uint32:
        return int64(v), nil
    case uint64:
        return int64(v), nil
    case ProfilePicturesShowToType:
        return int64(v), nil
    case ProfilePicturesVisibilityType:
        return int64(v), nil
    case URLUnfurlingModeType:
        return int64(v), nil
    default:
        return 0, errors.Wrapf(ErrTypeAssertionFailed, "expected a numeric type, received %T", value)
    }
}

func extractJSONBlob(jb *sqlite.JSONBlob) ([]byte, error) {
    value, err := jb.Value()
    if err != nil {
        return nil, err
    }

    if value == nil {
        return nil, nil
    }

    return value.([]byte), nil
}

func extractJSONRawMessage(jrm *json.RawMessage) []byte {
    if jrm == nil {
        return nil
    }
    out, _ := jrm.MarshalJSON() // Don't need to parse error because it is always nil
    if len(out) == 0 || bytes.Equal(out, []byte("null")) {
        return nil
    }
    return out
}

// DisplayName

func buildRawDisplayNameSyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_DISPLAY_NAME,
        Value: &protobuf.SyncSetting_ValueString{ValueString: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func displayNameProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertString(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawDisplayNameSyncMessage(v, clock, chatID)
}

func displayNameProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {

    return buildRawDisplayNameSyncMessage(s.DisplayName, clock, chatID)
}

// Bio

func buildRawBioSyncMessage(v string, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_BIO,
        Value: &protobuf.SyncSetting_ValueString{ValueString: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func bioProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertString(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawBioSyncMessage(v, clock, chatID)
}

func bioProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawBioSyncMessage(s.Bio, clock, chatID)
}

// MnemonicRemoved

func buildRawMnemonicRemovedSyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_MNEMONIC_REMOVED,
        Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func mnemonicRemovedProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertBool(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawMnemonicRemovedSyncMessage(v, clock, chatID)
}

func mnemonicRemovedProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawMnemonicRemovedSyncMessage(s.MnemonicRemoved, clock, chatID)
}

// UrlUnfurlingMode

func buildRawURLUnfurlingModeSyncMessage(v int64, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_URL_UNFURLING_MODE,
        Value: &protobuf.SyncSetting_ValueInt64{ValueInt64: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func urlUnfurlingModeProtobufFactory(value any, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := parseNumberToInt64(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawURLUnfurlingModeSyncMessage(v, clock, chatID)
}

func urlUnfurlingModeProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawURLUnfurlingModeSyncMessage(int64(s.URLUnfurlingMode), clock, chatID)
}

// ShowCommunityAssetWhenSendingTokens

func buildRawShowCommunityAssetWhenSendingTokensSyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_SHOW_COMMUNITY_ASSET_WHEN_SENDING_TOKENS,
        Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func showCommunityAssetWhenSendingTokensProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertBool(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawShowCommunityAssetWhenSendingTokensSyncMessage(v, clock, chatID)
}

func showCommunityAssetWhenSendingTokensProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawShowCommunityAssetWhenSendingTokensSyncMessage(s.ShowCommunityAssetWhenSendingTokens, clock, chatID)
}

// DisplayAssetsBelowBalance

func buildRawDisplayAssetsBelowBalanceSyncMessage(v bool, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_DISPLAY_ASSETS_BELOW_BALANCE,
        Value: &protobuf.SyncSetting_ValueBool{ValueBool: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func displayAssetsBelowBalanceProtobufFactory(value interface{}, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := assertBool(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawDisplayAssetsBelowBalanceSyncMessage(v, clock, chatID)
}

func displayAssetsBelowBalanceProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawDisplayAssetsBelowBalanceSyncMessage(s.DisplayAssetsBelowBalance, clock, chatID)
}

// DisplayAssetsBelowBalanceThreshold

func buildRawDisplayAssetsBelowBalanceThresholdSyncMessage(v int64, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    pb := &protobuf.SyncSetting{
        Type:  protobuf.SyncSetting_DISPLAY_ASSETS_BELOW_BALANCE_THRESHOLD,
        Value: &protobuf.SyncSetting_ValueInt64{ValueInt64: v},
        Clock: clock,
    }
    rm, err := buildRawSyncSettingMessage(pb, chatID)
    return rm, pb, err
}

func displayAssetsBelowBalanceThresholdProtobufFactory(value any, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    v, err := parseNumberToInt64(value)
    if err != nil {
        return nil, nil, err
    }

    return buildRawDisplayAssetsBelowBalanceThresholdSyncMessage(v, clock, chatID)
}

func displayAssetsBelowBalanceThresholdProtobufFactoryStruct(s Settings, clock uint64, chatID string) (*common.RawMessage, *protobuf.SyncSetting, error) {
    return buildRawDisplayAssetsBelowBalanceThresholdSyncMessage(s.DisplayAssetsBelowBalanceThreshold, clock, chatID)
}