func (c *CrawlerConfig) FetchMultiSigAddresses() error {
	if c.CivilListingsGraphqlURL == "" {
		return nil
	}
	var addressStrings []string
	var addressObjs []common.Address
	multiSigContractName := "multisigwallet"
	if c.ContractAddresses[multiSigContractName] != "" {
		addressStrings = strings.Split(c.ContractAddresses[multiSigContractName], "|")
	}
	client := graphql.NewClient(c.CivilListingsGraphqlURL, nil)
	q := allMultiSigAddressesQuery
	err := client.Query(context.Background(), &q, nil)
	if err != nil {
		return err
	}
	addrs := q.AllMultiSigAddresses
	for _, addr := range addrs {
		addressStrings = append(addressStrings, string(addr))
		addressObjs = append(addressObjs, common.HexToAddress(string(addr)))
	}
	c.ContractAddresses[multiSigContractName] = strings.Join(addressStrings, "|")
	c.ContractAddressObjs[multiSigContractName] = append(
		c.ContractAddressObjs[multiSigContractName], addressObjs...)
	return nil
}
FetchMultiSigAddresses retrieves the list of Civil multi sig addresses if given
the endpoint URL
package utils
import (
	"context"
	"errors"
	"fmt"
	"strings"
	log "github.com/golang/glog"
	cconfig "github.com/joincivil/go-common/pkg/config"
	cstrings "github.com/joincivil/go-common/pkg/strings"
	"github.com/ethereum/go-ethereum/common"
	"github.com/kelseyhightower/envconfig"
	"github.com/shurcooL/graphql"
)
const (
	envVarPrefix = "crawl"
)
type CrawlerConfig struct {
	EthAPIURL     string `envconfig:"eth_api_url" required:"true" desc:"Ethereum HTTP API address"`
	EthWsAPIURL   string `envconfig:"eth_ws_api_url" desc:"Ethereum Websocket API address (optional, disables watchers if empty)"`
	EthStartBlock uint64 `envconfig:"eth_start_block" desc:"Sets the start Eth block (default 0)" default:"0"`
	PollingEnabled      bool `envconfig:"polling_enabled" desc:"Enable polling only mode (true disables listeners)"`
	PollingIntervalSecs int  `envconfig:"polling_int_secs" desc:"Sets the polling interval"`
	CivilListingsGraphqlURL string `envconfig:"civil_listing_graphql_url" desc:"URL of the Civil Listings GraphQL endpoint"`
	ContractAddresses   map[string]string           `split_words:"true" required:"true" desc:"<contract name>:<contract addr>. Delimit contract address with '|' for multiple addresses"`
	ContractAddressObjs map[string][]common.Address `ignored:"true"`
	PersisterType             cconfig.PersisterType `ignored:"true"`
	PersisterTypeName         string                `split_words:"true" required:"true" desc:"Sets the persister type to use"`
	PersisterPostgresAddress  string                `split_words:"true" desc:"If persister type is Postgresql, sets the address"`
	PersisterPostgresPort     int                   `split_words:"true" desc:"If persister type is Postgresql, sets the port"`
	PersisterPostgresDbname   string                `split_words:"true" desc:"If persister type is Postgresql, sets the database name"`
	PersisterPostgresUser     string                `split_words:"true" desc:"If persister type is Postgresql, sets the database user"`
	PersisterPostgresPw       string                `split_words:"true" desc:"If persister type is Postgresql, sets the database password"`
	PersisterPostgresMaxConns *int                  `split_words:"true" desc:"If persister type is Postgresql, sets the max conns in pool"`
	PersisterPostgresMaxIdle  *int                  `split_words:"true" desc:"If persister type is Postgresql, sets the max idle conns in pool"`
	PersisterPostgresConnLife *int                  `split_words:"true" desc:"If persister type is Postgresql, sets the max conn lifetime in secs"`
	PubSubProjectID string `split_words:"true" desc:"Sets the Google Cloud PubSub Project ID"`
	PubSubTopicName string `split_words:"true" desc:"Sets the Google Cloud PubSub Topic name"`
	VersionNumber string `split_words:"true" desc:"Sets the version for table"`
	StackdriverProjectID      string `split_words:"true" desc:"Sets the Stackdriver Google Cloud project ID. If empty, will disable logging"`
	StackdriverServiceName    string `split_words:"true" desc:"Sets the Stackdriver service name"`
	StackdriverServiceVersion string `split_words:"true" desc:"Sets the Stackdriver service version"`
	SentryDsn        string `split_words:"true" desc:"Sets the Sentry DSN"`
	SentryEnv        string `split_words:"true" desc:"Sets the Sentry environment"`
	SentryLoggerName string `split_words:"true" desc:"Sets the Sentry logger name"`
	SentryRelease    string `split_words:"true" desc:"Sets the Sentry release value"`
	PprofEnable                bool   `split_words:"true" desc:"Enables the local pprof endpoints for debugging and profiling"`
	CloudProfileProjectID      string `split_words:"true" desc:"Sets the cloud profiler Google Cloud project ID. If empty, will disable cloud profiler agent"`
	CloudProfileServiceName    string `split_words:"true" desc:"Sets the service name to with in the Google Cloud profiler"`
	CloudProfileServiceVersion string `split_words:"true" desc:"Sets the Google Cloud profiler service version"`
	PreemptSecs *int `split_words:"true" desc:"Sets the secs delay before listener prempt restart. 0 if no preempt"`
}
type Edge struct {
	Node struct {
		Name            graphql.String
		ContractAddress graphql.String
		Whitelisted     graphql.Boolean
		ApprovalDate    graphql.Int
		LastGovState    graphql.String
	}
}
type PageInfo struct {
	EndCursor   graphql.String
	HasNextPage graphql.Boolean
}
var allListingAddressesQuery struct {
	AllListingAddresses []graphql.String `graphql:"allListingAddresses"`
}
var allMultiSigAddressesQuery struct {
	AllMultiSigAddresses []graphql.String `graphql:"allMultiSigAddresses"`
}
func (c *CrawlerConfig) FetchListingAddresses() error {
	if c.CivilListingsGraphqlURL == "" {
		return nil
	}
	var addressStrings []string
	var addressObjs []common.Address
	newsroomContractName := "newsroom"
	if c.ContractAddresses[newsroomContractName] != "" {
		addressStrings = strings.Split(c.ContractAddresses[newsroomContractName], "|")
	}
	client := graphql.NewClient(c.CivilListingsGraphqlURL, nil)
	q := allListingAddressesQuery
	err := client.Query(context.Background(), &q, nil)
	if err != nil {
		return err
	}
	addrs := q.AllListingAddresses
	for _, addr := range addrs {
		addressStrings = append(addressStrings, string(addr))
		addressObjs = append(addressObjs, common.HexToAddress(string(addr)))
	}
	c.ContractAddresses[newsroomContractName] = strings.Join(addressStrings, "|")
	c.ContractAddressObjs[newsroomContractName] = append(
		c.ContractAddressObjs[newsroomContractName], addressObjs...)
	return nil
}