diff --git a/pkg/contract_watcher/header/converter/converter.go b/pkg/contract_watcher/header/converter/converter.go index 3a62c807..67a32c25 100644 --- a/pkg/contract_watcher/header/converter/converter.go +++ b/pkg/contract_watcher/header/converter/converter.go @@ -92,6 +92,11 @@ func (c *Converter) Convert(logs []gethTypes.Log, event types.Event, headerID in case byte: b := input.(byte) strValues[fieldName] = string(b) + case [32]uint8: + raw := input.([32]uint8) + converted := convertUintSliceToHash(raw) + strValues[fieldName] = converted.String() + seenHashes = append(seenHashes, converted) default: return nil, errors.New(fmt.Sprintf("error: unhandled abi type %T", input)) } @@ -171,6 +176,11 @@ func (c *Converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.E case byte: b := input.(byte) strValues[fieldName] = string(b) + case [32]uint8: + raw := input.([32]uint8) + converted := convertUintSliceToHash(raw) + strValues[fieldName] = converted.String() + seenHashes = append(seenHashes, converted) default: return nil, errors.New(fmt.Sprintf("error: unhandled abi type %T", input)) } @@ -205,3 +215,11 @@ func (c *Converter) ConvertBatch(logs []gethTypes.Log, events map[string]types.E return eventsToLogs, nil } + +func convertUintSliceToHash(raw [32]uint8) common.Hash { + var asBytes []byte + for _, u := range raw { + asBytes = append(asBytes, u) + } + return common.BytesToHash(asBytes) +} diff --git a/pkg/contract_watcher/header/converter/converter_test.go b/pkg/contract_watcher/header/converter/converter_test.go index fa60b64c..75e83843 100644 --- a/pkg/contract_watcher/header/converter/converter_test.go +++ b/pkg/contract_watcher/header/converter/converter_test.go @@ -33,6 +33,7 @@ var _ = Describe("Converter", func() { var con *contract.Contract var tusdWantedEvents = []string{"Transfer", "Mint"} var ensWantedEvents = []string{"NewOwner"} + var marketPlaceWantedEvents = []string{"OrderCreated"} var err error Describe("Update", func() { @@ -145,6 +146,20 @@ var _ = Describe("Converter", func() { Expect(ok).To(Equal(false)) }) + It("keeps track of hashes derived from bytes32", func() { + con = test_helpers.SetupMarketPlaceContract(marketPlaceWantedEvents, []string{}) + event, ok := con.Events["OrderCreated"] + Expect(ok).To(BeTrue()) + + c := converter.Converter{} + c.Update(con) + result, err := c.Convert([]types.Log{mocks.MockOrderCreatedLog}, event, 232) + Expect(err).NotTo(HaveOccurred()) + + Expect(len(result)).To(Equal(1)) + Expect(result[0].Values["id"]).To(Equal("0x633f94affdcabe07c000231f85c752c97b9cc43966b432ec4d18641e6d178233")) + }) + It("Fails with an empty contract", func() { event := con.Events["Transfer"] c := converter.Converter{} diff --git a/pkg/contract_watcher/shared/constants/constants.go b/pkg/contract_watcher/shared/constants/constants.go index 5545f791..a8d754ac 100644 --- a/pkg/contract_watcher/shared/constants/constants.go +++ b/pkg/contract_watcher/shared/constants/constants.go @@ -70,6 +70,7 @@ func (e Event) Signature() string { var DaiContractAddress = "0x89d24a6b4ccb1b6faa2625fe562bdd9a23260359" var TusdContractAddress = "0x8dd5fbCe2F6a956C3022bA3663759011Dd51e73E" var EnsContractAddress = "0x314159265dD8dbb310642f98f50C066173C1259b" +var MarketPlaceContractAddress = "0x8e5660b4Ab70168b5a6fEeA0e0315cb49c8Cd539" var PublicResolverAddress = "0x1da022710dF5002339274AaDEe8D58218e9D6AB5" // Contract Owner @@ -83,6 +84,8 @@ var TusdAbiString = `[{"constant":true,"inputs":[],"name":"burnMin","outputs":[{ var ENSAbiString = `[{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"resolver","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"label","type":"bytes32"},{"name":"owner","type":"address"}],"name":"setSubnodeOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"ttl","type":"uint64"}],"name":"setTTL","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"node","type":"bytes32"}],"name":"ttl","outputs":[{"name":"","type":"uint64"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"resolver","type":"address"}],"name":"setResolver","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"node","type":"bytes32"},{"name":"owner","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"owner","type":"address"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":true,"name":"label","type":"bytes32"},{"indexed":false,"name":"owner","type":"address"}],"name":"NewOwner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"resolver","type":"address"}],"name":"NewResolver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"node","type":"bytes32"},{"indexed":false,"name":"ttl","type":"uint64"}],"name":"NewTTL","type":"event"}]` +var MarketPlaceAbiString = `[{"constant":false,"inputs":[{"name":"_ownerCutPerMillion","type":"uint256"}],"name":"setOwnerCutPerMillion","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_legacyNFTAddress","type":"address"}],"name":"setLegacyNFTAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ERC721_Interface","outputs":[{"name":"","type":"bytes4"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"InterfaceId_ValidateFingerprint","outputs":[{"name":"","type":"bytes4"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"acceptedToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"uint256"}],"name":"cancelOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"nftAddress","type":"address"},{"name":"assetId","type":"uint256"}],"name":"cancelOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"nftAddress","type":"address"},{"name":"assetId","type":"uint256"},{"name":"priceInWei","type":"uint256"},{"name":"expiresAt","type":"uint256"}],"name":"createOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"nftAddress","type":"address"},{"name":"assetId","type":"uint256"},{"name":"price","type":"uint256"},{"name":"fingerprint","type":"bytes"}],"name":"safeExecuteOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ownerCutPerMillion","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"uint256"},{"name":"priceInWei","type":"uint256"},{"name":"expiresAt","type":"uint256"}],"name":"createOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"publicationFeeInWei","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"nftAddress","type":"address"},{"name":"assetId","type":"uint256"},{"name":"price","type":"uint256"}],"name":"executeOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_publicationFee","type":"uint256"}],"name":"setPublicationFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"contractName","type":"string"},{"name":"migrationId","type":"string"}],"name":"isMigrated","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_acceptedToken","type":"address"},{"name":"_legacyNFTAddress","type":"address"},{"name":"_owner","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_sender","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"legacyNFTAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"assetId","type":"uint256"}],"name":"auctionByAssetId","outputs":[{"name":"","type":"bytes32"},{"name":"","type":"address"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"uint256"}],"name":"orderByAssetId","outputs":[{"name":"id","type":"bytes32"},{"name":"seller","type":"address"},{"name":"nftAddress","type":"address"},{"name":"price","type":"uint256"},{"name":"expiresAt","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"uint256"},{"name":"price","type":"uint256"}],"name":"executeOrder","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"bytes32"},{"indexed":true,"name":"assetId","type":"uint256"},{"indexed":true,"name":"seller","type":"address"},{"indexed":false,"name":"nftAddress","type":"address"},{"indexed":false,"name":"priceInWei","type":"uint256"},{"indexed":false,"name":"expiresAt","type":"uint256"}],"name":"OrderCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"bytes32"},{"indexed":true,"name":"assetId","type":"uint256"},{"indexed":true,"name":"seller","type":"address"},{"indexed":false,"name":"nftAddress","type":"address"},{"indexed":false,"name":"totalPrice","type":"uint256"},{"indexed":true,"name":"buyer","type":"address"}],"name":"OrderSuccessful","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"bytes32"},{"indexed":true,"name":"assetId","type":"uint256"},{"indexed":true,"name":"seller","type":"address"},{"indexed":false,"name":"nftAddress","type":"address"}],"name":"OrderCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"publicationFee","type":"uint256"}],"name":"ChangedPublicationFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"ownerCutPerMillion","type":"uint256"}],"name":"ChangedOwnerCutPerMillion","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"legacyNFTAddress","type":"address"}],"name":"ChangeLegacyNFTAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"bytes32"},{"indexed":true,"name":"assetId","type":"uint256"},{"indexed":true,"name":"seller","type":"address"},{"indexed":false,"name":"priceInWei","type":"uint256"},{"indexed":false,"name":"expiresAt","type":"uint256"}],"name":"AuctionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"bytes32"},{"indexed":true,"name":"assetId","type":"uint256"},{"indexed":true,"name":"seller","type":"address"},{"indexed":false,"name":"totalPrice","type":"uint256"},{"indexed":true,"name":"winner","type":"address"}],"name":"AuctionSuccessful","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"bytes32"},{"indexed":true,"name":"assetId","type":"uint256"},{"indexed":true,"name":"seller","type":"address"}],"name":"AuctionCancelled","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"contractName","type":"string"},{"indexed":false,"name":"migrationId","type":"string"}],"name":"Migrated","type":"event"}]` + // Look-up table for ABI strings var Abis = map[common.Address]string{ common.HexToAddress("0x314159265dD8dbb310642f98f50C066173C1259b"): ENSAbiString, diff --git a/pkg/contract_watcher/shared/helpers/test_helpers/database.go b/pkg/contract_watcher/shared/helpers/test_helpers/database.go index 3558614e..9f59bfaa 100644 --- a/pkg/contract_watcher/shared/helpers/test_helpers/database.go +++ b/pkg/contract_watcher/shared/helpers/test_helpers/database.go @@ -221,6 +221,24 @@ func SetupENSContract(wantedEvents, wantedMethods []string) *contract.Contract { }.Init() } +func SetupMarketPlaceContract(wantedEvents, wantedMethods []string) *contract.Contract { + p := mocks.NewParser(constants.MarketPlaceAbiString) + err := p.Parse() + Expect(err).NotTo(HaveOccurred()) + + return contract.Contract{ + Name: "Marketplace", + Address: constants.MarketPlaceContractAddress, + StartingBlock: 6496012, + Abi: p.Abi(), + ParsedAbi: p.ParsedAbi(), + Events: p.GetEvents(wantedEvents), + Methods: p.GetSelectMethods(wantedMethods), + FilterArgs: map[string]bool{}, + MethodArgs: map[string]bool{}, + }.Init() +} + // TODO: tear down/setup DB from migrations so this doesn't alter the schema between tests func TearDown(db *postgres.DB) { tx, err := db.Beginx() diff --git a/pkg/contract_watcher/shared/helpers/test_helpers/mocks/entities.go b/pkg/contract_watcher/shared/helpers/test_helpers/mocks/entities.go index c4eff41c..dbcd5a5f 100644 --- a/pkg/contract_watcher/shared/helpers/test_helpers/mocks/entities.go +++ b/pkg/contract_watcher/shared/helpers/test_helpers/mocks/entities.go @@ -279,6 +279,22 @@ var MockNewOwnerLog2 = types.Log{ Data: hexutil.MustDecode("0x000000000000000000000000000000000000000000000000000000000000af21"), } +var MockOrderCreatedLog = types.Log{ + Address: common.HexToAddress(constants.MarketPlaceContractAddress), + Topics: []common.Hash{ + common.HexToHash("0x84c66c3f7ba4b390e20e8e8233e2a516f3ce34a72749e4f12bd010dfba238039"), + common.HexToHash("0xffffffffffffffffffffffffffffff72ffffffffffffffffffffffffffffffd0"), + common.HexToHash("0x00000000000000000000000083b7b6f360a9895d163ea797d9b939b9173b292a"), + }, + Data: hexutil.MustDecode("0x633f94affdcabe07c000231f85c752c97b9cc43966b432ec4d18641e6d178233000000000000000000000000f87e31492faf9a91b02ee0deaad50d51d56d5d4d0000000000000000000000000000000000000000000003da9fbcf4446d6000000000000000000000000000000000000000000000000000000000016db2524880"), + BlockNumber: 8587618, + TxHash: common.HexToHash("0x7ad9e2f88416738f3c7ad0a6d260f71794532206a0e838299f5014b4fe81e66e"), + TxIndex: 93, + BlockHash: common.HexToHash("0x06a1762b7f2e070793fc24cd785de0fa485e728832c4f3469790153ae51a56a2"), + Index: 59, + Removed: false, +} + var ens = strings.ToLower(constants.EnsContractAddress) var tusd = strings.ToLower(constants.TusdContractAddress)