Add Rep price feed
This commit is contained in:
parent
2949996d22
commit
6e68dc4a92
@ -34,6 +34,7 @@ import (
|
|||||||
"github.com/vulcanize/vulcanizedb/pkg/transformers"
|
"github.com/vulcanize/vulcanizedb/pkg/transformers"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds/pep"
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds/pep"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds/pip"
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds/pip"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds/rep"
|
||||||
"github.com/vulcanize/vulcanizedb/utils"
|
"github.com/vulcanize/vulcanizedb/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -94,6 +95,7 @@ func syncPriceFeeds() {
|
|||||||
transformers := []transformers.Transformer{
|
transformers := []transformers.Transformer{
|
||||||
pep.NewPepTransformer(blockChain, &db),
|
pep.NewPepTransformer(blockChain, &db),
|
||||||
pip.NewPipTransformer(blockChain, &db),
|
pip.NewPipTransformer(blockChain, &db),
|
||||||
|
rep.NewRepTransformer(blockChain, &db),
|
||||||
}
|
}
|
||||||
go backFillPriceFeeds(blockChain, headerRepository, missingBlocksPopulated, startingBlockNumber, transformers)
|
go backFillPriceFeeds(blockChain, headerRepository, missingBlocksPopulated, startingBlockNumber, transformers)
|
||||||
|
|
||||||
|
1
db/migrations/1532635100_create_reps_table.down.sql
Normal file
1
db/migrations/1532635100_create_reps_table.down.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
DROP TABLE maker.reps;
|
9
db/migrations/1532635100_create_reps_table.up.sql
Normal file
9
db/migrations/1532635100_create_reps_table.up.sql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE maker.reps (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
block_number BIGINT NOT NULL,
|
||||||
|
header_id INTEGER NOT NULL,
|
||||||
|
usd_value NUMERIC,
|
||||||
|
CONSTRAINT headers_fk FOREIGN KEY (header_id)
|
||||||
|
REFERENCES headers (id)
|
||||||
|
ON DELETE CASCADE
|
||||||
|
);
|
@ -183,6 +183,38 @@ CREATE SEQUENCE maker.pips_id_seq
|
|||||||
ALTER SEQUENCE maker.pips_id_seq OWNED BY maker.pips.id;
|
ALTER SEQUENCE maker.pips_id_seq OWNED BY maker.pips.id;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: reps; Type: TABLE; Schema: maker; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE TABLE maker.reps (
|
||||||
|
id integer NOT NULL,
|
||||||
|
block_number bigint NOT NULL,
|
||||||
|
header_id integer NOT NULL,
|
||||||
|
usd_value numeric
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: reps_id_seq; Type: SEQUENCE; Schema: maker; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
CREATE SEQUENCE maker.reps_id_seq
|
||||||
|
AS integer
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: reps_id_seq; Type: SEQUENCE OWNED BY; Schema: maker; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER SEQUENCE maker.reps_id_seq OWNED BY maker.reps.id;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: logs; Type: TABLE; Schema: public; Owner: -
|
-- Name: logs; Type: TABLE; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -583,6 +615,13 @@ ALTER TABLE ONLY maker.peps ALTER COLUMN id SET DEFAULT nextval('maker.peps_id_s
|
|||||||
ALTER TABLE ONLY maker.pips ALTER COLUMN id SET DEFAULT nextval('maker.pips_id_seq'::regclass);
|
ALTER TABLE ONLY maker.pips ALTER COLUMN id SET DEFAULT nextval('maker.pips_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: reps id; Type: DEFAULT; Schema: maker; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY maker.reps ALTER COLUMN id SET DEFAULT nextval('maker.reps_id_seq'::regclass);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: blocks id; Type: DEFAULT; Schema: public; Owner: -
|
-- Name: blocks id; Type: DEFAULT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -694,6 +733,14 @@ ALTER TABLE ONLY maker.pips
|
|||||||
ADD CONSTRAINT pips_pkey PRIMARY KEY (id);
|
ADD CONSTRAINT pips_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: reps reps_pkey; Type: CONSTRAINT; Schema: maker; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY maker.reps
|
||||||
|
ADD CONSTRAINT reps_pkey PRIMARY KEY (id);
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: blocks blocks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
-- Name: blocks blocks_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
@ -857,6 +904,14 @@ ALTER TABLE ONLY maker.pips
|
|||||||
ADD CONSTRAINT headers_fk FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
ADD CONSTRAINT headers_fk FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Name: reps headers_fk; Type: FK CONSTRAINT; Schema: maker; Owner: -
|
||||||
|
--
|
||||||
|
|
||||||
|
ALTER TABLE ONLY maker.reps
|
||||||
|
ADD CONSTRAINT headers_fk FOREIGN KEY (header_id) REFERENCES public.headers(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Name: transactions blocks_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
-- Name: transactions blocks_fk; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||||
--
|
--
|
||||||
|
@ -8,12 +8,14 @@ import (
|
|||||||
var (
|
var (
|
||||||
ErrMultipleLogs = errors.New("multiple matching logs found in block")
|
ErrMultipleLogs = errors.New("multiple matching logs found in block")
|
||||||
ErrNoMatchingLog = errors.New("no matching log")
|
ErrNoMatchingLog = errors.New("no matching log")
|
||||||
PeekMethodName = "peek"
|
|
||||||
PepLogTopic0 = "0x296ba4ca62c6c21c95e828080cb8aec7481b71390585605300a8a76f9e95b527"
|
|
||||||
PipLogTopic0 = "0x1817835800000000000000000000000000000000000000000000000000000000"
|
|
||||||
PepAddress = "0x99041F808D598B782D5a3e498681C2452A31da08"
|
|
||||||
PipAddress = "0x729D19f657BD0614b4985Cf1D82531c67569197B"
|
|
||||||
PipMedianizerABI = `[{"constant":false,"inputs":[{"name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"","type":"bytes32"}],"name":"poke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"poke","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"compute","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"wat","type":"address"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"wat","type":"address"}],"name":"unset","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"indexes","outputs":[{"name":"","type":"bytes12"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"next","outputs":[{"name":"","type":"bytes12"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"read","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"peek","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes12"}],"name":"values","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"min_","type":"uint96"}],"name":"setMin","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"void","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"pos","type":"bytes12"},{"name":"wat","type":"address"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"pos","type":"bytes12"}],"name":"unset","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"next_","type":"bytes12"}],"name":"setNext","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"min","outputs":[{"name":"","type":"uint96"}],"payable":false,"type":"function"},{"anonymous":true,"inputs":[{"indexed":true,"name":"sig","type":"bytes4"},{"indexed":true,"name":"guy","type":"address"},{"indexed":true,"name":"foo","type":"bytes32"},{"indexed":true,"name":"bar","type":"bytes32"},{"indexed":false,"name":"wad","type":"uint256"},{"indexed":false,"name":"fax","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"}]`
|
|
||||||
Ether = big.NewFloat(1e18)
|
Ether = big.NewFloat(1e18)
|
||||||
|
PeekMethodName = "peek"
|
||||||
|
PepAddress = "0x99041F808D598B782D5a3e498681C2452A31da08"
|
||||||
|
PepLogTopic0 = "0x296ba4ca62c6c21c95e828080cb8aec7481b71390585605300a8a76f9e95b527"
|
||||||
|
PipAddress = "0x729D19f657BD0614b4985Cf1D82531c67569197B"
|
||||||
|
PipLogTopic0 = "0x1817835800000000000000000000000000000000000000000000000000000000"
|
||||||
|
PipMedianizerABI = `[{"constant":false,"inputs":[{"name":"owner_","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"","type":"bytes32"}],"name":"poke","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"poke","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"compute","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"wat","type":"address"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"wat","type":"address"}],"name":"unset","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"indexes","outputs":[{"name":"","type":"bytes12"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"next","outputs":[{"name":"","type":"bytes12"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"read","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"peek","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes12"}],"name":"values","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"min_","type":"uint96"}],"name":"setMin","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"authority_","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"void","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"pos","type":"bytes12"},{"name":"wat","type":"address"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"pos","type":"bytes12"}],"name":"unset","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"next_","type":"bytes12"}],"name":"setNext","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"min","outputs":[{"name":"","type":"uint96"}],"payable":false,"type":"function"},{"anonymous":true,"inputs":[{"indexed":true,"name":"sig","type":"bytes4"},{"indexed":true,"name":"guy","type":"address"},{"indexed":true,"name":"foo","type":"bytes32"},{"indexed":true,"name":"bar","type":"bytes32"},{"indexed":false,"name":"wad","type":"uint256"},{"indexed":false,"name":"fax","type":"bytes"}],"name":"LogNote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"authority","type":"address"}],"name":"LogSetAuthority","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"}],"name":"LogSetOwner","type":"event"}]`
|
||||||
Ray = big.NewFloat(1e27)
|
Ray = big.NewFloat(1e27)
|
||||||
|
RepAddress = "0xF5f94b7F9De14D43112e713835BCef2d55b76c1C"
|
||||||
|
RepLogTopic0 = "0x296ba4ca62c6c21c95e828080cb8aec7481b71390585605300a8a76f9e95b527"
|
||||||
)
|
)
|
||||||
|
40
pkg/transformers/price_feeds/rep/fetcher.go
Normal file
40
pkg/transformers/price_feeds/rep/fetcher.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package rep
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IRepFetcher interface {
|
||||||
|
FetchRepValue(header core.Header) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RepFetcher struct {
|
||||||
|
chain core.BlockChain
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRepFetcher(chain core.BlockChain) RepFetcher {
|
||||||
|
return RepFetcher{
|
||||||
|
chain: chain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fetcher RepFetcher) FetchRepValue(header core.Header) (string, error) {
|
||||||
|
blockNumber := big.NewInt(header.BlockNumber)
|
||||||
|
logs, err := fetcher.chain.GetLogs(price_feeds.RepAddress, price_feeds.RepLogTopic0, blockNumber, blockNumber)
|
||||||
|
return fetcher.getLogValue(logs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fetcher RepFetcher) getLogValue(logs []core.Log, err error) (string, error) {
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if len(logs) < 1 {
|
||||||
|
return "", price_feeds.ErrNoMatchingLog
|
||||||
|
}
|
||||||
|
if len(logs) > 1 {
|
||||||
|
return "", price_feeds.ErrMultipleLogs
|
||||||
|
}
|
||||||
|
return logs[0].Data, nil
|
||||||
|
}
|
62
pkg/transformers/price_feeds/rep/fetcher_test.go
Normal file
62
pkg/transformers/price_feeds/rep/fetcher_test.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package rep_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds/rep"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Rep fetcher", func() {
|
||||||
|
It("gets logs describing updated rep/usd value", func() {
|
||||||
|
mockBlockChain := fakes.NewMockBlockChain()
|
||||||
|
mockBlockChain.SetGetLogsReturnLogs([]core.Log{{}})
|
||||||
|
fetcher := rep.NewRepFetcher(mockBlockChain)
|
||||||
|
header := core.Header{
|
||||||
|
BlockNumber: 100,
|
||||||
|
Hash: "",
|
||||||
|
Raw: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := fetcher.FetchRepValue(header)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
mockBlockChain.AssertGetLogsCalledWith(price_feeds.RepAddress, price_feeds.RepLogTopic0, big.NewInt(header.BlockNumber), big.NewInt(header.BlockNumber))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if getting logs fails", func() {
|
||||||
|
mockBlockChain := fakes.NewMockBlockChain()
|
||||||
|
mockBlockChain.SetGetLogsReturnLogs([]core.Log{{}})
|
||||||
|
mockBlockChain.SetGetLogsReturnErr(fakes.FakeError)
|
||||||
|
fetcher := rep.NewRepFetcher(mockBlockChain)
|
||||||
|
|
||||||
|
_, err := fetcher.FetchRepValue(core.Header{})
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(fakes.FakeError))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns no matching logs error if no logs returned", func() {
|
||||||
|
mockBlockChain := fakes.NewMockBlockChain()
|
||||||
|
fetcher := rep.NewRepFetcher(mockBlockChain)
|
||||||
|
|
||||||
|
_, err := fetcher.FetchRepValue(core.Header{})
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(price_feeds.ErrNoMatchingLog))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns error if more than one matching logs returned", func() {
|
||||||
|
mockBlockChain := fakes.NewMockBlockChain()
|
||||||
|
mockBlockChain.SetGetLogsReturnLogs([]core.Log{{}, {}})
|
||||||
|
fetcher := rep.NewRepFetcher(mockBlockChain)
|
||||||
|
|
||||||
|
_, err := fetcher.FetchRepValue(core.Header{})
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(err).To(MatchError(price_feeds.ErrMultipleLogs))
|
||||||
|
})
|
||||||
|
})
|
13
pkg/transformers/price_feeds/rep/rep_suite_test.go
Normal file
13
pkg/transformers/price_feeds/rep/rep_suite_test.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package rep_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRep(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "Rep Suite")
|
||||||
|
}
|
25
pkg/transformers/price_feeds/rep/repository.go
Normal file
25
pkg/transformers/price_feeds/rep/repository.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package rep
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IRepRepository interface {
|
||||||
|
CreateRep(rep price_feeds.PriceUpdate) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type RepRepository struct {
|
||||||
|
db *postgres.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRepRepository(db *postgres.DB) RepRepository {
|
||||||
|
return RepRepository{
|
||||||
|
db: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repository RepRepository) CreateRep(rep price_feeds.PriceUpdate) error {
|
||||||
|
_, err := repository.db.Exec(`INSERT INTO maker.reps (block_number, header_id, usd_value) VALUES ($1, $2, $3::NUMERIC)`, rep.BlockNumber, rep.HeaderID, rep.UsdValue)
|
||||||
|
return err
|
||||||
|
}
|
49
pkg/transformers/price_feeds/rep/repository_test.go
Normal file
49
pkg/transformers/price_feeds/rep/repository_test.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package rep_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds/rep"
|
||||||
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Rep repository", func() {
|
||||||
|
It("returns header if matching header does not exist", func() {
|
||||||
|
db := test_config.NewTestDB(core.Node{})
|
||||||
|
repository := rep.NewRepRepository(db)
|
||||||
|
pepToAdd := price_feeds.PriceUpdate{
|
||||||
|
BlockNumber: 0,
|
||||||
|
HeaderID: 0,
|
||||||
|
UsdValue: "123.456",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := repository.CreateRep(pepToAdd)
|
||||||
|
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("creates a rep when matching header exists", func() {
|
||||||
|
db := test_config.NewTestDB(core.Node{})
|
||||||
|
repository := rep.NewRepRepository(db)
|
||||||
|
header := core.Header{BlockNumber: 12345}
|
||||||
|
headerRepository := repositories.NewHeaderRepository(db)
|
||||||
|
headerID, err := headerRepository.CreateOrUpdateHeader(header)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
pepToAdd := price_feeds.PriceUpdate{
|
||||||
|
BlockNumber: header.BlockNumber,
|
||||||
|
HeaderID: headerID,
|
||||||
|
UsdValue: "123.456",
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repository.CreateRep(pepToAdd)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
var dbRep price_feeds.PriceUpdate
|
||||||
|
err = db.Get(&dbRep, `SELECT block_number, header_id, usd_value FROM maker.reps WHERE header_id = $1`, pepToAdd.HeaderID)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(dbRep).To(Equal(pepToAdd))
|
||||||
|
})
|
||||||
|
})
|
43
pkg/transformers/price_feeds/rep/transformer.go
Normal file
43
pkg/transformers/price_feeds/rep/transformer.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package rep
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RepTransformer struct {
|
||||||
|
fetcher IRepFetcher
|
||||||
|
repository IRepRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRepTransformer(chain core.BlockChain, db *postgres.DB) RepTransformer {
|
||||||
|
fetcher := NewRepFetcher(chain)
|
||||||
|
repository := NewRepRepository(db)
|
||||||
|
return RepTransformer{
|
||||||
|
fetcher: fetcher,
|
||||||
|
repository: repository,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (transformer RepTransformer) Execute(header core.Header, headerID int64) error {
|
||||||
|
logValue, err := transformer.fetcher.FetchRepValue(header)
|
||||||
|
if err != nil {
|
||||||
|
if err == price_feeds.ErrNoMatchingLog {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rep := getRep(logValue, header, headerID)
|
||||||
|
return transformer.repository.CreateRep(rep)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRep(logValue string, header core.Header, headerID int64) price_feeds.PriceUpdate {
|
||||||
|
valueInUSD := price_feeds.Convert("wad", logValue, 15)
|
||||||
|
rep := price_feeds.PriceUpdate{
|
||||||
|
BlockNumber: header.BlockNumber,
|
||||||
|
HeaderID: headerID,
|
||||||
|
UsdValue: valueInUSD,
|
||||||
|
}
|
||||||
|
return rep
|
||||||
|
}
|
45
pkg/transformers/price_feeds/rep/transformer_test.go
Normal file
45
pkg/transformers/price_feeds/rep/transformer_test.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package rep_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/core"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres/repositories"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/fakes"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds"
|
||||||
|
"github.com/vulcanize/vulcanizedb/pkg/transformers/price_feeds/rep"
|
||||||
|
"github.com/vulcanize/vulcanizedb/test_config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Rep transformer", func() {
|
||||||
|
It("returns nil if no logs found", func() {
|
||||||
|
chain := fakes.NewMockBlockChain()
|
||||||
|
db := test_config.NewTestDB(core.Node{})
|
||||||
|
transformer := rep.NewRepTransformer(chain, db)
|
||||||
|
|
||||||
|
err := transformer.Execute(core.Header{}, 123)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("creates rep row for found log", func() {
|
||||||
|
chain := fakes.NewMockBlockChain()
|
||||||
|
chain.SetGetLogsReturnLogs([]core.Log{{Data: common.ToHex([]byte{1, 2, 3, 4, 5})}})
|
||||||
|
db := test_config.NewTestDB(core.Node{})
|
||||||
|
headerRepository := repositories.NewHeaderRepository(db)
|
||||||
|
header := core.Header{BlockNumber: 12345}
|
||||||
|
headerID, err := headerRepository.CreateOrUpdateHeader(header)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
transformer := rep.NewRepTransformer(chain, db)
|
||||||
|
|
||||||
|
err = transformer.Execute(header, headerID)
|
||||||
|
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
var dbRep price_feeds.PriceUpdate
|
||||||
|
err = db.Get(&dbRep, `SELECT block_number, header_id, usd_value FROM maker.reps WHERE header_id = $1`, headerID)
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(dbRep.BlockNumber).To(Equal(header.BlockNumber))
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user