2018-11-07 21:50:43 +00:00
// VulcanizeDB
2019-03-12 15:46:42 +00:00
// Copyright © 2019 Vulcanize
2018-11-07 21:50:43 +00:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2018-11-04 21:26:39 +00:00
package retriever
import (
"fmt"
2019-03-11 23:18:54 +00:00
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/types"
2018-11-07 21:50:43 +00:00
"strings"
2018-11-04 21:26:39 +00:00
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
2019-03-11 23:18:54 +00:00
"github.com/vulcanize/vulcanizedb/pkg/contract_watcher/shared/contract"
2018-11-04 21:26:39 +00:00
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
)
// Address retriever is used to retrieve the addresses associated with a contract
type AddressRetriever interface {
RetrieveTokenHolderAddresses ( info contract . Contract ) ( map [ common . Address ] bool , error )
}
type addressRetriever struct {
2018-11-24 04:26:07 +00:00
db * postgres . DB
mode types . Mode
2018-11-04 21:26:39 +00:00
}
2018-11-24 04:26:07 +00:00
func NewAddressRetriever ( db * postgres . DB , mode types . Mode ) ( r * addressRetriever ) {
2018-11-04 21:26:39 +00:00
return & addressRetriever {
2018-11-24 04:26:07 +00:00
db : db ,
mode : mode ,
2018-11-04 21:26:39 +00:00
}
}
// Method to retrieve list of token-holding/contract-related addresses by iterating over available events
// This generic method should work whether or not the argument/input names of the events meet the expected standard
// This could be generalized to iterate over ALL events and pull out any address arguments
func ( r * addressRetriever ) RetrieveTokenHolderAddresses ( info contract . Contract ) ( map [ common . Address ] bool , error ) {
addrList := make ( [ ] string , 0 )
_ , ok := info . Filters [ "Transfer" ]
if ok {
addrs , err := r . retrieveTransferAddresses ( info )
if err != nil {
return nil , err
}
addrList = append ( addrList , addrs ... )
}
_ , ok = info . Filters [ "Mint" ]
if ok {
addrs , err := r . retrieveTokenMintees ( info )
if err != nil {
return nil , err
}
addrList = append ( addrList , addrs ... )
}
contractAddresses := make ( map [ common . Address ] bool )
for _ , addr := range addrList {
contractAddresses [ common . HexToAddress ( addr ) ] = true
}
return contractAddresses , nil
}
2018-11-07 21:50:43 +00:00
func ( r * addressRetriever ) retrieveTransferAddresses ( con contract . Contract ) ( [ ] string , error ) {
2018-11-04 21:26:39 +00:00
transferAddrs := make ( [ ] string , 0 )
2018-11-07 21:50:43 +00:00
event := con . Events [ "Transfer" ]
2018-11-04 21:26:39 +00:00
for _ , field := range event . Fields { // Iterate over event fields, finding the ones with address type
if field . Type . T == abi . AddressTy { // If they have address type, retrieve those addresses
addrs := make ( [ ] string , 0 )
2018-11-24 04:26:07 +00:00
pgStr := fmt . Sprintf ( "SELECT %s_ FROM %s_%s.%s_event" , strings . ToLower ( field . Name ) , r . mode . String ( ) , strings . ToLower ( con . Address ) , strings . ToLower ( event . Name ) )
2018-11-23 18:12:24 +00:00
err := r . db . Select ( & addrs , pgStr )
2018-11-04 21:26:39 +00:00
if err != nil {
return [ ] string { } , err
}
transferAddrs = append ( transferAddrs , addrs ... ) // And append them to the growing list
}
}
return transferAddrs , nil
}
2018-11-07 21:50:43 +00:00
func ( r * addressRetriever ) retrieveTokenMintees ( con contract . Contract ) ( [ ] string , error ) {
2018-11-04 21:26:39 +00:00
mintAddrs := make ( [ ] string , 0 )
2018-11-07 21:50:43 +00:00
event := con . Events [ "Mint" ]
2018-11-04 21:26:39 +00:00
for _ , field := range event . Fields { // Iterate over event fields, finding the ones with address type
if field . Type . T == abi . AddressTy { // If they have address type, retrieve those addresses
addrs := make ( [ ] string , 0 )
2018-11-24 04:26:07 +00:00
pgStr := fmt . Sprintf ( "SELECT %s_ FROM %s_%s.%s_event" , strings . ToLower ( field . Name ) , r . mode . String ( ) , strings . ToLower ( con . Address ) , strings . ToLower ( event . Name ) )
2018-11-23 18:12:24 +00:00
err := r . db . Select ( & addrs , pgStr )
2018-11-04 21:26:39 +00:00
if err != nil {
return [ ] string { } , err
}
mintAddrs = append ( mintAddrs , addrs ... ) // And append them to the growing list
}
}
return mintAddrs , nil
}