change transformer interface and watcher so that contract config is now fed into AddTransformers such that a single watcher can be loaded with transformers that use different cofigs
This commit is contained in:
parent
44177e0772
commit
57820ff473
20
cmd/erc20.go
20
cmd/erc20.go
@ -22,7 +22,10 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/examples/constants"
|
||||||
|
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered/dai"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
|
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
|
||||||
|
"github.com/vulcanize/vulcanizedb/examples/generic"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
||||||
@ -35,7 +38,8 @@ import (
|
|||||||
var erc20Cmd = &cobra.Command{
|
var erc20Cmd = &cobra.Command{
|
||||||
Use: "erc20",
|
Use: "erc20",
|
||||||
Short: "Fetches and persists token supply",
|
Short: "Fetches and persists token supply",
|
||||||
Long: `Fetches the totalSupply for the configured token from each block and persists it in Vulcanize DB.
|
Long: `Fetches transfer and approval events, totalSupply, allowances, and
|
||||||
|
balances for the configured token from each block and persists it in Vulcanize DB.
|
||||||
vulcanizedb erc20 --config environments/public
|
vulcanizedb erc20 --config environments/public
|
||||||
|
|
||||||
Expects an ethereum node to be running and requires a .toml config file:
|
Expects an ethereum node to be running and requires a .toml config file:
|
||||||
@ -70,12 +74,24 @@ func watchERC20s() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to initialize database.")
|
log.Fatal("Failed to initialize database.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
con := generic.DaiConfig
|
||||||
|
con.Filters = constants.DaiERC20Filters
|
||||||
watcher := shared.Watcher{
|
watcher := shared.Watcher{
|
||||||
DB: *db,
|
DB: *db,
|
||||||
Blockchain: blockChain,
|
Blockchain: blockChain,
|
||||||
}
|
}
|
||||||
|
|
||||||
watcher.AddTransformers(every_block.TransformerInitializers())
|
// It is important that the event transformer is executed before the every_block transformer
|
||||||
|
// because the events are used to generate the token holder address list that is used to
|
||||||
|
// collect balances and allowances at every block
|
||||||
|
transformers := append(dai.DaiEventTriggeredTransformerInitializer(), every_block.ERC20EveryBlockTransformerInitializer()...)
|
||||||
|
|
||||||
|
err = watcher.AddTransformers(transformers, con)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
watcher.Execute()
|
watcher.Execute()
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@ import (
|
|||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/constants"
|
"github.com/vulcanize/vulcanizedb/examples/constants"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered"
|
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic"
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic/helpers"
|
"github.com/vulcanize/vulcanizedb/examples/generic/helpers"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
||||||
)
|
)
|
||||||
@ -37,10 +37,10 @@ type ERC20ConverterInterface interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ERC20Converter struct {
|
type ERC20Converter struct {
|
||||||
config generic.ContractConfig
|
config shared.ContractConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewERC20Converter(config generic.ContractConfig) (*ERC20Converter, error) {
|
func NewERC20Converter(config shared.ContractConfig) (*ERC20Converter, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
config.ParsedAbi, err = geth.ParseAbi(config.Abi)
|
config.ParsedAbi, err = geth.ParseAbi(config.Abi)
|
||||||
|
@ -71,6 +71,7 @@ var logs = []core.Log{
|
|||||||
|
|
||||||
var _ = Describe("Integration test with vulcanizedb", func() {
|
var _ = Describe("Integration test with vulcanizedb", func() {
|
||||||
var db *postgres.DB
|
var db *postgres.DB
|
||||||
|
var blk core.BlockChain
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
db = test_helpers.SetupIntegrationDB(db, logs)
|
db = test_helpers.SetupIntegrationDB(db, logs)
|
||||||
@ -81,7 +82,7 @@ var _ = Describe("Integration test with vulcanizedb", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("creates token_transfers entry for each Transfer event received", func() {
|
It("creates token_transfers entry for each Transfer event received", func() {
|
||||||
transformer, err := dai.NewTransformer(db, generic.DaiConfig)
|
transformer, err := dai.NewTransformer(db, blk, generic.DaiConfig)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
transformer.Execute()
|
transformer.Execute()
|
||||||
@ -107,7 +108,7 @@ var _ = Describe("Integration test with vulcanizedb", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("creates token_approvals entry for each Approval event received", func() {
|
It("creates token_approvals entry for each Approval event received", func() {
|
||||||
transformer, err := dai.NewTransformer(db, generic.DaiConfig)
|
transformer, err := dai.NewTransformer(db, blk, generic.DaiConfig)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
transformer.Execute()
|
transformer.Execute()
|
||||||
|
@ -20,11 +20,12 @@ import (
|
|||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/constants"
|
"github.com/vulcanize/vulcanizedb/examples/constants"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered"
|
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/event_triggered"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic"
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/filters"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ERC20EventTransformer struct {
|
type ERC20EventTransformer struct {
|
||||||
@ -32,34 +33,38 @@ type ERC20EventTransformer struct {
|
|||||||
WatchedEventRepository datastore.WatchedEventRepository
|
WatchedEventRepository datastore.WatchedEventRepository
|
||||||
FilterRepository datastore.FilterRepository
|
FilterRepository datastore.FilterRepository
|
||||||
Repository event_triggered.ERC20EventDatastore
|
Repository event_triggered.ERC20EventDatastore
|
||||||
|
Filters []filters.LogFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransformer(db *postgres.DB, config generic.ContractConfig) (shared.Transformer, error) {
|
func NewTransformer(db *postgres.DB, blockchain core.BlockChain, con shared.ContractConfig) (shared.Transformer, error) {
|
||||||
var transformer shared.Transformer
|
var transformer shared.Transformer
|
||||||
|
|
||||||
cnvtr, err := NewERC20Converter(config)
|
cnvtr, err := NewERC20Converter(con)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return transformer, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
wer := repositories.WatchedEventRepository{DB: db}
|
wer := repositories.WatchedEventRepository{DB: db}
|
||||||
fr := repositories.FilterRepository{DB: db}
|
fr := repositories.FilterRepository{DB: db}
|
||||||
lkr := event_triggered.ERC20EventRepository{DB: db}
|
lkr := event_triggered.ERC20EventRepository{DB: db}
|
||||||
|
|
||||||
transformer = ERC20EventTransformer{
|
transformer = ERC20EventTransformer{
|
||||||
Converter: cnvtr,
|
Converter: cnvtr,
|
||||||
WatchedEventRepository: wer,
|
WatchedEventRepository: wer,
|
||||||
FilterRepository: fr,
|
FilterRepository: fr,
|
||||||
Repository: lkr,
|
Repository: lkr,
|
||||||
|
Filters: con.Filters,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, filter := range constants.DaiERC20Filters {
|
for _, filter := range con.Filters {
|
||||||
fr.CreateFilter(filter)
|
fr.CreateFilter(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transformer, nil
|
return transformer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr ERC20EventTransformer) Execute() error {
|
func (tr ERC20EventTransformer) Execute() error {
|
||||||
for _, filter := range constants.DaiERC20Filters {
|
for _, filter := range tr.Filters {
|
||||||
watchedEvents, err := tr.WatchedEventRepository.GetWatchedEvents(filter.Name)
|
watchedEvents, err := tr.WatchedEventRepository.GetWatchedEvents(filter.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(fmt.Sprintf("Error fetching events for %s:", filter.Name), err)
|
log.Println(fmt.Sprintf("Error fetching events for %s:", filter.Name), err)
|
||||||
@ -84,5 +89,6 @@ func (tr ERC20EventTransformer) Execute() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -71,12 +71,14 @@ var _ = Describe("Mock ERC20 transformer", func() {
|
|||||||
watchedEventsRepo.SetWatchedEvents(fakeWatchedEvents)
|
watchedEventsRepo.SetWatchedEvents(fakeWatchedEvents)
|
||||||
mockEventRepo = mocks.MockEventRepo{}
|
mockEventRepo = mocks.MockEventRepo{}
|
||||||
filterRepo = mocks.MockFilterRepository{}
|
filterRepo = mocks.MockFilterRepository{}
|
||||||
|
filters := constants.DaiERC20Filters
|
||||||
|
|
||||||
transformer = dai.ERC20EventTransformer{
|
transformer = dai.ERC20EventTransformer{
|
||||||
Converter: &mockERC20Converter,
|
Converter: &mockERC20Converter,
|
||||||
WatchedEventRepository: &watchedEventsRepo,
|
WatchedEventRepository: &watchedEventsRepo,
|
||||||
FilterRepository: filterRepo,
|
FilterRepository: filterRepo,
|
||||||
Repository: &mockEventRepo,
|
Repository: &mockEventRepo,
|
||||||
|
Filters: filters,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
25
examples/erc20_watcher/event_triggered/dai/transformers.go
Normal file
25
examples/erc20_watcher/event_triggered/dai/transformers.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2018 Vulcanize
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package dai
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DaiEventTriggeredTransformerInitializer() []shared.TransformerInitializer {
|
||||||
|
return []shared.TransformerInitializer{
|
||||||
|
NewTransformer,
|
||||||
|
}
|
||||||
|
}
|
@ -61,12 +61,12 @@ var _ = Describe("Everyblock transformers", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("creates a token_supply record for each block in the given range", func() {
|
It("creates a token_supply record for each block in the given range", func() {
|
||||||
initializer := every_block.ERC20TokenTransformerInitializer{Config: generic.DaiConfig}
|
transformer, err := every_block.NewERC20TokenTransformer(db, blockChain, generic.DaiConfig)
|
||||||
transformer := initializer.NewERC20TokenTransformer(db, blockChain)
|
Expect(err).ToNot(HaveOccurred())
|
||||||
transformer.Execute()
|
transformer.Execute()
|
||||||
|
|
||||||
var tokenSupplyCount int
|
var tokenSupplyCount int
|
||||||
err := db.QueryRow(`SELECT COUNT(*) FROM token_supply where block_id = $1`, blockId).Scan(&tokenSupplyCount)
|
err = db.QueryRow(`SELECT COUNT(*) FROM token_supply where block_id = $1`, blockId).Scan(&tokenSupplyCount)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(tokenSupplyCount).To(Equal(1))
|
Expect(tokenSupplyCount).To(Equal(1))
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic"
|
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
@ -30,30 +30,27 @@ import (
|
|||||||
type ERC20Transformer struct {
|
type ERC20Transformer struct {
|
||||||
Getter ERC20GetterInterface
|
Getter ERC20GetterInterface
|
||||||
Repository ERC20TokenDatastore
|
Repository ERC20TokenDatastore
|
||||||
Retriever generic.TokenHolderRetriever
|
Retriever erc20_watcher.TokenHolderRetriever
|
||||||
Config generic.ContractConfig
|
Config shared.ContractConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ERC20Transformer) SetConfiguration(config generic.ContractConfig) {
|
func (t *ERC20Transformer) SetConfiguration(config shared.ContractConfig) {
|
||||||
t.Config = config
|
t.Config = config
|
||||||
}
|
}
|
||||||
|
|
||||||
type ERC20TokenTransformerInitializer struct {
|
func NewERC20TokenTransformer(db *postgres.DB, blockchain core.BlockChain, con shared.ContractConfig) (shared.Transformer, error) {
|
||||||
Config generic.ContractConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i ERC20TokenTransformerInitializer) NewERC20TokenTransformer(db *postgres.DB, blockchain core.BlockChain) shared.Transformer {
|
|
||||||
getter := NewGetter(blockchain)
|
getter := NewGetter(blockchain)
|
||||||
repository := ERC20TokenRepository{DB: db}
|
repository := ERC20TokenRepository{DB: db}
|
||||||
retriever := generic.NewTokenHolderRetriever(db, i.Config.Address)
|
retriever := erc20_watcher.NewTokenHolderRetriever(db, con.Address)
|
||||||
|
|
||||||
transformer := ERC20Transformer{
|
transformer := ERC20Transformer{
|
||||||
Getter: &getter,
|
Getter: &getter,
|
||||||
Repository: &repository,
|
Repository: &repository,
|
||||||
Retriever: retriever,
|
Retriever: retriever,
|
||||||
Config: i.Config,
|
Config: con,
|
||||||
}
|
}
|
||||||
|
|
||||||
return transformer
|
return transformer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -23,14 +23,15 @@ import (
|
|||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/constants"
|
"github.com/vulcanize/vulcanizedb/examples/constants"
|
||||||
|
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
|
"github.com/vulcanize/vulcanizedb/examples/erc20_watcher/every_block"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic"
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/mocks"
|
"github.com/vulcanize/vulcanizedb/examples/mocks"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/test_helpers"
|
"github.com/vulcanize/vulcanizedb/examples/test_helpers"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testContractConfig = generic.ContractConfig{
|
var testContractConfig = shared.ContractConfig{
|
||||||
Address: constants.DaiContractAddress,
|
Address: constants.DaiContractAddress,
|
||||||
Abi: constants.DaiAbiString,
|
Abi: constants.DaiAbiString,
|
||||||
FirstBlock: int64(4752008),
|
FirstBlock: int64(4752008),
|
||||||
@ -59,7 +60,7 @@ var _ = Describe("Everyblock transformer", func() {
|
|||||||
repository = mocks.ERC20TokenRepository{}
|
repository = mocks.ERC20TokenRepository{}
|
||||||
repository.SetMissingSupplyBlocks([]int64{config.FirstBlock})
|
repository.SetMissingSupplyBlocks([]int64{config.FirstBlock})
|
||||||
db := test_helpers.CreateNewDatabase()
|
db := test_helpers.CreateNewDatabase()
|
||||||
rt := generic.NewTokenHolderRetriever(db, config.Address)
|
rt := erc20_watcher.NewTokenHolderRetriever(db, config.Address)
|
||||||
//setting the mock repository to return the first block as the missing blocks
|
//setting the mock repository to return the first block as the missing blocks
|
||||||
|
|
||||||
transformer = every_block.ERC20Transformer{
|
transformer = every_block.ERC20Transformer{
|
||||||
|
@ -15,14 +15,11 @@
|
|||||||
package every_block
|
package every_block
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic"
|
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TransformerInitializers() []shared.TransformerInitializer {
|
func ERC20EveryBlockTransformerInitializer() []shared.TransformerInitializer {
|
||||||
config := generic.DaiConfig
|
|
||||||
initializer := ERC20TokenTransformerInitializer{config}
|
|
||||||
return []shared.TransformerInitializer{
|
return []shared.TransformerInitializer{
|
||||||
initializer.NewERC20TokenTransformer,
|
NewERC20TokenTransformer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
183
examples/erc20_watcher/retriever.go
Normal file
183
examples/erc20_watcher/retriever.go
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
// Copyright 2018 Vulcanize
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package erc20_watcher
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ERC20 retriever is used to iterate over addresses involved in token
|
||||||
|
// transfers and approvals to generate a list of token holder addresses
|
||||||
|
|
||||||
|
type TokenHolderRetrieverInterface interface {
|
||||||
|
RetrieveTokenHolderAddresses() (map[common.Address]bool, error)
|
||||||
|
retrieveTokenSenders() ([]string, error)
|
||||||
|
retrieveTokenReceivers() ([]string, error)
|
||||||
|
retrieveTokenOwners() ([]string, error)
|
||||||
|
retrieveTokenSpenders() ([]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TokenHolderRetriever struct {
|
||||||
|
Database *postgres.DB
|
||||||
|
ContractAddress string
|
||||||
|
}
|
||||||
|
|
||||||
|
type retrieverError struct {
|
||||||
|
err string
|
||||||
|
msg string
|
||||||
|
address string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retriever error method
|
||||||
|
func (re *retrieverError) Error() string {
|
||||||
|
return fmt.Sprintf(re.msg, re.address, re.err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to create a new retriever error for a given error and fetch method
|
||||||
|
func newRetrieverError(err error, msg string, address string) error {
|
||||||
|
e := retrieverError{err.Error(), msg, address}
|
||||||
|
log.Println(e.Error())
|
||||||
|
return &e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constant error definitions
|
||||||
|
const (
|
||||||
|
GetSendersError = "Error fetching token senders from contract %s: %s"
|
||||||
|
GetReceiversError = "Error fetching token receivers from contract %s: %s"
|
||||||
|
GetOwnersError = "Error fetching token owners from contract %s: %s"
|
||||||
|
GetSpendersError = "Error fetching token spenders from contract %s: %s"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewTokenHolderRetriever(db *postgres.DB, address string) TokenHolderRetriever {
|
||||||
|
return TokenHolderRetriever{
|
||||||
|
Database: db,
|
||||||
|
ContractAddress: address,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt TokenHolderRetriever) retrieveTokenSenders() ([]string, error) {
|
||||||
|
|
||||||
|
senders := make([]string, 0)
|
||||||
|
|
||||||
|
err := rt.Database.DB.Select(
|
||||||
|
&senders,
|
||||||
|
`SELECT from_address FROM token_transfers
|
||||||
|
WHERE token_address = $1`,
|
||||||
|
rt.ContractAddress,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, newRetrieverError(err, GetSendersError, rt.ContractAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
return senders, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt TokenHolderRetriever) retrieveTokenReceivers() ([]string, error) {
|
||||||
|
|
||||||
|
receivers := make([]string, 0)
|
||||||
|
|
||||||
|
err := rt.Database.DB.Select(
|
||||||
|
&receivers,
|
||||||
|
`SELECT to_address FROM token_transfers
|
||||||
|
WHERE token_address = $1`,
|
||||||
|
rt.ContractAddress,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, newRetrieverError(err, GetReceiversError, rt.ContractAddress)
|
||||||
|
}
|
||||||
|
return receivers, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt TokenHolderRetriever) retrieveTokenOwners() ([]string, error) {
|
||||||
|
|
||||||
|
owners := make([]string, 0)
|
||||||
|
|
||||||
|
err := rt.Database.DB.Select(
|
||||||
|
&owners,
|
||||||
|
`SELECT owner FROM token_approvals
|
||||||
|
WHERE token_address = $1`,
|
||||||
|
rt.ContractAddress,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, newRetrieverError(err, GetOwnersError, rt.ContractAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
return owners, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt TokenHolderRetriever) retrieveTokenSpenders() ([]string, error) {
|
||||||
|
|
||||||
|
spenders := make([]string, 0)
|
||||||
|
|
||||||
|
err := rt.Database.DB.Select(
|
||||||
|
&spenders,
|
||||||
|
`SELECT spender FROM token_approvals
|
||||||
|
WHERE token_address = $1`,
|
||||||
|
rt.ContractAddress,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, newRetrieverError(err, GetSpendersError, rt.ContractAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
return spenders, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt TokenHolderRetriever) RetrieveTokenHolderAddresses() (map[common.Address]bool, error) {
|
||||||
|
|
||||||
|
senders, err := rt.retrieveTokenSenders()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
receivers, err := rt.retrieveTokenReceivers()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
owners, err := rt.retrieveTokenOwners()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
spenders, err := rt.retrieveTokenSenders()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
contractAddresses := make(map[common.Address]bool)
|
||||||
|
|
||||||
|
for _, addr := range senders {
|
||||||
|
contractAddresses[common.HexToAddress(addr)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range receivers {
|
||||||
|
contractAddresses[common.HexToAddress(addr)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range owners {
|
||||||
|
contractAddresses[common.HexToAddress(addr)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range spenders {
|
||||||
|
contractAddresses[common.HexToAddress(addr)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return contractAddresses, nil
|
||||||
|
}
|
@ -15,34 +15,25 @@
|
|||||||
package generic
|
package generic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/constants"
|
"github.com/vulcanize/vulcanizedb/examples/constants"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ContractConfig struct {
|
var DaiConfig = shared.ContractConfig{
|
||||||
Address string
|
|
||||||
Owner string
|
|
||||||
Abi string
|
|
||||||
ParsedAbi abi.ABI
|
|
||||||
FirstBlock int64
|
|
||||||
LastBlock int64
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
||||||
var DaiConfig = ContractConfig{
|
|
||||||
Address: constants.DaiContractAddress,
|
Address: constants.DaiContractAddress,
|
||||||
Owner: constants.DaiContractOwner,
|
|
||||||
Abi: constants.DaiAbiString,
|
Abi: constants.DaiAbiString,
|
||||||
FirstBlock: int64(4752008),
|
FirstBlock: int64(4752008),
|
||||||
LastBlock: -1,
|
LastBlock: -1,
|
||||||
Name: "Dai",
|
Name: "Dai",
|
||||||
|
Filters: constants.DaiERC20Filters,
|
||||||
}
|
}
|
||||||
|
|
||||||
var TusdConfig = ContractConfig{
|
var TusdConfig = shared.ContractConfig{
|
||||||
Address: constants.TusdContractAddress,
|
Address: constants.TusdContractAddress,
|
||||||
Owner: constants.TusdContractOwner,
|
Owner: constants.TusdContractOwner,
|
||||||
Abi: constants.TusdAbiString,
|
Abi: constants.TusdAbiString,
|
||||||
FirstBlock: int64(5197514),
|
FirstBlock: int64(5197514),
|
||||||
LastBlock: -1,
|
LastBlock: -1,
|
||||||
Name: "Tusd",
|
Name: "Tusd",
|
||||||
|
Filters: constants.TusdGenericFilters,
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/constants"
|
"github.com/vulcanize/vulcanizedb/examples/constants"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic"
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic/event_triggered"
|
"github.com/vulcanize/vulcanizedb/examples/generic/event_triggered"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic/helpers"
|
"github.com/vulcanize/vulcanizedb/examples/generic/helpers"
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/core"
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
"github.com/vulcanize/vulcanizedb/pkg/geth"
|
||||||
)
|
)
|
||||||
@ -37,10 +37,10 @@ type GenericConverterInterface interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GenericConverter struct {
|
type GenericConverter struct {
|
||||||
config generic.ContractConfig
|
config shared.ContractConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGenericConverter(config generic.ContractConfig) (*GenericConverter, error) {
|
func NewGenericConverter(config shared.ContractConfig) (*GenericConverter, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
config.ParsedAbi, err = geth.ParseAbi(config.Abi)
|
config.ParsedAbi, err = geth.ParseAbi(config.Abi)
|
||||||
|
@ -71,6 +71,7 @@ var logs = []core.Log{
|
|||||||
|
|
||||||
var _ = Describe("Integration test with vulcanizedb", func() {
|
var _ = Describe("Integration test with vulcanizedb", func() {
|
||||||
var db *postgres.DB
|
var db *postgres.DB
|
||||||
|
var blk core.BlockChain
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
db = test_helpers.SetupIntegrationDB(db, logs)
|
db = test_helpers.SetupIntegrationDB(db, logs)
|
||||||
@ -81,7 +82,7 @@ var _ = Describe("Integration test with vulcanizedb", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("creates token_burns entry for each Burn event received", func() {
|
It("creates token_burns entry for each Burn event received", func() {
|
||||||
transformer, err := tusd.NewTransformer(db, generic.TusdConfig)
|
transformer, err := tusd.NewTransformer(db, blk, generic.TusdConfig)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
transformer.Execute()
|
transformer.Execute()
|
||||||
@ -106,7 +107,7 @@ var _ = Describe("Integration test with vulcanizedb", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("creates token_mints entry for each Mint event received", func() {
|
It("creates token_mints entry for each Mint event received", func() {
|
||||||
transformer, err := tusd.NewTransformer(db, generic.TusdConfig)
|
transformer, err := tusd.NewTransformer(db, blk, generic.TusdConfig)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
transformer.Execute()
|
transformer.Execute()
|
||||||
|
@ -19,12 +19,13 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/constants"
|
"github.com/vulcanize/vulcanizedb/examples/constants"
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic"
|
|
||||||
"github.com/vulcanize/vulcanizedb/examples/generic/event_triggered"
|
"github.com/vulcanize/vulcanizedb/examples/generic/event_triggered"
|
||||||
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/filters"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GenericTransformer struct {
|
type GenericTransformer struct {
|
||||||
@ -32,34 +33,38 @@ type GenericTransformer struct {
|
|||||||
WatchedEventRepository datastore.WatchedEventRepository
|
WatchedEventRepository datastore.WatchedEventRepository
|
||||||
FilterRepository datastore.FilterRepository
|
FilterRepository datastore.FilterRepository
|
||||||
Repository event_triggered.GenericEventDatastore
|
Repository event_triggered.GenericEventDatastore
|
||||||
|
Filters []filters.LogFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransformer(db *postgres.DB, config generic.ContractConfig) (shared.Transformer, error) {
|
func NewTransformer(db *postgres.DB, blockchain core.BlockChain, con shared.ContractConfig) (shared.Transformer, error) {
|
||||||
var transformer shared.Transformer
|
var transformer shared.Transformer
|
||||||
|
|
||||||
cnvtr, err := NewGenericConverter(config)
|
cnvtr, err := NewGenericConverter(con)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return transformer, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
wer := repositories.WatchedEventRepository{DB: db}
|
wer := repositories.WatchedEventRepository{DB: db}
|
||||||
fr := repositories.FilterRepository{DB: db}
|
fr := repositories.FilterRepository{DB: db}
|
||||||
lkr := event_triggered.GenericEventRepository{DB: db}
|
lkr := event_triggered.GenericEventRepository{DB: db}
|
||||||
|
|
||||||
transformer = GenericTransformer{
|
transformer = GenericTransformer{
|
||||||
Converter: cnvtr,
|
Converter: cnvtr,
|
||||||
WatchedEventRepository: wer,
|
WatchedEventRepository: wer,
|
||||||
FilterRepository: fr,
|
FilterRepository: fr,
|
||||||
Repository: lkr,
|
Repository: lkr,
|
||||||
|
Filters: con.Filters,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, filter := range constants.TusdGenericFilters {
|
for _, filter := range con.Filters {
|
||||||
fr.CreateFilter(filter)
|
fr.CreateFilter(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
return transformer, nil
|
return transformer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tr GenericTransformer) Execute() error {
|
func (tr GenericTransformer) Execute() error {
|
||||||
for _, filter := range constants.TusdGenericFilters {
|
for _, filter := range tr.Filters {
|
||||||
watchedEvents, err := tr.WatchedEventRepository.GetWatchedEvents(filter.Name)
|
watchedEvents, err := tr.WatchedEventRepository.GetWatchedEvents(filter.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(fmt.Sprintf("Error fetching events for %s:", filter.Name), err)
|
log.Println(fmt.Sprintf("Error fetching events for %s:", filter.Name), err)
|
||||||
@ -70,7 +75,7 @@ func (tr GenericTransformer) Execute() error {
|
|||||||
entity, err := tr.Converter.ToBurnEntity(*we)
|
entity, err := tr.Converter.ToBurnEntity(*we)
|
||||||
model := tr.Converter.ToBurnModel(entity)
|
model := tr.Converter.ToBurnModel(entity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error persisting data for Dai Burns (watchedEvent.LogID %d):\n %s", we.LogID, err)
|
log.Printf("Error persisting data for TrueUSD Burns (watchedEvent.LogID %d):\n %s", we.LogID, err)
|
||||||
}
|
}
|
||||||
tr.Repository.CreateBurn(model, we.LogID)
|
tr.Repository.CreateBurn(model, we.LogID)
|
||||||
}
|
}
|
||||||
@ -78,11 +83,12 @@ func (tr GenericTransformer) Execute() error {
|
|||||||
entity, err := tr.Converter.ToMintEntity(*we)
|
entity, err := tr.Converter.ToMintEntity(*we)
|
||||||
model := tr.Converter.ToMintModel(entity)
|
model := tr.Converter.ToMintModel(entity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Error persisting data for Dai Mints (watchedEvent.LogID %d):\n %s", we.LogID, err)
|
log.Printf("Error persisting data for TrueUSD Mints (watchedEvent.LogID %d):\n %s", we.LogID, err)
|
||||||
}
|
}
|
||||||
tr.Repository.CreateMint(model, we.LogID)
|
tr.Repository.CreateMint(model, we.LogID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -71,12 +71,14 @@ var _ = Describe("Mock ERC20 transformer", func() {
|
|||||||
watchedEventsRepo.SetWatchedEvents(fakeWatchedEvents)
|
watchedEventsRepo.SetWatchedEvents(fakeWatchedEvents)
|
||||||
mockEventRepo = mocks.MockEventRepo{}
|
mockEventRepo = mocks.MockEventRepo{}
|
||||||
filterRepo = mocks.MockFilterRepository{}
|
filterRepo = mocks.MockFilterRepository{}
|
||||||
|
filters := constants.TusdGenericFilters
|
||||||
|
|
||||||
transformer = tusd.GenericTransformer{
|
transformer = tusd.GenericTransformer{
|
||||||
Converter: &mockERC20Converter,
|
Converter: &mockERC20Converter,
|
||||||
WatchedEventRepository: &watchedEventsRepo,
|
WatchedEventRepository: &watchedEventsRepo,
|
||||||
FilterRepository: filterRepo,
|
FilterRepository: filterRepo,
|
||||||
Repository: &mockEventRepo,
|
Repository: &mockEventRepo,
|
||||||
|
Filters: filters,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
25
examples/generic/event_triggered/tusd/transformers.go
Normal file
25
examples/generic/event_triggered/tusd/transformers.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
// Copyright 2018 Vulcanize
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tusd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/libraries/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TusdEventTriggeredTransformerInitializer() []shared.TransformerInitializer {
|
||||||
|
return []shared.TransformerInitializer{
|
||||||
|
NewTransformer,
|
||||||
|
}
|
||||||
|
}
|
@ -23,8 +23,8 @@ import (
|
|||||||
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Retriever is used to iterate over addresses going into or out of a contract
|
// Generic retriever is used to iterate over addresses involved in token
|
||||||
// address in an attempt to generate a list of token holder addresses
|
// transfers, approvals, mints, and burns to generate a list of token holder addresses
|
||||||
|
|
||||||
type TokenHolderRetrieverInterface interface {
|
type TokenHolderRetrieverInterface interface {
|
||||||
RetrieveTokenHolderAddresses() (map[common.Address]bool, error)
|
RetrieveTokenHolderAddresses() (map[common.Address]bool, error)
|
||||||
@ -32,6 +32,8 @@ type TokenHolderRetrieverInterface interface {
|
|||||||
retrieveTokenReceivers() ([]string, error)
|
retrieveTokenReceivers() ([]string, error)
|
||||||
retrieveTokenOwners() ([]string, error)
|
retrieveTokenOwners() ([]string, error)
|
||||||
retrieveTokenSpenders() ([]string, error)
|
retrieveTokenSpenders() ([]string, error)
|
||||||
|
retrieveTokenMintees() ([]string, error)
|
||||||
|
retrieveTokenBurners() ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type TokenHolderRetriever struct {
|
type TokenHolderRetriever struct {
|
||||||
|
17
libraries/shared/contract_config.go
Normal file
17
libraries/shared/contract_config.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package shared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/filters"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ContractConfig struct {
|
||||||
|
Address string
|
||||||
|
Owner string
|
||||||
|
Abi string
|
||||||
|
ParsedAbi abi.ABI
|
||||||
|
FirstBlock int64
|
||||||
|
LastBlock int64
|
||||||
|
Name string
|
||||||
|
Filters []filters.LogFilter
|
||||||
|
}
|
@ -10,7 +10,7 @@ type Transformer interface {
|
|||||||
Execute() error
|
Execute() error
|
||||||
}
|
}
|
||||||
|
|
||||||
type TransformerInitializer func(db *postgres.DB, blockchain core.BlockChain) Transformer
|
type TransformerInitializer func(db *postgres.DB, blockchain core.BlockChain, con ContractConfig) (Transformer, error)
|
||||||
|
|
||||||
func HexToInt64(byteString string) int64 {
|
func HexToInt64(byteString string) int64 {
|
||||||
value := common.HexToHash(byteString)
|
value := common.HexToHash(byteString)
|
||||||
|
@ -11,11 +11,16 @@ type Watcher struct {
|
|||||||
Blockchain core.BlockChain
|
Blockchain core.BlockChain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (watcher *Watcher) AddTransformers(us []TransformerInitializer) {
|
func (watcher *Watcher) AddTransformers(us []TransformerInitializer, con ContractConfig) error {
|
||||||
for _, transformerInitializer := range us {
|
for _, transformerInitializer := range us {
|
||||||
transformer := transformerInitializer(&watcher.DB, watcher.Blockchain)
|
transformer, err := transformerInitializer(&watcher.DB, watcher.Blockchain, con)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
watcher.Transformers = append(watcher.Transformers, transformer)
|
watcher.Transformers = append(watcher.Transformers, transformer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (watcher *Watcher) Execute() error {
|
func (watcher *Watcher) Execute() error {
|
||||||
|
@ -23,15 +23,16 @@ func (mh *MockTransformer) Execute() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fakeTransformerInitializer(db *postgres.DB, blockchain core.BlockChain) shared.Transformer {
|
func fakeTransformerInitializer(db *postgres.DB, blockchain core.BlockChain, con shared.ContractConfig) (shared.Transformer, error) {
|
||||||
return &MockTransformer{}
|
return &MockTransformer{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = Describe("Watcher", func() {
|
var _ = Describe("Watcher", func() {
|
||||||
It("Adds transformers", func() {
|
It("Adds transformers", func() {
|
||||||
watcher := shared.Watcher{}
|
watcher := shared.Watcher{}
|
||||||
|
con := shared.ContractConfig{}
|
||||||
|
|
||||||
watcher.AddTransformers([]shared.TransformerInitializer{fakeTransformerInitializer})
|
watcher.AddTransformers([]shared.TransformerInitializer{fakeTransformerInitializer}, con)
|
||||||
|
|
||||||
Expect(len(watcher.Transformers)).To(Equal(1))
|
Expect(len(watcher.Transformers)).To(Equal(1))
|
||||||
Expect(watcher.Transformers).To(ConsistOf(&MockTransformer{}))
|
Expect(watcher.Transformers).To(ConsistOf(&MockTransformer{}))
|
||||||
@ -39,9 +40,10 @@ var _ = Describe("Watcher", func() {
|
|||||||
|
|
||||||
It("Adds transformers from multiple sources", func() {
|
It("Adds transformers from multiple sources", func() {
|
||||||
watcher := shared.Watcher{}
|
watcher := shared.Watcher{}
|
||||||
|
con := shared.ContractConfig{}
|
||||||
|
|
||||||
watcher.AddTransformers([]shared.TransformerInitializer{fakeTransformerInitializer})
|
watcher.AddTransformers([]shared.TransformerInitializer{fakeTransformerInitializer}, con)
|
||||||
watcher.AddTransformers([]shared.TransformerInitializer{fakeTransformerInitializer})
|
watcher.AddTransformers([]shared.TransformerInitializer{fakeTransformerInitializer}, con)
|
||||||
|
|
||||||
Expect(len(watcher.Transformers)).To(Equal(2))
|
Expect(len(watcher.Transformers)).To(Equal(2))
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user